[lldb] [llgs] Fix disabling non-stop mode

Stop all processes and clear notification queues when disabling non-stop
mode.  Ensure that no stop notifications are sent for processes stopped
due to the mode switch.

Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.llvm.org/D128893
This commit is contained in:
Michał Górny 2022-06-30 10:47:15 +02:00
parent 5d6659739c
commit c732afa2c2
3 changed files with 67 additions and 1 deletions

View File

@ -1919,6 +1919,20 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState(
bool force_synchronous) {
Log *log = GetLog(LLDBLog::Process);
if (m_disabling_non_stop) {
// Check if we are waiting for any more processes to stop. If we are,
// do not send the OK response yet.
for (const auto &it : m_debugged_processes) {
if (it.second.process_up->IsRunning())
return PacketResult::Success;
}
// If all expected processes were stopped after a QNonStop:0 request,
// send the OK response.
m_disabling_non_stop = false;
return SendOKResponse();
}
switch (process_state) {
case eStateAttaching:
case eStateLaunching:
@ -3903,12 +3917,33 @@ GDBRemoteCommunicationServerLLGS::Handle_qSaveCore(
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_QNonStop(
StringExtractorGDBRemote &packet) {
Log *log = GetLog(LLDBLog::Process);
StringRef packet_str{packet.GetStringRef()};
assert(packet_str.startswith("QNonStop:"));
packet_str.consume_front("QNonStop:");
if (packet_str == "0") {
for (auto &process_it : m_debugged_processes) {
if (process_it.second.process_up->IsRunning()) {
assert(m_non_stop);
Status error = process_it.second.process_up->Interrupt();
if (error.Fail()) {
LLDB_LOG(log,
"while disabling nonstop, failed to halt process {0}: {1}",
process_it.first, error);
return SendErrorResponse(0x41);
}
// we must not send stop reasons after QNonStop
m_disabling_non_stop = true;
}
}
m_stdio_notification_queue.clear();
m_stop_notification_queue.clear();
m_non_stop = false;
// TODO: stop all threads
// If we are stopping anything, defer sending the OK response until we're
// done.
if (m_disabling_non_stop)
return PacketResult::Success;
} else if (packet_str == "1") {
m_non_stop = true;
} else

View File

@ -117,6 +117,7 @@ protected:
bool m_thread_suffix_supported = false;
bool m_list_threads_in_stop_reply = false;
bool m_non_stop = false;
bool m_disabling_non_stop = false;
std::deque<std::string> m_stdio_notification_queue;
std::deque<std::string> m_stop_notification_queue;

View File

@ -362,3 +362,33 @@ class LldbGdbServerTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
"send packet: $OK#00",
], True)
self.expect_gdbremote_sequence()
@add_test_categories(["llgs"])
def test_leave_nonstop(self):
self.build()
self.set_inferior_startup_launch()
procs = self.prep_debug_monitor_and_inferior(
inferior_args=["thread:new", "thread:new", "stop", "sleep:15"])
self.test_sequence.add_log_lines(
["read packet: $QNonStop:1#00",
"send packet: $OK#00",
# stop is used to synchronize starting threads
"read packet: $c#63",
"send packet: $OK#00",
{"direction": "send", "regex": "%Stop:T.*"},
"read packet: $c#63",
"send packet: $OK#00",
# verify that the threads are running now
"read packet: $?#00",
"send packet: $OK#00",
"read packet: $QNonStop:0#00",
"send packet: $OK#00",
# we should issue some random request now to verify that the stub
# did not send stop reasons -- we may verify whether notification
# queue was cleared while at it
"read packet: $vStopped#00",
"send packet: $Eff#00",
"read packet: $?#00",
{"direction": "send", "regex": "[$]T.*"},
], True)
self.expect_gdbremote_sequence()