[v3,15/16,gdb/testsuite] sme: Add SVE/SME testcases

Message ID 20230630134616.1238105-16-luis.machado@arm.com
State New
Headers
Series SME support for AArch64 gdb/gdbserver on Linux |

Commit Message

Luis Machado June 30, 2023, 1:46 p.m. UTC
  v2:
- Introduced a couple helper functions to determine the available SVE and SME
  vector lengths.

- Before running a batch of tests, validate that the target supports a certain
  SVE vector length or SME streaming vector length.  If not supported, skip
  that batch of tests.

- Fixed up native core file testing to remove generation of a spurious core
  file, which later would be reported as unexpected by the testsuite.

- Fixed tpidr2 dump in core file tests.
--

Add 5 SVE/SME tests to exercise all the new features like reading/writing
registers, pseudo-registers, signal frames and core files.

- Sanity check for SME: Gives a brief smoke test to make sure the most basic
of features are working correctly.

- ZA unavailability tests: Validates the behavior/content of the ZA register
is correct when no payload is available.  It also exercises changing the
vector lengths.

- ZA Availability tests: These tests exercise reading/writing to all the
possible ZA pseudo-registers, and validates the state is correct.

- Core file tests: Validates that core file reading and writing works
correctly and that all state dumped/loaded is sane.  This is exercised for
both Linux Kernel core files and gcore core files.

- Signal frame tests: Validates the correct restoration of SME/SVE/FPSIMD
values across signal frames.

Since some of these tests are very lengthy and take a little while to run
(under QEMU at the moment), I decided to parallelize them into smaller
chunks so we can throw some more CPU power at them so they run faster.

I'd still like to add a few more tests to give the testsuite more coverage
in the areas of SME/SVE.  Hopefully in the near future that will happen.

Just a reminder that most of these tests will FAIL when running against
gdbserver because all of the tests change the vector length mid-execution
in some way.  Since gdbserver can't communicate the change of state over
RSP to GDB, we will always get wrong state from gdbserver.

Co-Authored-By: Ezra Sitorus <ezra.sitorus@arm.com>
---
 gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp |  18 +
 gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp |  18 +
 gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp |  18 +
 gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp |  18 +
 gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp |  18 +
 gdb/testsuite/gdb.arch/aarch64-sme-core.c     | 372 ++++++++++++++++++
 .../gdb.arch/aarch64-sme-core.exp.tcl         | 187 +++++++++
 .../gdb.arch/aarch64-sme-regs-available-0.exp |  18 +
 .../gdb.arch/aarch64-sme-regs-available-1.exp |  18 +
 .../gdb.arch/aarch64-sme-regs-available-2.exp |  18 +
 .../gdb.arch/aarch64-sme-regs-available-3.exp |  18 +
 .../gdb.arch/aarch64-sme-regs-available-4.exp |  18 +
 .../gdb.arch/aarch64-sme-regs-available.c     | 178 +++++++++
 .../aarch64-sme-regs-available.exp.tcl        | 245 ++++++++++++
 .../gdb.arch/aarch64-sme-regs-sigframe-0.exp  |  18 +
 .../gdb.arch/aarch64-sme-regs-sigframe-1.exp  |  18 +
 .../gdb.arch/aarch64-sme-regs-sigframe-2.exp  |  18 +
 .../gdb.arch/aarch64-sme-regs-sigframe-3.exp  |  18 +
 .../gdb.arch/aarch64-sme-regs-sigframe-4.exp  |  18 +
 .../gdb.arch/aarch64-sme-regs-sigframe.c      | 366 +++++++++++++++++
 .../aarch64-sme-regs-sigframe.exp.tcl         | 179 +++++++++
 .../aarch64-sme-regs-unavailable-0.exp        |  18 +
 .../aarch64-sme-regs-unavailable-1.exp        |  18 +
 .../aarch64-sme-regs-unavailable-2.exp        |  18 +
 .../aarch64-sme-regs-unavailable-3.exp        |  18 +
 .../aarch64-sme-regs-unavailable-4.exp        |  18 +
 .../gdb.arch/aarch64-sme-regs-unavailable.c   | 152 +++++++
 .../aarch64-sme-regs-unavailable.exp.tcl      | 212 ++++++++++
 gdb/testsuite/gdb.arch/aarch64-sme-sanity.c   | 249 ++++++++++++
 gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp |  72 ++++
 gdb/testsuite/lib/aarch64-test-sme.c          |  90 +++++
 gdb/testsuite/lib/aarch64-test-sve.c          |  90 +++++
 gdb/testsuite/lib/aarch64.exp                 | 372 ++++++++++++++++++
 gdb/testsuite/lib/gdb.exp                     | 249 ++++++++++++
 34 files changed, 3373 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-0.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-1.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-2.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-3.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core-4.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-0.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-1.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-2.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-3.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available-4.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-0.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-1.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-2.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-3.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe-4.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-0.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-1.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-2.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-3.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable-4.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-sanity.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-sme-sanity.exp
 create mode 100644 gdb/testsuite/lib/aarch64-test-sme.c
 create mode 100644 gdb/testsuite/lib/aarch64-test-sve.c
 create mode 100644 gdb/testsuite/lib/aarch64.exp
  

