diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 
65ca8ff2a7ff25b16e31135f4a8b11b6b013dae3..5525b0dd46a1bb641f4b6003942613437
202e785 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -49,6 +49,129 @@
 #define TRAP_HWBKPT 0x0004
 #endif

+#define sve_vg_from_vl(vl)	((vl) / 8)
+#define sve_vl_from_vg(vg)	((vg) * 8)
+
+/* Structures and defines taken from sigcontext.h.
+   These can be removed when kernel changes are fully committed.  */
+#ifndef SVE_SIG_ZREGS_SIZE
+
+struct sve_context {
+	struct _aarch64_ctx head;
+	__u16 vl;
+	__u16 __reserved[3];
+};
+
+#define SVE_VQ_MIN		1
+#define SVE_VQ_MAX		0x200
+
+#define SVE_VL_MIN		(SVE_VQ_MIN * 0x10)
+#define SVE_VL_MAX		(SVE_VQ_MAX * 0x10)
+
+#define SVE_NUM_ZREGS		32
+#define SVE_NUM_PREGS		16
+
+#define sve_vq_from_vl(vl)	((vl) / 0x10)
+#define sve_vl_valid(vl) \
+	((vl) % 0x10 == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX)
+
+#define SVE_SIG_ZREG_SIZE(vq)	((__u32)(vq) * 16)
+#define SVE_SIG_PREG_SIZE(vq)	((__u32)(vq) * 2)
+#define SVE_SIG_FFR_SIZE(vq)	SVE_SIG_PREG_SIZE(vq)
+
+#define SVE_SIG_REGS_OFFSET	((sizeof (struct sve_context) + 15) / 16 * 16)
+
+#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
+
+/* Structures and defines taken from ptrace.h.
+   These can be removed when kernel changes are fully committed.  */
+#ifndef SVE_PT_SVE_ZREG_SIZE
+
+struct user_sve_header {
+	__u32 size; /* total meaningful regset content in bytes */
+	__u32 max_size; /* maxmium possible size for this thread */
+	__u16 vl; /* current vector length */
+	__u16 max_vl; /* maximum possible vector length */
+	__u16 flags;
+	__u16 __reserved;
+};
+
+#define SVE_PT_REGS_MASK		(1 << 0)
+#define SVE_PT_REGS_FPSIMD		0
+#define SVE_PT_REGS_SVE			SVE_PT_REGS_MASK
+
+#define SVE_PT_REGS_OFFSET	((sizeof (struct sve_context) + 15) / 16 * 16)
+
+#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) + 15) / 16 * 16)
+#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 + 15) / 16 * 16)
+
+#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
+
 /* Per-process data.  We don't bind this to a per-inferior registry
    because of targets like x86 GNU/Linux that need to keep track of
    processes that aren't bound to any inferior (e.g., fork children,
@@ -342,6 +465,266 @@ 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, int regno)
+{
+  int ret, tid, i;
+  struct iovec iovec;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct user_sve_header header;
+  long vg, vq;
+  char *base;
+
+  tid = ptid_get_lwp (inferior_ptid);
+
+  /* First call ptrace to get a header.  */
+
+  iovec.iov_len = sizeof (header);
+  iovec.iov_base = &header;
+
+  ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec);
+  if (ret < 0)
+    perror_with_name (_("Unable to fetch sve register header"));
+
+  gdb_assert (sve_vl_valid (header.vl));
+  vg = sve_vg_from_vl (header.vl);
+  vq = sve_vq_from_vl (header.vl);
+  gdb_assert (SVE_PT_SIZE (vq, header.flags) == header.size);
+  regcache_raw_supply (regcache, AARCH64_SVE_VG_REGNUM, &vg);
+
+  /* Call again using the full buffer size.  */
+
+  iovec.iov_len = header.size;
+  iovec.iov_base = xmalloc (iovec.iov_len);
+  base = (char*)iovec.iov_base;
+
+  if (header.flags && SVE_PT_REGS_SVE)
+    {
+      ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to fetch sve registers"));
+
+      for (i = 0; i <= AARCH64_SVE_Z31_REGNUM - AARCH64_SVE_Z0_REGNUM;
i++)
+	regcache_raw_supply (regcache, AARCH64_SVE_Z0_REGNUM + i,
+			     base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
+
+      for (i = 0; i <= AARCH64_SVE_P15_REGNUM - AARCH64_SVE_P0_REGNUM;
i++)
+	regcache_raw_supply (regcache, AARCH64_SVE_P0_REGNUM + i,
+			     base + SVE_PT_SVE_PREG_OFFSET (vq, i));
+
+      regcache_raw_supply (regcache, AARCH64_SVE_FFR_REGNUM,
+			   base + SVE_PT_SVE_FFR_OFFSET (vq));
+      regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM,
+			   base + SVE_PT_SVE_FPSR_OFFSET (vq));
+      regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM,
+			   base + SVE_PT_SVE_FPCR_OFFSET (vq));
+    }
+  else
+    {
+      /* There is no SVE state.  Read fpsimd instead.  */
+      char sve_reg[SVE_PT_SVE_ZREG_SIZE (vq)];
+      struct user_fpsimd_state *fpsimd
+	= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec);
+      if (ret < 0)
+	perror_with_name (_("Unable to fetch fpsimd registers via sve"));
+
+      /* Clear the SVE only registers.  */
+
+      memset (&sve_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      for (i = 0; i <= AARCH64_SVE_P15_REGNUM - AARCH64_SVE_P0_REGNUM;
i++)
+	regcache_raw_supply (regcache, AARCH64_SVE_P0_REGNUM + i, &sve_reg);
+
+      regcache_raw_supply (regcache, AARCH64_SVE_FFR_REGNUM, &sve_reg);
+
+      /* Convert vregs from fpsimd state to zregs, ensuring additional
state is
+	 null.  */
+
+      for (i = 0; i <= AARCH64_SVE_Z31_REGNUM - AARCH64_SVE_Z0_REGNUM;
i++)
+	{
+	  memcpy (&sve_reg, &fpsimd->vregs[i], sizeof (__int128));
+	  regcache_raw_supply (regcache, AARCH64_SVE_Z0_REGNUM + i, &sve_reg);
+	}
+
+      regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
+      regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
+    }
+
+  free (iovec.iov_base);
+}
+
+/* Store to the current thread the valid sve register
+   values in the GDB's register array.  */
+
+static void
+store_sveregs_to_thread (const struct regcache *regcache, int regno)
+{
+  int ret, tid, r;
+  struct iovec iovec;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct user_sve_header header;
+  long vq;
+  char *sve_reg_p, *base;
+
+  tid = ptid_get_lwp (inferior_ptid);
+
+  /* First call ptrace to get a header.  */
+
+  iovec.iov_len = sizeof (header);
+  iovec.iov_base = &header;
+
+  ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec);
+  if (ret < 0)
+    perror_with_name (_("Unable to fetch sve register header"));
+
+  gdb_assert (sve_vl_valid (header.vl));
+  vq = sve_vq_from_vl (header.vl);
+  gdb_assert (SVE_PT_SIZE (vq, header.flags) == header.size);
+
+  /* Get the full structure.  */
+
+  if (header.flags && SVE_PT_REGS_SVE)
+    iovec.iov_len = header.size;
+  else
+    iovec.iov_len = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
+  iovec.iov_base = xmalloc (iovec.iov_len);
+  base = (char*)iovec.iov_base;
+
+  ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec);
+  if (ret < 0)
+    perror_with_name (_("Unable to fetch sve registers before storing"));
+
+  if (!(header.flags && SVE_PT_REGS_SVE))
+    {
+      /* There is no SVE state.  Try to put the registers into an fpsimd
+	 structure, whilst checking to see if there is any actual SVE
+	 state.  */
+      int has_sve_state = 0;
+      char sve_reg[SVE_PT_SVE_ZREG_SIZE (vq)];
+      struct user_fpsimd_state *fpsimd
+	= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      memset (&sve_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      /* Check if any SVE state exists in the regcache.  */
+
+      for (r = AARCH64_SVE_Z0_REGNUM; r <= AARCH64_SVE_Z31_REGNUM; r++)
+	{
+	  has_sve_state |= regcache_raw_compare (regcache, r, &sve_reg,
+						 sizeof (__int128));
+	  if (has_sve_state != 0)
+	    break;
+	}
+
+      if (has_sve_state == 0)
+	for (r = AARCH64_SVE_P0_REGNUM; r <= AARCH64_SVE_P15_REGNUM; r++)
+	  {
+	    has_sve_state |= regcache_raw_compare (regcache, r, &sve_reg, 0);
+	    if (has_sve_state != 0)
+	      break;
+	  }
+
+      if (has_sve_state == 0)
+	  has_sve_state |= regcache_raw_compare (regcache,
+						 AARCH64_SVE_FFR_REGNUM,
+						 &sve_reg, 0);
+
+      /* If no SVE state then copy into a fpsimd structure.  */
+
+      if (has_sve_state == 0)
+	{
+	  for (r = AARCH64_SVE_Z0_REGNUM; r <= AARCH64_SVE_Z31_REGNUM; r++)
+	    {
+	      if (REG_VALID == regcache_register_status (regcache, r))
+		regcache_raw_collect (
+		  regcache, r, &fpsimd->vregs[r - AARCH64_SVE_Z0_REGNUM]);
+	    }
+
+	  regcache_raw_collect (regcache, AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
+	  regcache_raw_collect (regcache, AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
+
+	  ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec);
+
+	  xfree (iovec.iov_base);
+
+	  if (ret < 0)
+	   perror_with_name (_("Unable to store sve registers using fpsimd"));
+
+	  return;
+	}
+
+      /* Expand the current kernel state into an SVE set (with null
values for
+	 the P and FFR regs) and set that as the current iov_base.  */
+
+      int sve_size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
+      char *sve_buf = (char*)xmalloc (sve_size);
+      struct user_sve_header *sve_header = (struct user_sve_header
*)sve_buf;
+
+      memcpy (sve_buf, iovec.iov_base, sizeof (struct user_sve_header));
+      sve_header->size = sve_size;
+      sve_header->flags |= SVE_PT_REGS_SVE;
+
+      for (r = 0; r <= AARCH64_SVE_Z31_REGNUM - AARCH64_SVE_Z0_REGNUM;
r++)
+	{
+	  memcpy (sve_buf + SVE_PT_SVE_ZREG_OFFSET (vq, r),
+		  &fpsimd->vregs[r], sizeof (__int128));
+	}
+
+      memcpy (sve_buf + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr,
+	      sizeof (uint32_t));
+      memcpy (sve_buf + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr,
+	      sizeof (uint32_t));
+
+      xfree (iovec.iov_base);
+      iovec.iov_base = sve_buf;
+      iovec.iov_len = sve_size;
+      base = (char*)iovec.iov_base;
+    }
+
+  /* Replace the kernel values with those from regcache.  */
+
+  sve_reg_p = base + SVE_PT_SVE_ZREGS_OFFSET;
+  for (r = AARCH64_SVE_Z0_REGNUM; r <= AARCH64_SVE_Z31_REGNUM; r++)
+    {
+      if (REG_VALID == regcache_register_status (regcache, r))
+	regcache_raw_collect (regcache, r, sve_reg_p);
+      sve_reg_p += SVE_PT_SVE_ZREG_SIZE (vq);
+    }
+
+  sve_reg_p = base + SVE_PT_SVE_PREGS_OFFSET (vq);
+  for (r = AARCH64_SVE_P0_REGNUM; r <= AARCH64_SVE_P15_REGNUM; r++)
+    {
+      if (REG_VALID == regcache_register_status (regcache, r))
+	regcache_raw_collect (regcache, r, sve_reg_p);
+      sve_reg_p += SVE_PT_SVE_PREG_SIZE (vq);
+    }
+
+  if (REG_VALID == regcache_register_status (regcache,
AARCH64_SVE_FFR_REGNUM))
+    regcache_raw_collect (regcache, AARCH64_SVE_FFR_REGNUM,
+			  base + SVE_PT_SVE_FFR_OFFSET (vq));
+  if (REG_VALID == regcache_register_status (regcache,
AARCH64_FPSR_REGNUM))
+    regcache_raw_collect (regcache, AARCH64_FPSR_REGNUM,
+			  base + SVE_PT_SVE_FPSR_OFFSET (vq));
+  if (REG_VALID == regcache_register_status (regcache,
AARCH64_FPCR_REGNUM))
+    regcache_raw_collect (regcache, AARCH64_FPCR_REGNUM,
+			  base + SVE_PT_SVE_FPCR_OFFSET (vq));
+
+  /* Note: We do not set VL.  Changing VL on the fly is currently
unsupported
+     in Linux.  */
+
+  ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec);
+
+  xfree (iovec.iov_base);
+
+  if (ret < 0)
+    perror_with_name (_("Unable to store sve registers"));
+}
+
 /* Implement the "to_fetch_register" target_ops method.  */

 static void
