gas: sframe: handle .cfi_same_value

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.

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.
diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index a29c959..2d1c196 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -1534,6 +1534,63 @@
   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 as
+   in the previous frame, i.e. no restoration needed.  In SFrame stack trace
+   format, the handling is done similar to DW_CFA_restore.
+
+   For SFRAME_CFA_RA_REG, if RA-tracking is enabled, 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.  For ABIs, where RA-tracking is disabled, handle it
+   similar to DW_CFA_restore: ignore the directive, it is safe to skip.  The
+   reasoning is similar to that for DW_CFA_restore: if such a restoration was
+   meant to be of any consequence, there must have been the necessary CFI
+   directives for updating the CFA rule too such that the recovered RA from
+   stack is valid.
+
+   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,
+   when going to the previous frame.  That said, if DW_CFA_same_value is seen
+   for SFRAME_CFA_SP_REG, handle it similar to DW_CFA_restore: ignore the
+   directive, it is safe to skip.  The reasoning is similar to that for
+   DW_CFA_restore: if such a restoration was meant to be of any consequence,
+   there must have been the necessary CFI directives for updating the CFA rule
+   too.  The latter will be duly processed by the SFrame generation code, as
+   expected.
+
+   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)
+{
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  if (sframe_ra_tracking_p () && 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 +1690,11 @@
     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 0000000..2584815
--- /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 0000000..e299f58
--- /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.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
index ad5602f..341a56a 100644
--- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
@@ -80,6 +80,7 @@
     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"