mgorny updated this revision to Diff 340558.
mgorny retitled this revision from "[lldb] [llgs server] Support creating core 
dumps on NetBSD [WIP]" to "[lldb] [llgs server] Support creating core dumps on 
NetBSD".
mgorny added a comment.

Create a temporary file if `path-hint` is not provided.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D101285/new/

https://reviews.llvm.org/D101285

Files:
  lldb/include/lldb/Host/common/NativeProcessProtocol.h
  lldb/include/lldb/Utility/StringExtractorGDBRemote.h
  lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
  lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.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/TestGdbRemoteSaveCore.py

Index: lldb/test/API/tools/lldb-server/TestGdbRemoteSaveCore.py
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-server/TestGdbRemoteSaveCore.py
@@ -0,0 +1,60 @@
+import gdbremote_testcase
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+import binascii
+import os
+
+class TestGdbSaveCore(gdbremote_testcase.GdbRemoteTestCaseBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessPlatform(oslist=["netbsd"])
+    def test_netbsd_path(self):
+        self.build()
+        self.set_inferior_startup_attach()
+        procs = self.prep_debug_monitor_and_inferior()
+        self.add_qSupported_packets()
+        ret = self.expect_gdbremote_sequence()
+        self.assertIn("qSaveCore", ret["qSupported_response"])
+        self.reset_test_sequence()
+
+        core_path = lldbutil.append_to_process_working_directory(self, "core")
+        self.test_sequence.add_log_lines([
+            "read packet: $qSaveCore;path-hint:{}#00".format(
+                binascii.b2a_hex(core_path.encode()).decode()),
+            {"direction": "send", "regex": "[$]core-path:([0-9a-f]+)#.*",
+             "capture": {1: "path"}},
+        ], True)
+        ret = self.expect_gdbremote_sequence()
+        out_path = binascii.a2b_hex(ret["path"].encode()).decode()
+        self.assertEqual(core_path, out_path)
+
+        target = self.dbg.CreateTarget(None)
+        process = target.LoadCore(out_path)
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.assertEqual(process.GetProcessID(), procs["inferior"].pid)
+
+    @skipUnlessPlatform(oslist=["netbsd"])
+    def test_netbsd_no_path(self):
+        self.build()
+        self.set_inferior_startup_attach()
+        procs = self.prep_debug_monitor_and_inferior()
+        self.add_qSupported_packets()
+        ret = self.expect_gdbremote_sequence()
+        self.assertIn("qSaveCore", ret["qSupported_response"])
+        self.reset_test_sequence()
+
+        self.test_sequence.add_log_lines([
+            "read packet: $qSaveCore#00",
+            {"direction": "send", "regex": "[$]core-path:([0-9a-f]+)#.*",
+             "capture": {1: "path"}},
+        ], True)
+        ret = self.expect_gdbremote_sequence()
+        out_path = binascii.a2b_hex(ret["path"].encode()).decode()
+
+        target = self.dbg.CreateTarget(None)
+        process = target.LoadCore(out_path)
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.assertEqual(process.GetProcessID(), procs["inferior"].pid)
+        os.unlink(out_path)
Index: lldb/source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -253,6 +253,8 @@
       break;
 
     case 'S':
+      if (PACKET_STARTS_WITH("qSaveCore"))
+        return eServerPacketType_qLLDBSaveCore;
       if (PACKET_STARTS_WITH("qSpeedTest:"))
         return eServerPacketType_qSpeedTest;
       if (PACKET_MATCHES("qShlibInfoAddr"))
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -214,6 +214,8 @@
 
   PacketResult Handle_QPassSignals(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_qSaveCore(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_g(StringExtractorGDBRemote &packet);
 
   void SetCurrentThreadID(lldb::tid_t tid);
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -217,6 +217,10 @@
                           quit = true;
                           return this->Handle_k(packet);
                         });
+
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore,
+      &GDBRemoteCommunicationServerLLGS::Handle_qSaveCore);
 }
 
 void GDBRemoteCommunicationServerLLGS::SetLaunchInfo(const ProcessLaunchInfo &info) {
@@ -3414,6 +3418,41 @@
   return SendOKResponse();
 }
 
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qSaveCore(
+    StringExtractorGDBRemote &packet) {
+  // Fail if we don't have a current process.
+  if (!m_current_process ||
+      (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID))
+    return SendErrorResponse(Status("Process not running."));
+
+  std::string path_hint;
+
+  StringRef packet_str{packet.GetStringRef()};
+  bool cf = packet_str.consume_front("qSaveCore");
+  assert(cf);
+  if (packet_str.consume_front(";")) {
+    llvm::SmallVector<llvm::StringRef, 2> fields;
+    packet_str.split(fields, ';');
+
+    for (auto x : fields) {
+      if (x.consume_front("path-hint:"))
+        StringExtractor(x).GetHexByteString(path_hint);
+      else
+        return SendErrorResponse(Status("Unsupported qSaveCore option"));
+    }
+  }
+
+  llvm::Expected<std::string> ret = m_current_process->SaveCore(path_hint);
+  if (!ret)
+    return SendErrorResponse(std::move(ret.takeError()));
+
+  StreamString response;
+  response.PutCString("core-path:");
+  response.PutStringAsRawHex8(ret.get());
+  return SendPacketNoLock(response.GetString());
+}
+
 void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() {
   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
 
@@ -3608,6 +3647,8 @@
     ret.push_back("qXfer:auxv:read+");
   if (bool(plugin_features & Extension::libraries_svr4))
     ret.push_back("qXfer:libraries-svr4:read+");
+  if (bool(plugin_features & Extension::savecore))
+    ret.push_back("qSaveCore");
 
   // check for client features
   m_extensions_supported = {};
Index: lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -88,6 +88,8 @@
   static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
                               int data = 0, int *result = nullptr);
 
