aboutsummaryrefslogtreecommitdiff
path: root/gdb/regcache.h
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 /gdb/regcache.h
parent08d8e7ff9474a88b491d22139ace851daae1a1c6 (diff)
downloadbinutils-51e6b8cfd649013ae16a3d00f1451b2531ba6bc9.zip
binutils-51e6b8cfd649013ae16a3d00f1451b2531ba6bc9.tar.gz
binutils-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 'gdb/regcache.h')
-rw-r--r--gdb/regcache.h110
1 files changed, 78 insertions, 32 deletions
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 7922a5c..d90f74b 100644
--- a/gdb/regcache.h
+++ b/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.