Skip to content

Commit bbc428e

Browse files
author
Greg Clayton
committed
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
1 parent 8d248db commit bbc428e

File tree

6 files changed

+116
-7
lines changed

6 files changed

+116
-7
lines changed

Diff for: lldb/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpUUID.py

+53
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import shutil
99

1010
import lldb
11+
import os
1112
from lldbsuite.test.decorators import *
1213
from lldbsuite.test.lldbtest import *
1314
from lldbsuite.test import lldbutil
@@ -132,3 +133,55 @@ def test_uuid_modules_elf_build_id_zero(self):
132133
self.assertEqual(2, len(modules))
133134
self.verify_module(modules[0], "/not/exist/a", None)
134135
self.verify_module(modules[1], "/not/exist/b", None)
136+
137+
@expectedFailureAll(oslist=["windows"])
138+
def test_partial_uuid_match(self):
139+
"""
140+
Breakpad has been known to create minidump files using CvRecord in each
141+
module whose signature is set to PDB70 where the UUID only contains the
142+
first 16 bytes of a 20 byte ELF build ID. Code was added to
143+
ProcessMinidump.cpp to deal with this and allows partial UUID matching.
144+
145+
This test verifies that if we have a minidump with a 16 byte UUID, that
146+
we are able to associate a symbol file with a 20 byte UUID only if the
147+
first 16 bytes match. In this case we will see the path from the file
148+
we found in the test directory and the 20 byte UUID from the actual
149+
file, not the 16 byte shortened UUID from the minidump.
150+
"""
151+
so_path = self.getBuildArtifact("libuuidmatch.so")
152+
self.yaml2obj("libuuidmatch.yaml", so_path)
153+
self.dbg.CreateTarget(None)
154+
self.target = self.dbg.GetSelectedTarget()
155+
cmd = 'settings set target.exec-search-paths "%s"' % (os.path.dirname(so_path))
156+
self.dbg.HandleCommand(cmd)
157+
self.process = self.target.LoadCore("linux-arm-partial-uuids-match.dmp")
158+
modules = self.target.modules
159+
self.assertEqual(1, len(modules))
160+
self.verify_module(modules[0], so_path,
161+
"7295E17C-6668-9E05-CBB5-DEE5003865D5-5267C116")
162+
163+
@expectedFailureAll(oslist=["windows"])
164+
def test_partial_uuid_mismatch(self):
165+
"""
166+
Breakpad has been known to create minidump files using CvRecord in each
167+
module whose signature is set to PDB70 where the UUID only contains the
168+
first 16 bytes of a 20 byte ELF build ID. Code was added to
169+
ProcessMinidump.cpp to deal with this and allows partial UUID matching.
170+
171+
This test verifies that if we have a minidump with a 16 byte UUID, that
172+
we are not able to associate a symbol file with a 20 byte UUID only if
173+
any of the first 16 bytes do not match. In this case we will see the UUID
174+
from the minidump file and the path from the minidump file.
175+
"""
176+
so_path = self.getBuildArtifact("libuuidmismatch.so")
177+
self.yaml2obj("libuuidmismatch.yaml", so_path)
178+
self.dbg.CreateTarget(None)
179+
self.target = self.dbg.GetSelectedTarget()
180+
cmd = 'settings set target.exec-search-paths "%s"' % (os.path.dirname(so_path))
181+
self.dbg.HandleCommand(cmd)
182+
self.process = self.target.LoadCore("linux-arm-partial-uuids-mismatch.dmp")
183+
modules = self.target.modules
184+
self.assertEqual(1, len(modules))
185+
self.verify_module(modules[0],
186+
"/invalid/path/on/current/system/libuuidmismatch.so",
187+
"7295E17C-6668-9E05-CBB5-DEE5003865D5")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--- !ELF
2+
FileHeader:
3+
Class: ELFCLASS32
4+
Data: ELFDATA2LSB
5+
Type: ET_DYN
6+
Machine: EM_ARM
7+
Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
8+
Sections:
9+
- Name: .note.gnu.build-id
10+
Type: SHT_NOTE
11+
Flags: [ SHF_ALLOC ]
12+
Address: 0x0000000000000114
13+
AddressAlign: 0x0000000000000004
14+
Content: 040000001400000003000000474E55007295E17C66689E05CBB5DEE5003865D55267C116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--- !ELF
2+
FileHeader:
3+
Class: ELFCLASS32
4+
Data: ELFDATA2LSB
5+
Type: ET_DYN
6+
Machine: EM_ARM
7+
Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
8+
Sections:
9+
- Name: .note.gnu.build-id
10+
Type: SHT_NOTE
11+
Flags: [ SHF_ALLOC ]
12+
Address: 0x0000000000000114
13+
AddressAlign: 0x0000000000000004
14+
Content: 040000001400000003000000474E55008295E17C66689E05CBB5DEE5003865D55267C116

