From 4833d6dac6d942ad1613dc47af88669e0c6da829 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Fri, 23 Dec 2022 03:16:17 +0000 Subject: [PATCH] gdb/testsuite: Add test to exercise multi-threaded AArch64 SVE inferiors This testcase exercises two scenarios involving a multi-threaded inferior. In the first scenario, the secondary inferior thread changes its vector length and then hits a breakpoint. GDB then examines the SVE state. In the second one, the secondary inferior thread changes its vector length and then the main thread hits a breakpoint. GDB then switches to the secondary thread and examines the SVE state. --- gdb/testsuite/gdb.arch/aarch64-sve-threads.c | 125 ++++++++++++++++++ .../gdb.arch/aarch64-sve-threads.exp | 80 +++++++++++ 2 files changed, 205 insertions(+) create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-sve-threads.exp diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-threads.c b/gdb/testsuite/gdb.arch/aarch64-sve-threads.c new file mode 100644 index 00000000000..e46912d3f8c --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sve-threads.c @@ -0,0 +1,125 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2024 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 . */ + +/* Exercise AArch64's Scalable Vector Extension in a multi-threaded program. */ + +#include +#include +#include +#include +#include +#include + +/* For one of the tests, the thread needs to sleep after setting the vector + length. This variable is set by GDB. */ +volatile bool should_sleep = false; + +/* Used to signal to the main thread that the additional thread's vector length + was changed. */ +sem_t vl_changed; + +/* Start routine for the additional thread. Sets a new vector length, sleeps if + requested then restores the original vector length. */ + +static void * +thread_function (void *unused) +{ + unsigned int vl; + int rc; + + rc = prctl (PR_SVE_GET_VL, 0, 0, 0, 0); + if (rc < 0) + { + perror ("FAILED to PR_SVE_GET_VL"); + sem_post (&vl_changed); + return NULL; + } + + vl = rc & PR_SVE_VL_LEN_MASK; + + /* Decrease vector length by 16 bytes. */ + vl -= 16; + + rc = prctl (PR_SVE_SET_VL, vl, 0, 0, 0); + if (rc < 0) + { + perror ("FAILED to PR_SVE_SET_VL"); + sem_post (&vl_changed); + return NULL; + } + + /* Let the main thread continue. */ + rc = sem_post (&vl_changed); + if (rc != 0) + { + perror ("sem_post"); + return NULL; + } + + if (should_sleep) + sleep (10); + + /* Restore original vector length. */ + vl += 16; /* break here 1 */ + + rc = prctl (PR_SVE_SET_VL, vl, 0, 0, 0); + if (rc < 0) + { + perror ("FAILED to PR_SVE_SET_VL"); + return NULL; + } + + return NULL; /* break here 2 */ +} + +int +main (int argc, char **argv) +{ + pthread_t thread; + int rc; + + rc = sem_init (&vl_changed, 0, 0); + if (rc != 0) + { + perror ("sem_init"); + return 1; + } + + rc = pthread_create (&thread, NULL, thread_function, NULL); + if (rc != 0) + { + perror ("pthread_create"); + return 1; + } + + /* Wait until the additional thread changes it's vector length. */ + rc = sem_wait (&vl_changed); + if (rc != 0) + { + perror ("sem_wait"); + return 1; + } + + rc = pthread_join (thread, NULL); /* break here 3 */ + if (rc != 0) + { + perror ("pthread_join"); + return 1; + } + + return 0; +} diff --git a/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp b/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp new file mode 100644 index 00000000000..049eb24b1e6 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-sve-threads.exp @@ -0,0 +1,80 @@ +# Copyright 2024 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 . + +# Test a multi-threaded binary that uses SVE and changes the SVE vector +# length in the additional thread. + +require allow_aarch64_sve_tests + +standard_testfile +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + {debug pthreads}] == -1} { + return -1 +} + +if ![runto_main] { + return -1 +} + +# Get the original VG value. +set orig_vg [get_valueof "" {$vg} "0" "get value of VG register"] +set expected_vg [expr {$orig_vg - 2}] + +# Stop after the additional thread has changed its vector length. +gdb_breakpoint [gdb_get_line_number "break here 1"] +gdb_continue_to_breakpoint "break here 1" + +# If GDB and gdbserver don't agree on the thread's vector length, this +# command will fail. +gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register" + +gdb_test "print \$vg" ". = ${expected_vg}" "vg was changed to ${expected_vg}" + +# Stop after the additional thread has restored its original vector length. +gdb_breakpoint [gdb_get_line_number "break here 2"] +gdb_continue_to_breakpoint "break here 2" + +# Test that going back to the original vector length doesn't confuse GDB or +# gdbserver. +gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register again" + +gdb_test "print \$vg" ". = ${orig_vg}" "vg was changed back to ${orig_vg}" + +# Restart GDB to test a scenario where GDB switches to a thread that +# changed its vector length but hasn't hit any breakpoints yet. +clean_restart ${binfile} + +if ![runto_main] { + return -1 +} + +# Make the thread sleep after changing its vector length. +gdb_test_no_output -nopass "set var should_sleep = 1" "make thread sleep" + +# Stop in the main thread after the additional thread has changed its +# vector length. +gdb_breakpoint [gdb_get_line_number "break here 3"] +gdb_continue_to_breakpoint "break here 3" + +# The regexp accounts for two lines of output after the "Switching to thread" +# message. +gdb_test_lines "thread 2" "switch to another thread" \ + {\[Switching to thread 2 \(.*\)\]\r\n#0 [[:print:]]+} + +# Make sure everything is still fine. +gdb_test "print \$z0" " = {q = {u = {.*}}}" "print z0 register in thread 2" + +gdb_test "print \$vg" ". = ${expected_vg}" \ + "vg was changed to ${expected_vg} in thread 2" -- 2.47.2