]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
regcache: Add support for register tags.
authorJohn Baldwin <jhb@FreeBSD.org>
Wed, 6 Jul 2022 21:29:36 +0000 (14:29 -0700)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 23:43:05 +0000 (16:43 -0700)
If a register's type is tagged, then allocate a byte in the register
cache buffer to hold the tag.  Separate methods are provided for
supplying and collecting the tag as a bool.

gdb/regcache.c
gdb/regcache.h
gdbsupport/common-regcache.h

index 47fd6a6ac412c33b93aa076034b529ca3f9f91ff..0bd5a2a1632a1e76f1474fa8519c13b7e7099cfd 100644 (file)
@@ -71,6 +71,12 @@ struct regcache_descr
   long *register_offset;
   long *sizeof_register;
 
+  /* Offset (in 8 bit bytes), of each register's tag in the register
+     cache.  All registers (including those in the range
+     [NR_RAW_REGISTERS .. NR_COOKED_REGISTERS) are given an
+     offset.  */
+  long *register_tag_offset;
+
   /* Cached table containing the type of each register.  */
   struct type **register_type;
 };
@@ -115,11 +121,18 @@ init_regcache_descr (struct gdbarch *gdbarch)
       = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
     descr->register_offset
       = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+    descr->register_tag_offset
+      = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
     for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
       {
        descr->sizeof_register[i] = TYPE_LENGTH (descr->register_type[i]);
        descr->register_offset[i] = offset;
        offset += descr->sizeof_register[i];
+       if (descr->register_type[i]->is_tagged ())
+         {
+           descr->register_tag_offset[i] = offset;
+           offset++;
+         }
       }
     /* Set the real size of the raw register cache buffer.  */
     descr->sizeof_raw_registers = offset;
@@ -129,6 +142,11 @@ init_regcache_descr (struct gdbarch *gdbarch)
        descr->sizeof_register[i] = TYPE_LENGTH (descr->register_type[i]);
        descr->register_offset[i] = offset;
        offset += descr->sizeof_register[i];
+       if (descr->register_type[i]->is_tagged ())
+         {
+           descr->register_tag_offset[i] = offset;
+           offset++;
+         }
       }
     /* Set the real size of the readonly register cache buffer.  */
     descr->sizeof_cooked_registers = offset;
@@ -170,6 +188,12 @@ register_size (struct gdbarch *gdbarch, int regnum)
   return size;
 }
 
+bool
+register_has_tag (struct gdbarch *gdbarch, int regnum)
+{
+  return register_type (gdbarch, regnum)->is_tagged ();
+}
+
 /* See gdbsupport/common-regcache.h.  */
 
 int
@@ -233,6 +257,14 @@ reg_buffer::register_buffer (int regnum) const
   return m_registers.get () + m_descr->register_offset[regnum];
 }
 
+/* Return a pointer to register REGNUM's tag buffer.  */
+
+gdb_byte *
+reg_buffer::register_tag (int regnum) const
+{
+  return m_registers.get () + m_descr->register_tag_offset[regnum];
+}
+
 void
 reg_buffer::save (register_read_ftype cooked_read)
 {
@@ -317,6 +349,13 @@ reg_buffer::assert_regnum (int regnum) const
     gdb_assert (regnum < gdbarch_num_regs (arch ()));
 }
 
+void
+reg_buffer::assert_tagged (int regnum) const
+{
+  assert_regnum (regnum);
+  gdb_assert (m_descr->register_type[regnum]->is_tagged ());
+}
+
 /* Type to map a ptid to a list of regcaches (one thread may have multiple
    regcaches, associated to different gdbarches).  */
 
@@ -750,11 +789,11 @@ 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))
+      if (register_has_tag (m_descr->gdbarch, regnum))
        {
          set_value_tagged (result, 1);
 
-         bool tag = gdbarch_register_tag (m_descr->gdbarch, this, regnum);
+         bool tag = raw_collect_tag (regnum);
          set_value_tag (result, tag);
        }
 