@@ -349,13 +732,21 @@ aarch64_linux_fetch_inferior_registers (struct
target_ops *ops,
 					struct regcache *regcache,
 					int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   if (regno == -1)
     {
       fetch_gregs_from_thread (regcache);
-      fetch_fpregs_from_thread (regcache);
+      if (AARCH64_TDEP_HAS_SVE (tdep))
+	fetch_sveregs_from_thread (regcache, regno);
+      else
+	fetch_fpregs_from_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
+  else if (AARCH64_TDEP_HAS_SVE (tdep))
+    fetch_sveregs_from_thread (regcache, regno);
   else
     fetch_fpregs_from_thread (regcache);
 }
@@ -367,13 +758,21 @@ aarch64_linux_store_inferior_registers (struct
target_ops *ops,
 					struct regcache *regcache,
 					int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   if (regno == -1)
     {
       store_gregs_to_thread (regcache);
-      store_fpregs_to_thread (regcache);
+      if (AARCH64_TDEP_HAS_SVE (tdep))
+	store_sveregs_to_thread (regcache, regno);
+      else
+	store_fpregs_to_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     store_gregs_to_thread (regcache);
+  else if (AARCH64_TDEP_HAS_SVE (tdep))
+    store_sveregs_to_thread (regcache, regno);
   else
     store_fpregs_to_thread (regcache);
 }
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 
625282070480017cd1e960ae3bd62c94f9163aa3..2eaf268e9ea2e1a7912c5778033d3ff01
737a648 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -30,6 +30,10 @@ struct regset;
 #define AARCH64_DWARF_X0   0
 #define AARCH64_DWARF_SP  31
 #define AARCH64_DWARF_V0  64
+#define AARCH64_DWARF_SVE_VG   46
+#define AARCH64_DWARF_SVE_FFR  47
+#define AARCH64_DWARF_SVE_P0   48
+#define AARCH64_DWARF_SVE_Z0   96

 /* Register numbers of various important registers.  */
 enum aarch64_regnum
@@ -46,8 +50,17 @@ enum aarch64_regnum

   /* Last floating point / vector register */
   AARCH64_V31_REGNUM = AARCH64_V0_REGNUM + 31,
-  AARCH64_FPSR_REGNUM,		/* Floating point status register */
-  AARCH64_FPCR_REGNUM,		/* Floating point control register */
+
+  AARCH64_SVE_Z0_REGNUM = AARCH64_V0_REGNUM,	/* First SVE register (Reuses
+						   the V register set).  */
+  AARCH64_SVE_Z31_REGNUM = AARCH64_V31_REGNUM,  /* Last SVE register.  */
+  AARCH64_FPSR_REGNUM,		/* Floating point status register.  */
+  AARCH64_FPCR_REGNUM,		/* Floating point control register.  */
+  AARCH64_SVE_P0_REGNUM,	/* First SVE predicate register.  */
+  AARCH64_SVE_P15_REGNUM = AARCH64_SVE_P0_REGNUM + 15,	/* Last SVE
predicate
+							   register.  */
+  AARCH64_SVE_FFR_REGNUM,	/* SVE First Failure register.  */
+  AARCH64_SVE_VG_REGNUM,	/* SVE Vector Granual.  */

   /* Other useful registers.  */

@@ -94,11 +107,14 @@ struct gdbarch_tdep
   struct type *vns_type;
   struct type *vnh_type;
   struct type *vnb_type;
+  struct type *vnv_type;

   /* syscall record.  */
   int (*aarch64_syscall_record) (struct regcache *regcache, unsigned long
svc_number);
 };

+#define AARCH64_TDEP_HAS_SVE(tdep) (0)
+
 extern struct target_desc *tdesc_aarch64;

 extern int aarch64_process_record (struct gdbarch *gdbarch,
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 
aba7a8525529102d01e3c7cd282a9ee793d643fe..9808997664597484d006d380e00384152
8512ca5 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -66,6 +66,7 @@
 #define AARCH64_S0_REGNUM (AARCH64_D0_REGNUM + 32)
 #define AARCH64_H0_REGNUM (AARCH64_S0_REGNUM + 32)
 #define AARCH64_B0_REGNUM (AARCH64_H0_REGNUM + 32)
+#define AARCH64_SVE_V0_REGNUM (AARCH64_B0_REGNUM + 32)

 /* The standard register names, and all the valid aliases for them.  */
 static const struct
@@ -150,6 +151,27 @@ static const char *const aarch64_v_register_names[] =
   "fpcr"
 };

+/* The SVE 'Z' and 'P' registers.  */
+static const char *const aarch64_sve_register_names[] =
+{
+  /* These registers must appear in consecutive RAW register number
+     order and they must begin with AARCH64_SVE_Z0_REGNUM! */
+  "z0", "z1", "z2", "z3",
+  "z4", "z5", "z6", "z7",
+  "z8", "z9", "z10", "z11",
+  "z12", "z13", "z14", "z15",
+  "z16", "z17", "z18", "z19",
+  "z20", "z21", "z22", "z23",
+  "z24", "z25", "z26", "z27",
+  "z28", "z29", "z30", "z31",
+  "fpsr", "fpcr",
+  "p0", "p1", "p2", "p3",
+  "p4", "p5", "p6", "p7",
+  "p8", "p9", "p10", "p11",
+  "p12", "p13", "p14", "p15",
+  "ffr", "vg"
+};
+
 /* AArch64 prologue cache structure.  */
 struct aarch64_prologue_cache
 {
@@ -1554,11 +1576,40 @@ aarch64_vnb_type (struct gdbarch *gdbarch)
   return tdep->vnb_type;
 }

+/* Return the type for an AdvSISD V register.  */
+
+static struct type *
+aarch64_vnv_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->vnv_type == NULL)
+    {
+      struct type *t;
+      struct type *elem;
+
+      t = arch_composite_type (gdbarch, "__gdb_builtin_type_vnv",
+			       TYPE_CODE_UNION);
+
+      append_composite_type_field (t, "d", aarch64_vnd_type (gdbarch));
+      append_composite_type_field (t, "s", aarch64_vns_type (gdbarch));
+      append_composite_type_field (t, "h", aarch64_vnh_type (gdbarch));
+      append_composite_type_field (t, "b", aarch64_vnb_type (gdbarch));
+      append_composite_type_field (t, "q", aarch64_vnq_type (gdbarch));
+
+      tdep->vnv_type = t;
+    }
+
+  return tdep->vnv_type;
+}
+
 /* Implement the "dwarf2_reg_to_regnum" gdbarch method.  */

 static int
 aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   if (reg >= AARCH64_DWARF_X0 && reg <= AARCH64_DWARF_X0 + 30)
     return AARCH64_X0_REGNUM + reg - AARCH64_DWARF_X0;

