[llvm-branch-commits] [lldb] 2bbf724 - Implement vAttachWait in lldb-server

Pavel Labath via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jan 14 00:32:01 PST 2021


Author: Augusto Noronha
Date: 2021-01-14T09:25:15+01:00
New Revision: 2bbf724feea9824f9b9e4d20d34828023dbec2af

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

LOG: Implement vAttachWait in lldb-server

This commit vAttachWait in lldb-server, so --waitfor can be used on
Linux

Reviewed By: labath, clayborg

Differential Revision: https://reviews.llvm.org/D93895

Added: 
    lldb/test/API/tools/lldb-server/TestGdbRemoteAttachWait.py

Modified: 
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index c202fc9d339f..2c8bcf477f50 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -159,6 +159,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_vAttach,
       &GDBRemoteCommunicationServerLLGS::Handle_vAttach);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_vAttachWait,
+      &GDBRemoteCommunicationServerLLGS::Handle_vAttachWait);
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_vCont,
       &GDBRemoteCommunicationServerLLGS::Handle_vCont);
@@ -334,6 +337,71 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
   return Status();
 }
 
+Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
+    llvm::StringRef process_name) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+  std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1);
+
+  // Create the matcher used to search the process list.
+  ProcessInstanceInfoList exclusion_list;
+  ProcessInstanceInfoMatch match_info;
+  match_info.GetProcessInfo().GetExecutableFile().SetFile(
+      process_name, llvm::sys::path::Style::posix);
+  match_info.SetNameMatchType(NameMatch::EndsWith);
+
+  // Create the excluded process list before polling begins.
+  Host::FindProcesses(match_info, exclusion_list);
+  LLDB_LOG(log, "placed '{0}' processes in the exclusion list.",
+           exclusion_list.size());
+
+  LLDB_LOG(log, "waiting for '{0}' to appear", process_name);
+
+  auto is_in_exclusion_list =
+      [&exclusion_list](const ProcessInstanceInfo &info) {
+        for (auto &excluded : exclusion_list) {
+          if (excluded.GetProcessID() == info.GetProcessID())
+            return true;
+        }
+        return false;
+      };
+
+  ProcessInstanceInfoList loop_process_list;
+  while (true) {
+    loop_process_list.clear();
+    if (Host::FindProcesses(match_info, loop_process_list)) {
+      // Remove all the elements that are in the exclusion list.
+      llvm::erase_if(loop_process_list, is_in_exclusion_list);
+
+      // One match! We found the desired process.
+      if (loop_process_list.size() == 1) {
+        auto matching_process_pid = loop_process_list[0].GetProcessID();
+        LLDB_LOG(log, "found pid {0}", matching_process_pid);
+        return AttachToProcess(matching_process_pid);
+      }
+
+      // Multiple matches! Return an error reporting the PIDs we found.
+      if (loop_process_list.size() > 1) {
+        StreamString error_stream;
+        error_stream.Format(
+            "Multiple executables with name: '{0}' found. Pids: ",
+            process_name);
+        for (size_t i = 0; i < loop_process_list.size() - 1; ++i) {
+          error_stream.Format("{0}, ", loop_process_list[i].GetProcessID());
+        }
+        error_stream.Format("{0}.", loop_process_list.back().GetProcessID());
+
+        Status error;
+        error.SetErrorString(error_stream.GetString());
+        return error;
+      }
+    }
+    // No matches, we have not found the process. Sleep until next poll.
+    LLDB_LOG(log, "sleep {0} seconds", polling_interval);
+    std::this_thread::sleep_for(polling_interval);
+  }
+}
+
 void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
     NativeProcessProtocol *process) {
   assert(process && "process cannot be NULL");
@@ -3188,6 +3256,36 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach(
   return SendStopReasonForState(m_debugged_process_up->GetState());
 }
 
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttachWait(
+    StringExtractorGDBRemote &packet) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+  // Consume the ';' after the identifier.
+  packet.SetFilePos(strlen("vAttachWait"));
+
+  if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+    return SendIllFormedResponse(packet, "vAttachWait missing expected ';'");
+
+  // Allocate the buffer for the process name from vAttachWait.
+  std::string process_name;
+  if (!packet.GetHexByteString(process_name))
+    return SendIllFormedResponse(packet,
+                                 "vAttachWait failed to parse process name");
+
+  LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+  Status error = AttachWaitProcess(process_name);
+  if (error.Fail()) {
+    LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+             error);
+    return SendErrorResponse(error);
+  }
+
+  // Notify we attached by sending a stop packet.
+  return SendStopReasonForState(m_debugged_process_up->GetState());
+}
+
 GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index ae8928c5d244..cdeba95b46ee 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -59,6 +59,17 @@ class GDBRemoteCommunicationServerLLGS
   ///     attach operation.
   Status AttachToProcess(lldb::pid_t pid);
 