Comments

Thiago Jung Bauermann Aug. 4, 2023, 12:59 a.m. UTC | #1
Luis Machado via Gdb-patches <gdb-patches@sourceware.org> writes:

> 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

It would be useful to have a comment mentioning that the range above
tests the fpsimd state.

Same comment for the other aarch64-sme-*.exp tests.

> +source $srcdir/$subdir/aarch64-sme-core.exp.tcl

<snip>

> +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
> +}

Can these "allow" tests also be invoked using "require"?
This question applies for all aarch64-sme-*.exp.tcl files.

> +
> +test_sme_core_file $id_start $id_end

<snip>

> +#
> +# 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)]
> +}

I suggest adding an sme_ prefix to the procedures above, since "id" here
is specific to SME testcases.

> +#
> +# 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 (85)
> +    # 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 (170) 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
> +}

Also here, perhaps call this function "check_sme_state"?

> +# 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.

s/SVE/SME/

> +    set src {
> +	int main() {
> +	    asm volatile ("smstart za");
> +	    return 0;
> +	}
> +    }
> +    if {![gdb_simple_compile $me $src executable $compile_flags]} {
  
Luis Machado Aug. 11, 2023, 3:42 p.m. UTC | #2
Hi,

On 8/4/23 01:59, Thiago Jung Bauermann wrote:
> 
> Luis Machado via Gdb-patches <gdb-patches@sourceware.org> writes:
> 
>> 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
> 
> It would be useful to have a comment mentioning that the range above
> tests the fpsimd state.
> 
> Same comment for the other aarch64-sme-*.exp tests.
> 

Yeah. That can be a bit obscure. I'll add some more documentation to that effect.

The current arrangement is mostly aiming at splitting these tests in a way that minimizes
the total run time.

I'm considering further splitting these, putting each test with SVL == 256 into its own
file. Those are the ones that take the longest to run. The others can be grouped.

Right now the split is based on continuous ranges (0~4, 5~9 etc). I may change that to a list
instead. That will allow us to clearly specify the tests we want for each sub-file, hopefully
causing each sub-test to have more or less the same run time.

>> +source $srcdir/$subdir/aarch64-sme-core.exp.tcl
> 
> <snip>
> 
>> +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
>> +}
> 
> Can these "allow" tests also be invoked using "require"?
> This question applies for all aarch64-sme-*.exp.tcl files.
> 

Yes. When I started this code, we had not switched to this new format. Fixed now.

>> +
>> +test_sme_core_file $id_start $id_end
> 
> <snip>
> 
>> +#
>> +# 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)]
>> +}
> 
> I suggest adding an sme_ prefix to the procedures above, since "id" here
> is specific to SME testcases.
> 

See below.

>> +#
>> +# 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 (85)
>> +    # 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 (170) 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
>> +}
> 
> Also here, perhaps call this function "check_sme_state"?
> 

Maybe. Instead of renaming these functions, how about renaming the helper .exp file
from aarch64.exp to aarch64-sme.exp? Or maybe split it into a sme-specific part and
a generic part.

Moving forward, I'd like to make these tests cover SVE as well. In that case, we would be
able to reuse some of these functions to raise the coverage of tests.

What do you think?

>> +# 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.
> 
> s/SVE/SME/
> 

Oops. Fixed now.

