[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.
This commit is contained in:
Indu Bhagat
2026-01-15 16:43:07 -08:00
parent 3b409a1504
commit 7e11620c67
8 changed files with 157 additions and 8 deletions

View File

@@ -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);

View File

@@ -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 +

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"
}
}