X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fregcache.c;h=adffa415e5bda2c2c5af9327f8a13ce844561957;hb=refs%2Fheads%2Finferior-thread-map-2019-12-18;hp=082b62e43e598c089fbd88a3d4fe1abf97793711;hpb=796bb0264184e8d9343f041c2f11cb898c0d18ac;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/regcache.c b/gdb/regcache.c index 082b62e43e..adffa415e5 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -1,6 +1,6 @@ /* Cache and manage the values of registers for GDB, the GNU debugger. - Copyright (C) 1986-2018 Free Software Foundation, Inc. + Copyright (C) 1986-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -19,14 +19,14 @@ #include "defs.h" #include "inferior.h" +#include "gdbthread.h" #include "target.h" +#include "test-target.h" #include "gdbarch.h" #include "gdbcmd.h" #include "regcache.h" #include "reggroups.h" -#include "observer.h" -#include "remote.h" -#include "valprint.h" +#include "observable.h" #include "regset.h" #include @@ -87,8 +87,7 @@ init_regcache_descr (struct gdbarch *gdbarch) /* Total size of the register space. The raw registers are mapped directly onto the raw register cache while the pseudo's are either mapped onto raw-registers or memory. */ - descr->nr_cooked_registers = gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch); + descr->nr_cooked_registers = gdbarch_num_cooked_regs (gdbarch); /* Fill in a table of register types. */ descr->register_type @@ -119,7 +118,6 @@ 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]; - gdb_assert (MAX_REGISTER_SIZE >= descr->sizeof_register[i]); } /* Set the real size of the raw register cache buffer. */ descr->sizeof_raw_registers = offset; @@ -129,7 +127,6 @@ 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]; - gdb_assert (MAX_REGISTER_SIZE >= descr->sizeof_register[i]); } /* Set the real size of the readonly register cache buffer. */ descr->sizeof_cooked_registers = offset; @@ -166,14 +163,12 @@ register_size (struct gdbarch *gdbarch, int regnum) struct regcache_descr *descr = regcache_descr (gdbarch); int size; - gdb_assert (regnum >= 0 - && regnum < (gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch))); + gdb_assert (regnum >= 0 && regnum < gdbarch_num_cooked_regs (gdbarch)); size = descr->sizeof_register[regnum]; return size; } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ int regcache_register_size (const struct regcache *regcache, int n) @@ -189,14 +184,15 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo) if (has_pseudo) { - m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_cooked_registers); - m_register_status = XCNEWVEC (signed char, - m_descr->nr_cooked_registers); + m_registers.reset (new gdb_byte[m_descr->sizeof_cooked_registers] ()); + m_register_status.reset + (new register_status[m_descr->nr_cooked_registers] ()); } else { - m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_raw_registers); - m_register_status = XCNEWVEC (signed char, gdbarch_num_regs (gdbarch)); + m_registers.reset (new gdb_byte[m_descr->sizeof_raw_registers] ()); + m_register_status.reset + (new register_status[gdbarch_num_regs (gdbarch)] ()); } } @@ -208,16 +204,12 @@ regcache::regcache (gdbarch *gdbarch, const address_space *aspace_) m_ptid = minus_one_ptid; } -static enum register_status -do_cooked_read (void *src, int regnum, gdb_byte *buf) -{ - struct regcache *regcache = (struct regcache *) src; - - return regcache_cooked_read (regcache, regnum, buf); -} - -readonly_detached_regcache::readonly_detached_regcache (const regcache &src) - : readonly_detached_regcache (src.arch (), do_cooked_read, (void *) &src) +readonly_detached_regcache::readonly_detached_regcache (regcache &src) + : readonly_detached_regcache (src.arch (), + [&src] (int regnum, gdb_byte *buf) + { + return src.cooked_read (regnum, buf); + }) { } @@ -227,58 +219,16 @@ reg_buffer::arch () const return m_descr->gdbarch; } -/* See regcache.h. */ - -ptid_t -regcache_get_ptid (const struct regcache *regcache) -{ - gdb_assert (!ptid_equal (regcache->ptid (), minus_one_ptid)); - - return regcache->ptid (); -} - -/* Cleanup class for invalidating a register. */ - -class regcache_invalidator -{ -public: - - regcache_invalidator (struct regcache *regcache, int regnum) - : m_regcache (regcache), - m_regnum (regnum) - { - } - - ~regcache_invalidator () - { - if (m_regcache != nullptr) - regcache_invalidate (m_regcache, m_regnum); - } - - DISABLE_COPY_AND_ASSIGN (regcache_invalidator); - - void release () - { - m_regcache = nullptr; - } - -private: - - struct regcache *m_regcache; - int m_regnum; -}; - /* Return a pointer to register REGNUM's buffer cache. */ gdb_byte * reg_buffer::register_buffer (int regnum) const { - return m_registers + m_descr->register_offset[regnum]; + return m_registers.get () + m_descr->register_offset[regnum]; } void -reg_buffer::save (regcache_cooked_read_ftype *cooked_read, - void *src) +reg_buffer::save (register_read_ftype cooked_read) { struct gdbarch *gdbarch = m_descr->gdbarch; int regnum; @@ -286,8 +236,8 @@ reg_buffer::save (regcache_cooked_read_ftype *cooked_read, /* It should have pseudo registers. */ gdb_assert (m_has_pseudo); /* Clear the dest. */ - memset (m_registers, 0, m_descr->sizeof_cooked_registers); - memset (m_register_status, 0, m_descr->nr_cooked_registers); + memset (m_registers.get (), 0, m_descr->sizeof_cooked_registers); + memset (m_register_status.get (), REG_UNKNOWN, m_descr->nr_cooked_registers); /* Copy over any registers (identified by their membership in the save_reggroup) and mark them as valid. The full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) range is checked since some architectures need @@ -297,7 +247,7 @@ reg_buffer::save (regcache_cooked_read_ftype *cooked_read, if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup)) { gdb_byte *dst_buf = register_buffer (regnum); - enum register_status status = cooked_read (src, regnum, dst_buf); + enum register_status status = cooked_read (regnum, dst_buf); gdb_assert (status != REG_UNKNOWN); @@ -334,30 +284,18 @@ regcache::restore (readonly_detached_regcache *src) } } -enum register_status -regcache_register_status (const struct regcache *regcache, int regnum) -{ - gdb_assert (regcache != NULL); - return regcache->get_register_status (regnum); -} +/* See gdbsupport/common-regcache.h. */ enum register_status reg_buffer::get_register_status (int regnum) const { assert_regnum (regnum); - return (enum register_status) m_register_status[regnum]; -} - -void -regcache_invalidate (struct regcache *regcache, int regnum) -{ - gdb_assert (regcache != NULL); - regcache->invalidate (regnum); + return m_register_status[regnum]; } void -detached_regcache::invalidate (int regnum) +reg_buffer::invalidate (int regnum) { assert_regnum (regnum); m_register_status[regnum] = REG_UNKNOWN; @@ -379,21 +317,58 @@ reg_buffer::assert_regnum (int regnum) const recording if the register values have been changed (eg. by the user). Therefore all registers must be written back to the target when appropriate. */ -std::forward_list regcache::current_regcache; + +/* Key for the hash map keeping the regcaches. */ + +struct ptid_arch +{ + ptid_arch (ptid_t ptid, gdbarch *arch) + : ptid (ptid), arch (arch) + {} + + ptid_t ptid; + gdbarch *arch; + + bool operator== (const ptid_arch &other) const + { + return this->ptid == other.ptid && this->arch == other.arch; + } +}; + +/* Hash function for ptid_arch. */ + +struct hash_ptid_arch +{ + size_t operator() (const ptid_arch &val) const + { + hash_ptid h_ptid; + std::hash h_long; + return h_ptid (val.ptid) + h_long ((long) val.arch); + } +}; + +using ptid_arch_regcache_map = std::unordered_map; + +/* Hash map containing the regcaches. */ + +static ptid_arch_regcache_map the_regcaches; struct regcache * -get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch, +get_thread_arch_aspace_regcache (ptid_t ptid, gdbarch *arch, struct address_space *aspace) { - for (const auto ®cache : regcache::current_regcache) - if (ptid_equal (regcache->ptid (), ptid) && regcache->arch () == gdbarch) - return regcache; - - regcache *new_regcache = new regcache (gdbarch, aspace); + /* Look up a regcache for this (ptid, arch). */ + ptid_arch key (ptid, arch); + auto it = the_regcaches.find (key); + if (it != the_regcaches.end ()) + return it->second; - regcache::current_regcache.push_front (new_regcache); + /* It does not exist, create it. */ + regcache *new_regcache = new regcache (arch, aspace); new_regcache->set_ptid (ptid); + the_regcaches[key] = new_regcache; + return new_regcache; } @@ -411,7 +386,7 @@ static struct gdbarch *current_thread_arch; struct regcache * get_thread_regcache (ptid_t ptid) { - if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid)) + if (!current_thread_arch || current_thread_ptid != ptid) { current_thread_ptid = ptid; current_thread_arch = target_thread_architecture (ptid); @@ -420,13 +395,21 @@ get_thread_regcache (ptid_t ptid) return get_thread_arch_regcache (ptid, current_thread_arch); } +/* See regcache.h. */ + +struct regcache * +get_thread_regcache (thread_info *thread) +{ + return get_thread_regcache (thread->ptid); +} + struct regcache * get_current_regcache (void) { - return get_thread_regcache (inferior_ptid); + return get_thread_regcache (inferior_thread ()); } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ struct regcache * get_thread_regcache_for_ptid (ptid_t ptid) @@ -444,13 +427,32 @@ regcache_observer_target_changed (struct target_ops *target) /* Update global variables old ptids to hold NEW_PTID if they were holding OLD_PTID. */ -void -regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) +static void +regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) { - for (auto ®cache : regcache::current_regcache) + std::vector keys_to_update; + + /* Find all the regcaches to updates. */ + for (auto &pair : the_regcaches) + { + regcache *rc = pair.second; + if (rc->ptid () == old_ptid) + keys_to_update.push_back (pair.first); + } + + for (const ptid_arch &old_key : keys_to_update) { - if (ptid_equal (regcache->ptid (), old_ptid)) - regcache->set_ptid (new_ptid); + /* Get the regcache, delete the hash map entry. */ + auto it = the_regcaches.find (old_key); + gdb_assert (it != the_regcaches.end ()); + regcache *rc = it->second; + + the_regcaches.erase (it); + + /* Insert the regcache back, with an updated key. */ + ptid_arch new_key (new_ptid, rc->arch ()); + rc->set_ptid (new_ptid); + the_regcaches[new_key] = rc; } } @@ -468,27 +470,26 @@ regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) void registers_changed_ptid (ptid_t ptid) { - for (auto oit = regcache::current_regcache.before_begin (), - it = std::next (oit); - it != regcache::current_regcache.end (); - ) + for (auto iter = the_regcaches.begin (); iter != the_regcaches.end (); ) { - if (ptid_match ((*it)->ptid (), ptid)) + regcache *rc = iter->second; + + if (rc->ptid ().matches (ptid)) { - delete *it; - it = regcache::current_regcache.erase_after (oit); + delete iter->second; + iter = the_regcaches.erase (iter); } else - oit = it++; + ++iter; } - if (ptid_match (current_thread_ptid, ptid)) + if (current_thread_ptid.matches (ptid)) { current_thread_ptid = null_ptid; current_thread_arch = NULL; } - if (ptid_match (inferior_ptid, ptid)) + if (inferior_ptid.matches (ptid)) { /* We just deleted the regcache of the current thread. Need to forget about any frames we have cached, too. */ @@ -496,25 +497,18 @@ registers_changed_ptid (ptid_t ptid) } } +/* See regcache.h. */ + void -registers_changed (void) +registers_changed_thread (thread_info *thread) { - registers_changed_ptid (minus_one_ptid); - - /* Force cleanup of any alloca areas if using C alloca instead of - a builtin alloca. This particular call is used to clean up - areas allocated by low level target code which may build up - during lengthy interactions between gdb and the target before - gdb gives control to the user (ie watchpoints). */ - alloca (0); + registers_changed_ptid (thread->ptid); } void -regcache_raw_update (struct regcache *regcache, int regnum) +registers_changed (void) { - gdb_assert (regcache != NULL); - - regcache->raw_update (regnum); + registers_changed_ptid (minus_one_ptid); } void @@ -539,12 +533,6 @@ regcache::raw_update (int regnum) } } -enum register_status -regcache_raw_read (struct regcache *regcache, int regnum, gdb_byte *buf) -{ - return regcache->raw_read (regnum, buf); -} - enum register_status readable_regcache::raw_read (int regnum, gdb_byte *buf) { @@ -557,7 +545,7 @@ readable_regcache::raw_read (int regnum, gdb_byte *buf) memcpy (buf, register_buffer (regnum), m_descr->sizeof_register[regnum]); - return (enum register_status) m_register_status[regnum]; + return m_register_status[regnum]; } enum register_status @@ -635,12 +623,6 @@ regcache_raw_get_signed (struct regcache *regcache, int regnum) return value; } -enum register_status -regcache_cooked_read (struct regcache *regcache, int regnum, gdb_byte *buf) -{ - return regcache->cooked_read (regnum, buf); -} - enum register_status readable_regcache::cooked_read (int regnum, gdb_byte *buf) { @@ -657,7 +639,7 @@ readable_regcache::cooked_read (int regnum, gdb_byte *buf) else memset (buf, 0, m_descr->sizeof_register[regnum]); - return (enum register_status) m_register_status[regnum]; + return m_register_status[regnum]; } else if (gdbarch_pseudo_register_read_value_p (m_descr->gdbarch)) { @@ -686,12 +668,6 @@ readable_regcache::cooked_read (int regnum, gdb_byte *buf) regnum, buf); } -struct value * -regcache_cooked_read_value (struct regcache *regcache, int regnum) -{ - return regcache->cooked_read_value (regnum); -} - struct value * readable_regcache::cooked_read_value (int regnum) { @@ -786,14 +762,6 @@ regcache_cooked_write_unsigned (struct regcache *regcache, int regnum, regcache->cooked_write (regnum, val); } -void -regcache_raw_write (struct regcache *regcache, int regnum, - const gdb_byte *buf) -{ - gdb_assert (regcache != NULL && buf != NULL); - regcache->raw_write (regnum, buf); -} - void regcache::raw_write (int regnum, const gdb_byte *buf) { @@ -818,7 +786,8 @@ regcache::raw_write (int regnum, const gdb_byte *buf) /* Invalidate the register after it is written, in case of a failure. */ - regcache_invalidator invalidator (this, regnum); + auto invalidator + = make_scope_exit ([&] { this->invalidate (regnum); }); target_store_registers (this, regnum); @@ -827,13 +796,6 @@ regcache::raw_write (int regnum, const gdb_byte *buf) invalidator.release (); } -void -regcache_cooked_write (struct regcache *regcache, int regnum, - const gdb_byte *buf) -{ - regcache->cooked_write (regnum, buf); -} - void regcache::cooked_write (int regnum, const gdb_byte *buf) { @@ -846,100 +808,155 @@ regcache::cooked_write (int regnum, const gdb_byte *buf) regnum, buf); } -/* Perform a partial register transfer using a read, modify, write - operation. */ - -typedef void (regcache_read_ftype) (struct regcache *regcache, int regnum, - void *buf); -typedef void (regcache_write_ftype) (struct regcache *regcache, int regnum, - const void *buf); +/* See regcache.h. */ enum register_status -readable_regcache::read_part (int regnum, int offset, int len, void *in, - bool is_raw) +readable_regcache::read_part (int regnum, int offset, int len, + gdb_byte *out, bool is_raw) { - struct gdbarch *gdbarch = arch (); - gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum)); + int reg_size = register_size (arch (), regnum); + + gdb_assert (out != NULL); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) + { + /* Nothing to do. */ + return REG_VALID; + } + + if (offset == 0 && len == reg_size) + { + /* Read the full register. */ + return (is_raw) ? raw_read (regnum, out) : cooked_read (regnum, out); + } - gdb_assert (in != NULL); - gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]); - gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]); - /* Something to do? */ - if (offset + len == 0) - return REG_VALID; - /* Read (when needed) ... */ enum register_status status; + gdb_byte *reg = (gdb_byte *) alloca (reg_size); - if (is_raw) - status = raw_read (regnum, reg); - else - status = cooked_read (regnum, reg); + /* Read full register to buffer. */ + status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg); if (status != REG_VALID) return status; - /* ... modify ... */ - memcpy (in, reg + offset, len); - + /* Copy out. */ + memcpy (out, reg + offset, len); return REG_VALID; } +/* See regcache.h. */ + +void +reg_buffer::raw_collect_part (int regnum, int offset, int len, + gdb_byte *out) const +{ + int reg_size = register_size (arch (), regnum); + + gdb_assert (out != nullptr); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) + { + /* Nothing to do. */ + return; + } + + if (offset == 0 && len == reg_size) + { + /* Collect the full register. */ + return raw_collect (regnum, out); + } + + /* Read to buffer, then write out. */ + gdb_byte *reg = (gdb_byte *) alloca (reg_size); + raw_collect (regnum, reg); + memcpy (out, reg + offset, len); +} + +/* See regcache.h. */ + enum register_status regcache::write_part (int regnum, int offset, int len, - const void *out, bool is_raw) + const gdb_byte *in, bool is_raw) { - struct gdbarch *gdbarch = arch (); - gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum)); + int reg_size = register_size (arch (), regnum); - gdb_assert (out != NULL); - gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]); - gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]); - /* Something to do? */ - if (offset + len == 0) - return REG_VALID; - /* Read (when needed) ... */ - if (offset > 0 - || offset + len < m_descr->sizeof_register[regnum]) + gdb_assert (in != NULL); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) { - enum register_status status; + /* Nothing to do. */ + return REG_VALID; + } - if (is_raw) - status = raw_read (regnum, reg); - else - status = cooked_read (regnum, reg); - if (status != REG_VALID) - return status; + if (offset == 0 && len == reg_size) + { + /* Write the full register. */ + (is_raw) ? raw_write (regnum, in) : cooked_write (regnum, in); + return REG_VALID; } - memcpy (reg + offset, out, len); - /* ... write (when needed). */ - if (is_raw) - raw_write (regnum, reg); - else - cooked_write (regnum, reg); + enum register_status status; + gdb_byte *reg = (gdb_byte *) alloca (reg_size); + + /* Read existing register to buffer. */ + status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg); + if (status != REG_VALID) + return status; + /* Update buffer, then write back to regcache. */ + memcpy (reg + offset, in, len); + is_raw ? raw_write (regnum, reg) : cooked_write (regnum, reg); return REG_VALID; } -enum register_status -regcache_raw_read_part (struct regcache *regcache, int regnum, - int offset, int len, gdb_byte *buf) +/* See regcache.h. */ + +void +reg_buffer::raw_supply_part (int regnum, int offset, int len, + const gdb_byte *in) { - return regcache->raw_read_part (regnum, offset, len, buf); + int reg_size = register_size (arch (), regnum); + + gdb_assert (in != nullptr); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) + { + /* Nothing to do. */ + return; + } + + if (offset == 0 && len == reg_size) + { + /* Supply the full register. */ + return raw_supply (regnum, in); + } + + gdb_byte *reg = (gdb_byte *) alloca (reg_size); + + /* Read existing value to buffer. */ + raw_collect (regnum, reg); + + /* Write to buffer, then write out. */ + memcpy (reg + offset, in, len); + raw_supply (regnum, reg); } enum register_status -readable_regcache::raw_read_part (int regnum, int offset, int len, gdb_byte *buf) +readable_regcache::raw_read_part (int regnum, int offset, int len, + gdb_byte *buf) { assert_regnum (regnum); return read_part (regnum, offset, len, buf, true); } -void -regcache_raw_write_part (struct regcache *regcache, int regnum, - int offset, int len, const gdb_byte *buf) -{ - regcache->raw_write_part (regnum, offset, len, buf); -} +/* See regcache.h. */ void regcache::raw_write_part (int regnum, int offset, int len, @@ -949,13 +966,7 @@ regcache::raw_write_part (int regnum, int offset, int len, write_part (regnum, offset, len, buf, true); } -enum register_status -regcache_cooked_read_part (struct regcache *regcache, int regnum, - int offset, int len, gdb_byte *buf) -{ - return regcache->cooked_read_part (regnum, offset, len, buf); -} - +/* See regcache.h. */ enum register_status readable_regcache::cooked_read_part (int regnum, int offset, int len, @@ -965,12 +976,7 @@ readable_regcache::cooked_read_part (int regnum, int offset, int len, return read_part (regnum, offset, len, buf, false); } -void -regcache_cooked_write_part (struct regcache *regcache, int regnum, - int offset, int len, const gdb_byte *buf) -{ - regcache->cooked_write_part (regnum, offset, len, buf); -} +/* See regcache.h. */ void regcache::cooked_write_part (int regnum, int offset, int len, @@ -980,17 +986,10 @@ regcache::cooked_write_part (int regnum, int offset, int len, write_part (regnum, offset, len, buf, false); } -/* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE. */ - -void -regcache_raw_supply (struct regcache *regcache, int regnum, const void *buf) -{ - gdb_assert (regcache != NULL); - regcache->raw_supply (regnum, buf); -} +/* See gdbsupport/common-regcache.h. */ void -detached_regcache::raw_supply (int regnum, const void *buf) +reg_buffer::raw_supply (int regnum, const void *buf) { void *regbuf; size_t size; @@ -1015,15 +1014,11 @@ detached_regcache::raw_supply (int regnum, const void *buf) } } -/* 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 sign or - zero extended. If the register size is smaller than the integer, then the - most significant bytes of the integer will be truncated. */ +/* See regcache.h. */ void -detached_regcache::raw_supply_integer (int regnum, const gdb_byte *addr, - int addr_len, bool is_signed) +reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr, + int addr_len, bool is_signed) { enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); gdb_byte *regbuf; @@ -1039,12 +1034,10 @@ detached_regcache::raw_supply_integer (int regnum, const gdb_byte *addr, m_register_status[regnum] = REG_VALID; } -/* Supply register REGNUM with zeroed value to REGCACHE. This is not the same - as calling raw_supply with NULL (which will set the state to - unavailable). */ +/* See regcache.h. */ void -detached_regcache::raw_supply_zeroed (int regnum) +reg_buffer::raw_supply_zeroed (int regnum) { void *regbuf; size_t size; @@ -1058,17 +1051,10 @@ detached_regcache::raw_supply_zeroed (int regnum) m_register_status[regnum] = REG_VALID; } -/* Collect register REGNUM from REGCACHE and store its contents in BUF. */ +/* See gdbsupport/common-regcache.h. */ void -regcache_raw_collect (const struct regcache *regcache, int regnum, void *buf) -{ - gdb_assert (regcache != NULL && buf != NULL); - regcache->raw_collect (regnum, buf); -} - -void -regcache::raw_collect (int regnum, void *buf) const +reg_buffer::raw_collect (int regnum, void *buf) const { const void *regbuf; size_t size; @@ -1081,19 +1067,11 @@ regcache::raw_collect (int regnum, void *buf) const memcpy (buf, regbuf, size); } -/* Transfer a single or all registers belonging to a certain register - set to or from a buffer. This is the main worker function for - regcache_supply_regset and regcache_collect_regset. */ - -/* 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 sign - or zero extended. If ADDR_LEN is smaller than the register size, then the - most significant bytes of the integer will be truncated. */ +/* See regcache.h. */ void -regcache::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, - bool is_signed) const +reg_buffer::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, + bool is_signed) const { enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); const gdb_byte *regbuf; @@ -1108,11 +1086,43 @@ regcache::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, byte_order); } +/* See regcache.h. */ + +void +regcache::transfer_regset_register (struct regcache *out_regcache, int regnum, + const gdb_byte *in_buf, gdb_byte *out_buf, + int slot_size, int offs) const +{ + struct gdbarch *gdbarch = arch (); + int reg_size = std::min (register_size (gdbarch, regnum), slot_size); + + /* Use part versions and reg_size to prevent possible buffer overflows when + accessing the regcache. */ + + if (out_buf != nullptr) + { + raw_collect_part (regnum, 0, reg_size, out_buf + offs); + + /* Ensure any additional space is cleared. */ + if (slot_size > reg_size) + memset (out_buf + offs + reg_size, 0, slot_size - reg_size); + } + else if (in_buf != nullptr) + out_regcache->raw_supply_part (regnum, 0, reg_size, in_buf + offs); + else + { + /* Invalidate the register. */ + out_regcache->raw_supply (regnum, nullptr); + } +} + +/* See regcache.h. */ + void regcache::transfer_regset (const struct regset *regset, struct regcache *out_regcache, - int regnum, const void *in_buf, - void *out_buf, size_t size) const + int regnum, const gdb_byte *in_buf, + gdb_byte *out_buf, size_t size) const { const struct regcache_map_entry *map; int offs = 0, count; @@ -1138,12 +1148,8 @@ regcache::transfer_regset (const struct regset *regset, if (offs + slot_size > size) break; - if (out_buf) - raw_collect (regno, (gdb_byte *) out_buf + offs); - else - out_regcache->raw_supply (regno, in_buf - ? (const gdb_byte *) in_buf + offs - : NULL); + transfer_regset_register (out_regcache, regno, in_buf, out_buf, + slot_size, offs); } else { @@ -1152,12 +1158,8 @@ regcache::transfer_regset (const struct regset *regset, if (offs + slot_size > size) return; - if (out_buf) - raw_collect (regnum, (gdb_byte *) out_buf + offs); - else - out_regcache->raw_supply (regnum, in_buf - ? (const gdb_byte *) in_buf + offs - : NULL); + transfer_regset_register (out_regcache, regnum, in_buf, out_buf, + slot_size, offs); return; } } @@ -1172,14 +1174,14 @@ regcache_supply_regset (const struct regset *regset, struct regcache *regcache, int regnum, const void *buf, size_t size) { - regcache->supply_regset (regset, regnum, buf, size); + regcache->supply_regset (regset, regnum, (const gdb_byte *) buf, size); } void regcache::supply_regset (const struct regset *regset, int regnum, const void *buf, size_t size) { - transfer_regset (regset, this, regnum, buf, NULL, size); + transfer_regset (regset, this, regnum, (const gdb_byte *) buf, nullptr, size); } /* Collect register REGNUM from REGCACHE to BUF, using the register @@ -1191,16 +1193,30 @@ regcache_collect_regset (const struct regset *regset, const struct regcache *regcache, int regnum, void *buf, size_t size) { - regcache->collect_regset (regset, regnum, buf, size); + regcache->collect_regset (regset, regnum, (gdb_byte *) buf, size); } void regcache::collect_regset (const struct regset *regset, int regnum, void *buf, size_t size) const { - transfer_regset (regset, NULL, regnum, NULL, buf, size); + transfer_regset (regset, nullptr, regnum, nullptr, (gdb_byte *) buf, size); } +/* See gdbsupport/common-regcache.h. */ + +bool +reg_buffer::raw_compare (int regnum, const void *buf, int offset) const +{ + gdb_assert (buf != NULL); + assert_regnum (regnum); + + const char *regbuf = (const char *) register_buffer (regnum); + size_t size = m_descr->sizeof_register[regnum]; + gdb_assert (size >= offset); + + return (memcmp (buf, regbuf + offset, size - offset) == 0); +} /* Special handling for register PC. */ @@ -1300,427 +1316,127 @@ reg_flush_command (const char *command, int from_tty) printf_filtered (_("Register cache flushed.\n")); } -/* An abstract base class for register dump. */ - -class register_dump +void +register_dump::dump (ui_file *file) { -public: - void dump (ui_file *file) - { - auto descr = regcache_descr (m_gdbarch); - int regnum; - int footnote_nr = 0; - int footnote_register_offset = 0; - int footnote_register_type_name_null = 0; - long register_offset = 0; - - gdb_assert (descr->nr_cooked_registers - == (gdbarch_num_regs (m_gdbarch) - + gdbarch_num_pseudo_regs (m_gdbarch))); - - for (regnum = -1; regnum < descr->nr_cooked_registers; regnum++) - { - /* Name. */ - if (regnum < 0) - fprintf_unfiltered (file, " %-10s", "Name"); - else - { - const char *p = gdbarch_register_name (m_gdbarch, regnum); + auto descr = regcache_descr (m_gdbarch); + int regnum; + int footnote_nr = 0; + int footnote_register_offset = 0; + int footnote_register_type_name_null = 0; + long register_offset = 0; - if (p == NULL) - p = ""; - else if (p[0] == '\0') - p = "''"; - fprintf_unfiltered (file, " %-10s", p); - } + gdb_assert (descr->nr_cooked_registers + == gdbarch_num_cooked_regs (m_gdbarch)); - /* Number. */ - if (regnum < 0) - fprintf_unfiltered (file, " %4s", "Nr"); - else - fprintf_unfiltered (file, " %4d", regnum); + for (regnum = -1; regnum < descr->nr_cooked_registers; regnum++) + { + /* Name. */ + if (regnum < 0) + fprintf_unfiltered (file, " %-10s", "Name"); + else + { + const char *p = gdbarch_register_name (m_gdbarch, regnum); - /* Relative number. */ - if (regnum < 0) - fprintf_unfiltered (file, " %4s", "Rel"); - else if (regnum < gdbarch_num_regs (m_gdbarch)) - fprintf_unfiltered (file, " %4d", regnum); - else - fprintf_unfiltered (file, " %4d", - (regnum - gdbarch_num_regs (m_gdbarch))); + if (p == NULL) + p = ""; + else if (p[0] == '\0') + p = "''"; + fprintf_unfiltered (file, " %-10s", p); + } - /* Offset. */ - if (regnum < 0) - fprintf_unfiltered (file, " %6s ", "Offset"); - else - { - fprintf_unfiltered (file, " %6ld", - descr->register_offset[regnum]); - if (register_offset != descr->register_offset[regnum] - || (regnum > 0 - && (descr->register_offset[regnum] - != (descr->register_offset[regnum - 1] - + descr->sizeof_register[regnum - 1]))) - ) - { - if (!footnote_register_offset) - footnote_register_offset = ++footnote_nr; - fprintf_unfiltered (file, "*%d", footnote_register_offset); - } - else - fprintf_unfiltered (file, " "); - register_offset = (descr->register_offset[regnum] - + descr->sizeof_register[regnum]); - } + /* Number. */ + if (regnum < 0) + fprintf_unfiltered (file, " %4s", "Nr"); + else + fprintf_unfiltered (file, " %4d", regnum); - /* Size. */ - if (regnum < 0) - fprintf_unfiltered (file, " %5s ", "Size"); - else - fprintf_unfiltered (file, " %5ld", descr->sizeof_register[regnum]); + /* Relative number. */ + if (regnum < 0) + fprintf_unfiltered (file, " %4s", "Rel"); + else if (regnum < gdbarch_num_regs (m_gdbarch)) + fprintf_unfiltered (file, " %4d", regnum); + else + fprintf_unfiltered (file, " %4d", + (regnum - gdbarch_num_regs (m_gdbarch))); - /* Type. */ + /* Offset. */ + if (regnum < 0) + fprintf_unfiltered (file, " %6s ", "Offset"); + else { - const char *t; - std::string name_holder; - - if (regnum < 0) - t = "Type"; - else + fprintf_unfiltered (file, " %6ld", + descr->register_offset[regnum]); + if (register_offset != descr->register_offset[regnum] + || (regnum > 0 + && (descr->register_offset[regnum] + != (descr->register_offset[regnum - 1] + + descr->sizeof_register[regnum - 1]))) + ) { - static const char blt[] = "builtin_type"; - - t = TYPE_NAME (register_type (m_gdbarch, regnum)); - if (t == NULL) - { - if (!footnote_register_type_name_null) - footnote_register_type_name_null = ++footnote_nr; - name_holder = string_printf ("*%d", - footnote_register_type_name_null); - t = name_holder.c_str (); - } - /* Chop a leading builtin_type. */ - if (startswith (t, blt)) - t += strlen (blt); + if (!footnote_register_offset) + footnote_register_offset = ++footnote_nr; + fprintf_unfiltered (file, "*%d", footnote_register_offset); } - fprintf_unfiltered (file, " %-15s", t); + else + fprintf_unfiltered (file, " "); + register_offset = (descr->register_offset[regnum] + + descr->sizeof_register[regnum]); } - /* Leading space always present. */ - fprintf_unfiltered (file, " "); - - dump_reg (file, regnum); - - fprintf_unfiltered (file, "\n"); - } - - if (footnote_register_offset) - fprintf_unfiltered (file, "*%d: Inconsistent register offsets.\n", - footnote_register_offset); - if (footnote_register_type_name_null) - fprintf_unfiltered (file, - "*%d: Register type's name NULL.\n", - footnote_register_type_name_null); - } - - virtual ~register_dump () {}; - -protected: - register_dump (gdbarch *arch) - : m_gdbarch (arch) - {} - - /* Dump the register REGNUM contents. If REGNUM is -1, print the - header. */ - virtual void dump_reg (ui_file *file, int regnum) = 0; - - gdbarch *m_gdbarch; -}; - -/* Dump registers from regcache, used for dump raw registers and - cooked registers. */ - -class register_dump_regcache : public register_dump -{ -public: - register_dump_regcache (regcache *regcache, bool dump_pseudo) - : register_dump (regcache->arch ()), m_regcache (regcache), - m_dump_pseudo (dump_pseudo) - { - } - -protected: - void dump_reg (ui_file *file, int regnum) override - { - if (regnum < 0) - { - if (m_dump_pseudo) - fprintf_unfiltered (file, "Cooked value"); - else - fprintf_unfiltered (file, "Raw value"); - } - else - { - if (regnum < gdbarch_num_regs (m_gdbarch) || m_dump_pseudo) - { - auto size = register_size (m_gdbarch, regnum); - - if (size == 0) - return; - - gdb::def_vector buf (size); - auto status = m_regcache->cooked_read (regnum, buf.data ()); - - if (status == REG_UNKNOWN) - fprintf_unfiltered (file, ""); - else if (status == REG_UNAVAILABLE) - fprintf_unfiltered (file, ""); - else - { - print_hex_chars (file, buf.data (), size, - gdbarch_byte_order (m_gdbarch), true); - } - } - else - { - /* Just print "" for pseudo register when - regcache_dump_raw. */ - fprintf_unfiltered (file, ""); - } - } - } - -private: - regcache *m_regcache; - - /* Dump pseudo registers or not. */ - const bool m_dump_pseudo; -}; - -/* Dump from reg_buffer, used when there is no thread or - registers. */ - -class register_dump_reg_buffer : public register_dump, reg_buffer -{ -public: - register_dump_reg_buffer (gdbarch *gdbarch, bool dump_pseudo) - : register_dump (gdbarch), reg_buffer (gdbarch, dump_pseudo) - { - } + /* Size. */ + if (regnum < 0) + fprintf_unfiltered (file, " %5s ", "Size"); + else + fprintf_unfiltered (file, " %5ld", descr->sizeof_register[regnum]); -protected: - void dump_reg (ui_file *file, int regnum) override - { - if (regnum < 0) + /* Type. */ { - if (m_has_pseudo) - fprintf_unfiltered (file, "Cooked value"); - else - fprintf_unfiltered (file, "Raw value"); - } - else - { - if (regnum < gdbarch_num_regs (m_gdbarch) || m_has_pseudo) - { - auto size = register_size (m_gdbarch, regnum); - - if (size == 0) - return; - - auto status = get_register_status (regnum); + const char *t; + std::string name_holder; - gdb_assert (status != REG_VALID); - - if (status == REG_UNKNOWN) - fprintf_unfiltered (file, ""); - else - fprintf_unfiltered (file, ""); - } + if (regnum < 0) + t = "Type"; else { - /* Just print "" for pseudo register when - regcache_dump_raw. */ - fprintf_unfiltered (file, ""); - } - } - } -}; - -/* For "maint print registers". */ - -class register_dump_none : public register_dump -{ -public: - register_dump_none (gdbarch *arch) - : register_dump (arch) - {} - -protected: - void dump_reg (ui_file *file, int regnum) override - {} -}; - -/* For "maint print remote-registers". */ - -class register_dump_remote : public register_dump -{ -public: - register_dump_remote (gdbarch *arch) - : register_dump (arch) - {} - -protected: - void dump_reg (ui_file *file, int regnum) override - { - if (regnum < 0) - { - fprintf_unfiltered (file, "Rmt Nr g/G Offset"); - } - else if (regnum < gdbarch_num_regs (m_gdbarch)) - { - int pnum, poffset; + static const char blt[] = "builtin_type"; - if (remote_register_number_and_offset (m_gdbarch, regnum, - &pnum, &poffset)) - fprintf_unfiltered (file, "%7d %11d", pnum, poffset); - } - } -}; - -/* For "maint print register-groups". */ - -class register_dump_groups : public register_dump -{ -public: - register_dump_groups (gdbarch *arch) - : register_dump (arch) - {} - -protected: - void dump_reg (ui_file *file, int regnum) override - { - if (regnum < 0) - fprintf_unfiltered (file, "Groups"); - else - { - const char *sep = ""; - struct reggroup *group; - - for (group = reggroup_next (m_gdbarch, NULL); - group != NULL; - group = reggroup_next (m_gdbarch, group)) - { - if (gdbarch_register_reggroup_p (m_gdbarch, regnum, group)) + t = TYPE_NAME (register_type (m_gdbarch, regnum)); + if (t == NULL) { - fprintf_unfiltered (file, - "%s%s", sep, reggroup_name (group)); - sep = ","; + if (!footnote_register_type_name_null) + footnote_register_type_name_null = ++footnote_nr; + name_holder = string_printf ("*%d", + footnote_register_type_name_null); + t = name_holder.c_str (); } + /* Chop a leading builtin_type. */ + if (startswith (t, blt)) + t += strlen (blt); } + fprintf_unfiltered (file, " %-15s", t); } - } -}; -enum regcache_dump_what -{ - regcache_dump_none, regcache_dump_raw, - regcache_dump_cooked, regcache_dump_groups, - regcache_dump_remote -}; + /* Leading space always present. */ + fprintf_unfiltered (file, " "); -static void -regcache_print (const char *args, enum regcache_dump_what what_to_dump) -{ - /* Where to send output. */ - stdio_file file; - ui_file *out; + dump_reg (file, regnum); - if (args == NULL) - out = gdb_stdout; - else - { - if (!file.open (args, "w")) - perror_with_name (_("maintenance print architecture")); - out = &file; + fprintf_unfiltered (file, "\n"); } - std::unique_ptr dump; - std::unique_ptr regs; - gdbarch *gdbarch; - - if (target_has_registers) - gdbarch = get_current_regcache ()->arch (); - else - gdbarch = target_gdbarch (); - - switch (what_to_dump) - { - case regcache_dump_none: - dump.reset (new register_dump_none (gdbarch)); - break; - case regcache_dump_remote: - dump.reset (new register_dump_remote (gdbarch)); - break; - case regcache_dump_groups: - dump.reset (new register_dump_groups (gdbarch)); - break; - case regcache_dump_raw: - case regcache_dump_cooked: - { - auto dump_pseudo = (what_to_dump == regcache_dump_cooked); - - if (target_has_registers) - dump.reset (new register_dump_regcache (get_current_regcache (), - dump_pseudo)); - else - { - /* For the benefit of "maint print registers" & co when - debugging an executable, allow dumping a regcache even when - there is no thread selected / no registers. */ - dump.reset (new register_dump_reg_buffer (target_gdbarch (), - dump_pseudo)); - } - } - break; - } - - dump->dump (out); -} - -static void -maintenance_print_registers (const char *args, int from_tty) -{ - regcache_print (args, regcache_dump_none); -} - -static void -maintenance_print_raw_registers (const char *args, int from_tty) -{ - regcache_print (args, regcache_dump_raw); -} - -static void -maintenance_print_cooked_registers (const char *args, int from_tty) -{ - regcache_print (args, regcache_dump_cooked); -} - -static void -maintenance_print_register_groups (const char *args, int from_tty) -{ - regcache_print (args, regcache_dump_groups); -} - -static void -maintenance_print_remote_registers (const char *args, int from_tty) -{ - regcache_print (args, regcache_dump_remote); + if (footnote_register_offset) + fprintf_unfiltered (file, "*%d: Inconsistent register offsets.\n", + footnote_register_offset); + if (footnote_register_type_name_null) + fprintf_unfiltered (file, + "*%d: Register type's name NULL.\n", + footnote_register_type_name_null); } #if GDB_SELF_TEST -#include "selftest.h" +#include "gdbsupport/selftest.h" #include "selftest-arch.h" -#include "gdbthread.h" #include "target-float.h" namespace selftests { @@ -1734,8 +1450,7 @@ public: static size_t current_regcache_size () { - return std::distance (regcache::current_regcache.begin (), - regcache::current_regcache.end ()); + return the_regcaches.size (); } }; @@ -1790,30 +1505,12 @@ current_regcache_test (void) SELF_CHECK (regcache_access::current_regcache_size () == 2); } -static void test_target_fetch_registers (target_ops *self, regcache *regs, - int regno); -static void test_target_store_registers (target_ops *self, regcache *regs, - int regno); -static enum target_xfer_status - test_target_xfer_partial (struct target_ops *ops, - enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, - ULONGEST *xfered_len); - class target_ops_no_register : public test_target_ops { public: target_ops_no_register () : test_target_ops {} - { - to_fetch_registers = test_target_fetch_registers; - to_store_registers = test_target_store_registers; - to_xfer_partial = test_target_xfer_partial; - - to_data = this; - } + {} void reset () { @@ -1822,38 +1519,42 @@ public: xfer_partial_called = 0; } + void fetch_registers (regcache *regs, int regno) override; + void store_registers (regcache *regs, int regno) override; + + enum target_xfer_status xfer_partial (enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) override; + unsigned int fetch_registers_called = 0; unsigned int store_registers_called = 0; unsigned int xfer_partial_called = 0; }; -static void -test_target_fetch_registers (target_ops *self, regcache *regs, int regno) +void +target_ops_no_register::fetch_registers (regcache *regs, int regno) { - auto ops = static_cast (self->to_data); - /* Mark register available. */ regs->raw_supply_zeroed (regno); - ops->fetch_registers_called++; + this->fetch_registers_called++; } -static void -test_target_store_registers (target_ops *self, regcache *regs, int regno) +void +target_ops_no_register::store_registers (regcache *regs, int regno) { - auto ops = static_cast (self->to_data); - - ops->store_registers_called++; + this->store_registers_called++; } -static enum target_xfer_status -test_target_xfer_partial (struct target_ops *self, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) +enum target_xfer_status +target_ops_no_register::xfer_partial (enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) { - auto ops = static_cast (self->to_data); - - ops->xfer_partial_called++; + this->xfer_partial_called++; *xfered_len = len; return TARGET_XFER_OK; @@ -1875,7 +1576,7 @@ cooked_read_test (struct gdbarch *gdbarch) { /* Error out if debugging something, because we're going to push the test target, which would pop any existing target. */ - if (current_target.to_stratum >= process_stratum) + if (current_top_target ()->stratum () >= process_stratum) error (_("target already pushed")); /* Create a mock environment. An inferior with a thread, with a @@ -1888,9 +1589,7 @@ cooked_read_test (struct gdbarch *gdbarch) mock_inferior.gdbarch = gdbarch; mock_inferior.aspace = &mock_aspace; thread_info mock_thread (&mock_inferior, mock_ptid); - - scoped_restore restore_thread_list - = make_scoped_restore (&thread_list, &mock_thread); + mock_inferior.thread_map[mock_ptid] = &mock_thread; /* Add the mock inferior to the inferior list so that look ups by target+ptid can find it. */ @@ -1921,19 +1620,21 @@ cooked_read_test (struct gdbarch *gdbarch) /* Test that read one raw register from regcache_no_target will go to the target layer. */ - int regnum; /* Find a raw register which size isn't zero. */ - for (regnum = 0; regnum < gdbarch_num_regs (gdbarch); regnum++) + int nonzero_regnum; + for (nonzero_regnum = 0; + nonzero_regnum < gdbarch_num_regs (gdbarch); + nonzero_regnum++) { - if (register_size (gdbarch, regnum) != 0) + if (register_size (gdbarch, nonzero_regnum) != 0) break; } readwrite_regcache readwrite (gdbarch); - gdb::def_vector buf (register_size (gdbarch, regnum)); + gdb::def_vector buf (register_size (gdbarch, nonzero_regnum)); - readwrite.raw_read (regnum, buf.data ()); + readwrite.raw_read (nonzero_regnum, buf.data ()); /* raw_read calls target_fetch_registers. */ SELF_CHECK (mock_target.fetch_registers_called > 0); @@ -1947,23 +1648,19 @@ cooked_read_test (struct gdbarch *gdbarch) mock_target.reset (); /* Then, read all raw and pseudo registers, and don't expect calling to_{fetch,store}_registers. */ - for (int regnum = 0; - regnum < gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); - regnum++) + for (int regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++) { if (register_size (gdbarch, regnum) == 0) continue; - gdb::def_vector buf (register_size (gdbarch, regnum)); + gdb::def_vector inner_buf (register_size (gdbarch, regnum)); - SELF_CHECK (REG_VALID == readwrite.cooked_read (regnum, buf.data ())); + SELF_CHECK (REG_VALID == readwrite.cooked_read (regnum, + inner_buf.data ())); SELF_CHECK (mock_target.fetch_registers_called == 0); SELF_CHECK (mock_target.store_registers_called == 0); - - /* Some SPU pseudo registers are got via TARGET_OBJECT_SPU. */ - if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_spu) - SELF_CHECK (mock_target.xfer_partial_called == 0); + SELF_CHECK (mock_target.xfer_partial_called == 0); mock_target.reset (); } @@ -1974,16 +1671,14 @@ cooked_read_test (struct gdbarch *gdbarch) readonly regcache. */ mock_target.reset (); - for (int regnum = 0; - regnum < gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); - regnum++) + for (int regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++) { if (register_size (gdbarch, regnum) == 0) continue; - gdb::def_vector buf (register_size (gdbarch, regnum)); + gdb::def_vector inner_buf (register_size (gdbarch, regnum)); enum register_status status = readonly.cooked_read (regnum, - buf.data ()); + inner_buf.data ()); if (regnum < gdbarch_num_regs (gdbarch)) { @@ -1995,7 +1690,8 @@ cooked_read_test (struct gdbarch *gdbarch) || bfd_arch == bfd_arch_msp430 || bfd_arch == bfd_arch_mep || bfd_arch == bfd_arch_mips || bfd_arch == bfd_arch_v850_rh850 || bfd_arch == bfd_arch_tic6x || bfd_arch == bfd_arch_mn10300 - || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score) + || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score + || bfd_arch == bfd_arch_riscv || bfd_arch == bfd_arch_csky) { /* Raw registers. If raw registers are not in save_reggroup, their status are unknown. */ @@ -2048,7 +1744,7 @@ cooked_write_test (struct gdbarch *gdbarch) { /* Error out if debugging something, because we're going to push the test target, which would pop any existing target. */ - if (current_target.to_stratum >= process_stratum) + if (current_top_target ()->stratum () >= process_stratum) error (_("target already pushed")); /* Create a mock environment. A process_stratum target pushed. */ @@ -2070,8 +1766,7 @@ cooked_write_test (struct gdbarch *gdbarch) readwrite_regcache readwrite (gdbarch); - const int num_regs = (gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch)); + const int num_regs = gdbarch_num_cooked_regs (gdbarch); for (auto regnum = 0; regnum < num_regs; regnum++) { @@ -2081,20 +1776,12 @@ cooked_write_test (struct gdbarch *gdbarch) auto bfd_arch = gdbarch_bfd_arch_info (gdbarch)->arch; - if ((bfd_arch == bfd_arch_sparc - /* SPARC64_CWP_REGNUM, SPARC64_PSTATE_REGNUM, - SPARC64_ASI_REGNUM and SPARC64_CCR_REGNUM are hard to test. */ - && gdbarch_ptr_bit (gdbarch) == 64 - && (regnum >= gdbarch_num_regs (gdbarch) - && regnum <= gdbarch_num_regs (gdbarch) + 4)) - || (bfd_arch == bfd_arch_sh - /* FPSCR_C_REGNUM in sh64 is hard to test. */ - && gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_sh5 - && regnum == 243) - || (bfd_arch == bfd_arch_spu - /* SPU pseudo registers except SPU_SP_REGNUM are got by - TARGET_OBJECT_SPU. */ - && regnum >= gdbarch_num_regs (gdbarch) && regnum != 130)) + if (bfd_arch == bfd_arch_sparc + /* SPARC64_CWP_REGNUM, SPARC64_PSTATE_REGNUM, + SPARC64_ASI_REGNUM and SPARC64_CCR_REGNUM are hard to test. */ + && gdbarch_ptr_bit (gdbarch) == 64 + && (regnum >= gdbarch_num_regs (gdbarch) + && regnum <= gdbarch_num_regs (gdbarch) + 4)) continue; std::vector expected (register_size (gdbarch, regnum), 0); @@ -2169,37 +1856,11 @@ _initialize_regcache (void) regcache_descr_handle = gdbarch_data_register_post_init (init_regcache_descr); - observer_attach_target_changed (regcache_observer_target_changed); - observer_attach_thread_ptid_changed (regcache::regcache_thread_ptid_changed); + gdb::observers::target_changed.attach (regcache_observer_target_changed); + gdb::observers::thread_ptid_changed.attach (regcache_thread_ptid_changed); add_com ("flushregs", class_maintenance, reg_flush_command, - _("Force gdb to flush its register cache (maintainer command)")); - - add_cmd ("registers", class_maintenance, maintenance_print_registers, - _("Print the internal register configuration.\n" - "Takes an optional file parameter."), &maintenanceprintlist); - add_cmd ("raw-registers", class_maintenance, - maintenance_print_raw_registers, - _("Print the internal register configuration " - "including raw values.\n" - "Takes an optional file parameter."), &maintenanceprintlist); - add_cmd ("cooked-registers", class_maintenance, - maintenance_print_cooked_registers, - _("Print the internal register configuration " - "including cooked values.\n" - "Takes an optional file parameter."), &maintenanceprintlist); - add_cmd ("register-groups", class_maintenance, - maintenance_print_register_groups, - _("Print the internal register configuration " - "including each register's group.\n" - "Takes an optional file parameter."), - &maintenanceprintlist); - add_cmd ("remote-registers", class_maintenance, - maintenance_print_remote_registers, _("\ -Print the internal register configuration including each register's\n\ -remote register number and buffer offset in the g/G packets.\n\ -Takes an optional file parameter."), - &maintenanceprintlist); + _("Force gdb to flush its register cache (maintainer command).")); #if GDB_SELF_TEST selftests::register_test ("current_regcache", selftests::current_regcache_test);