>> +    set src {
>> +	int main() {
>> +	    asm volatile ("smstart za");
>> +	    return 0;
>> +	}
>> +    }
>> +    if {![gdb_simple_compile $me $src executable $compile_flags]} {
> 
>
  
Thiago Jung Bauermann Aug. 12, 2023, 12:42 a.m. UTC | #3
Hello,

Luis Machado <luis.machado@arm.com> writes:

> Hi,
>
> On 8/4/23 01:59, Thiago Jung Bauermann wrote:
>> 
>> Luis Machado via Gdb-patches <gdb-patches@sourceware.org> writes:
>> 
>>> 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
>> 
>> It would be useful to have a comment mentioning that the range above
>> tests the fpsimd state.
>> 
>> Same comment for the other aarch64-sme-*.exp tests.
>> 
>
> Yeah. That can be a bit obscure. I'll add some more documentation to that effect.
>
> The current arrangement is mostly aiming at splitting these tests in a way that minimizes
> the total run time.

That is a nice idea.

> I'm considering further splitting these, putting each test with SVL == 256 into its own
> file. Those are the ones that take the longest to run. The others can be grouped.
>
> Right now the split is based on continuous ranges (0~4, 5~9 etc). I may change that to a
> list
> instead. That will allow us to clearly specify the tests we want for each sub-file,
> hopefully
> causing each sub-test to have more or less the same run time.

Sounds good. Thanks for the explanation.

>>> +source $srcdir/$subdir/aarch64-sme-core.exp.tcl
>> 
>> <snip>
>> 
>>> +#
>>> +# 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)]
>>> +}
>> 
>> I suggest adding an sme_ prefix to the procedures above, since "id" here
>> is specific to SME testcases.
>> 
>
> See below.
>
>>> +#
>>> +# 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 (85)
>>> +    # 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 (170) 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
>>> +}
>> 
>> Also here, perhaps call this function "check_sme_state"?
>> 
>
> Maybe. Instead of renaming these functions, how about renaming the helper .exp file
> from aarch64.exp to aarch64-sme.exp? Or maybe split it into a sme-specific part and
> a generic part.

The 1d_array and 2d_array functions are even generic enough to go in gdb.exp.

> Moving forward, I'd like to make these tests cover SVE as well. In that case, we would be
> able to reuse some of these functions to raise the coverage of tests.
>
> What do you think?

I like the idea. Perhaps rename to aarch64-scalable.exp so that it
covers both SVE and SME? Also some functions that are currently in
gdb.exp could go there, such as allow_aarch64_sve_tests,
aarch64_initialize_sve_information, aarch64_supports_sve_vl and their
SME counterparts.
  

