Message ID | 20250412050338.2260505-1-thiago.bauermann@linaro.org |
---|---|
State | New |
Headers | show |
Series | [v2] gdb/testsuite: Add gdb.arch/aarch64-sve-sigunwind.exp | expand |
On 4/12/25 06:03, Thiago Jung Bauermann wrote: > There's currently no test for unwinding the SVE registers from a signal > frame, so add one. > > Tested on aarch64-linux-gnu native. > --- > .../gdb.arch/aarch64-sve-sigunwind.c | 205 ++++++++++++++++++ > .../gdb.arch/aarch64-sve-sigunwind.exp | 106 +++++++++ > 2 files changed, 311 insertions(+) > create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.c > create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.exp > > Hello, > > This version addresses Luis' comments from v1. > > By using the testsuite's vector list, it's easy to return early in the .exp > file if the system supports only one vector length, and I don't hit the > corner case that Luis described anymore. > > I decided to make the test more complete by also checking the contents of > all registers in the SVE context of the signal frame. Unfortunately I get > the following failures: > > Running /path/to/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.exp ... > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z0.b.u contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z1.b.u contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z2.b.u contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z3.b.u contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z4.b.u contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z5.b.u contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p0 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p1 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p2 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p3 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p4 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p5 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p6 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p7 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p8 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p9 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p10 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p11 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p12 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p13 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p14 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p15 contents were correctly unwound > FAIL: gdb.arch/aarch64-sve-sigunwind.exp: ffr contents were correctly unwound > > === gdb Summary === > > # of expected passes 144 > # of unexpected failures 23 > > After some investigation, I suspect this is a bug in the kernel though. To > take GDB out of the picture, I wrote the following test program: > > https://people.linaro.org/~thiago.bauermann/sve/sve-sigunwind.c > > Running it in a QEMU VM with VL of 128 bits, I get: > > SVE context: vl = 16 > SVE context: flags = 0 > SVE context: Z0 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 > SVE context: Z1 = 0 0 0 0 0 0 3 232 0 0 0 0 0 0 3 232 > SVE context: Z2 = 0 0 0 0 0 0 0 0 0 0 235 17 78 62 96 0 > SVE context: Z3 = 0 0 0 0 0 0 0 0 0 0 202 159 237 8 8 128 > SVE context: Z4 = 0 0 0 0 0 0 0 56 0 0 202 159 237 8 0 64 > SVE context: Z5 = 0 0 0 0 0 0 16 0 0 0 0 0 0 0 0 9 > SVE context: Z6 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z7 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z8 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z9 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z10 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z11 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z12 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z13 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z14 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z15 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z16 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z17 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z18 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z19 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z20 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z21 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z22 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z23 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z24 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z25 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z26 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z27 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z28 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z29 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z30 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: Z31 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 > SVE context: P0 = 0 0 > SVE context: P1 = 0 0 > SVE context: P2 = 0 0 > SVE context: P3 = 0 0 > SVE context: P4 = 0 0 > SVE context: P5 = 0 0 > SVE context: P6 = 0 0 > SVE context: P7 = 0 0 > SVE context: P8 = 0 0 > SVE context: P9 = 0 0 > SVE context: P10 = 0 0 > SVE context: P11 = 0 0 > SVE context: P12 = 0 0 > SVE context: P13 = 0 0 > SVE context: P14 = 0 0 > SVE context: P15 = 0 0 > SVE context: FFR = 0 0 > > Maybe there's a bug in my test program as well? I couldn't find it, but > it's interesting that the registers with wrong contents are the same ones > that GDB gets. > > I'll investigate some more and report the problem on the kernel mailing > list if I don't find anything. In any case, I think it's worth to add the > test even with these failures. Interesting. I wonder if gdb is getting confused with the register set to use (FPSIMD/SVE) or with the payload size, and reading some garbage for the first 5 Z registers and the predicate ones. Might be worth checking what exactly the payload looks like when we force-update the vector length in the signal handler. Odd case anyway. In any case... > > Changes in v2: > - Use vector length list detected by the testsuite's helper to find two > valid vector lengths that the test can use (suggested by Luis). > - Test unwinding Z, P and FFR register contents, not just VG. > - Rename test files to aarch64-sve-sigunwind.{c,exp}. > > 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" > > base-commit: 4fa9476ad23d5868c2bc4c02dc1a73acaefbcbc2 ... this patch looks good to me as is. Thanks for the update and fixup. Tested-By: Luis Machado <luis.machado@arm.com> Approved-By: Luis Machado <luis.machado@arm.com>
Luis Machado <luis.machado@arm.com> writes: > On 4/12/25 06:03, Thiago Jung Bauermann wrote: >> I decided to make the test more complete by also checking the contents of >> all registers in the SVE context of the signal frame. Unfortunately I get >> the following failures: >> >> Running /path/to/gdb/testsuite/gdb.arch/aarch64-sve-sigunwind.exp ... >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z0.b.u contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z1.b.u contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z2.b.u contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z3.b.u contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z4.b.u contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $z5.b.u contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p0 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p1 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p2 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p3 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p4 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p5 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p6 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p7 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p8 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p9 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p10 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p11 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p12 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p13 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p14 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: $p15 contents were correctly unwound >> FAIL: gdb.arch/aarch64-sve-sigunwind.exp: ffr contents were correctly unwound >> >> === gdb Summary === >> >> # of expected passes 144 >> # of unexpected failures 23 >> >> After some investigation, I suspect this is a bug in the kernel though. To >> take GDB out of the picture, I wrote the following test program: >> >> https://people.linaro.org/~thiago.bauermann/sve/sve-sigunwind.c >> >> Running it in a QEMU VM with VL of 128 bits, I get: >> >> SVE context: vl = 16 >> SVE context: flags = 0 >> SVE context: Z0 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 >> SVE context: Z1 = 0 0 0 0 0 0 3 232 0 0 0 0 0 0 3 232 >> SVE context: Z2 = 0 0 0 0 0 0 0 0 0 0 235 17 78 62 96 0 >> SVE context: Z3 = 0 0 0 0 0 0 0 0 0 0 202 159 237 8 8 128 >> SVE context: Z4 = 0 0 0 0 0 0 0 56 0 0 202 159 237 8 0 64 >> SVE context: Z5 = 0 0 0 0 0 0 16 0 0 0 0 0 0 0 0 9 >> SVE context: Z6 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z7 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z8 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z9 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z10 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z11 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z12 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z13 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z14 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z15 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z16 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z17 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z18 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z19 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z20 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z21 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z22 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z23 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z24 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z25 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z26 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z27 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z28 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z29 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z30 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: Z31 = 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 >> SVE context: P0 = 0 0 >> SVE context: P1 = 0 0 >> SVE context: P2 = 0 0 >> SVE context: P3 = 0 0 >> SVE context: P4 = 0 0 >> SVE context: P5 = 0 0 >> SVE context: P6 = 0 0 >> SVE context: P7 = 0 0 >> SVE context: P8 = 0 0 >> SVE context: P9 = 0 0 >> SVE context: P10 = 0 0 >> SVE context: P11 = 0 0 >> SVE context: P12 = 0 0 >> SVE context: P13 = 0 0 >> SVE context: P14 = 0 0 >> SVE context: P15 = 0 0 >> SVE context: FFR = 0 0 >> >> Maybe there's a bug in my test program as well? I couldn't find it, but >> it's interesting that the registers with wrong contents are the same ones >> that GDB gets. >> >> I'll investigate some more and report the problem on the kernel mailing >> list if I don't find anything. In any case, I think it's worth to add the >> test even with these failures. > > Interesting. I wonder if gdb is getting confused with the register set to use (FPSIMD/SVE) or > with the payload size, and reading some garbage for the first 5 Z registers and the > predicate ones. If that is the case then I made the same mistake in my test program. I still haven't spotted it, but I'll keep looking. And in my program, I'm using the kernel's access macros from <asm/sigcontext.h> to rule out a mistake in GDB's hard-coded offsets. > Might be worth checking what exactly the payload looks like when we force-update the vector length > in the signal handler. Odd case anyway. > > In any case... <snip> > ... this patch looks good to me as is. Thanks for the update and fixup. > > Tested-By: Luis Machado <luis.machado@arm.com> > Approved-By: Luis Machado <luis.machado@arm.com> Thank you! Pushed as commit f844b66ad075.
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"