[Lldb-commits] [lldb] 25fbbc5 - [lldb] Support SaveCore() from gdb-remote client
Michał Górny via lldb-commits
lldb-commits at lists.llvm.org
Mon Sep 6 09:33:23 PDT 2021
Author: Michał Górny
Date: 2021-09-06T18:33:02+02:00
New Revision: 25fbbc5936c0e05095618f4b80b303227fbb708b
URL: https://github.com/llvm/llvm-project/commit/25fbbc5936c0e05095618f4b80b303227fbb708b
DIFF: https://github.com/llvm/llvm-project/commit/25fbbc5936c0e05095618f4b80b303227fbb708b.diff
LOG: [lldb] Support SaveCore() from gdb-remote client
Extend PluginManager::SaveCore() to support saving core dumps
via Process plugins. Implement the client-side part of qSaveCore
request in the gdb-remote plugin, that creates the core dump
on the remote host and then uses vFile packets to transfer it.
Differential Revision: https://reviews.llvm.org/D101329
Added:
Modified:
lldb/include/lldb/Target/Process.h
lldb/source/Core/PluginManager.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py
Removed:
################################################################################
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index a11c8cbf87ec9..eb7ad99d5adf3 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -687,6 +687,18 @@ class Process : public std::enable_shared_from_this<Process>,
"Not implemented");
}
+ /// Save core dump into the specified file.
+ ///
+ /// \param[in] outfile
+ /// Path to store core dump in.
+ ///
+ /// \return
+ /// true if saved successfully, false if saving the core dump
+ /// is not supported by the plugin, error otherwise.
+ virtual llvm::Expected<bool> SaveCore(llvm::StringRef outfile) {
+ return false;
+ }
+
protected:
virtual JITLoaderList &GetJITLoaders();
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index f65ec9fae277f..d8cebc83005fe 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -12,6 +12,7 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Target/Process.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
@@ -687,6 +688,16 @@ Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp,
const FileSpec &outfile,
lldb::SaveCoreStyle &core_style,
const ConstString plugin_name) {
+ if (!plugin_name) {
+ // Try saving core directly from the process plugin first.
+ llvm::Expected<bool> ret = process_sp->SaveCore(outfile.GetPath());
+ if (!ret)
+ return Status(std::move(ret.takeError()));
+ if (ret.get())
+ return Status();
+ }
+
+ // Fall back to object plugins.
Status error;
auto &instances = GetObjectFileInstances().GetInstances();
for (auto &instance : instances) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index d3b9bc78ea102..c38a4ee19d152 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -257,6 +257,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
m_attach_or_wait_reply = eLazyBoolCalculate;
m_avoid_g_packets = eLazyBoolCalculate;
m_supports_multiprocess = eLazyBoolCalculate;
+ m_supports_qSaveCore = eLazyBoolCalculate;
m_supports_qXfer_auxv_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
@@ -312,6 +313,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_qEcho = eLazyBoolNo;
m_supports_QPassSignals = eLazyBoolNo;
m_supports_memory_tagging = eLazyBoolNo;
+ m_supports_qSaveCore = eLazyBoolNo;
m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
// not, we assume no limit
@@ -359,6 +361,8 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_multiprocess = eLazyBoolYes;
else if (x == "memory-tagging+")
m_supports_memory_tagging = eLazyBoolYes;
+ else if (x == "qSaveCore+")
+ m_supports_qSaveCore = eLazyBoolYes;
// Look for a list of compressions in the features list e.g.
// qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-
// deflate,lzma
@@ -501,6 +505,10 @@ LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported(
return eLazyBoolNo;
}
+bool GDBRemoteCommunicationClient::GetSaveCoreSupported() const {
+ return m_supports_qSaveCore == eLazyBoolYes;
+}
+
StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() {
// Get information on all threads at one using the "jThreadsInfo" packet
StructuredData::ObjectSP object_sp;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 06d4f4d0df087..63bccc8781c8a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -547,6 +547,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
SendTraceGetBinaryData(const TraceGetBinaryDataRequest &request,
std::chrono::seconds interrupt_timeout);
+ bool GetSaveCoreSupported() const;
+
protected:
LazyBool m_supports_not_sending_acks = eLazyBoolCalculate;
LazyBool m_supports_thread_suffix = eLazyBoolCalculate;
@@ -585,6 +587,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
LazyBool m_supports_error_string_reply = eLazyBoolCalculate;
LazyBool m_supports_multiprocess = eLazyBoolCalculate;
LazyBool m_supports_memory_tagging = eLazyBoolCalculate;
+ LazyBool m_supports_qSaveCore = eLazyBoolCalculate;
bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
m_supports_qUserName : 1, m_supports_qGroupName : 1,
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 71177a0811b07..a39e6eb0f3776 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5147,6 +5147,58 @@ void ProcessGDBRemote::HandleStopReply() {
BuildDynamicRegisterInfo(true);
}
+llvm::Expected<bool> ProcessGDBRemote::SaveCore(llvm::StringRef outfile) {
+ if (!m_gdb_comm.GetSaveCoreSupported())
+ return false;
+
+ StreamString packet;
+ packet.PutCString("qSaveCore;path-hint:");
+ packet.PutStringAsRawHex8(outfile);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ // TODO: grab error message from the packet? StringExtractor seems to
+ // be missing a method for that
+ if (response.IsErrorResponse())
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv("qSaveCore returned an error"));
+
+ std::string path;
+
+ // process the response
+ llvm::SmallVector<llvm::StringRef, 1> reply_data;
+ response.GetStringRef().split(reply_data, ';');
+ for (auto x : reply_data) {
+ if (x.consume_front("core-path:"))
+ StringExtractor(x).GetHexByteString(path);
+ }
+
+ // verify that we've gotten what we need
+ if (path.empty())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "qSaveCore returned no core path");
+
+ // now transfer the core file
+ FileSpec remote_core{llvm::StringRef(path)};
+ Platform &platform = *GetTarget().GetPlatform();
+ Status error = platform.GetFile(remote_core, FileSpec(outfile));
+
+ if (platform.IsRemote()) {
+ // NB: we unlink the file on error too
+ platform.Unlink(remote_core);
+ if (error.Fail())
+ return error.ToError();
+ }
+
+ return true;
+ }
+
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Unable to send qSaveCore");
+}
+
static const char *const s_async_json_packet_prefix = "JSON-async:";
static StructuredData::ObjectSP
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 69c2233f40e74..59c82722a1398 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -235,6 +235,8 @@ class ProcessGDBRemote : public Process,
void DidVForkDone() override;
void DidExec() override;
+ llvm::Expected<bool> SaveCore(llvm::StringRef outfile) override;
+
protected:
friend class ThreadGDBRemote;
friend class GDBRemoteCommunicationClient;
diff --git a/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py b/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py
index 7b6754972edfe..9897fb6b4910c 100644
--- a/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py
+++ b/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py
@@ -63,3 +63,31 @@ def test_save_windows_mini_dump(self):
self.assertTrue(self.dbg.DeleteTarget(target))
if (os.path.isfile(core)):
os.unlink(core)
+
+ @skipUnlessPlatform(["netbsd"])
+ def test_save_core_via_process_plugin(self):
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ core = self.getBuildArtifact("a.out.core")
+ try:
+ target = self.dbg.CreateTarget(exe)
+ breakpoint = target.BreakpointCreateByName("bar")
+ process = target.LaunchSimple(
+ None, None, self.get_process_working_directory())
+ self.assertEqual(process.GetState(), lldb.eStateStopped)
+ self.assertTrue(process.SaveCore(core))
+ self.assertTrue(os.path.isfile(core))
+ self.assertTrue(process.Kill().Success())
+ pid = process.GetProcessID()
+
+ target = self.dbg.CreateTarget(None)
+ process = target.LoadCore(core)
+ self.assertTrue(process, PROCESS_IS_VALID)
+ self.assertEqual(process.GetProcessID(), pid)
+
+ finally:
+ self.assertTrue(self.dbg.DeleteTarget(target))
+ try:
+ os.unlink(core)
+ except OSError:
+ pass
More information about the lldb-commits
mailing list