diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 
5525b0dd46a1bb641f4b6003942613437202e785..97212864dcce84779b3a86355f0ac69c5
0e3b20e 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -44,6 +44,7 @@

 /* Defines ps_err_e, struct ps_prochandle.  */
 #include "gdb_proc_service.h"
+#include "arch-utils.h"

 #ifndef TRAP_HWBKPT
 #define TRAP_HWBKPT 0x0004
@@ -191,6 +192,34 @@ struct aarch64_process_info

 static struct aarch64_process_info *aarch64_process_list = NULL;

+
+/* Read VG for the given tid using ptrace.  If SVE is not supported then
zero
+   is returned.  */
+
+static unsigned long
+aarch64_read_vg (int tid)
+{
+  int ret;
+  struct iovec iovec;
+  struct user_sve_header header;
+
+  iovec.iov_len = sizeof (header);
+  iovec.iov_base = &header;
+
+  /* Ptrace gives the vector length in bytes.  Convert it to VG - which
is the
+     number of 64bit chunks.  We use VG because that is the value that
appears
+     as a DWARF register.  */
+
+  ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec);
+  if (ret >= 0)
+    {
+      gdb_assert (sve_vl_valid (header.vl));
+      return sve_vg_from_vl (header.vl);
+    }
+  /* SVE is not supported.  */
+  return 0;
+}
+
 /* Find process data for process PID.  */

 static struct aarch64_process_info *
@@ -900,7 +929,7 @@ aarch64_linux_read_description (struct target_ops *ops)
   if (ret == 0)
     return tdesc_arm_with_neon;
   else
-    return tdesc_aarch64;
+    return aarch64_get_tdesc (aarch64_read_vg (tid));
 }

 /* Convert a native/host siginfo object, into/from the siginfo in the
@@ -1179,6 +1208,20 @@ aarch64_linux_can_do_single_step (struct target_ops
*target)
   return 1;
 }

+/* Implement the "to_thread_architecture" target_ops method.  */
+
+static struct gdbarch *
+aarch64_thread_architecture (struct target_ops *ops, ptid_t ptid)
+{
+  long vg = aarch64_read_vg (ptid_get_lwp (ptid));
+  struct gdbarch_info info;
+
+  gdbarch_info_init (&info);
+  info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu);
+  info.tdep_info = &vg;
+  return gdbarch_find_by_info (info);
+}
+
 /* Define AArch64 maintenance commands.  */

 static void
@@ -1231,6 +1274,7 @@ _initialize_aarch64_linux_nat (void)
   t->to_watchpoint_addr_within_range =
     aarch64_linux_watchpoint_addr_within_range;
   t->to_can_do_single_step = aarch64_linux_can_do_single_step;
+  t->to_thread_architecture = aarch64_thread_architecture;

   /* Override the GNU/Linux inferior startup hook.  */
   super_post_startup_inferior = t->to_post_startup_inferior;
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 
2eaf268e9ea2e1a7912c5778033d3ff01737a648..2c789e7aca1c3c4e3150c88d53aae5afb
41e2410 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -111,11 +111,14 @@ struct gdbarch_tdep

   /* syscall record.  */
   int (*aarch64_syscall_record) (struct regcache *regcache, unsigned long
svc_number);
+
+  /* For SVE targets, the VG value.  */
+  long vg;
 };

-#define AARCH64_TDEP_HAS_SVE(tdep) (0)
+#define AARCH64_TDEP_HAS_SVE(tdep) (tdep->vg != 0)

-extern struct target_desc *tdesc_aarch64;
+struct target_desc *aarch64_get_tdesc (long vg);

 extern int aarch64_process_record (struct gdbarch *gdbarch,
                                struct regcache *regcache, CORE_ADDR addr);
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 
9808997664597484d006d380e003841528512ca5..e1cdee9e35534e1910c31feca5208ff1c
d5bc8b5 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -51,6 +51,7 @@
 #include "record.h"
 #include "record-full.h"
 #include "features/aarch64.c"
+#include "features/aarch64-sve.c"
 #include "arch/aarch64-insn.h"
 #include "opcode/aarch64.h"
 #include <algorithm>
@@ -68,6 +69,12 @@
 #define AARCH64_B0_REGNUM (AARCH64_H0_REGNUM + 32)
 #define AARCH64_SVE_V0_REGNUM (AARCH64_B0_REGNUM + 32)