+  llvm::Expected<std::string> SaveCore(llvm::StringRef path_hint) override;
+
 private:
   MainLoop::SignalHandleUP m_sigchld_handle;
   ArchSpec m_arch;
Index: lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -136,7 +136,8 @@
 NativeProcessNetBSD::Extension
 NativeProcessNetBSD::Factory::GetSupportedExtensions() const {
   return Extension::multiprocess | Extension::fork | Extension::vfork |
-         Extension::pass_signals | Extension::auxv | Extension::libraries_svr4;
+         Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |
+         Extension::savecore;
 }
 
 // Public Instance Methods
@@ -1073,3 +1074,19 @@
     }
   }
 }
+
+llvm::Expected<std::string>
+NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {
+  llvm::SmallString<128> path{path_hint};
+  if (path.empty()) {
+    if (std::error_code errc =
+        llvm::sys::fs::createTemporaryFile("lldb", "core", path))
+      return llvm::createStringError(errc, "Unable to create a temporary file");
+  }
+
+  Status error = PtraceWrapper(PT_DUMPCORE, GetID(),
+                               const_cast<char *>(path.data()), path.size());
+  if (error.Fail())
+    return error.ToError();
+  return path.str().str();
+}
Index: lldb/include/lldb/Utility/StringExtractorGDBRemote.h
===================================================================
--- lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -167,6 +167,8 @@
     eServerPacketType_jLLDBTraceStop,
     eServerPacketType_jLLDBTraceGetState,
     eServerPacketType_jLLDBTraceGetBinaryData,
+
+    eServerPacketType_qLLDBSaveCore,
   };
 
   ServerPacketType GetServerPacketType() const;
Index: lldb/include/lldb/Host/common/NativeProcessProtocol.h
===================================================================
--- lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -243,8 +243,9 @@
     pass_signals = (1u << 3),
     auxv = (1u << 4),
     libraries_svr4 = (1u << 5),
+    savecore = (1u << 6),
 
-    LLVM_MARK_AS_BITMASK_ENUM(libraries_svr4)
+    LLVM_MARK_AS_BITMASK_ENUM(savecore)
   };
 
   class Factory {
@@ -362,6 +363,19 @@
     m_enabled_extensions = flags;
   }
 
+  /// Write a core dump (without crashing the program).
+  ///
+  /// \param[in] path_hint
+  ///     Suggested core dump path (optional, can be empty).
+  ///
+  /// \return
+  ///     Path to the core dump if successfully written, an error
+  ///     otherwise.
+  virtual llvm::Expected<std::string> SaveCore(llvm::StringRef path_hint) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Not implemented");
+  }
+
 protected:
   struct SoftwareBreakpoint {
     uint32_t ref_count;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to