]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
aarch64-linux: Use tag_map to populate register tags in the regcache.
authorJohn Baldwin <jhb@FreeBSD.org>
Wed, 6 Jul 2022 23:46:51 +0000 (16:46 -0700)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 23:43:06 +0000 (16:43 -0700)
gdb/aarch64-linux-tdep.c

index ea28ec044a911bb2928df8741311ddaebdaf2163..9f40eed3ef561cce9e2deb0037c81da6549a3674 100644 (file)
@@ -559,24 +559,30 @@ static const struct regcache_map_entry aarch64_linux_fpregmap[] =
     { 0 }
   };
 
-/* Since the C register numbers are determined dynamically, we leave
-   placeholders so we can update the numbers later.  */
-static struct regcache_map_entry aarch64_linux_cregmap[] =
+/* The register numbers are relative to the first capability register
+   number.  Please note the PCC/CSP position in GDB's target
+   description is the inverse of the position in the Linux Kernel's
+   user_morello_state data structure.  This can cause some
+   confusion.  */
+
+static const struct regcache_map_entry aarch64_linux_cregmap[] =
   {
-    { 31, -1, 16 }, /* c0 ... c30 */
-    { 1, -1, 16 }, /* pcc */
-    { 1, -1, 16 }, /* csp */
-    { 1, -1, 16 }, /* ddc */
-    { 1, -1, 16 }, /* ctpidr */
-    { 1, -1, 16 }, /* rcsp */
-    { 1, -1, 16 }, /* rddc */
-    { 1, -1, 16 }, /* rctpidr */
-    { 1, -1, 16 }, /* cid */
-    { 1, -1, 8 },  /* tag_map */
-    { 1, -1, 8 },  /* cctlr */
+    { 31, 0, 16 }, /* c0 ... c30 */
+    { 1, 32, 16 }, /* pcc */
+    { 1, 31, 16 }, /* csp */
+    { 1, 33, 16 }, /* ddc */
+    { 1, 34, 16 }, /* ctpidr */
+    { 1, 35, 16 }, /* rcsp */
+    { 1, 36, 16 }, /* rddc */
+    { 1, 37, 16 }, /* rctpidr */
+    { 1, 38, 16 }, /* cid */
+    { 1, REGCACHE_MAP_SKIP, 8 },  /* tag_map */
+    { 1, 39, 8 },  /* cctlr */
     { 0 }
   };
 
+#define TAG_MAP_OFFSET         (16 * 39)
+
 /* Register set definitions.  */
 
 const struct regset aarch64_linux_gregset =
@@ -591,11 +597,81 @@ const struct regset aarch64_linux_fpregset =
     regcache_supply_regset, regcache_collect_regset
   };
 
+static int
+tag_map_regno(aarch64_gdbarch_tdep *tdep, int idx)
+{
+  switch (idx)
+    {
+    case 31:
+      return (tdep->cap_reg_csp);
+    case 32:
+      return (tdep->cap_reg_pcc);
+    default:
+      return (tdep->cap_reg_base + idx);
+    }
+}
+
 /* The capability register set.  */
+static void
+aarch64_linux_supply_cregset (const struct regset *regset,
+                             struct regcache *regcache,
+                             int regnum, const void *buf, size_t size)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  regcache->supply_regset (regset, tdep->cap_reg_base, regnum, buf, size);
+
+  uint64_t tag_map = extract_unsigned_integer ((const gdb_byte *)buf
+                                              + TAG_MAP_OFFSET, 8,
+                                              gdbarch_byte_order (gdbarch));
+  for (unsigned i = 0; i < 39; i++)
+    {
+      int regno;
+
+      regno = tag_map_regno(tdep, i);
+      if (regnum == -1 || regno == regnum)
+       regcache->raw_supply_tag (tag_map_regno(tdep, i), tag_map & 1);
+      tag_map >>= 1;
+    }
+}
+
+static void
+aarch64_linux_collect_cregset (const struct regset *regset,
+                            const struct regcache *regcache,
+                            int regnum, void *buf, size_t size)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  regcache->collect_regset (regset, tdep->cap_reg_base, regnum, buf, size);
+
+  uint64_t tag_map = extract_unsigned_integer ((const gdb_byte *)buf
+                                              + TAG_MAP_OFFSET, 8,
+                                              gdbarch_byte_order (gdbarch));
+  for (unsigned i = 0; i < 39; i++)
+    {
+      uint64_t mask;
+      int regno;
+
+      regno = tag_map_regno(tdep, i);
+      if (regnum == -1 || regno == regnum)
+       {
+         mask = (uint64_t)1 << i;
+         if (regcache->raw_collect_tag (tag_map_regno(tdep, i)))
+           tag_map |= mask;
+         else
+           tag_map &= ~mask;
+       }
+    }
+  store_unsigned_integer ((gdb_byte *)buf + TAG_MAP_OFFSET, 8,
+                         gdbarch_byte_order (gdbarch), tag_map);
+}
+
 const struct regset aarch64_linux_cregset =
   {
     aarch64_linux_cregmap,
-    regcache_supply_regset, regcache_collect_regset
+    aarch64_linux_supply_cregset, aarch64_linux_collect_cregset
   };
 
 /* The fields in an SVE header at the start of a SVE regset.  */
@@ -2580,22 +2656,6 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
        set_solib_svr4_fetch_link_map_offsets (gdbarch,
                                        svr4_lp64_cheri_fetch_link_map_offsets);
 
-      /* Initialize the register numbers for the core file register set.
-        Please note the PCC/CSP position in GDB's target description is
-        the inverse of the position in the Linux Kernel's user_morello_state
-        data structure.  This can cause some confusion.  */
-      aarch64_linux_cregmap[0].regno = tdep->cap_reg_base;
-      aarch64_linux_cregmap[1].regno = tdep->cap_reg_pcc;
-      aarch64_linux_cregmap[2].regno = tdep->cap_reg_csp;
-
-      /* Set the rest of the registers.  */
-      int next_regnum = tdep->cap_reg_base + 33;
-      for (int i = 3; i <= 10; i++)
-       {
-         aarch64_linux_cregmap[i].regno = next_regnum;
-         next_regnum++;
-       }
-
       set_gdbarch_report_signal_info (gdbarch,
                                      aarch64_linux_report_signal_info);
       set_gdbarch_get_cap_tag_from_address (gdbarch,