| //===-- ObjectFileMinidump.cpp --------------------------------------------===// | |
| // | |
| // 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 "ObjectFileMinidump.h" | |
| #include "MinidumpFileBuilder.h" | |
| #include "lldb/Core/ModuleSpec.h" | |
| #include "lldb/Core/PluginManager.h" | |
| #include "lldb/Core/Section.h" | |
| #include "lldb/Target/Process.h" | |
| #include "lldb/Utility/LLDBLog.h" | |
| #include "lldb/Utility/Log.h" | |
| #include "llvm/Support/FileSystem.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| LLDB_PLUGIN_DEFINE(ObjectFileMinidump) | |
| void ObjectFileMinidump::Initialize() { | |
| PluginManager::RegisterPlugin( | |
| GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, | |
| CreateMemoryInstance, GetModuleSpecifications, SaveCore); | |
| } | |
| void ObjectFileMinidump::Terminate() { | |
| PluginManager::UnregisterPlugin(CreateInstance); | |
| } | |
| ObjectFile *ObjectFileMinidump::CreateInstance( | |
| const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_sp, | |
| lldb::offset_t data_offset, const lldb_private::FileSpec *file, | |
| lldb::offset_t offset, lldb::offset_t length) { | |
| return nullptr; | |
| } | |
| ObjectFile *ObjectFileMinidump::CreateMemoryInstance( | |
| const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, | |
| const ProcessSP &process_sp, lldb::addr_t header_addr) { | |
| return nullptr; | |
| } | |
| ModuleSpecList ObjectFileMinidump::GetModuleSpecifications( | |
| const lldb_private::FileSpec &file, lldb::DataExtractorSP &extractor_sp, | |
| lldb::offset_t file_offset, lldb::offset_t length) { | |
| return {}; | |
| } | |
| struct DumpFailRemoveHolder { | |
| DumpFailRemoveHolder(MinidumpFileBuilder &builder) : m_builder(builder) {} | |
| ~DumpFailRemoveHolder() { | |
| if (!m_success) | |
| m_builder.DeleteFile(); | |
| } | |
| void SetSuccess() { m_success = true; } | |
| private: | |
| MinidumpFileBuilder &m_builder; | |
| bool m_success = false; | |
| }; | |
| bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp, | |
| lldb_private::SaveCoreOptions &options, | |
| lldb_private::Status &error) { | |
| // Output file and process_sp are both checked in PluginManager::SaveCore. | |
| assert(options.GetOutputFile().has_value()); | |
| assert(process_sp); | |
| // Minidump defaults to stacks only. | |
| if (options.GetStyle() == SaveCoreStyle::eSaveCoreUnspecified) | |
| options.SetStyle(SaveCoreStyle::eSaveCoreStackOnly); | |
| llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open( | |
| options.GetOutputFile().value(), | |
| File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate); | |
| if (!maybe_core_file) { | |
| error = Status::FromError(maybe_core_file.takeError()); | |
| return false; | |
| } | |
| MinidumpFileBuilder builder(std::move(maybe_core_file.get()), process_sp, | |
| options); | |
| DumpFailRemoveHolder request(builder); | |
| Log *log = GetLog(LLDBLog::Object); | |
| error = builder.AddHeaderAndCalculateDirectories(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddHeaderAndCalculateDirectories failed: %s", | |
| error.AsCString()); | |
| return false; | |
| }; | |
| error = builder.AddSystemInfo(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddSystemInfo failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| error = builder.AddModuleList(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddModuleList failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| error = builder.AddMiscInfo(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddMiscInfo failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| error = builder.AddThreadList(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddThreadList failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| error = builder.AddLinuxFileStreams(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddLinuxFileStreams failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| // Add any exceptions but only if there are any in any threads. | |
| error = builder.AddExceptions(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddExceptions failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| // Note: add memory HAS to be the last thing we do. It can overflow into 64b | |
| // land and many RVA's only support 32b | |
| error = builder.AddMemoryList(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "AddMemoryList failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| error = builder.DumpFile(); | |
| if (error.Fail()) { | |
| LLDB_LOGF(log, "DumpFile failed: %s", error.AsCString()); | |
| return false; | |
| } | |
| request.SetSuccess(); | |
| return true; | |
| } |