]> 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)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:59:24 +0000 (15:59 -0700)
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 1badb114770f692814ec973911e1bc72cdf0948c..5e29e72169ff7e609a4f51f672494a0f21dcd828 100644 (file)
@@ -5363,6 +5363,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 ();
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_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.
@@ -5712,13 +5739,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 12daa98826de858355d0a44e95f307f8387e1b90..47fd6a6ac412c33b93aa076034b529ca3f9f91ff 100644 (file)
@@ -1366,22 +1366,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"));