]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[General/Morello] Fetch and display register capability tags correctly
authorLuis Machado <luis.machado@arm.com>
Thu, 8 Oct 2020 09:14:37 +0000 (06:14 -0300)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:53:22 +0000 (15:53 -0700)
This patch teaches GDB how to print the capability tag from registers.

gdb/ChangeLog:

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

* aarch64-tdep.c (aarch64_register_has_tag, aarch64_register_tag): New
functions.
(aarch64_gdbarch_init): Register hooks.
* arch-utils.c (default_register_has_tag, default_register_tag): New
functions.
* arch-utils.h (default_register_has_tag, default_register_tag): New
prototypes.
* gdbarch.c: Regenerate.
* gdbarch.h: Likewise.
* gdbarch.sh (register_has_tag, register_tag): New gdbarch hooks.
* regcache.c (readable_regcache::cooked_read_value): Fetch the tag
metadata from registers.
* valprint.c (generic_value_print_capability): Display register tags.
* value.c (struct value) <tagged, tag>: New fields.
(value_contents_copy_raw): Handle tags.
(value_tagged, set_value_tagged, value_tag, set_value_tag): New
functions.
(value_copy): Handle tags.
* value.h (value_tagged, set_value_tagged, value_tag)
(set_value_tag): New prototypes.

gdb/aarch64-tdep.c
gdb/arch-utils.c
gdb/arch-utils.h
gdb/gdbarch-components.py
gdb/gdbarch-gen.h
gdb/gdbarch.c
gdb/gdbarch.h
gdb/regcache.c
gdb/valprint.c
gdb/value.c
gdb/value.h

index 47445774987ce12df1a6b63a608b1202d13ea921..6ef8b2751bcb174b3df367786fe496526c495a69 100644 (file)
@@ -3818,6 +3818,72 @@ aarch64_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile,
                  name);
 }
 
+/* Implements the gdbarch_register_has_tag hook.  */
+
+static bool
+aarch64_register_has_tag (struct gdbarch *gdbarch,
+                         readable_regcache *regcache,
+                         int regnum)
+{
+  if (aarch64_debug)
+    debug_printf ("%s: Entering\n", __func__);
+
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  /* Only Morello's registers have tags.  */
+  if (!tdep->has_capability ())
+    return false;
+
+  /* The last two registers of the C register set don't have tags.  */
+  if (regnum < tdep->cap_reg_base ||
+      regnum > tdep->cap_reg_last - 2)
+    return false;
+
+  if (aarch64_debug)
+    debug_printf ("%s: regnum %d\n", __func__, regnum);
+
+  return true;
+}
+
+/* Implements the gdbarch_register_tag hook.  */
+
+static bool
+aarch64_register_tag (struct gdbarch *gdbarch,
+                     readable_regcache *regcache,
+                     int regnum)
+{
+  if (aarch64_debug)
+    debug_printf ("%s: Entering\n", __func__);
+
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  /* Only Morello's registers have tags.  */
+  if (!tdep->has_capability ())
+    return false;
+
+  /* The last two registers of the C register set don't have tags.  */
+  if (regnum < tdep->cap_reg_base ||
+      regnum > tdep->cap_reg_last - 2)
+    return false;
+
+  /* Find the proper bit within the tag_map.  */
+  int shift = regnum - tdep->cap_reg_base;
+  ULONGEST tag_map = 0;
+
+  /* Fetch the tag_map register.  */
+  regcache->cooked_read (tdep->cap_reg_last - 1, &tag_map);
+
+  if (aarch64_debug)
+    debug_printf ("%s: regnum %d, shift %d, tag bit %ld, tag_map %lx\n",
+                 __func__, regnum, shift,
+                 (tag_map >> shift) & 1, tag_map);
+
+  if (((tag_map >> shift) & 1) == 0)
+    return false;
+
+  return true;
+}
+
 /* 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.
@@ -4167,6 +4233,10 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_record_special_symbol (gdbarch,
                                         aarch64_record_special_symbol);
 
+      /* For fetching register tag information.  */
+      set_gdbarch_register_has_tag (gdbarch, aarch64_register_has_tag);
+      set_gdbarch_register_tag (gdbarch, aarch64_register_tag);
+
       /* Create the Morello register aliases.  */
       /* cip0 and cip1 */
       aarch64_morello_register_aliases[0].regnum = tdep->cap_reg_base + 16;
