]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Adjust PCC bounds when calling a function by hand in AAPCS64-CAP
authorLuis Machado <luis.machado@linaro.org>
Wed, 1 Dec 2021 11:23:24 +0000 (08:23 -0300)
committerLuis Machado <luis.machado@linaro.org>
Fri, 14 Jan 2022 14:29:52 +0000 (11:29 -0300)
For dynamically-linked binaries using the AAPCS64-CAP ABI, the PCC bounds for
distinct DSO's can be different, and that needs to be taken into account.

Since there isn't a good interface for GDB to fetch the precise bounds (the
.plt.got could be used for this, but doesn't contain data for symbols not
being used by the program), we use maximum bounds and the existing PCC
permissions.

This allows GDB to call functions by hand in AAPCS64-CAP mode.

Also, revert a previous change to do partial writes (lower 64 bits) of the
PCC, as this isn't needed anymore.

gdb/aarch64-tdep.c
gdb/regcache.c

index 49ecc57da7f71e06e20bfe8434ac4bb7a6a5d3f6..2928bc6d44bf27dbd3fbfd289f979966fbb7df07 100644 (file)
@@ -5298,6 +5298,33 @@ aarch64_register_tag (struct gdbarch *gdbarch,
   return true;
 }
 
+/* Morello-specific hook to write the PC.  This is mostly used when calling
+   a function by hand.  Different DSO's have different bounds for PCC, so GDB
+   would need to figure out those bounds.
+
+   Given that information is not currently available, we set maximum bounds
+   for PCC as a compromise.  */
+
+static void
+morello_write_pc (struct regcache *regs, CORE_ADDR pc)
+{
+  struct gdbarch *gdbarch = regs->arch ();
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  regs->cooked_write_part (tdep->cap_reg_pcc, 0, sizeof (pc),
+                          (const gdb_byte *) &pc);
+
+  /* Upper 64 bits of the capability with maximum bounds and reasonable
+     permissions.  We only adjust this if we are using the purecap ABI.  */
+  pc = 0xffffc00000010005;
+  regs->cooked_write_part (tdep->cap_reg_pcc, 8, sizeof (pc),
+                          (const gdb_byte *) &pc);
+
+  /* We may need to set the tag of the PCC here, but we don't do so at the
+     moment.  If this turns out to be a problem in the future, we should
+     force the tag to 1.  */
+}
+
 /* Initialize the current architecture based on INFO.  If possible,
    re-use an architecture from ARCHES, which is a list of
    architectures already created during this debugging session.
@@ -5605,13 +5632,21 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Set address class hooks for capabilities.  */
   if (feature_capability)
     {
-      set_gdbarch_sp_regnum (gdbarch, tdep->cap_reg_csp);
-      set_gdbarch_pc_regnum (gdbarch, tdep->cap_reg_pcc);
-
-      /* Morello-specific implementations for function calls and returning
-        of results.  */
-      set_gdbarch_push_dummy_call (gdbarch, morello_push_dummy_call);
-      set_gdbarch_return_value (gdbarch, morello_return_value);
+      if (have_capability)
+       {
+         /* These hooks only make sense if we are using the AAPCS64-CAP
+            ABI.  */
+         set_gdbarch_sp_regnum (gdbarch, tdep->cap_reg_csp);
+         set_gdbarch_pc_regnum (gdbarch, tdep->cap_reg_pcc);
+
+         /* Hook to adjust the PCC bounds.  */
+         set_gdbarch_write_pc (gdbarch, morello_write_pc);
+
+         /* Morello-specific implementations for function calls and returning
+            of results.  */
+         set_gdbarch_push_dummy_call (gdbarch, morello_push_dummy_call);
+         set_gdbarch_return_value (gdbarch, morello_return_value);
+       }
 
       /* Address manipulation.  */
       set_gdbarch_addr_bits_remove (gdbarch, aarch64_addr_bits_remove);
index 40247816a2c24637d0d82c7ef1ad50552e1577a4..1ebe12449aaa39cb1045c21b9e5a827030dd80fb 100644 (file)
@@ -1335,22 +1335,11 @@ regcache_write_pc (struct regcache *regcache, CORE_ADDR pc)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   int regnum = gdbarch_pc_regnum (gdbarch);
-  int reg_size = register_size (gdbarch, regnum);
 
   if (gdbarch_write_pc_p (gdbarch))
     gdbarch_write_pc (gdbarch, regcache, pc);
   else if (gdbarch_pc_regnum (gdbarch) >= 0)
-    {
-      /* If our PC is bigger than a CORE_ADDR, only modify the required
-        bits.  Leave the unmodified bits alone.  */
-      if (reg_size > sizeof (pc))
-       regcache->cooked_write_part (regnum, 0, sizeof (pc),
-                                    (const gdb_byte *) &pc);
-      else
-       {
-         regcache_cooked_write_unsigned (regcache, regnum, pc);
-       }
-    }
+    regcache_cooked_write_unsigned (regcache, regnum, pc);
   else
     internal_error (__FILE__, __LINE__,
                    _("regcache_write_pc: Unable to update PC"));