@@ -1568,6 +1619,21 @@ aarch64_dwarf_reg_to_regnum (struct gdbarch
*gdbarch, int reg)
   if (reg >= AARCH64_DWARF_V0 && reg <= AARCH64_DWARF_V0 + 31)
     return AARCH64_V0_REGNUM + reg - AARCH64_DWARF_V0;

+  if (AARCH64_TDEP_HAS_SVE (tdep))
+    {
+      if (reg == AARCH64_DWARF_SVE_VG)
+	return AARCH64_SVE_VG_REGNUM;
+
+      if (reg == AARCH64_DWARF_SVE_FFR)
+	return AARCH64_SVE_FFR_REGNUM;
+
+      if (reg >= AARCH64_DWARF_SVE_P0 && reg <= AARCH64_DWARF_SVE_P0 + 15)
+	return AARCH64_SVE_P0_REGNUM + reg - AARCH64_DWARF_SVE_P0;
+
+      if (reg >= AARCH64_DWARF_SVE_Z0 && reg <= AARCH64_DWARF_SVE_Z0 + 15)
+	return AARCH64_SVE_Z0_REGNUM + reg - AARCH64_DWARF_SVE_Z0;
+    }
+
   return -1;
 }


@@ -1902,6 +1968,8 @@ aarch64_gen_return_address (struct gdbarch *gdbarch,
 static const char *
 aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   static const char *const q_name[] =
     {
       "q0", "q1", "q2", "q3",
@@ -1979,6 +2047,25 @@ aarch64_pseudo_register_name (struct gdbarch
*gdbarch, int regnum)
   if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
     return b_name[regnum - AARCH64_B0_REGNUM];

+  if (AARCH64_TDEP_HAS_SVE (tdep))
+    {
+      static const char *const sve_v_name[] =
+	{
+	  "v0", "v1", "v2", "v3",
+	  "v4", "v5", "v6", "v7",
+	  "v8", "v9", "v10", "v11",
+	  "v12", "v13", "v14", "v15",
+	  "v16", "v17", "v18", "v19",
+	  "v20", "v21", "v22", "v23",
+	  "v24", "v25", "v26", "v27",
+	  "v28", "v29", "v30", "v31",
+	};
+
+      if (regnum >= AARCH64_SVE_V0_REGNUM
+	  && regnum < AARCH64_SVE_V0_REGNUM + 32)
+	return sve_v_name[regnum - AARCH64_SVE_V0_REGNUM];
+    }
+
   internal_error (__FILE__, __LINE__,
 		  _("aarch64_pseudo_register_name: bad register number %d"),
 		  regnum);
@@ -1989,6 +2076,8 @@ aarch64_pseudo_register_name (struct gdbarch
*gdbarch, int regnum)
 static struct type *
 aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   regnum -= gdbarch_num_regs (gdbarch);

   if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
@@ -2006,6 +2095,10 @@ aarch64_pseudo_register_type (struct gdbarch
*gdbarch, int regnum)
   if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
     return aarch64_vnb_type (gdbarch);

+  if (AARCH64_TDEP_HAS_SVE (tdep) && regnum >= AARCH64_SVE_V0_REGNUM
+      && regnum < AARCH64_SVE_V0_REGNUM + 32)
+    return aarch64_vnv_type (gdbarch);
+
   internal_error (__FILE__, __LINE__,
 		  _("aarch64_pseudo_register_type: bad register number %d"),
 		  regnum);
@@ -2017,6 +2110,8 @@ static int
 aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
 				    struct reggroup *group)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   regnum -= gdbarch_num_regs (gdbarch);

   if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
@@ -2031,6 +2126,9 @@ aarch64_pseudo_register_reggroup_p (struct gdbarch
*gdbarch, int regnum,
     return group == all_reggroup || group == vector_reggroup;
   else if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
     return group == all_reggroup || group == vector_reggroup;
+  else if (AARCH64_TDEP_HAS_SVE (tdep) && regnum >= AARCH64_SVE_V0_REGNUM
+	   && regnum < AARCH64_SVE_V0_REGNUM + 32)
+    return group == all_reggroup || group == vector_reggroup;

   return group == all_reggroup;
 }
@@ -2042,6 +2140,7 @@ aarch64_pseudo_read_value (struct gdbarch *gdbarch,
 			   struct regcache *regcache,
 			   int regnum)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   gdb_byte reg_buf[MAX_REGISTER_SIZE];
   struct value *result_value;
   gdb_byte *buf;
@@ -2128,6 +2227,22 @@ aarch64_pseudo_read_value (struct gdbarch *gdbarch,
       return result_value;
     }

+  if (AARCH64_TDEP_HAS_SVE (tdep) && regnum >= AARCH64_SVE_V0_REGNUM
+      && regnum < AARCH64_SVE_V0_REGNUM + 32)
+    {
+      enum register_status status;
+      unsigned v_regnum;
+
+      v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_SVE_V0_REGNUM;
+      status = regcache_raw_read (regcache, v_regnum, reg_buf);
+      if (status != REG_VALID)
+	mark_value_bytes_unavailable (result_value, 0,
+				      TYPE_LENGTH (value_type (result_value)));
+      else
+	memcpy (buf, reg_buf, V_REGISTER_SIZE);
+      return result_value;
+    }
+
   gdb_assert_not_reached ("regnum out of bound");
 }

