Index: lldb/include/lldb/Target/Process.h =================================================================== --- lldb/include/lldb/Target/Process.h +++ lldb/include/lldb/Target/Process.h @@ -687,6 +687,18 @@ "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 SaveCore(llvm::StringRef outfile) { + return false; + } + protected: virtual JITLoaderList &GetJITLoaders(); Index: lldb/source/Core/PluginManager.cpp =================================================================== --- lldb/source/Core/PluginManager.cpp +++ 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" @@ -685,6 +686,14 @@ Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, const FileSpec &outfile) { + // Try saving core directly from the process plugin first. + llvm::Expected 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) { Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -521,6 +521,8 @@ llvm::Expected> SendTraceGetBinaryData(const TraceGetBinaryDataRequest &request); + bool GetSaveCoreSupported() const; + protected: LazyBool m_supports_not_sending_acks; LazyBool m_supports_thread_suffix; @@ -558,6 +560,7 @@ LazyBool m_supports_QPassSignals; LazyBool m_supports_error_string_reply; LazyBool m_supports_multiprocess; + LazyBool m_supports_qSaveCore; bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1, m_supports_qUserName : 1, m_supports_qGroupName : 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 @@ -90,6 +90,7 @@ m_supports_QPassSignals(eLazyBoolCalculate), m_supports_error_string_reply(eLazyBoolCalculate), m_supports_multiprocess(eLazyBoolCalculate), + m_supports_qSaveCore(eLazyBoolCalculate), m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), m_supports_qUserName(true), m_supports_qGroupName(true), m_supports_qThreadStopInfo(true), m_supports_z0(true), @@ -294,6 +295,7 @@ 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; @@ -345,6 +347,7 @@ m_supports_qXfer_features_read = eLazyBoolNo; m_supports_qXfer_memory_map_read = eLazyBoolNo; m_supports_multiprocess = eLazyBoolNo; + m_supports_qSaveCore = eLazyBoolNo; m_supports_qEcho = eLazyBoolNo; m_supports_QPassSignals = eLazyBoolNo; @@ -392,6 +395,8 @@ m_supports_QPassSignals = eLazyBoolYes; else if (x == "multiprocess+") m_supports_multiprocess = 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 @@ -534,6 +539,10 @@ 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; Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -230,6 +230,8 @@ std::string HarmonizeThreadIdsForProfileData( StringExtractorGDBRemote &inputStringExtractor); + llvm::Expected SaveCore(llvm::StringRef outfile) override; + protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -5062,6 +5062,54 @@ BuildDynamicRegisterInfo(true); } +llvm::Expected ProcessGDBRemote::SaveCore(llvm::StringRef outfile) { + if (!m_gdb_comm.GetSaveCoreSupported()) + return false; + + // TODO: path-hint + std::string packet{"qSaveCore"}; + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, false) == + 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 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)); + + // 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