From: Indu Bhagat Date: Sat, 6 Dec 2025 20:50:44 +0000 (-0800) Subject: [SFrame-V3] gas: sframe: add handling for .cfi_register for FP and RA X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf7b7bf992632df1083555bde6f7f30139310510;p=thirdparty%2Fbinutils-gdb.git [SFrame-V3] gas: sframe: add handling for .cfi_register for FP and RA Use SFrame FDE of type SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME. When FP, RA were moved to a general-purpose register, the SFrame generation previously warned and skipped the FDE (except on S390X). This patch updates the translator to detect`.cfi_register` for RA (and FP) on AMD64, tracks the destination register in the SFrame row entry, and emits the register in the relevant FRE offsets in SFrame FDE type SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME. gas/ * gen-sframe.c (output_sframe_row_entry_offsets): Emit register encoding for RA if tracked. (sframe_row_entry_initialize): Propagate ra_reg and ra_deref_p. (sframe_xlate_do_register): Handle .cfi_register for RA/FP on AMD64 by setting flex_topmost_p and recording the register. * gen-sframe.h (struct sframe_row_entry): Add ra_reg and ra_deref_p. testsuite/gas/ * cfi-sframe/cfi-sframe.exp: Run new test. * cfi-sframe/cfi-sframe-x86_64-6.d: New test. * cfi-sframe/cfi-sframe-x86_64-6.s: New test. --- diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index 11cc828dbde..89675379d51 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -644,13 +644,25 @@ output_sframe_row_entry_offsets (const struct sframe_func_entry *sframe_fde, /* RA tracking enabled or not, emit two offsets for RA. Aside, emitting SFRAME_FRE_RA_OFFSET_INVALID is equivalent to emitting - SFRAME_V3_FLEX_FDE_REG_ENCODE (0, 0, 0). - FIXME - This may change later when we implement handling .cfi_register - RA, reg. Emit two 0 offsets for now. */ - fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID); - /* FIXME Offset 0 for now. */ - fre_offset_func_map[idx].out_func (0); - fre_write_offsets += 2; + SFRAME_V3_FLEX_FDE_REG_ENCODE (0, 0, 0). */ + if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK) + { + /* Output RA related FRE offsets. */ + reg_data = SFRAME_V3_FLEX_FDE_REG_ENCODE (sframe_fre->ra_reg, + sframe_fre->ra_deref_p, + 1 /* reg_p. */); + offset_data = sframe_fre->ra_offset; + fre_offset_func_map[idx].out_func (reg_data); + fre_offset_func_map[idx].out_func (offset_data); + fre_write_offsets += 2; + } + else + { + fre_offset_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID); + /* FIXME Offset 0 for now. */ + fre_offset_func_map[idx].out_func (0); + fre_write_offsets += 2; + } if (sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK) { @@ -1116,7 +1128,9 @@ sframe_row_entry_initialize (struct sframe_row_entry *cur_fre, cur_fre->fp_offset = prev_fre->fp_offset; cur_fre->fp_deref_p = prev_fre->fp_deref_p; cur_fre->ra_loc = prev_fre->ra_loc; + cur_fre->ra_reg = prev_fre->ra_reg; cur_fre->ra_offset = prev_fre->ra_offset; + cur_fre->ra_deref_p = prev_fre->ra_deref_p; /* Treat RA mangling as a sticky bit. It retains its value until another .cfi_negate_ra_state is seen. */ cur_fre->mangled_ra_p = prev_fre->mangled_ra_p; @@ -1440,6 +1454,18 @@ s390_sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx, } /* Translate DW_CFA_register into SFrame context. + + This opcode indicates: Previous value of register1 is register2. This is + not representable in SFrame stack trace format. Detect the use of registers + interesting to SFrame (FP, RA for this opcode), and skip FDE generation + while warning the user. + + Two exceptions apply though: + - for S390X, the stack offsets are used to carry register number in + default FDE types. So invoke S390X specific handling. + - for AMD64, the flexible topmost frame encoding + SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME can be used for FP, RA registers. + Return SFRAME_XLATE_OK if success. */ static int @@ -1449,15 +1475,31 @@ sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx, /* Conditionally invoke S390-specific implementation. */ if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG) return s390_sframe_xlate_do_register (xlate_ctx, cfi_insn); + else if (sframe_get_abi_arch () == SFRAME_ABI_AMD64_ENDIAN_LITTLE) + { + struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre; - /* Previous value of register1 is register2. However, if the specified - register1 is not interesting (FP or RA reg), the current DW_CFA_register - instruction can be safely skipped without sacrificing the asynchronicity of - stack trace information. */ - if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG - || cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG - /* Ignore SP reg, as it can be recovered from the CFA tracking info. */ - ) + if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG) + { + sframe_fre_set_fp_track (cur_fre, 0); + cur_fre->fp_reg = cfi_insn->u.rr.reg2; + cur_fre->fp_deref_p = false; + cur_fre->merge_candidate = false; + xlate_ctx->flex_topmost_p = true; + } + else if (cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG) + { + sframe_fre_set_ra_track (cur_fre, 0); + cur_fre->ra_reg = cfi_insn->u.rr.reg2; + cur_fre->ra_deref_p = false; + cur_fre->merge_candidate = false; + xlate_ctx->flex_topmost_p = true; + } + } + else if (cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG + /* Ignore SP reg, as it can be recovered from the CFA tracking + info. */ + || cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG) { as_warn (_("no SFrame FDE emitted; %s register %u in .cfi_register"), sframe_register_name (cfi_insn->u.rr.reg1), cfi_insn->u.rr.reg1); diff --git a/gas/gen-sframe.h b/gas/gen-sframe.h index 4921e796a10..6c0699dec46 100644 --- a/gas/gen-sframe.h +++ b/gas/gen-sframe.h @@ -87,9 +87,13 @@ struct sframe_row_entry bool fp_deref_p; /* Track RA location. Specify whether it is in register or memory. */ + unsigned int ra_reg; unsigned int ra_loc; /* If RA is stashed on stack, note the offset. */ offsetT ra_offset; + /* Whether RA recovery needs dereferencing. This is tracked for + SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME SFrame FDE type. */ + bool ra_deref_p; }; /* SFrame Function Description Entry. */ diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.d new file mode 100644 index 00000000000..1906a0b5630 --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.d @@ -0,0 +1,21 @@ +#as: --gsframe +#objdump: --sframe=.sframe +#name: DW_CFA_register RA in flex FDE type +#... + +Contents of the SFrame section .sframe: + Header : + + Version: SFRAME_VERSION_3 + Flags: SFRAME_F_FDE_FUNC_START_PCREL + CFA fixed RA offset: -8 + Num FDEs: 1 + Num FREs: 3 + + Function Index : + + func idx \[0\]: pc = 0x0, size = 7 bytes + STARTPC +CFA +FP +RA + + 0+0000 +sp\+8 +u +f + + 0+0004 +sp\+40 +u +f + + 0+0005 +sp\+0 +u +r2\+0 + diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.s new file mode 100644 index 00000000000..69a3efb7e85 --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.s @@ -0,0 +1,13 @@ + .p2align 4 + .globl foo + .type foo, @function +foo: + .cfi_startproc + sub $0x20,%rsp + .cfi_adjust_cfa_offset 0x20 + popq %rcx + .cfi_register 16, 2 + .cfi_def_cfa_offset 0 + jmp *%rcx + .cfi_endproc + .size foo, .-foo diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp index 489b3ff003f..d7a2afbaf3d 100644 --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp @@ -64,6 +64,7 @@ if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then { run_dump_test "cfi-sframe-x86_64-3" run_dump_test "cfi-sframe-x86_64-4" run_dump_test "cfi-sframe-x86_64-5" + run_dump_test "cfi-sframe-x86_64-6" run_dump_test "cfi-sframe-x86_64-pr33170" run_dump_test "cfi-sframe-x86_64-signal-1" run_dump_test "cfi-sframe-x86_64-empty-1"