@@ -2137,6 +2252,7 @@ static void
 aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
 		      int regnum, const gdb_byte *buf)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   gdb_byte reg_buf[MAX_REGISTER_SIZE];

   /* Ensure the register buffer is zero, we want gdb writes of the
@@ -2201,6 +2317,18 @@ aarch64_pseudo_write (struct gdbarch *gdbarch,
struct regcache *regcache,
       return;
     }

+  if (AARCH64_TDEP_HAS_SVE (tdep) && regnum >= AARCH64_SVE_V0_REGNUM
+      && regnum < AARCH64_SVE_V0_REGNUM + 32)
+    {
+      /* pseudo V registers.  */
+      unsigned v_regnum;
+
+      v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_SVE_V0_REGNUM;
+      memcpy (reg_buf, buf, V_REGISTER_SIZE);
+      regcache_raw_write (regcache, v_regnum, reg_buf);
+      return;
+    }
+
   gdb_assert_not_reached ("regnum out of bound");
 }

diff --git a/gdb/gdbserver/linux-aarch64-low.c
b/gdb/gdbserver/linux-aarch64-low.c
index 
a4cf4746285683e1529142b0073f58b68eed9cf3..6a6fc5b22dabd2d3000300aa5212f4331
25ab751 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -28,6 +28,8 @@
 #include "elf/common.h"
 #include "ax.h"
 #include "tracepoint.h"
