]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[Morello] Unwinding: Restore CLR and PCC properly
authorLuis Machado <luis.machado@arm.com>
Fri, 9 Oct 2020 16:50:17 +0000 (13:50 -0300)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:53:22 +0000 (15:53 -0700)
This patch teaches GDB how to handle restoring CLR and PCC values properly.

gdb/ChangeLog:

2020-10-20  Luis Machado  <luis.machado@arm.com>

* aarch64-tdep.c (aarch64_prologue_prev_register): Use LR or CLR
depending on the request.
(aarch64_dwarf_reg_to_regnum): Redirect CLR to LR temporarily.
* aarch64-tdep.h (AARCH64_DWARF_CLR): New constant.

gdb/aarch64-tdep.c
gdb/aarch64-tdep.h

index 7b395dafdb81996f63b128ed23625a83adf9c1da..8900ac816ff2c5ef3547ffd944a6a415b579ea92 100644 (file)
@@ -1280,20 +1280,48 @@ aarch64_prologue_prev_register (struct frame_info *this_frame,
 
   /* If we are asked to unwind the PC, then we need to return the LR
      instead.  The prologue may save PC, but it will point into this
-     frame's prologue, not the next frame's resume location.  */
+     frame's prologue, not the next frame's resume location.
+
+     We do the same for PCC and CLR.  */
   if (prev_regnum == AARCH64_PC_REGNUM || prev_regnum == pcc_regnum)
     {
       CORE_ADDR lr;
       struct gdbarch *gdbarch = get_frame_arch (this_frame);
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
-      lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
+      /* Fetch LR or CLR depending on the ABI.  */
+      int lr_regnum;
+      if (prev_regnum == AARCH64_PC_REGNUM)
+       lr_regnum = AARCH64_LR_REGNUM;
+      else
+       lr_regnum = tdep->cap_reg_base + 30;
+
+      struct value *lr_value = frame_unwind_register_value (this_frame,
+                                                           lr_regnum);
+
+      /* Extract only the bottom 8 bytes of CLR.  This truncates the capability
+        to 8 bytes.  For LR, this gets us the whole register.  */
+      lr = extract_unsigned_integer (value_contents_all (lr_value).data (), 8,
+                                    byte_order);
 
       if (tdep->has_pauth ()
          && cache->saved_regs[tdep->pauth_ra_state_regnum].is_value ())
        lr = aarch64_frame_unmask_lr (tdep, this_frame, lr);
 
+      /* Remove any potential LSB's in the address.  */
       lr = gdbarch_addr_bits_remove (gdbarch, lr);
-      return frame_unwind_got_constant (this_frame, prev_regnum, lr);
+
+      struct value *lr_value_adjusted
+         = frame_unwind_got_constant (this_frame, prev_regnum, lr);
+
+      /* Copy the capability tag over, if it exists.  */
+      if (prev_regnum == pcc_regnum && value_tagged (lr_value))
+       {
+         set_value_tagged (lr_value_adjusted, 1);
+         set_value_tag (lr_value_adjusted, value_tag (lr_value));
+       }
+
+      return lr_value_adjusted;
     }
 
   /* SP is generally not saved to the stack, but this frame is
@@ -2416,6 +2444,10 @@ aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 
   if (tdep->has_capability ())
     {
+      /* FIXME-Morello: Redirect CLR to LR for now.  */
+      if (reg == AARCH64_DWARF_CLR)
+       return AARCH64_LR_REGNUM;
+
       if (reg >= AARCH64_DWARF_C0 && reg <= AARCH64_DWARF_C0 + 30)
        return tdep->cap_reg_base + (reg - AARCH64_DWARF_C0);
 
index 7598df1471e2d1b9962c738b13e1b0a0cd66b940..6a77f98b93c1c95f5b706f933f8221adb767b846 100644 (file)
@@ -43,6 +43,7 @@ struct regset;
 #define AARCH64_DWARF_SVE_P0   48
 #define AARCH64_DWARF_SVE_Z0   96
 #define AARCH64_DWARF_C0  198
+#define AARCH64_DWARF_CLR 228
 #define AARCH64_DWARF_CSP 229
 #define AARCH64_DWARF_PCC 230
 #define AARCH64_DWARF_DDC 231