Patch

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..d71d18ebd3b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core.c
@@ -0,0 +1,372 @@ 
+/* 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_tpidr2 ()
+{
+  __asm __volatile ("mov x0, #0xffffffffffffffff");
+
+  /* Write x0 to tpidr2.  */
+  __asm __volatile (".word 0xd51bd0a0");
+}
+
+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)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", 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 || set_svl_size (svl) == -1)
+	return -1;
+
+      enable_states (state);
+
+      /* Also set the TPIDR2 register so we can test dumping its contents
+	 to a core file.  */
+      initialize_tpidr2 ();
+
+      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..ed229982d7c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-core.exp.tcl
@@ -0,0 +1,187 @@ 
+# 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" " = 0xffffffffffffffff" \
+	     "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
+
+    # 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]
+
+	set skip_unsupported 0
+	if {![aarch64_supports_sve_vl $vl]
+	    || ![aarch64_supports_sme_svl $svl]} {
+	    # We have a vector length or streaming vector length that
+	    # is not supported by this target.  Skip to the next iteration
+	    # since it is no use running tests for an unsupported vector
+	    # length.
+	    if {![aarch64_supports_sve_vl $vl]} {
+		verbose -log "SVE vector length $vl not supported."
+	    } elseif {![aarch64_supports_sme_svl $svl]} {
+		verbose -log "SME streaming vector length $svl not supported."
+	    }
+	    verbose -log "Skipping test."
+	    set skip_unsupported 1
+	}
+
+	with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+	    # If the SVE or SME vector length is not supported, just skip
+	    # these next tests.
+	    if {$skip_unsupported} {
+		untested "unsupported configuration on target"
+		continue
+	    }
+
+	    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..58c01d0bf9a
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.c
@@ -0,0 +1,178 @@ 
+/* 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)\n", 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)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", 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 || set_svl_size (svl) == -1)
+	    continue;
+
+	  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);
+
+	  if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1)
+	    continue;
+
+	  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..635588777ec
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-available.exp.tcl
@@ -0,0 +1,245 @@ 
+# 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 skip_unsupported 0
+	if {![aarch64_supports_sve_vl $vl]
+	    || ![aarch64_supports_sme_svl $svl]} {
+	    # We have a vector length or streaming vector length that
+	    # is not supported by this target.  Skip to the next iteration
+	    # since it is no use running tests for an unsupported vector
+	    # length.
+	    if {![aarch64_supports_sve_vl $vl]} {
+		verbose -log "SVE vector length $vl not supported."
+	    } elseif {![aarch64_supports_sme_svl $svl]} {
+		verbose -log "SME streaming vector length $svl not supported."
+	    }
+	    verbose -log "Skipping test."
+	    set skip_unsupported 1
+	}
+
+	set mode "prctl"
+	with_test_prefix "$mode, vl=${vl} svl=${svl}" {
+	    # If the SVE or SME vector length is not supported, just skip
+	    # these next tests.
+	    if {$skip_unsupported} {
+		untested "unsupported configuration on target"
+		continue
+	    }
+
+	    # 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]
+
+    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 skip_unsupported 0
+	if {![aarch64_supports_sve_vl $vl]
+	    || ![aarch64_supports_sme_svl $svl]} {
+	    # We have a vector length or streaming vector length that
+	    # is not supported by this target.  Skip to the next iteration
+	    # since it is no use running tests for an unsupported vector
+	    # length.
+	    if {![aarch64_supports_sve_vl $vl]} {
+		verbose -log "SVE vector length $vl not supported."
+	    } elseif {![aarch64_supports_sme_svl $svl]} {
+		verbose -log "SME streaming vector length $svl not supported."
+	    }
+	    verbose -log "Skipping test."
+	    set skip_unsupported 1
+	}
+
+	set mode "gdb"
+	with_test_prefix "$mode, vl=${vl} svl=${svl}" {
+	    # If the SVE or SME vector length is not supported, just skip
+	    # these next tests.
+	    if {$skip_unsupported} {
+		untested "unsupported configuration on target"
+		continue
+	    }
+
+	    # Run the program until we stop at the point where gdb should
+	    # adjust the SVE and SME vector lengths.
+	    gdb_continue_to_breakpoint $non_prctl_breakpoint
+
+	    # 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..9bc3e9c16fc
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c
@@ -0,0 +1,366 @@ 
+/* 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)\n", 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)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", 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 || set_svl_size (svl) == -1)
+	    continue;
+
+	  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..0a9eae7dc5e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.exp.tcl
@@ -0,0 +1,179 @@ 
+# 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]
+
+	set skip_unsupported 0
+	if {![aarch64_supports_sve_vl $vl]
+	    || ![aarch64_supports_sme_svl $svl]} {
+	    # We have a vector length or streaming vector length that
+	    # is not supported by this target.  Skip to the next iteration
+	    # since it is no use running tests for an unsupported vector
+	    # length.
+	    if {![aarch64_supports_sve_vl $vl]} {
+		verbose -log "SVE vector length $vl not supported."
+	    } elseif {![aarch64_supports_sme_svl $svl]} {
+		verbose -log "SME streaming vector length $svl not supported."
+	    }
+	    verbose -log "Skipping test."
+	    set skip_unsupported 1
+	}
+
+	with_test_prefix "state=${state} vl=${vl} svl=${svl}" {
+
+	    # If the SVE or SME vector length is not supported, just skip
+	    # these next tests.
+	    if {$skip_unsupported} {
+		untested "unsupported configuration on target"
+		continue
+	    }
+
+	    # 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..9c844c91c7c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.c
@@ -0,0 +1,152 @@ 
+/* 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)\n", 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)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_vl_size ();
+  if (res != new_vl)
+    {
+      printf ("Unexpected VL value (%d)\n", 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)\n", res);
+      return -1;
+    }
+
+  res = get_svl_size ();
+  if (res != new_svl)
+    {
+      printf ("Unexpected SVL value (%d)\n", 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 || set_svl_size (svl) == -1)
+	    continue;
+
+	  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..69c70ae87b3
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sme-regs-unavailable.exp.tcl
@@ -0,0 +1,212 @@ 
+# 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]
+
+	set skip_unsupported 0
+	if {![aarch64_supports_sve_vl $vl]
+	    || ![aarch64_supports_sme_svl $svl]} {
+	    # We have a vector length or streaming vector length that
+	    # is not supported by this target.  Skip to the next iteration
+	    # since it is no use running tests for an unsupported vector
+	    # length.
+	    if {![aarch64_supports_sve_vl $vl]} {
+		verbose -log "SVE vector length $vl not supported."
+	    } elseif {![aarch64_supports_sme_svl $svl]} {
+		verbose -log "SME streaming vector length $svl not supported."
+	    }
+	    verbose -log "Skipping test."
+	    set skip_unsupported 1
+	}
+
+	with_test_prefix "prctl, vl=${vl} svl=${svl}" {
+	    # If the SVE or SME vector length is not supported, just skip
+	    # these next tests.
+	    if {$skip_unsupported} {
+		untested "unsupported configuration on target"
+		continue
+	    }
+
+	    # 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]
+
+	set skip_unsupported 0
+	if {![aarch64_supports_sve_vl $vl]
+	    || ![aarch64_supports_sme_svl $svl]} {
+	    # We have a vector length or streaming vector length that
+	    # is not supported by this target.  Skip to the next iteration
+	    # since it is no use running tests for an unsupported vector
+	    # length.
+	    if {![aarch64_supports_sve_vl $vl]} {
+		verbose -log "SVE vector length $vl not supported."
+	    } elseif {![aarch64_supports_sme_svl $svl]} {
+		verbose -log "SME streaming vector length $svl not supported."
+	    }
+	    verbose -log "Skipping test."
+	    set skip_unsupported 1
+	}
+
+	with_test_prefix "gdb, vl=${vl} svl=${svl}" {
+
+	    # If the SVE or SME vector length is not supported, just skip
+	    # these next tests.
+	    if {$skip_unsupported} {
+		untested "unsupported configuration on target"
+		continue
+	    }
+
+	    # 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-test-sme.c b/gdb/testsuite/lib/aarch64-test-sme.c
new file mode 100644
index 00000000000..c123f37e0df
--- /dev/null
+++ b/gdb/testsuite/lib/aarch64-test-sme.c
@@ -0,0 +1,90 @@ 
+/* 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/>.  */
+
+/* AArch64 SME feature check.  This test serves as a way for the GDB testsuite
+   to verify that a target supports SVE at runtime, and also reports data
+   about the various supported SME streaming vector lengths.  */
+
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#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_svl_size ()
+{
+  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
+
+  if (res < 0)
+    return -1;
+
+  return (res & PR_SME_VL_LEN_MASK);
+}
+
+static int set_svl_size (int new_svl)
+{
+  if (prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0) < 0)
+    return -1;
+
+  if (get_svl_size () != new_svl)
+    return -1;
+
+  return 0;
+}
+
+static void
+dummy ()
+{
+}
+
+#define SVL_MIN 16
+#define SVL_MAX 256
+#define SVL_INCREMENT_POWER 1
+
+int
+main (int argc, char **argv)
+{
+  /* Number of supported SME streaming vector lengths.  */
+  size_t supported_svl_count = 0;
+  /* Vector containing the various supported SME streaming vector lengths.  */
+  size_t supported_svl[5];
+
+  if (getauxval (AT_HWCAP) & HWCAP2_SME)
+    {
+      for (int svl = SVL_MIN; svl <= SVL_MAX; svl <<= SVL_INCREMENT_POWER)
+	{
+	  if (set_svl_size (svl) == 0)
+	    {
+	      supported_svl[supported_svl_count] = svl;
+	      supported_svl_count++;
+	    }
+	}
+    }
+
+  return 0; /* stop here */
+}
diff --git a/gdb/testsuite/lib/aarch64-test-sve.c b/gdb/testsuite/lib/aarch64-test-sve.c
new file mode 100644
index 00000000000..4673581b467
--- /dev/null
+++ b/gdb/testsuite/lib/aarch64-test-sve.c
@@ -0,0 +1,90 @@ 
+/* 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/>.  */
+
+/* AArch64 SVE feature check.  This test serves as a way for the GDB testsuite
+   to verify that a target supports SVE at runtime, and also reports data
+   about the various supported SVE vector lengths.  */
+
+#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 PR_SVE_SET_VL
+#define PR_SVE_SET_VL 50
+#define PR_SVE_GET_VL 51
+#define PR_SVE_VL_LEN_MASK 0xffff
+#endif
+
+static int get_vl_size ()
+{
+  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
+
+  if (res < 0)
+    return -1;
+
+  return (res & PR_SVE_VL_LEN_MASK);
+}
+
+static int set_vl_size (int new_vl)
+{
+  if (prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0) < 0)
+    return -1;
+
+  if (get_vl_size () != new_vl)
+    return -1;
+
+  return 0;
+}
+
+static void
+dummy ()
+{
+}
+
+#define VL_MIN 16
+#define VL_MAX 256
+#define VL_INCREMENT 16
+
+int
+main (int argc, char **argv)
+{
+  /* Number of supported SVE vector lengths.  */
+  size_t supported_vl_count = 0;
+  /* Vector containing the various supported SVE vector lengths.  */
+  size_t supported_vl[16];
+
+  if (getauxval (AT_HWCAP) & HWCAP_SVE)
+    {
+      for (int vl = VL_MIN; vl <= VL_MAX; vl += VL_INCREMENT)
+	{
+	  if (set_vl_size (vl) == 0)
+	    {
+	      supported_vl[supported_vl_count] = vl;
+	      supported_vl_count++;
+	    }
+	}
+    }
+
+  return 0; /* stop here */
+}
diff --git a/gdb/testsuite/lib/aarch64.exp b/gdb/testsuite/lib/aarch64.exp
new file mode 100644
index 00000000000..031ffa68373
--- /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 (85)
+    # 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 (170) 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 b4900ae25a6..399ebe6772a 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4089,10 +4089,259 @@  gdb_caching_proc allow_aarch64_sve_tests {} {
     gdb_exit
     remote_file build delete $obj
 
