Index: packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py +++ packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py @@ -70,6 +70,17 @@ self.assertEqual(self.process.GetProcessID(), self._linux_x86_64_pid) self.check_state() + def test_modules_in_mini_dump(self): + """Test that lldb can read the list of modules from the minidump.""" + # target create -c linux-x86_64.dmp + self.dbg.CreateTarget(None) + self.target = self.dbg.GetSelectedTarget() + self.process = self.target.LoadCore("linux-x86_64.dmp") + self.assertTrue(self.process, PROCESS_IS_VALID) + self.assertEqual(self.target.GetNumModules(), 9) + for module in self.target.modules: + self.assertTrue(module.IsValid()) + def test_thread_info_in_minidump(self): """Test that lldb can read the thread information from the Minidump.""" # target create -c linux-x86_64.dmp @@ -100,6 +111,7 @@ self.assertEqual(thread.GetNumFrames(), 2) frame = thread.GetFrameAtIndex(0) self.assertTrue(frame.IsValid()) + self.assertTrue(frame.GetModule().IsValid()) pc = frame.GetPC() eip = frame.FindRegister("pc") self.assertTrue(eip.IsValid()) Index: packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py +++ packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py @@ -41,6 +41,26 @@ stop_description = thread.GetStopDescription(256) self.assertTrue("0xc0000005" in stop_description) + def test_modules_in_mini_dump(self): + """Test that lldb can read the list of modules from the minidump.""" + # target create -c fizzbuzz_no_heap.dmp + self.dbg.CreateTarget("") + self.target = self.dbg.GetSelectedTarget() + self.process = self.target.LoadCore("fizzbuzz_no_heap.dmp") + self.assertTrue(self.process, PROCESS_IS_VALID) + expected_modules = [ + r"C:\Windows\System32\MSVCP120D.dll", + r"C:\Windows\SysWOW64\kernel32.dll", + r"C:\Users\amccarth\Documents\Visual Studio 2013\Projects\fizzbuzz\Debug\fizzbuzz.exe", + r"C:\Windows\System32\MSVCR120D.dll", + r"C:\Windows\SysWOW64\KERNELBASE.dll", + r"C:\Windows\SysWOW64\ntdll.dll", + ] + self.assertEqual(self.target.GetNumModules(), len(expected_modules)) + for module, expected in zip(self.target.modules, expected_modules): + self.assertTrue(module.IsValid()) + self.assertEqual(module.file.fullpath, expected) + @expectedFailureAll(bugnumber="llvm.org/pr35193", hostoslist=["windows"]) def test_stack_info_in_mini_dump(self): """Test that we can see a trivial stack in a VS-generate mini dump.""" @@ -58,6 +78,7 @@ frame = thread.GetFrameAtIndex(i) self.assertTrue(frame.IsValid()) self.assertEqual(frame.GetPC(), pc_list[i]) + self.assertTrue(frame.GetModule().IsValid()) @skipUnlessWindows # Minidump saving works only on windows def test_deeper_stack_in_mini_dump(self): Index: source/Commands/CommandObjectTarget.cpp =================================================================== --- source/Commands/CommandObjectTarget.cpp +++ source/Commands/CommandObjectTarget.cpp @@ -1388,7 +1388,8 @@ strm.EOL(); } ObjectFile *objfile = module->GetObjectFile(); - objfile->Dump(&strm); + if (objfile) + objfile->Dump(&strm); } } strm.IndentLess(); Index: source/Core/Module.cpp =================================================================== --- source/Core/Module.cpp +++ source/Core/Module.cpp @@ -1278,7 +1278,7 @@ } SectionList *Module::GetSectionList() { - // Populate m_unified_sections_ap with sections from objfile. + // Populate m_sections_ap with sections from objfile. if (!m_sections_ap) { ObjectFile *obj_file = GetObjectFile(); if (obj_file != nullptr) @@ -1297,7 +1297,6 @@ } SectionList *Module::GetUnifiedSectionList() { - // Populate m_unified_sections_ap with sections from objfile. if (!m_sections_ap) m_sections_ap = llvm::make_unique(); return m_sections_ap.get(); Index: source/Core/Section.cpp =================================================================== --- source/Core/Section.cpp +++ source/Core/Section.cpp @@ -326,10 +326,11 @@ // The top most section prints the module basename const char *name = NULL; ModuleSP module_sp(GetModule()); - const FileSpec &file_spec = m_obj_file->GetFileSpec(); - if (m_obj_file) + if (m_obj_file) { + const FileSpec &file_spec = m_obj_file->GetFileSpec(); name = file_spec.GetFilename().AsCString(); + } if ((!name || !name[0]) && module_sp) name = module_sp->GetFileSpec().GetFilename().AsCString(); if (name && name[0]) Index: source/Plugins/Process/minidump/ProcessMinidump.h =================================================================== --- source/Plugins/Process/minidump/ProcessMinidump.h +++ source/Plugins/Process/minidump/ProcessMinidump.h @@ -61,6 +61,8 @@ uint32_t GetPluginVersion() override; + SystemRuntime *GetSystemRuntime() override { return nullptr; } + Status DoDestroy() override; void RefreshStateAfterStop() override; Index: source/Plugins/Process/minidump/ProcessMinidump.cpp =================================================================== --- source/Plugins/Process/minidump/ProcessMinidump.cpp +++ 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,53 @@ // 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 FileSpec &file_spec, const ArchSpec &arch) : + Module(file_spec, arch) {} + + // 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; @@ -281,7 +326,18 @@ 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(file_spec, GetArchitecture()); + placeholder_module->CreateImageSection(module, GetTarget()); + module_sp = placeholder_module; + GetTarget().GetImages().Append(module_sp); } if (log) {