diff options
Diffstat (limited to 'source/Plugins/Process/minidump')
-rw-r--r-- | source/Plugins/Process/minidump/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/Plugins/Process/minidump/MinidumpParser.cpp | 206 | ||||
-rw-r--r-- | source/Plugins/Process/minidump/MinidumpParser.h | 14 | ||||
-rw-r--r-- | source/Plugins/Process/minidump/MinidumpTypes.cpp | 46 | ||||
-rw-r--r-- | source/Plugins/Process/minidump/MinidumpTypes.h | 15 | ||||
-rw-r--r-- | source/Plugins/Process/minidump/ProcessMinidump.cpp | 102 | ||||
-rw-r--r-- | source/Plugins/Process/minidump/ProcessMinidump.h | 2 |
7 files changed, 301 insertions, 86 deletions
diff --git a/source/Plugins/Process/minidump/CMakeLists.txt b/source/Plugins/Process/minidump/CMakeLists.txt index 61ce16830c9b9..b898ee1aa1444 100644 --- a/source/Plugins/Process/minidump/CMakeLists.txt +++ b/source/Plugins/Process/minidump/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(../Utility) - add_lldb_library(lldbPluginProcessMinidump PLUGIN MinidumpTypes.cpp MinidumpParser.cpp diff --git a/source/Plugins/Process/minidump/MinidumpParser.cpp b/source/Plugins/Process/minidump/MinidumpParser.cpp index 36350fdb63986..9a979335e99e1 100644 --- a/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -14,10 +14,13 @@ // Other libraries and framework includes #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/LLDBAssert.h" // C includes // C++ includes +#include <algorithm> #include <map> +#include <vector> using namespace lldb_private; using namespace minidump; @@ -27,47 +30,11 @@ MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) { if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) { return llvm::None; } - - llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(), - sizeof(MinidumpHeader)); - const MinidumpHeader *header = MinidumpHeader::Parse(header_data); - - if (header == nullptr) { - return llvm::None; - } - - lldb::offset_t directory_list_offset = header->stream_directory_rva; - // check if there is enough data for the parsing of the directory list - if ((directory_list_offset + - sizeof(MinidumpDirectory) * header->streams_count) > - data_buf_sp->GetByteSize()) { - return llvm::None; - } - - const MinidumpDirectory *directory = nullptr; - Status error; - llvm::ArrayRef<uint8_t> directory_data( - data_buf_sp->GetBytes() + directory_list_offset, - sizeof(MinidumpDirectory) * header->streams_count); - llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map; - - for (uint32_t i = 0; i < header->streams_count; ++i) { - error = consumeObject(directory_data, directory); - if (error.Fail()) { - return llvm::None; - } - directory_map[static_cast<const uint32_t>(directory->stream_type)] = - directory->location; - } - - return MinidumpParser(data_buf_sp, header, std::move(directory_map)); + return MinidumpParser(data_buf_sp); } -MinidumpParser::MinidumpParser( - const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, - llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map) - : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { -} +MinidumpParser::MinidumpParser(const lldb::DataBufferSP &data_buf_sp) + : m_data_sp(data_buf_sp) {} llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), @@ -96,6 +63,31 @@ llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) { return parseMinidumpString(arr_ref); } +UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) { + auto cv_record = + GetData().slice(module->CV_record.rva, module->CV_record.data_size); + + // Read the CV record signature + const llvm::support::ulittle32_t *signature = nullptr; + Status error = consumeObject(cv_record, signature); + if (error.Fail()) + return UUID(); + + const CvSignature cv_signature = + static_cast<CvSignature>(static_cast<const uint32_t>(*signature)); + + if (cv_signature == CvSignature::Pdb70) { + // PDB70 record + const CvRecordPdb70 *pdb70_uuid = nullptr; + Status error = consumeObject(cv_record, pdb70_uuid); + if (!error.Fail()) + return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid)); + } else if (cv_signature == CvSignature::ElfBuildId) + return UUID::fromData(cv_record); + + return UUID(); +} + llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() { llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList); @@ -115,12 +107,12 @@ MinidumpParser::GetThreadContext(const MinidumpThread &td) { llvm::ArrayRef<uint8_t> MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) { - // On Windows, a 32-bit process can run on a 64-bit machine under - // WOW64. If the minidump was captured with a 64-bit debugger, then - // the CONTEXT we just grabbed from the mini_dump_thread is the one - // for the 64-bit "native" process rather than the 32-bit "guest" - // process we care about. In this case, we can get the 32-bit CONTEXT - // from the TEB (Thread Environment Block) of the 64-bit process. + // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If + // the minidump was captured with a 64-bit debugger, then the CONTEXT we just + // grabbed from the mini_dump_thread is the one for the 64-bit "native" + // process rather than the 32-bit "guest" process we care about. In this + // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment + // Block) of the 64-bit process. auto teb_mem = GetMemory(td.teb, sizeof(TEB64)); if (teb_mem.empty()) return {}; @@ -130,9 +122,9 @@ MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) { if (error.Fail()) return {}; - // Slot 1 of the thread-local storage in the 64-bit TEB points to a - // structure that includes the 32-bit CONTEXT (after a ULONG). - // See: https://msdn.microsoft.com/en-us/library/ms681670.aspx + // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure + // that includes the 32-bit CONTEXT (after a ULONG). See: + // https://msdn.microsoft.com/en-us/library/ms681670.aspx auto context = GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32)); if (context.size() < sizeof(MinidumpContext_x86_32)) @@ -334,10 +326,10 @@ MinidumpParser::FindMemoryRange(lldb::addr_t addr) { } } - // Some Minidumps have a Memory64ListStream that captures all the heap - // memory (full-memory Minidumps). We can't exactly use the same loop as - // above, because the Minidump uses slightly different data structures to - // describe those + // Some Minidumps have a Memory64ListStream that captures all the heap memory + // (full-memory Minidumps). We can't exactly use the same loop as above, + // because the Minidump uses slightly different data structures to describe + // those if (!data64.empty()) { llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list; @@ -377,8 +369,8 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, return {}; // There's at least some overlap between the beginning of the desired range - // (addr) and the current range. Figure out where the overlap begins and - // how much overlap there is. + // (addr) and the current range. Figure out where the overlap begins and how + // much overlap there is. const size_t offset = addr - range->start; @@ -456,3 +448,109 @@ MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { // appear truncated. return info; } + +Status MinidumpParser::Initialize() { + Status error; + + lldbassert(m_directory_map.empty()); + + llvm::ArrayRef<uint8_t> header_data(m_data_sp->GetBytes(), + sizeof(MinidumpHeader)); + const MinidumpHeader *header = MinidumpHeader::Parse(header_data); + if (header == nullptr) { + error.SetErrorString("invalid minidump: can't parse the header"); + return error; + } + + // A minidump without at least one stream is clearly ill-formed + if (header->streams_count == 0) { + error.SetErrorString("invalid minidump: no streams present"); + return error; + } + + struct FileRange { + uint32_t offset = 0; + uint32_t size = 0; + + FileRange(uint32_t offset, uint32_t size) : offset(offset), size(size) {} + uint32_t end() const { return offset + size; } + }; + + const uint32_t file_size = m_data_sp->GetByteSize(); + + // Build a global minidump file map, checking for: + // - overlapping streams/data structures + // - truncation (streams pointing past the end of file) + std::vector<FileRange> minidump_map; + + // Add the minidump header to the file map + if (sizeof(MinidumpHeader) > file_size) { + error.SetErrorString("invalid minidump: truncated header"); + return error; + } + minidump_map.emplace_back( 0, sizeof(MinidumpHeader) ); + + // Add the directory entries to the file map + FileRange directory_range(header->stream_directory_rva, + header->streams_count * + sizeof(MinidumpDirectory)); + if (directory_range.end() > file_size) { + error.SetErrorString("invalid minidump: truncated streams directory"); + return error; + } + minidump_map.push_back(directory_range); + + // Parse stream directory entries + llvm::ArrayRef<uint8_t> directory_data( + m_data_sp->GetBytes() + directory_range.offset, directory_range.size); + for (uint32_t i = 0; i < header->streams_count; ++i) { + const MinidumpDirectory *directory_entry = nullptr; + error = consumeObject(directory_data, directory_entry); + if (error.Fail()) + return error; + if (directory_entry->stream_type == 0) { + // Ignore dummy streams (technically ill-formed, but a number of + // existing minidumps seem to contain such streams) + if (directory_entry->location.data_size == 0) + continue; + error.SetErrorString("invalid minidump: bad stream type"); + return error; + } + // Update the streams map, checking for duplicate stream types + if (!m_directory_map + .insert({directory_entry->stream_type, directory_entry->location}) + .second) { + error.SetErrorString("invalid minidump: duplicate stream type"); + return error; + } + // Ignore the zero-length streams for layout checks + if (directory_entry->location.data_size != 0) { + minidump_map.emplace_back(directory_entry->location.rva, + directory_entry->location.data_size); + } + } + + // Sort the file map ranges by start offset + std::sort(minidump_map.begin(), minidump_map.end(), + [](const FileRange &a, const FileRange &b) { + return a.offset < b.offset; + }); + + // Check for overlapping streams/data structures + for (size_t i = 1; i < minidump_map.size(); ++i) { + const auto &prev_range = minidump_map[i - 1]; + if (prev_range.end() > minidump_map[i].offset) { + error.SetErrorString("invalid minidump: overlapping streams"); + return error; + } + } + + // Check for streams past the end of file + const auto &last_range = minidump_map.back(); + if (last_range.end() > file_size) { + error.SetErrorString("invalid minidump: truncated stream"); + return error; + } + + return error; +} diff --git a/source/Plugins/Process/minidump/MinidumpParser.h b/source/Plugins/Process/minidump/MinidumpParser.h index b7329ffc00289..49b1eef14de58 100644 --- a/source/Plugins/Process/minidump/MinidumpParser.h +++ b/source/Plugins/Process/minidump/MinidumpParser.h @@ -17,6 +17,7 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/UUID.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -54,6 +55,8 @@ public: llvm::Optional<std::string> GetMinidumpString(uint32_t rva); + UUID GetModuleUUID(const MinidumpModule* module); + llvm::ArrayRef<MinidumpThread> GetThreads(); llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td); @@ -86,14 +89,15 @@ public: llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t); + // Perform consistency checks and initialize internal data structures + Status Initialize(); + +private: + MinidumpParser(const lldb::DataBufferSP &data_buf_sp); + private: lldb::DataBufferSP m_data_sp; - const MinidumpHeader *m_header; llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map; - - MinidumpParser( - const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, - llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map); }; } // end namespace minidump diff --git a/source/Plugins/Process/minidump/MinidumpTypes.cpp b/source/Plugins/Process/minidump/MinidumpTypes.cpp index 24ce3f94c0941..049704ba80caf 100644 --- a/source/Plugins/Process/minidump/MinidumpTypes.cpp +++ b/source/Plugins/Process/minidump/MinidumpTypes.cpp @@ -33,9 +33,6 @@ const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) { version != MinidumpHeaderConstants::Version) return nullptr; - // TODO check for max number of streams ? - // TODO more sanity checks ? - return header; } @@ -44,19 +41,23 @@ llvm::Optional<std::string> lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) { std::string result; - const uint32_t *source_length; - Status error = consumeObject(data, source_length); - if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0) + const uint32_t *source_length_ptr; + Status error = consumeObject(data, source_length_ptr); + + // Copy non-aligned source_length data into aligned memory. + uint32_t source_length; + std::memcpy(&source_length, source_length_ptr, sizeof(source_length)); + + if (error.Fail() || source_length > data.size() || source_length % 2 != 0) return llvm::None; auto source_start = reinterpret_cast<const llvm::UTF16 *>(data.data()); - // source_length is the length of the string in bytes - // we need the length of the string in UTF-16 characters/code points (16 bits - // per char) - // that's why it's divided by 2 - const auto source_end = source_start + (*source_length) / 2; + // source_length is the length of the string in bytes we need the length of + // the string in UTF-16 characters/code points (16 bits per char) that's why + // it's divided by 2 + const auto source_end = source_start + source_length / 2; // resize to worst case length - result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * (*source_length) / 2); + result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * source_length / 2); auto result_start = reinterpret_cast<llvm::UTF8 *>(&result[0]); const auto result_end = result_start + result.size(); llvm::ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end, @@ -80,11 +81,17 @@ const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) { llvm::ArrayRef<MinidumpThread> MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) { + const auto orig_size = data.size(); const llvm::support::ulittle32_t *thread_count; Status error = consumeObject(data, thread_count); if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size()) return {}; + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *thread_count * sizeof(MinidumpThread) < orig_size) + data = data.drop_front(4); + return llvm::ArrayRef<MinidumpThread>( reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count); } @@ -156,12 +163,17 @@ const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) { llvm::ArrayRef<MinidumpModule> MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) { - + const auto orig_size = data.size(); const llvm::support::ulittle32_t *modules_count; Status error = consumeObject(data, modules_count); if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size()) return {}; - + + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *modules_count * sizeof(MinidumpModule) < orig_size) + data = data.drop_front(4); + return llvm::ArrayRef<MinidumpModule>( reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count); } @@ -179,11 +191,17 @@ MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) { llvm::ArrayRef<MinidumpMemoryDescriptor> MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) { + const auto orig_size = data.size(); const llvm::support::ulittle32_t *mem_ranges_count; Status error = consumeObject(data, mem_ranges_count); if (error.Fail() || *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size()) return {}; + + // Compilers might end up padding an extra 4 bytes depending on how the + // structure is padded by the compiler and the #pragma pack settings. + if (4 + *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) < orig_size) + data = data.drop_front(4); return llvm::makeArrayRef( reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()), diff --git a/source/Plugins/Process/minidump/MinidumpTypes.h b/source/Plugins/Process/minidump/MinidumpTypes.h index 6de4f55a769d8..e83089865b9e0 100644 --- a/source/Plugins/Process/minidump/MinidumpTypes.h +++ b/source/Plugins/Process/minidump/MinidumpTypes.h @@ -43,6 +43,21 @@ enum class MinidumpHeaderConstants : uint32_t { }; +enum class CvSignature : uint32_t { + Pdb70 = 0x53445352, // RSDS + ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps) +}; + +// Reference: +// https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html +struct CvRecordPdb70 { + uint8_t Uuid[16]; + llvm::support::ulittle32_t Age; + // char PDBFileName[]; +}; +static_assert(sizeof(CvRecordPdb70) == 20, + "sizeof CvRecordPdb70 is not correct!"); + // Reference: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680394.aspx enum class MinidumpStreamType : uint32_t { diff --git a/source/Plugins/Process/minidump/ProcessMinidump.cpp b/source/Plugins/Process/minidump/ProcessMinidump.cpp index d4d65c044eabe..b43f22382eaca 100644 --- a/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/State.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/DataBufferLLVM.h" @@ -31,9 +32,56 @@ // C includes // C++ includes +using namespace lldb; using namespace lldb_private; using namespace minidump; +//------------------------------------------------------------------ +/// A placeholder module used for minidumps, where the original +/// object files may not be available (so we can't parse the object +/// files to extract the set of sections/segments) +/// +/// This placeholder module has a single synthetic section (.module_image) +/// which represents the module memory range covering the whole module. +//------------------------------------------------------------------ +class PlaceholderModule : public Module { +public: + PlaceholderModule(const ModuleSpec &module_spec) : + Module(module_spec.GetFileSpec(), module_spec.GetArchitecture()) { + if (module_spec.GetUUID().IsValid()) + SetUUID(module_spec.GetUUID()); + } + + // Creates a synthetic module section covering the whole module image (and + // sets the section load address as well) + void CreateImageSection(const MinidumpModule *module, Target& target) { + const ConstString section_name(".module_image"); + lldb::SectionSP section_sp(new Section( + shared_from_this(), // Module to which this section belongs. + nullptr, // ObjectFile + 0, // Section ID. + section_name, // Section name. + eSectionTypeContainer, // Section type. + module->base_of_image, // VM address. + module->size_of_image, // VM size in bytes of this section. + 0, // Offset of this section in the file. + module->size_of_image, // Size of the section as found in the file. + 12, // Alignment of the section (log2) + 0, // Flags for this section. + 1)); // Number of host bytes per target byte + section_sp->SetPermissions(ePermissionsExecutable | ePermissionsReadable); + GetSectionList()->AddSection(section_sp); + target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, module->base_of_image); + } + + ObjectFile *GetObjectFile() override { return nullptr; } + + SectionList *GetSectionList() override { + return Module::GetUnifiedSectionList(); + } +}; + ConstString ProcessMinidump::GetPluginNameStatic() { static ConstString g_name("minidump"); return g_name; @@ -57,7 +105,7 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, if (!DataPtr) return nullptr; - assert(DataPtr->GetByteSize() == header_size); + lldbassert(DataPtr->GetByteSize() == header_size); // first, only try to parse the header, beacuse we need to be fast llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData(); @@ -92,10 +140,10 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, ProcessMinidump::~ProcessMinidump() { Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. Finalize(); } @@ -116,10 +164,29 @@ void ProcessMinidump::Terminate() { Status ProcessMinidump::DoLoadCore() { Status error; + // Minidump parser initialization & consistency checks + error = m_minidump_parser.Initialize(); + if (error.Fail()) + return error; + + // Do we support the minidump's architecture? + ArchSpec arch = GetArchitecture(); + switch (arch.GetMachine()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + // supported + break; + + default: + error.SetErrorStringWithFormat("unsupported minidump architecture: %s", + arch.GetArchitectureName()); + return error; + } + m_thread_list = m_minidump_parser.GetThreads(); m_active_exception = m_minidump_parser.GetExceptionStream(); ReadModuleList(); - GetTarget().SetArchitecture(GetArchitecture()); + GetTarget().SetArchitecture(arch); llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid(); if (!pid) { @@ -185,8 +252,8 @@ bool ProcessMinidump::WarnBeforeDetach() const { return false; } size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { - // Don't allow the caching that lldb_private::Process::ReadMemory does - // since we have it all cached in our dump file anyway. + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // we have it all cached in our dump file anyway. return DoReadMemory(addr, buf, size, error); } @@ -276,12 +343,25 @@ void ProcessMinidump::ReadModuleList() { m_is_wow64 = true; } - const auto file_spec = FileSpec(name.getValue(), true); - ModuleSpec module_spec = file_spec; + const auto uuid = m_minidump_parser.GetModuleUUID(module); + const auto file_spec = + FileSpec(name.getValue(), true, GetArchitecture().GetTriple()); + ModuleSpec module_spec(file_spec, uuid); Status error; lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error); if (!module_sp || error.Fail()) { - continue; + // We failed to locate a matching local object file. Fortunately, the + // minidump format encodes enough information about each module's memory + // range to allow us to create placeholder modules. + // + // This enables most LLDB functionality involving address-to-module + // translations (ex. identifing the module for a stack frame PC) and + // modules/sections commands (ex. target modules list, ...) + auto placeholder_module = + std::make_shared<PlaceholderModule>(module_spec); + placeholder_module->CreateImageSection(module, GetTarget()); + module_sp = placeholder_module; + GetTarget().GetImages().Append(module_sp); } if (log) { diff --git a/source/Plugins/Process/minidump/ProcessMinidump.h b/source/Plugins/Process/minidump/ProcessMinidump.h index 4b91d1ba396a4..d65ada9009a7e 100644 --- a/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/source/Plugins/Process/minidump/ProcessMinidump.h @@ -61,6 +61,8 @@ public: uint32_t GetPluginVersion() override; + SystemRuntime *GetSystemRuntime() override { return nullptr; } + Status DoDestroy() override; void RefreshStateAfterStop() override; |