gdb: change regcache interface to use array_view
Change most of regcache (and base classes) to use array_view when possible, instead of raw pointers. By propagating the use of array_view further, it enables having some runtime checks to make sure the what we read from or write to regcaches has the expected length (such as the one in the `copy(array_view, array_view)` function. It also integrates well when connecting with other APIs already using gdb::array_view. Add some overloads of the methods using raw pointers to avoid having to change all call sites at once (which is both a lot of work and risky). I tried to do this change in small increments, but since many of these functions use each other, it ended up simpler to do it in one shot than having a lot of intermediary / transient changes. This change extends into gdbserver as well, because there is some part of the regcache interface that is shared. Changing the reg_buffer_common interface to use array_view caused some build failures in nat/aarch64-scalable-linux-ptrace.c. That file currently "takes advantage" of the fact that reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which IMO is dangerous. It uses raw_supply/raw_collect directly on uint64_t's, which I guess is fine because it is expected that native code will have the same endianness as the debugged process. To accomodate that, add some overloads of raw_collect and raw_supply that work on uint64_t. This file also uses raw_collect and raw_supply on `char` pointers. Change it to use `gdb_byte` pointers instead. Add overloads of raw_collect and raw_supply that work on `gdb_byte *` and make an array_view on the fly using the register's size. Those call sites could be converted to use array_view with not much work, in which case these overloads could be removed, but I didn't want to do it in this patch, to avoid starting to dig in arch-specific code. During development, I inadvertently changed reg_buffer::raw_compare's behavior to not accept an offset equal to the register size. This behavior (effectively comparing 0 bytes, returning true) change was caught by the AArch64 SME core tests. Add a selftest to make sure that this raw_compare behavior is preserved in the future. Change-Id: I9005f04114543ddff738949e12d85a31855304c2 Reviewed-By: John Baldwin <jhb@FreeBSD.org>
This commit is contained in:
parent
08d8e7ff94
commit
51e6b8cfd6
@ -1108,9 +1108,9 @@ get_frame_func (frame_info_ptr this_frame)
|
||||
std::unique_ptr<readonly_detached_regcache>
|
||||
frame_save_as_regcache (frame_info_ptr this_frame)
|
||||
{
|
||||
auto cooked_read = [this_frame] (int regnum, gdb_byte *buf)
|
||||
auto cooked_read = [this_frame] (int regnum, gdb::array_view<gdb_byte> buf)
|
||||
{
|
||||
if (!deprecated_frame_register_read (this_frame, regnum, buf))
|
||||
if (!deprecated_frame_register_read (this_frame, regnum, buf.data ()))
|
||||
return REG_UNAVAILABLE;
|
||||
else
|
||||
return REG_VALID;
|
||||
|
@ -613,7 +613,7 @@ aarch64_sve_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf)
|
||||
{
|
||||
gdb::byte_vector sve_state = aarch64_fetch_sve_regset (tid);
|
||||
|
||||
char *base = (char *) sve_state.data ();
|
||||
gdb_byte *base = sve_state.data ();
|
||||
struct user_sve_header *header
|
||||
= (struct user_sve_header *) sve_state.data ();
|
||||
|
||||
@ -684,8 +684,10 @@ aarch64_sve_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf)
|
||||
reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg);
|
||||
}
|
||||
|
||||
reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
|
||||
reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
|
||||
reg_buf->raw_supply (AARCH64_FPSR_REGNUM,
|
||||
(const gdb_byte *) &fpsimd->fpsr);
|
||||
reg_buf->raw_supply (AARCH64_FPCR_REGNUM,
|
||||
(const gdb_byte *) &fpsimd->fpcr);
|
||||
|
||||
/* Clear the SVE only registers. */
|
||||
memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
|
||||
@ -720,7 +722,7 @@ aarch64_sve_regs_copy_from_reg_buf (int tid,
|
||||
gdb::byte_vector new_state (SVE_PT_SIZE (32, SVE_PT_REGS_SVE), 0);
|
||||
memcpy (new_state.data (), sve_state.data (), sve_state.size ());
|
||||
header = (struct user_sve_header *) new_state.data ();
|
||||
char *base = (char *) new_state.data ();
|
||||
gdb_byte *base = new_state.data ();
|
||||
|
||||
/* Sanity check the data in the header. */
|
||||
if (!sve_vl_valid (header->vl)
|
||||
@ -805,9 +807,11 @@ aarch64_sve_regs_copy_from_reg_buf (int tid,
|
||||
}
|
||||
|
||||
if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
|
||||
reg_buf->raw_collect (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
|
||||
reg_buf->raw_collect (AARCH64_FPSR_REGNUM,
|
||||
(gdb_byte *) &fpsimd->fpsr);
|
||||
if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
|
||||
reg_buf->raw_collect (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
|
||||
reg_buf->raw_collect (AARCH64_FPCR_REGNUM,
|
||||
(gdb_byte *) &fpsimd->fpcr);
|
||||
|
||||
/* At this point we have collected all the data from the register
|
||||
cache and we are ready to update the FPSIMD register content
|
||||
@ -894,7 +898,7 @@ aarch64_za_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf,
|
||||
/* Sanity check. */
|
||||
gdb_assert (!za_state.empty ());
|
||||
|
||||
char *base = (char *) za_state.data ();
|
||||
gdb_byte *base = za_state.data ();
|
||||
struct user_za_header *header = (struct user_za_header *) base;
|
||||
|
||||
/* If we have ZA state, read it. Otherwise, make the contents of ZA
|
||||
@ -1027,7 +1031,7 @@ aarch64_za_regs_copy_from_reg_buf (int tid,
|
||||
/* Fetch the current ZA state from the thread. */
|
||||
gdb::byte_vector za_state = aarch64_fetch_za_regset (tid);
|
||||
|
||||
char *base = (char *) za_state.data ();
|
||||
gdb_byte *base = za_state.data ();
|
||||
struct user_za_header *za_header = (struct user_za_header *) base;
|
||||
uint64_t svq = sve_vq_from_vl (za_header->vl);
|
||||
|
||||
|
501
gdb/regcache.c
501
gdb/regcache.c
@ -220,10 +220,9 @@ regcache::regcache (inferior *inf_for_target_calls, gdbarch *gdbarch)
|
||||
|
||||
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);
|
||||
})
|
||||
[&src] (int regnum,
|
||||
gdb::array_view<gdb_byte> buf)
|
||||
{ return src.cooked_read (regnum, buf); })
|
||||
{
|
||||
}
|
||||
|
||||
@ -233,19 +232,38 @@ reg_buffer::arch () const
|
||||
return m_descr->gdbarch;
|
||||
}
|
||||
|
||||
/* Return a pointer to register REGNUM's buffer cache. */
|
||||
/* Helper for reg_buffer::register_buffer. */
|
||||
|
||||
gdb_byte *
|
||||
template<typename ElemType>
|
||||
gdb::array_view<ElemType>
|
||||
reg_buffer::register_buffer (int regnum) const
|
||||
{
|
||||
return m_registers.get () + m_descr->register_offset[regnum];
|
||||
assert_regnum (regnum);
|
||||
ElemType *start = &m_registers[m_descr->register_offset[regnum]];
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
return gdb::array_view<ElemType> (start, size);
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
gdb::array_view<const gdb_byte>
|
||||
reg_buffer::register_buffer (int regnum) const
|
||||
{
|
||||
return register_buffer<const gdb_byte> (regnum);
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
gdb::array_view<gdb_byte>
|
||||
reg_buffer::register_buffer (int regnum)
|
||||
{
|
||||
return register_buffer<gdb_byte> (regnum);
|
||||
}
|
||||
|
||||
void
|
||||
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);
|
||||
@ -256,17 +274,17 @@ reg_buffer::save (register_read_ftype cooked_read)
|
||||
save_reggroup) and mark them as valid. The full [0 .. gdbarch_num_regs +
|
||||
gdbarch_num_pseudo_regs) range is checked since some architectures need
|
||||
to save/restore `cooked' registers that live in memory. */
|
||||
for (regnum = 0; regnum < m_descr->nr_cooked_registers; regnum++)
|
||||
for (int regnum = 0; regnum < m_descr->nr_cooked_registers; regnum++)
|
||||
{
|
||||
if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
|
||||
{
|
||||
gdb_byte *dst_buf = register_buffer (regnum);
|
||||
enum register_status status = cooked_read (regnum, dst_buf);
|
||||
gdb::array_view<gdb_byte> dst_buf = register_buffer (regnum);
|
||||
register_status status = cooked_read (regnum, dst_buf);
|
||||
|
||||
gdb_assert (status != REG_UNKNOWN);
|
||||
|
||||
if (status != REG_VALID)
|
||||
memset (dst_buf, 0, register_size (gdbarch, regnum));
|
||||
memset (dst_buf.data (), 0, dst_buf.size ());
|
||||
|
||||
m_register_status[regnum] = status;
|
||||
}
|
||||
@ -592,21 +610,30 @@ regcache::raw_update (int regnum)
|
||||
}
|
||||
}
|
||||
|
||||
enum register_status
|
||||
readable_regcache::raw_read (int regnum, gdb_byte *buf)
|
||||
register_status
|
||||
readable_regcache::raw_read (int regnum, gdb::array_view<gdb_byte> dst)
|
||||
{
|
||||
gdb_assert (buf != NULL);
|
||||
assert_regnum (regnum);
|
||||
gdb_assert (dst.size () == m_descr->sizeof_register[regnum]);
|
||||
|
||||
raw_update (regnum);
|
||||
|
||||
if (m_register_status[regnum] != REG_VALID)
|
||||
memset (buf, 0, m_descr->sizeof_register[regnum]);
|
||||
memset (dst.data (), 0, dst.size ());
|
||||
else
|
||||
memcpy (buf, register_buffer (regnum),
|
||||
m_descr->sizeof_register[regnum]);
|
||||
copy (register_buffer (regnum), dst);
|
||||
|
||||
return m_register_status[regnum];
|
||||
}
|
||||
|
||||
register_status
|
||||
readable_regcache::raw_read (int regnum, gdb_byte *dst)
|
||||
{
|
||||
assert_regnum (regnum);
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
return raw_read (regnum, gdb::make_array_view (dst, size));
|
||||
}
|
||||
|
||||
enum register_status
|
||||
regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val)
|
||||
{
|
||||
@ -619,14 +646,16 @@ enum register_status
|
||||
readable_regcache::raw_read (int regnum, T *val)
|
||||
{
|
||||
assert_regnum (regnum);
|
||||
size_t len = m_descr->sizeof_register[regnum];
|
||||
gdb_byte *buf = (gdb_byte *) alloca (len);
|
||||
register_status status = raw_read (regnum, buf);
|
||||
size_t size = m_descr->sizeof_register[regnum];
|
||||
gdb_byte *buf = (gdb_byte *) alloca (size);
|
||||
auto view = gdb::make_array_view (buf, size);
|
||||
register_status status = raw_read (regnum, view);
|
||||
|
||||
if (status == REG_VALID)
|
||||
*val = extract_integer<T> ({buf, len},
|
||||
gdbarch_byte_order (m_descr->gdbarch));
|
||||
*val = extract_integer<T> (view, gdbarch_byte_order (m_descr->gdbarch));
|
||||
else
|
||||
*val = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -650,13 +679,13 @@ template<typename T, typename>
|
||||
void
|
||||
regcache::raw_write (int regnum, T val)
|
||||
{
|
||||
gdb_byte *buf;
|
||||
|
||||
assert_regnum (regnum);
|
||||
buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
|
||||
store_integer (buf, m_descr->sizeof_register[regnum],
|
||||
gdbarch_byte_order (m_descr->gdbarch), val);
|
||||
raw_write (regnum, buf);
|
||||
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
gdb_byte *buf = (gdb_byte *) alloca (size);
|
||||
auto view = gdb::make_array_view (buf, size);
|
||||
store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val);
|
||||
raw_write (regnum, view);
|
||||
}
|
||||
|
||||
void
|
||||
@ -680,47 +709,60 @@ regcache_raw_get_signed (struct regcache *regcache, int regnum)
|
||||
return value;
|
||||
}
|
||||
|
||||
enum register_status
|
||||
readable_regcache::cooked_read (int regnum, gdb_byte *buf)
|
||||
/* See regcache.h. */
|
||||
|
||||
register_status
|
||||
readable_regcache::cooked_read (int regnum, gdb::array_view<gdb_byte> dst)
|
||||
{
|
||||
gdb_assert (regnum >= 0);
|
||||
gdb_assert (regnum < m_descr->nr_cooked_registers);
|
||||
|
||||
if (regnum < num_raw_registers ())
|
||||
return raw_read (regnum, buf);
|
||||
else if (m_has_pseudo
|
||||
&& m_register_status[regnum] != REG_UNKNOWN)
|
||||
return raw_read (regnum, dst);
|
||||
|
||||
gdb_assert (dst.size () == m_descr->sizeof_register[regnum]);
|
||||
|
||||
if (m_has_pseudo && m_register_status[regnum] != REG_UNKNOWN)
|
||||
{
|
||||
if (m_register_status[regnum] == REG_VALID)
|
||||
memcpy (buf, register_buffer (regnum),
|
||||
m_descr->sizeof_register[regnum]);
|
||||
copy (register_buffer (regnum), dst);
|
||||
else
|
||||
memset (buf, 0, m_descr->sizeof_register[regnum]);
|
||||
memset (dst.data (), 0, dst.size ());
|
||||
|
||||
return m_register_status[regnum];
|
||||
}
|
||||
else if (gdbarch_pseudo_register_read_value_p (m_descr->gdbarch))
|
||||
{
|
||||
struct value *computed;
|
||||
enum register_status result = REG_VALID;
|
||||
|
||||
register_status result = REG_VALID;
|
||||
scoped_value_mark mark;
|
||||
value *computed
|
||||
= gdbarch_pseudo_register_read_value (m_descr->gdbarch, this, regnum);
|
||||
|
||||
computed = gdbarch_pseudo_register_read_value (m_descr->gdbarch,
|
||||
this, regnum);
|
||||
if (computed->entirely_available ())
|
||||
memcpy (buf, computed->contents_raw ().data (),
|
||||
m_descr->sizeof_register[regnum]);
|
||||
copy (computed->contents_raw (), dst);
|
||||
else
|
||||
{
|
||||
memset (buf, 0, m_descr->sizeof_register[regnum]);
|
||||
memset (dst.data (), 0, dst.size ());
|
||||
result = REG_UNAVAILABLE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return gdbarch_pseudo_register_read (m_descr->gdbarch, this,
|
||||
regnum, buf);
|
||||
return gdbarch_pseudo_register_read (m_descr->gdbarch, this, regnum,
|
||||
dst.data ());
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
register_status
|
||||
readable_regcache::cooked_read (int regnum, gdb_byte *dst)
|
||||
{
|
||||
gdb_assert (regnum >= 0);
|
||||
gdb_assert (regnum < m_descr->nr_cooked_registers);
|
||||
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
return cooked_read (regnum, gdb::make_array_view (dst, size));
|
||||
}
|
||||
|
||||
struct value *
|
||||
@ -742,8 +784,7 @@ readable_regcache::cooked_read_value (int regnum)
|
||||
/* It is more efficient in general to do this delegation in this
|
||||
direction than in the other one, even though the value-based
|
||||
API is preferred. */
|
||||
if (cooked_read (regnum,
|
||||
result->contents_raw ().data ()) == REG_UNAVAILABLE)
|
||||
if (cooked_read (regnum, result->contents_raw ()) == REG_UNAVAILABLE)
|
||||
result->mark_bytes_unavailable (0,
|
||||
result->type ()->length ());
|
||||
|
||||
@ -767,12 +808,12 @@ enum register_status
|
||||
readable_regcache::cooked_read (int regnum, T *val)
|
||||
{
|
||||
gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers);
|
||||
size_t len = m_descr->sizeof_register[regnum];
|
||||
gdb_byte *buf = (gdb_byte *) alloca (len);
|
||||
register_status status = cooked_read (regnum, buf);
|
||||
size_t size = m_descr->sizeof_register[regnum];
|
||||
gdb_byte *buf = (gdb_byte *) alloca (size);
|
||||
auto view = gdb::make_array_view (buf, size);
|
||||
register_status status = cooked_read (regnum, view);
|
||||
if (status == REG_VALID)
|
||||
*val = extract_integer<T> ({buf, len},
|
||||
gdbarch_byte_order (m_descr->gdbarch));
|
||||
*val = extract_integer<T> (view, gdbarch_byte_order (m_descr->gdbarch));
|
||||
else
|
||||
*val = 0;
|
||||
return status;
|
||||
@ -798,13 +839,14 @@ template<typename T, typename>
|
||||
void
|
||||
regcache::cooked_write (int regnum, T val)
|
||||
{
|
||||
gdb_byte *buf;
|
||||
gdb_assert (regnum >= 0);
|
||||
gdb_assert (regnum < m_descr->nr_cooked_registers);
|
||||
|
||||
gdb_assert (regnum >=0 && regnum < m_descr->nr_cooked_registers);
|
||||
buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
|
||||
store_integer (buf, m_descr->sizeof_register[regnum],
|
||||
gdbarch_byte_order (m_descr->gdbarch), val);
|
||||
cooked_write (regnum, buf);
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
gdb_byte *buf = (gdb_byte *) alloca (size);
|
||||
auto view = gdb::make_array_view (buf, size);
|
||||
store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val);
|
||||
cooked_write (regnum, view);
|
||||
}
|
||||
|
||||
void
|
||||
@ -816,11 +858,10 @@ regcache_cooked_write_unsigned (struct regcache *regcache, int regnum,
|
||||
}
|
||||
|
||||
void
|
||||
regcache::raw_write (int regnum, const gdb_byte *buf)
|
||||
regcache::raw_write (int regnum, gdb::array_view<const gdb_byte> src)
|
||||
{
|
||||
|
||||
gdb_assert (buf != NULL);
|
||||
assert_regnum (regnum);
|
||||
gdb_assert (src.size () == m_descr->sizeof_register[regnum]);
|
||||
|
||||
/* On the sparc, writing %g0 is a no-op, so we don't even want to
|
||||
change the registers array if something writes to this register. */
|
||||
@ -830,15 +871,15 @@ regcache::raw_write (int regnum, const gdb_byte *buf)
|
||||
/* If we have a valid copy of the register, and new value == old
|
||||
value, then don't bother doing the actual store. */
|
||||
if (get_register_status (regnum) == REG_VALID
|
||||
&& (memcmp (register_buffer (regnum), buf,
|
||||
m_descr->sizeof_register[regnum]) == 0))
|
||||
&& (memcmp (register_buffer (regnum).data (), src.data (), src.size ())
|
||||
== 0))
|
||||
return;
|
||||
|
||||
std::optional<scoped_restore_current_thread> maybe_restore_thread
|
||||
= maybe_switch_inferior (m_inf_for_target_calls);
|
||||
|
||||
target_prepare_to_store (this);
|
||||
raw_supply (regnum, buf);
|
||||
raw_supply (regnum, src);
|
||||
|
||||
/* Invalidate the register after it is written, in case of a
|
||||
failure. */
|
||||
@ -853,211 +894,248 @@ regcache::raw_write (int regnum, const gdb_byte *buf)
|
||||
}
|
||||
|
||||
void
|
||||
regcache::cooked_write (int regnum, const gdb_byte *buf)
|
||||
regcache::raw_write (int regnum, const gdb_byte *src)
|
||||
{
|
||||
gdb_assert (regnum >= 0);
|
||||
gdb_assert (regnum < m_descr->nr_cooked_registers);
|
||||
if (regnum < num_raw_registers ())
|
||||
raw_write (regnum, buf);
|
||||
else
|
||||
gdbarch_pseudo_register_write (m_descr->gdbarch, this,
|
||||
regnum, buf);
|
||||
assert_regnum (regnum);
|
||||
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
raw_write (regnum, gdb::make_array_view (src, size));
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
enum register_status
|
||||
readable_regcache::read_part (int regnum, int offset, int len,
|
||||
gdb_byte *out, bool is_raw)
|
||||
void
|
||||
regcache::cooked_write (int regnum, gdb::array_view<const gdb_byte> src)
|
||||
{
|
||||
gdb_assert (regnum >= 0);
|
||||
gdb_assert (regnum < m_descr->nr_cooked_registers);
|
||||
|
||||
if (regnum < num_raw_registers ())
|
||||
raw_write (regnum, src);
|
||||
else
|
||||
gdbarch_pseudo_register_write (m_descr->gdbarch, this, regnum,
|
||||
src.data ());
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
regcache::cooked_write (int regnum, const gdb_byte *src)
|
||||
{
|
||||
gdb_assert (regnum >= 0);
|
||||
gdb_assert (regnum < m_descr->nr_cooked_registers);
|
||||
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
return cooked_write (regnum, gdb::make_array_view (src, size));
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
register_status
|
||||
readable_regcache::read_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst, bool is_raw)
|
||||
{
|
||||
int reg_size = register_size (arch (), regnum);
|
||||
|
||||
gdb_assert (out != NULL);
|
||||
gdb_assert (offset >= 0);
|
||||
gdb_assert (len >= 0 && offset + len <= reg_size);
|
||||
gdb_assert (offset + dst.size () <= reg_size);
|
||||
|
||||
if (len == 0)
|
||||
if (dst.size () == 0)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
return REG_VALID;
|
||||
}
|
||||
|
||||
if (len == reg_size)
|
||||
if (dst.size () == reg_size)
|
||||
{
|
||||
/* Read the full register. */
|
||||
return (is_raw) ? raw_read (regnum, out) : cooked_read (regnum, out);
|
||||
if (is_raw)
|
||||
return raw_read (regnum, dst);
|
||||
else
|
||||
return cooked_read (regnum, dst);
|
||||
}
|
||||
|
||||
enum register_status status;
|
||||
gdb_byte *reg = (gdb_byte *) alloca (reg_size);
|
||||
|
||||
/* Read full register to buffer. */
|
||||
status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg);
|
||||
register_status status;
|
||||
gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size);
|
||||
auto reg = gdb::make_array_view (reg_buf, reg_size);
|
||||
|
||||
if (is_raw)
|
||||
status = raw_read (regnum, reg);
|
||||
else
|
||||
status = cooked_read (regnum, reg);
|
||||
|
||||
if (status != REG_VALID)
|
||||
return status;
|
||||
|
||||
/* Copy out. */
|
||||
memcpy (out, reg + offset, len);
|
||||
copy (reg.slice (offset, dst.size ()), dst);
|
||||
return REG_VALID;
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
reg_buffer::raw_collect_part (int regnum, int offset, int len,
|
||||
gdb_byte *out) const
|
||||
reg_buffer::raw_collect_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst) const
|
||||
{
|
||||
int reg_size = register_size (arch (), regnum);
|
||||
|
||||
gdb_assert (out != nullptr);
|
||||
gdb_assert (offset >= 0);
|
||||
gdb_assert (len >= 0 && offset + len <= reg_size);
|
||||
gdb_assert (offset + dst.size () <= reg_size);
|
||||
|
||||
if (len == 0)
|
||||
if (dst.size () == 0)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (len == reg_size)
|
||||
if (dst.size () == reg_size)
|
||||
{
|
||||
/* Collect the full register. */
|
||||
return raw_collect (regnum, out);
|
||||
return raw_collect (regnum, dst);
|
||||
}
|
||||
|
||||
/* Read to buffer, then write out. */
|
||||
gdb_byte *reg = (gdb_byte *) alloca (reg_size);
|
||||
gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size);
|
||||
auto reg = gdb::make_array_view (reg_buf, reg_size);
|
||||
raw_collect (regnum, reg);
|
||||
memcpy (out, reg + offset, len);
|
||||
copy (reg.slice (offset, dst.size ()), dst);
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
enum register_status
|
||||
regcache::write_part (int regnum, int offset, int len,
|
||||
const gdb_byte *in, bool is_raw)
|
||||
register_status
|
||||
regcache::write_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src, bool is_raw)
|
||||
{
|
||||
int reg_size = register_size (arch (), regnum);
|
||||
|
||||
gdb_assert (in != NULL);
|
||||
gdb_assert (offset >= 0);
|
||||
gdb_assert (len >= 0 && offset + len <= reg_size);
|
||||
gdb_assert (offset + src.size () <= reg_size);
|
||||
|
||||
if (len == 0)
|
||||
if (src.size () == 0)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
return REG_VALID;
|
||||
}
|
||||
|
||||
if (len == reg_size)
|
||||
if (src.size () == reg_size)
|
||||
{
|
||||
/* Write the full register. */
|
||||
(is_raw) ? raw_write (regnum, in) : cooked_write (regnum, in);
|
||||
if (is_raw)
|
||||
raw_write (regnum, src);
|
||||
else
|
||||
cooked_write (regnum, src);
|
||||
|
||||
return REG_VALID;
|
||||
}
|
||||
|
||||
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);
|
||||
register_status status;
|
||||
gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size);
|
||||
auto reg = gdb::make_array_view (reg_buf, reg_size);
|
||||
|
||||
if (is_raw)
|
||||
status = raw_read (regnum, reg);
|
||||
else
|
||||
status = 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);
|
||||
copy (src, reg.slice (offset, src.size ()));
|
||||
|
||||
if (is_raw)
|
||||
raw_write (regnum, reg);
|
||||
else
|
||||
cooked_write (regnum, reg);
|
||||
|
||||
return REG_VALID;
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
reg_buffer::raw_supply_part (int regnum, int offset, int len,
|
||||
const gdb_byte *in)
|
||||
reg_buffer::raw_supply_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src)
|
||||
{
|
||||
int reg_size = register_size (arch (), regnum);
|
||||
|
||||
gdb_assert (in != nullptr);
|
||||
gdb_assert (offset >= 0);
|
||||
gdb_assert (len >= 0 && offset + len <= reg_size);
|
||||
gdb_assert (offset + src.size () <= reg_size);
|
||||
|
||||
if (len == 0)
|
||||
if (src.size () == 0)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (len == reg_size)
|
||||
if (src.size () == reg_size)
|
||||
{
|
||||
/* Supply the full register. */
|
||||
return raw_supply (regnum, in);
|
||||
return raw_supply (regnum, src);
|
||||
}
|
||||
|
||||
gdb_byte *reg = (gdb_byte *) alloca (reg_size);
|
||||
|
||||
/* Read existing value to buffer. */
|
||||
gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size);
|
||||
auto reg = gdb::make_array_view (reg_buf, reg_size);
|
||||
raw_collect (regnum, reg);
|
||||
|
||||
/* Write to buffer, then write out. */
|
||||
memcpy (reg + offset, in, len);
|
||||
copy (src, reg.slice (offset, src.size ()));
|
||||
raw_supply (regnum, reg);
|
||||
}
|
||||
|
||||
enum register_status
|
||||
readable_regcache::raw_read_part (int regnum, int offset, int len,
|
||||
gdb_byte *buf)
|
||||
register_status
|
||||
readable_regcache::raw_read_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst)
|
||||
{
|
||||
assert_regnum (regnum);
|
||||
return read_part (regnum, offset, len, buf, true);
|
||||
return read_part (regnum, offset, dst, true);
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
regcache::raw_write_part (int regnum, int offset, int len,
|
||||
const gdb_byte *buf)
|
||||
regcache::raw_write_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src)
|
||||
{
|
||||
assert_regnum (regnum);
|
||||
write_part (regnum, offset, len, buf, true);
|
||||
write_part (regnum, offset, src, true);
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
enum register_status
|
||||
readable_regcache::cooked_read_part (int regnum, int offset, int len,
|
||||
gdb_byte *buf)
|
||||
register_status
|
||||
readable_regcache::cooked_read_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst)
|
||||
{
|
||||
gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers);
|
||||
return read_part (regnum, offset, len, buf, false);
|
||||
return read_part (regnum, offset, dst, false);
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
regcache::cooked_write_part (int regnum, int offset, int len,
|
||||
const gdb_byte *buf)
|
||||
regcache::cooked_write_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src)
|
||||
{
|
||||
gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers);
|
||||
write_part (regnum, offset, len, buf, false);
|
||||
write_part (regnum, offset, src, false);
|
||||
}
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
|
||||
void
|
||||
reg_buffer::raw_supply (int regnum, const void *buf)
|
||||
reg_buffer::raw_supply (int regnum, gdb::array_view<const gdb_byte> src)
|
||||
{
|
||||
void *regbuf;
|
||||
size_t size;
|
||||
gdb::array_view<gdb_byte> dst = register_buffer (regnum);
|
||||
|
||||
assert_regnum (regnum);
|
||||
|
||||
regbuf = register_buffer (regnum);
|
||||
size = m_descr->sizeof_register[regnum];
|
||||
|
||||
if (buf)
|
||||
if (src.data () != nullptr)
|
||||
{
|
||||
memcpy (regbuf, buf, size);
|
||||
copy (src, dst);
|
||||
m_register_status[regnum] = REG_VALID;
|
||||
}
|
||||
else
|
||||
@ -1065,7 +1143,7 @@ reg_buffer::raw_supply (int regnum, const void *buf)
|
||||
/* This memset not strictly necessary, but better than garbage
|
||||
in case the register value manages to escape somewhere (due
|
||||
to a bug, no less). */
|
||||
memset (regbuf, 0, size);
|
||||
memset (dst.data (), 0, dst.size ());
|
||||
m_register_status[regnum] = REG_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
@ -1073,19 +1151,24 @@ reg_buffer::raw_supply (int regnum, const void *buf)
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr,
|
||||
int addr_len, bool is_signed)
|
||||
reg_buffer::raw_supply (int regnum, const void *src)
|
||||
{
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
|
||||
gdb_byte *regbuf;
|
||||
size_t regsize;
|
||||
|
||||
assert_regnum (regnum);
|
||||
|
||||
regbuf = register_buffer (regnum);
|
||||
regsize = m_descr->sizeof_register[regnum];
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
raw_supply (regnum, gdb::make_array_view ((const gdb_byte *) src, size));
|
||||
}
|
||||
|
||||
copy_integer_to_size (regbuf, regsize, addr, addr_len, is_signed,
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr, int addr_len,
|
||||
bool is_signed)
|
||||
{
|
||||
gdb::array_view<gdb_byte> dst = register_buffer (regnum);
|
||||
bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
|
||||
|
||||
copy_integer_to_size (dst.data (), dst.size (), addr, addr_len, is_signed,
|
||||
byte_order);
|
||||
m_register_status[regnum] = REG_VALID;
|
||||
}
|
||||
@ -1095,32 +1178,29 @@ reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr,
|
||||
void
|
||||
reg_buffer::raw_supply_zeroed (int regnum)
|
||||
{
|
||||
void *regbuf;
|
||||
size_t size;
|
||||
|
||||
assert_regnum (regnum);
|
||||
|
||||
regbuf = register_buffer (regnum);
|
||||
size = m_descr->sizeof_register[regnum];
|
||||
|
||||
memset (regbuf, 0, size);
|
||||
gdb::array_view<gdb_byte> dst = register_buffer (regnum);
|
||||
memset (dst.data (), 0, dst.size ());
|
||||
m_register_status[regnum] = REG_VALID;
|
||||
}
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
|
||||
void
|
||||
reg_buffer::raw_collect (int regnum, void *buf) const
|
||||
reg_buffer::raw_collect (int regnum, gdb::array_view<gdb_byte> dst) const
|
||||
{
|
||||
const void *regbuf;
|
||||
size_t size;
|
||||
gdb::array_view<const gdb_byte> src = register_buffer (regnum);
|
||||
copy (src, dst);
|
||||
}
|
||||
|
||||
gdb_assert (buf != NULL);
|
||||
/* See regcache.h. */
|
||||
|
||||
void
|
||||
reg_buffer::raw_collect (int regnum, void *dst) const
|
||||
{
|
||||
assert_regnum (regnum);
|
||||
|
||||
regbuf = register_buffer (regnum);
|
||||
size = m_descr->sizeof_register[regnum];
|
||||
memcpy (buf, regbuf, size);
|
||||
int size = m_descr->sizeof_register[regnum];
|
||||
return raw_collect (regnum, gdb::make_array_view ((gdb_byte *) dst, size));
|
||||
}
|
||||
|
||||
/* See regcache.h. */
|
||||
@ -1129,16 +1209,9 @@ void
|
||||
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;
|
||||
size_t regsize;
|
||||
|
||||
assert_regnum (regnum);
|
||||
|
||||
regbuf = register_buffer (regnum);
|
||||
regsize = m_descr->sizeof_register[regnum];
|
||||
|
||||
copy_integer_to_size (addr, addr_len, regbuf, regsize, is_signed,
|
||||
gdb::array_view<const gdb_byte> dst = register_buffer (regnum);
|
||||
bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
|
||||
copy_integer_to_size (addr, addr_len, dst.data (), dst.size (), is_signed,
|
||||
byte_order);
|
||||
}
|
||||
|
||||
@ -1157,7 +1230,8 @@ regcache::transfer_regset_register (struct regcache *out_regcache, int regnum,
|
||||
|
||||
if (out_buf != nullptr)
|
||||
{
|
||||
raw_collect_part (regnum, 0, reg_size, out_buf + offs);
|
||||
raw_collect_part (regnum, 0,
|
||||
gdb::make_array_view (out_buf + offs, reg_size));
|
||||
|
||||
/* Ensure any additional space is cleared. */
|
||||
if (slot_size > reg_size)
|
||||
@ -1168,12 +1242,14 @@ regcache::transfer_regset_register (struct regcache *out_regcache, int regnum,
|
||||
/* Zero-extend the register value if the slot is smaller than the register. */
|
||||
if (slot_size < register_size (gdbarch, regnum))
|
||||
out_regcache->raw_supply_zeroed (regnum);
|
||||
out_regcache->raw_supply_part (regnum, 0, reg_size, in_buf + offs);
|
||||
out_regcache->raw_supply_part (regnum, 0,
|
||||
gdb::make_array_view (in_buf + offs,
|
||||
reg_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalidate the register. */
|
||||
out_regcache->raw_supply (regnum, nullptr);
|
||||
out_regcache->raw_supply (regnum, {});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1304,13 +1380,12 @@ 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);
|
||||
gdb::array_view<const gdb_byte> regbuf = register_buffer (regnum);
|
||||
gdb_assert (offset <= regbuf.size ());
|
||||
regbuf = regbuf.slice (offset);
|
||||
|
||||
return (memcmp (buf, regbuf + offset, size - offset) == 0);
|
||||
return memcmp (buf, regbuf.data (), regbuf.size ()) == 0;
|
||||
}
|
||||
|
||||
/* Special handling for register PC. */
|
||||
@ -1399,17 +1474,15 @@ regcache::debug_print_register (const char *func, int regno)
|
||||
if (regno >= 0 && regno < gdbarch_num_regs (gdbarch))
|
||||
{
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
int size = register_size (gdbarch, regno);
|
||||
gdb_byte *buf = register_buffer (regno);
|
||||
gdb::array_view<gdb_byte> buf = register_buffer (regno);
|
||||
|
||||
gdb_printf (gdb_stdlog, " = ");
|
||||
for (int i = 0; i < size; i++)
|
||||
for (gdb_byte byte : buf)
|
||||
gdb_printf (gdb_stdlog, "%02x", byte);
|
||||
|
||||
if (buf.size () <= sizeof (LONGEST))
|
||||
{
|
||||
gdb_printf (gdb_stdlog, "%02x", buf[i]);
|
||||
}
|
||||
if (size <= sizeof (LONGEST))
|
||||
{
|
||||
ULONGEST val = extract_unsigned_integer (buf, size, byte_order);
|
||||
ULONGEST val = extract_unsigned_integer (buf, byte_order);
|
||||
|
||||
gdb_printf (gdb_stdlog, " %s %s",
|
||||
core_addr_to_string_nz (val), plongest (val));
|
||||
@ -1758,6 +1831,23 @@ registers_changed_ptid_target_ptid_test ()
|
||||
ptid_t (2, 2)) == 1);
|
||||
}
|
||||
|
||||
/* Test using reg_buffer::raw_compare with offset equal to the register size
|
||||
(thus comparing 0 bytes). */
|
||||
|
||||
static void
|
||||
reg_buffer_raw_compare_zero_len_test ()
|
||||
{
|
||||
regcache_test_data_up data = populate_regcaches_for_test ();
|
||||
inferior &inf = data->test_ctx_1.mock_inferior;
|
||||
const regcache *regcache
|
||||
= get_thread_arch_regcache (&inf, ptid_t (1, 1), inf.arch ());
|
||||
|
||||
/* The buffer address is irrelevant since we end up comparing 0 bytes, we just
|
||||
need to pass something. */
|
||||
gdb_byte buf;
|
||||
SELF_CHECK (regcache->raw_compare (0, &buf, register_size (inf.arch (), 0)));
|
||||
}
|
||||
|
||||
class target_ops_no_register : public test_target_ops
|
||||
{
|
||||
public:
|
||||
@ -1869,7 +1959,7 @@ cooked_read_test (struct gdbarch *gdbarch)
|
||||
readwrite.set_ptid (mockctx.mock_ptid);
|
||||
gdb::byte_vector buf (register_size (gdbarch, nonzero_regnum));
|
||||
|
||||
readwrite.raw_read (nonzero_regnum, buf.data ());
|
||||
readwrite.raw_read (nonzero_regnum, buf);
|
||||
|
||||
/* raw_read calls target_fetch_registers. */
|
||||
SELF_CHECK (mockctx.mock_target.fetch_registers_called > 0);
|
||||
@ -1890,9 +1980,7 @@ cooked_read_test (struct gdbarch *gdbarch)
|
||||
|
||||
gdb::byte_vector inner_buf (register_size (gdbarch, regnum));
|
||||
|
||||
SELF_CHECK (REG_VALID == readwrite.cooked_read (regnum,
|
||||
inner_buf.data ()));
|
||||
|
||||
SELF_CHECK (REG_VALID == readwrite.cooked_read (regnum, inner_buf));
|
||||
SELF_CHECK (mockctx.mock_target.fetch_registers_called == 0);
|
||||
SELF_CHECK (mockctx.mock_target.store_registers_called == 0);
|
||||
SELF_CHECK (mockctx.mock_target.xfer_partial_called == 0);
|
||||
@ -1912,8 +2000,7 @@ cooked_read_test (struct gdbarch *gdbarch)
|
||||
continue;
|
||||
|
||||
gdb::byte_vector inner_buf (register_size (gdbarch, regnum));
|
||||
enum register_status status = readonly.cooked_read (regnum,
|
||||
inner_buf.data ());
|
||||
register_status status = readonly.cooked_read (regnum, inner_buf);
|
||||
|
||||
if (regnum < gdbarch_num_regs (gdbarch))
|
||||
{
|
||||
@ -2003,8 +2090,8 @@ cooked_write_test (struct gdbarch *gdbarch)
|
||||
&& regnum <= gdbarch_num_regs (gdbarch) + 4))
|
||||
continue;
|
||||
|
||||
std::vector<gdb_byte> expected (register_size (gdbarch, regnum), 0);
|
||||
std::vector<gdb_byte> buf (register_size (gdbarch, regnum), 0);
|
||||
gdb::byte_vector expected (register_size (gdbarch, regnum), 0);
|
||||
gdb::byte_vector buf (register_size (gdbarch, regnum), 0);
|
||||
const auto type = register_type (gdbarch, regnum);
|
||||
|
||||
if (type->code () == TYPE_CODE_FLT
|
||||
@ -2059,9 +2146,9 @@ cooked_write_test (struct gdbarch *gdbarch)
|
||||
SELF_CHECK (0);
|
||||
}
|
||||
|
||||
readwrite.cooked_write (regnum, expected.data ());
|
||||
readwrite.cooked_write (regnum, expected);
|
||||
|
||||
SELF_CHECK (readwrite.cooked_read (regnum, buf.data ()) == REG_VALID);
|
||||
SELF_CHECK (readwrite.cooked_read (regnum, buf) == REG_VALID);
|
||||
SELF_CHECK (expected == buf);
|
||||
}
|
||||
}
|
||||
@ -2154,6 +2241,8 @@ _initialize_regcache ()
|
||||
selftests::registers_changed_ptid_target_pid_test);
|
||||
selftests::register_test ("registers_changed_ptid_target_ptid",
|
||||
selftests::registers_changed_ptid_target_ptid_test);
|
||||
selftests::register_test ("reg_buffer_raw_compare_zero_len",
|
||||
selftests::reg_buffer_raw_compare_zero_len_test);
|
||||
|
||||
selftests::register_test_foreach_arch ("regcache::cooked_read_test",
|
||||
selftests::cooked_read_test);
|
||||
|
110
gdb/regcache.h
110
gdb/regcache.h
@ -20,6 +20,7 @@
|
||||
#ifndef REGCACHE_H
|
||||
#define REGCACHE_H
|
||||
|
||||
#include "gdbsupport/array-view.h"
|
||||
#include "gdbsupport/common-regcache.h"
|
||||
#include "gdbsupport/function-view.h"
|
||||
|
||||
@ -167,8 +168,8 @@ extern struct type *register_type (struct gdbarch *gdbarch, int regnum);
|
||||
|
||||
extern int register_size (struct gdbarch *gdbarch, int regnum);
|
||||
|
||||
typedef gdb::function_view<register_status (int regnum, gdb_byte *buf)>
|
||||
register_read_ftype;
|
||||
using register_read_ftype
|
||||
= gdb::function_view<register_status (int, gdb::array_view<gdb_byte>)>;
|
||||
|
||||
/* A (register_number, register_value) pair. */
|
||||
|
||||
@ -194,7 +195,10 @@ public:
|
||||
enum register_status get_register_status (int regnum) const override;
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
void raw_collect (int regnum, void *buf) const override;
|
||||
void raw_collect (int regnum, gdb::array_view<gdb_byte> dst) const override;
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
void raw_collect (int regnum, void *dst) const;
|
||||
|
||||
/* 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.
|
||||
@ -204,17 +208,23 @@ public:
|
||||
void raw_collect_integer (int regnum, gdb_byte *addr, int addr_len,
|
||||
bool is_signed) const;
|
||||
|
||||
/* Collect register REGNUM from REGCACHE, starting at OFFSET in register,
|
||||
reading only LEN. */
|
||||
void raw_collect_part (int regnum, int offset, int len, gdb_byte *out) const;
|
||||
/* Collect part of register REGNUM from this register buffer. Start at OFFSET
|
||||
in register. The size is given by the size of DST. */
|
||||
void raw_collect_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst) const;
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
void raw_collect_part (int regnum, int offset, int len, gdb_byte *dst) const
|
||||
{ raw_collect_part (regnum, offset, gdb::make_array_view (dst, len)); }
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
void raw_supply (int regnum, const void *buf) override;
|
||||
void raw_supply (int regnum, gdb::array_view<const gdb_byte> src) override;
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
void raw_supply (int regnum, const void *src);
|
||||
|
||||
void raw_supply (int regnum, const reg_buffer &src)
|
||||
{
|
||||
raw_supply (regnum, src.register_buffer (regnum));
|
||||
}
|
||||
{ raw_supply (regnum, src.register_buffer (regnum)); }
|
||||
|
||||
/* 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.
|
||||
@ -229,9 +239,11 @@ public:
|
||||
unavailable). */
|
||||
void raw_supply_zeroed (int regnum);
|
||||
|
||||
/* Supply register REGNUM to REGCACHE, starting at OFFSET in register, writing
|
||||
only LEN, without editing the rest of the register. */
|
||||
void raw_supply_part (int regnum, int offset, int len, const gdb_byte *in);
|
||||
/* Supply part of register REGNUM to this register buffer. Start at OFFSET in
|
||||
the register. The size is given by the size of SRC. The rest of the
|
||||
register left untouched. */
|
||||
void raw_supply_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src);
|
||||
|
||||
void invalidate (int regnum);
|
||||
|
||||
@ -246,7 +258,11 @@ protected:
|
||||
|
||||
int num_raw_registers () const;
|
||||
|
||||
gdb_byte *register_buffer (int regnum) const;
|
||||
/* Return a view on register REGNUM's buffer cache. */
|
||||
template <typename ElemType>
|
||||
gdb::array_view<ElemType> register_buffer (int regnum) const;
|
||||
gdb::array_view<const gdb_byte> register_buffer (int regnum) const;
|
||||
gdb::array_view<gdb_byte> register_buffer (int regnum);
|
||||
|
||||
/* Save a register cache. The set of registers saved into the
|
||||
regcache determined by the save_reggroup. COOKED_READ returns
|
||||
@ -276,27 +292,41 @@ public:
|
||||
|
||||
/* Transfer a raw register [0..NUM_REGS) from core-gdb to this regcache,
|
||||
return its value in *BUF and return its availability status. */
|
||||
register_status raw_read (int regnum, gdb::array_view<gdb_byte> dst);
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
register_status raw_read (int regnum, gdb_byte *dst);
|
||||
|
||||
enum register_status raw_read (int regnum, gdb_byte *buf);
|
||||
template<typename T, typename = RequireLongest<T>>
|
||||
enum register_status raw_read (int regnum, T *val);
|
||||
register_status raw_read (int regnum, T *val);
|
||||
|
||||
/* Partial transfer of raw registers. Return the status of the register. */
|
||||
enum register_status raw_read_part (int regnum, int offset, int len,
|
||||
gdb_byte *buf);
|
||||
register_status raw_read_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst);
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
register_status raw_read_part (int regnum, int offset, int len,
|
||||
gdb_byte *dst)
|
||||
{ return raw_read_part (regnum, offset, gdb::make_array_view (dst, len)); }
|
||||
|
||||
/* Make certain that the register REGNUM is up-to-date. */
|
||||
virtual void raw_update (int regnum) = 0;
|
||||
|
||||
/* Transfer a raw register [0..NUM_REGS+NUM_PSEUDO_REGS) from core-gdb to
|
||||
this regcache, return its value in *BUF and return its availability status. */
|
||||
enum register_status cooked_read (int regnum, gdb_byte *buf);
|
||||
this regcache, return its value in DST and return its availability status. */
|
||||
register_status cooked_read (int regnum, gdb::array_view<gdb_byte> dst);
|
||||
register_status cooked_read (int regnum, gdb_byte *dst);
|
||||
|
||||
template<typename T, typename = RequireLongest<T>>
|
||||
enum register_status cooked_read (int regnum, T *val);
|
||||
register_status cooked_read (int regnum, T *val);
|
||||
|
||||
/* Partial transfer of a cooked register. */
|
||||
enum register_status cooked_read_part (int regnum, int offset, int len,
|
||||
gdb_byte *buf);
|
||||
register_status cooked_read_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst);
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
register_status cooked_read_part (int regnum, int offset, int len, gdb_byte *src)
|
||||
{ return cooked_read_part (regnum, offset, gdb::make_array_view (src, len)); }
|
||||
|
||||
/* Read register REGNUM from the regcache and return a new value. This
|
||||
will call mark_value_bytes_unavailable as appropriate. */
|
||||
@ -306,8 +336,8 @@ protected:
|
||||
|
||||
/* Perform a partial register transfer using a read, modify, write
|
||||
operation. Will fail if register is currently invalid. */
|
||||
enum register_status read_part (int regnum, int offset, int len,
|
||||
gdb_byte *out, bool is_raw);
|
||||
register_status read_part (int regnum, int offset,
|
||||
gdb::array_view<gdb_byte> dst, bool is_raw);
|
||||
};
|
||||
|
||||
/* Buffer of registers, can be read and written. */
|
||||
@ -343,13 +373,19 @@ public:
|
||||
/* Update the value of raw register REGNUM (in the range [0..NUM_REGS)) and
|
||||
transfer its value to core-gdb. */
|
||||
|
||||
void raw_write (int regnum, const gdb_byte *buf);
|
||||
void raw_write (int regnum, gdb::array_view<const gdb_byte> src);
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
void raw_write (int regnum, const gdb_byte *src);
|
||||
|
||||
template<typename T, typename = RequireLongest<T>>
|
||||
void raw_write (int regnum, T val);
|
||||
|
||||
/* Transfer of pseudo-registers. */
|
||||
void cooked_write (int regnum, const gdb_byte *buf);
|
||||
void cooked_write (int regnum, gdb::array_view<const gdb_byte> src);
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
void cooked_write (int regnum, const gdb_byte *src);
|
||||
|
||||
template<typename T, typename = RequireLongest<T>>
|
||||
void cooked_write (int regnum, T val);
|
||||
@ -358,12 +394,21 @@ public:
|
||||
|
||||
/* Partial transfer of raw registers. Perform read, modify, write style
|
||||
operations. */
|
||||
void raw_write_part (int regnum, int offset, int len, const gdb_byte *buf);
|
||||
void raw_write_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src);
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
void raw_write_part (int regnum, int offset, int len, const gdb_byte *src)
|
||||
{ raw_write_part (regnum, offset, gdb::make_array_view (src, len)); }
|
||||
|
||||
/* Partial transfer of a cooked register. Perform read, modify, write style
|
||||
operations. */
|
||||
void cooked_write_part (int regnum, int offset, int len,
|
||||
const gdb_byte *buf);
|
||||
void cooked_write_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src);
|
||||
|
||||
/* Deprecated overload of the above. */
|
||||
void cooked_write_part (int regnum, int offset, int len, const gdb_byte *src)
|
||||
{ cooked_write_part (regnum, offset, gdb::make_array_view (src, len)); }
|
||||
|
||||
/* Transfer a set of registers (as described by REGSET) between
|
||||
REGCACHE and BUF. If REGNUM == -1, transfer all registers
|
||||
@ -430,8 +475,9 @@ private:
|
||||
|
||||
/* Perform a partial register transfer using a read, modify, write
|
||||
operation. */
|
||||
enum register_status write_part (int regnum, int offset, int len,
|
||||
const gdb_byte *in, bool is_raw);
|
||||
register_status write_part (int regnum, int offset,
|
||||
gdb::array_view<const gdb_byte> src,
|
||||
bool is_raw);
|
||||
|
||||
/* The inferior to switch to, to make target calls.
|
||||
|
||||
|
@ -315,27 +315,32 @@ regcache_register_size (const reg_buffer_common *regcache, int n)
|
||||
(gdb::checked_static_cast<const struct regcache *> (regcache)->tdesc, n);
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
static gdb::array_view<gdb_byte>
|
||||
register_data (const struct regcache *regcache, int n)
|
||||
{
|
||||
return (regcache->registers
|
||||
+ find_register_by_number (regcache->tdesc, n).offset / 8);
|
||||
const gdb::reg ® = find_register_by_number (regcache->tdesc, n);
|
||||
return gdb::make_array_view (regcache->registers + reg.offset / 8,
|
||||
reg.size / 8);
|
||||
}
|
||||
|
||||
void
|
||||
supply_register (struct regcache *regcache, int n, const void *buf)
|
||||
supply_register (struct regcache *regcache, int n, const void *vbuf)
|
||||
{
|
||||
return regcache->raw_supply (n, buf);
|
||||
const gdb::reg ® = find_register_by_number (regcache->tdesc, n);
|
||||
const gdb_byte *buf = static_cast<const gdb_byte *> (vbuf);
|
||||
return regcache->raw_supply (n, gdb::make_array_view (buf, reg.size / 8));
|
||||
}
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
|
||||
void
|
||||
regcache::raw_supply (int n, const void *buf)
|
||||
regcache::raw_supply (int n, gdb::array_view<const gdb_byte> src)
|
||||
{
|
||||
if (buf)
|
||||
auto dst = register_data (this, n);
|
||||
|
||||
if (src.data () != nullptr)
|
||||
{
|
||||
memcpy (register_data (this, n), buf, register_size (tdesc, n));
|
||||
copy (src, dst);
|
||||
#ifndef IN_PROCESS_AGENT
|
||||
if (register_status != NULL)
|
||||
register_status[n] = REG_VALID;
|
||||
@ -343,7 +348,7 @@ regcache::raw_supply (int n, const void *buf)
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (register_data (this, n), 0, register_size (tdesc, n));
|
||||
memset (dst.data (), 0, dst.size ());
|
||||
#ifndef IN_PROCESS_AGENT
|
||||
if (register_status != NULL)
|
||||
register_status[n] = REG_UNAVAILABLE;
|
||||
@ -356,8 +361,8 @@ regcache::raw_supply (int n, const void *buf)
|
||||
void
|
||||
supply_register_zeroed (struct regcache *regcache, int n)
|
||||
{
|
||||
memset (register_data (regcache, n), 0,
|
||||
register_size (regcache->tdesc, n));
|
||||
auto dst = register_data (regcache, n);
|
||||
memset (dst.data (), 0, dst.size ());
|
||||
#ifndef IN_PROCESS_AGENT
|
||||
if (regcache->register_status != NULL)
|
||||
regcache->register_status[n] = REG_VALID;
|
||||
@ -426,17 +431,20 @@ supply_register_by_name (struct regcache *regcache,
|
||||
#endif
|
||||
|
||||
void
|
||||
collect_register (struct regcache *regcache, int n, void *buf)
|
||||
collect_register (struct regcache *regcache, int n, void *vbuf)
|
||||
{
|
||||
regcache->raw_collect (n, buf);
|
||||
const gdb::reg ® = find_register_by_number (regcache->tdesc, n);
|
||||
gdb_byte *buf = static_cast<gdb_byte *> (vbuf);
|
||||
regcache->raw_collect (n, gdb::make_array_view (buf, reg.size / 8));
|
||||
}
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
|
||||
void
|
||||
regcache::raw_collect (int n, void *buf) const
|
||||
regcache::raw_collect (int n, gdb::array_view<gdb_byte> dst) const
|
||||
{
|
||||
memcpy (buf, register_data (this, n), register_size (tdesc, n));
|
||||
auto src = register_data (this, n);
|
||||
copy (src, dst);
|
||||
}
|
||||
|
||||
enum register_status
|
||||
@ -476,8 +484,7 @@ regcache_raw_get_unsigned_by_name (struct regcache *regcache,
|
||||
void
|
||||
collect_register_as_string (struct regcache *regcache, int n, char *buf)
|
||||
{
|
||||
bin2hex (register_data (regcache, n), buf,
|
||||
register_size (regcache->tdesc, n));
|
||||
bin2hex (register_data (regcache, n), buf);
|
||||
}
|
||||
|
||||
void
|
||||
@ -524,9 +531,9 @@ regcache::raw_compare (int regnum, const void *buf, int offset) const
|
||||
{
|
||||
gdb_assert (buf != NULL);
|
||||
|
||||
const unsigned char *regbuf = register_data (this, regnum);
|
||||
int size = register_size (tdesc, regnum);
|
||||
gdb_assert (size >= offset);
|
||||
gdb::array_view<const gdb_byte> regbuf = register_data (this, regnum);
|
||||
gdb_assert (offset < regbuf.size ());
|
||||
regbuf = regbuf.slice (offset);
|
||||
|
||||
return (memcmp (buf, regbuf + offset, size - offset) == 0);
|
||||
return memcmp (buf, regbuf.data (), regbuf.size ()) == 0;
|
||||
}
|
||||
|
@ -50,10 +50,10 @@ struct regcache : public reg_buffer_common
|
||||
enum register_status get_register_status (int regnum) const override;
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
void raw_supply (int regnum, const void *buf) override;
|
||||
void raw_supply (int regnum, gdb::array_view<const gdb_byte> src) override;
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
void raw_collect (int regnum, void *buf) const override;
|
||||
void raw_collect (int regnum, gdb::array_view<gdb_byte> dst) const override;
|
||||
|
||||
/* See gdbsupport/common-regcache.h. */
|
||||
bool raw_compare (int regnum, const void *buf, int offset) const override;
|
||||
|
@ -78,11 +78,41 @@ struct reg_buffer_common
|
||||
buffer. */
|
||||
virtual register_status get_register_status (int regnum) const = 0;
|
||||
|
||||
/* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE. */
|
||||
virtual void raw_supply (int regnum, const void *buf) = 0;
|
||||
/* Supply register REGNUM, whose contents are stored in SRC, to this register
|
||||
buffer. */
|
||||
virtual void raw_supply (int regnum, gdb::array_view<const gdb_byte> src)
|
||||
= 0;
|
||||
|
||||
/* Collect register REGNUM from REGCACHE and store its contents in BUF. */
|
||||
virtual void raw_collect (int regnum, void *buf) const = 0;
|
||||
void raw_supply (int regnum, const uint64_t *src)
|
||||
{
|
||||
raw_supply (regnum,
|
||||
gdb::make_array_view ((const gdb_byte *) src, sizeof (*src)));
|
||||
}
|
||||
|
||||
void raw_supply (int regnum, const gdb_byte *src)
|
||||
{
|
||||
raw_supply (regnum,
|
||||
gdb::make_array_view (src,
|
||||
regcache_register_size (this, regnum)));
|
||||
}
|
||||
|
||||
/* Collect register REGNUM from this register buffer and store its contents in
|
||||
DST. */
|
||||
virtual void raw_collect (int regnum, gdb::array_view<gdb_byte> dst) const
|
||||
= 0;
|
||||
|
||||
void raw_collect (int regnum, uint64_t *dst) const
|
||||
{
|
||||
raw_collect (regnum,
|
||||
gdb::make_array_view ((gdb_byte *) dst, sizeof (*dst)));
|
||||
};
|
||||
|
||||
void raw_collect (int regnum, gdb_byte *dst)
|
||||
{
|
||||
raw_collect (regnum,
|
||||
gdb::make_array_view (dst,
|
||||
regcache_register_size (this, regnum)));
|
||||
}
|
||||
|
||||
/* Compare the contents of the register stored in the regcache (ignoring the
|
||||
first OFFSET bytes) to the contents of BUF (without any offset). Returns
|
||||
|
@ -143,6 +143,14 @@ bin2hex (const gdb_byte *bin, char *hex, int count)
|
||||
|
||||
/* See rsp-low.h. */
|
||||
|
||||
int
|
||||
bin2hex (gdb::array_view<gdb_byte> bin, char *hex)
|
||||
{
|
||||
return bin2hex (bin.data (), hex, bin.size ());
|
||||
}
|
||||
|
||||
/* See rsp-low.h. */
|
||||
|
||||
std::string
|
||||
bin2hex (const gdb_byte *bin, int count)
|
||||
{
|
||||
|
@ -54,6 +54,8 @@ extern std::string hex2str (const char *hex, int count);
|
||||
|
||||
extern int bin2hex (const gdb_byte *bin, char *hex, int count);
|
||||
|
||||
extern int bin2hex (gdb::array_view<gdb_byte> bin, char *hex);
|
||||
|
||||
/* Overloaded version of bin2hex that returns a std::string. */
|
||||
|
||||
extern std::string bin2hex (const gdb_byte *bin, int count);
|
||||
|
Loading…
x
Reference in New Issue
Block a user