Skip to content

Commit e8fe7e9

Browse files
committed
[lldb] [llgs] Make k kill all processes, and fix multiple exits
Modify the behavior of the `k` packet to kill all inferiors rather than just the current one. The specification leaves the exact behavior of this packet up to the implementation but since vKill is specifically meant to be used to kill a single process, it seems logical to use `k` to provide the alternate function of killing all of them. Move starting stdio forwarding from the "running" response to the packet handlers that trigger the process to start. This avoids attempting to start it multiple times when multiple processes are killed on Linux which implicitly causes LLGS to receive "started" events for all of them. This is probably also more correct as the ability to send "O" packets is implied by the continue-like command being issued (and therefore the client waiting for responses) rather than the start notification. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D127500
1 parent 8ad4c6e commit e8fe7e9

File tree

2 files changed

+82
-33
lines changed

2 files changed

+82
-33
lines changed

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,17 +1041,26 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited(
10411041
__FUNCTION__, process->GetID());
10421042
}
10431043

1044-
// Close the pipe to the inferior terminal i/o if we launched it and set one
1045-
// up.
1046-
MaybeCloseInferiorTerminalConnection();
1047-
1048-
// When running in non-stop mode, wait for the vStopped to clear
1049-
// the notification queue.
1050-
if (!m_non_stop) {
1051-
// We are ready to exit the debug monitor.
1052-
m_exit_now = true;
1053-
m_mainloop.RequestTermination();
1054-
}
1044+
if (m_current_process == process)
1045+
m_current_process = nullptr;
1046+
if (m_continue_process == process)
1047+
m_continue_process = nullptr;
1048+
1049+
lldb::pid_t pid = process->GetID();
1050+
m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) {
1051+
m_debugged_processes.erase(pid);
1052+
// When running in non-stop mode, wait for the vStopped to clear
1053+
// the notification queue.
1054+
if (m_debugged_processes.empty() && !m_non_stop) {
1055+
// Close the pipe to the inferior terminal i/o if we launched it and set
1056+
// one up.
1057+
MaybeCloseInferiorTerminalConnection();
1058+
1059+
// We are ready to exit the debug monitor.
1060+
m_exit_now = true;
1061+
loop.RequestTermination();
1062+
}
1063+
});
10551064
}
10561065

