/* Cache and manage the values of registers for GDB, the GNU debugger.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#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 <forward_list>
/* 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
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;
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;
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)
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)] ());
}
}
-regcache::regcache (gdbarch *gdbarch, const address_space *aspace_)
+regcache::regcache (process_stratum_target *target, gdbarch *gdbarch,
+ const address_space *aspace_)
/* The register buffers. A read/write register cache can only hold
[0 .. gdbarch_num_regs). */
- : detached_regcache (gdbarch, false), m_aspace (aspace_)
+ : detached_regcache (gdbarch, false), m_aspace (aspace_), m_target (target)
{
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);
+ })
{
}
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;
/* 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
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);
}
}
-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;
std::forward_list<regcache *> regcache::current_regcache;
struct regcache *
-get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
+get_thread_arch_aspace_regcache (process_stratum_target *target,
+ ptid_t ptid, struct gdbarch *gdbarch,
struct address_space *aspace)
{
+ gdb_assert (target != nullptr);
+
for (const auto ®cache : regcache::current_regcache)
- if (ptid_equal (regcache->ptid (), ptid) && regcache->arch () == gdbarch)
+ if (regcache->target () == target
+ && regcache->ptid () == ptid
+ && regcache->arch () == gdbarch)
return regcache;
- regcache *new_regcache = new regcache (gdbarch, aspace);
+ regcache *new_regcache = new regcache (target, gdbarch, aspace);
regcache::current_regcache.push_front (new_regcache);
new_regcache->set_ptid (ptid);
}
struct regcache *
-get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+get_thread_arch_regcache (process_stratum_target *target, ptid_t ptid,
+ struct gdbarch *gdbarch)
{
+ scoped_restore_current_inferior restore_current_inferior;
+ set_current_inferior (find_inferior_ptid (target, ptid));
address_space *aspace = target_thread_address_space (ptid);
- return get_thread_arch_aspace_regcache (ptid, gdbarch, aspace);
+ return get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace);
}
+static process_stratum_target *current_thread_target;
static ptid_t current_thread_ptid;
static struct gdbarch *current_thread_arch;
struct regcache *
-get_thread_regcache (ptid_t ptid)
+get_thread_regcache (process_stratum_target *target, ptid_t ptid)
{
- if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid))
+ if (!current_thread_arch
+ || target != current_thread_target
+ || current_thread_ptid != ptid)
{
+ gdb_assert (ptid != null_ptid);
+
current_thread_ptid = ptid;
+ current_thread_target = target;
+
+ scoped_restore_current_inferior restore_current_inferior;
+ set_current_inferior (find_inferior_ptid (target, ptid));
current_thread_arch = target_thread_architecture (ptid);
}
- return get_thread_arch_regcache (ptid, current_thread_arch);
+ return get_thread_arch_regcache (target, ptid, current_thread_arch);
+}
+
+/* See regcache.h. */
+
+struct regcache *
+get_thread_regcache (thread_info *thread)
+{
+ return get_thread_regcache (thread->inf->process_target (),
+ 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)
{
- return get_thread_regcache (ptid);
+ /* This function doesn't take a process_stratum_target parameter
+ because it's a gdbsupport/ routine implemented by both gdb and
+ gdbserver. It always refers to a ptid of the current target. */
+ process_stratum_target *proc_target = current_inferior ()->process_target ();
+ return get_thread_regcache (proc_target, ptid);
}
/* Observer for the target_changed event. */
{
for (auto ®cache : regcache::current_regcache)
{
- if (ptid_equal (regcache->ptid (), old_ptid))
+ if (regcache->ptid () == old_ptid)
regcache->set_ptid (new_ptid);
}
}
Indicate that registers may have changed, so invalidate the cache. */
void
-registers_changed_ptid (ptid_t ptid)
+registers_changed_ptid (process_stratum_target *target, ptid_t ptid)
{
for (auto oit = regcache::current_regcache.before_begin (),
it = std::next (oit);
it != regcache::current_regcache.end ();
)
{
- if (ptid_match ((*it)->ptid (), ptid))
+ struct regcache *regcache = *it;
+ if ((target == nullptr || regcache->target () == target)
+ && regcache->ptid ().matches (ptid))
{
- delete *it;
+ delete regcache;
it = regcache::current_regcache.erase_after (oit);
}
else
oit = it++;
}
- if (ptid_match (current_thread_ptid, ptid))
+ if ((target == nullptr || current_thread_target == target)
+ && current_thread_ptid.matches (ptid))
{
+ current_thread_target = NULL;
current_thread_ptid = null_ptid;
current_thread_arch = NULL;
}
- if (ptid_match (inferior_ptid, ptid))
+ if ((target == nullptr || current_inferior ()->process_target () == target)
+ && inferior_ptid.matches (ptid))
{
/* We just deleted the regcache of the current thread. Need to
forget about any frames we have cached, too. */
}
}
+/* 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->inf->process_target (), 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 (nullptr, minus_one_ptid);
}
void
}
}
-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)
{
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
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)
{
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))
{
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)
{
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)
{
/* 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);
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)
{
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,
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,
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,
write_part (regnum, offset, len, buf, false);
}
-/* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE. */
+/* See gdbsupport/common-regcache.h. */
void
-regcache_raw_supply (struct regcache *regcache, int regnum, const void *buf)
-{
- gdb_assert (regcache != NULL);
- regcache->raw_supply (regnum, buf);
-}
-
-void
-detached_regcache::raw_supply (int regnum, const void *buf)
+reg_buffer::raw_supply (int regnum, const void *buf)
{
void *regbuf;
size_t size;
}
}
-/* 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;
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;
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;
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;
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;
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
{
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;
}
}
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
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. */
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<gdb_byte> buf (size);
- auto status = m_regcache->cooked_read (regnum, buf.data ());
-
- if (status == REG_UNKNOWN)
- fprintf_unfiltered (file, "<invalid>");
- else if (status == REG_UNAVAILABLE)
- fprintf_unfiltered (file, "<unavailable>");
- else
- {
- print_hex_chars (file, buf.data (), size,
- gdbarch_byte_order (m_gdbarch), true);
- }
- }
- else
- {
- /* Just print "<cooked>" for pseudo register when
- regcache_dump_raw. */
- fprintf_unfiltered (file, "<cooked>");
- }
- }
- }
-
-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)
- {
- if (m_has_pseudo)
- fprintf_unfiltered (file, "Cooked value");
- else
- fprintf_unfiltered (file, "Raw value");
- }
- else
+ /* Type. */
{
- if (regnum < gdbarch_num_regs (m_gdbarch) || m_has_pseudo)
- {
- auto size = register_size (m_gdbarch, regnum);
+ const char *t;
+ std::string name_holder;
- if (size == 0)
- return;
-
- auto status = get_register_status (regnum);
-
- gdb_assert (status != REG_VALID);
-
- if (status == REG_UNKNOWN)
- fprintf_unfiltered (file, "<invalid>");
- else
- fprintf_unfiltered (file, "<unavailable>");
- }
+ if (regnum < 0)
+ t = "Type";
else
{
- /* Just print "<cooked>" for pseudo register when
- regcache_dump_raw. */
- fprintf_unfiltered (file, "<cooked>");
- }
- }
- }
-};
-
-/* 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;
-
- 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;
+ static const char blt[] = "builtin_type";
- 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
-};
-
-static void
-regcache_print (const char *args, enum regcache_dump_what what_to_dump)
-{
- /* Where to send output. */
- stdio_file file;
- ui_file *out;
-
- if (args == NULL)
- out = gdb_stdout;
- else
- {
- if (!file.open (args, "w"))
- perror_with_name (_("maintenance print architecture"));
- out = &file;
- }
-
- std::unique_ptr<register_dump> dump;
- std::unique_ptr<regcache> regs;
- gdbarch *gdbarch;
- if (target_has_registers)
- gdbarch = get_current_regcache ()->arch ();
- else
- gdbarch = target_gdbarch ();
+ /* Leading space always present. */
+ fprintf_unfiltered (file, " ");
- 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);
+ dump_reg (file, regnum);
- 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;
+ fprintf_unfiltered (file, "\n");
}
- 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 {
}
};
+/* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */
+
+static void
+test_get_thread_arch_aspace_regcache (process_stratum_target *target,
+ ptid_t ptid, struct gdbarch *gdbarch,
+ address_space *aspace)
+{
+ struct regcache *regcache
+ = get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace);
+ SELF_CHECK (regcache != NULL);
+ SELF_CHECK (regcache->target () == target);
+ SELF_CHECK (regcache->ptid () == ptid);
+ SELF_CHECK (regcache->aspace () == aspace);
+}
+
static void
current_regcache_test (void)
{
ptid_t ptid1 (1), ptid2 (2), ptid3 (3);
- /* Get regcache from ptid1, a new regcache is added to
- current_regcache. */
- regcache *regcache = get_thread_arch_aspace_regcache (ptid1,
- target_gdbarch (),
- NULL);
+ test_target_ops test_target1;
+ test_target_ops test_target2;
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid1);
+ /* Get regcache from (target1,ptid1), a new regcache is added to
+ current_regcache. */
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid1,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 1);
- /* Get regcache from ptid2, a new regcache is added to
+ /* Get regcache from (target1,ptid2), a new regcache is added to
current_regcache. */
- regcache = get_thread_arch_aspace_regcache (ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid2);
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 2);
- /* Get regcache from ptid3, a new regcache is added to
+ /* Get regcache from (target1,ptid3), a new regcache is added to
current_regcache. */
- regcache = get_thread_arch_aspace_regcache (ptid3,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid3);
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid3,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 3);
- /* Get regcache from ptid2 again, nothing is added to
+ /* Get regcache from (target1,ptid2) again, nothing is added to
current_regcache. */
- regcache = get_thread_arch_aspace_regcache (ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcache != NULL);
- SELF_CHECK (regcache->ptid () == ptid2);
+ test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
+ target_gdbarch (),
+ NULL);
SELF_CHECK (regcache_access::current_regcache_size () == 3);
- /* Mark ptid2 is changed, so regcache of ptid2 should be removed from
- current_regcache. */
- registers_changed_ptid (ptid2);
- SELF_CHECK (regcache_access::current_regcache_size () == 2);
-}
+ /* Get regcache from (target2,ptid2), a new regcache is added to
+ current_regcache, since this time we're using a differen
+ target. */
+ test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
+ target_gdbarch (),
+ NULL);
+ SELF_CHECK (regcache_access::current_regcache_size () == 4);
+
+ /* Mark that (target1,ptid2) changed. The regcache of (target1,
+ ptid2) should be removed from current_regcache. */
+ registers_changed_ptid (&test_target1, ptid2);
+ SELF_CHECK (regcache_access::current_regcache_size () == 3);
+
+ /* Get the regcache from (target2,ptid2) again, confirming the
+ registers_changed_ptid call above did not delete it. */
+ test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
+ target_gdbarch (),
+ NULL);
+ SELF_CHECK (regcache_access::current_regcache_size () == 3);
-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);
+ /* Confirm that marking all regcaches of all targets as changed
+ clears current_regcache. */
+ registers_changed_ptid (nullptr, minus_one_ptid);
+ SELF_CHECK (regcache_access::current_regcache_size () == 0);
+}
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 ()
{
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<target_ops_no_register *> (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<target_ops_no_register *> (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<target_ops_no_register *> (self->to_data);
-
- ops->xfer_partial_called++;
+ this->xfer_partial_called++;
*xfered_len = len;
return TARGET_XFER_OK;
class readwrite_regcache : public regcache
{
public:
- readwrite_regcache (struct gdbarch *gdbarch)
- : regcache (gdbarch, nullptr)
+ readwrite_regcache (process_stratum_target *target,
+ struct gdbarch *gdbarch)
+ : regcache (target, gdbarch, nullptr)
{}
};
{
/* 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
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_list = &mock_thread;
/* Add the mock inferior to the inferior list so that look ups by
target+ptid can find it. */
/* 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<gdb_byte> buf (register_size (gdbarch, regnum));
+ readwrite_regcache readwrite (&mock_target, gdbarch);
+ gdb::def_vector<gdb_byte> 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);
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<gdb_byte> buf (register_size (gdbarch, regnum));
+ gdb::def_vector<gdb_byte> 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 ();
}
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<gdb_byte> buf (register_size (gdbarch, regnum));
+ gdb::def_vector<gdb_byte> 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))
{
|| 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. */
{
/* 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. */
}
} pop_targets;
- readwrite_regcache readwrite (gdbarch);
+ readwrite_regcache readwrite (&mock_target, 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++)
{
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<gdb_byte> expected (register_size (gdbarch, regnum), 0);
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::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);