aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/remote.c10
-rw-r--r--gdb/testsuite/gdb.server/attach-flag.c29
-rw-r--r--gdb/testsuite/gdb.server/attach-flag.exp79
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}
+ }
+}