Use the UUID from the minidump's CodeView Record for placeholder modules
This change adds support for two types of Minidump CodeView records:
PDB70 (reference: https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html)
This is by far the most common record type.
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.
Differential Revision: https://reviews.llvm.org/D46292
llvm-svn: 331394
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 45204b6..ee7e0e9 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -1386,6 +1386,10 @@
ObjectFile *objfile = module->GetObjectFile();
if (objfile)
objfile->Dump(&strm);
+ else {
+ strm.Format("No object file for module: {0:F}\n",
+ module->GetFileSpec());
+ }
}
}
strm.IndentLess();
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 1ae4d4a..94fbc72 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/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<std::recursive_mutex> 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<std::recursive_mutex> 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);
}
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
index 5aa04e3..58cafc7 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/lldb/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);
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h
index b7329ff..1814e9a 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h
+++ b/lldb/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);
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
index 6de4f55..e830898 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
+++ b/lldb/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 {
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index 0f4f123..8149f95 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/lldb/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<PlaceholderModule>(file_spec, GetArchitecture());
+ std::make_shared<PlaceholderModule>(module_spec);
placeholder_module->CreateImageSection(module, GetTarget());
module_sp = placeholder_module;
GetTarget().GetImages().Append(module_sp);