[Lldb-commits] [lldb] 37cbd81 - [lldb] [llgs server] Support creating core dumps on NetBSD
Michał Górny via lldb-commits
lldb-commits at lists.llvm.org
Mon Sep 6 03:16:34 PDT 2021
Author: Michał Górny
Date: 2021-09-06T12:16:14+02:00
New Revision: 37cbd817d3e2b8c673862e2eb262cad6dd3dd244
URL: https://github.com/llvm/llvm-project/commit/37cbd817d3e2b8c673862e2eb262cad6dd3dd244
DIFF: https://github.com/llvm/llvm-project/commit/37cbd817d3e2b8c673862e2eb262cad6dd3dd244.diff
LOG: [lldb] [llgs server] Support creating core dumps on NetBSD
Add a new SaveCore() process method that can be used to request a core
dump. This is currently implemented on NetBSD via the PT_DUMPCORE
ptrace(2) request, and enabled via 'savecore' extension.
Protocol-wise, a new qSaveCore packet is introduced. It accepts zero
or more semicolon-separated key:value options, invokes the core dump
and returns a key:value response. Currently the only option supported
is "path-hint", and the return value contains the "path" actually used.
The support for the feature is exposed via qSaveCore qSupported feature.
Differential Revision: https://reviews.llvm.org/D101285
Added:
lldb/test/API/tools/lldb-server/TestGdbRemoteSaveCore.py
Modified:
lldb/include/lldb/Host/common/NativeProcessProtocol.h
lldb/include/lldb/Utility/StringExtractorGDBRemote.h
lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
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
Removed:
################################################################################
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index 770149e3fb28..7c3458527616 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -250,8 +250,9 @@ class NativeProcessProtocol {
auxv = (1u << 4),
libraries_svr4 = (1u << 5),
memory_tagging = (1u << 6),
+ savecore = (1u << 7),
- LLVM_MARK_AS_BITMASK_ENUM(memory_tagging)
+ LLVM_MARK_AS_BITMASK_ENUM(savecore)
};
class Factory {
@@ -369,6 +370,19 @@ class NativeProcessProtocol {
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;
diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index c67c05bdf182..90b2837944cd 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -170,6 +170,8 @@ class StringExtractorGDBRemote : public StringExtractor {
eServerPacketType_qMemTags, // read memory tags
eServerPacketType_QMemTags, // write memory tags
+
+ eServerPacketType_qLLDBSaveCore,
};
ServerPacketType GetServerPacketType() const;
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
index c45ef5a3c82c..fd157a4b5c67 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -860,6 +860,7 @@ def add_qSupported_packets(self, client_features=[]):
"fork-events",
"vfork-events",
"memory-tagging",
+ "qSaveCore",
]
def parse_qSupported_response(self, context):
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
index 9ea1a16b8785..0420d00e39d6 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -136,7 +136,8 @@ NativeProcessNetBSD::Factory::Attach(
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,27 @@ void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork,
}
}
}
+
+llvm::Expected<std::string>
+NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {
+ llvm::SmallString<128> path{path_hint};
+ Status error;
+
+ // Try with the suggested path first.
+ if (!path.empty()) {
+ error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
+ if (!error.Fail())
+ return path.str().str();
+
+ // If the request errored, fall back to a generic temporary file.
+ }
+
+ if (std::error_code errc =
+ llvm::sys::fs::createTemporaryFile("lldb", "core", path))
+ return llvm::createStringError(errc, "Unable to create a temporary file");
+
+ error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());
+ if (error.Fail())
+ return error.ToError();
+ return path.str().str();
+}
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
index 90d32aa6069d..3f54d02a9075 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -88,6 +88,8 @@ class NativeProcessNetBSD : public NativeProcessELF {
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;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 8e1f6bc29a6f..5d0ce3a6ef85 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -226,6 +226,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
quit = true;
return this->Handle_k(packet);
});
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore,
+ &GDBRemoteCommunicationServerLLGS::Handle_qSaveCore);
}
void GDBRemoteCommunicationServerLLGS::SetLaunchInfo(const ProcessLaunchInfo &info) {
@@ -3604,6 +3608,41 @@ GDBRemoteCommunicationServerLLGS::Handle_QMemTags(
return status.Success() ? SendOKResponse() : SendErrorResponse(1);
}
+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));
@@ -3800,6 +3839,8 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures(
ret.push_back("qXfer:libraries-svr4:read+");
if (bool(plugin_features & Extension::memory_tagging))
ret.push_back("memory-tagging+");
+ if (bool(plugin_features & Extension::savecore))
+ ret.push_back("qSaveCore+");
// check for client features
m_extensions_supported = {};
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index 04d0605fe420..f054e37eae94 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -214,6 +214,8 @@ class GDBRemoteCommunicationServerLLGS
PacketResult Handle_QPassSignals(StringExtractorGDBRemote &packet);
+ PacketResult Handle_qSaveCore(StringExtractorGDBRemote &packet);
+
PacketResult Handle_g(StringExtractorGDBRemote &packet);
PacketResult Handle_qMemTags(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 29cf585bea56..727907595942 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -260,6 +260,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
break;
case 'S':
+ if (PACKET_STARTS_WITH("qSaveCore"))
+ return eServerPacketType_qLLDBSaveCore;
if (PACKET_STARTS_WITH("qSpeedTest:"))
return eServerPacketType_qSpeedTest;
if (PACKET_MATCHES("qShlibInfoAddr"))
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteSaveCore.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteSaveCore.py
new file mode 100644
index 000000000000..405a73bcdba8
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteSaveCore.py
@@ -0,0 +1,52 @@
+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__)
+
+ def coredump_test(self, core_path=None, expect_path=None):
+ 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()
+
+ packet = "$qSaveCore"
+ if core_path is not None:
+ packet += ";path-hint:{}".format(
+ binascii.b2a_hex(core_path.encode()).decode())
+
+ self.test_sequence.add_log_lines([
+ "read packet: {}#00".format(packet),
+ {"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()
+ if expect_path is not None:
+ self.assertEqual(out_path, expect_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_path(self):
+ core = lldbutil.append_to_process_working_directory(self, "core")
+ self.coredump_test(core, core)
+
+ @skipUnlessPlatform(oslist=["netbsd"])
+ def test_netbsd_no_path(self):
+ self.coredump_test()
+
+ @skipUnlessPlatform(oslist=["netbsd"])
+ def test_netbsd_bad_path(self):
+ self.coredump_test("/dev/null/cantwritehere")
More information about the lldb-commits
mailing list