diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 1270b7e0c0..bc570ade6d 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -388,19 +388,65 @@ store_fpregs_to_thread (const struct regcache *regcache)
     }
 }
 
+/* Fill GDB's register array with the sve register values
+   from the current thread.  */
+
+static void
+fetch_sveregs_from_thread (struct regcache *regcache)
+{
+  gdb_byte *base = aarch64_sve_get_sveregs (ptid_get_lwp (inferior_ptid));
+  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 (struct regcache *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 (struct regcache *regcache,
 					   int regno)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+
   if (regno == -1)
     {
       fetch_gregs_from_thread (regcache);
-      fetch_fpregs_from_thread (regcache);
+      if (tdep->has_sve ())
+	fetch_sveregs_from_thread (regcache);
+      else
+	fetch_fpregs_from_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
+  else if (tdep->has_sve ())
+    fetch_sveregs_from_thread (regcache);
   else
     fetch_fpregs_from_thread (regcache);
 }
@@ -411,13 +457,20 @@ void
 aarch64_linux_nat_target::store_registers (struct regcache *regcache,
 					   int regno)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+
   if (regno == -1)
     {
       store_gregs_to_thread (regcache);
-      store_fpregs_to_thread (regcache);
+      if (tdep->has_sve ())
+	store_sveregs_to_thread (regcache);
+      else
+	store_fpregs_to_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     store_gregs_to_thread (regcache);
+  else if (tdep->has_sve ())
+    store_sveregs_to_thread (regcache);
   else
     store_fpregs_to_thread (regcache);
 }
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index c377378809..22ff19a2d2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -218,6 +218,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/nat/aarch64-sve-linux-ptrace.c b/gdb/nat/aarch64-sve-linux-ptrace.c
index 9381786fda..84c7a41f40 100644
--- a/gdb/nat/aarch64-sve-linux-ptrace.c
+++ b/gdb/nat/aarch64-sve-linux-ptrace.c
@@ -25,6 +25,13 @@
 #include "aarch64-sve-linux-ptrace.h"
 #include "arch/aarch64.h"
 
+#ifndef GDBSERVER
+#include "defs.h"
+#endif
+#include "regcache.h"
+
+static bool vq_change_warned = false;
+
 /* Read VQ for the given tid using ptrace.  If SVE is not supported then zero
    is returned (on a system that supports SVE, then VQ cannot be zeo).  */
 
@@ -50,3 +57,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 (struct regcache *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 (struct regcache *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 b318150ac1..eff90ea2ea 100644
--- a/gdb/nat/aarch64-sve-linux-ptrace.h
+++ b/gdb/nat/aarch64-sve-linux-ptrace.h
@@ -34,10 +34,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 (struct regcache *regcache,
+					       const void *buf);
+
+/* Put the registers from regcache into linux structure buf.  */
+
+extern void aarch64_sve_regs_copy_from_regcache (struct regcache *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 +73,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 +118,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 */
