From: Indu Bhagat Date: Mon, 26 May 2025 16:40:39 +0000 (-0700) Subject: gas: sframe: handle .cfi_same_value X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5bd7ac079aeeec1a2d87fb2d24dab60a135b387f;p=thirdparty%2Fbinutils-gdb.git gas: sframe: handle .cfi_same_value Fix PR gas/32953 - sframe: incorrect handling of .cfi_same_value in gas As per documentation, .cfi_same_value indicates that the current value of register is the same like in the previous frame, i.e. no restoration needed. gas/ * gen-sframe.c (sframe_xlate_do_same_value): New definition. (sframe_do_cfi_insn): Handle DW_CFA_same_value. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Add new tests. * gas/cfi-sframe/cfi-sframe-common-11.d: New test. * gas/cfi-sframe/cfi-sframe-common-11.s: New test. --- diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index a29c959db1c..2d1c1961fd7 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -1534,6 +1534,63 @@ sframe_xlate_do_cfi_undefined (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUT return SFRAME_XLATE_OK; } +/* Translate DW_CFA_same_value into SFrame context. + + DW_CFA_same_value op indicates that current value of register is the same as + in the previous frame, i.e. no restoration needed. In SFrame stack trace + format, the handling is done similar to DW_CFA_restore. + + For SFRAME_CFA_RA_REG, if RA-tracking is enabled, reset the SFrame FRE state + for REG_RA to indicate that register does not need restoration. P.S.: Even + though resetting just REG_RA may be contradicting the AArch64 ABI (as Frame + Record contains for FP and LR), sframe_xlate_do_same_value () does not + detect the case and assumes the users' DW_CFA_same_value SFRAME_CFA_RA_REG + has a sound reason. For ABIs, where RA-tracking is disabled, handle it + similar to DW_CFA_restore: ignore the directive, it is safe to skip. The + reasoning is similar to that for DW_CFA_restore: if such a restoration was + meant to be of any consequence, there must have been the necessary CFI + directives for updating the CFA rule too such that the recovered RA from + stack is valid. + + SFrame based stacktracers will implement CFA-based SP recovery for all ABIs: + SP for previous frame is based on the applicable CFA-rule. There is no + representation in SFrame to indicate "no restoration needed" for REG_SP, + when going to the previous frame. That said, if DW_CFA_same_value is seen + for SFRAME_CFA_SP_REG, handle it similar to DW_CFA_restore: ignore the + directive, it is safe to skip. The reasoning is similar to that for + DW_CFA_restore: if such a restoration was meant to be of any consequence, + there must have been the necessary CFI directives for updating the CFA rule + too. The latter will be duly processed by the SFrame generation code, as + expected. + + For SFRAME_CFA_FP_REG, reset the state of the current FRE to indicate that + the value is the same as previous frame. + + Return SFRAME_XLATE_OK if success. */ + +static int +sframe_xlate_do_same_value (const struct sframe_xlate_ctx *xlate_ctx, + const struct cfi_insn_data *cfi_insn) +{ + struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre; + + if (sframe_ra_tracking_p () && cfi_insn->u.r == SFRAME_CFA_RA_REG) + { + cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_REG; + cur_fre->ra_offset = 0; + cur_fre->merge_candidate = false; + } + else if (cfi_insn->u.r == SFRAME_CFA_FP_REG) + { + cur_fre->bp_loc = SFRAME_FRE_ELEM_LOC_REG; + cur_fre->bp_offset = 0; + cur_fre->merge_candidate = false; + } + + /* Safe to skip. */ + return SFRAME_XLATE_OK; +} + /* Returns the DWARF call frame instruction name or fake CFI name for the specified CFI opcode, or NULL if the value is not recognized. */ @@ -1633,13 +1690,11 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx, case CFI_escape: err = sframe_xlate_do_cfi_escape (xlate_ctx, cfi_insn); break; - /* Following CFI opcodes are not processed at this time. - These do not impact the coverage of the basic stack tracing - information as conveyed in the SFrame format. */ case DW_CFA_undefined: err = sframe_xlate_do_cfi_undefined (xlate_ctx, cfi_insn); break; case DW_CFA_same_value: + err = sframe_xlate_do_same_value (xlate_ctx, cfi_insn); break; default: /* Other skipped operations may, however, impact the asynchronicity. */ diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.d new file mode 100644 index 00000000000..25848150135 --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.d @@ -0,0 +1,22 @@ +#as: --gsframe +#objdump: --sframe=.sframe +#name: SFrame cfi_same_value test +#... +Contents of the SFrame section .sframe: + + Header : + + Version: SFRAME_VERSION_2 + Flags: NONE +#? CFA fixed FP offset: \-?\d+ +#? CFA fixed RA offset: \-?\d+ + Num FDEs: 1 + Num FREs: 2 + + Function Index : + func idx \[0\]: pc = 0x0, size = 8 bytes + STARTPC + CFA + FP + RA + +#... + 0+0004 +sp\+16 +u +[uf] + + +#pass diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.s new file mode 100644 index 00000000000..e299f586cf2 --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.s @@ -0,0 +1,12 @@ +## cfi_same_value when used with "not interesting" registers (from the +## perspective of SFrame section, non SP/FP/RA registers are not +## interesting) does not affect the asynchronicity of the SFrame stack +## trace information. Such CFI directives can be skipped for SFrame +## stack trace info generation. + .cfi_startproc + .long 0 + .cfi_def_cfa_offset 16 + .cfi_same_value 1 + .cfi_same_value 2 + .long 0 + .cfi_endproc diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp index ad5602fc373..341a56a9eab 100644 --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp @@ -80,6 +80,7 @@ if { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]) \ run_dump_test "cfi-sframe-common-8" run_dump_test "cfi-sframe-common-9" run_dump_test "cfi-sframe-common-10" + run_dump_test "cfi-sframe-common-11" run_dump_test "common-empty-1" run_dump_test "common-empty-2"