+#include "tdesc.h"
+#include "regdef.h"

 #include <signal.h>
 #include <sys/user.h>
@@ -39,6 +41,129 @@

 #include "gdb_proc_service.h"

+#define sve_vg_from_vl(vl)	((vl) / 8)
+#define sve_vl_from_vg(vg)	((vg) * 8)
+
+/* Structures and defines taken from sigcontext.h.
+   These can be removed when kernel changes are fully committed.  */
+#ifndef SVE_SIG_ZREGS_SIZE
+
+struct sve_context {
+	struct _aarch64_ctx head;
+	__u16 vl;
+	__u16 __reserved[3];
+};
+
+#define SVE_VQ_MIN		1
+#define SVE_VQ_MAX		0x200
+
+#define SVE_VL_MIN		(SVE_VQ_MIN * 0x10)
+#define SVE_VL_MAX		(SVE_VQ_MAX * 0x10)
+
+#define SVE_NUM_ZREGS		32
+#define SVE_NUM_PREGS		16
+
+#define sve_vq_from_vl(vl)	((vl) / 0x10)
+#define sve_vl_valid(vl) \
+	((vl) % 0x10 == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX)
+
+#define SVE_SIG_ZREG_SIZE(vq)	((__u32)(vq) * 16)
+#define SVE_SIG_PREG_SIZE(vq)	((__u32)(vq) * 2)
+#define SVE_SIG_FFR_SIZE(vq)	SVE_SIG_PREG_SIZE(vq)
+
+#define SVE_SIG_REGS_OFFSET	((sizeof (struct sve_context) + 15) / 16 * 16)
+
+#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
+
+/* Structures and defines taken from ptrace.h.
+   These can be removed when kernel changes are fully committed.  */
+#ifndef SVE_PT_SVE_ZREG_SIZE
+
+struct user_sve_header {
+	__u32 size; /* total meaningful regset content in bytes */
+	__u32 max_size; /* maxmium possible size for this thread */
+	__u16 vl; /* current vector length */
+	__u16 max_vl; /* maximum possible vector length */
+	__u16 flags;
+	__u16 __reserved;
+};
+
+#define SVE_PT_REGS_MASK		(1 << 0)
+#define SVE_PT_REGS_FPSIMD		0
+#define SVE_PT_REGS_SVE			SVE_PT_REGS_MASK
+
+#define SVE_PT_REGS_OFFSET	((sizeof (struct sve_context) + 15) / 16 * 16)
+
+#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) + 15) / 16 * 16)
+#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 + 15) / 16 * 16)
+
+#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
+
 /* Defined in auto-generated files.  */
 void init_registers_aarch64 (void);
 extern const struct target_desc *tdesc_aarch64;
