]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: ensure thread state is updated when remote target starts up
authorAndrew Burgess <aburgess@redhat.com>
Thu, 17 Jul 2025 14:50:51 +0000 (15:50 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Fri, 12 Sep 2025 16:57:08 +0000 (17:57 +0100)
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

gdb/remote.c
gdb/testsuite/gdb.multi/remote-with-running-inferior.exp

index 984b7166b7bec405be6c4621e13e3c5803666312..aa7e6e490b7dd6254cd876b5cf7faa8bb4f517fc 100644 (file)
@@ -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
index c08122379de94b01b6f9986ab9fb0cfb66dd313f..43842ba706256b4b863eabf648c24cca5faa4217 100644 (file)
@@ -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.