+  /// Wait to attach to a process with a given name.
+  ///
+  /// This method supports waiting for the next instance of a process
+  /// with a given name and attaching llgs to that via the configured
+  /// Platform.
+  ///
+  /// \return
+  ///     An Status object indicating the success or failure of the
+  ///     attach operation.
+  Status AttachWaitProcess(llvm::StringRef process_name);
+
   // NativeProcessProtocol::NativeDelegate overrides
   void InitializeDelegate(NativeProcessProtocol *process) override;
 
@@ -170,6 +181,8 @@ class GDBRemoteCommunicationServerLLGS
 
   PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_vAttachWait(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_D(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet);

diff  --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteAttachWait.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteAttachWait.py
new file mode 100644
index 000000000000..d2ba674a8be6
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteAttachWait.py
@@ -0,0 +1,75 @@
+
+import os
+from time import sleep
+
+import gdbremote_testcase
+import lldbgdbserverutils
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestGdbRemoteAttachWait(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def test_attach_with_vAttachWait(self):
+        exe = '%s_%d' % (self.testMethodName, os.getpid())
+
+        def launch_inferior():
+            inferior = self.launch_process_for_attach(
+                inferior_args=["sleep:60"],
+                exe_path=self.getBuildArtifact(exe))
+            self.assertIsNotNone(inferior)
+            self.assertTrue(inferior.pid > 0)
+            self.assertTrue(
+                lldbgdbserverutils.process_is_running(
+                    inferior.pid, True))
+            return inferior
+
+        self.build(dictionary={'EXE': exe})
+        self.set_inferior_startup_attach_manually()
+
+        server = self.connect_to_debug_monitor()
+        self.assertIsNotNone(server)
+
+        # Launch the first inferior (we shouldn't attach to this one).
+        launch_inferior()
+        
+        self.add_no_ack_remote_stream()
+        self.test_sequence.add_log_lines([
+            # Do the attach.
+            "read packet: $vAttachWait;{}#00".format(lldbgdbserverutils.gdbremote_hex_encode_string(exe)),
+        ], True)
+        # Run the stream until attachWait.
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+
+        # Sleep so we're sure that the inferior is launched after we ask for the attach.
+        sleep(1)
+
+        # Launch the second inferior (we SHOULD attach to this one).
+        inferior_to_attach = launch_inferior()
+
+        # Make sure the attach succeeded.
+        self.test_sequence.add_log_lines([
+            {"direction": "send",
+             "regex": r"^\$T([0-9a-fA-F]{2})[^#]*#[0-9a-fA-F]{2}$",
+             "capture": {1: "stop_signal_hex"}},
+        ], True)
+        self.add_process_info_collection_packets()
+
+
+        # Run the stream sending the response..
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+
+        # Gather process info response.
+        process_info = self.parse_process_info_response(context)
+        self.assertIsNotNone(process_info)
+
+        # Ensure the process id matches what we expected.
+        pid_text = process_info.get('pid', None)
+        self.assertIsNotNone(pid_text)
+        reported_pid = int(pid_text, base=16)
+        self.assertEqual(reported_pid, inferior_to_attach.pid)


        


More information about the llvm-branch-commits mailing list