+    # While testing for SVE support, also discover all the supported vector
+    # length values.
+    aarch64_initialize_sve_information
+
     verbose "$me:  returning $allow_sve_tests" 2
     return $allow_sve_tests
 }
 
+# Assuming SVE is supported by the target, run some checks to determine all
+# the supported vector length values and return an array containing all of those
+# values.  Since this is a gdb_caching_proc, this proc will only be executed
+# once.
+#
+# To check if a particular SVE vector length is supported, the following code
+# can be used. For instance, for vl == 16:
+#
+# if {[aarch64_supports_sve_vl 16]} {
+#     verbose -log "SVE vector length 16 is supported."
+# }
+#
+# This procedure should NEVER be called by hand, as it reinitializes the GDB
+# session and will derail a test.  This should be called automatically as part
+# of the SVE support test routine allow_aarch64_sve_tests.  Users should
+# restrict themselves to calling the helper proc aarch64_supports_sve_vl.
+
+gdb_caching_proc aarch64_initialize_sve_information { } {
+    global srcdir
+
+    set src "${srcdir}/lib/aarch64-test-sve.c"
+    set test_exec [standard_temp_file "aarch64-test-sve.x"]
+    set compile_flags "{additional_flags=-march=armv8-a+sve}"
+    array set supported_vl {}
+
+    # Compile the SVE vector length test.
+    set result [gdb_compile $src $test_exec executable [list debug ${compile_flags} nowarnings]]
+
+    if {$result != ""} {
+	verbose -log "Failed to compile SVE information gathering test."
+	return [array get supported_vl]
+    }
+
+    clean_restart $test_exec
+
+    if {![runto_main]} {
+	return [array get supported_vl]
+    }
+
+    set stop_breakpoint "stop here"
+    gdb_breakpoint [gdb_get_line_number $stop_breakpoint $src]
+    gdb_continue_to_breakpoint $stop_breakpoint
+
+    # Go through the data and extract the supported SVE vector lengths.
+    set vl_count [get_valueof "" "supported_vl_count" "0" \
+			      "fetch value of supported_vl_count"]
+    verbose -log "Found $vl_count supported SVE vector length values"
+
+    for {set vl_index 0} {$vl_index < $vl_count} {incr vl_index} {
+	set test_vl [get_valueof "" "supported_vl\[$vl_index\]" "0" \
+				 "fetch value of supported_vl\[$vl_index\]"]
+
+	# Mark this vector length as supported.
+	if {$test_vl != 0} {
+	    verbose -log "Found supported SVE vector length $test_vl"
+	    set supported_vl($test_vl) 1
+	}
+    }
+
+    gdb_exit
+    verbose -log "Cleaning up"
+    remote_file build delete $test_exec
+
+    verbose -log "Done gathering information about AArch64 SVE vector lengths."
+
+    # Return the array containing all of the supported SVE vl values.
+    return [array get supported_vl]
+}
+
+#
+# Return 1 if the target supports SVE vl LENGTH
+# Return 0 otherwise.
+#
+
+proc aarch64_supports_sve_vl { length } {
+
+    # Fetch the cached array of supported SVE vl values.
+    array set supported_vl [aarch64_initialize_sve_information]
+
+    # Do we have the global values cached?
+    if {![info exists supported_vl($length)]} {
+	verbose -log "Target does not support SVE vl $length"
+	return 0
+    }
+
+    # The target supports SVE vl LENGTH.
+    return 1
+}
+
+# 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 SME 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
+
+    # While testing for SME support, also discover all the supported vector
+    # length values.
+    aarch64_initialize_sme_information
+
+    verbose "$me:  returning $allow_sme_tests" 2
+    return $allow_sme_tests
+}
+
+# Assuming SME is supported by the target, run some checks to determine all
+# the supported streaming vector length values and return an array containing
+# all of those values.  Since this is a gdb_caching_proc, this proc will only
+# be executed once.
+#
+# To check if a particular SME streaming vector length is supported, the
+# following code can be used. For instance, for svl == 32:
+#
+# if {[aarch64_supports_sme_svl 32]} {
+#     verbose -log "SME streaming vector length 32 is supported."
+# }
+#
+# This procedure should NEVER be called by hand, as it reinitializes the GDB
+# session and will derail a test.  This should be called automatically as part
+# of the SME support test routine allow_aarch64_sme_tests.  Users should
+# restrict themselves to calling the helper proc aarch64_supports_sme_svl.
+
+gdb_caching_proc aarch64_initialize_sme_information { } {
+    global srcdir
+
+    set src "${srcdir}/lib/aarch64-test-sme.c"
+    set test_exec [standard_temp_file "aarch64-test-sme.x"]
+    set compile_flags "{additional_flags=-march=armv8-a+sme}"
+    array set supported_svl {}
+
+    # Compile the SME vector length test.
+    set result [gdb_compile $src $test_exec executable [list debug ${compile_flags} nowarnings]]
+
+    if {$result != ""} {
+	verbose -log "Failed to compile SME information gathering test."
+	return [array get supported_svl]
+    }
+
+    clean_restart $test_exec
+
+    if {![runto_main]} {
+	return [array get supported_svl]
+    }
+
+    set stop_breakpoint "stop here"
+    gdb_breakpoint [gdb_get_line_number $stop_breakpoint $src]
+    gdb_continue_to_breakpoint $stop_breakpoint
+
+    # Go through the data and extract the supported SME vector lengths.
+    set svl_count [get_valueof "" "supported_svl_count" "0" \
+			       "fetch value of supported_svl_count"]
+    verbose -log "Found $svl_count supported SME vector length values"
+
+    for {set svl_index 0} {$svl_index < $svl_count} {incr svl_index} {
+	set test_svl [get_valueof "" "supported_svl\[$svl_index\]" "0" \
+				  "fetch value of supported_svl\[$svl_index\]"]
+
+	# Mark this streaming vector length as supported.
+	if {$test_svl != 0} {
+	    verbose -log "Found supported SME vector length $test_svl"
+	    set supported_svl($test_svl) 1
+	}
+    }
+
+    gdb_exit
+    verbose -log "Cleaning up"
+    remote_file build delete $test_exec
+
+    verbose -log "Done gathering information about AArch64 SME vector lengths."
+
+    # Return the array containing all of the supported SME svl values.
+    return [array get supported_svl]
+}
+
+#
+# Return 1 if the target supports SME svl LENGTH
+# Return 0 otherwise.
+#
+
+proc aarch64_supports_sme_svl { length } {
+
+    # Fetch the cached array of supported SME svl values.
+    array set supported_svl [aarch64_initialize_sme_information]
+
+    # Do we have the global values cached?
+    if {![info exists supported_svl($length)]} {
+	verbose -log "Target does not support SME svl $length"
+	return 0
+    }
+
+    # The target supports SME svl LENGTH.
+    return 1
+}
 
 # A helper that compiles a test case to see if __int128 is supported.
 proc gdb_int128_helper {lang} {