diff options
-rw-r--r-- | gdb/remote.c | 10 | ||||
-rw-r--r-- | gdb/testsuite/gdb.server/attach-flag.c | 29 | ||||
-rw-r--r-- | gdb/testsuite/gdb.server/attach-flag.exp | 79 |
3 files changed, 117 insertions, 1 deletions
diff --git a/gdb/remote.c b/gdb/remote.c index 0dfe36a..c4a31e0 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -4609,7 +4609,15 @@ remote_target::process_initial_stop_replies (int from_tty) the inferiors. */ if (!non_stop) { - stop_all_threads (); + { + /* At this point, the remote target is not async. It needs to be for + the poll in stop_all_threads to consider events from it, so enable + it temporarily. */ + gdb_assert (!this->is_async_p ()); + SCOPE_EXIT { target_async (0); }; + target_async (1); + stop_all_threads (); + } /* If all threads of an inferior were already stopped, we haven't setup the inferior yet. */ diff --git a/gdb/testsuite/gdb.server/attach-flag.c b/gdb/testsuite/gdb.server/attach-flag.c new file mode 100644 index 0000000..f6ed618 --- /dev/null +++ b/gdb/testsuite/gdb.server/attach-flag.c @@ -0,0 +1,29 @@ +#include <pthread.h> +#include <unistd.h> + +static const int NTHREADS = 10; +static pthread_barrier_t barrier; + +static void * +thread_func (void *p) +{ + pthread_barrier_wait (&barrier); + return NULL; +} + +int +main (void) +{ + alarm (60); + + pthread_t threads[NTHREADS]; + pthread_barrier_init (&barrier, NULL, NTHREADS + 2); + + for (int i = 0; i < NTHREADS; i++) + pthread_create (&threads[i], NULL, thread_func, NULL); + + pthread_barrier_wait (&barrier); + + for (int i = 0; i < NTHREADS; i++) + pthread_join (threads[i], NULL); +} diff --git a/gdb/testsuite/gdb.server/attach-flag.exp b/gdb/testsuite/gdb.server/attach-flag.exp new file mode 100644 index 0000000..dc94938 --- /dev/null +++ b/gdb/testsuite/gdb.server/attach-flag.exp @@ -0,0 +1,79 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2021 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/>. + +# Test attaching to a multi-threaded process using gdbserver's --attach flag. + +load_lib gdbserver-support.exp + +standard_testfile + +if { [skip_gdbserver_tests] } { + return 0 +} + +if {![can_spawn_for_attach]} { + return 0 +} + +# Start the test program, attach to it using gdbserver's --attach flag, connect +# to it with GDB, check that what we see makes sense. + +proc run_one_test { non-stop target-non-stop } { + save_vars { ::GDBFLAGS } { + # If GDB and GDBserver are both running locally, set the sysroot to avoid + # reading files via the remote protocol. + if { ![is_remote host] && ![is_remote target] } { + set ::GDBFLAGS "$::GDBFLAGS -ex \"set sysroot\"" + } + + if { [prepare_for_testing "failed to prepare" $::testfile $::srcfile \ + {debug pthreads}] } { + return -1 + } + } + + # Make sure we're disconnected, in case we're testing with an + # extended-remote board, therefore already connected. + gdb_test "disconnect" ".*" + + set target_exec [gdbserver_download_current_prog] + set test_spawn_id [spawn_wait_for_attach $::binfile] + set testpid [spawn_id_get_pid $test_spawn_id] + + lassign [gdbserver_start "" "--attach $testpid"] unused gdbserver_address + + gdb_test_no_output "set non-stop ${non-stop}" + gdb_test_no_output "maint set target-non-stop ${target-non-stop}" + gdb_target_cmd "remote" $gdbserver_address + + # There should be 11 threads. + gdb_test "thread 11" "Switching to thread 11.*" + + kill_wait_spawned_process $test_spawn_id + gdbserver_exit 0 +} + +foreach_with_prefix non-stop {0 1} { + foreach_with_prefix target-non-stop {0 1} { + # This combination does not make sense. + if { ${non-stop} == 1 && ${target-non-stop} == 0} { + continue + } + + run_one_test ${non-stop} ${target-non-stop} + } +} |