diff options
author | Pedro Alves <pedro@palves.net> | 2021-01-06 02:19:38 +0000 |
---|---|---|
committer | Pedro Alves <pedro@palves.net> | 2021-02-03 01:14:46 +0000 |
commit | b0083dd72fcff6ac3cd8ae10d104cf714e5e32aa (patch) | |
tree | 834d4ebbe8d24c43f4abbb26367500e0a0c5a751 /gdbserver/server.cc | |
parent | 92234eb192f11b1981acb46a3a5e725360b89d6f (diff) | |
download | gdb-b0083dd72fcff6ac3cd8ae10d104cf714e5e32aa.zip gdb-b0083dd72fcff6ac3cd8ae10d104cf714e5e32aa.tar.gz gdb-b0083dd72fcff6ac3cd8ae10d104cf714e5e32aa.tar.bz2 |
Fix a couple vStopped pending ack bugs
A following patch will add a testcase that has two processes with
threads stepping over a breakpoint continuously, and then detaches
from one of the processes while threads are running. The other
process continues stepping over its breakpoint. And then the testcase
sends a SIGUSR1, expecting that GDB reports it. That would sometimes
hang against gdbserver, due to the bugs fixed here. Both bugs are
related, in that they're about remote protocol asynchronous Stop
notifications. There's a bug in GDB, and another in GDBserver.
The GDB bug:
- when we detach from a process, the remote target discards any
pending RSP notification related to that process, including the
in-flight, yet-unacked notification. Discarding the in-flight
notification is the problem. Until the in-flight notification is
acked with a vStopped packet, the server won't send another %Stop
notification. As a result, the debug session gets messed up. In
the new testcase's case, GDB would hang inside stop_all_threads,
waiting for a stop for one of the process'es threads, which never
arrived -- its stop reply was permanently stuck in the stop reply
queue, waiting for a vStopped packet that never arrived.
In summary:
1. GDBserver sends stop notification about thread X, the remote
target receives it and stores it
2. At the same time, GDB detaches thread X's inferior
3. The remote target discards the received stop notification
4. GDBserver waits forever for the ack
The GDBserver bug:
GDBserver has the opposite bug. It also discards notifications for
the process being detached. If that discards the head of the
notification queue, when gdb sends an ack, it ends up acking the
_next_ notification. Meaning, gdb loses one notification. In the
testcase, this results in a similar hang in stop_all_threads.
So we have two very similar bugs in GDB and GDBserver, both resulting
in a similar symptom. That's why I'm fixing them both at the same
time.
gdb/ChangeLog:
* remote.c (remote_notif_stop_ack): Don't error out on
TARGET_WAITKIND_IGNORE; instead, just ignore the notification.
(remote_target::discard_pending_stop_replies): Don't delete
in-flight notification; instead, clear its contents.
gdbserver/ChangeLog:
* server.cc (discard_queued_stop_replies): Don't ever discard the
notification at the head of the list.
Diffstat (limited to 'gdbserver/server.cc')
-rw-r--r-- | gdbserver/server.cc | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/gdbserver/server.cc b/gdbserver/server.cc index 77e89fe..a5497e9 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -203,6 +203,15 @@ discard_queued_stop_replies (ptid_t ptid) next = iter; ++next; + if (iter == notif_stop.queue.begin ()) + { + /* The head of the list contains the notification that was + already sent to GDB. So we can't remove it, otherwise + when GDB sends the vStopped, it would ack the _next_ + notification, which hadn't been sent yet! */ + continue; + } + if (remove_all_on_match_ptid (*iter, ptid)) { delete *iter; |