@@ -1078,6 +1117,19 @@ reg_buffer::raw_supply (int regnum, const void *buf)
     }
 }
 
+/* See gdbsupport/common-regcache.h.  */
+
+void
+reg_buffer::raw_supply_tag (int regnum, bool tag)
+{
+  gdb_byte *tagbuf;
+
+  assert_tagged (regnum);
+
+  tagbuf = register_tag (regnum);
+  *tagbuf = tag;
+}
+
 /* See regcache.h.  */
 
 void
@@ -1131,6 +1183,19 @@ reg_buffer::raw_collect (int regnum, void *buf) const
   memcpy (buf, regbuf, size);
 }
 
+/* See gdbsupport/common-regcache.h.  */
+
+bool
+reg_buffer::raw_collect_tag (int regnum) const
+{
+  const gdb_byte *tagbuf;
+
+  assert_tagged (regnum);
+
+  tagbuf = register_tag (regnum);
+  return (*tagbuf != 0);
+}
+
 /* See regcache.h.  */
 
 void
index 1dbba5ce9af0637ccb7c2a34946e35a0927140e3..f905f511418346d6bcdbb04a7c8033ecc285540b 100644 (file)
@@ -171,6 +171,10 @@ extern struct type *register_type (struct gdbarch *gdbarch, int regnum);
    
 extern int register_size (struct gdbarch *gdbarch, int regnum);
 
+/* Return true if register REGNUM is tagged.  */
+
+extern bool register_has_tag (struct gdbarch *gdbarch, int regnum);
+
 typedef gdb::function_view<register_status (int regnum, gdb_byte *buf)>
   register_read_ftype;
 
@@ -200,6 +204,9 @@ public:
   /* See gdbsupport/common-regcache.h.  */
   void raw_collect (int regnum, void *buf) const override;
 
+  /* See gdbsupport/common-regcache.h.  */
+  bool raw_collect_tag (int regnum) const override;
+
   /* Collect register REGNUM from REGCACHE.  Store collected value as an integer
      at address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED.
      If ADDR_LEN is greater than the register size, then the integer will be
@@ -220,6 +227,9 @@ public:
     raw_supply (regnum, src.register_buffer (regnum));
   }
 
+  /* See gdbsupport/common-regcache.h.  */
+  void raw_supply_tag (int regnum, bool tag) override;
+
   /* Supply register REGNUM to REGCACHE.  Value to supply is an integer stored
      at address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED.
      If the register size is greater than ADDR_LEN, then the integer will be
@@ -248,10 +258,15 @@ protected:
   /* Assert on the range of REGNUM.  */
   void assert_regnum (int regnum) const;
 
+  /* Assert that register REGNUM is tagged.  */
+  void assert_tagged (int regnum) const;
+
   int num_raw_registers () const;
 
   gdb_byte *register_buffer (int regnum) const;
 
+  gdb_byte *register_tag (int regnum) const;
+
   /* Save a register cache.  The set of registers saved into the
      regcache determined by the save_reggroup.  COOKED_READ returns
      zero iff the register's value can't be returned.  */
index ca1a51bb6491836ec33df3b60c16d20c50ad6b49..f4033fe347dd2388404e0aa5f5164e9645d8a41f 100644 (file)
@@ -78,9 +78,15 @@ struct reg_buffer_common
   /* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE.  */
   virtual void raw_supply (int regnum, const void *buf) = 0;
 
+  /* Supply tag for register REGNUM.  Only valid for tagged registers.  */
+  virtual void raw_supply_tag (int regnum, bool tag) = 0;
+
   /* Collect register REGNUM from REGCACHE and store its contents in BUF.  */
   virtual void raw_collect (int regnum, void *buf) const = 0;
 
+  /* Return tag for register REGNUM.  Only valid for tagged registers.  */
+  virtual bool raw_collect_tag (int regnum) const = 0;
+
   /* Compare the contents of the register stored in the regcache (ignoring the
      first OFFSET bytes) to the contents of BUF (without any offset).  Returns
      true if the same.  */