From: Andrew Burgess Date: Thu, 17 Jul 2025 14:50:51 +0000 (+0100) Subject: gdb: ensure thread state is updated when remote target starts up X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=390bbb28f339a3095f73d5ae9e39341956890879;p=thirdparty%2Fbinutils-gdb.git gdb: ensure thread state is updated when remote target starts up This patch fixes a bug that was exposed by a test added in the previous commit. After writing this patch I also discovered that this issue had been reported as PR gdb/27322. When 'maint set target-non-stop on' is in effect, then the remote targets will be running in non-stop mode. The previous commit revealed a bug where, in this mode, GDB can fail to copy the thread state from the target to the GDB frontend, this leaves the thread marked as running in the frontend, even though the thread is actually stopped. When this happens the user is no longer able to interrupt the thread (it's already stopped), nor can the user resume the thread (GDB thinks the threads is running). To reproduce the bug: gdb -q -ex 'maint set target-non-stop on' \ -ex 'set non-stop off' \ -ex 'set sysroot' \ -ex 'file /bin/ls' \ -ex 'run &' \ -ex 'add-inferior' \ -ex 'infer 2' \ -ex 'set sysroot' \ -ex 'target remote | gdbserver - ls' \ -ex 'info threads' The 'info threads' output will look something like: Id Target Id Frame 1.1 process 1746383 "ls" (running) * 2.1 Thread 1746389.1746389 "ls" 0x00007ffff7fd3110 in _start () from /lib64/ld-linux-x86-64.so.2 The thread 1.1 should be stopped. GDB is running in all-stop mode after all. The problem is that in remote_target::process_initial_stop_replies, there is a call to stop_all_threads, however, the changes in the thread state are never copied back to the GDB frontend. This leaves the threads stopped, but still marked running. Solve this by adding a scoped_finish_thread_state. This is similar to how scoped_finish_thread_state is used in run_command_1 when we start a new inferior running. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27322 --- diff --git a/gdb/remote.c b/gdb/remote.c index 984b7166b7b..aa7e6e490b7 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -5028,6 +5028,24 @@ remote_target::process_initial_stop_replies (int from_tty) the inferiors. */ if (!non_stop) { + /* Ensure changes to the thread state are propagated to the + frontend. In non-stop mode only the current inferior will be + stopped, but in all-stop mode, all inferiors will change, and + the frontend will need updating. */ + process_stratum_target *finish_target; + ptid_t finish_ptid; + if (non_stop) + { + finish_target = current_inferior ()->process_target (); + finish_ptid = ptid_t (current_inferior ()->pid); + } + else + { + finish_target = nullptr; + finish_ptid = minus_one_ptid; + } + scoped_finish_thread_state finish_state (finish_target, finish_ptid); + { /* 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 diff --git a/gdb/testsuite/gdb.multi/remote-with-running-inferior.exp b/gdb/testsuite/gdb.multi/remote-with-running-inferior.exp index c08122379de..43842ba7062 100644 --- a/gdb/testsuite/gdb.multi/remote-with-running-inferior.exp +++ b/gdb/testsuite/gdb.multi/remote-with-running-inferior.exp @@ -77,15 +77,6 @@ proc run_test { target_non_stop non_stop } { set res [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] gdb_assert {$res == 0} "connect to remote target" - # FIXME: A bug in GDB means that the state of thread 1.1 will be wrong, - # GDB's frontend thinks that the thread is running when really the - # thread is stopped. This will be fixed in the next commit, at which - # point this whole 'if' will be removed. - if { $target_non_stop == "on" && $non_stop == "off" } { - gdb_test "p 1 + 2" " = 3" "check GDB is still alive" - return - } - # Check the info threads output. We're checking that we see the two # threads we expect, that the correct thread (inferior two's thread) # is current, and that none of the threads are running.