+/* Maximum supported VG value.  Increase if required.  */
+#define AARCH64_TDEP_MAX_SVE_VG  32
+
+/* All possible aarch64 target descriptors.  */
+struct target_desc *tdesc_aarch64_sve_list[AARCH64_TDEP_MAX_SVE_VG + 1];
+
 /* The standard register names, and all the valid aliases for them.  */
 static const struct
 {
@@ -2783,6 +2790,42 @@ aarch64_target_get_tdep_info (void *registers)
   return NULL;
 }

+/* Get the correct target description for the given VG value.
+   If VG is zero then it is assumed SVE is not supported.
+   (It is not possible to set VG to zero on an SVE system).  */
+struct target_desc *
+aarch64_get_tdesc (long vg)
+{
+  if (vg > AARCH64_TDEP_MAX_SVE_VG)
+    error (_("VG is %ld, maximum supported value is %d"), vg,
+	   AARCH64_TDEP_MAX_SVE_VG);
+  struct target_desc *tdesc;
+
+  if (vg == 0)
+    return tdesc_aarch64;
+
+  tdesc = tdesc_aarch64_sve_list[vg];
+
+  if (tdesc == NULL)
+    {
+      struct tdesc_feature *feature;
+
+      /* The target descriptor for the given VG value has not been
accessed
+	 yet.  Allocate a new one and then update all the register sizes.  */
+
+      initialize_tdesc_aarch64_sve ();
+      tdesc = tdesc_aarch64_sve;
+
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
+      tdesc_rescale_vector_types (feature, vg);
+      tdesc_rescale_registers (feature, "svev", vg);
+      tdesc_rescale_registers (feature, "svep", vg);
+
+      tdesc_aarch64_sve_list[vg] = tdesc;
+    }
+  return tdesc;
+}
+
 /* Initialize the current architecture based on INFO.  If possible,
    re-use an architecture from ARCHES, which is a list of
    architectures already created during this debugging session.
@@ -2800,19 +2843,35 @@ aarch64_gdbarch_init (struct gdbarch_info info,
struct gdbarch_list *arches)
   const struct target_desc *tdesc = info.target_desc;
   int i;
   int valid_p = 1;
-  const struct tdesc_feature *feature;
+  const struct tdesc_feature *feature_core;
+  const struct tdesc_feature *feature_fpu;
+  const struct tdesc_feature *feature_sve;
   int num_regs = 0;
   int num_pseudo_regs = 0;
-
-  /* Ensure we always have a target descriptor.  */
-  if (!tdesc_has_registers (tdesc))
-    tdesc = tdesc_aarch64;
-
+  long vg = 0;
+
+  if (info.tdep_info)
+    vg = *(long *)info.tdep_info;
+  else if (tdesc && tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve"))
+    /* The current target descriptor says we have SVE but we were not
given a
+       VG value.  Set VG to the minimum SVE supported value.  */
+    vg = 2;
+
+  if (vg > AARCH64_TDEP_MAX_SVE_VG)
+    internal_error (__FILE__, __LINE__, _("VG out of bounds: %ld (max
%d)"),
+		    vg, AARCH64_TDEP_MAX_SVE_VG);
+
+  /* Ensure we always have a target descriptor, and that it is for the
current
+     VG value.  */
+  if (!tdesc_has_registers (tdesc) || vg > 0)
+    tdesc = aarch64_get_tdesc (vg);
   gdb_assert (tdesc);

-  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.core");
+  feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.core");
+  feature_fpu = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu");
+  feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");

-  if (feature == NULL)
+  if (feature_core == NULL)
     return NULL;

   tdesc_data = tdesc_data_alloc ();
@@ -2820,25 +2879,47 @@ aarch64_gdbarch_init (struct gdbarch_info info,
struct gdbarch_list *arches)
   /* Validate the descriptor provides the mandatory core R registers
      and allocate their numbers.  */
   for (i = 0; i < ARRAY_SIZE (aarch64_r_register_names); i++)
-    valid_p &=
-      tdesc_numbered_register (feature, tdesc_data, AARCH64_X0_REGNUM + i,
-			       aarch64_r_register_names[i]);
+    valid_p &= tdesc_numbered_register (feature_core, tdesc_data,
+					AARCH64_X0_REGNUM + i,
+					aarch64_r_register_names[i]);

   num_regs = AARCH64_X0_REGNUM + i;

-  /* Look for the V registers.  */
-  feature = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu");
-  if (feature)
+  /* Add the V registers.  */
+  if (feature_fpu != NULL)
     {
+      gdb_assert (feature_sve == NULL);
+      gdb_assert (vg == 0);
+
       /* Validate the descriptor provides the mandatory V registers
-         and allocate their numbers.  */
+	 and allocate their numbers.  */
       for (i = 0; i < ARRAY_SIZE (aarch64_v_register_names); i++)
-	valid_p &=
-	  tdesc_numbered_register (feature, tdesc_data, AARCH64_V0_REGNUM + i,
-				   aarch64_v_register_names[i]);
+	valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data,
+					    AARCH64_V0_REGNUM + i,
+					    aarch64_v_register_names[i]);

       num_regs = AARCH64_V0_REGNUM + i;
+    }
+
+  /* Add the SVE registers.  */
+  if (feature_sve != NULL)
+    {
+      gdb_assert (feature_fpu == NULL);
+      gdb_assert (vg > 0);
+
+      /* Validate the descriptor provides the mandatory sve registers
+	 and allocate their numbers.  */
+      for (i = 0; i < ARRAY_SIZE (aarch64_sve_register_names); i++)
+	valid_p &= tdesc_numbered_register (feature_sve, tdesc_data,
+					    AARCH64_SVE_Z0_REGNUM + i,
+					    aarch64_sve_register_names[i]);
+
+      num_regs = AARCH64_SVE_Z0_REGNUM + i;
+      num_pseudo_regs += 32;	/* add the Vn register pseudos.  */
+    }

