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
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
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.