]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Introduce capability pseudo registers
authorLuis Machado <luis.machado@linaro.org>
Wed, 8 Dec 2021 18:47:27 +0000 (15:47 -0300)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:59:24 +0000 (15:59 -0700)
Introduce corresponding C pseudo registers that contain the following
fields:

type = struct __gdb_builtin_type_capability {
    uint64_t l;
    uint64_t u;
    bool t;
}

For each register of the C set, users can reference the pseudo registers by
adding a 'p' prefix.  For example, the pseudo register of c0 and pcc are pc0
and ppcc.

Users can set the entire 129 bits of the capability this way, if the
cheri.ptrace_forge_cap flag is enabled.

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

index a7609b3c1c59c266b7206012ccc80de7136814f4..1badb114770f692814ec973911e1bc72cdf0948c 100644 (file)
@@ -342,6 +342,17 @@ static const char *const aarch64_mte_register_names[] =
   "tag_ctl"
 };
 
+/* The capability pseudo registers.  These contain the same information
+   as the C registers, but broken up in 3 pieces.  */
+static const char *const aarch64_c_pseudo_register_names[] =
+{
+  "pc0", "pc1", "pc2", "pc3", "pc4", "pc5", "pc6", "pc7",
+  "pc8", "pc9", "pc10", "pc11", "pc12", "pc13", "pc14", "pc15",
+  "pc16", "pc17", "pc18", "pc19", "pc20", "pc21", "pc22", "pc23",
+  "pc24", "pc25", "pc26", "pc27", "pc28", "pc29", "pc30", "pcsp",
+  "ppcc", "pddc", "pctpidr", "prcsp", "prddc", "prctpidr", "pcid"
+};
+
 /* AArch64 prologue cache structure.  */
 struct aarch64_prologue_cache
 {
@@ -2038,7 +2049,7 @@ set_register_tag (struct gdbarch *gdbarch, struct regcache *regcache,
     regnum = tdep->cap_reg_pcc;
 
   int shift = regnum - tdep->cap_reg_base;
-  tag_map |= (1 << shift);
+  tag_map = _set_bit (tag_map, shift, tag ? 1 : 0);
   regcache->cooked_write (tdep->cap_reg_last - 1, (gdb_byte *) &tag_map);
 }
 
@@ -3219,6 +3230,39 @@ aarch64_vnv_type (struct gdbarch *gdbarch)
   return tdep->vnv_type;
 }
 
+/* Return the type for a capability pseudo register.  */
+
+static struct type *
+morello_capability_pseudo_type (struct gdbarch *gdbarch)
+{
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  if (tdep->morello_capability_pseudo_type == NULL)
+    {
+      struct type *t;
+      struct type *elem;
+
+      t = arch_composite_type (gdbarch, "__gdb_builtin_type_capability",
+                              TYPE_CODE_STRUCT);
+
+      /* Lower 64 bits of the capability.  */
+      elem = builtin_type (gdbarch)->builtin_uint64;
+      append_composite_type_field (t, "l", elem);
+
+      /* Upper 64 bits of the capability.  */
+      elem = builtin_type (gdbarch)->builtin_uint64;
+      append_composite_type_field (t, "u", elem);
+
+      /* Tag bit of the capability.  */
+      elem = builtin_type (gdbarch)->builtin_bool;
+      append_composite_type_field (t, "t", elem);
+
+      tdep->morello_capability_pseudo_type = t;
+    }
+
+  return tdep->morello_capability_pseudo_type;
+}
+
 /* Implement the "dwarf2_reg_to_regnum" gdbarch method.  */
 
 static int
@@ -4038,6 +4082,17 @@ aarch64_gen_return_address (struct gdbarch *gdbarch,
 }
 \f
 
+static bool is_capability_pseudo (gdbarch *gdbarch, int regnum)
+{
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  if (tdep->has_capability () && regnum >= tdep->cap_pseudo_base
+      && regnum < tdep->cap_pseudo_base + tdep->cap_pseudo_count)
+    return true;
+
+  return false;
+}
+
 /* Return the pseudo register name corresponding to register regnum.  */
 
 static const char *
@@ -4147,6 +4202,14 @@ aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
   if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
     return "";
 
+  /* Pseudo capability registers.  */
+  if (is_capability_pseudo (gdbarch, regnum))
+    {
+      int c_regnum = regnum - tdep->cap_pseudo_base;
+
+      return aarch64_c_pseudo_register_names[c_regnum];
+    }
+
   internal_error (__FILE__, __LINE__,
                  _("aarch64_pseudo_register_name: bad register number %d"),
                  p_regnum);
@@ -4183,6 +4246,10 @@ aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
   if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
     return builtin_type (gdbarch)->builtin_uint64;
 
+  /* Pseudo capability registers.  */
+  if (is_capability_pseudo (gdbarch, regnum))
+    return morello_capability_pseudo_type (gdbarch);
+
   internal_error (__FILE__, __LINE__,
                  _("aarch64_pseudo_register_type: bad register number %d"),
                  p_regnum);
@@ -4217,6 +4284,11 @@ aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
   if (tdep->has_pauth () && regnum == tdep->pauth_ra_state_regnum)
     return 0;
 
+  /* The capability pseudo registers are just helper.  They don't belong
+     to any group.  */
+  if (is_capability_pseudo (gdbarch, regnum))
+    return 0;
+
   return group == all_reggroup;
 }
 
