aboutsummaryrefslogtreecommitdiff
path: root/gdbserver
diff options
context:
space:
mode:
authorSimon Marchi <simon.marchi@efficios.com>2023-12-01 11:27:18 -0500
committerSimon Marchi <simon.marchi@efficios.com>2023-12-14 16:04:49 +0000
commit51e6b8cfd649013ae16a3d00f1451b2531ba6bc9 (patch)
tree7f07b62493f0ffdcfb523d57452812cf491a88f2 /gdbserver
parent08d8e7ff9474a88b491d22139ace851daae1a1c6 (diff)
downloadgdb-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')
-rw-r--r--gdbserver/regcache.cc49
-rw-r--r--gdbserver/regcache.h4
2 files changed, 30 insertions, 23 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 &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 &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 &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;
}
diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
index 4700c03..02791a0 100644
--- a/gdbserver/regcache.h
+++ b/gdbserver/regcache.h
@@ -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;