diff options
-rw-r--r-- | gdb/aarch64-linux-nat.c | 57 | ||||
-rw-r--r-- | gdb/common/common-regcache.h | 9 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 1 | ||||
-rw-r--r-- | gdb/gdbserver/regcache.c | 8 | ||||
-rw-r--r-- | gdb/gdbserver/regcache.h | 20 | ||||
-rw-r--r-- | gdb/nat/aarch64-sve-linux-ptrace.c | 258 | ||||
-rw-r--r-- | gdb/nat/aarch64-sve-linux-ptrace.h | 122 | ||||
-rw-r--r-- | gdb/regcache.c | 4 | ||||
-rw-r--r-- | gdb/regcache.h | 10 |
9 files changed, 466 insertions, 23 deletions
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index 79dd9ce..8165594 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -384,19 +384,65 @@ store_fpregs_to_thread (ptid_t ptid, const reg_buffer *regcache) } } +/* Fill GDB's register array with the sve register values + from the current thread. */ + +static void +fetch_sveregs_from_thread (ptid_t ptid, reg_buffer *regcache) +{ + gdb_byte *base = aarch64_sve_get_sveregs (ptid.lwp ()); + aarch64_sve_regs_copy_to_regcache (regcache, base); + xfree (base); +} + +/* Store to the current thread the valid sve register + values in the GDB's register array. */ + +static void +store_sveregs_to_thread (ptid_t ptid, reg_buffer *regcache) +{ + gdb_byte *base; + int ret, tid; + struct iovec iovec; + + tid = ptid_get_lwp (inferior_ptid); + + /* Obtain a dump of SVE registers from ptrace. */ + base = aarch64_sve_get_sveregs (tid); + + /* Overwrite with regcache state. */ + aarch64_sve_regs_copy_from_regcache (regcache, base); + + /* Write back to the kernel. */ + iovec.iov_base = base; + iovec.iov_len = ((struct user_sve_header *) base)->size; + ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec); + xfree (base); + + if (ret < 0) + perror_with_name (_("Unable to store sve registers")); +} + /* Implement the "fetch_registers" target_ops method. */ void aarch64_linux_nat_target::fetch_registers (ptid_t ptid, reg_buffer *regcache, int regno) { + struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + if (regno == -1) { fetch_gregs_from_thread (ptid, regcache); - fetch_fpregs_from_thread (ptid, regcache); + if (tdep->has_sve ()) + fetch_sveregs_from_thread (ptid, regcache); + else + fetch_fpregs_from_thread (ptid, regcache); } else if (regno < AARCH64_V0_REGNUM) fetch_gregs_from_thread (ptid, regcache); + else if (tdep->has_sve ()) + fetch_sveregs_from_thread (ptid, regcache); else fetch_fpregs_from_thread (ptid, regcache); } @@ -407,13 +453,20 @@ void aarch64_linux_nat_target::store_registers (ptid_t ptid, reg_buffer *regcache, int regno) { + struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + if (regno == -1) { store_gregs_to_thread (ptid, regcache); - store_fpregs_to_thread (ptid, regcache); + if (tdep->has_sve ()) + store_sveregs_to_thread (ptid, regcache); + else + store_fpregs_to_thread (ptid, regcache); } else if (regno < AARCH64_V0_REGNUM) store_gregs_to_thread (ptid, regcache); + else if (tdep->has_sve ()) + store_sveregs_to_thread (ptid, regcache); else store_fpregs_to_thread (ptid, regcache); } diff --git a/gdb/common/common-regcache.h b/gdb/common/common-regcache.h index 9709ba4..3f18cce 100644 --- a/gdb/common/common-regcache.h +++ b/gdb/common/common-regcache.h @@ -62,4 +62,13 @@ extern enum register_status regcache_raw_read_unsigned ULONGEST regcache_raw_get_unsigned (struct regcache *regcache, int regnum); +struct reg_buffer_common +{ + virtual ~reg_buffer_common () = default; + virtual void raw_supply (int regnum, const void *buf) = 0; + virtual void raw_collect (int regnum, void *buf) const = 0; + virtual bool raw_compare (int regnum, const void *buf, int offset) const = 0; + virtual register_status get_register_status (int regnum) const = 0; +}; + #endif /* COMMON_REGCACHE_H */ diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 675faa4..f924e6a 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -219,6 +219,7 @@ SFILES = \ $(srcdir)/common/tdesc.c \ $(srcdir)/common/vec.c \ $(srcdir)/common/xml-utils.c \ + $(srcdir)/nat/aarch64-sve-linux-ptrace.c \ $(srcdir)/nat/linux-btrace.c \ $(srcdir)/nat/linux-namespaces.c \ $(srcdir)/nat/linux-osdata.c \ diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c index 88f0db0..39bc6f0 100644 --- a/gdb/gdbserver/regcache.c +++ b/gdb/gdbserver/regcache.c @@ -159,7 +159,7 @@ init_register_cache (struct regcache *regcache, struct regcache * new_register_cache (const struct target_desc *tdesc) { - struct regcache *regcache = XCNEW (struct regcache); + struct regcache *regcache = new struct regcache; gdb_assert (tdesc->registers_size != 0); @@ -174,7 +174,7 @@ free_register_cache (struct regcache *regcache) if (regcache->registers_owned) free (regcache->registers); free (regcache->register_status); - free (regcache); + delete regcache; } } @@ -506,10 +506,10 @@ regcache::get_register_status (int regnum) const first OFFSET bytes) to the contents of BUF (without any offset). Returns 0 if identical. */ -int +bool regcache::raw_compare (int regnum, const void *buf, int offset) const { gdb_assert (register_size (tdesc, regnum) > offset); return memcmp (buf, register_data (this, regnum, 1) + offset, - register_size (tdesc, regnum) - offset); + register_size (tdesc, regnum) - offset) == 0; } diff --git a/gdb/gdbserver/regcache.h b/gdb/gdbserver/regcache.h index b3631be..ad199a9 100644 --- a/gdb/gdbserver/regcache.h +++ b/gdb/gdbserver/regcache.h @@ -28,31 +28,31 @@ struct target_desc; inferior; this is primarily for simplicity, as the performance benefit is minimal. */ -struct regcache +struct regcache : public reg_buffer_common { /* The regcache's target description. */ - const struct target_desc *tdesc; + const struct target_desc *tdesc = nullptr; /* Whether the REGISTERS buffer's contents are valid. If false, we haven't fetched the registers from the target yet. Not that this register cache is _not_ pass-through, unlike GDB's. Note that "valid" here is unrelated to whether the registers are available in a traceframe. For that, check REGISTER_STATUS below. */ - int registers_valid; - int registers_owned; - unsigned char *registers; + int registers_valid = 0; + int registers_owned = 0; + unsigned char *registers = nullptr; #ifndef IN_PROCESS_AGENT /* One of REG_UNAVAILBLE or REG_VALID. */ - unsigned char *register_status; + unsigned char *register_status = nullptr; #endif - void raw_supply (int regnum, const void *buf); + void raw_supply (int regnum, const void *buf) override; - void raw_collect (int regnum, void *buf) const; + void raw_collect (int regnum, void *buf) const override; - int raw_compare (int regnum, const void *buf, int offset) const; + bool raw_compare (int regnum, const void *buf, int offset) const override; - enum register_status get_register_status (int regnum) const; + enum register_status get_register_status (int regnum) const override; }; struct regcache *init_register_cache (struct regcache *regcache, diff --git a/gdb/nat/aarch64-sve-linux-ptrace.c b/gdb/nat/aarch64-sve-linux-ptrace.c index 3a1dbae..0f0b76c 100644 --- a/gdb/nat/aarch64-sve-linux-ptrace.c +++ b/gdb/nat/aarch64-sve-linux-ptrace.c @@ -25,6 +25,8 @@ #include "aarch64-sve-linux-ptrace.h" #include "arch/aarch64.h" +static bool vq_change_warned = false; + /* See nat/aarch64-sve-linux-ptrace.h. */ unsigned long @@ -56,3 +58,259 @@ aarch64_sve_get_vq (int tid) return vq; } + +/* Read the current SVE register set using ptrace, allocating space as + required. */ + +gdb_byte * +aarch64_sve_get_sveregs (int tid) +{ + int ret; + struct iovec iovec; + struct user_sve_header header; + long vq = aarch64_sve_get_vq (tid); + + if (vq == 0) + perror_with_name (_("Unable to fetch sve register header")); + + /* A ptrace call with NT_ARM_SVE will return a header followed by either a + dump of all the SVE and FP registers, or an fpsimd structure (identical to + the one returned by NT_FPREGSET) if the kernel has not yet executed any + SVE code. Make sure we allocate enough space for a full SVE dump. */ + + iovec.iov_len = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE); + iovec.iov_base = xmalloc (iovec.iov_len); + + ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec); + if (ret < 0) + perror_with_name (_("Unable to fetch sve registers")); + + return (gdb_byte *) iovec.iov_base; +} + +/* Put the registers from linux structure buf into regcache. */ + +void +aarch64_sve_regs_copy_to_regcache (reg_buffer_common *regcache, const void *buf) +{ + char *base = (char*) buf; + int i; + struct user_sve_header *header = (struct user_sve_header *) buf; + long vq, vg_regcache; + + vq = sve_vq_from_vl (header->vl); + + /* Sanity check the data in the header. */ + gdb_assert (sve_vl_valid (header->vl)); + gdb_assert (SVE_PT_SIZE (vq, header->flags) == header->size); + + regcache->raw_collect (AARCH64_SVE_VG_REGNUM, &vg_regcache); + if (vg_regcache == 0) + { + /* VG has not been set. */ + vg_regcache = sve_vg_from_vl (header->vl); + regcache->raw_supply (AARCH64_SVE_VG_REGNUM, &vg_regcache); + } + else if (vg_regcache != sve_vg_from_vl (header->vl) && !vq_change_warned) + { + /* Vector length on the running process has changed. GDB currently does + not support this and will result in GDB showing incorrect partially + incorrect data for the vector registers. Warn once and continue. We + do not expect many programs to exhibit this behaviour. To fix this + we need to spot the change earlier and generate a new target + descriptor. */ + warning (_("Vector length has changed (%ld to %d). " + "Vector registers may show incorrect data."), + vg_regcache, sve_vg_from_vl (header->vl)); + vq_change_warned = true; + } + + if (HAS_SVE_STATE (*header)) + { + /* The register dump contains a set of SVE registers. */ + + for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) + regcache->raw_supply (AARCH64_SVE_Z0_REGNUM + i, + base + SVE_PT_SVE_ZREG_OFFSET (vq, i)); + + for (i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) + regcache->raw_supply (AARCH64_SVE_P0_REGNUM + i, + base + SVE_PT_SVE_PREG_OFFSET (vq, i)); + + regcache->raw_supply (AARCH64_SVE_FFR_REGNUM, + base + SVE_PT_SVE_FFR_OFFSET (vq)); + regcache->raw_supply (AARCH64_FPSR_REGNUM, + base + SVE_PT_SVE_FPSR_OFFSET (vq)); + regcache->raw_supply (AARCH64_FPCR_REGNUM, + base + SVE_PT_SVE_FPCR_OFFSET (vq)); + } + else + { + /* There is no SVE state yet - the register dump contains a fpsimd + structure instead. These registers still exist in the hardware, but + the kernel has not yet initialised them, and so they will be null. */ + + char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq)); + struct user_fpsimd_state *fpsimd + = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET); + + /* Copy across the V registers from fpsimd structure to the Z registers, + ensuring the non overlapping state is set to null. */ + + memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); + + for (i = 0; i <= AARCH64_SVE_Z_REGS_NUM; i++) + { + memcpy (zero_reg, &fpsimd->vregs[i], sizeof (__int128_t)); + regcache->raw_supply (AARCH64_SVE_Z0_REGNUM + i, zero_reg); + } + + regcache->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr); + regcache->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr); + + /* Clear the SVE only registers. */ + + for (i = 0; i <= AARCH64_SVE_P_REGS_NUM; i++) + regcache->raw_supply (AARCH64_SVE_P0_REGNUM + i, zero_reg); + + regcache->raw_supply (AARCH64_SVE_FFR_REGNUM, zero_reg); + } +} + + +/* Put the registers from regcache into linux structure buf. */ + +void +aarch64_sve_regs_copy_from_regcache (reg_buffer_common *regcache, void *buf) +{ + struct user_sve_header *header = (struct user_sve_header *) buf; + char *base = (char*) buf; + long vq, vg_regcache; + int i; + + vq = sve_vq_from_vl (header->vl); + + /* Sanity check the data in the header. */ + gdb_assert (sve_vl_valid (header->vl)); + gdb_assert (SVE_PT_SIZE (vq, header->flags) == header->size); + + regcache->raw_collect (AARCH64_SVE_VG_REGNUM, &vg_regcache); + if (vg_regcache != 0 && vg_regcache != sve_vg_from_vl (header->vl)) + /* Vector length on the running process has changed. GDB currently does + not support this and will result in GDB writing invalid data back to the + vector registers. Error and exit. We do not expect many programs to + exhibit this behaviour. To fix this we need to spot the change earlier + and generate a new target descriptor. */ + error (_("Vector length has changed. Cannot write back registers.")); + + if (!HAS_SVE_STATE (*header)) + { + /* There is no SVE state yet - the register dump contains a fpsimd + structure instead. Where possible we want to write the regcache data + back to the kernel using the fpsimd structure. However, if we cannot + then we'll need to reformat the fpsimd into a full SVE structure, + resulting in the initialization of SVE state written back to the + kernel, which is why we try to avoid it. */ + + int has_sve_state = 0; + char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq)); + struct user_fpsimd_state *fpsimd + = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET); + + memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); + + /* Check in the regcache if any of the Z registers are set after the + first 128 bits, or if any of the other SVE registers are set. */ + + for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) + { + has_sve_state |= regcache->raw_compare (AARCH64_SVE_Z0_REGNUM + i, + zero_reg, sizeof (__int128_t)); + if (has_sve_state != 0) + break; + } + + if (has_sve_state == 0) + for (i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) + { + has_sve_state |= regcache->raw_compare (AARCH64_SVE_P0_REGNUM + i, + zero_reg, 0); + if (has_sve_state != 0) + break; + } + + if (has_sve_state == 0) + has_sve_state |= regcache->raw_compare (AARCH64_SVE_FFR_REGNUM, + zero_reg, 0); + + /* If no SVE state exists, then use the existing fpsimd structure to + write out state and return. */ + + if (has_sve_state == 0) + { + /* The collects of the Z registers will overflow the size of a vreg. + There is enough space in the structure to allow for this, but we + cannot overflow into the next register as we might not be + collecting every register. */ + + for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) + { + if (REG_VALID == regcache->get_register_status ( + AARCH64_SVE_Z0_REGNUM + i)) + { + regcache->raw_collect (AARCH64_SVE_Z0_REGNUM + i, zero_reg); + memcpy (&fpsimd->vregs[i], zero_reg, sizeof (__int128_t)); + } + } + + if (REG_VALID == regcache->get_register_status (AARCH64_FPSR_REGNUM)) + regcache->raw_collect (AARCH64_FPSR_REGNUM, &fpsimd->fpsr); + if (REG_VALID == regcache->get_register_status (AARCH64_FPCR_REGNUM)) + regcache->raw_collect ( AARCH64_FPCR_REGNUM, &fpsimd->fpcr); + + return; + } + + /* Otherwise, reformat the fpsimd structure into a full SVE set, by + expanding the V registers (working backwards so we don't splat + registers before they are copied) and using null for everything else. + Note that enough space for a full SVE dump was originally allocated + for base. */ + + header->flags |= SVE_PT_REGS_SVE; + header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE); + + memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr, + sizeof (uint32_t)); + memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr, + sizeof (uint32_t)); + + for (i = AARCH64_SVE_Z_REGS_NUM; i >= 0 ; i--) + { + memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i], + sizeof (__int128_t)); + } + } + + /* Replace the kernel values with those from regcache. */ + + for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) + if (REG_VALID == regcache->get_register_status (AARCH64_SVE_Z0_REGNUM + i)) + regcache->raw_collect (AARCH64_SVE_Z0_REGNUM + i, + base + SVE_PT_SVE_ZREG_OFFSET (vq, i)); + + for (i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) + if (REG_VALID == regcache->get_register_status (AARCH64_SVE_P0_REGNUM + i)) + regcache->raw_collect (AARCH64_SVE_P0_REGNUM + i, + base + SVE_PT_SVE_PREG_OFFSET (vq, i)); + + if (REG_VALID == regcache->get_register_status (AARCH64_SVE_FFR_REGNUM)) + regcache->raw_collect (AARCH64_SVE_FFR_REGNUM, + base + SVE_PT_SVE_FFR_OFFSET (vq)); + if (REG_VALID == regcache->get_register_status (AARCH64_FPSR_REGNUM)) + regcache->raw_collect (AARCH64_FPSR_REGNUM, + base + SVE_PT_SVE_FPSR_OFFSET (vq)); + if (REG_VALID == regcache->get_register_status (AARCH64_FPCR_REGNUM)) + regcache->raw_collect (AARCH64_FPCR_REGNUM, + base + SVE_PT_SVE_FPCR_OFFSET (vq)); +} diff --git a/gdb/nat/aarch64-sve-linux-ptrace.h b/gdb/nat/aarch64-sve-linux-ptrace.h index a32ddf1..1754989 100644 --- a/gdb/nat/aarch64-sve-linux-ptrace.h +++ b/gdb/nat/aarch64-sve-linux-ptrace.h @@ -20,6 +20,8 @@ #ifndef AARCH64_SVE_LINUX_PTRACE_H #define AARCH64_SVE_LINUX_PTRACE_H +#include "common/common-regcache.h" + /* Where indicated, this file contains defines and macros lifted directly from the Linux kernel headers, with no modification. Refer to Linux kernel documentation for details. */ @@ -34,10 +36,31 @@ extern unsigned long aarch64_sve_get_vq (int tid); +/* Read the current SVE register set using ptrace, allocating space as + required. */ + +extern gdb_byte *aarch64_sve_get_sveregs (int tid); + +/* Put the registers from linux structure buf into regcache. */ + +extern void aarch64_sve_regs_copy_to_regcache (reg_buffer_common *regcache, + const void *buf); + +/* Put the registers from regcache into linux structure buf. */ + +extern void aarch64_sve_regs_copy_from_regcache (reg_buffer_common *regcache, + void *buf); + /* Structures and defines taken from sigcontext.h. */ #ifndef SVE_SIG_ZREGS_SIZE +struct sve_context { + struct _aarch64_ctx head; + __u16 vl; + __u16 __reserved[3]; +}; + #define SVE_VQ_BYTES 16 /* number of bytes per quadword */ #define SVE_VQ_MIN 1 @@ -52,6 +75,35 @@ extern unsigned long aarch64_sve_get_vq (int tid); #define sve_vl_valid(vl) \ ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX) +#define SVE_SIG_ZREG_SIZE(vq) ((__u32)(vq) * SVE_VQ_BYTES) +#define SVE_SIG_PREG_SIZE(vq) ((__u32)(vq) * (SVE_VQ_BYTES / 8)) +#define SVE_SIG_FFR_SIZE(vq) SVE_SIG_PREG_SIZE(vq) + +#define SVE_SIG_REGS_OFFSET \ + ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) + +#define SVE_SIG_ZREGS_OFFSET SVE_SIG_REGS_OFFSET +#define SVE_SIG_ZREG_OFFSET(vq, n) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n)) +#define SVE_SIG_ZREGS_SIZE(vq) \ + (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET) + +#define SVE_SIG_PREGS_OFFSET(vq) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq)) +#define SVE_SIG_PREG_OFFSET(vq, n) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n)) +#define SVE_SIG_PREGS_SIZE(vq) \ + (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq)) + +#define SVE_SIG_FFR_OFFSET(vq) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq)) + +#define SVE_SIG_REGS_SIZE(vq) \ + (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET) + +#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq)) + #endif /* SVE_SIG_ZREGS_SIZE. */ @@ -68,6 +120,76 @@ struct user_sve_header { __u16 __reserved; }; + +#define SVE_PT_REGS_MASK 1 + +#define SVE_PT_REGS_FPSIMD 0 +#define SVE_PT_REGS_SVE SVE_PT_REGS_MASK + +#define SVE_PT_VL_INHERIT (PR_SVE_VL_INHERIT >> 16) +#define SVE_PT_VL_ONEXEC (PR_SVE_SET_VL_ONEXEC >> 16) + +#define SVE_PT_REGS_OFFSET \ + ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) + +#define SVE_PT_FPSIMD_OFFSET SVE_PT_REGS_OFFSET + +#define SVE_PT_FPSIMD_SIZE(vq, flags) (sizeof(struct user_fpsimd_state)) + +#define SVE_PT_SVE_ZREG_SIZE(vq) SVE_SIG_ZREG_SIZE(vq) +#define SVE_PT_SVE_PREG_SIZE(vq) SVE_SIG_PREG_SIZE(vq) +#define SVE_PT_SVE_FFR_SIZE(vq) SVE_SIG_FFR_SIZE(vq) +#define SVE_PT_SVE_FPSR_SIZE sizeof(__u32) +#define SVE_PT_SVE_FPCR_SIZE sizeof(__u32) + +#define __SVE_SIG_TO_PT(offset) \ + ((offset) - SVE_SIG_REGS_OFFSET + SVE_PT_REGS_OFFSET) + +#define SVE_PT_SVE_OFFSET SVE_PT_REGS_OFFSET + +#define SVE_PT_SVE_ZREGS_OFFSET \ + __SVE_SIG_TO_PT(SVE_SIG_ZREGS_OFFSET) +#define SVE_PT_SVE_ZREG_OFFSET(vq, n) \ + __SVE_SIG_TO_PT(SVE_SIG_ZREG_OFFSET(vq, n)) +#define SVE_PT_SVE_ZREGS_SIZE(vq) \ + (SVE_PT_SVE_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET) + +#define SVE_PT_SVE_PREGS_OFFSET(vq) \ + __SVE_SIG_TO_PT(SVE_SIG_PREGS_OFFSET(vq)) +#define SVE_PT_SVE_PREG_OFFSET(vq, n) \ + __SVE_SIG_TO_PT(SVE_SIG_PREG_OFFSET(vq, n)) +#define SVE_PT_SVE_PREGS_SIZE(vq) \ + (SVE_PT_SVE_PREG_OFFSET(vq, SVE_NUM_PREGS) - \ + SVE_PT_SVE_PREGS_OFFSET(vq)) + +#define SVE_PT_SVE_FFR_OFFSET(vq) \ + __SVE_SIG_TO_PT(SVE_SIG_FFR_OFFSET(vq)) + +#define SVE_PT_SVE_FPSR_OFFSET(vq) \ + ((SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq) + \ + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) +#define SVE_PT_SVE_FPCR_OFFSET(vq) \ + (SVE_PT_SVE_FPSR_OFFSET(vq) + SVE_PT_SVE_FPSR_SIZE) + +#define SVE_PT_SVE_SIZE(vq, flags) \ + ((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE \ + - SVE_PT_SVE_OFFSET + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) + +#define SVE_PT_SIZE(vq, flags) \ + (((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ? \ + SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) \ + : SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags)) + #endif /* SVE_PT_SVE_ZREG_SIZE. */ + +/* Indicates whether a SVE ptrace header is followed by SVE registers or a + fpsimd structure. */ + +#define HAS_SVE_STATE(header) ((header).flags && SVE_PT_REGS_SVE) + + #endif /* aarch64-sve-linux-ptrace.h */ diff --git a/gdb/regcache.c b/gdb/regcache.c index a2a43da..df521c9 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -1087,7 +1087,7 @@ reg_buffer::collect_regset (const struct regset *regset, first OFFSET bytes) to the contents of BUF (without any offset). Returns 0 if identical. */ -int +bool reg_buffer::raw_compare (int regnum, const void *buf, int offset) const { const char *regbuf; @@ -1098,7 +1098,7 @@ reg_buffer::raw_compare (int regnum, const void *buf, int offset) const regbuf = (const char *) register_buffer (regnum); size = m_descr->sizeof_register[regnum]; - return memcmp (buf, regbuf + offset, size - offset); + return memcmp (buf, regbuf + offset, size - offset) == 0; } /* Special handling for register PC. */ diff --git a/gdb/regcache.h b/gdb/regcache.h index 432e1b3..f271775 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -121,7 +121,7 @@ typedef struct cached_reg /* Buffer of registers. */ -class reg_buffer +class reg_buffer : public reg_buffer_common { public: reg_buffer (gdbarch *gdbarch, bool has_pseudo); @@ -133,10 +133,10 @@ public: /* Get the availability status of the value of register REGNUM in this buffer. */ - enum register_status get_register_status (int regnum) const; + enum register_status get_register_status (int regnum) const override; /* Collect register REGNUM from REGCACHE and store its contents in BUF. */ - void raw_collect (int regnum, void *buf) const; + void raw_collect (int regnum, void *buf) const override; void raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, bool is_signed) const; @@ -145,7 +145,7 @@ public: void *buf, size_t size) const; /* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE. */ - void raw_supply (int regnum, const void *buf); + void raw_supply (int regnum, const void *buf) override; void raw_supply (int regnum, const reg_buffer &src) { @@ -162,7 +162,7 @@ public: void invalidate (int regnum); - int raw_compare (int regnum, const void *buf, int offset) const; + bool raw_compare (int regnum, const void *buf, int offset) const override; /* Dump the contents of a register from the register cache to the target debug. */ |