[Lldb-commits] [lldb] c18784b - [lldb] [llgs] Implement the vKill packet

Michał Górny via lldb-commits lldb-commits at lists.llvm.org
Fri Jun 24 08:20:34 PDT 2022


Author: Michał Górny
Date: 2022-06-24T17:20:23+02:00
New Revision: c18784ba330ac0f57e6ec433cfa8317349c445ff

URL: https://github.com/llvm/llvm-project/commit/c18784ba330ac0f57e6ec433cfa8317349c445ff
DIFF: https://github.com/llvm/llvm-project/commit/c18784ba330ac0f57e6ec433cfa8317349c445ff.diff

LOG: [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

Added: 
    

Modified: 
    lldb/include/lldb/Utility/StringExtractorGDBRemote.h
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
    lldb/source/Utility/StringExtractorGDBRemote.cpp
    lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index 2a63212e9d287..c32ce0389116e 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -136,6 +136,7 @@ class StringExtractorGDBRemote : public StringExtractor {
     eServerPacketType_vAttachName,
     eServerPacketType_vCont,
     eServerPacketType_vCont_actions, // vCont?
+    eServerPacketType_vKill,
     eServerPacketType_vRun,
 
     eServerPacketType_stop_reason, // '?'

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 434fb50862f8b..1ff0b7fe4ee5d 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -232,6 +232,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
                           return this->Handle_k(packet);
                         });
 
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_vKill,
+      &GDBRemoteCommunicationServerLLGS::Handle_vKill);
+
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore,
       &GDBRemoteCommunicationServerLLGS::Handle_qSaveCore);
@@ -482,6 +486,10 @@ GDBRemoteCommunicationServerLLGS::SendWResponse(
   LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(),
            *wait_status);
 
+  // If the process was killed through vKill, return "OK".
+  if (m_vkilled_processes.find(process->GetID()) != m_vkilled_processes.end())
+    return SendOKResponse();
+
   StreamGDBRemote response;
   response.Format("{0:g}", *wait_status);
   if (bool(m_extensions_supported & NativeProcessProtocol::Extension::multiprocess))
@@ -1049,9 +1057,13 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited(
   lldb::pid_t pid = process->GetID();
   m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) {
     m_debugged_processes.erase(pid);
+    auto vkill_it = m_vkilled_processes.find(pid);
+    if (vkill_it != m_vkilled_processes.end())
+      m_vkilled_processes.erase(vkill_it);
+    // Terminate the main loop only if vKill has not been used.
     // When running in non-stop mode, wait for the vStopped to clear
     // the notification queue.
-    if (m_debugged_processes.empty() && !m_non_stop) {
+    else if (m_debugged_processes.empty() && !m_non_stop) {
       // Close the pipe to the inferior terminal i/o if we launched it and set
       // one up.
       MaybeCloseInferiorTerminalConnection();
@@ -1442,6 +1454,30 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) {
   return SendContinueSuccessResponse();
 }
 
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vKill(
+    StringExtractorGDBRemote &packet) {
+  StopSTDIOForwarding();
+
+  packet.SetFilePos(6); // vKill;
+  uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16);
+  if (pid == LLDB_INVALID_PROCESS_ID)
+    return SendIllFormedResponse(packet,
+                                 "vKill failed to parse the process id");
+
+  auto it = m_debugged_processes.find(pid);
+  if (it == m_debugged_processes.end())
+    return SendErrorResponse(42);
+
+  Status error = it->second->Kill();
+  if (error.Fail())
+    return SendErrorResponse(error.ToError());
+
+  // OK response is sent when the process dies.
+  m_vkilled_processes.insert(pid);
+  return PacketResult::Success;
+}
+
 GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR(
     StringExtractorGDBRemote &packet) {

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index 6a2ef89e07d58..728334ac81698 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -11,6 +11,7 @@
 
 #include <mutex>
 #include <unordered_map>
+#include <unordered_set>
 
 #include "lldb/Core/Communication.h"
 #include "lldb/Host/MainLoop.h"
@@ -95,6 +96,7 @@ class GDBRemoteCommunicationServerLLGS
   std::recursive_mutex m_debugged_process_mutex;
   std::unordered_map<lldb::pid_t, std::unique_ptr<NativeProcessProtocol>>
       m_debugged_processes;
+  std::unordered_set<lldb::pid_t> m_vkilled_processes;
 
   Communication m_stdio_communication;
   MainLoop::ReadHandleUP m_stdio_handle_up;
@@ -129,6 +131,8 @@ class GDBRemoteCommunicationServerLLGS
 
   PacketResult Handle_k(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_vKill(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_qC(StringExtractorGDBRemote &packet);

diff  --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 17ab5ef21f58a..75fc74de4e215 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -372,6 +372,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
         return eServerPacketType_vCont;
       if (PACKET_MATCHES("vCont?"))
         return eServerPacketType_vCont_actions;
+      if (PACKET_STARTS_WITH("vKill;"))
+        return eServerPacketType_vKill;
       if (PACKET_STARTS_WITH("vRun;"))
         return eServerPacketType_vRun;
       if (PACKET_MATCHES("vStopped"))

diff  --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
index 8a3474ca78df1..a49a5b42c2ba8 100644
--- a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
@@ -296,3 +296,60 @@ def test_kill_all(self):
         ret = self.expect_gdbremote_sequence()
         self.assertEqual(set([ret["pid1"], ret["pid2"]]),
                          set([parent_pid, child_pid]))
+
+    def vkill_test(self, kill_parent=False, kill_child=False):
+        assert kill_parent or kill_child
+        self.build()
+        self.prep_debug_monitor_and_inferior(inferior_args=["fork"])
+        self.add_qSupported_packets(["multiprocess+",
+                                     "fork-events+"])
+        ret = self.expect_gdbremote_sequence()
+        self.assertIn("fork-events+", ret["qSupported_response"])
+        self.reset_test_sequence()
+
+        # continue and expect fork
+        self.test_sequence.add_log_lines([
+            "read packet: $c#00",
+            {"direction": "send", "regex": self.fork_regex.format("fork"),
+             "capture": self.fork_capture},
+        ], True)
+        ret = self.expect_gdbremote_sequence()
+        parent_pid = ret["parent_pid"]
+        parent_tid = ret["parent_tid"]
+        child_pid = ret["child_pid"]
+        child_tid = ret["child_tid"]
+        self.reset_test_sequence()
+
+        if kill_parent:
+            self.test_sequence.add_log_lines([
+                # kill the process
+                "read packet: $vKill;{}#00".format(parent_pid),
+                "send packet: $OK#00",
+            ], True)
+        if kill_child:
+            self.test_sequence.add_log_lines([
+                # kill the process
+                "read packet: $vKill;{}#00".format(child_pid),
+                "send packet: $OK#00",
+            ], True)
+        self.test_sequence.add_log_lines([
+            # check child PID/TID
+            "read packet: $Hgp{}.{}#00".format(child_pid, child_tid),
+            "send packet: ${}#00".format("Eff" if kill_child else "OK"),
+            # check parent PID/TID
+            "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid),
+            "send packet: ${}#00".format("Eff" if kill_parent else "OK"),
+        ], True)
+        self.expect_gdbremote_sequence()
+
+    @add_test_categories(["fork"])
+    def test_vkill_child(self):
+        self.vkill_test(kill_child=True)
+
+    @add_test_categories(["fork"])
+    def test_vkill_parent(self):
+        self.vkill_test(kill_parent=True)
+
+    @add_test_categories(["fork"])
+    def test_vkill_both(self):
+        self.vkill_test(kill_parent=True, kill_child=True)


        


More information about the lldb-commits mailing list