]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
s390: SFrame track FP/RA saved in register
authorJens Remus <jremus@linux.ibm.com>
Tue, 9 Apr 2024 13:59:12 +0000 (15:59 +0200)
committerJens Remus <jremus@linux.ibm.com>
Thu, 16 May 2024 11:32:22 +0000 (13:32 +0200)
GCC on s390x, when in a leaf function, can be observed to save the
frame pointer (FP) and/or return address (RA) register in a floating-
point registers (FPR) instead of on the stack. This is declared using
the following CFI directive:

  .cfi_register <fp/ra-regno>, <fpr-regno>

SFrame cannot represent the FP and/or RA being saved in another
register. It does only track the CFA base register (SP/FP), CFA offset
from CFA base register, and FP and RA save area offsets from CFA.

On s390x the FP and/or RA are only saved in another FPR when in a leaf
function. That is a function that does not call any other functions.
Therefore it can ever only be the topmost function in a call chain.
During function return, if the RA would be restored into a non-default
RA register, the function would also only ever be the topmost function
on the call stack.
An unwinder by default has access to all registers of the function that
if the topmost on the call stack. Therefore no further information would
be required for those registers.

Represent the FP/RA in another register on s390, by encoding the
register number shifted by one to the left with the least-significant
bit set in the offset as follows:

  offset = (regno << 1) | 1

Add s390-specific SFrame (error) test cases for FP/RA being saved in
FPRs in leaf-function.

gas/
* gen-sframe.c (s390_sframe_xlate_do_register): New s390-
specific function to represent FP/RA in another register on
s390.
(sframe_xlate_do_register): Invoke s390_sframe_xlate_do_register
on s390.

libsframe/
* sframe-dump.c (is_sframe_abi_arch_s390): New helper to test
whether ABI/arch is s390.
(dump_sframe_func_with_fres): Dump FP/RA in another register on
s390.

gas/testsuite/
* gas/cfi-sframe/cfi-sframe.exp: Update s390-specific SFrame
(error) test cases.
* gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-2.s: Rename
to ...
* gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-2.d:
Likewise.
* gas/cfi-sframe/cfi-sframe-s390-fpra-register-1.s: This. Test
case no longer triggers a warning, as SFrame can represent FP
and RA saved in registers.
* gas/cfi-sframe/cfi-sframe-s390-fpra-register-1.d: Likewise.
* gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-1.d: Test
case now triggers a different warning, as SFrame can represent
FP and RA saved in registers, but not FP without RA saved in
register.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
gas/gen-sframe.c
gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-1.d [new file with mode: 0644]
gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-1.s [moved from gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-2.s with 100% similarity]
gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-1.d
gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-2.d [deleted file]
gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
libsframe/sframe-dump.c

index dd97d4f883935e9911b85b8349c9c6e96efa466d..0bb7afb7e7217c208fc051e638ad4894e21c9ce9 100644 (file)
@@ -1152,6 +1152,37 @@ sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
   return SFRAME_XLATE_OK;
 }
 
+/* S390-specific translate DW_CFA_register into SFrame context.
+   Return SFRAME_XLATE_OK if success.  */
+
+static int
+s390_sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx,
+                              struct cfi_insn_data *cfi_insn)
+{
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  gas_assert (cur_fre);
+
+  /* Change the rule for the register indicated by the register number to
+     be the specified register.  Encode the register number as offset by
+     shifting it to the left by one and setting the least-significant bit
+     (LSB).  The LSB can be used to differentiate offsets from register
+     numbers, as offsets from CFA are always a multiple of -8 on s390x.  */
+  if (cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG)
+    sframe_fre_set_bp_track (cur_fre, cfi_insn->u.rr.reg2 << 1 | 1);
+#ifdef SFRAME_FRE_RA_TRACKING
+  else if (sframe_ra_tracking_p ()
+          && cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG)
+    sframe_fre_set_ra_track (cur_fre, cfi_insn->u.rr.reg2 << 1 | 1);
+#endif
+
+  /* Safe to skip.  */
+  return SFRAME_XLATE_OK;
+}
+
 /* Translate DW_CFA_register into SFrame context.
    Return SFRAME_XLATE_OK if success.  */
 
