diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp
new file mode 100644
index 00000000000..c4755346bc8
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 0
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp
new file mode 100644
index 00000000000..6461c47d6b5
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 25
+set id_end 49
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp
new file mode 100644
index 00000000000..e5bf5bf2b84
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 50
+set id_end 74
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp
new file mode 100644
index 00000000000..1846c83a63c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 75
+set id_end 99
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp
new file mode 100644
index 00000000000..45e69fa8ad5
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 100
+set id_end 124
+source $srcdir/$subdir/aarch64-sme-core.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core.c b/gdb/testsuite/gdb.arch/aarch64-sme-core.c
new file mode 100644
index 00000000000..7d4284b80c8
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core.c
@@ -0,0 +1,361 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Exercise AArch64's Scalable Vector/Matrix Extension core file generation
+   for GDB.  This includes reading Linux Kernel-generated core files and
+   writing GDB core files via the gcore command and making sure the contents
+   are sane.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static void
+enable_sm ()
+{
+  /* smstart sm */
+  __asm __volatile (".word 0xD503437F");
+}
+
+static void
+disable_sm ()
+{
+  /* smstop sm */
+  __asm __volatile (".word 0xD503427F");
+}
+
+static void
+initialize_fpsimd_state ()
+{
+  char buffer[16];
+
+  for (int i = 0; i < 16; i++)
+    buffer[i] = 0x55;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+		    : : "r" (buffer));
+
+  __asm __volatile ("ldr q0, [x0]");
+  __asm __volatile ("ldr q1, [x0]");
+  __asm __volatile ("ldr q2, [x0]");
+  __asm __volatile ("ldr q3, [x0]");
+  __asm __volatile ("ldr q4, [x0]");
+  __asm __volatile ("ldr q5, [x0]");
+  __asm __volatile ("ldr q6, [x0]");
+  __asm __volatile ("ldr q7, [x0]");
+  __asm __volatile ("ldr q8, [x0]");
+  __asm __volatile ("ldr q9, [x0]");
+  __asm __volatile ("ldr q10, [x0]");
+  __asm __volatile ("ldr q11, [x0]");
+  __asm __volatile ("ldr q12, [x0]");
+  __asm __volatile ("ldr q13, [x0]");
+  __asm __volatile ("ldr q14, [x0]");
+  __asm __volatile ("ldr q15, [x0]");
+  __asm __volatile ("ldr q16, [x0]");
+  __asm __volatile ("ldr q17, [x0]");
+  __asm __volatile ("ldr q18, [x0]");
+  __asm __volatile ("ldr q19, [x0]");
+  __asm __volatile ("ldr q20, [x0]");
+  __asm __volatile ("ldr q21, [x0]");
+  __asm __volatile ("ldr q22, [x0]");
+  __asm __volatile ("ldr q23, [x0]");
+  __asm __volatile ("ldr q24, [x0]");
+  __asm __volatile ("ldr q25, [x0]");
+  __asm __volatile ("ldr q26, [x0]");
+  __asm __volatile ("ldr q27, [x0]");
+  __asm __volatile ("ldr q28, [x0]");
+  __asm __volatile ("ldr q29, [x0]");
+  __asm __volatile ("ldr q30, [x0]");
+  __asm __volatile ("ldr q31, [x0]");
+}
+
+static void
+initialize_za_state ()
+{
+  /* zero za */
+  __asm __volatile (".word 0xC00800FF");
+
+  char buffer[256];
+
+  for (int i = 0; i < 256; i++)
+    buffer[i] = 0xaa;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+		    : : "r" (buffer));
+
+  /* Initialize loop boundaries.  */
+  __asm __volatile ("mov w12, 0");
+  __asm __volatile ("mov w17, 256");
+
+  /* loop: ldr za[w12, 0], [x0] */
+  __asm __volatile ("loop: .word 0xe1000000");
+  __asm __volatile ("add w12, w12, 1");
+  __asm __volatile ("cmp w12, w17");
+  __asm __volatile ("bne loop");
+}
+
+static void
+initialize_sve_state ()
+{
+  __asm __volatile ("dup z0.b, -1");
+  __asm __volatile ("dup z1.b, -1");
+  __asm __volatile ("dup z2.b, -1");
+  __asm __volatile ("dup z3.b, -1");
+  __asm __volatile ("dup z4.b, -1");
+  __asm __volatile ("dup z5.b, -1");
+  __asm __volatile ("dup z6.b, -1");
+  __asm __volatile ("dup z7.b, -1");
+  __asm __volatile ("dup z8.b, -1");
+  __asm __volatile ("dup z9.b, -1");
+  __asm __volatile ("dup z10.b, -1");
+  __asm __volatile ("dup z11.b, -1");
+  __asm __volatile ("dup z12.b, -1");
+  __asm __volatile ("dup z13.b, -1");
+  __asm __volatile ("dup z14.b, -1");
+  __asm __volatile ("dup z15.b, -1");
+  __asm __volatile ("dup z16.b, -1");
+  __asm __volatile ("dup z17.b, -1");
+  __asm __volatile ("dup z18.b, -1");
+  __asm __volatile ("dup z19.b, -1");
+  __asm __volatile ("dup z20.b, -1");
+  __asm __volatile ("dup z21.b, -1");
+  __asm __volatile ("dup z22.b, -1");
+  __asm __volatile ("dup z23.b, -1");
+  __asm __volatile ("dup z24.b, -1");
+  __asm __volatile ("dup z25.b, -1");
+  __asm __volatile ("dup z26.b, -1");
+  __asm __volatile ("dup z27.b, -1");
+  __asm __volatile ("dup z28.b, -1");
+  __asm __volatile ("dup z29.b, -1");
+  __asm __volatile ("dup z30.b, -1");
+  __asm __volatile ("dup z31.b, -1");
+  __asm __volatile ("ptrue p0.b");
+  __asm __volatile ("ptrue p1.b");
+  __asm __volatile ("ptrue p2.b");
+  __asm __volatile ("ptrue p3.b");
+  __asm __volatile ("ptrue p4.b");
+  __asm __volatile ("ptrue p5.b");
+  __asm __volatile ("ptrue p6.b");
+  __asm __volatile ("ptrue p7.b");
+  __asm __volatile ("ptrue p8.b");
+  __asm __volatile ("ptrue p9.b");
+  __asm __volatile ("ptrue p10.b");
+  __asm __volatile ("ptrue p11.b");
+  __asm __volatile ("ptrue p12.b");
+  __asm __volatile ("ptrue p13.b");
+  __asm __volatile ("ptrue p14.b");
+  __asm __volatile ("ptrue p15.b");
+  __asm __volatile ("setffr");
+}
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+/* Enable register states based on STATE.
+
+   0 - FPSIMD
+   1 - SVE
+   2 - SSVE
+   3 - ZA
+   4 - ZA and SSVE.  */
+
+void enable_states (int state)
+{
+  disable_za ();
+  disable_sm ();
+  initialize_fpsimd_state ();
+
+  if (state == 1)
+    {
+      initialize_sve_state ();
+    }
+  else if (state == 2)
+    {
+      enable_sm ();
+      initialize_sve_state ();
+    }
+  else if (state == 3)
+    {
+      enable_za ();
+      initialize_za_state ();
+    }
+  else if (state == 4)
+    {
+      enable_za ();
+      enable_sm ();
+      initialize_sve_state ();
+      initialize_za_state ();
+    }
+
+  return;
+}
+
+static int
+test_id_to_state (int id)
+{
+  return id / 25;
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (argc > 2)
+    printf ("Incorrect number of arguments passed to test.\n");
+
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      long test_id = 0;
+
+      /* If we have a test id passed as argument, read it now.  */
+      if (argc == 2)
+	test_id = strtol (argv[1], NULL, 0);
+
+      dummy (); /* stop to initialize test_id */
+
+      int state = test_id_to_state (test_id);
+      int vl = test_id_to_vl (test_id);
+      int svl = test_id_to_svl (test_id);
+
+      if (set_vl_size (vl) == -1)
+	return -1;
+      if (set_svl_size (svl) == -1)
+	return -1;
+
+      enable_states (state);
+
+      char *p = 0x0;
+      *p = 0xff; /* crash point */
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl
new file mode 100644
index 00000000000..1fc325d4df7
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl
@@ -0,0 +1,167 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# 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/>.
+#
+# Exercise core file reading/writing in the presence of SME support.
+# This test exercises GDB's dumping/loading capability for Linux
+# Kernel core files and for gcore core files.
+
+load_lib aarch64.exp
+
+#
+# Validate that CORE_FILENAME can be read correctly and that the register
+# state is sane.
+#
+proc check_sme_core_file { core_filename state vl svl } {
+    # Load the core file.
+    if [gdb_test "core $core_filename" \
+	[multi_line \
+	    "Core was generated by.*\." \
+	    "Program terminated with signal SIGSEGV, Segmentation fault\." \
+	    "#0  ${::hex} in main \\(.*\\) at .*" \
+	    ".*p = 0xff;.* crash point .*"] \
+	    "load core file"] {
+	untested "failed to generate core file"
+	return -1
+    }
+
+    check_state $state $vl $svl
+
+    # Check the value of TPIDR2 in the core file.
+    gdb_test "print/x \$tpidr2" " = 0x1f2f3f4f5f6f7f8f" "tpidr2 contents from core file"
+}
+
+#
+# Generate two core files for EXECUTABLE, BINFILE with a test id of ID.
+# STATE is the register state, VL is the SVE vector length and SVL is the
+# SME vector length.
+# One of the core files is generated by the kernel and the other by the
+# gcore command.
+#
+proc generate_sme_core_files { executable binfile id state vl svl} {
+    # Run the program until the point where we need to adjust the
+    # test id.
+    set init_breakpoint "stop to initialize test_id"
+    gdb_breakpoint [gdb_get_line_number $init_breakpoint]
+    gdb_continue_to_breakpoint $init_breakpoint
+    gdb_test_no_output "set test_id = $id"
+
+    # Run the program until just before the crash.
+    set crash_breakpoint "crash point"
+    gdb_breakpoint [gdb_get_line_number $crash_breakpoint]
+    gdb_continue_to_breakpoint $crash_breakpoint
+    gdb_test_no_output "set print repeats 1" "adjust repeat count pre-crash"
+
+    # Adjust the register to custom values that we will check later when
+    # loading the core files.
+    check_state $state $vl $svl
+
+    # Modify tpidr2 so we can validate its value is properly dumped to the
+    # core files.
+    gdb_test_no_output "set \$tpidr2 = 0x1f2f3f4f5f6f7f8f"
+
+    # Continue until a crash.
+    gdb_test "continue" \
+	[multi_line \
+	    "Program received signal SIGSEGV, Segmentation fault\." \
+	    "${::hex} in main \\(.*\\) at .*" \
+	    ".*p = 0xff;.* crash point .*"] \
+	    "run to crash"
+
+    # Generate the gcore core file.
+    set gcore_filename [standard_output_file "${executable}-${id}-${state}-${vl}-${svl}.gcore"]
+    set gcore_generated [gdb_gcore_cmd "$gcore_filename" "generate gcore file"]
+
+    # Continue until the end.
+    gdb_test "continue" "Program terminated with signal SIGSEGV.*" \
+	     "program terminated with SIGSEGV"
+
+    # Generate a native core file.
+    set core_filename [core_find ${binfile} {} $id]
+    set core_generated [expr {$core_filename != ""}]
+    set native_core_name "${binfile}-${id}-${state}-${vl}-${svl}.core"
+    remote_exec build "mv $core_filename ${native_core_name}"
+    set core_filename ${native_core_name}
+
+    # At this point we have a couple core files, the gcore one generated by GDB
+    # and the native one generated by the Linux Kernel.  Make sure GDB can read
+    # both correctly.
+    if {$gcore_generated} {
+	clean_restart ${binfile}
+	gdb_test_no_output "set print repeats 1" \
+	    "adjust repeat count post-crash gcore"
+
+	with_test_prefix "gcore corefile" {
+	    check_sme_core_file $gcore_filename $state $vl $svl
+	}
+    } else {
+	fail "gcore corefile not generated"
+    }
+
+    if {$core_generated} {
+	clean_restart ${binfile}
+
+	gdb_test_no_output "set print repeats 1" \
+	    "adjust repeat count post-crash native core"
+
+	with_test_prefix "native corefile" {
+	    check_sme_core_file $core_filename $state $vl $svl
+	}
+    } else {
+	untested "native corefile not generated"
+    }
+}
+
+#
+# Exercise core file reading (kernel-generated core files) and writing
+# (gcore command) for test id's ID_START through ID_END.
+#
+proc test_sme_core_file { id_start id_end } {
+    set compile_flags {"debug" "macros" "additional_flags=-march=armv8.5-a+sve"}
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-core.c
+    set executable "${::testfile}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+	return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+	set state [test_id_to_state $id]
+	set vl [test_id_to_vl $id]
+	set svl [test_id_to_svl $id]
+
+	with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+	    if ![runto_main] {
+		untested "could not run to main"
+		return -1
+	    }
+
+	    generate_sme_core_files ${executable} ${binfile} $id $state $vl $svl
+	}
+    }
+}
+
+require is_aarch64_target
+
+if {![allow_aarch64_sve_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+if {![allow_aarch64_sme_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+test_sme_core_file $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp
new file mode 100644
index 00000000000..b264170c56a
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 0
+set id_end 4
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp
new file mode 100644
index 00000000000..ac48aa905bc
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 5
+set id_end 9
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp
new file mode 100644
index 00000000000..0e8f3e311ee
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 10
+set id_end 14
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp
new file mode 100644
index 00000000000..fabb24c5aad
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 14
+set id_end 19
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp
new file mode 100644
index 00000000000..5abeabb74c4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 20
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-regs-available.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c
new file mode 100644
index 00000000000..bf27356908f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c
@@ -0,0 +1,184 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Exercise various cases of reading/writing ZA contents for AArch64's
+   Scalable Matrix Extension.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      int id_start = ID_START;
+      int id_end = ID_END;
+
+      for (int id = id_start; id <= id_end; id++)
+	{
+	  int vl = test_id_to_vl (id);
+	  int svl = test_id_to_svl (id);
+
+	  if (set_vl_size (vl) == -1)
+	    return -1;
+	  if (set_svl_size (svl) == -1)
+	    return -1;
+
+	  enable_za ();
+	  dummy (); /* stop 1 */
+	}
+
+      for (int id = id_start; id <= id_end; id++)
+	{
+	  int vl = test_id_to_vl (id);
+	  int svl = test_id_to_svl (id);
+
+	  /* Make sure the vl/svl is something other than what gdb is about
+	     to set them to.  */
+	  if (set_vl_size (vl == 16? 32 : vl) == -1)
+	    return -1;
+	  if (set_svl_size (svl == 16? 32 : svl) == -1)
+	    return -1;
+
+	  disable_za ();
+	  dummy (); /* stop 2 */
+	}
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl
new file mode 100644
index 00000000000..19131819273
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl
@@ -0,0 +1,194 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Exercise reading/writing ZA registers when there is ZA state.
+
+load_lib aarch64.exp
+
+#
+# Cycle through all ZA registers and pseudo-registers and validate that their
+# contents are available for vector length SVL.
+#
+# Make sure reading/writing to ZA registers work as expected.
+#
+proc check_regs { mode vl svl } {
+    # Check VG to make sure it is correct
+    set expected_vg [expr $vl / 8]
+    gdb_test "print \$vg" "= ${expected_vg}"
+
+    # Check SVG to make sure it is correct
+    set expected_svg [expr $svl / 8]
+    gdb_test "print \$svg" "= ${expected_svg}"
+
+    # If svl is adjusted by prctl, we will have ZA enabled.  If gdb is
+    # adjusting svl, ZA will not be enabled by default.  It will only be
+    # enabled when ZA is written to.
+    set za_state "= \\\[ ZA \\\]"
+    if {$mode == "gdb"} {
+	set za_state "= \\\[ \\\]"
+    }
+
+    # Check SVCR.
+    if [gdb_test "print \$svcr" $za_state "svcr before assignments" ] {
+	fail "incorrect za state"
+	return -1
+    }
+
+    # Check the size of ZA.
+    set expected_za_size [expr $svl * $svl]
+    gdb_test "print sizeof \$za" " = $expected_za_size"
+
+    # Check the size of Z0.
+    gdb_test "print sizeof \$z0" " = $vl"
+
+    # Exercise reading/writing from/to ZA.
+    initialize_2d_array "\$za" 255 $svl $svl
+    set pattern [string_to_regexp [2d_array_value_pattern 255 $svl $svl]]
+    gdb_test "print \$za" " = $pattern" "read back from za"
+
+    # Exercise reading/writing from/to the tile pseudo-registers.
+    set last_tile 1
+    set expected_size [expr $svl * $svl]
+    set tile_svl $svl
+    set za_state "= \\\[ ZA \\\]"
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+	for {set tile 0} {$tile < $last_tile} {incr tile} {
+	    set register_name "\$za${tile}${granularity}"
+
+	    # Test the size.
+	    gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+
+	    # Test reading/writing
+	    initialize_2d_array $register_name 255 $tile_svl $tile_svl
+
+	    # Make sure we have ZA state.
+	    if [gdb_test "print \$svcr" $za_state "svcr after assignment to ${register_name}" ] {
+		fail "incorrect za state"
+		return -1
+	    }
+
+	    set pattern [string_to_regexp [2d_array_value_pattern 255 $tile_svl $tile_svl]]
+	    gdb_test "print $register_name" " = $pattern" "read back from $register_name"
+	}
+	set last_tile [expr $last_tile * 2]
+	set expected_size [expr $expected_size / 2]
+	set tile_svl [expr $tile_svl / 2]
+    }
+
+    # Exercise reading/writing from/to the tile slice pseudo-registers.
+    set last_tile 1
+    set last_slice $svl
+    set expected_size $svl
+    set num_elements $svl
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+	for {set tile 0} {$tile < $last_tile} {incr tile} {
+	    for {set slice 0} {$slice < $last_slice} {incr slice} {
+		foreach_with_prefix direction {"h" "v"} {
+		    set register_name "\$za${tile}${direction}${granularity}${slice}"
+
+		    # Test the size.
+		    gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+
+		    # Test reading/writing
+		    initialize_1d_array $register_name 255 $num_elements
+
+		    # Make sure we have ZA state.
+		    if [gdb_test "print \$svcr" $za_state "svcr after assignment of ${register_name}" ] {
+			fail "incorrect za state"
+			return -1
+		    }
+
+		    set pattern [string_to_regexp [1d_array_value_pattern 255 $num_elements]]
+		    gdb_test "print $register_name" " = $pattern" "read back from $register_name"
+		}
+	    }
+	}
+	set last_tile [expr $last_tile * 2]
+	set last_slice [expr ($last_slice / 2)]
+	set num_elements [expr $num_elements / 2]
+    }
+}
+
+#
+# Cycle through all ZA registers and pseudo-registers and validate their
+# contents.
+#
+proc test_sme_registers_available { id_start id_end } {
+
+    set compile_flags {"debug" "macros"}
+    lappend compile_flags "additional_flags=-DID_START=${id_start}"
+    lappend compile_flags "additional_flags=-DID_END=${id_end}"
+
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-regs-available.c
+    set executable "${::testfile}-${id_start}-${id_end}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+	return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    if ![runto_main] {
+	untested "could not run to main"
+	return -1
+    }
+
+    gdb_test_no_output "set print repeats 1"
+
+    set prctl_breakpoint "stop 1"
+    gdb_breakpoint [gdb_get_line_number $prctl_breakpoint]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+	set vl [test_id_to_vl $id]
+	set svl [test_id_to_svl $id]
+	set mode "prctl"
+	with_test_prefix "$mode, vl=${vl} svl=${svl}" {
+	    # Run the program until it has adjusted svl.
+	    gdb_continue_to_breakpoint $prctl_breakpoint
+	    check_regs $mode $vl $svl
+	}
+    }
+
+    set non_prctl_breakpoint "stop 2"
+    gdb_breakpoint [gdb_get_line_number $non_prctl_breakpoint]
+    gdb_continue_to_breakpoint $non_prctl_breakpoint
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+	set vl [test_id_to_vl $id]
+	set svl [test_id_to_svl $id]
+	set mode "gdb"
+	with_test_prefix "$mode, vl=${vl} svl=${svl}" {
+	    # Adjust svl via gdb.
+	    set vg_value [expr $vl / 8]
+	    set svg_value [expr $svl / 8]
+	    gdb_test_no_output "set \$vg = ${vg_value}"
+	    gdb_test_no_output "set \$svg = ${svg_value}"
+
+	    check_regs $mode $vl $svl
+	}
+    }
+}
+
+require is_aarch64_target
+
+if {![allow_aarch64_sve_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+if {![allow_aarch64_sme_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+test_sme_registers_available $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp
new file mode 100644
index 00000000000..00b29deed98
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 0
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp
new file mode 100644
index 00000000000..991efce4f25
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 25
+set id_end 49
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp
new file mode 100644
index 00000000000..5bd3cb80861
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 50
+set id_end 74
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp
new file mode 100644
index 00000000000..6e9cf9e929b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 75
+set id_end 99
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp
new file mode 100644
index 00000000000..0a9a11c30a2
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 100
+set id_end 124
+source $srcdir/$subdir/aarch64-sme-regs-sigframe.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c
new file mode 100644
index 00000000000..4d178ec01f6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c
@@ -0,0 +1,368 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Exercise AArch64's Scalable Vector/Matrix Extension signal frame handling
+   for GDB.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static int count = 0;
+
+static void
+handler (int sig)
+{
+  count++; /* handler */
+}
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static void
+enable_sm ()
+{
+  /* smstart sm */
+  __asm __volatile (".word 0xD503437F");
+}
+
+static void
+disable_sm ()
+{
+  /* smstop sm */
+  __asm __volatile (".word 0xD503427F");
+}
+
+static void
+initialize_fpsimd_state ()
+{
+  char buffer[16];
+
+  for (int i = 0; i < 16; i++)
+    buffer[i] = 0x55;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+		    : : "r" (buffer));
+
+  __asm __volatile ("ldr q0, [x0]");
+  __asm __volatile ("ldr q1, [x0]");
+  __asm __volatile ("ldr q2, [x0]");
+  __asm __volatile ("ldr q3, [x0]");
+  __asm __volatile ("ldr q4, [x0]");
+  __asm __volatile ("ldr q5, [x0]");
+  __asm __volatile ("ldr q6, [x0]");
+  __asm __volatile ("ldr q7, [x0]");
+  __asm __volatile ("ldr q8, [x0]");
+  __asm __volatile ("ldr q9, [x0]");
+  __asm __volatile ("ldr q10, [x0]");
+  __asm __volatile ("ldr q11, [x0]");
+  __asm __volatile ("ldr q12, [x0]");
+  __asm __volatile ("ldr q13, [x0]");
+  __asm __volatile ("ldr q14, [x0]");
+  __asm __volatile ("ldr q15, [x0]");
+  __asm __volatile ("ldr q16, [x0]");
+  __asm __volatile ("ldr q17, [x0]");
+  __asm __volatile ("ldr q18, [x0]");
+  __asm __volatile ("ldr q19, [x0]");
+  __asm __volatile ("ldr q20, [x0]");
+  __asm __volatile ("ldr q21, [x0]");
+  __asm __volatile ("ldr q22, [x0]");
+  __asm __volatile ("ldr q23, [x0]");
+  __asm __volatile ("ldr q24, [x0]");
+  __asm __volatile ("ldr q25, [x0]");
+  __asm __volatile ("ldr q26, [x0]");
+  __asm __volatile ("ldr q27, [x0]");
+  __asm __volatile ("ldr q28, [x0]");
+  __asm __volatile ("ldr q29, [x0]");
+  __asm __volatile ("ldr q30, [x0]");
+  __asm __volatile ("ldr q31, [x0]");
+}
+
+static void
+initialize_za_state ()
+{
+  /* zero za */
+  __asm __volatile (".word 0xC00800FF");
+
+  char buffer[256];
+
+  for (int i = 0; i < 256; i++)
+    buffer[i] = 0xaa;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+		    : : "r" (buffer));
+
+  /* Initialize loop boundaries.  */
+  __asm __volatile ("mov w12, 0");
+  __asm __volatile ("mov w17, 256");
+
+  /* loop: ldr za[w12, 0], [x0] */
+  __asm __volatile ("loop: .word 0xe1000000");
+  __asm __volatile ("add w12, w12, 1");
+  __asm __volatile ("cmp w12, w17");
+  __asm __volatile ("bne loop");
+}
+
+static void
+initialize_sve_state ()
+{
+  __asm __volatile ("dup z0.b, -1");
+  __asm __volatile ("dup z1.b, -1");
+  __asm __volatile ("dup z2.b, -1");
+  __asm __volatile ("dup z3.b, -1");
+  __asm __volatile ("dup z4.b, -1");
+  __asm __volatile ("dup z5.b, -1");
+  __asm __volatile ("dup z6.b, -1");
+  __asm __volatile ("dup z7.b, -1");
+  __asm __volatile ("dup z8.b, -1");
+  __asm __volatile ("dup z9.b, -1");
+  __asm __volatile ("dup z10.b, -1");
+  __asm __volatile ("dup z11.b, -1");
+  __asm __volatile ("dup z12.b, -1");
+  __asm __volatile ("dup z13.b, -1");
+  __asm __volatile ("dup z14.b, -1");
+  __asm __volatile ("dup z15.b, -1");
+  __asm __volatile ("dup z16.b, -1");
+  __asm __volatile ("dup z17.b, -1");
+  __asm __volatile ("dup z18.b, -1");
+  __asm __volatile ("dup z19.b, -1");
+  __asm __volatile ("dup z20.b, -1");
+  __asm __volatile ("dup z21.b, -1");
+  __asm __volatile ("dup z22.b, -1");
+  __asm __volatile ("dup z23.b, -1");
+  __asm __volatile ("dup z24.b, -1");
+  __asm __volatile ("dup z25.b, -1");
+  __asm __volatile ("dup z26.b, -1");
+  __asm __volatile ("dup z27.b, -1");
+  __asm __volatile ("dup z28.b, -1");
+  __asm __volatile ("dup z29.b, -1");
+  __asm __volatile ("dup z30.b, -1");
+  __asm __volatile ("dup z31.b, -1");
+  __asm __volatile ("ptrue p0.b");
+  __asm __volatile ("ptrue p1.b");
+  __asm __volatile ("ptrue p2.b");
+  __asm __volatile ("ptrue p3.b");
+  __asm __volatile ("ptrue p4.b");
+  __asm __volatile ("ptrue p5.b");
+  __asm __volatile ("ptrue p6.b");
+  __asm __volatile ("ptrue p7.b");
+  __asm __volatile ("ptrue p8.b");
+  __asm __volatile ("ptrue p9.b");
+  __asm __volatile ("ptrue p10.b");
+  __asm __volatile ("ptrue p11.b");
+  __asm __volatile ("ptrue p12.b");
+  __asm __volatile ("ptrue p13.b");
+  __asm __volatile ("ptrue p14.b");
+  __asm __volatile ("ptrue p15.b");
+  __asm __volatile ("setffr");
+}
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+/* Enable register states based on STATE.
+
+   0 - FPSIMD
+   1 - SVE
+   2 - SSVE
+   3 - ZA
+   4 - ZA and SSVE.  */
+
+void enable_states (int state)
+{
+  disable_za ();
+  disable_sm ();
+  initialize_fpsimd_state ();
+
+  if (state == 1)
+    {
+      initialize_sve_state ();
+    }
+  else if (state == 2)
+    {
+      enable_sm ();
+      initialize_sve_state ();
+    }
+  else if (state == 3)
+    {
+      enable_za ();
+      initialize_za_state ();
+    }
+  else if (state == 4)
+    {
+      enable_za ();
+      enable_sm ();
+      initialize_sve_state ();
+      initialize_za_state ();
+    }
+
+  return;
+}
+
+static int
+test_id_to_state (int id)
+{
+  return (id / 25);
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      int id_start = ID_START;
+      int id_end = ID_END;
+#ifdef SIGILL
+      signal (SIGILL, handler);
+#endif
+
+      int signal_count = 0;
+      for (int id = id_start; id <= id_end; id++)
+	{
+	  int state = test_id_to_state (id);
+	  int vl = test_id_to_vl (id);
+	  int svl = test_id_to_svl (id);
+
+	  if (set_vl_size (vl) == -1)
+	    return -1;
+	  if (set_svl_size (svl) == -1)
+	    return -1;
+
+	  signal_count++;
+	  enable_states (state);
+	  dummy (); /* stop before SIGILL */
+	  __asm __volatile (".word 0xDEADBEEF"); /* illegal instruction */
+	  while (signal_count != count);
+	}
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl
new file mode 100644
index 00000000000..4279cdc6d9b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl
@@ -0,0 +1,156 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Exercise restoring SME/TPIDR2 state from a signal frame.
+
+load_lib aarch64.exp
+
+#
+# Validate the state of registers in the signal frame for various states.
+#
+proc test_sme_registers_sigframe { id_start id_end } {
+
+    set compile_flags {"debug" "macros"}
+    lappend compile_flags "additional_flags=-march=armv8.5-a+sve"
+    lappend compile_flags "additional_flags=-DID_START=${id_start}"
+    lappend compile_flags "additional_flags=-DID_END=${id_end}"
+
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-regs-sigframe.c
+    set executable "${::testfile}-${id_start}-${id_end}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+	return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    if ![runto_main] {
+	untested "could not run to main"
+	return -1
+    }
+
+    set sigill_breakpoint "stop before SIGILL"
+    set handler_breakpoint "handler"
+    gdb_breakpoint [gdb_get_line_number $sigill_breakpoint]
+    gdb_breakpoint [gdb_get_line_number $handler_breakpoint]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+	set state [test_id_to_state $id]
+	set vl [test_id_to_vl $id]
+	set svl [test_id_to_svl $id]
+
+	with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+
+	    # Run the program until it has adjusted the svl.
+	    if [gdb_continue_to_breakpoint $sigill_breakpoint] {
+		return -1
+	    }
+
+	    # Check SVG to make sure it is correct
+	    set expected_svg [expr $svl / 8]
+	    gdb_test "print \$svg" "= ${expected_svg}"
+
+	    # Check the size of ZA.
+	    set expected_za_size [expr $svl * $svl]
+	    gdb_test "print sizeof \$za" " = $expected_za_size"
+
+	    # Check the value of SVCR.
+	    gdb_test "print \$svcr" [get_svcr_value $state] "svcr before signal"
+
+	    # Handle SME ZA initialization and state.
+	    set byte 0
+	    if { $state == "za" || $state == "za_ssve" } {
+		set byte 170
+	    }
+
+	    # Set the expected ZA pattern.
+	    set za_pattern [string_to_regexp [2d_array_value_pattern $byte $svl $svl]]
+
+	    # Handle SVE/SSVE initialization and state.
+	    set sve_vl $svl
+	    if { $state == "ssve" || $state == "za_ssve" } {
+		# SVE state comes from SSVE.
+		set sve_vl $svl
+	    } else {
+		# SVE state comes from regular SVE.
+		set sve_vl $vl
+	    }
+
+	    # Initialize the SVE state.
+	    set sve_pattern [string_to_regexp [sve_value_pattern $state $sve_vl 85 255]]
+	    for {set row 0} {$row < 32} {incr row} {
+		set register_name "\$z${row}\.b\.u"
+		gdb_test "print sizeof $register_name" " = $sve_vl" "size of $register_name"
+		gdb_test "print $register_name" $sve_pattern "read back from $register_name"
+	    }
+
+	    # Print ZA to check its value.
+	    gdb_test "print \$za" $za_pattern "read back from za"
+
+	    # Test TPIDR2 restore from signal frame as well.
+	    gdb_test_no_output "set \$tpidr2=0x0102030405060708"
+
+	    # Run to the illegal instruction.
+	    if [gdb_test "continue" "Continuing\.\r\n\r\nProgram received signal SIGILL, Illegal instruction\..*in main.*"] {
+		return
+	    }
+
+	    # Skip the illegal instruction.  The signal handler will be called after we continue.
+	    gdb_test_no_output "set \$pc=\$pc+4"
+	    # Continue to the signal handler.
+	    if [gdb_continue_to_breakpoint $handler_breakpoint] {
+		return -1
+	    }
+
+	    # Modify TPIDR2 so it is different from its value past the signal
+	    # frame.
+	    gdb_test_no_output "set \$tpidr2 = 0x0"
+
+	    # Select the frame that contains "main".
+	    gdb_test "frame 2" "#2.* main \\\(.*\\\) at.*"
+
+	    for {set row 0} {$row < 32} {incr row} {
+		set register_name "\$z${row}\.b\.u"
+		gdb_test "print sizeof $register_name" " = $sve_vl" "size of $register_name in the signal frame"
+		gdb_test "print $register_name" $sve_pattern "$register_name contents from signal frame"
+	    }
+
+	    # Check the size of ZA in the signal frame.
+	    set expected_za_size [expr $svl * $svl]
+	    gdb_test "print sizeof \$za" " = $expected_za_size" "size of za in signal frame"
+
+	    # Check the value of SVCR in the signal frame.
+	    gdb_test "print \$svcr" [get_svcr_value $state] "svcr from signal frame"
+
+	    # Check the value of ZA in the signal frame.
+	    gdb_test "print \$za" $za_pattern "za contents from signal frame"
+
+	    # Check the value of TPIDR2 in the signal frame.
+	    gdb_test "print/x \$tpidr2" " = 0x102030405060708" "tpidr2 contents from signal frame"
+	}
+    }
+}
+
+require is_aarch64_target
+
+if {![allow_aarch64_sve_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+if {![allow_aarch64_sme_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+test_sme_registers_sigframe $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp
new file mode 100644
index 00000000000..c758c4862be
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 0
+set id_end 3
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp
new file mode 100644
index 00000000000..10e27174067
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 11
+set id_end 15
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp
new file mode 100644
index 00000000000..c1e5e279231
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 16
+set id_end 19
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp
new file mode 100644
index 00000000000..cbe84dbff9a
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 20
+set id_end 22
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp
new file mode 100644
index 00000000000..f6f884cb910
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp
@@ -0,0 +1,18 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+set id_start 23
+set id_end 24
+source $srcdir/$subdir/aarch64-sme-regs-unavailable.exp.tcl
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c
new file mode 100644
index 00000000000..2dd72ffd5d4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c
@@ -0,0 +1,154 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Exercise various cases of ZA contents not being available for AArch64's
+   Scalable Matrix Extension.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+#ifndef PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+#ifndef PR_SME_SET_VL
+#define PR_SME_SET_VL 63
+#define PR_SME_GET_VL 64
+#define PR_SME_VL_LEN_MASK 0xffff
+#endif
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int get_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_GET_VL (%d)", res);
+      return -1;
+    }
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SVE_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int set_svl_size (int new_svl)
+{
+  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
+  if (res < 0)
+    {
+      printf ("FAILED to PR_SME_SET_VL (%d)", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)", res);
+      return -1;
+    }
+
+  return res;
+}
+
+static int
+test_id_to_vl (int id)
+{
+  return 16 << ((id / 5) % 5);
+}
+
+static int
+test_id_to_svl (int id)
+{
+  return 16 << (id % 5);
+}
+
+static void
+dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      int id_start = ID_START;
+      int id_end = ID_END;
+
+      for (int id = id_start; id <= id_end; id++)
+	{
+	  int vl = test_id_to_vl (id);
+	  int svl = test_id_to_svl (id);
+
+	  if (set_vl_size (vl) == -1)
+	    return -1;
+	  if (set_svl_size (svl) == -1)
+	    return -1;
+
+	  dummy (); /* stop 1 */
+	}
+
+      dummy (); /* stop 2 */
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl
new file mode 100644
index 00000000000..d515fe07b90
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl
@@ -0,0 +1,162 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Exercise the following:
+# - Printing ZA registers when there is no ZA state.
+# - Setting values of ZA registers when there is no ZA state.
+# - Validating ZA state is activated when we write to ZA registers.
+
+load_lib aarch64.exp
+
+#
+# Validate that the ZA registers have the expected state.
+#
+proc_with_prefix check_regs { vl svl } {
+    # Check VG to make sure it is correct
+    set expected_vg [expr $vl / 8]
+    gdb_test "print \$vg" "= ${expected_vg}"
+
+    # Check SVG to make sure it is correct
+    set expected_svg [expr $svl / 8]
+    gdb_test "print \$svg" "= ${expected_svg}"
+
+    # Make sure there is no SM or ZA state.
+    if [gdb_test "print \$svcr" "= \\\[ \\\]"] {
+	fail "incorrect ZA state"
+	return -1
+    }
+
+    # Check the size of ZA.
+    set expected_za_size [expr $svl * $svl]
+    gdb_test "print sizeof \$za" " = $expected_za_size"
+
+    # Check the size of Z0.
+    gdb_test "print sizeof \$z0" " = $vl"
+
+    # Set the expected ZA pattern.
+    set za_pattern [string_to_regexp [2d_array_value_pattern 0 $svl $svl]]
+
+    # Check ZA.
+    gdb_test "print \$za" $za_pattern
+
+    # Exercise reading/writing the tile slice pseudo-registers.
+    set last_tile 1
+    set last_slice $svl
+    set elements $svl
+    set expected_size $svl
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+	set pattern [string_to_regexp [1d_array_value_pattern 0 $elements]]
+	for {set tile 0} {$tile < $last_tile} {incr tile} {
+	    for {set slice 0} {$slice < $last_slice} {incr slice} {
+		foreach_with_prefix direction {"h" "v"} {
+		    set register_name "\$za${tile}${direction}${granularity}${slice}"
+		    # Test the size.
+		    gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+		    gdb_test "print ${register_name}" $pattern
+		}
+	    }
+	}
+	set last_tile [expr $last_tile * 2]
+	set last_slice [expr ($last_slice / 2)]
+	set elements [expr ($elements / 2)]
+    }
+
+    # Exercise reading/writing the tile pseudo-registers.
+    set last_tile 1
+    set elements $svl
+    set expected_size [expr $svl * $svl]
+    foreach_with_prefix granularity {"b" "h" "s" "d" "q"} {
+	set pattern [string_to_regexp [2d_array_value_pattern 0 $elements $elements]]
+	for {set tile 0} {$tile < $last_tile} {incr tile} {
+	    set register_name "\$za${tile}${granularity}"
+	    # Test the size.
+	    gdb_test "print sizeof ${register_name}" " = ${expected_size}"
+	    gdb_test "print ${register_name}" $pattern
+	}
+	set last_tile [expr $last_tile * 2]
+	set expected_size [expr $expected_size / 2]
+	set elements [expr ($elements / 2)]
+    }
+}
+
+#
+# Cycle through all ZA registers and pseudo-registers and validate that their
+# contents are unavailable (zeroed out) for vector length SVL.
+#
+proc test_sme_registers_unavailable { id_start id_end } {
+
+    set compile_flags {"debug" "macros"}
+    lappend compile_flags "additional_flags=-DID_START=${id_start}"
+    lappend compile_flags "additional_flags=-DID_END=${id_end}"
+
+    standard_testfile ${::srcdir}/${::subdir}/aarch64-sme-regs-unavailable.c
+    set executable "${::testfile}-${id_start}-${id_end}"
+    if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} {
+	return -1
+    }
+    set binfile [standard_output_file ${executable}]
+
+    if ![runto_main] {
+	untested "could not run to main"
+	return -1
+    }
+
+    gdb_test_no_output "set print repeats 1"
+
+    set prctl_breakpoint "stop 1"
+    gdb_breakpoint [gdb_get_line_number $prctl_breakpoint]
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+	set vl [test_id_to_vl $id]
+	set svl [test_id_to_svl $id]
+	with_test_prefix "prctl, vl=${vl} svl=${svl}" {
+	    # Run the program until it has adjusted svl.
+	    gdb_continue_to_breakpoint $prctl_breakpoint
+	    check_regs $vl $svl
+	}
+    }
+
+    set non_prctl_breakpoint "stop 2"
+    gdb_breakpoint [gdb_get_line_number $non_prctl_breakpoint]
+    gdb_continue_to_breakpoint $non_prctl_breakpoint
+
+    for {set id $id_start} {$id <= $id_end} {incr id} {
+	set vl [test_id_to_vl $id]
+	set svl [test_id_to_svl $id]
+	with_test_prefix "non prctl, vl=${vl} svl=${svl}" {
+	    # Adjust vg and svg.
+	    set vg_value [expr $vl / 8]
+	    set svg_value [expr $svl / 8]
+	    gdb_test_no_output "set \$vg = ${vg_value}"
+	    gdb_test_no_output "set \$svg = ${svg_value}"
+
+	    check_regs $vl $svl
+	}
+    }
+}
+
+require is_aarch64_target
+
+if {![allow_aarch64_sve_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+if {![allow_aarch64_sme_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+test_sme_registers_unavailable $id_start $id_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-sanity.c b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.c
new file mode 100644
index 00000000000..694de0626d2
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.c
@@ -0,0 +1,249 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2023 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Sanity test to exercise AArch64's Scalable Vector/Matrix Extension basic
+   functionality.  It cycles through different combinations of state and
+   initializes different register sets.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+
+static void
+enable_za ()
+{
+  /* smstart za */
+  __asm __volatile (".word 0xD503457F");
+}
+
+static void
+disable_za ()
+{
+  /* smstop za */
+  __asm __volatile (".word 0xD503447F");
+}
+
+static void
+enable_sm ()
+{
+  /* smstart sm */
+  __asm __volatile (".word 0xD503437F");
+}
+
+static void
+disable_sm ()
+{
+  /* smstop sm */
+  __asm __volatile (".word 0xD503427F");
+}
+
+static void
+initialize_fpsimd_state ()
+{
+  char buffer[16];
+
+  for (int i = 0; i < 16; i++)
+    buffer[i] = 0x55;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+		    : : "r" (buffer));
+
+  __asm __volatile ("ldr q0, [x0]");
+  __asm __volatile ("ldr q1, [x0]");
+  __asm __volatile ("ldr q2, [x0]");
+  __asm __volatile ("ldr q3, [x0]");
+  __asm __volatile ("ldr q4, [x0]");
+  __asm __volatile ("ldr q5, [x0]");
+  __asm __volatile ("ldr q6, [x0]");
+  __asm __volatile ("ldr q7, [x0]");
+  __asm __volatile ("ldr q8, [x0]");
+  __asm __volatile ("ldr q9, [x0]");
+  __asm __volatile ("ldr q10, [x0]");
+  __asm __volatile ("ldr q11, [x0]");
+  __asm __volatile ("ldr q12, [x0]");
+  __asm __volatile ("ldr q13, [x0]");
+  __asm __volatile ("ldr q14, [x0]");
+  __asm __volatile ("ldr q15, [x0]");
+  __asm __volatile ("ldr q16, [x0]");
+  __asm __volatile ("ldr q17, [x0]");
+  __asm __volatile ("ldr q18, [x0]");
+  __asm __volatile ("ldr q19, [x0]");
+  __asm __volatile ("ldr q20, [x0]");
+  __asm __volatile ("ldr q21, [x0]");
+  __asm __volatile ("ldr q22, [x0]");
+  __asm __volatile ("ldr q23, [x0]");
+  __asm __volatile ("ldr q24, [x0]");
+  __asm __volatile ("ldr q25, [x0]");
+  __asm __volatile ("ldr q26, [x0]");
+  __asm __volatile ("ldr q27, [x0]");
+  __asm __volatile ("ldr q28, [x0]");
+  __asm __volatile ("ldr q29, [x0]");
+  __asm __volatile ("ldr q30, [x0]");
+  __asm __volatile ("ldr q31, [x0]");
+}
+
+static void
+initialize_za_state ()
+{
+  /* zero za */
+  __asm __volatile (".word 0xC00800FF");
+
+  char buffer[256];
+
+  for (int i = 0; i < 256; i++)
+    buffer[i] = 0xaa;
+
+  __asm __volatile ("mov x0, %0\n\t" \
+		    : : "r" (buffer));
+
+  /* Initialize loop boundaries.  */
+  __asm __volatile ("mov w12, 0");
+  __asm __volatile ("mov w17, 256");
+
+  /* loop: ldr za[w12, 0], [x0] */
+  __asm __volatile ("loop: .word 0xe1000000");
+  __asm __volatile ("add w12, w12, 1");
+  __asm __volatile ("cmp w12, w17");
+  __asm __volatile ("bne loop");
+}
+
+static void
+initialize_sve_state ()
+{
+  __asm __volatile ("dup z0.b, -1");
+  __asm __volatile ("dup z1.b, -1");
+  __asm __volatile ("dup z2.b, -1");
+  __asm __volatile ("dup z3.b, -1");
+  __asm __volatile ("dup z4.b, -1");
+  __asm __volatile ("dup z5.b, -1");
+  __asm __volatile ("dup z6.b, -1");
+  __asm __volatile ("dup z7.b, -1");
+  __asm __volatile ("dup z8.b, -1");
+  __asm __volatile ("dup z9.b, -1");
+  __asm __volatile ("dup z10.b, -1");
+  __asm __volatile ("dup z11.b, -1");
+  __asm __volatile ("dup z12.b, -1");
+  __asm __volatile ("dup z13.b, -1");
+  __asm __volatile ("dup z14.b, -1");
+  __asm __volatile ("dup z15.b, -1");
+  __asm __volatile ("dup z16.b, -1");
+  __asm __volatile ("dup z17.b, -1");
+  __asm __volatile ("dup z18.b, -1");
+  __asm __volatile ("dup z19.b, -1");
+  __asm __volatile ("dup z20.b, -1");
+  __asm __volatile ("dup z21.b, -1");
+  __asm __volatile ("dup z22.b, -1");
+  __asm __volatile ("dup z23.b, -1");
+  __asm __volatile ("dup z24.b, -1");
+  __asm __volatile ("dup z25.b, -1");
+  __asm __volatile ("dup z26.b, -1");
+  __asm __volatile ("dup z27.b, -1");
+  __asm __volatile ("dup z28.b, -1");
+  __asm __volatile ("dup z29.b, -1");
+  __asm __volatile ("dup z30.b, -1");
+  __asm __volatile ("dup z31.b, -1");
+  __asm __volatile ("ptrue p0.b");
+  __asm __volatile ("ptrue p1.b");
+  __asm __volatile ("ptrue p2.b");
+  __asm __volatile ("ptrue p3.b");
+  __asm __volatile ("ptrue p4.b");
+  __asm __volatile ("ptrue p5.b");
+  __asm __volatile ("ptrue p6.b");
+  __asm __volatile ("ptrue p7.b");
+  __asm __volatile ("ptrue p8.b");
+  __asm __volatile ("ptrue p9.b");
+  __asm __volatile ("ptrue p10.b");
+  __asm __volatile ("ptrue p11.b");
+  __asm __volatile ("ptrue p12.b");
+  __asm __volatile ("ptrue p13.b");
+  __asm __volatile ("ptrue p14.b");
+  __asm __volatile ("ptrue p15.b");
+  __asm __volatile ("setffr");
+}
+
+/* Enable register states based on STATE.
+
+   0 - FPSIMD
+   1 - SVE
+   2 - SSVE
+   3 - ZA
+   4 - ZA and SSVE.  */
+
+void enable_states (int state)
+{
+  disable_za ();
+  disable_sm ();
+  initialize_fpsimd_state ();
+
+  if (state == 1)
+    {
+      initialize_sve_state ();
+    }
+  else if (state == 2)
+    {
+      enable_sm ();
+      initialize_sve_state ();
+    }
+  else if (state == 3)
+    {
+      enable_za ();
+      initialize_za_state ();
+    }
+  else if (state == 4)
+    {
+      enable_za ();
+      enable_sm ();
+      initialize_sve_state ();
+      initialize_za_state ();
+    }
+
+  return;
+}
+
+void dummy ()
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
+    {
+      for (int state = 0; state < 5; state++)
+	{
+	  enable_states (state);
+	  dummy (); /* stop here */
+	}
+    }
+  else
+    {
+      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp
new file mode 100644
index 00000000000..c96df7543e0
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp
@@ -0,0 +1,72 @@
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# 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/>.
+#
+# Sanity check for AArch64 Scalable Vector/Matrix Extensions functionality.
+
+load_lib aarch64.exp
+
+#
+# Run a series of basic checks for SVE/SME states.
+#
+proc sanity_check { vl svl } {
+    # Run the program until the point where we start initializing the different
+    # register states.
+    set state_breakpoint "stop here"
+    gdb_breakpoint [gdb_get_line_number $state_breakpoint]
+
+    for {set id 0} {$id < 5} {incr id} {
+	set state [state_id_to_state_string $id]
+
+	with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+	    gdb_continue_to_breakpoint $state_breakpoint
+	    check_state $state $vl $svl
+	}
+    }
+}
+
+require is_aarch64_target
+
+if {![allow_aarch64_sve_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+if {![allow_aarch64_sme_tests]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+set compile_flags {"debug" "macros" "additional_flags=-march=armv8.5-a+sve"}
+standard_testfile
+if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${compile_flags}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    return -1
+}
+
+# Adjust the repeat count for the test.
+gdb_test_no_output "set print repeats 1" "adjust repeat count"
+
+# Fetch both the vector length and the streaming vector length the target
+# system is using.  We do not force any vector lengths and do not change
+# it mid-execution.
+set vl [expr [get_valueof "" "\$vg" "0" "fetch value of vl"] * 8]
+set svl [expr [get_valueof "" "\$svg" "0" "fetch value of svl"] * 8]
+
+# Now we are at the point where we can start checking state and moving the
+# testcase forward.
+sanity_check $vl $svl
diff --git a/gdb/testsuite/lib/aarch64.exp b/gdb/testsuite/lib/aarch64.exp
new file mode 100644
index 00000000000..076964e2028
--- /dev/null
+++ b/gdb/testsuite/lib/aarch64.exp
@@ -0,0 +1,372 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# 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/>.  */
+
+# Support routines for aarch64-specific tests
+
+#
+# Return a regular expression that matches what gdb would print for a
+# 1-dimension vector containing ELEMENTS elements of value BYTE.
+#
+# The pattern is of the form "{BYTE <repeats ELEMENTS times>".
+#
+proc 1d_array_value_pattern { byte elements } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open $byte
+    if {$elements > 1} {
+	append data " <repeats $elements times>"
+    }
+    append data $brace_close
+
+    verbose -log "1d_array_value_pattern Pattern string is..."
+    verbose -log $data
+    return $data
+}
+
+#
+# Return a regular expression that matches what gdb would print for a
+# 2-dimension vector containing ROWS rows and COLUMNS columns of elements
+# of value BYTE.
+#
+# The pattern is of the form
+# "{{BYTE <repeats COLUMNS times>} <repeats ROWS times>}".
+#
+proc 2d_array_value_pattern { byte rows columns } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open [1d_array_value_pattern $byte $columns]
+    if {$rows > 1} {
+	append data " <repeats $rows times>"
+    }
+    append data $brace_close
+
+    verbose -log "2d_array_value_pattern Pattern string is..."
+    verbose -log $data
+    return $data
+}
+
+#
+# Return a regular expression that matches what gdb would print for a
+# SVE Z register of length VL in state STATE.  The Z register should be filled
+# with BYTE_SVE and the FPSIMD registers should be filled with BYTE_FPSIMD.
+#
+# The pattern is of the form
+#
+# {BYTE_FPSIMD <repeats 16 times>}
+#
+# or
+#
+# {BYTE_FPSIMD <repeats 16 times>, 0 <repeats ... times>}
+#
+# or
+#
+# {BYTE_SVE <repeats VL times>}
+#
+proc sve_value_pattern { state vl byte_fpsimd byte_sve } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open
+    if { $state == "fpsimd" || $state == "za" } {
+	if { $vl > 16 } {
+	    set sve_repeat_count [expr $vl - 16]
+	    append data "$byte_fpsimd <repeats 16 times>, 0 <repeats $sve_repeat_count times>"
+	} else {
+	    append data "$byte_fpsimd <repeats 16 times>"
+	}
+    } else {
+	append data "$byte_sve <repeats $vl times>"
+    }
+    append data $brace_close
+
+    verbose -log "sve_value_pattern pattern string is..."
+    verbose -log $data
+    return $data
+}
+
+#
+# Initialize register NAME, a 1-dimension vector, with ELEMENTS elements
+# by setting all elements to BYTE.  ELEMENTS is limited at 256 for memory
+# usage purposes.
+#
+# The initialization is of the form "{BYTE, BYTE, BYTE ...}".
+#
+proc initialize_1d_array { name byte elements } {
+    set brace_open "{"
+    set brace_close "}"
+
+    append data $brace_open
+
+    # Build the assignment in a single shot.
+    for {set element 0} {$element < $elements} {incr element} {
+	# Construct the initializer by appending elements to it.
+	append data $byte
+
+	# If this isn't the last element, add a comma.
+	if {[expr $element + 1] < $elements} {
+	    append data ", "
+	}
+    }
+    append data $brace_close
+
+    verbose -log "initialization string is..."
+    verbose -log $data
+    gdb_test_no_output "set $name = $data" "write to $name"
+}
+
+#
+# Return an initializer string for a 2-dimension vector with ROWS rows and
+# COLUMNS columns, initializing all elements to BYTE for register NAME.
+#
+# COLUMNS is limited to 256 elements for memory usage purposes.
+#
+# The initialization is of the form "{{BYTE, BYTE}, ..., {BYTE, BYTE}}}".
+#
+proc initialize_2d_array { name byte rows columns } {
+    set brace_open "{"
+    set brace_close "}"
+
+    if {[expr $rows * $columns] <= 256} {
+	# Build the assignment in a single shot, as we have a maximum of 256
+	# elements.
+	for {set row 0} {$row < $rows} {incr row} {
+	    append data $brace_open
+	    for {set column 0} {$column < $columns} {incr column} {
+		# Construct the initializer by appending elements to it.
+		append data $byte
+
+		# If this isn't the last column, add a comma.
+		if {[expr $column + 1] < $columns} {
+		    append data ", "
+		}
+	    }
+
+	    append data $brace_close
+
+	    # If this isn't the last row, add a comma.
+	    if {[expr $row + 1] < $rows} {
+		append data ","
+	    }
+	}
+
+	set data $brace_open$data
+	set data $data$brace_close
+
+	verbose -log "initialization string is..."
+	verbose -log $data
+	gdb_test_no_output "set $name = $data" "write to $name"
+    } else {
+	# There are too many elements to initialize (more than 256), so we
+	# will do the initialization row by row.
+	for {set row 0} {$row < $rows} {incr row} {
+	    initialize_1d_array "$name\[$row\]" $byte $columns
+	}
+    }
+}
+
+#
+# Return the SVCR value based STATE.
+#
+proc get_svcr_value { state } {
+    if { $state == "ssve" } {
+      return "= \\\[ SM \\\]"
+    } elseif { $state == "za" } {
+      return "= \\\[ ZA \\\]"
+    } elseif { $state == "za_ssve" } {
+      return "= \\\[ SM ZA \\\]"
+    }
+
+  return "= \\\[ \\\]"
+}
+
+#
+# Return the state string based on STATE
+#
+proc state_id_to_state_string { state } {
+  if {$state == 0} {
+    return "fpsimd"
+  } elseif {$state == 1} {
+    return "sve"
+  } elseif {$state == 2} {
+    return "ssve"
+  } elseif {$state == 3} {
+    return "za"
+  } elseif {$state == 4} {
+    return "za_ssve"
+  }
+}
+
+#
+# Given a test ID, return the string representing the register state.
+# The state is one of fpsimd, sve, ssve, za and za_ssve.
+#
+proc test_id_to_state { id } {
+  set state [expr $id / 25]
+
+  return [state_id_to_state_string $state]
+}
+
+#
+# Given a test ID, return the associated vector length.
+#
+proc test_id_to_vl { id } {
+  return [expr 16 << (($id / 5) % 5)]
+}
+
+#
+# Given a test ID, return the associated streaming vector length.
+#
+proc test_id_to_svl { id } {
+  return [expr 16 << ($id % 5)]
+}
+
+#
+# Validate the values of the FPSIMD registers.
+#
+proc check_fpsimd_regs { byte state vl svl} {
+    set fpsimd_pattern [string_to_regexp [1d_array_value_pattern $byte 16]]
+
+    for {set number 0} {$number < 32} {incr number} {
+	set register_name "\$v${number}\.b\.u"
+	gdb_test "print sizeof $register_name" " = 16"
+	gdb_test "print $register_name" $fpsimd_pattern
+    }
+}
+
+#
+# Validate the values of the SVE registers.
+#
+proc check_sve_regs { byte state vl svl } {
+
+    # If streaming mode is enabled, the vector length is the streaming
+    # vector length.
+    set z_pattern ""
+    set z_size 0
+    if {$state == "ssve" || $state == "za_ssve"} {
+	set z_pattern [string_to_regexp [1d_array_value_pattern $byte $svl]]
+	set z_size $svl
+    } else {
+	set z_size $vl
+
+	if {$state == "fpsimd" || $state == "za"} {
+	    # If there is no SVE/SSVE state, the contents of the Z/P/FFR registers
+	    # are zero.
+	    if {$vl == 16} {
+		set z_pattern [string_to_regexp [1d_array_value_pattern $byte $vl]]
+	    } else {
+		set z_repeats [expr $vl - 16]
+		set z_pattern [string_to_regexp "{$byte <repeats 16 times>, 0 <repeats $z_repeats times>}"]
+	      }
+	} else {
+	    set z_pattern [string_to_regexp [1d_array_value_pattern $byte $vl]]
+	}
+    }
+    set p_size [expr $z_size / 8]
+
+    # If there is no SVE/SSVE state, the contents of the Z/P/FFR registers
+    # are zero.
+    set p_byte $byte
+    if {$state == "fpsimd" || $state == "za"} {
+	set p_byte 0
+    }
+    set p_pattern [string_to_regexp [1d_array_value_pattern $p_byte $p_size]]
+
+    for {set number 0} {$number < 32} {incr number} {
+	set register_name "\$z${number}\.b\.u"
+	gdb_test "print sizeof $register_name" " = $z_size"
+	gdb_test "print $register_name" $z_pattern
+    }
+
+    for {set number 0} {$number < 16} {incr number} {
+	set register_name "\$p${number}"
+	gdb_test "print sizeof $register_name" " = $p_size"
+	gdb_test "print $register_name" $p_pattern
+    }
+
+    gdb_test "print \$ffr" $p_pattern
+}
+
+#
+# Validate the values of the SME registers.
+#
+proc check_sme_regs { byte state svl } {
+    # ZA contents are only available when the ZA state is enabled.  Otherwise
+    # the ZA contents are unavailable (zeroed out).
+    set za_pattern ""
+    set expected_za_size [expr $svl * $svl]
+
+    if {$state != "za" && $state != "za_ssve"} {
+	set byte 0
+    }
+
+    set za_pattern [string_to_regexp [2d_array_value_pattern $byte $svl $svl]]
+
+    gdb_test "print sizeof \$za" " = $expected_za_size"
+    gdb_test "print \$za" $za_pattern
+}
+
+#
+# With register STATE, vector length VL and streaming vector length SVL,
+# run some register state checks to make sure the values are the expected
+# ones
+#
+proc check_state { state vl svl } {
+    # The FPSIMD registers are initialized with a value of 0x55 (125)
+    # for each byte.
+    #
+    # The SVE registers are initialized with a value of 0xff (255) for each
+    # byte, including the predicate registers and FFR.
+    #
+    # The SME (ZA) register is initialized with a value of 0xaa (252) for
+    # each byte.
+
+    # Check VG to make sure it is correct
+    set expected_vg [expr $vl / 8]
+    # If streaming mode is enabled, then vg is actually svg.
+    if {$state == "ssve" || $state == "za_ssve"} {
+	set expected_vg [expr $svl / 8]
+    }
+    gdb_test "print \$vg" " = ${expected_vg}"
+
+    # Check SVG to make sure it is correct
+    set expected_svg [expr $svl / 8]
+    gdb_test "print \$svg" " = ${expected_svg}"
+
+    # Check the value of SVCR.
+    gdb_test "print \$svcr" [get_svcr_value $state]
+
+    # When we have any SVE or SSVE state, the FPSIMD registers will have
+    # the same values as the SVE/SSVE Z registers.
+    set fpsimd_byte 85
+    if {$state == "sve" || $state == "ssve" || $state == "za_ssve"} {
+	set fpsimd_byte 255
+    }
+
+    set sve_byte 255
+    if {$state == "fpsimd" || $state == "za"} {
+	set sve_byte 85
+    }
+
+    # Check FPSIMD registers
+    check_fpsimd_regs $fpsimd_byte $state $vl $svl
+    # Check SVE registers
+    check_sve_regs $sve_byte $state $vl $svl
+    # Check SME registers
+    check_sme_regs 170 $state $svl
+}
+
+
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 133d914aff8..7b5c641d0cc 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4085,6 +4085,69 @@ gdb_caching_proc allow_aarch64_sve_tests {} {
     return $allow_sve_tests
 }
 
+# Run a test on the target to see if it supports Aarch64 SME extensions.
+# Return 0 if so, 1 if it does not.  Note this causes a restart of GDB.
+
+gdb_caching_proc allow_aarch64_sme_tests {} {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "allow_aarch64_sme_tests"
+
+    if { ![is_aarch64_target]} {
+	return 0
+    }
+
+    set compile_flags "{additional_flags=-march=armv8-a+sme}"
+
+    # Compile a test program containing SVE instructions.
+    set src {
+	int main() {
+	    asm volatile ("smstart za");
+	    return 0;
+	}
+    }
+    if {![gdb_simple_compile $me $src executable $compile_flags]} {
+	# Try again, but with a raw hex instruction so we don't rely on
+	# assembler support for SME.
+
+	set compile_flags "{additional_flags=-march=armv8-a}"
+
+	# Compile a test program containing SVE instructions.
+	set src {
+	    int main() {
+		asm volatile (".word 0xD503457F");
+		return 0;
+	    }
+	}
+
+	if {![gdb_simple_compile $me $src executable $compile_flags]} {
+	    return 0
+	}
+    }
+
+    # Compilation succeeded so now run it via gdb.
+    clean_restart $obj
+    gdb_run_cmd
+    gdb_expect {
+	-re ".*Illegal instruction.*${gdb_prompt} $" {
+	    verbose -log "\n$me sme support not detected"
+	    set allow_sme_tests 0
+	}
+	-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+	    verbose -log "\n$me: sme support detected"
+	    set allow_sme_tests 1
+	}
+	default {
+	  warning "\n$me: default case taken"
+	    set allow_sme_tests 0
+	}
+    }
+    gdb_exit
+    remote_file build delete $obj
+
+    verbose "$me:  returning $allow_sme_tests" 2
+    return $allow_sme_tests
+}
 
 # A helper that compiles a test case to see if __int128 is supported.
 proc gdb_int128_helper {lang} {
