From: Indu Bhagat Date: Fri, 16 Jan 2026 00:43:07 +0000 (-0800) Subject: [SFrame-V3] gas: sframe: testsuite: handle .cfi_register FP/RA for flex FDE X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7e11620c672a7992b15fb7306bc800f02d2f38e8;p=thirdparty%2Fbinutils-gdb.git [SFrame-V3] gas: sframe: testsuite: handle .cfi_register FP/RA for flex FDE 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), 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. gas/ * gen-sframe.c (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_p and recording the register. gas/testsuite/gas/ * cfi-sframe/cfi-sframe.exp: Run new test. * cfi-sframe/cfi-sframe-x86_64-5.d: New test. * cfi-sframe/cfi-sframe-x86_64-5.s: Simple test for checking FLEX FDE generation for `.cfi_register REG_RA, XX`. * cfi-sframe/cfi-sframe-x86_64-esc-expr-3.d: New test. * cfi-sframe/cfi-sframe-x86_64-esc-expr-3.s: New test with DWARF expression for REG_FP, followed by .cfi_register and .cfi_offset for REG_FP. * cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.d: New test. * cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.s: New test for FLEX FDE with undefined RA. --- diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index c21ac9b63aa..d1f6e3780f6 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -1164,6 +1164,7 @@ sframe_row_entry_initialize (struct sframe_row_entry *cur_fre, 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; @@ -1489,6 +1490,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 can be used for FP, RA registers. + Return SFRAME_XLATE_OK if success. */ static int @@ -1498,15 +1511,33 @@ 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_support_flex_fde_p ()) + { + 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_loc = SFRAME_FRE_ELEM_LOC_REG; + cur_fre->fp_reg = cfi_insn->u.rr.reg2; + cur_fre->fp_deref_p = false; + cur_fre->merge_candidate = false; + xlate_ctx->flex_p = true; + } + else if (cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG) + { + sframe_fre_set_ra_track (cur_fre, 0); + cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_REG; + cur_fre->ra_reg = cfi_insn->u.rr.reg2; + cur_fre->ra_deref_p = false; + cur_fre->merge_candidate = false; + xlate_ctx->flex_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/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-5.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-5.d new file mode 100644 index 00000000000..9274e60618d --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-5.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, attr = "F" + 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-5.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-5.s new file mode 100644 index 00000000000..61335c36abf --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-5.s @@ -0,0 +1,12 @@ +# Testcase to check FLEX FDE generation for .cfi_register RIP, XX + .type foo, @function +foo: + .cfi_startproc + sub $0x20,%rsp + .cfi_adjust_cfa_offset 0x20 + popq %rcx + .cfi_register rip, 2 + .cfi_def_cfa_offset 0 + jmp *%rcx + .cfi_endproc + .size foo, .-foo diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.d new file mode 100644 index 00000000000..2893fbe646a --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.d @@ -0,0 +1,26 @@ +#as: --gsframe +#objdump: --sframe=.sframe +#name: Flex FDE with RA state transition +#... +Contents of the SFrame section .sframe: + + Header : + + Version: SFRAME_VERSION_3 + Flags: SFRAME_F_FDE_FUNC_START_PCREL +#? CFA fixed FP offset: \-?\d+ +#? CFA fixed RA offset: \-?\d+ + Num FDEs: 1 + Num FREs: 5 + + Function Index : + + func idx \[0\]: pc = 0x0, size = 17 bytes, attr = "F" + STARTPC +CFA +FP +RA + + 0+0000 +sp\+8 +u +f + + 0+0004 +sp\+40 +u +f + + 0+0008 +sp\+40 +\(fp\+48\) +U + + 0+000c +sp\+40 +r3\+0 +U + + 0+0010 +sp\+8 +c\+16 +U + + +#pass diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.s new file mode 100644 index 00000000000..68213d96690 --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.s @@ -0,0 +1,18 @@ +# Testcase for transition of tracked entity (rbp) from DWARF expression, to +# register, and finally to CFA+offset. + .type foo, @function +foo: + .cfi_startproc + .long 0 + .cfi_adjust_cfa_offset 0x20 + .long 0 + # DW_CFA_expression, (uleb)reg, length, DW_OP_breg6, (sleb)offset + .cfi_escape 0x10,0x6,0x2,0x76,sleb128(48) + .long 0 + .cfi_register rbp, 3 + .long 0 + .cfi_offset rbp, 16 + .cfi_def_cfa rsp, 8 + ret + .cfi_endproc + .size foo, .-foo diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.d new file mode 100644 index 00000000000..436c0a239db --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.d @@ -0,0 +1,23 @@ +#as: --gsframe -O0 +#objdump: --sframe=.sframe +#name: SFrame generation on x86_64 - .cfi_undefined RA +#... +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: 5 + + Function Index : + + func idx \[0\]: pc = 0x0, size = 7 bytes, attr = "F" + STARTPC +CFA +FP +RA + + 0+0000 +sp\+8 +u +f + + 0+0001 +sp\+16 +c\-16 +U + + 0+0004 +fp\+16 +c\-16 +U + + 0+0005 +fp\+16 +c\-16 +r3\+0 + + 0+0006 +RA undefined diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.s new file mode 100644 index 00000000000..6c8114cef6c --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.s @@ -0,0 +1,15 @@ +# Testcase with FLEX FDE generation due to RA using reg on AMD64 +# Also, tagged as outermost frame. + .cfi_startproc + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register rbp + nop + .cfi_register rip, rbx + nop + .cfi_undefined rip + .cfi_def_cfa rsp, 8 + ret + .cfi_endproc diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp index 04edb47ea19..b516e531fe0 100644 --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp @@ -62,8 +62,10 @@ if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then { run_dump_test "cfi-sframe-x86_64-2" 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-esc-expr-1" run_dump_test "cfi-sframe-x86_64-esc-expr-2" + run_dump_test "cfi-sframe-x86_64-esc-expr-3" run_dump_test "cfi-sframe-x86_64-pr33170" run_dump_test "cfi-sframe-x86_64-pr33756" run_dump_test "cfi-sframe-x86_64-signal-1" @@ -73,6 +75,7 @@ if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then { run_dump_test "cfi-sframe-x86_64-empty-4" run_dump_test "cfi-sframe-x86_64-empty-pr33277" run_dump_test "cfi-sframe-x86_64-ra-undefined-1" + run_dump_test "cfi-sframe-x86_64-ra-undefined-flex-1" set ASFLAGS "$old_ASFLAGS" } }