diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index f1b014b5eb26..5e12a2e403f6 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -586,7 +586,7 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
 
       /* We attempt to fetch SVE registers if there is support for either
 	 SVE or SME (due to the SSVE state of SME).  */
-      if (tdep->has_sve () || tdep->has_sme ())
+      if (tdep->has_sve || tdep->has_sme ())
 	fetch_sveregs_from_thread (regcache);
       else
 	fetch_fpregs_from_thread (regcache);
@@ -610,10 +610,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
   /* SVE register?  */
-  else if ((tdep->has_sve () || tdep->has_sme ())
-	   && regno < AARCH64_SVE_VG_REGNUM)
+  else if ((tdep->has_sve || tdep->has_sme ()) && regno < AARCH64_SVE_VG_REGNUM)
     fetch_sveregs_from_thread (regcache);
-  else if (tdep->has_sve () && regno == AARCH64_SVE_VG_REGNUM)
+  else if (tdep->has_sve && regno == AARCH64_SVE_VG_REGNUM)
     fetch_sve_vg_from_thread (regcache);
   /* FPSIMD register?  */
   else if (regno <= AARCH64_FPCR_REGNUM)
@@ -694,7 +693,7 @@ aarch64_store_registers (struct regcache *regcache, int regno)
 
       /* We attempt to store SVE registers if there is support for either
 	 SVE or SME (due to the SSVE state of SME).  */
-      if (tdep->has_sve () || tdep->has_sme ())
+      if (tdep->has_sve || tdep->has_sme ())
 	store_sveregs_to_thread (regcache);
       else
 	store_fpregs_to_thread (regcache);
@@ -715,10 +714,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
   else if (regno < AARCH64_V0_REGNUM)
     store_gregs_to_thread (regcache);
   /* SVE register?  */
-  else if ((tdep->has_sve () || tdep->has_sme ())
-	   && regno < AARCH64_SVE_VG_REGNUM)
+  else if ((tdep->has_sve || tdep->has_sme ()) && regno < AARCH64_SVE_VG_REGNUM)
     store_sveregs_to_thread (regcache);
-  else if (tdep->has_sve () && regno == AARCH64_SVE_VG_REGNUM)
+  else if (tdep->has_sve && regno == AARCH64_SVE_VG_REGNUM)
     store_sve_vg_to_thread (regcache);
   /* FPSIMD register?  */
   else if (regno <= AARCH64_FPCR_REGNUM)
@@ -911,7 +909,7 @@ aarch64_linux_nat_target::read_description ()
   /* SVE/SSVE check.  Reading VQ may return either the regular vector length
      or the streaming vector length, depending on whether streaming mode is
      active or not.  */
-  features.vq = aarch64_sve_get_vq (tid);
+  features.sve = aarch64_sve_get_vq (tid) != 0;
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
   features.tls = aarch64_tls_register_count (tid);
@@ -1025,19 +1023,19 @@ aarch64_linux_nat_target::thread_architecture (ptid_t ptid)
      the tdep.  */
   aarch64_gdbarch_tdep *tdep
     = gdbarch_tdep<aarch64_gdbarch_tdep> (inf->arch ());
-  uint64_t vq = aarch64_sve_get_vq (ptid.lwp ());
+  bool sve = aarch64_sve_get_vq (ptid.lwp ()) != 0;
   uint64_t svq = aarch64_za_get_svq (ptid.lwp ());
-  if (vq == tdep->vq && svq == tdep->sme_svq)
+  if (sve == tdep->has_sve && svq == tdep->sme_svq)
     return inf->arch ();
 
   /* We reach here if any vector length for the thread is different from its
      value at process start.  Lookup gdbarch via info (potentially creating a
-     new one) by using a target description that corresponds to the new vq/svq
-     value and the current architecture features.  */
+     new one) by using a target description that corresponds to the new
+     vector/matrix state and the current architecture features.  */
 
   const struct target_desc *tdesc = gdbarch_target_desc (inf->arch ());
   aarch64_features features = aarch64_features_from_target_desc (tdesc);
