Attempt #2 to get this patch working. I will watch the build bots carefully today.

Allow partial UUID matching in Minidump core file plug-in

Breakpad had bugs in earlier versions where it would take a 20 byte ELF build ID and put it into the minidump file as a 16 byte PDB70 UUID with an age of zero. This would make it impossible to do postmortem debugging with one of these older minidump files.

This fix allows partial matching of UUIDs. To do this we first try and match with the full UUID value, and then fall back to removing the original directory path from the module specification and we remove the UUID requirement, and then manually do the matching ourselves. This allows scripts to find symbols files using a symbol server, place them all in a directory, use the "setting set target.exec-search-paths" setting to specify the directory, and then load the core file. The Target::GetSharedModule() can then find the correct file without doing any other matching and load it.

Tests were added to cover a partial UUID match where the breakpad file has a 16 byte UUID and the actual file on disk has a 20 byte UUID, both where the first 16 bytes match, and don't match.

Differential Revision: https://reviews.llvm.org/D60001

llvm-svn: 357603
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index a7f35b4..4d16f82 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -351,6 +351,8 @@
   std::vector<const MinidumpModule *> filtered_modules =
       m_minidump_parser->GetFilteredModuleList();
 
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
+
   for (auto module : filtered_modules) {
     llvm::Optional<std::string> name =
         m_minidump_parser->GetMinidumpString(module->module_name_rva);
@@ -358,7 +360,6 @@
     if (!name)
       continue;
 
-    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
     if (log) {
       log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
                   "-%#010" PRIx64 " size: %" PRIu32,
@@ -374,14 +375,46 @@
       m_is_wow64 = true;
     }
 
+    if (log) {
+      log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
+                  name.getValue().c_str());
+    }
+
     const auto uuid = m_minidump_parser->GetModuleUUID(module);
     auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
     FileSystem::Instance().Resolve(file_spec);
     ModuleSpec module_spec(file_spec, uuid);
     module_spec.GetArchitecture() = GetArchitecture();
     Status error;
+    // Try and find a module with a full UUID that matches. This function will
+    // add the module to the target if it finds one.
     lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
-    if (!module_sp || error.Fail()) {
+    if (!module_sp) {
+      // Try and find a module without specifying the UUID and only looking for
+      // the file given a basename. We then will look for a partial UUID match
+      // if we find any matches. This function will add the module to the
+      // target if it finds one, so we need to remove the module from the target
+      // if the UUID doesn't match during our manual UUID verification. This
+      // allows the "target.exec-search-paths" setting to specify one or more
+      // directories that contain executables that can be searched for matches.
+      ModuleSpec basename_module_spec(module_spec);
+      basename_module_spec.GetUUID().Clear();
+      basename_module_spec.GetFileSpec().GetDirectory().Clear();
+      module_sp = GetTarget().GetSharedModule(basename_module_spec, &error);
+      if (module_sp) {
+        // We consider the module to be a match if the minidump UUID is a
+        // prefix of the actual UUID, or if either of the UUIDs are empty.
+        const auto dmp_bytes = uuid.GetBytes();
+        const auto mod_bytes = module_sp->GetUUID().GetBytes();
+        const bool match = dmp_bytes.empty() || mod_bytes.empty() ||
+            mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes;
+        if (!match) {
+            GetTarget().GetImages().Remove(module_sp);
+            module_sp.reset();
+        }
+      }
+    }
+    if (!module_sp) {
       // 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.
@@ -400,11 +433,6 @@
       GetTarget().GetImages().Append(module_sp);
     }
 
-    if (log) {
-      log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
-                  name.getValue().c_str());
-    }
-
     bool load_addr_changed = false;
     module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
                               load_addr_changed);