@@ -1159,6 +1190,10 @@ static int
 sframe_xlate_do_register (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
                          struct cfi_insn_data *cfi_insn)
 {
+  /* Conditionally invoke S390-specific implementation.  */
+  if (sframe_get_abi_arch () == SFRAME_ABI_S390_ENDIAN_BIG)
+    return s390_sframe_xlate_do_register (xlate_ctx, cfi_insn);
+
   /* 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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-1.d
new file mode 100644 (file)
index 0000000..7368698
--- /dev/null
@@ -0,0 +1,22 @@
+#objdump: --sframe=.sframe
+#name: SFrame generation on s390 - FP and RA registers saved in FPR registers
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 5
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 26 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+160 +u +u +
+    0+0004 +sp\+160 +u +r16 +
+    0+0008 +sp\+160 +r17 +r16 +
+    0+0014 +sp\+160 +u +r16 +
+    0+0018 +sp\+160 +u +u +
+#pass
index 2b9456be731a8e138f21b94096638f6f739d11df..49d4e4a45afaf88b4d7a5b344286f55e7e8756fd 100644 (file)
@@ -1,6 +1,6 @@
-#name: SFrame generation on s390 - FP and RA saved in register
+#name: SFrame generation on s390 - FP without RA saved in register
 #as: --gsframe
-#warning: skipping SFrame FDE due to .cfi_register specifying FP register
+#warning: skipping SFrame FDE due to FP without RA on stack
 #objdump: --sframe=.sframe
 #...
 Contents of the SFrame section .sframe:
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390-fpra-register-err-2.d
deleted file mode 100644 (file)
index 4c15bd0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#name: SFrame generation on s390 - FP and RA saved in register
-#as: --gsframe
-#warning: skipping SFrame FDE due to .cfi_register specifying RA register
-#objdump: --sframe=.sframe
-#...
-Contents of the SFrame section .sframe:
-
-  Header :
-
-    Version: SFRAME_VERSION_2
-    Flags: NONE
-    Num FDEs: 0
-    Num FREs: 0
-
-#pass
index 67735d437c2a926d56e906cde65d2efd41475f79..77281a189f20129019d2291017a6ff0559a3fa3f 100644 (file)
@@ -110,6 +110,6 @@ if { [istarget "s390x*-*-*"] && [gas_sframe_check] } then {
     run_dump_test "cfi-sframe-s390-err-3"
     run_dump_test "cfi-sframe-s390-fpra-offset-1"
     run_dump_test "cfi-sframe-s390-fpra-offset-err-1"
+    run_dump_test "cfi-sframe-s390-fpra-register-1"
     run_dump_test "cfi-sframe-s390-fpra-register-err-1"
-    run_dump_test "cfi-sframe-s390-fpra-register-err-2"
 }
index 69633d53a33a859e607afe65873b6b7ceb4dd9cb..40ea531314ba5f5dd0a75d5b7b1c80786ebb953a 100644 (file)
@@ -40,6 +40,14 @@ is_sframe_abi_arch_aarch64 (sframe_decoder_ctx *sfd_ctx)
   return aarch64_p;
 }
 
+/* Return TRUE if the SFrame section is associated with the s390 ABIs.  */
+
+static bool
+is_sframe_abi_arch_s390 (sframe_decoder_ctx *sfd_ctx)
+{
+  return sframe_decoder_get_abi_arch (sfd_ctx) == SFRAME_ABI_S390_ENDIAN_BIG;
+}
+
 static void
 dump_sframe_header (sframe_decoder_ctx *sfd_ctx)
 {
@@ -175,7 +183,12 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
 
       /* Dump SP/FP info.  */
       if (err[1] == 0)
-       sprintf (temp, "c%+d", fp_offset);
+       {
+         if (is_sframe_abi_arch_s390 (sfd_ctx) && (fp_offset & 1))
+           sprintf (temp, "r%d", fp_offset >> 1);
+         else
+           sprintf (temp, "c%+d", fp_offset);
+       }
       else
        strcpy (temp, "u");
       printf ("%-10s", temp);
@@ -187,7 +200,12 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
          != SFRAME_CFA_FIXED_RA_INVALID)
        strcpy (temp, "f");
       else if (err[2] == 0)
-       sprintf (temp, "c%+d", ra_offset);
+       {
+         if (is_sframe_abi_arch_s390 (sfd_ctx) && (ra_offset & 1))
+           sprintf (temp, "r%d", ra_offset >> 1);
+         else
+           sprintf (temp, "c%+d", ra_offset);
+       }
       else
        strcpy (temp, "u");