Index: include/lldb/Core/Module.h =================================================================== --- include/lldb/Core/Module.h +++ include/lldb/Core/Module.h @@ -757,7 +757,7 @@ TypeList *GetTypeList(); //------------------------------------------------------------------ - /// Get a pointer to the UUID value contained in this object. + /// Get a reference to the UUID value contained in this object. /// /// If the executable image file doesn't not have a UUID value built /// into the file format, an MD5 checksum of the entire file, or @@ -1129,7 +1129,7 @@ std::atomic m_did_load_objfile{false}; std::atomic m_did_load_symbol_vendor{false}; - std::atomic m_did_parse_uuid{false}; + std::atomic m_did_set_uuid{false}; mutable bool m_file_has_changed : 1, m_first_file_changed_log : 1; /// See if the module was modified after it /// was initially opened. @@ -1179,6 +1179,8 @@ bool SetArchitecture(const ArchSpec &new_arch); + void SetUUID(const lldb_private::UUID &uuid); + SectionList *GetUnifiedSectionList(); friend class ModuleList; Index: include/lldb/Core/ModuleSpec.h =================================================================== --- include/lldb/Core/ModuleSpec.h +++ include/lldb/Core/ModuleSpec.h @@ -34,9 +34,9 @@ m_object_name(), m_object_offset(0), m_object_size(0), m_source_mappings() {} - ModuleSpec(const FileSpec &file_spec) + ModuleSpec(const FileSpec &file_spec, const UUID& uuid = UUID()) : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(), - m_uuid(), m_object_name(), m_object_offset(0), + m_uuid(uuid), m_object_name(), m_object_offset(0), m_object_size(file_spec.GetByteSize()), m_source_mappings() {} ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) 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 @@ -77,9 +77,49 @@ 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: + expected_modules = [ + { + 'filename' : 'linux-gate.so', + 'uuid' : '4EAD28F8-88EF-3520-872B-73C6F2FE7306-C41AF22F', + }, + { + 'filename' : 'libm-2.19.so', + 'uuid' : 'D144258E-6149-00B2-55A3-1F3FD2283A87-8670D5BC', + }, + { + 'filename' : 'libstdc++.so.6.0.19', + 'uuid' : '76190E92-2AF7-457D-078F-75C9B15FA184-E83EB506', + }, + { + 'filename' : 'libc-2.19.so', + 'uuid' : 'CF699A15-CAAE-64F5-0311-FC4655B86DC3-9A479789', + }, + { + 'filename' : 'linux-x86_64', + 'uuid' : 'E35C283B-C327-C287-62DB-788BF5A4078B-E2351448', + }, + { + 'filename' : 'libgcc_s.so.1', + 'uuid' : '36311B44-5771-0AE5-578C-4BF00791DED7-359DBB92', + }, + { + 'filename' : 'libpthread-2.19.so', + 'uuid' : '31E9F21A-E8C1-0396-171F-1E13DA157809-86FA696C', + }, + { + 'filename' : 'ld-2.19.so', + 'uuid' : 'D0F53790-4076-D73F-29E4-A37341F8A449-E2EF6CD0', + }, + { + 'filename' : 'libbreakpad.so', + 'uuid' : '784FD549-332D-826E-D23F-18C17C6F320A', + }, + ] + 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.basename, expected['filename']) + self.assertEqual(module.GetUUIDString(), expected['uuid']) def test_thread_info_in_minidump(self): """Test that lldb can read the thread information from the Minidump.""" 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 @@ -49,17 +49,36 @@ 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", + { + 'filename' : r"C:\Windows\System32/MSVCP120D.dll", + 'uuid' : '6E51053C-E757-EB40-8D3F-9722C5BD80DD-01000000', + }, + { + 'filename' : r"C:\Windows\SysWOW64/kernel32.dll", + 'uuid' : '1B7ECBE5-5E00-1341-AB98-98D6913B52D8-02000000', + }, + { + 'filename' : r"C:\Users\amccarth\Documents\Visual Studio 2013\Projects\fizzbuzz\Debug/fizzbuzz.exe", + 'uuid' : '91B7450F-969A-F946-BF8F-2D6076EA421A-11000000', + }, + { + 'filename' : r"C:\Windows\System32/MSVCR120D.dll", + 'uuid' : '86FB8263-C446-4640-AE42-8D97B3F91FF2-01000000', + }, + { + 'filename' : r"C:\Windows\SysWOW64/KERNELBASE.dll", + 'uuid' : '4152F90B-0DCB-D44B-AC5D-186A6452E522-01000000', + }, + { + 'filename' : r"C:\Windows\SysWOW64/ntdll.dll", + 'uuid' : '6A84B0BB-2C40-5240-A16B-67650BBFE6B0-02000000', + }, ] 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) + self.assertEqual(module.file.fullpath, expected['filename']) + self.assertEqual(module.GetUUIDString(), expected['uuid']) @expectedFailureAll(bugnumber="llvm.org/pr35193", hostoslist=["windows"]) def test_stack_info_in_mini_dump(self): Index: source/Commands/CommandObjectTarget.cpp =================================================================== --- source/Commands/CommandObjectTarget.cpp +++ source/Commands/CommandObjectTarget.cpp @@ -1386,6 +1386,10 @@ ObjectFile *objfile = module->GetObjectFile(); if (objfile) objfile->Dump(&strm); + else { + strm.Printf("No object file for module: %s\n", + module->GetFileSpec().GetFilename().GetCString()); + } } } strm.IndentLess(); Index: source/Core/Module.cpp =================================================================== --- source/Core/Module.cpp +++ source/Core/Module.cpp @@ -38,6 +38,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" // for GetLogIfAn... #include "lldb/Utility/RegularExpression.h" @@ -321,20 +322,30 @@ } const lldb_private::UUID &Module::GetUUID() { - if (!m_did_parse_uuid.load()) { + if (!m_did_set_uuid.load()) { std::lock_guard guard(m_mutex); - if (!m_did_parse_uuid.load()) { + if (!m_did_set_uuid.load()) { ObjectFile *obj_file = GetObjectFile(); if (obj_file != nullptr) { obj_file->GetUUID(&m_uuid); - m_did_parse_uuid = true; + m_did_set_uuid = true; } } } return m_uuid; } +void Module::SetUUID(const lldb_private::UUID &uuid) { + std::lock_guard guard(m_mutex); + if (!m_did_set_uuid) { + m_uuid = uuid; + m_did_set_uuid = true; + } else { + lldbassert(!"Attempting to overwrite the existing module UUID"); + } +} + TypeSystem *Module::GetTypeSystemForLanguage(LanguageType language) { return m_type_system_map.GetTypeSystemForLanguage(language, this, true); } Index: source/Plugins/Process/minidump/MinidumpParser.h =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.h +++ 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 @@ llvm::Optional GetMinidumpString(uint32_t rva); + UUID GetModuleUUID(const MinidumpModule* module); + llvm::ArrayRef GetThreads(); llvm::ArrayRef GetThreadContext(const MinidumpThread &td); Index: source/Plugins/Process/minidump/MinidumpParser.cpp =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.cpp +++ source/Plugins/Process/minidump/MinidumpParser.cpp @@ -96,6 +96,40 @@ 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(static_cast(*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(pdb70_uuid, sizeof(*pdb70_uuid)); + } else if (cv_signature == CvSignature::ElfBuildId) { + // ELF BuildID (found in Breakpad/Crashpad generated minidumps) + // + // This is variable-length, but usually 20 bytes + // as the binutils ld default is a SHA-1 hash. + // (We'll handle only 16 and 20 bytes signatures, + // matching LLDB support for UUIDs) + // + if (cv_record.size() == 16 || cv_record.size() == 20) + return UUID(cv_record.data(), cv_record.size()); + } + + return UUID(); +} + llvm::ArrayRef MinidumpParser::GetThreads() { llvm::ArrayRef data = GetStream(MinidumpStreamType::ThreadList); Index: source/Plugins/Process/minidump/MinidumpTypes.h =================================================================== --- source/Plugins/Process/minidump/MinidumpTypes.h +++ source/Plugins/Process/minidump/MinidumpTypes.h @@ -43,6 +43,21 @@ }; +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 { Index: source/Plugins/Process/minidump/ProcessMinidump.cpp =================================================================== --- source/Plugins/Process/minidump/ProcessMinidump.cpp +++ source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -46,8 +46,11 @@ //------------------------------------------------------------------ class PlaceholderModule : public Module { public: - PlaceholderModule(const FileSpec &file_spec, const ArchSpec &arch) : - Module(file_spec, arch) {} + 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) @@ -321,9 +324,10 @@ m_is_wow64 = true; } + const auto uuid = m_minidump_parser.GetModuleUUID(module); const auto file_spec = FileSpec(name.getValue(), true, GetArchitecture().GetTriple()); - ModuleSpec module_spec = file_spec; + ModuleSpec module_spec(file_spec, uuid); Status error; lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error); if (!module_sp || error.Fail()) { @@ -335,7 +339,7 @@ // 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()); + std::make_shared(module_spec); placeholder_module->CreateImageSection(module, GetTarget()); module_sp = placeholder_module; GetTarget().GetImages().Append(module_sp);