@@ -49,15 +174,22 @@ extern const struct target_desc *tdesc_aarch64;

 #define AARCH64_X_REGS_NUM 31
 #define AARCH64_V_REGS_NUM 32
+#define AARCH64_SVE_Z_REGS_NUM AARCH64_V_REGS_NUM
+#define AARCH64_SVE_P_REGS_NUM 16
 #define AARCH64_X0_REGNO    0
 #define AARCH64_SP_REGNO   31
 #define AARCH64_PC_REGNO   32
 #define AARCH64_CPSR_REGNO 33
 #define AARCH64_V0_REGNO   34
+#define AARCH64_SVE_Z0_REGNO AARCH64_V0_REGNO
 #define AARCH64_FPSR_REGNO (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM)
 #define AARCH64_FPCR_REGNO (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM + 1)
+#define AARCH64_SVE_P0_REGNO (AARCH64_FPCR_REGNO + 1)
+#define AARCH64_SVE_FFR_REGNO (AARCH64_SVE_P0_REGNO +
AARCH64_SVE_P_REGS_NUM)
+#define AARCH64_SVE_VG_REGNO (AARCH64_SVE_FFR_REGNO + 1)

-#define AARCH64_NUM_REGS (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM + 2)
+#define AARCH64_NUM_REGS AARCH64_FPCR_REGNO + 1
+#define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNO + 1

 /* Per-process arch-specific data we want to keep.  */

@@ -86,6 +218,16 @@ is_64bit_tdesc (void)
   return register_size (regcache->tdesc, 0) == 8;
 }

+/* Return true if the Z and P registers exist.  */
+
+static int
+is_sve_tdesc (void)
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+
+  return regcache->tdesc->num_registers == AARCH64_SVE_NUM_REGS;
+}
+
 /* Implementation of linux_target_ops method "cannot_store_register".  */

 static int
@@ -153,6 +295,201 @@ aarch64_store_fpregset (struct regcache *regcache,
const void *buf)
   supply_register (regcache, AARCH64_FPCR_REGNO, &regset->fpcr);
 }