index 3ee978a02498ef37a2c09c35ae483842afb1bad9..46af565f324b7eb6af9c4b7d62ec4376a199457b 100644 (file)
@@ -1092,6 +1092,24 @@ default_read_core_file_mappings
 {
 }
 
+/* See arch-utils.h.  */
+bool
+default_register_has_tag (struct gdbarch *gdbarch,
+                         readable_regcache *regcache,
+                         int cookednum)
+{
+  return false;
+}
+
+/* See arch-utils.h.  */
+bool
+default_register_tag (struct gdbarch *gdbarch,
+                     readable_regcache *regcache,
+                     int cookednum)
+{
+  return false;
+}
+
 /* Static function declarations */
 
 static void alloc_gdbarch_data (struct gdbarch *);
index f850e5fd6e78371c8ce11ff05a21ef0697644834..67d96e529f8b898611e2c8591e583e6d3ceaf50f 100644 (file)
@@ -300,4 +300,14 @@ extern void default_read_core_file_mappings
    struct bfd *cbfd,
    read_core_file_mappings_pre_loop_ftype pre_loop_cb,
    read_core_file_mappings_loop_ftype loop_cb);
+
+/* Default implementation of gdbarch_register_has_tag.  */
+extern bool default_register_has_tag (struct gdbarch *gdbarch,
+                                     readable_regcache *regcache,
+                                     int cookednum);
+
+/* Default implementation of gdbarch_register_tag.  */
+extern bool default_register_tag (struct gdbarch *gdbarch,
+                                 readable_regcache *regcache,
+                                 int cookednum);
 #endif /* ARCH_UTILS_H */
index 516707129042624ffdeb3793e961ea7981ca6e07..811f3636e7e9b0e58b4d38ac557a22dbd3f285c8 100644 (file)
@@ -2702,3 +2702,33 @@ Read core file mappings
     predefault="default_read_core_file_mappings",
     invalid=False,
 )
+
+Method(
+    comment="""
+Returns true if register COOKEDNUM has a tag and false otherwise.
+The default is to always return false.
+""",
+    type="bool",
+    name="register_has_tag",
+    params=[
+        ("readable_regcache *", "regcache"),
+        ("int", "cookednum"),
+    ],
+    predefault="default_register_has_tag",
+    invalid=False,
+)
+
+Method(
+    comment="""
+Returns true if the register tag bit is 1 and false otherwise.
+The default is to always return false.
+""",
+    type="bool",
+    name="register_tag",
+    params=[
+        ("readable_regcache *", "regcache"),
+        ("int", "cookednum"),
+    ],
+    predefault="default_register_tag",
+    invalid=False,
+)
index 4dd66f58631e3b85e4156ffd917de83e4103132c..47b77558f09f8a91fd63e56b8d942ddec93e0ba5 100644 (file)
@@ -1658,3 +1658,17 @@ extern void set_gdbarch_get_pc_address_flags (struct gdbarch *gdbarch, gdbarch_g
 typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
 extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb);
 extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarch_read_core_file_mappings_ftype *read_core_file_mappings);
