From 9ba620e80588587559deab28a17b99bcf3fa5d02 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Wed, 6 Jul 2022 14:29:36 -0700 Subject: [PATCH] regcache: Add support for register tags. 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 | 69 ++++++++++++++++++++++++++++++++++-- gdb/regcache.h | 15 ++++++++ gdbsupport/common-regcache.h | 6 ++++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/gdb/regcache.c b/gdb/regcache.c index 47fd6a6ac41..0bd5a2a1632 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -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 diff --git a/gdb/regcache.h b/gdb/regcache.h index 1dbba5ce9af..f905f511418 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -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_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. */ diff --git a/gdbsupport/common-regcache.h b/gdbsupport/common-regcache.h index ca1a51bb649..f4033fe347d 100644 --- a/gdbsupport/common-regcache.h +++ b/gdbsupport/common-regcache.h @@ -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. */ -- 2.47.2