-  features.vq = vq;
+  features.sve = sve;
   features.svq = svq;
 
   /* Check for the SME2 feature.  */
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index c608a84bc711..c04b693f70e7 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -275,7 +275,8 @@ read_aarch64_ctx (CORE_ADDR ctx_addr, enum bfd_endian byte_order,
 static void
 aarch64_linux_restore_vregs (struct gdbarch *gdbarch,
 			     struct trad_frame_cache *cache,
-			     CORE_ADDR fpsimd_context)
+			     CORE_ADDR fpsimd_context,
+			     ULONGEST vl)
 {
   /* WARNING: SIMD state is laid out in memory in target-endian format.
 
@@ -335,7 +336,7 @@ aarch64_linux_restore_vregs (struct gdbarch *gdbarch,
 					  num_regs + AARCH64_B0_REGNUM
 					  + i, {buf, B_REGISTER_SIZE});
 
-	  if (tdep->has_sve ())
+	  if (tdep->has_sve)
 	    trad_frame_set_reg_value_bytes (cache,
 					    num_regs + AARCH64_SVE_V0_REGNUM
 					    + i, {buf, V_REGISTER_SIZE});
@@ -356,22 +357,22 @@ aarch64_linux_restore_vregs (struct gdbarch *gdbarch,
 	  trad_frame_set_reg_addr (cache, num_regs + AARCH64_B0_REGNUM + i,
 				   offset);
 
-	  if (tdep->has_sve ())
+	  if (tdep->has_sve)
 	    trad_frame_set_reg_addr (cache, num_regs + AARCH64_SVE_V0_REGNUM
 				     + i, offset);
 	}
 
-      if (tdep->has_sve ())
+      if (tdep->has_sve)
 	{
 	  /* If SVE is supported for this target, zero out the Z
 	     registers then copy the first 16 bytes of each of the V
 	     registers to the associated Z register.  Otherwise the Z
 	     registers will contain uninitialized data.  */
-	  std::vector<gdb_byte> z_buffer (tdep->vq * 16);
+	  std::vector<gdb_byte> z_buffer (vl);
 
 	  /* We have already handled the endianness swap above, so we don't need
 	     to worry about it here.  */
-	  memcpy (z_buffer.data (), buf, V_REGISTER_SIZE);
+	  memcpy (z_buffer.data (), buf, vl);
 	  trad_frame_set_reg_value_bytes (cache,
 					  AARCH64_SVE_Z0_REGNUM + i,
 					  z_buffer);
@@ -403,8 +404,8 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame,
   CORE_ADDR section_end = signal_frame.section_end;
   uint32_t size, magic;
   bool extra_found = false;
-  enum bfd_endian byte_order
-    = gdbarch_byte_order (get_frame_arch (this_frame));
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
   while ((magic = read_aarch64_ctx (section, byte_order, &size)) != 0
 	 && size != 0)
@@ -423,6 +424,11 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame,
 	    /* Check if the section is followed by a full SVE dump, and set
 	       sve_regs if it is.  */
 	    gdb_byte buf[4];
+	    aarch64_gdbarch_tdep *tdep
+	      = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+	    if (!tdep->has_sve)
+	      break;
 
 	    /* Extract the vector length.  */
 	    if (target_read_memory (section + AARCH64_SVE_CONTEXT_VL_OFFSET,
@@ -436,6 +442,10 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame,
 
 	    signal_frame.vl = extract_unsigned_integer (buf, 2, byte_order);
 
+	    if (signal_frame.vl == 0)
+	      error (_ ("Invalid vector length in signal frame %" PRIu64 "."),
+		     signal_frame.vl);
+
 	    /* Extract the flags to check if we are in streaming mode.  */
 	    if (target_read_memory (section
 				    + AARCH64_SVE_CONTEXT_FLAGS_OFFSET,
@@ -598,7 +608,7 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
 
   /* Restore the SVE / FPSIMD registers.  */
-  if (tdep->has_sve () && signal_frame.sve_section != 0)
+  if (tdep->has_sve && signal_frame.sve_section != 0)
     {
       ULONGEST vq = sve_vq_from_vl (signal_frame.vl);
       CORE_ADDR sve_regs = signal_frame.sve_section;
@@ -648,8 +658,9 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
 			       fpsimd + AARCH64_FPSIMD_FPCR_OFFSET);
 
       /* If there was no SVE section then set up the V registers.  */
-      if (!tdep->has_sve () || signal_frame.sve_section == 0)
-	aarch64_linux_restore_vregs (gdbarch, this_cache, fpsimd);
+      if (!tdep->has_sve || signal_frame.sve_section == 0)
+	aarch64_linux_restore_vregs (gdbarch, this_cache, fpsimd,
+				     tdep->has_sve ? signal_frame.vl : 0);
     }
 
   /* Restore the SME registers.  */
@@ -726,7 +737,7 @@ aarch64_linux_sigframe_prev_arch (const frame_info_ptr &this_frame,
   const struct target_desc *tdesc
     = gdbarch_target_desc (get_frame_arch (this_frame));
   aarch64_features features = aarch64_features_from_target_desc (tdesc);
-  features.vq = sve_vq_from_vl (signal_frame.vl);
+  features.sve = signal_frame.vl != 0;
   features.svq = (uint8_t) sve_vq_from_vl (signal_frame.svl);
 
   struct gdbarch_info info;
@@ -1053,9 +1064,12 @@ collect_sve_regset (const struct regset *regset,
   gdb_byte *header = (gdb_byte *) buf;
   struct gdbarch *gdbarch = regcache->arch ();
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
-  uint64_t vq = tdep->vq;
+  ULONGEST vg;
+  // FIXME: Remove this cast.
+  enum register_status vg_status
+    = const_cast<struct regcache *> (regcache)->raw_read (AARCH64_SVE_VG_REGNUM, &vg);
 
+  gdb_assert (vg_status == REG_VALID);
   gdb_assert (buf != NULL);
   gdb_assert (size > SVE_HEADER_SIZE);
 
@@ -1067,7 +1081,7 @@ collect_sve_regset (const struct regset *regset,
   store_unsigned_integer (header + SVE_HEADER_MAX_SIZE_OFFSET,
 			  SVE_HEADER_MAX_SIZE_LENGTH, byte_order, max_size);
   store_unsigned_integer (header + SVE_HEADER_VL_OFFSET, SVE_HEADER_VL_LENGTH,
-			  byte_order, sve_vl_from_vq (vq));
+			  byte_order, sve_vl_from_vg (vg));
   uint16_t max_vl = SVE_CORE_DUMMY_MAX_VL;
   store_unsigned_integer (header + SVE_HEADER_MAX_VL_OFFSET,
 			  SVE_HEADER_MAX_VL_LENGTH, byte_order,
@@ -1437,14 +1451,15 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
   cb (".reg", AARCH64_LINUX_SIZEOF_GREGSET, AARCH64_LINUX_SIZEOF_GREGSET,
       &aarch64_linux_gregset, NULL, cb_data);
 
-  if (tdep->has_sve ())
+  if (tdep->has_sve)
     {
       /* Create this on the fly in order to handle vector register sizes.  */
+      // FIXME: Don't use maximum VQ.
       const struct regcache_map_entry sve_regmap[] =
 	{
-	  { 32, AARCH64_SVE_Z0_REGNUM, (int) (tdep->vq * 16) },
-	  { 16, AARCH64_SVE_P0_REGNUM, (int) (tdep->vq * 16 / 8) },
-	  { 1, AARCH64_SVE_FFR_REGNUM, (int) (tdep->vq * 16 / 8) },
+	  { 32, AARCH64_SVE_Z0_REGNUM, (int)(AARCH64_MAX_SVE_VQ * 16) },
+	  { 16, AARCH64_SVE_P0_REGNUM, (int)(AARCH64_MAX_SVE_VQ * 16 / 8) },
+	  { 1, AARCH64_SVE_FFR_REGNUM, (int)(AARCH64_MAX_SVE_VQ * 16 / 8) },
 	  { 1, AARCH64_FPSR_REGNUM, 4 },
 	  { 1, AARCH64_FPCR_REGNUM, 4 },
 	  { 0 }
@@ -1627,7 +1642,7 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
      Otherwise the SVE section is considered active.  This guarantees we will
      have the correct target description with the correct SVE vector
      length.  */
-  features.vq = aarch64_linux_core_read_vq_from_sections (gdbarch, abfd);
+  features.sve = aarch64_linux_core_read_vq_from_sections (gdbarch, abfd) != 0;
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
 
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 04442f22ea3f..ff356b6a0ac7 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -2468,38 +2468,54 @@ aarch64_vnv_type (struct gdbarch *gdbarch)
 /* Implement the "dwarf2_reg_to_regnum" gdbarch method.  */
 
 static int
-aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+aarch64_tdep_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 {
+  int ret = aarch64_dwarf_reg_to_regnum (reg);
+
+  if (ret != -1)
+    return ret;
+
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+  if (tdep->has_pauth () && reg == AARCH64_DWARF_RA_SIGN_STATE)
+    return tdep->ra_sign_state_regnum;
 
-  if (reg >= AARCH64_DWARF_X0 && reg <= AARCH64_DWARF_X0 + 30)
-    return AARCH64_X0_REGNUM + reg - AARCH64_DWARF_X0;
+  return -1;
+}
+
+/* Implement the "regnum_to_dwarf2_reg" gdbarch method.  */
+
+static int
+aarch64_regnum_to_dwarf_reg (struct gdbarch *gdbarch, int regnum)
+{
+  if (regnum >= AARCH64_X0_REGNUM && regnum <= AARCH64_X0_REGNUM + 30)
+    return AARCH64_DWARF_X0 + regnum - AARCH64_X0_REGNUM;
 
-  if (reg == AARCH64_DWARF_SP)
-    return AARCH64_SP_REGNUM;
+  if (regnum == AARCH64_SP_REGNUM)
+    return AARCH64_DWARF_SP;
 
-  if (reg == AARCH64_DWARF_PC)
-    return AARCH64_PC_REGNUM;
+  if (regnum == AARCH64_PC_REGNUM)
+    return AARCH64_DWARF_PC;
 
-  if (reg >= AARCH64_DWARF_V0 && reg <= AARCH64_DWARF_V0 + 31)
-    return AARCH64_V0_REGNUM + reg - AARCH64_DWARF_V0;
+  if (regnum >= AARCH64_V0_REGNUM && regnum <= AARCH64_V0_REGNUM + 31)
+    return AARCH64_DWARF_V0 + regnum - AARCH64_V0_REGNUM;
 
-  if (reg == AARCH64_DWARF_SVE_VG)
-    return AARCH64_SVE_VG_REGNUM;
+  if (regnum == AARCH64_SVE_VG_REGNUM)
+    return AARCH64_DWARF_SVE_VG;
 
-  if (reg == AARCH64_DWARF_SVE_FFR)
-    return AARCH64_SVE_FFR_REGNUM;
+  if (regnum == AARCH64_SVE_FFR_REGNUM)
+    return AARCH64_DWARF_SVE_FFR;
 
-  if (reg >= AARCH64_DWARF_SVE_P0 && reg <= AARCH64_DWARF_SVE_P0 + 15)
-    return AARCH64_SVE_P0_REGNUM + reg - AARCH64_DWARF_SVE_P0;
+  if (regnum >= AARCH64_SVE_P0_REGNUM && regnum <= AARCH64_SVE_P0_REGNUM + 15)
+    return AARCH64_DWARF_SVE_P0 + regnum - AARCH64_SVE_P0_REGNUM;
 
-  if (reg >= AARCH64_DWARF_SVE_Z0 && reg <= AARCH64_DWARF_SVE_Z0 + 15)
-    return AARCH64_SVE_Z0_REGNUM + reg - AARCH64_DWARF_SVE_Z0;
+  if (regnum >= AARCH64_SVE_Z0_REGNUM && regnum <= AARCH64_SVE_Z0_REGNUM + 15)
+    return AARCH64_DWARF_SVE_Z0 + regnum - AARCH64_SVE_Z0_REGNUM;
 
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
   if (tdep->has_pauth ())
     {
-      if (reg == AARCH64_DWARF_RA_SIGN_STATE)
-	return tdep->ra_sign_state_regnum;
+      if (regnum == tdep->ra_sign_state_regnum)
+	return AARCH64_DWARF_RA_SIGN_STATE;
     }
 
   return -1;
@@ -2994,7 +3010,7 @@ aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
   if (is_w_pseudo_register (gdbarch, regnum))
     return w_name[regnum - tdep->w_pseudo_base];
 
-  if (tdep->has_sve ())
+  if (tdep->has_sve)
     {
       static const char *const sve_v_name[] =
 	{
@@ -3050,7 +3066,7 @@ aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
   if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
     return aarch64_vnb_type (gdbarch);
 
-  if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM
+  if (tdep->has_sve && p_regnum >= AARCH64_SVE_V0_REGNUM
       && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
     return aarch64_vnv_type (gdbarch);
 
@@ -3090,7 +3106,7 @@ aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
     return group == all_reggroup || group == vector_reggroup;
   else if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32)
     return group == all_reggroup || group == vector_reggroup;
-  else if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM
+  else if (tdep->has_sve && p_regnum >= AARCH64_SVE_V0_REGNUM
 	   && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM)
     return group == all_reggroup || group == vector_reggroup;
   else if (is_sme_pseudo_register (gdbarch, regnum))
@@ -3285,7 +3301,7 @@ aarch64_pseudo_read_value (gdbarch *gdbarch, const frame_info_ptr &next_frame,
     return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
 					pseudo_offset - AARCH64_B0_REGNUM);
 
-  if (tdep->has_sve () && pseudo_offset >= AARCH64_SVE_V0_REGNUM
+  if (tdep->has_sve && pseudo_offset >= AARCH64_SVE_V0_REGNUM
       && pseudo_offset < AARCH64_SVE_V0_REGNUM + 32)
     return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num,
 					pseudo_offset - AARCH64_SVE_V0_REGNUM);
@@ -3425,7 +3441,7 @@ aarch64_pseudo_write (gdbarch *gdbarch, const frame_info_ptr &next_frame,
     return aarch64_pseudo_write_1 (gdbarch, next_frame,
 				   pseudo_offset - AARCH64_B0_REGNUM, buf);
 
-  if (tdep->has_sve () && pseudo_offset >= AARCH64_SVE_V0_REGNUM
+  if (tdep->has_sve && pseudo_offset >= AARCH64_SVE_V0_REGNUM
       && pseudo_offset < AARCH64_SVE_V0_REGNUM + 32)
     return aarch64_pseudo_write_1 (gdbarch, next_frame,
 				   pseudo_offset - AARCH64_SVE_V0_REGNUM, buf);
@@ -3941,10 +3957,6 @@ aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch)
 const target_desc *
 aarch64_read_description (const aarch64_features &features)
 {
-  if (features.vq > AARCH64_MAX_SVE_VQ)
-    error (_("VQ is %" PRIu64 ", maximum supported value is %d"), features.vq,
-	   AARCH64_MAX_SVE_VQ);
-
   struct target_desc *tdesc = tdesc_aarch64_map[features];
 
   if (tdesc == NULL)
@@ -3956,27 +3968,6 @@ aarch64_read_description (const aarch64_features &features)
   return tdesc;
 }
 
-/* Return the VQ used when creating the target description TDESC.  */
-
-static uint64_t
-aarch64_get_tdesc_vq (const struct target_desc *tdesc)
-{
-  const struct tdesc_feature *feature_sve;
-
-  if (!tdesc_has_registers (tdesc))
-    return 0;
-
-  feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
-
-  if (feature_sve == nullptr)
-    return 0;
-
-  uint64_t vl = tdesc_register_bitsize (feature_sve,
-					aarch64_sve_register_names[0]) / 8;
-  return sve_vq_from_vl (vl);
-}
-
-
 /* Return the svq (streaming vector quotient) used when creating the target
    description TDESC.  */
 
@@ -4013,7 +4004,8 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
   if (tdesc == nullptr)
     return features;
 
-  features.vq = aarch64_get_tdesc_vq (tdesc);
+  features.sve
+      = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve") != nullptr;
 
   /* We need to look for a couple pauth feature name variations.  */
   features.pauth
@@ -4358,13 +4350,11 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   int i, num_regs = 0, num_pseudo_regs = 0;
   int first_pauth_regnum = -1, ra_sign_state_offset = -1;
   int first_mte_regnum = -1, first_tls_regnum = -1;
-  uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
+  bool has_sve = (info.target_desc == nullptr ? false
+		  : tdesc_find_feature (info.target_desc,
+					"org.gnu.gdb.aarch64.sve") != nullptr);
   uint64_t svq = aarch64_get_tdesc_svq (info.target_desc);
 
-  if (vq > AARCH64_MAX_SVE_VQ)
-    internal_error (_("VQ out of bounds: %s (max %d)"),
-		    pulongest (vq), AARCH64_MAX_SVE_VQ);
-
   if (svq > AARCH64_MAX_SVE_VQ)
     internal_error (_("Streaming vector quotient (svq) out of bounds: %s"
 		      " (max %d)"),
@@ -4377,18 +4367,17 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     {
       aarch64_gdbarch_tdep *tdep
 	= gdbarch_tdep<aarch64_gdbarch_tdep> (best_arch->gdbarch);
-      if (tdep && tdep->vq == vq && tdep->sme_svq == svq)
+      if (tdep && tdep->has_sve == has_sve && tdep->sme_svq == svq)
 	return best_arch->gdbarch;
     }
 
   /* Ensure we always have a target descriptor, and that it is for the given VQ
      value.  */
   const struct target_desc *tdesc = info.target_desc;
-  if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc)
-      || svq != aarch64_get_tdesc_svq (tdesc))
+  if (!tdesc_has_registers (tdesc))
     {
       aarch64_features features;
-      features.vq = vq;
+      features.sve = has_sve;
       features.svq = svq;
       tdesc = aarch64_read_description (features);
     }
@@ -4603,7 +4592,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->vq = vq;
+  tdep->has_sve = feature_sve != nullptr;
   tdep->pauth_reg_base = first_pauth_regnum;
   tdep->pauth_reg_count = pauth_masks;
   tdep->ra_sign_state_regnum = -1;
@@ -4690,7 +4679,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_stack_frame_destroyed_p (gdbarch, aarch64_stack_frame_destroyed_p);
 
   /* Internal <-> external register number maps.  */
-  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, aarch64_dwarf_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, aarch64_tdep_dwarf_reg_to_regnum);
+  set_gdbarch_regnum_to_dwarf2_reg (gdbarch, aarch64_regnum_to_dwarf_reg);
 
   /* Returning results.  */
   set_gdbarch_return_value_as_value (gdbarch, aarch64_return_value);
@@ -4857,6 +4847,9 @@ aarch64_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
   gdb_printf (file, _("aarch64_dump_tdep: Lowest pc = 0x%s\n"),
 	      paddress (gdbarch, tdep->lowest_pc));
 
+  gdb_printf (file, _ ("aarch64_dump_tdep: has_sve = %s\n"),
+	      tdep->has_sve ? "true" : "false");
+
   /* SME fields.  */
   gdb_printf (file, _("aarch64_dump_tdep: sme_tile_type_q = %s\n"),
 	      host_address_to_string (tdep->sme_tile_type_q));
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 50166fb4f24f..c34027c7f387 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -31,17 +31,6 @@
 struct gdbarch;
 struct regset;
 
-/* AArch64 Dwarf register numbering.  */
-#define AARCH64_DWARF_X0   0
-#define AARCH64_DWARF_SP  31
-#define AARCH64_DWARF_PC  32
-#define AARCH64_DWARF_RA_SIGN_STATE  34
-#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
-
 /* Size of integer registers.  */
 #define X_REGISTER_SIZE  8
 #define B_REGISTER_SIZE  1
@@ -100,14 +89,8 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
   int (*aarch64_syscall_record) (struct regcache *regcache,
 				 unsigned long svc_number) = nullptr;
 
-  /* The VQ value for SVE targets, or zero if SVE is not supported.  */
-  uint64_t vq = 0;
-
-  /* Returns true if the target supports SVE.  */
-  bool has_sve () const
-  {
-    return vq != 0;
-  }
+  /* Whether SVE is supported.  */
+  bool has_sve = false;
 
   int pauth_reg_base = 0;
   /* Number of pauth masks.  */
diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
index 5526aa1b580b..aa246857a79f 100644
--- a/gdb/arch/aarch64.c
+++ b/gdb/arch/aarch64.c
@@ -42,10 +42,10 @@ aarch64_create_target_description (const aarch64_features &features)
 
   regnum = create_feature_aarch64_core (tdesc.get (), regnum);
 
-  if (features.vq == 0)
+  if (!features.sve)
     regnum = create_feature_aarch64_fpu (tdesc.get (), regnum);
   else
-    regnum = create_feature_aarch64_sve (tdesc.get (), regnum, features.vq);
+    regnum = create_feature_aarch64_sve (tdesc.get (), regnum);
 
   if (features.pauth)
     regnum = create_feature_aarch64_pauth (tdesc.get (), regnum);
@@ -98,3 +98,35 @@ aarch64_mask_from_pac_registers (const CORE_ADDR cmask, const CORE_ADDR dmask)
 
   return cmask;
 }
+
+/* See arch/aarch64.h.  */
+
+int
+aarch64_dwarf_reg_to_regnum (int reg)
+{
+  if (reg >= AARCH64_DWARF_X0 && reg <= AARCH64_DWARF_X0 + 30)
+    return AARCH64_X0_REGNUM + reg - AARCH64_DWARF_X0;
+
+  if (reg == AARCH64_DWARF_SP)
+    return AARCH64_SP_REGNUM;
+
+  if (reg == AARCH64_DWARF_PC)
+    return AARCH64_PC_REGNUM;
+
+  if (reg >= AARCH64_DWARF_V0 && reg <= AARCH64_DWARF_V0 + 31)
+    return AARCH64_V0_REGNUM + reg - AARCH64_DWARF_V0;
+
+  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;
+}
diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
index b4c0111aeb49..1857fd4802fb 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -26,12 +26,7 @@
    used to select register sets.  */
 struct aarch64_features
 {
-  /* A non zero VQ value indicates both the presence of SVE and the
-     Vector Quotient - the number of 128-bit chunks in an SVE Z
-     register.
-
-     The maximum value for VQ is 16 (5 bits).  */
-  uint64_t vq = 0;
+  bool sve = false;
   bool pauth = false;
   bool mte = false;
 
@@ -55,7 +50,7 @@ struct aarch64_features
 
 inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
 {
-  return lhs.vq == rhs.vq
+  return lhs.sve == rhs.sve
     && lhs.pauth == rhs.pauth
     && lhs.mte == rhs.mte
     && lhs.tls == rhs.tls
@@ -72,7 +67,7 @@ namespace std
     {
       std::size_t h;
 
-      h = features.vq;
+      h = features.sve;
       h = h << 1 | features.pauth;
       h = h << 1 | features.mte;
       /* Shift by two bits for now.  We may need to increase this in the future
@@ -107,6 +102,9 @@ CORE_ADDR aarch64_remove_top_bits (CORE_ADDR pointer, CORE_ADDR mask);
 CORE_ADDR
 aarch64_mask_from_pac_registers (const CORE_ADDR cmask, const CORE_ADDR dmask);
 
+/* Map DWARF reg number to GDB regnum.  */
+int aarch64_dwarf_reg_to_regnum (int reg);
+
 /* Register numbers of various important registers.
    Note that on SVE, the Z registers reuse the V register numbers and the V
    registers become pseudo registers.  */
@@ -136,6 +134,17 @@ enum aarch64_regnum
   AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
 };
 
+/* AArch64 Dwarf register numbering.  */
+#define AARCH64_DWARF_X0 0
+#define AARCH64_DWARF_SP 31
+#define AARCH64_DWARF_PC 32
+#define AARCH64_DWARF_RA_SIGN_STATE 34
+#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
+
 /* Sizes of various AArch64 registers.  */
 #define AARCH64_TLS_REGISTER_SIZE 8
 #define V_REGISTER_SIZE	  16
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 01b327cbce1f..f84debb4f15c 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -202,6 +202,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	aarch64-fpu.xml \
 	aarch64-pauth.xml \
 	aarch64-mte.xml \
+	aarch64-sve.xml \
 	arc/v1-core.xml \
 	arc/v1-aux.xml \
 	arc/v2-core.xml \
diff --git a/gdb/features/aarch64-sve.c b/gdb/features/aarch64-sve.c
index 67fc801ec70e..1bed5f402376 100644
--- a/gdb/features/aarch64-sve.c
+++ b/gdb/features/aarch64-sve.c
@@ -1,76 +1,86 @@
-/* Copyright (C) 2018-2024 Free Software Foundation, Inc.
-
-   This file is part of GDB.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: aarch64-sve.xml */
 
 #include "gdbsupport/tdesc.h"
-
-/* This function is NOT auto generated from xml.  Create the aarch64 with SVE
-   feature into RESULT, where SCALE is the number of 128 bit chunks in a Z
-   register.  */
+#include "dwarf2.h"
 
 static int
-create_feature_aarch64_sve (struct target_desc *result, long regnum,
-			    uint64_t scale)
+create_feature_aarch64_sve (struct target_desc *result, long regnum)
 {
   struct tdesc_feature *feature;
-  tdesc_type *element_type, *field_type;
-  tdesc_type_with_fields *type_with_fields;
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.sve");
-
+  tdesc_type *element_type;
   element_type = tdesc_named_type (feature, "uint128");
-  tdesc_create_vector (feature, "svevqu", element_type, scale);
+  gdb_byte svevq_count_locexpr[5];
+  svevq_count_locexpr[0] = DW_OP_bregx;
+  svevq_count_locexpr[1] = 46;
+  svevq_count_locexpr[2] = 0;
+  svevq_count_locexpr[3] = DW_OP_lit2;
+  svevq_count_locexpr[4] = DW_OP_div;
+  tdesc_create_vector (feature, "svevqu", element_type, svevq_count_locexpr);
 
   element_type = tdesc_named_type (feature, "int128");
-  tdesc_create_vector (feature, "svevqs", element_type, scale);
+  tdesc_create_vector (feature, "svevqs", element_type, svevq_count_locexpr);
 
   element_type = tdesc_named_type (feature, "ieee_double");
-  tdesc_create_vector (feature, "svevdf", element_type, 2 * scale);
+  gdb_byte svevd_count_locexpr[3];
+  svevd_count_locexpr[0] = DW_OP_bregx;
+  svevd_count_locexpr[1] = 46;
+  svevd_count_locexpr[2] = 0;
+  tdesc_create_vector (feature, "svevdf", element_type, svevd_count_locexpr);
 
   element_type = tdesc_named_type (feature, "uint64");
-  tdesc_create_vector (feature, "svevdu", element_type, 2 * scale);
+  tdesc_create_vector (feature, "svevdu", element_type, svevd_count_locexpr);
 
   element_type = tdesc_named_type (feature, "int64");
-  tdesc_create_vector (feature, "svevds", element_type, 2 * scale);
+  tdesc_create_vector (feature, "svevds", element_type, svevd_count_locexpr);
 
   element_type = tdesc_named_type (feature, "ieee_single");
-  tdesc_create_vector (feature, "svevsf", element_type, 4 * scale);
+  gdb_byte svevs_count_locexpr[5];
+  svevs_count_locexpr[0] = DW_OP_bregx;
+  svevs_count_locexpr[1] = 46;
+  svevs_count_locexpr[2] = 0;
+  svevs_count_locexpr[3] = DW_OP_lit2;
+  svevs_count_locexpr[4] = DW_OP_mul;
+  tdesc_create_vector (feature, "svevsf", element_type, svevs_count_locexpr);
 
   element_type = tdesc_named_type (feature, "uint32");
-  tdesc_create_vector (feature, "svevsu", element_type, 4 * scale);
+  tdesc_create_vector (feature, "svevsu", element_type, svevs_count_locexpr);
 
   element_type = tdesc_named_type (feature, "int32");
-  tdesc_create_vector (feature, "svevss", element_type, 4 * scale);
+  tdesc_create_vector (feature, "svevss", element_type, svevs_count_locexpr);
 
   element_type = tdesc_named_type (feature, "ieee_half");
-  tdesc_create_vector (feature, "svevhf", element_type, 8 * scale);
+  gdb_byte svevh_count_locexpr[5];
+  svevh_count_locexpr[0] = DW_OP_bregx;
+  svevh_count_locexpr[1] = 46;
+  svevh_count_locexpr[2] = 0;
+  svevh_count_locexpr[3] = DW_OP_lit4;
+  svevh_count_locexpr[4] = DW_OP_mul;
+  tdesc_create_vector (feature, "svevhf", element_type, svevh_count_locexpr);
 
   element_type = tdesc_named_type (feature, "uint16");
-  tdesc_create_vector (feature, "svevhu", element_type, 8 * scale);
+  tdesc_create_vector (feature, "svevhu", element_type, svevh_count_locexpr);
 
   element_type = tdesc_named_type (feature, "int16");
-  tdesc_create_vector (feature, "svevhs", element_type, 8 * scale);
+  tdesc_create_vector (feature, "svevhs", element_type, svevh_count_locexpr);
 
   element_type = tdesc_named_type (feature, "uint8");
-  tdesc_create_vector (feature, "svevbu", element_type, 16 * scale);
+  gdb_byte svevb_count_locexpr[5];
+  svevb_count_locexpr[0] = DW_OP_bregx;
+  svevb_count_locexpr[1] = 46;
+  svevb_count_locexpr[2] = 0;
+  svevb_count_locexpr[3] = DW_OP_lit8;
+  svevb_count_locexpr[4] = DW_OP_mul;
+  tdesc_create_vector (feature, "svevbu", element_type, svevb_count_locexpr);
 
   element_type = tdesc_named_type (feature, "int8");
-  tdesc_create_vector (feature, "svevbs", element_type, 16 * scale);
+  tdesc_create_vector (feature, "svevbs", element_type, svevb_count_locexpr);
 
+  tdesc_type_with_fields *type_with_fields;
   type_with_fields = tdesc_create_union (feature, "svevnq");
+  tdesc_type *field_type;
   field_type = tdesc_named_type (feature, "svevqu");
   tdesc_add_field (type_with_fields, "u", field_type);
   field_type = tdesc_named_type (feature, "svevqs");
@@ -118,10 +128,15 @@ create_feature_aarch64_sve (struct target_desc *result, long regnum,
   field_type = tdesc_named_type (feature, "svevnb");
   tdesc_add_field (type_with_fields, "b", field_type);
 
-  field_type = tdesc_named_type (feature, "uint8");
-  tdesc_create_vector (feature, "svep", field_type, 2 * scale);
+  element_type = tdesc_named_type (feature, "uint8");
+  gdb_byte svep_locexpr[5];
+  svep_locexpr[0] = DW_OP_bregx;
+  svep_locexpr[1] = 46;
+  svep_locexpr[2] = 0;
+  svep_locexpr[3] = DW_OP_lit4;
+  svep_locexpr[4] = DW_OP_mul;
+  tdesc_create_vector (feature, "svep", element_type, svep_locexpr);
 
-  /* FPSR register type */
   type_with_fields = tdesc_create_flags (feature, "fpsr_flags", 4);
   tdesc_add_flag (type_with_fields, 0, "IOC");
   tdesc_add_flag (type_with_fields, 1, "DZC");
@@ -135,7 +150,6 @@ create_feature_aarch64_sve (struct target_desc *result, long regnum,
   tdesc_add_flag (type_with_fields, 30, "Z");
   tdesc_add_flag (type_with_fields, 31, "N");
 
-  /* FPCR register type */
   type_with_fields = tdesc_create_flags (feature, "fpcr_flags", 4);
   tdesc_add_flag (type_with_fields, 0, "FIZ");
   tdesc_add_flag (type_with_fields, 1, "AH");
@@ -155,57 +169,58 @@ create_feature_aarch64_sve (struct target_desc *result, long regnum,
   tdesc_add_flag (type_with_fields, 25, "DN");
   tdesc_add_flag (type_with_fields, 26, "AHP");
 
-  tdesc_create_reg (feature, "z0", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z1", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z2", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z3", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z4", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z5", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z6", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z7", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z8", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z9", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z10", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z11", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z12", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z13", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z14", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z15", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z16", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z17", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z18", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z19", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z20", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z21", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z22", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z23", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z24", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z25", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z26", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z27", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z28", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z29", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z30", regnum++, 1, NULL, 128 * scale, "svev");
-  tdesc_create_reg (feature, "z31", regnum++, 1, NULL, 128 * scale, "svev");
+  regnum = 34;
+  tdesc_create_reg (feature, "z0", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z1", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z2", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z3", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z4", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z5", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z6", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z7", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z8", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z9", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z10", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z11", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z12", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z13", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z14", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z15", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z16", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z17", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z18", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z19", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z20", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z21", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z22", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z23", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z24", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z25", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z26", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z27", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z28", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z29", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z30", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
+  tdesc_create_reg (feature, "z31", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svev");
   tdesc_create_reg (feature, "fpsr", regnum++, 1, NULL, 32, "fpsr_flags");
   tdesc_create_reg (feature, "fpcr", regnum++, 1, NULL, 32, "fpcr_flags");
-  tdesc_create_reg (feature, "p0", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p1", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p2", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p3", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p4", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p5", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p6", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p7", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p8", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p9", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p10", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p11", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p12", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p13", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p14", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "p15", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "ffr", regnum++, 1, NULL, 16 * scale, "svep");
-  tdesc_create_reg (feature, "vg", regnum++, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "p0", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p1", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p2", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p3", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p4", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p5", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p6", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p7", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p8", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p9", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p10", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p11", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p12", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p13", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p14", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "p15", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "ffr", regnum++, 1, NULL, TDESC_REG_VARIABLE_SIZE, "svep");
+  tdesc_create_reg (feature, "vg", regnum++, 1, NULL, 64, "int", true);
   return regnum;
 }
diff --git a/gdb/features/aarch64-sve.xml b/gdb/features/aarch64-sve.xml
new file mode 100644
index 000000000000..b843012b7927
--- /dev/null
+++ b/gdb/features/aarch64-sve.xml
@@ -0,0 +1,217 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2024 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.aarch64.sve">
+  <architecture>aarch64</architecture>
+  <vector id="svevqu" type="uint128">
+    <count id="svevq_count">
+      <!-- How many 128-bit elements there are in a z register: $vg / 2  -->
+      <math>
+        <apply>
+          <divide/>
+          <ci>85</ci>
+          <cn>2</cn>
+        </apply>
+      </math>
+    </count>
+  </vector>
+  <vector id="svevqs" type="int128">
+    <count idref="svevq_count"/>
+  </vector>
+  <vector id="svevdf" type="ieee_double">
+    <count id="svevd_count">
+      <!-- How many 64-bit elements there are in a z register: $vg  -->
+      <math>
+        <ci>85</ci>
+      </math>
+    </count>
+  </vector>
+  <vector id="svevdu" type="uint64">
+    <count idref="svevd_count"/>
+  </vector>
+  <vector id="svevds" type="int64">
+    <count idref="svevd_count"/>
+  </vector>
+  <vector id="svevsf" type="ieee_single">
+    <count id="svevs_count">
+      <!-- How many 32-bit elements there are in a z register: $vg * 2 -->
+      <math>
+        <apply>
+          <times/>
+          <ci>85</ci>
+          <cn>2</cn>
+        </apply>
+      </math>
+    </count>
+  </vector>
+  <vector id="svevsu" type="uint32">
+    <count idref="svevs_count"/>
+  </vector>
+  <vector id="svevss" type="int32">
+    <count idref="svevs_count"/>
+  </vector>
+  <vector id="svevhf" type="ieee_half">
+    <count id="svevh_count">
+      <!-- How many 16-bit elements there are in a z register: $vg * 4 -->
+      <math>
+        <apply>
+          <times/>
+          <ci>85</ci>
+          <cn>4</cn>
+        </apply>
+      </math>
+    </count>
+  </vector>
+  <vector id="svevhu" type="uint16">
+    <count idref="svevh_count"/>
+  </vector>
+  <vector id="svevhs" type="int16">
+    <count idref="svevh_count"/>
+  </vector>
+  <vector id="svevbu" type="uint8">
+    <count id="svevb_count">
+      <!-- How many 8-bit elements there are in a z register: $vg * 8 -->
+      <math>
+        <apply>
+          <times/>
+          <ci>85</ci>
+          <cn>8</cn>
+        </apply>
+      </math>
+    </count>
+  </vector>
+  <vector id="svevbs" type="int8">
+    <count idref="svevb_count"/>
+  </vector>
+  <union id="svevnq">
+    <field name="u" type="svevqu"/>
+    <field name="s" type="svevqs"/>
+  </union>
+  <union id="svevnd">
+    <field name="f" type="svevdf"/>
+    <field name="u" type="svevdu"/>
+    <field name="s" type="svevds"/>
+  </union>
+  <union id="svevns">
+    <field name="f" type="svevsf"/>
+    <field name="u" type="svevsu"/>
+    <field name="s" type="svevss"/>
+  </union>
+  <union id="svevnh">
+    <field name="f" type="svevhf"/>
+    <field name="u" type="svevhu"/>
+    <field name="s" type="svevhs"/>
+  </union>
+  <union id="svevnb">
+    <field name="u" type="svevbu"/>
+    <field name="s" type="svevbs"/>
+  </union>
+  <union id="svev">
+    <field name="q" type="svevnq"/>
+    <field name="d" type="svevnd"/>
+    <field name="s" type="svevns"/>
+    <field name="h" type="svevnh"/>
+    <field name="b" type="svevnb"/>
+  </union>
+  <vector id="svep" type="uint8">
+    <count>
+      <!-- How many predicate elements there are in a p register: $vg * 4 -->
+      <math>
+        <apply>
+          <times/>
+          <ci>85</ci>
+          <cn>4</cn>
+        </apply>
+      </math>
+    </count>
+  </vector>
+  <flags id="fpsr_flags" size="4">
+    <field name="IOC" start="0" end="0" type="bool"/>
+    <field name="DZC" start="1" end="1" type="bool"/>
+    <field name="OFC" start="2" end="2" type="bool"/>
+    <field name="UFC" start="3" end="3" type="bool"/>
+    <field name="IXC" start="4" end="4" type="bool"/>
+    <field name="IDC" start="7" end="7" type="bool"/>
+    <field name="QC" start="27" end="27" type="bool"/>
+    <field name="V" start="28" end="28" type="bool"/>
+    <field name="C" start="29" end="29" type="bool"/>
+    <field name="Z" start="30" end="30" type="bool"/>
+    <field name="N" start="31" end="31" type="bool"/>
+  </flags>
+  <flags id="fpcr_flags" size="4">
+    <field name="FIZ" start="0" end="0" type="bool"/>
+    <field name="AH" start="1" end="1" type="bool"/>
+    <field name="NEP" start="2" end="2" type="bool"/>
+    <field name="IOE" start="8" end="8" type="bool"/>
+    <field name="DZE" start="9" end="9" type="bool"/>
+    <field name="OFE" start="10" end="10" type="bool"/>
+    <field name="UFE" start="11" end="11" type="bool"/>
+    <field name="IXE" start="12" end="12" type="bool"/>
+    <field name="EBF" start="13" end="13" type="bool"/>
+    <field name="IDE" start="15" end="15" type="bool"/>
+    <field name="Len" start="16" end="18" type="uint32"/>
+    <field name="FZ16" start="19" end="19" type="bool"/>
+    <field name="Stride" start="20" end="21" type="uint32"/>
+    <field name="RMode" start="22" end="23" type="uint32"/>
+    <field name="FZ" start="24" end="24" type="bool"/>
+    <field name="DN" start="25" end="25" type="bool"/>
+    <field name="AHP" start="26" end="26" type="bool"/>
+  </flags>
+  <reg name="z0" bitsize="-1" type="svev" regnum="34"/>
+  <reg name="z1" bitsize="-1" type="svev" regnum="35"/>
+  <reg name="z2" bitsize="-1" type="svev" regnum="36"/>
+  <reg name="z3" bitsize="-1" type="svev" regnum="37"/>
+  <reg name="z4" bitsize="-1" type="svev" regnum="38"/>
+  <reg name="z5" bitsize="-1" type="svev" regnum="39"/>
+  <reg name="z6" bitsize="-1" type="svev" regnum="40"/>
+  <reg name="z7" bitsize="-1" type="svev" regnum="41"/>
+  <reg name="z8" bitsize="-1" type="svev" regnum="42"/>
+  <reg name="z9" bitsize="-1" type="svev" regnum="43"/>
+  <reg name="z10" bitsize="-1" type="svev" regnum="44"/>
+  <reg name="z11" bitsize="-1" type="svev" regnum="45"/>
+  <reg name="z12" bitsize="-1" type="svev" regnum="46"/>
+  <reg name="z13" bitsize="-1" type="svev" regnum="47"/>
+  <reg name="z14" bitsize="-1" type="svev" regnum="48"/>
+  <reg name="z15" bitsize="-1" type="svev" regnum="49"/>
+  <reg name="z16" bitsize="-1" type="svev" regnum="50"/>
+  <reg name="z17" bitsize="-1" type="svev" regnum="51"/>
+  <reg name="z18" bitsize="-1" type="svev" regnum="52"/>
+  <reg name="z19" bitsize="-1" type="svev" regnum="53"/>
+  <reg name="z20" bitsize="-1" type="svev" regnum="54"/>
+  <reg name="z21" bitsize="-1" type="svev" regnum="55"/>
+  <reg name="z22" bitsize="-1" type="svev" regnum="56"/>
+  <reg name="z23" bitsize="-1" type="svev" regnum="57"/>
+  <reg name="z24" bitsize="-1" type="svev" regnum="58"/>
+  <reg name="z25" bitsize="-1" type="svev" regnum="59"/>
+  <reg name="z26" bitsize="-1" type="svev" regnum="60"/>
+  <reg name="z27" bitsize="-1" type="svev" regnum="61"/>
+  <reg name="z28" bitsize="-1" type="svev" regnum="62"/>
+  <reg name="z29" bitsize="-1" type="svev" regnum="63"/>
+  <reg name="z30" bitsize="-1" type="svev" regnum="64"/>
+  <reg name="z31" bitsize="-1" type="svev" regnum="65"/>
+  <reg name="fpsr" bitsize="32" type="fpsr_flags" regnum="66"/>
+  <reg name="fpcr" bitsize="32" type="fpcr_flags" regnum="67"/>
+  <reg name="p0" bitsize="-1" type="svep" regnum="68"/>
+  <reg name="p1" bitsize="-1" type="svep" regnum="69"/>
+  <reg name="p2" bitsize="-1" type="svep" regnum="70"/>
+  <reg name="p3" bitsize="-1" type="svep" regnum="71"/>
+  <reg name="p4" bitsize="-1" type="svep" regnum="72"/>
+  <reg name="p5" bitsize="-1" type="svep" regnum="73"/>
+  <reg name="p6" bitsize="-1" type="svep" regnum="74"/>
+  <reg name="p7" bitsize="-1" type="svep" regnum="75"/>
+  <reg name="p8" bitsize="-1" type="svep" regnum="76"/>
+  <reg name="p9" bitsize="-1" type="svep" regnum="77"/>
+  <reg name="p10" bitsize="-1" type="svep" regnum="78"/>
+  <reg name="p11" bitsize="-1" type="svep" regnum="79"/>
+  <reg name="p12" bitsize="-1" type="svep" regnum="80"/>
+  <reg name="p13" bitsize="-1" type="svep" regnum="81"/>
+  <reg name="p14" bitsize="-1" type="svep" regnum="82"/>
+  <reg name="p15" bitsize="-1" type="svep" regnum="83"/>
+  <reg name="ffr" bitsize="-1" type="svep" regnum="84"/>
+  <reg name="vg" bitsize="64" type="int" regnum="85"/>
+</feature>
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
index 95359137f4f4..62de58d0c013 100644
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -57,6 +57,7 @@ case "${gdbserver_host}" in
 			srv_tgtobj="${srv_tgtobj} $srv_linux_obj"
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
+                        srv_dwarf_reg_to_regnum=yes
 			ipa_obj="linux-aarch64-ipa.o"
 			ipa_obj="${ipa_obj} linux-aarch64-tdesc-ipa.o"
 			ipa_obj="${ipa_obj} arch/aarch64-ipa.o"
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 998ad0a9d658..13c891d282ba 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -884,11 +884,11 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
 	  break;
 	case NT_FPREGSET:
 	  /* This is unavailable when SVE is present.  */
-	  if (features.vq == 0)
+	  if (!features.sve)
 	    regset->size = sizeof (struct user_fpsimd_state);
 	  break;
 	case NT_ARM_SVE:
-	  if (features.vq > 0)
+	  if (features.sve)
 	    regset->size = SVE_PT_SIZE (AARCH64_MAX_SVE_VQ, SVE_PT_REGS_SVE);
 	  break;
 	case NT_ARM_PAC_MASK:
@@ -938,7 +938,7 @@ aarch64_target::low_arch_setup ()
       struct aarch64_features features;
       int pid = current_thread->id.pid ();
 
-      features.vq = aarch64_sve_get_vq (tid);
+      features.sve = aarch64_sve_get_vq (tid) != 0;
       /* A-profile PAC is 64-bit only.  */
       features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA;
       /* A-profile MTE is 64-bit only.  */
diff --git a/gdbserver/linux-aarch64-tdesc.cc b/gdbserver/linux-aarch64-tdesc.cc
index 31ec7854cc0b..87f2a484ac32 100644
--- a/gdbserver/linux-aarch64-tdesc.cc
+++ b/gdbserver/linux-aarch64-tdesc.cc
@@ -37,10 +37,6 @@ aarch64_linux_read_description (const aarch64_features &features)
      initialised.  */
   static std::unordered_map<aarch64_features, target_desc *> tdesc_aarch64_map;
 
-  if (features.vq > AARCH64_MAX_SVE_VQ)
-    error (_("VQ is %" PRIu64 ", maximum supported value is %d"), features.vq,
-	   AARCH64_MAX_SVE_VQ);
-
   if (features.svq > AARCH64_MAX_SVE_VQ)
     error (_("Streaming svq is %" PRIu8 ", maximum supported value is %d"),
 	   features.svq,
@@ -60,8 +56,6 @@ aarch64_linux_read_description (const aarch64_features &features)
       expedited_registers.push_back ("sp");
       expedited_registers.push_back ("pc");
 
-      if (features.vq > 0)
-	expedited_registers.push_back ("vg");
       if (features.svq > 0)
 	expedited_registers.push_back ("svg");
 
@@ -74,3 +68,14 @@ aarch64_linux_read_description (const aarch64_features &features)
 
   return tdesc;
 }
+
+/* See gdbsupport/tdesc.h.  */
+
+int
+tdesc_dwarf_reg_to_regnum (const char *arch, int dwarf_reg)
+{
+  if (!strcmp (arch, "aarch64"))
+    return aarch64_dwarf_reg_to_regnum (dwarf_reg);
+
+  return -1;
+}