+
+/* Returns true if register COOKEDNUM has a tag and false otherwise.
+   The default is to always return false. */
+
+typedef bool (gdbarch_register_has_tag_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern bool gdbarch_register_has_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern void set_gdbarch_register_has_tag (struct gdbarch *gdbarch, gdbarch_register_has_tag_ftype *register_has_tag);
+
+/* Returns true if the register tag bit is 1 and false otherwise.
+   The default is to always return false. */
+
+typedef bool (gdbarch_register_tag_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern bool gdbarch_register_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern void set_gdbarch_register_tag (struct gdbarch *gdbarch, gdbarch_register_tag_ftype *register_tag);
index 7e44134b461642581e9e8f234367d6cc80301fd7..f8baccf05ce0ab4dccacbe66ecdbb5561a16d428 100644 (file)
@@ -255,6 +255,8 @@ struct gdbarch
   gdbarch_type_align_ftype *type_align;
   gdbarch_get_pc_address_flags_ftype *get_pc_address_flags;
   gdbarch_read_core_file_mappings_ftype *read_core_file_mappings;
+  gdbarch_register_has_tag_ftype *register_has_tag;
+  gdbarch_register_tag_ftype *register_tag;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
@@ -379,6 +381,8 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->type_align = default_type_align;
   gdbarch->get_pc_address_flags = default_get_pc_address_flags;
   gdbarch->read_core_file_mappings = default_read_core_file_mappings;
+  gdbarch->register_has_tag = default_register_has_tag;
+  gdbarch->register_tag = default_register_tag;
   /* gdbarch_alloc() */
 
   return gdbarch;
@@ -623,6 +627,8 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of type_align, invalid_p == 0 */
   /* Skip verify of get_pc_address_flags, invalid_p == 0 */
   /* Skip verify of read_core_file_mappings, invalid_p == 0 */
+  /* Skip verify of register_has_tag, invalid_p == 0 */
+  /* Skip verify of register_tag, invalid_p == 0 */
   if (!log.empty ())
     internal_error (__FILE__, __LINE__,
                    _("verify_gdbarch: the following are invalid ...%s"),
@@ -1468,6 +1474,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_filtered (file,
                       "gdbarch_dump: read_core_file_mappings = <%s>\n",
                       host_address_to_string (gdbarch->read_core_file_mappings));
+  fprintf_filtered (file,
+                      "gdbarch_dump: register_has_tag = <%s>\n",
+                      host_address_to_string (gdbarch->register_has_tag));
+  fprintf_filtered (file,
+                      "gdbarch_dump: register_tag = <%s>\n",
+                      host_address_to_string (gdbarch->register_tag));
   if (gdbarch->dump_tdep != NULL)
     gdbarch->dump_tdep (gdbarch, file);
 }
@@ -5464,3 +5476,37 @@ set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch,
 {
   gdbarch->read_core_file_mappings = read_core_file_mappings;
 }
+
+bool
+gdbarch_register_has_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->register_has_tag != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_register_has_tag called\n");
+  return gdbarch->register_has_tag (gdbarch, regcache, cookednum);
+}
+
+void
+set_gdbarch_register_has_tag (struct gdbarch *gdbarch,
+                              gdbarch_register_has_tag_ftype register_has_tag)
+{
+  gdbarch->register_has_tag = register_has_tag;
+}
+
+bool
+gdbarch_register_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->register_tag != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_register_tag called\n");
+  return gdbarch->register_tag (gdbarch, regcache, cookednum);
+}
+
+void
+set_gdbarch_register_tag (struct gdbarch *gdbarch,
+                          gdbarch_register_tag_ftype register_tag)
+{
+  gdbarch->register_tag = register_tag;
+}
index 6404dc1cb438b09e2179ff90c29d6b582f3ee63c..9f1efecb0239f7fa0ad5249a383e45eab1c81f4c 100644 (file)
@@ -142,6 +142,20 @@ using read_core_file_mappings_loop_ftype =
 
 #include "gdbarch-gen.h"
 