+static void
+aarch64_fill_svefpregset (struct regcache *regcache, void *buf)
+{
+  struct user_fpsimd_state *regset = (struct user_fpsimd_state *) buf;
+
+  collect_register (regcache, AARCH64_FPSR_REGNO, &regset->fpsr);
+  collect_register (regcache, AARCH64_FPCR_REGNO, &regset->fpcr);
+}
+
+static void
+aarch64_store_svefpregset (struct regcache *regcache, const void *buf)
+{
+  const struct user_fpsimd_state *regset
+    = (const struct user_fpsimd_state *) buf;
+
+  supply_register (regcache, AARCH64_FPSR_REGNO, &regset->fpsr);
+  supply_register (regcache, AARCH64_FPCR_REGNO, &regset->fpcr);
+}
+
+/* Put the registers from regcache into linux structure buf.  */
+
+static void
+aarch64_fill_sveregset (struct regcache *regcache, void *buf)
+{
+  struct user_sve_header *header = (struct user_sve_header *) buf;
+  char *base = (char*) buf;
+  long vq;
+  int i;
+
+  /* Note: We do not set VL.  Changing VL on the fly is currently 
unsupported
+     in Linux.  */
+  gdb_assert (sve_vl_valid (header->vl));
+  vq = sve_vq_from_vl (header->vl);
+  gdb_assert (SVE_PT_SIZE (vq, header->flags) == header->size);
+
+  if (!(header->flags && SVE_PT_REGS_SVE))
+    {
+      /* There is no SVE state, however our buffer does have enough room 
to fit
+	 a full SVE state.  Try to put the registers into an fpsimd structure,
+	 whilst checking to see if there is any actual SVE state.  */
+
+      int has_sve_state = 0;
+      char sve_reg[SVE_PT_SVE_ZREG_SIZE (vq)];
+      struct user_fpsimd_state *fpsimd
+	= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      memset (&sve_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      /* Check if any SVE state exists in the regcache.  */
+
+      for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+	{
+	  has_sve_state |= compare_register (regcache,
+					     AARCH64_SVE_Z0_REGNO + i, &sve_reg,
+					     sizeof (__int128));
+	  if (has_sve_state != 0)
+	    break;
+	}
+
+      if (has_sve_state == 0)
+	for (i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+	  {
+	    has_sve_state |= compare_register (regcache,
+					       AARCH64_SVE_P0_REGNO + i,
+					       &sve_reg, 0);
+	    if (has_sve_state != 0)
+	      break;
+	  }
+
+      if (has_sve_state == 0)
+	  has_sve_state |= compare_register (regcache, AARCH64_SVE_FFR_REGNO,
+					     &sve_reg, 0);
+
+      /* If no SVE state then copy into a fpsimd structure.  */
+
+      if (has_sve_state == 0)
+	{
+	  /* These collects will overflow the size of a vreg, but that does not
+	     matter as we have enough room in the buffer and we know that the
+	     overflow will always be 0s.  */
+	  for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+	    collect_register (regcache, AARCH64_SVE_Z0_REGNO + i,
+			      &fpsimd->vregs[i]);
+
+	  collect_register (regcache, AARCH64_FPSR_REGNO, &fpsimd->fpsr);
+	  collect_register (regcache, AARCH64_FPCR_REGNO, &fpsimd->fpcr);
+
+	  return;
+	}
+
+      /* Otherwise, enable SVE state in the header.  */
+
+      header->flags |= SVE_PT_REGS_SVE;
+      header->size = SVE_PT_SIZE (vq, header->flags);
+      memset (base + SVE_PT_SVE_OFFSET, 0,
+	      SVE_PT_SVE_SIZE (vq, SVE_PT_REGS_SVE));
+    }
+
+  for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+    collect_register (regcache, AARCH64_SVE_Z0_REGNO + i,
+		      base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
+
+  for (i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+    collect_register (regcache, AARCH64_SVE_P0_REGNO + i,
+		      base + SVE_PT_SVE_PREG_OFFSET (vq, i));
+
+  collect_register (regcache, AARCH64_SVE_FFR_REGNO,
+		    base + SVE_PT_SVE_FFR_OFFSET (vq));
+  collect_register (regcache, AARCH64_FPSR_REGNO,
+		    base + SVE_PT_SVE_FPSR_OFFSET (vq));
+  collect_register (regcache, AARCH64_FPCR_REGNO,
+		    base + SVE_PT_SVE_FPCR_OFFSET (vq));
+}
+
+/* Put the registers from linux structure buf into regcache.  */
+
+static void
+aarch64_store_sveregset (struct regcache *regcache, const void *buf)
+{
+  struct user_sve_header *header = (struct user_sve_header *) buf;
+  char *base = (char*) buf;
+  long vg, vq;
+  int i;
+
+  gdb_assert (sve_vl_valid (header->vl));
+  vg = sve_vg_from_vl (header->vl);
+  vq = sve_vq_from_vl (header->vl);
+  gdb_assert (SVE_PT_SIZE (vq, header->flags) == header->size);
+  supply_register (regcache, AARCH64_SVE_VG_REGNO, &vg);
+
+  if (header->flags && SVE_PT_REGS_SVE)
+    {
+      for (i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+	supply_register (regcache, AARCH64_SVE_Z0_REGNO + i,
+			 base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
+
+      for (i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+	supply_register (regcache, AARCH64_SVE_P0_REGNO + i,
+			 base + SVE_PT_SVE_PREG_OFFSET (vq, i));
+
+      supply_register (regcache, AARCH64_SVE_FFR_REGNO,
+		       base + SVE_PT_SVE_FFR_OFFSET (vq));
+      supply_register (regcache, AARCH64_FPSR_REGNO,
+		       base + SVE_PT_SVE_FPSR_OFFSET (vq));
+      supply_register (regcache, AARCH64_FPCR_REGNO,
+		       base + SVE_PT_SVE_FPCR_OFFSET (vq));
+    }
+  else
+    {
+      /* There is no SVE state.  */
+      char sve_reg[SVE_PT_SVE_ZREG_SIZE (vq)];
+      struct user_fpsimd_state *fpsimd
+	= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      /* Clear the SVE only registers.  */
+
+      memset (&sve_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      for (i = 0; i <= AARCH64_SVE_P_REGS_NUM; i++)
+	supply_register (regcache, AARCH64_SVE_P0_REGNO + i, &sve_reg);
+
+      supply_register (regcache, AARCH64_SVE_FFR_REGNO, &sve_reg);
+
+      /* Convert vregs from fpsimd state to zregs, ensuring additional 
state is
+	 null.  */
+
+      for (i = 0; i <= AARCH64_SVE_Z_REGS_NUM; i++)
+	{
+	  memcpy (&sve_reg, &fpsimd->vregs[i], sizeof (__int128));
+	  supply_register (regcache, AARCH64_SVE_Z0_REGNO + i, &sve_reg);
+	}
+
+      supply_register (regcache, AARCH64_FPSR_REGNO, &fpsimd->fpsr);
+      supply_register (regcache, AARCH64_FPCR_REGNO, &fpsimd->fpcr);
+    }
+}
+
+/* Given an sve header from ptrace, return the size of a full register set
+   (with header).  */
+
+static int
+aarch64_get_full_sve_size (const void *buf)
+{
+  struct user_sve_header *header = (struct user_sve_header *) buf;
+
+  gdb_assert (sve_vl_valid (header->vl));
+
+  if (header->flags && SVE_PT_REGS_SVE)
+    return header->size;
+  else
+    /* There is no SVE state.  If we are writing state back to the kernel 
then
+       there needs to be enough room to fit a current sized SVE state.  */
+    return SVE_PT_SIZE (sve_vq_from_vl (header->vl), SVE_PT_REGS_SVE);
+}
+
 /* Enable miscellaneous debugging output.  The name is historical - it
    was originally used to debug LinuxThreads support.  */
 extern int debug_threads;
@@ -526,13 +863,48 @@ static struct regs_info regs_info_aarch64 =
     &aarch64_regsets_info,
   };

+static struct regset_info aarch64_sve_regsets[] =
+{
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
+    sizeof (struct user_pt_regs), GENERAL_REGS,
+    aarch64_fill_gregset, aarch64_store_gregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
+    sizeof (struct user_fpsimd_state), FP_REGS,
+    aarch64_fill_svefpregset, aarch64_store_svefpregset
+  },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_SVE,
+    sizeof (struct user_sve_header), EXTENDED_REGS,
+    aarch64_fill_sveregset, aarch64_store_sveregset,
+    aarch64_get_full_sve_size
+  },
+  NULL_REGSET
+};
+
+static struct regsets_info aarch64_sve_regsets_info =
+  {
+    aarch64_sve_regsets, /* regsets.  */
+    0, /* num_regsets.  */
+    NULL, /* disabled_regsets.  */
+  };
+
+static struct regs_info regs_info_aarch64_sve =
+  {
+    NULL, /* regset_bitmap.  */
+    NULL, /* usrregs.  */
+    &aarch64_sve_regsets_info,
+  };
+
 /* Implementation of linux_target_ops method "regs_info".  */

 static const struct regs_info *
 aarch64_regs_info (void)
 {
   if (is_64bit_tdesc ())
-    return &regs_info_aarch64;
+    {
+      if (is_sve_tdesc ())
+	return &regs_info_aarch64_sve;
+      return &regs_info_aarch64;
+    }
   else
     return &regs_info_aarch32;
 }
@@ -546,8 +918,8 @@ aarch64_supports_tracepoints (void)
     return 1;
   else
     {
-      /* We don't support tracepoints on aarch32 now.  */
-      return is_64bit_tdesc ();
+      /* We don't support tracepoints on either aarch32 or SVE.  */
+      return is_64bit_tdesc () && !is_sve_tdesc ();
     }
 }

@@ -3022,4 +3394,5 @@ initialize_low_arch (void)
   initialize_low_arch_aarch32 ();

   initialize_regsets_info (&aarch64_regsets_info);
+  initialize_regsets_info (&aarch64_sve_regsets_info);
 }
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 
b5ac8de5ccee13866d6b74a34d3db87412537e66..78a671fe13f689c64b64378eeafe2ded3
e309ca7 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -32,6 +32,7 @@
 #ifdef HAVE_LINUX_REGSETS
 typedef void (*regset_fill_func) (struct regcache *, void *);
 typedef void (*regset_store_func) (struct regcache *, const void *);
+typedef int (*regset_get_full_size_func) (const void *);
 enum regset_type {
   GENERAL_REGS,
   FP_REGS,
@@ -53,6 +54,7 @@ struct regset_info
   enum regset_type type;
   regset_fill_func fill_function;
   regset_store_func store_function;
+  regset_get_full_size_func get_full_size_function;
 };

 /* Aggregation of all the supported regsets of a given
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 
602f7376c60a9b7b23496e4e0dea437e985f7c71..595144f7123c72a248dda651bd7c42b04
0f286a7 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5490,6 +5490,38 @@ regsets_fetch_inferior_registers (struct 
regsets_info *regsets_info,
 #else
       res = ptrace (regset->get_request, pid, data, nt_type);
 #endif
+
+      if (res == 0 && regset->get_full_size_function != NULL)
+	{
+	  /* First call only obtained a partial set of data.  Use obtained data
+	     to get the full size and then call ptrace again.  */
+
+	  int full_size = regset->get_full_size_function (buf);
+
+	  if (full_size <= 0)
+	    res = -1;
+	  else
+	    {
+	      free (buf);
+	      buf = xmalloc (full_size);
+
+	      if (nt_type)
+		{
+		  iov.iov_base = buf;
+		  iov.iov_len = full_size;
+		}
+	      else
+		data = buf;
+
+#ifndef __sparc__
+	      res = ptrace (regset->get_request, pid,
+			    (PTRACE_TYPE_ARG3) (long) nt_type, data);
+#else
+	      res = ptrace (regset->get_request, pid, data, nt_type);
+#endif
+	    }
+	}
+
       if (res < 0)
 	{
 	  if (errno == EIO)
@@ -5574,6 +5606,37 @@ regsets_store_inferior_registers (struct 
regsets_info *regsets_info,
       res = ptrace (regset->get_request, pid, data, nt_type);
 #endif

+      if (res == 0 && regset->get_full_size_function != NULL)
+	{
+	  /* First call only obtained a partial set of data.  Use obtained data
+	     to get the full size and then call ptrace again.  */
+
+	  int full_size = regset->get_full_size_function (buf);
+
+	  if (full_size <= 0)
+	    res = -1;
+	  else
+	    {
+	      free (buf);
+	      buf = xmalloc (full_size);
+
+	      if (nt_type)
+		{
+		  iov.iov_base = buf;
+		  iov.iov_len = full_size;
+		}
+	      else
+		data = buf;
+
+#ifndef __sparc__
+	      res = ptrace (regset->get_request, pid,
+			    (PTRACE_TYPE_ARG3) (long) nt_type, data);
+#else
+	      res = ptrace (regset->get_request, pid, data, nt_type);
+#endif
+	    }
+	}
+
       if (res == 0)
 	{
 	  /* Then overlay our cached registers on that.  */
diff --git a/include/elf/common.h b/include/elf/common.h
index 
da79613e6dbad54003e921c2fbe2b30b34c21595..80a4d730b5c86e8cfdb29e1163e934b9f
8a7b498 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -605,6 +605,7 @@
 					/*   note name must be "LINUX".  */
 #define NT_ARM_HW_WATCH	0x403		/* AArch hardware watchpoint registers */
 					/*   note name must be "LINUX".  */
+#define NT_ARM_SVE	0x405		/* ARM SVE registers.  */
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */

