[COMMITTED 23/36] [SFrame-V3] gas: sframe: testsuite: handle .cfi_register FP/RA for flex FDE

Indu Bhagat indu.bhagat@oracle.com
Fri Jan 16 06:10:23 GMT 2026


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.
---
 gas/gen-sframe.c                              | 47 +++++++++++++++----
 .../gas/cfi-sframe/cfi-sframe-x86_64-5.d      | 21 +++++++++
 .../gas/cfi-sframe/cfi-sframe-x86_64-5.s      | 12 +++++
 .../cfi-sframe/cfi-sframe-x86_64-esc-expr-3.d | 26 ++++++++++
 .../cfi-sframe/cfi-sframe-x86_64-esc-expr-3.s | 18 +++++++
 .../cfi-sframe-x86_64-ra-undefined-flex-1.d   | 23 +++++++++
 .../cfi-sframe-x86_64-ra-undefined-flex-1.s   | 15 ++++++
 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |  3 ++
 8 files changed, 157 insertions(+), 8 deletions(-)
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-5.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-5.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-esc-expr-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-flex-1.s

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



More information about the Binutils mailing list