Skip to content

Commit c18784b

Browse files
committed
[lldb] [llgs] Implement the vKill packet
Implement the support for the vKill packet. This is the modern packet used by the GDB Remote Serial Protocol to kill one of the debugged processes. Unlike the `k` packet, it has well-defined semantics. The `vKill` packet takes the PID of the process to kill, and always replies with an `OK` reply (rather than the exit status, as LLGS does for `k` packets at the moment). Additionally, unlike the `k` packet it does not cause the connection to be terminated once the last process is killed — the client needs to close it explicitly. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D127667
1 parent e8fe7e9 commit c18784b

File tree

5 files changed

+101
-1
lines changed

5 files changed

+101
-1
lines changed

lldb/include/lldb/Utility/StringExtractorGDBRemote.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class StringExtractorGDBRemote : public StringExtractor {
136136
eServerPacketType_vAttachName,
137137
eServerPacketType_vCont,
138138
eServerPacketType_vCont_actions, // vCont?
139+
eServerPacketType_vKill,
139140
eServerPacketType_vRun,
140141

141142
eServerPacketType_stop_reason, // '?'

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

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
232232
return this->Handle_k(packet);
233233
});
234234

235+
RegisterMemberFunctionHandler(
236+
StringExtractorGDBRemote::eServerPacketType_vKill,
237+
&GDBRemoteCommunicationServerLLGS::Handle_vKill);
238+
235239
RegisterMemberFunctionHandler(
236240
StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore,
237241
&GDBRemoteCommunicationServerLLGS::Handle_qSaveCore);
@@ -482,6 +486,10 @@ GDBRemoteCommunicationServerLLGS::SendWResponse(
482486
LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(),
483487
*wait_status);
484488

489+
// If the process was killed through vKill, return "OK".
490+
if (m_vkilled_processes.find(process->GetID()) != m_vkilled_processes.end())
491+
return SendOKResponse();
492+
485493
StreamGDBRemote response;
486494
response.Format("{0:g}", *wait_status);
487495
if (bool(m_extensions_supported & NativeProcessProtocol::Extension::multiprocess))
@@ -1049,9 +1057,13 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited(
10491057
lldb::pid_t pid = process->GetID();
10501058
m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) {
10511059
m_debugged_processes.erase(pid);
1060+
auto vkill_it = m_vkilled_processes.find(pid);
1061+
if (vkill_it != m_vkilled_processes.end())
1062+
m_vkilled_processes.erase(vkill_it);
1063+
// Terminate the main loop only if vKill has not been used.
10521064
// When running in non-stop mode, wait for the vStopped to clear
10531065
// the notification queue.
1054-
if (m_debugged_processes.empty() && !m_non_stop) {
1066+
else if (m_debugged_processes.empty() && !m_non_stop) {
10551067
// Close the pipe to the inferior terminal i/o if we launched it and set
10561068
// one up.
10571069
MaybeCloseInferiorTerminalConnection();
@@ -1442,6 +1454,30 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) {
14421454
return SendContinueSuccessResponse();
14431455
}
14441456

1457+
GDBRemoteCommunication::PacketResult
1458+
GDBRemoteCommunicationServerLLGS::Handle_vKill(
1459+
StringExtractorGDBRemote &packet) {
1460+
StopSTDIOForwarding();
1461+
1462+
packet.SetFilePos(6); // vKill;
1463+
uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
1464+
if (pid == LLDB_INVALID_PROCESS_ID)
1465+
return SendIllFormedResponse(packet,
1466+
"vKill failed to parse the process id");
1467+
1468+
auto it = m_debugged_processes.find(pid);
1469+
if (it == m_debugged_processes.end())
1470+
return SendErrorResponse(42);
1471+
1472+
Status error = it->second->Kill();
1473+
if (error.Fail())
1474+
return SendErrorResponse(error.ToError());
1475+
1476+
// OK response is sent when the process dies.
1477+
m_vkilled_processes.insert(pid);
1478+
return PacketResult::Success;
1479+
}
1480+
14451481
GDBRemoteCommunication::PacketResult
14461482
GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR(
14471483
StringExtractorGDBRemote &packet) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <mutex>
1313
#include <unordered_map>
14+
#include <unordered_set>
1415

1516
#include "lldb/Core/Communication.h"
1617
#include "lldb/Host/MainLoop.h"
@@ -95,6 +96,7 @@ class GDBRemoteCommunicationServerLLGS
9596
std::recursive_mutex m_debugged_process_mutex;
9697
std::unordered_map<lldb::pid_t, std::unique_ptr<NativeProcessProtocol>>
9798
m_debugged_processes;
99+
std::unordered_set<lldb::pid_t> m_vkilled_processes;
98100

99101
Communication m_stdio_communication;
100102
MainLoop::ReadHandleUP m_stdio_handle_up;
@@ -129,6 +131,8 @@ class GDBRemoteCommunicationServerLLGS
129131

130132
PacketResult Handle_k(StringExtractorGDBRemote &packet);
131133

134+
PacketResult Handle_vKill(StringExtractorGDBRemote &packet);
135+
132136
PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
133137

134138
PacketResult Handle_qC(StringExtractorGDBRemote &packet);

lldb/source/Utility/StringExtractorGDBRemote.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
372372
return eServerPacketType_vCont;
373373
if (PACKET_MATCHES("vCont?"))
374374
return eServerPacketType_vCont_actions;
375+
if (PACKET_STARTS_WITH("vKill;"))
376+
return eServerPacketType_vKill;
375377
if (PACKET_STARTS_WITH("vRun;"))
376378
return eServerPacketType_vRun;
377379
if (PACKET_MATCHES("vStopped"))

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,60 @@ def test_kill_all(self):
296296
ret = self.expect_gdbremote_sequence()
297297
self.assertEqual(set([ret["pid1"], ret["pid2"]]),
298298
set([parent_pid, child_pid]))
299+
300+
def vkill_test(self, kill_parent=False, kill_child=False):
301+
assert kill_parent or kill_child
302+
self.build()
303+
self.prep_debug_monitor_and_inferior(inferior_args=["fork"])
304+
self.add_qSupported_packets(["multiprocess+",
305+
"fork-events+"])
306+
ret = self.expect_gdbremote_sequence()
307+
self.assertIn("fork-events+", ret["qSupported_response"])
308+
self.reset_test_sequence()
309+
310+
# continue and expect fork
311+
self.test_sequence.add_log_lines([
312+
"read packet: $c#00",
313+
{"direction": "send", "regex": self.fork_regex.format("fork"),
314+
"capture": self.fork_capture},
315+
], True)
316+
ret = self.expect_gdbremote_sequence()
317+
parent_pid = ret["parent_pid"]
318+
parent_tid = ret["parent_tid"]
319+
child_pid = ret["child_pid"]
320+
child_tid = ret["child_tid"]
321+
self.reset_test_sequence()
322+
323+
if kill_parent:
324+
self.test_sequence.add_log_lines([
325+
# kill the process
326+
"read packet: $vKill;{}#00".format(parent_pid),
327+
"send packet: $OK#00",
328+
], True)
329+
if kill_child:
330+
self.test_sequence.add_log_lines([
331+
# kill the process
332+
"read packet: $vKill;{}#00".format(child_pid),
333+
"send packet: $OK#00",
334+
], True)
335+
self.test_sequence.add_log_lines([
336+
# check child PID/TID
337+
"read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
338+
"send packet: ${}#00".format("Eff" if kill_child else "OK"),
339+
# check parent PID/TID
340+
"read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
341+
"send packet: ${}#00".format("Eff" if kill_parent else "OK"),
342+
], True)
343+
self.expect_gdbremote_sequence()
344+
345+
@add_test_categories(["fork"])
346+
def test_vkill_child(self):
347+
self.vkill_test(kill_child=True)
348+
349+
@add_test_categories(["fork"])
350+
def test_vkill_parent(self):
351+
self.vkill_test(kill_parent=True)
352+
353+
@add_test_categories(["fork"])
354+
def test_vkill_both(self):
355+
self.vkill_test(kill_parent=True, kill_child=True)

0 commit comments

Comments
 (0)