[PATCH,V2 4/4] gas: sframe: handle .cfi_same_value

Indu Bhagat indu.bhagat@oracle.com
Thu May 15 21:06:17 GMT 2025
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.

In some cases, SFrame has no means to encode this information.  Warn and
skip generating the SFrame FDE in those cases.

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.
	* gas/cfi-sframe/cfi-sframe-x86_64-empty-5.d: New test.
	* gas/cfi-sframe/cfi-sframe-x86_64-empty-5.s: New test.

---
[Changes from V1]
 - Update the implementation.  Skip generating FDE only those cases when
   the representation is not supported in SFrame.
 - Correct the name of the test.  Updated the test
   cfi-sframe-x86_64-empty-5.s to be for REG_RA instead of the earlier
   REG_FP.
 - Reword the warning text.
[End of changes from V1]
---
 gas/gen-sframe.c                              | 65 ++++++++++++++++++-
 .../gas/cfi-sframe/cfi-sframe-common-11.d     | 22 +++++++
 .../gas/cfi-sframe/cfi-sframe-common-11.s     | 12 ++++
 .../cfi-sframe/cfi-sframe-x86_64-empty-5.d    | 17 +++++
 .../cfi-sframe/cfi-sframe-x86_64-empty-5.s    | 10 +++
 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |  2 +
 6 files changed, 125 insertions(+), 3 deletions(-)
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-11.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-5.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-5.s

diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index a29c959db1c..d62e7406eb1 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -1534,6 +1534,67 @@ 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 like
+   in the previous frame, i.e. no restoration needed.  In SFrame stack trace
+   format, whether or not we can encode "no restoration needed" is case
+   specific.
+
+   For SFRAME_CFA_RA_REG, perform an ABI-sensitive check.  For AMD64, SFrame
+   can only represent the fact that REG_RA is at a fixed offset from CFA; IOW,
+   restoration is always necessary.  Hence, .cfi_same_value REG_RA cannot be
+   represented in SFrame.  For AArch64, since RA-tracking is enabled, the
+   manner to restore REG_RA is, in theory, encodable.  So, for
+   DW_CFA_same_value, 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.
+
+   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.  So
+   skip generating the SFrame FDE if DW_CFA_same_value is seen for
+   SFRAME_CFA_SP_REG.
+
+   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)
+{
+  /* For some cases, SFrame cannot encode such information.  */
+  if (cfi_insn->u.r == SFRAME_CFA_SP_REG
+      || (!sframe_ra_tracking_p () && cfi_insn->u.r == SFRAME_CFA_RA_REG))
+    {
+      as_warn (_("no SFrame FDE emitted; %s reg %u in .cfi_same_value"),
+	       sframe_register_name (cfi_insn->u.r), cfi_insn->u.r);
+      return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
+    }
+
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  if (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 +1694,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-x86_64-empty-5.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-5.d
new file mode 100644
index 00000000000..aaeb563df60
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-5.d
@@ -0,0 +1,17 @@
+#as: --gsframe
+#warning: no SFrame FDE emitted; RA reg 16 in \.cfi\_same\_value
+#objdump: --sframe=.sframe
+#name: DW_CFA_same_value with RA reg
+#...
+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: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-5.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-5.s
new file mode 100644
index 00000000000..0a778dc914c
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-empty-5.s
@@ -0,0 +1,10 @@
+# In SFrame stack trace format, whether or not we can encode "no restoration
+# needed" semantic for DW_CFA_same_value is case specific.  In case of AMD64,
+# SFrame can only represent the fact # that REG_RA is at a fixed offset from
+# CFA; IOW, restoration is always # necessary.
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.cfi_same_value 16
+	.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..8ca22d3c652 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"
@@ -96,6 +97,7 @@ if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then {
 	run_dump_test "cfi-sframe-x86_64-empty-2"
 	run_dump_test "cfi-sframe-x86_64-empty-3"
 	run_dump_test "cfi-sframe-x86_64-empty-4"
+	run_dump_test "cfi-sframe-x86_64-empty-5"
 	set ASFLAGS "$old_ASFLAGS"
     }
 }
-- 
2.43.0



More information about the Binutils mailing list