diff options
author | Simon Marchi <simon.marchi@efficios.com> | 2023-12-01 11:27:18 -0500 |
---|---|---|
committer | Simon Marchi <simon.marchi@efficios.com> | 2023-12-14 16:04:49 +0000 |
commit | 51e6b8cfd649013ae16a3d00f1451b2531ba6bc9 (patch) | |
tree | 7f07b62493f0ffdcfb523d57452812cf491a88f2 /gdbserver/regcache.cc | |
parent | 08d8e7ff9474a88b491d22139ace851daae1a1c6 (diff) | |
download | gdb-51e6b8cfd649013ae16a3d00f1451b2531ba6bc9.zip gdb-51e6b8cfd649013ae16a3d00f1451b2531ba6bc9.tar.gz gdb-51e6b8cfd649013ae16a3d00f1451b2531ba6bc9.tar.bz2 |
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>
Diffstat (limited to 'gdbserver/regcache.cc')
-rw-r--r-- | gdbserver/regcache.cc | 49 |
1 files changed, 28 insertions, 21 deletions
diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc index 823ea1f..c5d3670 100644 --- a/gdbserver/regcache.cc +++ b/gdbserver/regcache.cc @@ -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; } |