diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.c b/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.c
new file mode 100644
index 000000000000..c86beaf5dda0
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.c
@@ -0,0 +1,205 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2025 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 unwinding AArch64's SVE registers from a signal frame.   */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+static int second_vl = 0;
+
+static void
+initialize_sve_state_main ()
+{
+  __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.d");
+  __asm __volatile ("ptrue p1.d");
+  __asm __volatile ("ptrue p2.d");
+  __asm __volatile ("ptrue p3.d");
+  __asm __volatile ("ptrue p4.d");
+  __asm __volatile ("ptrue p5.d");
+  __asm __volatile ("ptrue p6.d");
+  __asm __volatile ("ptrue p7.d");
+  __asm __volatile ("ptrue p8.d");
+  __asm __volatile ("ptrue p9.d");
+  __asm __volatile ("ptrue p10.d");
+  __asm __volatile ("ptrue p11.d");
+  __asm __volatile ("ptrue p12.d");
+  __asm __volatile ("ptrue p13.d");
+  __asm __volatile ("ptrue p14.d");
+  __asm __volatile ("ptrue p15.d");
+  __asm __volatile ("setffr");
+}
+
+static void
+initialize_sve_state_sighandler ()
+{
+  __asm __volatile ("dup z0.b, -2");
+  __asm __volatile ("dup z1.b, -2");
+  __asm __volatile ("dup z2.b, -2");
+  __asm __volatile ("dup z3.b, -2");
+  __asm __volatile ("dup z4.b, -2");
+  __asm __volatile ("dup z5.b, -2");
+  __asm __volatile ("dup z6.b, -2");
+  __asm __volatile ("dup z7.b, -2");
+  __asm __volatile ("dup z8.b, -2");
+  __asm __volatile ("dup z9.b, -2");
+  __asm __volatile ("dup z10.b, -2");
+  __asm __volatile ("dup z11.b, -2");
+  __asm __volatile ("dup z12.b, -2");
+  __asm __volatile ("dup z13.b, -2");
+  __asm __volatile ("dup z14.b, -2");
+  __asm __volatile ("dup z15.b, -2");
+  __asm __volatile ("dup z16.b, -2");
+  __asm __volatile ("dup z17.b, -2");
+  __asm __volatile ("dup z18.b, -2");
+  __asm __volatile ("dup z19.b, -2");
+  __asm __volatile ("dup z20.b, -2");
+  __asm __volatile ("dup z21.b, -2");
+  __asm __volatile ("dup z22.b, -2");
+  __asm __volatile ("dup z23.b, -2");
+  __asm __volatile ("dup z24.b, -2");
+  __asm __volatile ("dup z25.b, -2");
+  __asm __volatile ("dup z26.b, -2");
+  __asm __volatile ("dup z27.b, -2");
+  __asm __volatile ("dup z28.b, -2");
+  __asm __volatile ("dup z29.b, -2");
+  __asm __volatile ("dup z30.b, -2");
+  __asm __volatile ("dup z31.b, -2");
+  __asm __volatile ("pfalse p0.b");
+  __asm __volatile ("pfalse p1.b");
+  __asm __volatile ("pfalse p2.b");
+  __asm __volatile ("pfalse p3.b");
+  __asm __volatile ("pfalse p4.b");
+  __asm __volatile ("pfalse p5.b");
+  __asm __volatile ("pfalse p6.b");
+  __asm __volatile ("pfalse p7.b");
+  __asm __volatile ("pfalse p8.b");
+  __asm __volatile ("pfalse p9.b");
+  __asm __volatile ("pfalse p10.b");
+  __asm __volatile ("pfalse p11.b");
+  __asm __volatile ("pfalse p12.b");
+  __asm __volatile ("pfalse p13.b");
+  __asm __volatile ("pfalse p14.b");
+  __asm __volatile ("pfalse p15.b");
+  __asm __volatile ("setffr");
+}
+
+/* Set new value for the SVE vector length.
+   Return the value that was set.  */
+
+static int
+set_vl (int vl)
+{
+  int rc;
+
+  rc = prctl (PR_SVE_SET_VL, vl, 0, 0, 0);
+  if (rc < 0)
+    {
+      perror ("FAILED to PR_SVE_SET_VL");
+      exit (EXIT_FAILURE);
+    }
+
+  return rc & PR_SVE_VL_LEN_MASK;
+}
+
+static void
+sighandler (int sig, siginfo_t *info, void *ucontext)
+{
+  /* Set vector length to the second value.  */
+  second_vl = set_vl (second_vl);
+  initialize_sve_state_sighandler ();
+  printf ("sighandler: second_vl = %d\n", second_vl); /* Break here.  */
+}
+
+int
+main (int argc, char *argv[])
+{
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: %s <first vl> <second vl>\n", argv[0]);
+      return 1;
+    }
+
+  int first_vl = atoi (argv[1]);
+  second_vl = atoi (argv[2]);
+
+  if (first_vl == 0 || second_vl == 0)
+    {
+      fprintf (stderr, "Invalid vector length.\n");
+      return 1;
+    }
+
+  /* Set vector length to the first value.  */
+  first_vl = set_vl (first_vl);
+
+  printf ("main: first_vl = %d\n", first_vl);
+
+  unsigned char buf[256];
+
+  /* Use an SVE register to make the kernel start saving the SVE bank.  */
+  asm volatile ("mov z0.b, #255\n\t"
+		"str z0, %0"
+		:
+		: "m" (buf)
+		: "z0", "memory");
+
+  initialize_sve_state_main ();
+
+  struct sigaction sigact;
+  sigact.sa_sigaction = sighandler;
+  sigact.sa_flags = SA_SIGINFO;
+  sigaction (SIGUSR1, &sigact, NULL);
+
+  kill (getpid (), SIGUSR1);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.exp b/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.exp
new file mode 100644
index 000000000000..32340bb53a33
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.exp
@@ -0,0 +1,106 @@
+# Copyright 2025 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 unwinding AArch64's SVE registers from a signal frame.
+
+require allow_aarch64_sve_tests
+# Remote targets can't communicate vector length changes to GDB via the RSP.
+require !gdb_protocol_is_remote
+
+set first_vl 0
+set second_vl 0
+
+# Find two valid VL values to use in the test.
+# The minimum supported VL is 16 bytes, maximum is 256 bytes, and VL can change
+# in increments of at least 16 bytes.
+for {set i 16} {$i <= 256} {incr i 16} {
+    if {![aarch64_supports_sve_vl $i]} {
+	continue
+    }
+
+    if {$first_vl == 0} {
+	set first_vl $i
+    } elseif {$second_vl == 0} {
+	set second_vl $i
+	break
+    }
+}
+
+if {$first_vl == 0 || $second_vl == 0} {
+    untested "test needs to support at least two vector lengths"
+    return
+}
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+	  [list debug additional_flags=-march=armv9-a]] } {
+    return
+}
+
+# We want SIGUSR1 to be delivered normally.
+gdb_test "handle SIGUSR1 nostop" \
+    [multi_line {Signal        Stop	Print	Pass to program	Description} \
+		{SIGUSR1       No	Yes	Yes		User defined signal 1}] \
+    "don't stop for SIGUSR1"
+
+set linespec ${srcfile}:[gdb_get_line_number "Break here."]
+gdb_test_no_output "set args $first_vl $second_vl"
+
+if ![runto ${linespec}] {
+    return
+}
+
+set first_vg [expr $first_vl/8]
+set second_vg [expr $second_vl/8]
+
+gdb_test "print \$vg" ". = $second_vg" "vg was changed"
+
+for {set row 0} {$row < 32} {incr row} {
+    set register_name "\$z${row}\.b\.u"
+    gdb_test "print sizeof $register_name" " = $second_vl" \
+	"size of $register_name in the signal handler"
+    gdb_test "print $register_name" ". = \\{254 <repeats $second_vl times>\\}" \
+	"$register_name contents in signal handler"
+}
+
+for {set row 0} {$row < 16} {incr row} {
+    set register_name "\$p${row}"
+    gdb_test "print $register_name" ". = \\{(0, ){[expr $second_vl/8 - 1]}0\\}" \
+	"$register_name contents in signal handler"
+}
+gdb_test "print \$ffr" ". = \\{(255, ){[expr $second_vl/8 - 1]}255\\}" \
+    "ffr contents in signal handler"
+
+gdb_test "frame function main" \
+    [multi_line "#$decimal  $hex in main \[^\r\n\]+" \
+		"$decimal\[ \t\]+kill \\(getpid \\(\\), SIGUSR1\\);"]
+
+gdb_test "print \$vg" ". = $first_vg" "vg was correctly unwound"
+
+for {set row 0} {$row < 32} {incr row} {
+    set register_name "\$z${row}\.b\.u"
+    gdb_test "print sizeof $register_name" " = $first_vl" \
+	"size of $register_name was correctly unwound"
+    gdb_test "print $register_name" ". = \\{255 <repeats $first_vl times>\\}" \
+	"$register_name contents were correctly unwound"
+}
+
+for {set row 0} {$row < 16} {incr row} {
+    set register_name "\$p${row}"
+    gdb_test "print $register_name" ". = \\{(1, ){[expr $first_vl/8 - 1]}1\\}" \
+	"$register_name contents were correctly unwound"
+}
+gdb_test "print \$ffr" ". = \\{(255, ){[expr $first_vl/8 - 1]}255\\}" \
+    "ffr contents were correctly unwound"
