lemo created this revision.
lemo added reviewers: amccarth, clayborg, labath.
lemo added a project: LLDB.

This change adds support for two types of Minidump CodeView records:

1. PDB70 (reference: 
https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html)

This is by far the most common record type.

2. ELF BuildID (found in Breakpad/Crashpad generated minidumps)

This would set a proper UUID for placeholder modules, in turn enabling an 
accurate match with local module images.


https://reviews.llvm.org/D46292

Files:
  include/lldb/Core/Module.h
  include/lldb/Core/ModuleSpec.h
  
packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py
  source/Commands/CommandObjectTarget.cpp
  source/Core/Module.cpp
  source/Plugins/Process/minidump/MinidumpParser.cpp
  source/Plugins/Process/minidump/MinidumpParser.h
  source/Plugins/Process/minidump/MinidumpTypes.h
  source/Plugins/Process/minidump/ProcessMinidump.cpp

Index: source/Plugins/Process/minidump/ProcessMinidump.cpp
===================================================================
--- source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -321,9 +321,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()) {
@@ -337,6 +338,7 @@
       auto placeholder_module =
           std::make_shared<PlaceholderModule>(file_spec, GetArchitecture());
       placeholder_module->CreateImageSection(module, GetTarget());
+      placeholder_module->SetUUID(uuid);
       module_sp = placeholder_module;
       GetTarget().GetImages().Append(module_sp);
     }
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/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<std::string> GetMinidumpString(uint32_t rva);
 
+  UUID GetModuleUUID(const MinidumpModule* module);
+
   llvm::ArrayRef<MinidumpThread> GetThreads();
 
   llvm::ArrayRef<uint8_t> 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<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(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<MinidumpThread> MinidumpParser::GetThreads() {
   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
 
Index: source/Core/Module.cpp
===================================================================
--- source/Core/Module.cpp
+++ source/Core/Module.cpp
@@ -335,6 +335,12 @@
   return m_uuid;
 }
 
+void Module::SetUUID(const lldb_private::UUID &uuid) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  m_uuid = uuid;
+  m_did_parse_uuid = true;
+}
+
 TypeSystem *Module::GetTypeSystemForLanguage(LanguageType language) {
   return m_type_system_map.GetTypeSystemForLanguage(language, this, true);
 }
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: 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: 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: 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
@@ -771,6 +771,14 @@
   const lldb_private::UUID &GetUUID();
 
   //------------------------------------------------------------------
+  /// Explicitly set the UUID
+  ///
+  /// @param[in] uuid
+  ///     The new UUID for this module.
+  //------------------------------------------------------------------
+  void SetUUID(const lldb_private::UUID &uuid);
+
+  //------------------------------------------------------------------
   /// A debugging function that will cause everything in a module to
   /// be parsed.
   ///
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to