10571066
void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped(
@@ -1094,7 +1103,6 @@ void GDBRemoteCommunicationServerLLGS::ProcessStateChanged(
10941103

10951104
switch (state) {
10961105
case StateType::eStateRunning:
1097-
StartSTDIOForwarding();
10981106
break;
10991107

11001108
case StateType::eStateStopped:
@@ -1219,7 +1227,7 @@ void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() {
12191227
return;
12201228

12211229
Status error;
1222-
lldbassert(!m_stdio_handle_up);
1230+
assert(!m_stdio_handle_up);
12231231
m_stdio_handle_up = m_mainloop.RegisterReadObject(
12241232
m_stdio_communication.GetConnection()->GetReadObject(),
12251233
[this](MainLoopBase &) { SendProcessOutput(); }, error);
@@ -1228,10 +1236,7 @@ void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() {
12281236
// Not much we can do about the failure. Log it and continue without
12291237
// forwarding.
12301238
if (Log *log = GetLog(LLDBLog::Process))
1231-
LLDB_LOGF(log,
1232-
"GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio "
1233-
"forwarding: %s",
1234-
__FUNCTION__, error.AsCString());
1239+
LLDB_LOG(log, "Failed to set up stdio forwarding: {0}", error);
12351240
}
12361241
}
12371242

@@ -1416,15 +1421,19 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) {
14161421

14171422
StopSTDIOForwarding();
14181423

1419-
if (!m_current_process) {
1424+
if (m_debugged_processes.empty()) {
14201425
LLDB_LOG(log, "No debugged process found.");
14211426
return PacketResult::Success;
14221427
}
14231428

1424-
Status error = m_current_process->Kill();
1425-
if (error.Fail())
1426-
LLDB_LOG(log, "Failed to kill debugged process {0}: {1}",
1427-
m_current_process->GetID(), error);
1429+
for (auto it = m_debugged_processes.begin(); it != m_debugged_processes.end();
1430+
++it) {
1431+
LLDB_LOG(log, "Killing process {0}", it->first);
1432+
Status error = it->second->Kill();
1433+
if (error.Fail())
1434+
LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", it->first,
1435+
error);
1436+
}
14281437

14291438
// The response to kill packet is undefined per the spec. LLDB
14301439
// follows the same rules as for continue packets, i.e. no response
@@ -1743,24 +1752,24 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason(
17431752
StringExtractorGDBRemote &packet) {
17441753
// Handle the $? gdbremote command.
17451754

1746-
// If no process, indicate error
1747-
if (!m_current_process)
1748-
return SendErrorResponse(02);
1749-
17501755
if (m_non_stop) {
17511756
// Clear the notification queue first, except for pending exit
17521757
// notifications.
17531758
llvm::erase_if(m_stop_notification_queue, [](const std::string &x) {
17541759
return x.front() != 'W' && x.front() != 'X';
17551760
});
17561761

1757-
// Queue stop reply packets for all active threads. Start with the current
1758-
// thread (for clients that don't actually support multiple stop reasons).
1759-
NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
1760-
if (thread)
1761-
m_stop_notification_queue.push_back(
1762-
PrepareStopReplyPacketForThread(*thread).GetString().str());
1763-
EnqueueStopReplyPackets(thread ? thread->GetID() : LLDB_INVALID_THREAD_ID);
1762+
if (m_current_process) {
1763+
// Queue stop reply packets for all active threads. Start with
1764+
// the current thread (for clients that don't actually support multiple
1765+
// stop reasons).
1766+
NativeThreadProtocol *thread = m_current_process->GetCurrentThread();
1767+
if (thread)
1768+
m_stop_notification_queue.push_back(
1769+
PrepareStopReplyPacketForThread(*thread).GetString().str());
1770+
EnqueueStopReplyPackets(thread ? thread->GetID()
1771+
: LLDB_INVALID_THREAD_ID);
1772+
}
17641773

17651774
// If the notification queue is empty (i.e. everything is running), send OK.
17661775
if (m_stop_notification_queue.empty())
@@ -1770,6 +1779,10 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason(
17701779
return SendPacketNoLock(m_stop_notification_queue.front());
17711780
}
17721781

1782+
// If no process, indicate error
1783+
if (!m_current_process)
1784+
return SendErrorResponse(02);
1785+
17731786
return SendStopReasonForState(*m_current_process,
17741787
m_current_process->GetState(),
17751788
/*force_synchronous=*/true);
@@ -4059,6 +4072,8 @@ void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions(
40594072

40604073
GDBRemoteCommunication::PacketResult
40614074
GDBRemoteCommunicationServerLLGS::SendContinueSuccessResponse() {
4075+
// TODO: how to handle forwarding in non-stop mode?
4076+
StartSTDIOForwarding();
40624077
return m_non_stop ? SendOKResponse() : PacketResult::Success;
40634078
}
40644079

lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,37 @@ def test_detach_all(self):
262262
"send packet: $Eff#00",
263263
], True)
264264
self.expect_gdbremote_sequence()
265+
266+
@add_test_categories(["fork"])
267+
def test_kill_all(self):
268+
self.build()
269+
self.prep_debug_monitor_and_inferior(inferior_args=["fork"])
270+
self.add_qSupported_packets(["multiprocess+",
271+
"fork-events+"])
272+
ret = self.expect_gdbremote_sequence()
273+
self.assertIn("fork-events+", ret["qSupported_response"])
274+
self.reset_test_sequence()
275+
276+
# continue and expect fork
277+
self.test_sequence.add_log_lines([
278+
"read packet: $c#00",
279+
{"direction": "send", "regex": self.fork_regex.format("fork"),
280+
"capture": self.fork_capture},
281+
], True)
282+
ret = self.expect_gdbremote_sequence()
283+
parent_pid = ret["parent_pid"]
284+
child_pid = ret["child_pid"]
285+
self.reset_test_sequence()
286+
287+
exit_regex = "[$]X09;process:([0-9a-f]+)#.*"
288+
self.test_sequence.add_log_lines([
289+
# kill all processes
290+
"read packet: $k#00",
291+
{"direction": "send", "regex": exit_regex,
292+
"capture": {1: "pid1"}},
293+
{"direction": "send", "regex": exit_regex,
294+
"capture": {1: "pid2"}},
295+
], True)
296+
ret = self.expect_gdbremote_sequence()
297+
self.assertEqual(set([ret["pid1"], ret["pid2"]]),
298+
set([parent_pid, child_pid]))

0 commit comments

Comments
 (0)