]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[SFrame-V3] gas: sframe: add handling for .cfi_register for FP and RA
authorIndu Bhagat <indu.bhagat@oracle.com>
Sat, 6 Dec 2025 20:50:44 +0000 (12:50 -0800)
committerIndu Bhagat <indu.bhagat@oracle.com>
Tue, 9 Dec 2025 08:26:14 +0000 (00:26 -0800)
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.

gas/gen-sframe.c
gas/gen-sframe.h
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.d [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.s [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe.exp

index 11cc828dbde3982fd36a3b6f99f02be216efb672..89675379d516e4c2db318e0952b3838e5eab846e 100644 (file)
@@ -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);
index 4921e796a10b6b91db811ee133a3866c40c5e5cf..6c0699dec4612fb8c12f9637551d9484df345153 100644 (file)
@@ -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 (file)
index 0000000..1906a0b
--- /dev/null
@@ -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 (file)
index 0000000..69a3efb
--- /dev/null
@@ -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
index 489b3ff003f72f948715291b598b94f83b4f9305..d7a2afbaf3d2fcc50a67a5a9e1c9abc3c1ffe491 100644 (file)
@@ -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"