]> 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)
committerLuis Machado <luis.machado@linaro.org>
Tue, 20 Oct 2020 18:06:30 +0000 (15:06 -0300)
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/ChangeLog
gdb/aarch64-tdep.c
gdb/arch-utils.c
gdb/arch-utils.h
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/regcache.c
gdb/valprint.c
gdb/value.c
gdb/value.h

index c480bc8077ca29bd3634a458b3a1127cf5de40e2..a85c361f820357bee8ada0c081fb9c793a351edb 100644 (file)
@@ -1,3 +1,26 @@
+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.
+
 2020-10-20  Luis Machado  <luis.machado@arm.com>
 
        * aarch64-tdep.c: Include elf-bfd.h.
index 1cf1e9ccf237ac5898ae776dce64105959394131..72adec05884ebca0a0b0e68a7ce49455bf276fd2 100644 (file)
@@ -3748,6 +3748,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__);
+
+  struct gdbarch_tdep *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__);
+
+  struct gdbarch_tdep *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.
@@ -4055,6 +4121,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 12e3b8dbbb97ddad3b1ffc9ea626d8c601cf5610..c68add668dbda56b1944c066131f0df0fd2458dc 100644 (file)
@@ -1052,6 +1052,24 @@ default_read_core_file_mappings (struct gdbarch *gdbarch,
 {
 }
 
+/* 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;
+}
+
 void _initialize_gdbarch_utils ();
 void
 _initialize_gdbarch_utils ()
index 8cb0db04c8c4121295a08e2634e6674e43797e22..b23dc17cb337e88110c78c3391be873dcbebf8e6 100644 (file)
@@ -292,4 +292,14 @@ extern void default_read_core_file_mappings (struct gdbarch *gdbarch,
                                                                      const char *filename,
                                                                      const void *other)>
                                               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 8bab2d9de9ef5ddbb7fd12886de2399012c1b29d..875b31cb3b3735ae9f740e89281ea6886a3dd3b2 100644 (file)
@@ -355,6 +355,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
@@ -474,6 +476,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;
@@ -733,6 +737,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"),
@@ -1329,6 +1335,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: record_special_symbol = <%s>\n",
                       host_address_to_string (gdbarch->record_special_symbol));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: register_has_tag = <%s>\n",
+                      host_address_to_string (gdbarch->register_has_tag));
   fprintf_unfiltered (file,
                       "gdbarch_dump: register_name = <%s>\n",
                       host_address_to_string (gdbarch->register_name));
@@ -1338,6 +1347,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: register_sim_regno = <%s>\n",
                       host_address_to_string (gdbarch->register_sim_regno));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: register_tag = <%s>\n",
+                      host_address_to_string (gdbarch->register_tag));
   fprintf_unfiltered (file,
                       "gdbarch_dump: register_to_value = <%s>\n",
                       host_address_to_string (gdbarch->register_to_value));
@@ -5300,6 +5312,40 @@ 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;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules.  */
index fd9692d16846eed535e8fd806381b23859a62363..bcce5060ad017debdad4bce719f26b193c76907f 100644 (file)
@@ -1664,6 +1664,20 @@ typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, s
 extern void gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd,gdb::function_view<void (ULONGEST count)> pre_loop_cb,gdb::function_view<void (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs, const char *filename, const void *other)> 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);
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 
 
index 08ad20f26494ffc2b96ee0e001718f236b221af3..d0b58eca60e2509774168685c2c70d1449965444 100755 (executable)
@@ -1196,6 +1196,13 @@ f;std::string;get_pc_address_flags;frame_info *frame, CORE_ADDR pc;frame, pc;;de
 # Read core file mappings
 m;void;read_core_file_mappings;struct bfd *cbfd,gdb::function_view<void (ULONGEST count)> pre_loop_cb,gdb::function_view<void (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs, const char *filename, const void *other)> loop_cb;cbfd, pre_loop_cb, loop_cb;;default_read_core_file_mappings;;0
 
+# Returns true if register COOKEDNUM has a tag and false otherwise.
+# The default is to always return false.
+m;bool;register_has_tag;readable_regcache *regcache, int cookednum;regcache, cookednum;;default_register_has_tag;;0
+# Returns true if the register tag bit is 1 and false otherwise.
+# The default is to always return false.
+m;bool;register_tag;readable_regcache *regcache, int cookednum;regcache, cookednum;;default_register_tag;;0
+
 EOF
 }
 
index 91d3202b94baa87573c1b903bd6759dd83f99981..778b8f61dad62b9bf8b5626c7d808f01fed5cbb9 100644 (file)
@@ -749,6 +749,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 6e1672a3dcad07237219852570486d19dfb9d127..048512d31087f51ba89dc45780bc5207fc60d251 100644 (file)
@@ -485,17 +485,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);
   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 ef2ebf09ef5d23c584da8329c02a4c953accd3e0..01f47af7466ee0938762d97d2236043cdafb6f16 100644 (file)
@@ -178,6 +178,7 @@ struct value
       lazy (1),
       initialized (1),
       stack (0),
+      tagged (0),
       type (type_),
       enclosing_type (type_)
   {
@@ -228,6 +229,9 @@ struct value
      used instead of read_memory to enable extra caching.  */
   unsigned int stack : 1;
 
+  /* Whether the value has a tag bit.  */
+  unsigned int tagged : 1;
+
   /* Location of value (if lval).  */
   union
   {
@@ -336,6 +340,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.  NULL or not
      valid if lazy is nonzero.  */
   gdb::unique_xmalloc_ptr<gdb_byte> contents;
@@ -1331,6 +1338,10 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
          value_contents_all_raw (src) + src_offset * unit_size,
          length * unit_size);
 
+  /* 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;
@@ -1385,6 +1396,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;
+}
+
 const gdb_byte *
 value_contents (struct value *value)
 {
@@ -1489,6 +1512,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)
 {
@@ -1690,6 +1725,8 @@ value_copy (struct value *arg)
   val->embedded_offset = value_embedded_offset (arg);
   val->pointed_to_offset = arg->pointed_to_offset;
   val->modifiable = arg->modifiable;
+  val->tagged = arg->tagged;
+  val->tag = arg->tag;
   if (!value_lazy (val))
     {
       memcpy (value_contents_all_raw (val), value_contents_all_raw (arg),
index f7d57d125421d68963db2090a57ab284be1fb206..90a361c0168485fdb1ace075aa8af55de26dbc83 100644 (file)
@@ -240,6 +240,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).
 
@@ -334,6 +337,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.  */