@@ -4254,6 +4326,38 @@ aarch64_pseudo_read_value (struct gdbarch *gdbarch, readable_regcache *regcache,
   VALUE_LVAL (result_value) = lval_register;
   VALUE_REGNUM (result_value) = regnum;
 
+  /* Read the capability pseudo registers.  */
+  if (is_capability_pseudo (gdbarch, regnum))
+    {
+      gdb_byte lower_bytes[8];
+      gdb_byte upper_bytes[8];
+
+      int c_regnum = regnum - tdep->cap_pseudo_base;
+      /* Fetch the corresponding C register this pseudo register maps to.  */
+      int c_real_regnum = tdep->cap_reg_base + c_regnum;
+
+      /* Read the lower 64 bits.  */
+      if (regcache->raw_read_part (c_real_regnum, 0,
+                                  8, lower_bytes) != REG_VALID)
+       mark_value_bytes_unavailable (result_value, 0, 8);
+      else
+       memcpy (value_contents_raw (result_value).data (), lower_bytes, 8);
+
+      /* Read the upper 64 bits.  */
+      if (regcache->raw_read_part (c_real_regnum, 8,
+                                  8, upper_bytes) != REG_VALID)
+       mark_value_bytes_unavailable (result_value, 0, 8);
+      else
+       memcpy (value_contents_raw (result_value).data () + 8, upper_bytes, 8);
+
+      bool tag = gdbarch_register_tag (gdbarch, regcache, c_real_regnum);
+      memcpy (value_contents_raw (result_value).data () + 16, &tag, 1);
+
+      /* If we are dealing with the tag pseudo register, we need to isolate the
+        specific tag we're dealing with.  */
+      return result_value;
+    }
+
   regnum -= gdbarch_num_regs (gdbarch);
 
   if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
@@ -4319,6 +4423,32 @@ aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
                      int regnum, const gdb_byte *buf)
 {
   aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  /* Write the capability pseudo registers.  */
+  if (is_capability_pseudo (gdbarch, regnum))
+    {
+      gdb_byte lower_bytes[8];
+      gdb_byte upper_bytes[8];
+      gdb_byte tag;
+
+      /* Copy over the different fields.  */
+      memcpy (lower_bytes, buf, 8);
+      memcpy (upper_bytes, buf + 8, 8);
+      memcpy (&tag, buf + 16, 1);
+
+      /* Fetch the capability pseudo register index.  */
+      int c_regnum = regnum - tdep->cap_pseudo_base;
+      /* Fetch the actual C register this pseudo register maps to.  */
+      int c_real_regnum = tdep->cap_reg_base + c_regnum;
+
+      regcache->raw_write_part (c_real_regnum, 0, 8, lower_bytes);
+      regcache->raw_write_part (c_real_regnum, 8, 8, upper_bytes);
+
+      set_register_tag (gdbarch, regcache, c_real_regnum,
+                       (tag != 0)? true : false);
+      return;
+    }
+
   regnum -= gdbarch_num_regs (gdbarch);
 
   if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
@@ -5414,6 +5544,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.capability");
   int first_cap_regnum = -1;
   int last_cap_regnum = -1;
+  int first_cap_pseudo = -1;
 
   if (feature_capability != nullptr)
     {
@@ -5427,6 +5558,18 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
       last_cap_regnum = first_cap_regnum + i - 1;
       num_regs += i;
+
+      /* Also add pseudo registers to make it easier to set the whole 129
+        bits of the C registers.  Each C register is broken into 3 fields:
+
+        - lower 64 bits: Contains the value (pointer).
+        - upper 64 bits: Contains the bounds/permissions/flags.
+        - tag bit (1 bit): Contains the capability tag.
+      */
+
+      first_cap_pseudo = num_pseudo_regs;
+      /* 39 pseudo capability registers.  */
+      num_pseudo_regs += AARCH64_C_PSEUDO_COUNT;
     }
 
   if (!valid_p)
@@ -5619,6 +5762,12 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        user_reg_add (gdbarch, aarch64_morello_register_aliases[i].name,
                      value_of_aarch64_user_reg,
                      &aarch64_morello_register_aliases[i].regnum);
+
+      num_regs = gdbarch_num_regs (gdbarch);
+      tdep->cap_pseudo_base
+       = (first_cap_pseudo == -1)? -1 : num_regs + first_cap_pseudo;
+      tdep->cap_pseudo_count
+       = (first_cap_pseudo == -1)? 0 : AARCH64_C_PSEUDO_COUNT;
     }
 
   return gdbarch;
index f3241f8e5d47d7283a255d93aee97be6d4733229..04ef40cddf67bc0d8c2fe4117d6c8d64a6de681c 100644 (file)
@@ -63,6 +63,8 @@ struct regset;
 #define AARCH64_X_REGISTER_COUNT 32
 /* Total number of D registers.  */
 #define AARCH64_D_REGISTER_COUNT 32
+/* Total number of Morello pseudo registers.  */
+#define AARCH64_C_PSEUDO_COUNT 39
 
 /* The maximum number of modified instructions generated for one
    single-stepped instruction.  */
@@ -155,6 +157,13 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep
   int cap_reg_pcc;
   /* RCSP register number.  */
   int cap_reg_rcsp;
+  /* First capability pseudo register.  */
+  int cap_pseudo_base;
+  /* Number of capability pseudo registers.  */
+  int cap_pseudo_count;
+
+  /* Types for Morello.  */
+  struct type *morello_capability_pseudo_type;
 
   /* Returns true if the target supports capabilities.  */
   bool has_capability () const