+  if (feature_fpu != NULL || feature_sve != NULL)
+    {
       num_pseudo_regs += 32;	/* add the Qn scalar register pseudos */
       num_pseudo_regs += 32;	/* add the Dn scalar register pseudos */
       num_pseudo_regs += 32;	/* add the Sn scalar register pseudos */
@@ -2860,15 +2941,14 @@ aarch64_gdbarch_init (struct gdbarch_info info,
struct gdbarch_list *arches)
        best_arch != NULL;
        best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
     {
-      /* Found a match.  */
-      break;
-    }
-
-  if (best_arch != NULL)
-    {
-      if (tdesc_data != NULL)
-	tdesc_data_cleanup (tdesc_data);
-      return best_arch->gdbarch;
+      tdep = gdbarch_tdep (best_arch->gdbarch);
+      if (tdep && tdep->vg == vg)
+	{
+	  /* Found a match.  */
+	  if (tdesc_data != NULL)
+	    tdesc_data_cleanup (tdesc_data);
+	  return best_arch->gdbarch;
+	}
     }

   tdep = XCNEW (struct gdbarch_tdep);
@@ -2878,6 +2958,7 @@ aarch64_gdbarch_init (struct gdbarch_info info,
struct gdbarch_list *arches)
   tdep->lowest_pc = 0x20;
   tdep->jb_pc = -1;		/* Longjump support not enabled by default.  */
   tdep->jb_elt_size = 8;
+  tdep->vg = vg;

   set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
   set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h
index 
ef97d1d5f76d80bad1a47c435fa1b7f3cb871d73..217293a4f4e29dccf191508efab1f6a43
9623aac 100644
--- a/gdb/target-descriptions.h
+++ b/gdb/target-descriptions.h
@@ -175,8 +175,8 @@ int tdesc_has_registers (const struct target_desc *);
 /* Return the feature with the given name, if present, or NULL if
    the named feature is not found.  */

-const struct tdesc_feature *tdesc_find_feature (const struct target_desc
*,
-						const char *name);
+struct tdesc_feature *tdesc_find_feature (const struct target_desc *,
+					  const char *name);

 /* Return the name of FEATURE.  */

@@ -253,4 +253,9 @@ void tdesc_create_reg (struct tdesc_feature *feature,
const char *name,
 		       int regnum, int save_restore, const char *group,
 		       int bitsize, const char *type);

+void tdesc_rescale_vector_types (struct tdesc_feature *feature, int
scale);
+
+void tdesc_rescale_registers (struct tdesc_feature *feature, char
*type_name,
+			      int scale);
+
 #endif /* TARGET_DESCRIPTIONS_H */
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index 
40f04786b08613d59d94868e5a9c02b9c9df6520..62155a5a94f423ee88af739e3070ff78b
6f75661 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -491,7 +491,7 @@ tdesc_has_registers (const struct target_desc
*target_desc)
 /* Return the feature with the given name, if present, or NULL if
    the named feature is not found.  */

-const struct tdesc_feature *
+struct tdesc_feature *
 tdesc_find_feature (const struct target_desc *target_desc,
 		    const char *name)