+/* Returns true if register COOKEDNUM has a tag and false otherwise.
+   The default is to always return false. */
+
+typedef bool (gdbarch_register_has_tag_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern bool gdbarch_register_has_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern void set_gdbarch_register_has_tag (struct gdbarch *gdbarch, gdbarch_register_has_tag_ftype *register_has_tag);
+
+/* Returns true if the register tag bit is 1 and false otherwise.
+   The default is to always return false. */
+
+typedef bool (gdbarch_register_tag_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern bool gdbarch_register_tag (struct gdbarch *gdbarch, readable_regcache *regcache, int cookednum);
+extern void set_gdbarch_register_tag (struct gdbarch *gdbarch, gdbarch_register_tag_ftype *register_tag);
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 
 
index 00d7a10e2892a3f05b3526263f339242af21bdba..e676ab64d615145417798b4b235dba5aac548dbd 100644 (file)
@@ -750,6 +750,14 @@ readable_regcache::cooked_read_value (int regnum)
        mark_value_bytes_unavailable (result, 0,
                                      TYPE_LENGTH (value_type (result)));
 
+      if (gdbarch_register_has_tag (m_descr->gdbarch, this, regnum))
+       {
+         set_value_tagged (result, 1);
+
+         bool tag = gdbarch_register_tag (m_descr->gdbarch, this, regnum);
+         set_value_tag (result, tag);
+       }
+
       return result;
     }
   else
index 01a4a12b52159eca1611c385be5f18dd6ac5c4d2..2be4e5e4b448b8f8620a6c2b2e064d1dff27bebe 100644 (file)
@@ -500,17 +500,34 @@ generic_value_print_capability (struct value *val, struct ui_file *stream,
                                const struct value_print_options *options)
 {
   struct type *type = check_typedef (value_type (val));
-  int length = TYPE_LENGTH (type);
+  /* Account for the tag bit in the length.  */
+  int length = TYPE_LENGTH (type) + 1;
   const gdb_byte *contents = value_contents_for_printing (val).data ();
   enum bfd_endian byte_order = type_byte_order (type);
+  bool tag = false;
+
+  switch (VALUE_LVAL (val))
+    {
+      case lval_register:
+       if (value_tagged (val))
+         tag = value_tag (val);
+       break;
+      case lval_memory:
+       /* TODO-Morello: Add hook that reads capabilities from memory.  We
+          should use those here to fetch the tag from a memory location.  */
+       tag = true;
+       break;
+      default:
+       break;
+    }
 
   if (options->format && options->format == 'x')
-      print_hex_chars (stream, contents, length, byte_order, 0);
+    print_hex_chars (stream, contents, length, byte_order, 0);
   else
     {
       uint128_t dummy_cap;
       memcpy (&dummy_cap, contents, length);
-      capability cap (dummy_cap, false);
+      capability cap (dummy_cap, tag);
       fprintf_filtered (stream, "%s", cap.to_str ().c_str ());
     }
 
index ab55aaa0c982542dbab9ae0e8b1f11e1eb3c5c68..92769824e619328853e915101f8f15a3e86af07a 100644 (file)
@@ -181,6 +181,7 @@ struct value
       initialized (1),
       stack (0),
       is_zero (false),
+      tagged (0),
       type (type_),
       enclosing_type (type_)
   {
@@ -235,6 +236,9 @@ struct value
      otherwise.  */
   bool is_zero : 1;
 
+  /* Whether the value has a tag bit.  */
+  unsigned int tagged : 1;
+
   /* Location of value (if lval).  */
   union
   {
@@ -343,6 +347,9 @@ struct value
   LONGEST embedded_offset = 0;
   LONGEST pointed_to_offset = 0;
 
+  /* The tag value, if tagged.  */
+  bool tag;
+
   /* Actual contents of the value.  Target byte-order.
 
      May be nullptr if the value is lazy or is entirely optimized out.
@@ -1354,6 +1361,10 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
                                          length * unit_size);
   copy (src_contents, dst_contents);
 
+  /* Copy the tagged and tag metadata.  */
+  set_value_tagged (dst, value_tagged (src));
+  set_value_tag (dst, value_tag (src));
+
   /* Copy the meta-data, adjusted.  */
   src_bit_offset = src_offset * unit_size * HOST_CHAR_BIT;
   dst_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
@@ -1408,6 +1419,18 @@ set_value_stack (struct value *value, int val)
   value->stack = val;
 }
 
+int
+value_tagged (const struct value *value)
+{
+  return value->tagged;
+}
+
+void
+set_value_tagged (struct value *value, int val)
+{
+  value->tagged = val;
+}
+
 gdb::array_view<const gdb_byte>
 value_contents (struct value *value)
 {
@@ -1523,6 +1546,18 @@ set_value_pointed_to_offset (struct value *value, LONGEST val)
   value->pointed_to_offset = val;
 }
 
+bool
+value_tag (const struct value *value)
+{
+  return value->tag;
+}
+
+void
+set_value_tag (struct value *value, bool tag)
+{
+  value->tag = tag;
+}
+
 const struct lval_funcs *
 value_computed_funcs (const struct value *v)
 {
@@ -1727,6 +1762,8 @@ value_copy (const value *arg)
   val->stack = arg->stack;
   val->is_zero = arg->is_zero;
   val->initialized = arg->initialized;
+  val->tagged = arg->tagged;
+  val->tag = arg->tag;
   val->unavailable = arg->unavailable;
   val->optimized_out = arg->optimized_out;
 
index 4cd2044ac7cff23054ed0f23c106a878f2c455f0..e740e3c5ad2f9e2bbede3f6be1a0c60987ef3a5d 100644 (file)
@@ -241,6 +241,9 @@ extern void set_value_pointed_to_offset (struct value *value, LONGEST val);
 extern LONGEST value_embedded_offset (const struct value *value);
 extern void set_value_embedded_offset (struct value *value, LONGEST val);
 
+extern bool value_tag (const struct value *value);
+extern void set_value_tag (struct value *value, bool tag);
+
 /* For lval_computed values, this structure holds functions used to
    retrieve and set the value (or portions of the value).
 
@@ -341,6 +344,9 @@ extern void set_value_lazy (struct value *value, int val);
 extern int value_stack (const struct value *);
 extern void set_value_stack (struct value *value, int val);
 
+extern int value_tagged (const struct value *);
+extern void set_value_tagged (struct value *value, int val);
+
 /* Throw an error complaining that the value has been optimized
    out.  */