mgorny created this revision.
mgorny added reviewers: labath, krytarowski, emaste, jingham.
Herald added a subscriber: arichardson.
Herald added a project: All.
mgorny requested review of this revision.

Prefer the modern vKill packet over k if the server reports multiprocess
support.  This ensures that when multiple processes are debugged over
a shared connection, only the correct one will be killed.

Sponsored by: The FreeBSD Foundation


https://reviews.llvm.org/D130341

Files:
  lldb/packages/Python/lldbsuite/test/gdbclientutils.py
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
  lldb/test/API/functionalities/gdb_remote_client/TestMultiprocess.py

Index: lldb/test/API/functionalities/gdb_remote_client/TestMultiprocess.py
===================================================================
--- lldb/test/API/functionalities/gdb_remote_client/TestMultiprocess.py
+++ lldb/test/API/functionalities/gdb_remote_client/TestMultiprocess.py
@@ -46,3 +46,97 @@
                          lldb.eStopReasonSignal)
         self.assertEqual(process.GetThreadByID(0x10204).stop_reason,
                          lldb.eStopReasonNone)
+
+    def test_kill_no_mp(self):
+        class MyResponder(MockGDBServerResponder):
+            got_vKill = False
+
+            def qfThreadInfo(self):
+                return "mp100.100"
+
+            def vKill(self, pid):
+                self.got_vKill = True
+                return "E01"
+
+            def k(self):
+                return "X01"
+
+        self.server.responder = MyResponder()
+        target = self.dbg.CreateTarget("")
+        process = self.connect(target)
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateStopped])
+        process.Kill()
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateExited])
+        self.assertPacketLogContains(["k"])
+        self.assertFalse(self.server.responder.got_vKill)
+        self.assertEqual(process.GetExitStatus(), 1)
+
+    def test_kill_mp(self):
+        class MyResponder(MockGDBServerResponder):
+            got_k = False
+
+            def __init__(self, test_case):
+                super().__init__()
+                self.test_case = test_case
+
+            def qSupported(self, client_supported):
+                self.test_case.assertIn("multiprocess+", client_supported)
+                return "multiprocess+;" + super().qSupported(client_supported)
+
+            def qfThreadInfo(self):
+                return "mp100.100"
+
+            def vKill(self, pid):
+                return "OK"
+
+            def k(self):
+                self.got_k = True
+                return "X00"
+
+        self.server.responder = MyResponder(self)
+        target = self.dbg.CreateTarget("")
+        process = self.connect(target)
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateStopped])
+        process.Kill()
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateExited])
+        self.assertPacketLogContains(["vKill;100"])
+        self.assertFalse(self.server.responder.got_k)
+        self.assertEqual(process.GetExitStatus(),
+                         lldbutil.get_signal_number("SIGKILL"))
+
+    def test_kill_mp_no_vKill(self):
+        class MyResponder(MockGDBServerResponder):
+            def __init__(self, test_case):
+                super().__init__()
+                self.test_case = test_case
+
+            def qSupported(self, client_supported):
+                self.test_case.assertIn("multiprocess+", client_supported)
+                return "multiprocess+;" + super().qSupported(client_supported)
+
+            def qC(self):
+                return "QC100"
+
+            def qfThreadInfo(self):
+                return "mp100.100"
+
+            def cont(self):
+                return "S02"
+
+            def k(self):
+                return "X01"
+
+        self.server.responder = MyResponder(self)
+        target = self.dbg.CreateTarget("")
+        process = self.connect(target)
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateStopped])
+        process.Kill()
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateExited])
+        self.assertPacketLogContains(["vKill;100", "k"])
+        self.assertEqual(process.GetExitStatus(), 1)
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -4252,8 +4252,27 @@
 
 llvm::Expected<int> GDBRemoteCommunicationClient::KillProcess(lldb::pid_t pid) {
   StringExtractorGDBRemote response;
+  StreamString packet;
   GDBRemoteCommunication::ScopedTimeout(*this, seconds(3));
 
+  if (m_supports_multiprocess == eLazyBoolYes &&
+      pid != LLDB_INVALID_PROCESS_ID) {
+    packet.Format("vKill;{0:x-}", pid);
+    if (SendPacketAndWaitForResponse(packet.GetString(), response,
+                                     GetPacketTimeout()) !=
+        PacketResult::Success)
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "failed to send vKill packet");
+
+    if (response.IsOKResponse())
+      return SIGKILL;
+
+    if (!response.IsUnsupportedResponse())
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "unexpected response to vKill packet: %s",
+                                     response.GetStringRef().str().c_str());
+  }
+
   if (SendPacketAndWaitForResponse("k", response, GetPacketTimeout()) !=
       PacketResult::Success)
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
Index: lldb/packages/Python/lldbsuite/test/gdbclientutils.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -212,6 +212,8 @@
             return self.vCtrlC()
         if packet == "vCont;t":
             return self.vContT()
+        if packet.startswith("vKill;"):
+            return self.vKill(int(packet[6:], 16))
         if packet == "k":
             return self.k()
 
@@ -363,6 +365,9 @@
     def k(self):
         return ["W01", self.RESPONSE_DISCONNECT]
 
+    def vKill(self, pid):
+        return ""
+
     """
     Raised when we receive a packet for which there is no default action.
     Override the responder class to implement behavior suitable for the test at
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to