Diff for: lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp

+35-7
Original file line numberDiff line numberDiff line change
@@ -351,14 +351,15 @@ void ProcessMinidump::ReadModuleList() {
351351
std::vector<const MinidumpModule *> filtered_modules =
352352
m_minidump_parser->GetFilteredModuleList();
353353

354+
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
355+
354356
for (auto module : filtered_modules) {
355357
llvm::Optional<std::string> name =
356358
m_minidump_parser->GetMinidumpString(module->module_name_rva);
357359

358360
if (!name)
359361
continue;
360362

361-
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
362363
if (log) {
363364
log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
364365
"-%#010" PRIx64 " size: %" PRIu32,
@@ -374,14 +375,46 @@ void ProcessMinidump::ReadModuleList() {
374375
m_is_wow64 = true;
375376
}
376377

378+
if (log) {
379+
log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
380+
name.getValue().c_str());
381+
}
382+
377383
const auto uuid = m_minidump_parser->GetModuleUUID(module);
378384
auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
379385
FileSystem::Instance().Resolve(file_spec);
380386
ModuleSpec module_spec(file_spec, uuid);
381387
module_spec.GetArchitecture() = GetArchitecture();
382388
Status error;
389+
// Try and find a module with a full UUID that matches. This function will
390+
// add the module to the target if it finds one.
383391
lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
384-
if (!module_sp || error.Fail()) {
392+
if (!module_sp) {
393+
// Try and find a module without specifying the UUID and only looking for
394+
// the file given a basename. We then will look for a partial UUID match
395+
// if we find any matches. This function will add the module to the
396+
// target if it finds one, so we need to remove the module from the target
397+
// if the UUID doesn't match during our manual UUID verification. This
398+
// allows the "target.exec-search-paths" setting to specify one or more
399+
// directories that contain executables that can be searched for matches.
400+
ModuleSpec basename_module_spec(module_spec);
401+
basename_module_spec.GetUUID().Clear();
402+
basename_module_spec.GetFileSpec().GetDirectory().Clear();
403+
module_sp = GetTarget().GetSharedModule(basename_module_spec, &error);
404+
if (module_sp) {
405+
// We consider the module to be a match if the minidump UUID is a
406+
// prefix of the actual UUID, or if either of the UUIDs are empty.
407+
const auto dmp_bytes = uuid.GetBytes();
408+
const auto mod_bytes = module_sp->GetUUID().GetBytes();
409+
const bool match = dmp_bytes.empty() || mod_bytes.empty() ||
410+
mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes;
411+
if (!match) {
412+
GetTarget().GetImages().Remove(module_sp);
413+
module_sp.reset();
414+
}
415+
}
416+
}
417+
if (!module_sp) {
385418
// We failed to locate a matching local object file. Fortunately, the
386419
// minidump format encodes enough information about each module's memory
387420
// range to allow us to create placeholder modules.
@@ -400,11 +433,6 @@ void ProcessMinidump::ReadModuleList() {
400433
GetTarget().GetImages().Append(module_sp);
401434
}
402435

403-
if (log) {
404-
log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
405-
name.getValue().c_str());
406-
}
407-
408436
bool load_addr_changed = false;
409437
module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
410438
load_addr_changed);

0 commit comments

Comments
 (0)