aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/aarch64-linux-nat.c57
-rw-r--r--gdb/common/common-regcache.h9
-rw-r--r--gdb/gdbserver/Makefile.in1
-rw-r--r--gdb/gdbserver/regcache.c8
-rw-r--r--gdb/gdbserver/regcache.h20
-rw-r--r--gdb/nat/aarch64-sve-linux-ptrace.c258
-rw-r--r--gdb/nat/aarch64-sve-linux-ptrace.h122
-rw-r--r--gdb/regcache.c4
-rw-r--r--gdb/regcache.h10
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. */