Author: Jacob Lalonde Date: 2024-07-18T17:10:15-07:00 New Revision: 4120570dc408a6ccc7133b4bdbaf5cf6c4af9db7
URL: https://github.com/llvm/llvm-project/commit/4120570dc408a6ccc7133b4bdbaf5cf6c4af9db7 DIFF: https://github.com/llvm/llvm-project/commit/4120570dc408a6ccc7133b4bdbaf5cf6c4af9db7.diff LOG: [LLDB][SaveCore] Add SBSaveCoreOptions Object, and SBProcess::SaveCore() overload (#98403) This PR adds `SBSaveCoreOptions`, which is a container class for options when LLDB is taking coredumps. For this first iteration this container just keeps parity with the extant API of `file, style, plugin`. In the future this options object can be extended to allow users to take a subset of their core dumps. Added: lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i lldb/include/lldb/API/SBSaveCoreOptions.h lldb/include/lldb/Symbol/SaveCoreOptions.h lldb/source/API/SBSaveCoreOptions.cpp lldb/source/Symbol/SaveCoreOptions.cpp lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py Modified: lldb/bindings/headers.swig lldb/bindings/interfaces.swig lldb/include/lldb/API/LLDB.h lldb/include/lldb/API/SBDefines.h lldb/include/lldb/API/SBError.h lldb/include/lldb/API/SBFileSpec.h lldb/include/lldb/API/SBProcess.h lldb/include/lldb/Core/PluginManager.h lldb/include/lldb/lldb-private-interfaces.h lldb/source/API/CMakeLists.txt lldb/source/API/SBProcess.cpp lldb/source/Commands/CommandObjectProcess.cpp lldb/source/Core/PluginManager.cpp lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h lldb/source/Symbol/CMakeLists.txt lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py Removed: ################################################################################ diff --git a/lldb/bindings/headers.swig b/lldb/bindings/headers.swig index c91504604b6ac..c0dde905f986b 100644 --- a/lldb/bindings/headers.swig +++ b/lldb/bindings/headers.swig @@ -21,6 +21,7 @@ #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBCommunication.h" #include "lldb/API/SBCompileUnit.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBData.h" #include "lldb/API/SBDebugger.h" #include "lldb/API/SBDeclaration.h" diff --git a/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i b/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig index 0953f4c72a910..8a6fed95f0b72 100644 --- a/lldb/bindings/interfaces.swig +++ b/lldb/bindings/interfaces.swig @@ -25,6 +25,7 @@ %include "./interface/SBCommandReturnObjectDocstrings.i" %include "./interface/SBCommunicationDocstrings.i" %include "./interface/SBCompileUnitDocstrings.i" +%include "./interface/SBSaveCoreOptionsDocstrings.i" %include "./interface/SBDataDocstrings.i" %include "./interface/SBDebuggerDocstrings.i" %include "./interface/SBDeclarationDocstrings.i" @@ -101,6 +102,7 @@ %include "lldb/API/SBCommandReturnObject.h" %include "lldb/API/SBCommunication.h" %include "lldb/API/SBCompileUnit.h" +%include "lldb/API/SBSaveCoreOptions.h" %include "lldb/API/SBData.h" %include "lldb/API/SBDebugger.h" %include "lldb/API/SBDeclaration.h" diff --git a/lldb/include/lldb/API/LLDB.h b/lldb/include/lldb/API/LLDB.h index d8cc9f5067fe9..40368e036e0e4 100644 --- a/lldb/include/lldb/API/LLDB.h +++ b/lldb/include/lldb/API/LLDB.h @@ -57,6 +57,7 @@ #include "lldb/API/SBQueue.h" #include "lldb/API/SBQueueItem.h" #include "lldb/API/SBReproducer.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBSection.h" #include "lldb/API/SBSourceManager.h" #include "lldb/API/SBStatisticsOptions.h" diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index 87c0a1c3661ca..f42e2be558d2e 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -61,6 +61,7 @@ class LLDB_API SBCommandPluginInterface; class LLDB_API SBCommandReturnObject; class LLDB_API SBCommunication; class LLDB_API SBCompileUnit; +class LLDB_API SBSaveCoreOptions; class LLDB_API SBData; class LLDB_API SBDebugger; class LLDB_API SBDeclaration; diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h index 1a720a479d9a6..17f2c6c3027af 100644 --- a/lldb/include/lldb/API/SBError.h +++ b/lldb/include/lldb/API/SBError.h @@ -77,6 +77,7 @@ class LLDB_API SBError { friend class SBBreakpointName; friend class SBCommandReturnObject; friend class SBCommunication; + friend class SBSaveCoreOptions; friend class SBData; friend class SBDebugger; friend class SBFile; diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index beefa19ad7f36..36641843aabeb 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -78,6 +78,7 @@ class LLDB_API SBFileSpec { friend class SBTarget; friend class SBThread; friend class SBTrace; + friend class SBSaveCoreOptions; SBFileSpec(const lldb_private::FileSpec &fspec); diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h index a6ab7ae759918..778be79583990 100644 --- a/lldb/include/lldb/API/SBProcess.h +++ b/lldb/include/lldb/API/SBProcess.h @@ -378,6 +378,12 @@ class LLDB_API SBProcess { /// \param[in] file_name - The name of the file to save the core file to. lldb::SBError SaveCore(const char *file_name); + /// Save the state of the process with the desired settings + /// as defined in the options object. + /// + /// \param[in] options - The options to use when saving the core file. + lldb::SBError SaveCore(SBSaveCoreOptions &options); + /// Query the address load_addr and store the details of the memory /// region that contains it in the supplied SBMemoryRegionInfo object. /// To iterate over all memory regions use GetMemoryRegionList. diff --git a/lldb/include/lldb/API/SBSaveCoreOptions.h b/lldb/include/lldb/API/SBSaveCoreOptions.h new file mode 100644 index 0000000000000..b8659bf128a78 --- /dev/null +++ b/lldb/include/lldb/API/SBSaveCoreOptions.h @@ -0,0 +1,69 @@ +//===-- SBSaveCoreOptions.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_API_SBSAVECOREOPTIONS_H +#define LLDB_API_SBSAVECOREOPTIONS_H + +#include "lldb/API/SBDefines.h" +#include "lldb/Symbol/SaveCoreOptions.h" + +namespace lldb { + +class LLDB_API SBSaveCoreOptions { +public: + SBSaveCoreOptions(); + SBSaveCoreOptions(const lldb::SBSaveCoreOptions &rhs); + ~SBSaveCoreOptions() = default; + + const SBSaveCoreOptions &operator=(const lldb::SBSaveCoreOptions &rhs); + + /// Set the plugin name. Supplying null or empty string will reset + /// the option. + /// + /// \param plugin Name of the object file plugin. + SBError SetPluginName(const char *plugin); + + /// Get the Core dump plugin name, if set. + /// + /// \return The name of the plugin, or null if not set. + const char *GetPluginName() const; + + /// Set the Core dump style. + /// + /// \param style The style of the core dump. + void SetStyle(lldb::SaveCoreStyle style); + + /// Get the Core dump style, if set. + /// + /// \return The core dump style, or undefined if not set. + lldb::SaveCoreStyle GetStyle() const; + + /// Set the output file path + /// + /// \param output_file a + /// \class SBFileSpec object that describes the output file. + void SetOutputFile(SBFileSpec output_file); + + /// Get the output file spec + /// + /// \return The output file spec. + SBFileSpec GetOutputFile() const; + + /// Reset all options. + void Clear(); + +protected: + friend class SBProcess; + lldb_private::SaveCoreOptions &ref() const; + +private: + std::unique_ptr<lldb_private::SaveCoreOptions> m_opaque_up; +}; // SBSaveCoreOptions +} // namespace lldb + +#endif // LLDB_API_SBSAVECOREOPTIONS_H diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h index f2296e2920238..38a291d9f0afd 100644 --- a/lldb/include/lldb/Core/PluginManager.h +++ b/lldb/include/lldb/Core/PluginManager.h @@ -178,6 +178,8 @@ class PluginManager { static bool UnregisterPlugin(ObjectFileCreateInstance create_callback); + static bool IsRegisteredObjectFilePluginName(llvm::StringRef name); + static ObjectFileCreateInstance GetObjectFileCreateCallbackAtIndex(uint32_t idx); @@ -191,9 +193,7 @@ class PluginManager { GetObjectFileCreateMemoryCallbackForPluginName(llvm::StringRef name); static Status SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, - llvm::StringRef plugin_name); + const lldb_private::SaveCoreOptions &core_options); // ObjectContainer static bool RegisterPlugin( diff --git a/lldb/include/lldb/Symbol/SaveCoreOptions.h b/lldb/include/lldb/Symbol/SaveCoreOptions.h new file mode 100644 index 0000000000000..583bc1f483d04 --- /dev/null +++ b/lldb/include/lldb/Symbol/SaveCoreOptions.h @@ -0,0 +1,44 @@ +//===-- SaveCoreOptions.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H + +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" + +#include <optional> +#include <string> + +namespace lldb_private { + +class SaveCoreOptions { +public: + SaveCoreOptions(){}; + ~SaveCoreOptions() = default; + + lldb_private::Status SetPluginName(const char *name); + std::optional<std::string> GetPluginName() const; + + void SetStyle(lldb::SaveCoreStyle style); + lldb::SaveCoreStyle GetStyle() const; + + void SetOutputFile(lldb_private::FileSpec file); + const std::optional<lldb_private::FileSpec> GetOutputFile() const; + + void Clear(); + +private: + std::optional<std::string> m_plugin_name; + std::optional<lldb_private::FileSpec> m_file; + std::optional<lldb::SaveCoreStyle> m_style; +}; +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h index cdd9b51d9329c..10eaf1e6a5add 100644 --- a/lldb/include/lldb/lldb-private-interfaces.h +++ b/lldb/include/lldb/lldb-private-interfaces.h @@ -9,6 +9,7 @@ #ifndef LLDB_LLDB_PRIVATE_INTERFACES_H #define LLDB_LLDB_PRIVATE_INTERFACES_H +#include "lldb/Symbol/SaveCoreOptions.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" @@ -55,8 +56,7 @@ typedef ObjectFile *(*ObjectFileCreateMemoryInstance)( const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t offset); typedef bool (*ObjectFileSaveCore)(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, Status &error); typedef EmulateInstruction *(*EmulateInstructionCreateInstance)( const ArchSpec &arch, InstructionType inst_type); diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 6397101609315..a32bc58507d8e 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -56,6 +56,7 @@ add_lldb_library(liblldb SHARED ${option_framework} SBCommandReturnObject.cpp SBCommunication.cpp SBCompileUnit.cpp + SBSaveCoreOptions.cpp SBData.cpp SBDebugger.cpp SBDeclaration.cpp diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp index efb3c8def2796..b88f897ff5280 100644 --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -40,6 +40,7 @@ #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBMemoryRegionInfo.h" #include "lldb/API/SBMemoryRegionInfoList.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBScriptObject.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" @@ -1216,13 +1217,28 @@ bool SBProcess::IsInstrumentationRuntimePresent( lldb::SBError SBProcess::SaveCore(const char *file_name) { LLDB_INSTRUMENT_VA(this, file_name); - return SaveCore(file_name, "", SaveCoreStyle::eSaveCoreFull); + SBSaveCoreOptions options; + options.SetOutputFile(SBFileSpec(file_name)); + options.SetStyle(SaveCoreStyle::eSaveCoreFull); + return SaveCore(options); } lldb::SBError SBProcess::SaveCore(const char *file_name, const char *flavor, SaveCoreStyle core_style) { LLDB_INSTRUMENT_VA(this, file_name, flavor, core_style); + SBSaveCoreOptions options; + options.SetOutputFile(SBFileSpec(file_name)); + options.SetStyle(core_style); + SBError error = options.SetPluginName(flavor); + if (error.Fail()) + return error; + return SaveCore(options); +} + +lldb::SBError SBProcess::SaveCore(SBSaveCoreOptions &options) { + + LLDB_INSTRUMENT_VA(this, options); lldb::SBError error; ProcessSP process_sp(GetSP()); @@ -1239,10 +1255,7 @@ lldb::SBError SBProcess::SaveCore(const char *file_name, return error; } - FileSpec core_file(file_name); - FileSystem::Instance().Resolve(core_file); - error.ref() = PluginManager::SaveCore(process_sp, core_file, core_style, - flavor); + error.ref() = PluginManager::SaveCore(process_sp, options.ref()); return error; } diff --git a/lldb/source/API/SBSaveCoreOptions.cpp b/lldb/source/API/SBSaveCoreOptions.cpp new file mode 100644 index 0000000000000..6c3f74596203d --- /dev/null +++ b/lldb/source/API/SBSaveCoreOptions.cpp @@ -0,0 +1,85 @@ +//===-- SBSaveCoreOptions.cpp -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBSaveCoreOptions.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SaveCoreOptions.h" +#include "lldb/Utility/Instrumentation.h" + +#include "Utils.h" + +using namespace lldb; + +SBSaveCoreOptions::SBSaveCoreOptions() { + LLDB_INSTRUMENT_VA(this) + + m_opaque_up = std::make_unique<lldb_private::SaveCoreOptions>(); +} + +SBSaveCoreOptions::SBSaveCoreOptions(const SBSaveCoreOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +const SBSaveCoreOptions & +SBSaveCoreOptions::operator=(const SBSaveCoreOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +SBError SBSaveCoreOptions::SetPluginName(const char *name) { + LLDB_INSTRUMENT_VA(this, name); + lldb_private::Status error = m_opaque_up->SetPluginName(name); + return SBError(error); +} + +void SBSaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { + LLDB_INSTRUMENT_VA(this, style); + m_opaque_up->SetStyle(style); +} + +void SBSaveCoreOptions::SetOutputFile(lldb::SBFileSpec file_spec) { + LLDB_INSTRUMENT_VA(this, file_spec); + m_opaque_up->SetOutputFile(file_spec.ref()); +} + +const char *SBSaveCoreOptions::GetPluginName() const { + LLDB_INSTRUMENT_VA(this); + const auto name = m_opaque_up->GetPluginName(); + if (!name) + return nullptr; + return lldb_private::ConstString(name.value()).GetCString(); +} + +SBFileSpec SBSaveCoreOptions::GetOutputFile() const { + LLDB_INSTRUMENT_VA(this); + const auto file_spec = m_opaque_up->GetOutputFile(); + if (file_spec) + return SBFileSpec(file_spec.value()); + return SBFileSpec(); +} + +lldb::SaveCoreStyle SBSaveCoreOptions::GetStyle() const { + LLDB_INSTRUMENT_VA(this); + return m_opaque_up->GetStyle(); +} + +void SBSaveCoreOptions::Clear() { + LLDB_INSTRUMENT_VA(this); + m_opaque_up->Clear(); +} + +lldb_private::SaveCoreOptions &SBSaveCoreOptions::ref() const { + return *m_opaque_up.get(); +} diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index 8685d5761557b..50695af556939 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -1273,13 +1273,13 @@ class CommandObjectProcessSaveCore : public CommandObjectParsed { switch (short_option) { case 'p': - m_requested_plugin_name = option_arg.str(); + error = m_core_dump_options.SetPluginName(option_arg.data()); break; case 's': - m_requested_save_core_style = + m_core_dump_options.SetStyle( (lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum( option_arg, GetDefinitions()[option_idx].enum_values, - eSaveCoreUnspecified, error); + eSaveCoreUnspecified, error)); break; default: llvm_unreachable("Unimplemented option"); @@ -1289,13 +1289,11 @@ class CommandObjectProcessSaveCore : public CommandObjectParsed { } void OptionParsingStarting(ExecutionContext *execution_context) override { - m_requested_save_core_style = eSaveCoreUnspecified; - m_requested_plugin_name.clear(); + m_core_dump_options.Clear(); } // Instance variables to hold the values for command options. - SaveCoreStyle m_requested_save_core_style = eSaveCoreUnspecified; - std::string m_requested_plugin_name; + SaveCoreOptions m_core_dump_options; }; protected: @@ -1305,13 +1303,14 @@ class CommandObjectProcessSaveCore : public CommandObjectParsed { if (command.GetArgumentCount() == 1) { FileSpec output_file(command.GetArgumentAtIndex(0)); FileSystem::Instance().Resolve(output_file); - SaveCoreStyle corefile_style = m_options.m_requested_save_core_style; - Status error = - PluginManager::SaveCore(process_sp, output_file, corefile_style, - m_options.m_requested_plugin_name); + auto &core_dump_options = m_options.m_core_dump_options; + core_dump_options.SetOutputFile(output_file); + Status error = PluginManager::SaveCore(process_sp, core_dump_options); if (error.Success()) { - if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly || - corefile_style == SaveCoreStyle::eSaveCoreStackOnly) { + if (core_dump_options.GetStyle() == + SaveCoreStyle::eSaveCoreDirtyOnly || + core_dump_options.GetStyle() == + SaveCoreStyle::eSaveCoreStackOnly) { result.AppendMessageWithFormat( "\nModified-memory or stack-memory only corefile " "created. This corefile may \n" diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index b428370d7f333..759ef3a8afe02 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/Symbol/SaveCoreOptions.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" @@ -639,6 +640,18 @@ static ObjectFileInstances &GetObjectFileInstances() { return g_instances; } +bool PluginManager::IsRegisteredObjectFilePluginName(llvm::StringRef name) { + if (name.empty()) + return false; + + const auto &instances = GetObjectFileInstances().GetInstances(); + for (auto &instance : instances) { + if (instance.name == name) + return true; + } + return false; +} + bool PluginManager::RegisterPlugin( llvm::StringRef name, llvm::StringRef description, ObjectFileCreateInstance create_callback, @@ -689,12 +702,22 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName( } Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, - llvm::StringRef plugin_name) { - if (plugin_name.empty()) { + const lldb_private::SaveCoreOptions &options) { + Status error; + if (!options.GetOutputFile()) { + error.SetErrorString("No output file specified"); + return error; + } + + if (!process_sp) { + error.SetErrorString("Invalid process"); + return error; + } + + if (!options.GetPluginName().has_value()) { // Try saving core directly from the process plugin first. - llvm::Expected<bool> ret = process_sp->SaveCore(outfile.GetPath()); + llvm::Expected<bool> ret = + process_sp->SaveCore(options.GetOutputFile()->GetPath()); if (!ret) return Status(ret.takeError()); if (ret.get()) @@ -702,17 +725,20 @@ Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, } // Fall back to object plugins. - Status error; + const auto &plugin_name = options.GetPluginName().value_or(""); auto &instances = GetObjectFileInstances().GetInstances(); for (auto &instance : instances) { if (plugin_name.empty() || instance.name == plugin_name) { - if (instance.save_core && - instance.save_core(process_sp, outfile, core_style, error)) + if (instance.save_core && instance.save_core(process_sp, options, error)) return error; } } - error.SetErrorString( - "no ObjectFile plugins were able to save a core for this process"); + + // Check to see if any of the object file plugins tried and failed to save. + // If none ran, set the error message. + if (error.Success()) + error.SetErrorString( + "no ObjectFile plugins were able to save a core for this process"); return error; } diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 0dcb1bed23548..2c7005449f9d7 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -6519,14 +6519,15 @@ struct page_object { }; bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, Status &error) { - if (!process_sp) - return false; - - // Default on macOS is to create a dirty-memory-only corefile. + const lldb_private::SaveCoreOptions &options, + Status &error) { + auto core_style = options.GetStyle(); if (core_style == SaveCoreStyle::eSaveCoreUnspecified) core_style = SaveCoreStyle::eSaveCoreDirtyOnly; + // The FileSpec and Process are already checked in PluginManager::SaveCore. + assert(options.GetOutputFile().has_value()); + assert(process_sp); + const FileSpec outfile = options.GetOutputFile().value(); Target &target = process_sp->GetTarget(); const ArchSpec target_arch = target.GetArchitecture(); diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 55bc688126eb3..e7af90e28bc4b 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -62,8 +62,7 @@ class ObjectFileMachO : public lldb_private::ObjectFile { lldb_private::ModuleSpecList &specs); static bool SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error); static bool MagicBytesMatch(lldb::DataBufferSP data_sp, lldb::addr_t offset, diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index 7c875aa3223ed..faa144bfb5f6a 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -56,18 +56,20 @@ size_t ObjectFileMinidump::GetModuleSpecifications( } bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error) { - // Set default core style if it isn't set. + // Output file and process_sp are both checked in PluginManager::SaveCore. + assert(options.GetOutputFile().has_value()); + assert(process_sp); + + // Minidump defaults to stacks only. + SaveCoreStyle core_style = options.GetStyle(); if (core_style == SaveCoreStyle::eSaveCoreUnspecified) core_style = SaveCoreStyle::eSaveCoreStackOnly; - if (!process_sp) - return false; - llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open( - outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate); + options.GetOutputFile().value(), + File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate); if (!maybe_core_file) { error = maybe_core_file.takeError(); return false; diff --git a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h index b5c40445fe742..0cd31a0e482d5 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h +++ b/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h @@ -55,8 +55,7 @@ class ObjectFileMinidump : public lldb_private::PluginInterface { // Saves dump in Minidump file format static bool SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error); private: diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index be0020cad5bee..bda691ade8af0 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -355,11 +355,12 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( } bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error) { - core_style = eSaveCoreFull; - return SaveMiniDump(process_sp, outfile, error); + // Outfile and process_sp are validated by PluginManager::SaveCore + assert(options.GetOutputFile().has_value()); + assert(process_sp); + return SaveMiniDump(process_sp, options, error); } bool ObjectFilePECOFF::MagicBytesMatch(DataBufferSP data_sp) { diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index c59701fa65ec3..2eb2b3b774538 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -82,8 +82,7 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile { lldb_private::ModuleSpecList &specs); static bool SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error); static bool MagicBytesMatch(lldb::DataBufferSP data_sp); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp index e5cb36910dd25..61cd74da22223 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp @@ -21,11 +21,12 @@ namespace lldb_private { bool SaveMiniDump(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, + const SaveCoreOptions &core_options, lldb_private::Status &error) { if (!process_sp) return false; #ifdef _WIN32 + const auto &outfile = core_options.GetOutputFile().value(); HANDLE process_handle = ::OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_sp->GetID()); const std::string file_name = outfile.GetPath(); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h index 04b93e221362a..03c0ece306143 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h @@ -14,7 +14,7 @@ namespace lldb_private { bool SaveMiniDump(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, + const SaveCoreOptions &core_options, lldb_private::Status &error); } // namespace lldb_private diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt index ad3488dcdfcec..e49477df06c94 100644 --- a/lldb/source/Symbol/CMakeLists.txt +++ b/lldb/source/Symbol/CMakeLists.txt @@ -6,6 +6,7 @@ add_lldb_library(lldbSymbol NO_PLUGIN_DEPENDENCIES CompilerDecl.cpp CompilerDeclContext.cpp CompilerType.cpp + SaveCoreOptions.cpp DWARFCallFrameInfo.cpp DebugMacros.cpp DeclVendor.cpp diff --git a/lldb/source/Symbol/SaveCoreOptions.cpp b/lldb/source/Symbol/SaveCoreOptions.cpp new file mode 100644 index 0000000000000..0f6fdac1ce22e --- /dev/null +++ b/lldb/source/Symbol/SaveCoreOptions.cpp @@ -0,0 +1,53 @@ +//===-- SaveCoreOptions.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/SaveCoreOptions.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; + +Status SaveCoreOptions::SetPluginName(const char *name) { + Status error; + if (!name || !name[0]) { + m_plugin_name = std::nullopt; + return error; + } + + if (!PluginManager::IsRegisteredObjectFilePluginName(name)) { + error.SetErrorStringWithFormat( + "plugin name '%s' is not a valid ObjectFile plugin name", name); + return error; + } + + m_plugin_name = name; + return error; +} + +void SaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { m_style = style; } + +void SaveCoreOptions::SetOutputFile(FileSpec file) { m_file = file; } + +std::optional<std::string> SaveCoreOptions::GetPluginName() const { + return m_plugin_name; +} + +lldb::SaveCoreStyle SaveCoreOptions::GetStyle() const { + return m_style.value_or(lldb::eSaveCoreUnspecified); +} + +const std::optional<lldb_private::FileSpec> +SaveCoreOptions::GetOutputFile() const { + return m_file; +} + +void SaveCoreOptions::Clear() { + m_file = std::nullopt; + m_plugin_name = std::nullopt; + m_style = std::nullopt; +} diff --git a/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py b/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py index c3f0e7597758a..07d06bdc116ec 100644 --- a/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py +++ b/lldb/test/API/functionalities/process_save_core/TestProcessSaveCore.py @@ -2,7 +2,6 @@ Test saving a core file (or mini dump). """ - import os import lldb from lldbsuite.test.decorators import * @@ -21,6 +20,8 @@ def test_cannot_save_core_unless_process_stopped(self): target = self.dbg.CreateTarget(exe) process = target.LaunchSimple(None, None, self.get_process_working_directory()) self.assertNotEqual(process.GetState(), lldb.eStateStopped) + options = SBSaveCoreOptions() + options.SetOutputFile(SBFileSpec(core)) error = process.SaveCore(core) self.assertTrue(error.Fail()) diff --git a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py index 1e171e726fb6b..96511d790271f 100644 --- a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py +++ b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py @@ -132,8 +132,13 @@ def test_save_linux_mini_dump(self): stacks_to_sp_map, ) + options = lldb.SBSaveCoreOptions() + core_sb_stack_spec = lldb.SBFileSpec(core_sb_stack) + options.SetOutputFile(core_sb_stack_spec) + options.SetPluginName("minidump") + options.SetStyle(lldb.eSaveCoreStackOnly) # validate saving via SBProcess - error = process.SaveCore(core_sb_stack, "minidump", lldb.eSaveCoreStackOnly) + error = process.SaveCore(options) self.assertTrue(error.Success()) self.assertTrue(os.path.isfile(core_sb_stack)) self.verify_core_file( @@ -144,7 +149,12 @@ def test_save_linux_mini_dump(self): stacks_to_sp_map, ) - error = process.SaveCore(core_sb_dirty, "minidump", lldb.eSaveCoreDirtyOnly) + options = lldb.SBSaveCoreOptions() + core_sb_dirty_spec = lldb.SBFileSpec(core_sb_dirty) + options.SetOutputFile(core_sb_dirty_spec) + options.SetPluginName("minidump") + options.SetStyle(lldb.eSaveCoreDirtyOnly) + error = process.SaveCore(options) self.assertTrue(error.Success()) self.assertTrue(os.path.isfile(core_sb_dirty)) self.verify_core_file( @@ -157,7 +167,12 @@ def test_save_linux_mini_dump(self): # Minidump can now save full core files, but they will be huge and # they might cause this test to timeout. - error = process.SaveCore(core_sb_full, "minidump", lldb.eSaveCoreFull) + options = lldb.SBSaveCoreOptions() + core_sb_full_spec = lldb.SBFileSpec(core_sb_full) + options.SetOutputFile(core_sb_full_spec) + options.SetPluginName("minidump") + options.SetStyle(lldb.eSaveCoreFull) + error = process.SaveCore(options) self.assertTrue(error.Success()) self.assertTrue(os.path.isfile(core_sb_full)) self.verify_core_file( diff --git a/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py new file mode 100644 index 0000000000000..c509e81d8951a --- /dev/null +++ b/lldb/test/API/python_api/sbsavecoreoptions/TestSBSaveCoreOptions.py @@ -0,0 +1,28 @@ +"""Test the SBSaveCoreOptions APIs.""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + + +class SBSaveCoreOptionsAPICase(TestBase): + def test_plugin_name_assignment(self): + """Test assignment ensuring valid plugin names only.""" + options = lldb.SBSaveCoreOptions() + error = options.SetPluginName(None) + self.assertTrue(error.Success()) + self.assertEqual(options.GetPluginName(), None) + error = options.SetPluginName("Not a real plugin") + self.assertTrue(error.Fail()) + self.assertEqual(options.GetPluginName(), None) + error = options.SetPluginName("minidump") + self.assertTrue(error.Success()) + self.assertEqual(options.GetPluginName(), "minidump") + error = options.SetPluginName("") + self.assertTrue(error.Success()) + self.assertEqual(options.GetPluginName(), None) + + def test_default_corestyle_behavior(self): + """Test that the default core style is unspecified.""" + options = lldb.SBSaveCoreOptions() + self.assertEqual(options.GetStyle(), lldb.eSaveCoreUnspecified) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits