Skip to content

Commit 1bec6eb

Browse files
committed
Add support for firmware/standalone LC_NOTE "main bin spec" corefiles
When a Mach-O corefile has an LC_NOTE "main bin spec" for a standalone binary / firmware, with only a UUID and no load address, try to locate the binary and dSYM by UUID and if found, load it at offset 0 for the user. Add a test case that tests a firmware/standalone corefile with both the "kern ver str" and "main bin spec" LC_NOTEs. <rdar://problem/68193804> Differential Revision: https://reviews.llvm.org/D88282
1 parent a83eb04 commit 1bec6eb

File tree

9 files changed

+660
-91
lines changed

9 files changed

+660
-91
lines changed

lldb/include/lldb/Symbol/ObjectFile.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
9191
eStrataJIT
9292
};
9393

94+
/// If we have a corefile binary hint, this enum
95+
/// specifies the binary type which we can use to
96+
/// select the correct DynamicLoader plugin.
97+
enum BinaryType {
98+
eBinaryTypeInvalid = 0,
99+
eBinaryTypeUnknown,
100+
eBinaryTypeKernel, /// kernel binary
101+
eBinaryTypeUser, /// user process binary
102+
eBinaryTypeStandalone /// standalone binary / firmware
103+
};
104+
94105
struct LoadableData {
95106
lldb::addr_t Dest;
96107
llvm::ArrayRef<uint8_t> Contents;
@@ -500,12 +511,17 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
500511
/// If the uuid of the binary is specified, this will be set.
501512
/// If no UUID is available, will be cleared.
502513
///
514+
/// \param[out] type
515+
/// Return the type of the binary, which will dictate which
516+
/// DynamicLoader plugin should be used.
517+
///
503518
/// \return
504519
/// Returns true if either address or uuid has been set.
505-
virtual bool GetCorefileMainBinaryInfo (lldb::addr_t &address, UUID &uuid) {
506-
address = LLDB_INVALID_ADDRESS;
507-
uuid.Clear();
508-
return false;
520+
virtual bool GetCorefileMainBinaryInfo(lldb::addr_t &address, UUID &uuid,
521+
ObjectFile::BinaryType &type) {
522+
address = LLDB_INVALID_ADDRESS;
523+
uuid.Clear();
524+
return false;
509525
}
510526

511527
virtual lldb::RegisterContextSP

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5519,7 +5519,8 @@ std::string ObjectFileMachO::GetIdentifierString() {
55195519
return result;
55205520
}
55215521

5522-
bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) {
5522+
bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid,
5523+
ObjectFile::BinaryType &type) {
55235524
address = LLDB_INVALID_ADDRESS;
55245525
uuid.Clear();
55255526
ModuleSP module_sp(GetModule());
@@ -5542,24 +5543,43 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) {
55425543
// "main bin spec" (main binary specification) data payload is
55435544
// formatted:
55445545
// uint32_t version [currently 1]
5545-
// uint32_t type [0 == unspecified, 1 == kernel, 2 == user
5546-
// process] uint64_t address [ UINT64_MAX if address not
5547-
// specified ] uuid_t uuid [ all zero's if uuid not
5548-
// specified ] uint32_t log2_pagesize [ process page size in log base
5549-
// 2, e.g. 4k pages are 12. 0 for unspecified ]
5546+
// uint32_t type [0 == unspecified, 1 == kernel,
5547+
// 2 == user process, 3 == firmware ]
5548+
// uint64_t address [ UINT64_MAX if address not specified ]
5549+
// uuid_t uuid [ all zero's if uuid not specified ]
5550+
// uint32_t log2_pagesize [ process page size in log base
5551+
// 2, e.g. 4k pages are 12.
5552+
// 0 for unspecified ]
5553+
// uint32_t unused [ for alignment ]
55505554

55515555
if (strcmp("main bin spec", data_owner) == 0 && size >= 32) {
55525556
offset = fileoff;
55535557
uint32_t version;
55545558
if (m_data.GetU32(&offset, &version, 1) != nullptr && version == 1) {
5555-
uint32_t type = 0;
5559+
uint32_t binspec_type = 0;
55565560
uuid_t raw_uuid;
55575561
memset(raw_uuid, 0, sizeof(uuid_t));
55585562

5559-
if (m_data.GetU32(&offset, &type, 1) &&
5563+
if (m_data.GetU32(&offset, &binspec_type, 1) &&
55605564
m_data.GetU64(&offset, &address, 1) &&
55615565
m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) {
55625566
uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t));
5567+
// convert the "main bin spec" type into our
5568+
// ObjectFile::BinaryType enum
5569+
switch (binspec_type) {
5570+
case 0:
5571+
type = eBinaryTypeUnknown;
5572+
break;
5573+
case 1:
5574+
type = eBinaryTypeKernel;
5575+
break;
5576+
case 2:
5577+
type = eBinaryTypeUser;
5578+
break;
5579+
case 3:
5580+
type = eBinaryTypeStandalone;
5581+
break;
5582+
}
55635583
return true;
55645584
}
55655585
}

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ class ObjectFileMachO : public lldb_private::ObjectFile {
112112

113113
std::string GetIdentifierString() override;
114114

115-
bool GetCorefileMainBinaryInfo (lldb::addr_t &address, lldb_private::UUID &uuid) override;
115+
bool GetCorefileMainBinaryInfo(lldb::addr_t &address,
116+
lldb_private::UUID &uuid,
117+
ObjectFile::BinaryType &type) override;
116118

117119
lldb::RegisterContextSP
118120
GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override;

lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp

Lines changed: 103 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,9 @@ Status ProcessMachCore::DoLoadCore() {
281281

282282
addr_t objfile_binary_addr;
283283
UUID objfile_binary_uuid;
284-
if (core_objfile->GetCorefileMainBinaryInfo (objfile_binary_addr, objfile_binary_uuid))
285-
{
284+
ObjectFile::BinaryType type;
285+
if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_addr,
286+
objfile_binary_uuid, type)) {
286287
if (objfile_binary_addr != LLDB_INVALID_ADDRESS)
287288
{
288289
m_mach_kernel_addr = objfile_binary_addr;
@@ -293,7 +294,7 @@ Status ProcessMachCore::DoLoadCore() {
293294
m_mach_kernel_addr);
294295
}
295296
}
296-
297+
297298
// This checks for the presence of an LC_IDENT string in a core file;
298299
// LC_IDENT is very obsolete and should not be used in new code, but if the
299300
// load command is present, let's use the contents.
@@ -326,58 +327,80 @@ Status ProcessMachCore::DoLoadCore() {
326327
addr, corefile_identifier.c_str());
327328
}
328329
}
329-
if (found_main_binary_definitively == false
330-
&& corefile_identifier.find("EFI ") != std::string::npos) {
331-
UUID uuid;
330+
331+
// In the case where we have an LC_NOTE specifying a standalone
332+
// binary with only a UUID (and no load address) (iBoot, EFI, etc),
333+
// then let's try to force a load of the binary and set its
334+
// load address to 0-offset.
335+
//
336+
// The two forms this can come in is either a
337+
// 'kern ver str' LC_NOTE with "EFI UUID=...."
338+
// 'main bin spec' LC_NOTE with UUID and no load address.
339+
340+
if (found_main_binary_definitively == false &&
341+
(corefile_identifier.find("EFI ") != std::string::npos ||
342+
(objfile_binary_uuid.IsValid() &&
343+
objfile_binary_addr == LLDB_INVALID_ADDRESS))) {
344+
UUID uuid;
345+
if (objfile_binary_uuid.IsValid()) {
346+
uuid = objfile_binary_uuid;
347+
LLDB_LOGF(log,
348+
"ProcessMachCore::DoLoadCore: Using the main bin spec "
349+
"LC_NOTE with UUID %s and no load address",
350+
uuid.GetAsString().c_str());
351+
} else {
332352
if (corefile_identifier.find("UUID=") != std::string::npos) {
333-
size_t p = corefile_identifier.find("UUID=") + strlen("UUID=");
334-
std::string uuid_str = corefile_identifier.substr(p, 36);
335-
uuid.SetFromStringRef(uuid_str);
353+
size_t p = corefile_identifier.find("UUID=") + strlen("UUID=");
354+
std::string uuid_str = corefile_identifier.substr(p, 36);
355+
uuid.SetFromStringRef(uuid_str);
356+
if (uuid.IsValid()) {
357+
LLDB_LOGF(log,
358+
"ProcessMachCore::DoLoadCore: Using the EFI "
359+
"from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'",
360+
corefile_identifier.c_str());
361+
}
336362
}
337-
if (uuid.IsValid()) {
338-
LLDB_LOGF(log,
339-
"ProcessMachCore::DoLoadCore: Using the EFI "
340-
"from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'",
341-
corefile_identifier.c_str());
342-
343-
// We're only given a UUID here, not a load address.
344-
// But there are python scripts in the EFI binary's dSYM which
345-
// know how to relocate the binary to the correct load address.
346-
// lldb only needs to locate & load the binary + dSYM.
347-
ModuleSpec module_spec;
348-
module_spec.GetUUID() = uuid;
349-
module_spec.GetArchitecture() = GetTarget().GetArchitecture();
350-
351-
// Lookup UUID locally, before attempting dsymForUUID like action
352-
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
353-
module_spec.GetSymbolFileSpec() =
354-
Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
355-
if (module_spec.GetSymbolFileSpec()) {
356-
ModuleSpec executable_module_spec =
357-
Symbols::LocateExecutableObjectFile(module_spec);
358-
if (FileSystem::Instance().Exists(
359-
executable_module_spec.GetFileSpec())) {
360-
module_spec.GetFileSpec() = executable_module_spec.GetFileSpec();
361-
}
363+
}
364+
365+
if (uuid.IsValid()) {
366+
ModuleSpec module_spec;
367+
module_spec.GetUUID() = uuid;
368+
module_spec.GetArchitecture() = GetTarget().GetArchitecture();
369+
370+
// Lookup UUID locally, before attempting dsymForUUID-like action
371+
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
372+
module_spec.GetSymbolFileSpec() =
373+
Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
374+
if (module_spec.GetSymbolFileSpec()) {
375+
ModuleSpec executable_module_spec =
376+
Symbols::LocateExecutableObjectFile(module_spec);
377+
if (FileSystem::Instance().Exists(
378+
executable_module_spec.GetFileSpec())) {
379+
module_spec.GetFileSpec() = executable_module_spec.GetFileSpec();
362380
}
381+
}
363382

364-
// Force a a dsymForUUID lookup, if that tool is available.
365-
if (!module_spec.GetSymbolFileSpec())
366-
Symbols::DownloadObjectAndSymbolFile(module_spec, true);
367-
368-
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
369-
ModuleSP module_sp(new Module(module_spec));
370-
if (module_sp.get() && module_sp->GetObjectFile()) {
371-
// Get the current target executable
372-
ModuleSP exe_module_sp(GetTarget().GetExecutableModule());
373-
374-
// Make sure you don't already have the right module loaded
375-
// and they will be uniqued
376-
if (exe_module_sp.get() != module_sp.get())
377-
GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo);
378-
}
383+
// Force a a dsymForUUID lookup, if that tool is available.
384+
if (!module_spec.GetSymbolFileSpec())
385+
Symbols::DownloadObjectAndSymbolFile(module_spec, true);
386+
387+
// If we found a binary, load it at offset 0 and set our
388+
// dyld_plugin to be the static plugin.
389+
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
390+
ModuleSP module_sp(new Module(module_spec));
391+
if (module_sp.get() && module_sp->GetObjectFile()) {
392+
GetTarget().GetImages().AppendIfNeeded(module_sp, true);
393+
GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo);
394+
found_main_binary_definitively = true;
395+
bool changed = true;
396+
module_sp->SetLoadAddress(GetTarget(), 0, true, changed);
397+
ModuleList added_module;
398+
added_module.Append(module_sp, false);
399+
GetTarget().ModulesDidLoad(added_module);
400+
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
379401
}
380402
}
403+
}
381404
}
382405

383406
if (!found_main_binary_definitively &&
@@ -440,35 +463,37 @@ Status ProcessMachCore::DoLoadCore() {
440463
}
441464
}
442465

443-
// If we found both a user-process dyld and a kernel binary, we need to
444-
// decide which to prefer.
445-
if (GetCorefilePreference() == eKernelCorefile) {
446-
if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
447-
LLDB_LOGF(log,
448-
"ProcessMachCore::DoLoadCore: Using kernel corefile image "
449-
"at 0x%" PRIx64,
450-
m_mach_kernel_addr);
451-
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
452-
} else if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
453-
LLDB_LOGF(log,
454-
"ProcessMachCore::DoLoadCore: Using user process dyld "
455-
"image at 0x%" PRIx64,
456-
m_dyld_addr);
457-
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
458-
}
459-
} else {
460-
if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
461-
LLDB_LOGF(log,
462-
"ProcessMachCore::DoLoadCore: Using user process dyld "
463-
"image at 0x%" PRIx64,
464-
m_dyld_addr);
465-
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
466-
} else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
467-
LLDB_LOGF(log,
468-
"ProcessMachCore::DoLoadCore: Using kernel corefile image "
469-
"at 0x%" PRIx64,
470-
m_mach_kernel_addr);
471-
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
466+
if (m_dyld_plugin_name.IsEmpty()) {
467+
// If we found both a user-process dyld and a kernel binary, we need to
468+
// decide which to prefer.
469+
if (GetCorefilePreference() == eKernelCorefile) {
470+
if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
471+
LLDB_LOGF(log,
472+
"ProcessMachCore::DoLoadCore: Using kernel corefile image "
473+
"at 0x%" PRIx64,
474+
m_mach_kernel_addr);
475+
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
476+
} else if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
477+
LLDB_LOGF(log,
478+
"ProcessMachCore::DoLoadCore: Using user process dyld "
479+
"image at 0x%" PRIx64,
480+
m_dyld_addr);
481+
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
482+
}
483+
} else {
484+
if (m_dyld_addr != LLDB_INVALID_ADDRESS) {
485+
LLDB_LOGF(log,
486+
"ProcessMachCore::DoLoadCore: Using user process dyld "
487+
"image at 0x%" PRIx64,
488+
m_dyld_addr);
489+
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
490+
} else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) {
491+
LLDB_LOGF(log,
492+
"ProcessMachCore::DoLoadCore: Using kernel corefile image "
493+
"at 0x%" PRIx64,
494+
m_mach_kernel_addr);
495+
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
496+
}
472497
}
473498
}
474499

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
MAKE_DSYM := NO
2+
C_SOURCES := main.c
3+
CFLAGS_EXTRAS := -Wl,-random_uuid
4+
5+
all: a.out b.out create-empty-corefile
6+
7+
create-empty-corefile:
8+
$(MAKE) -f $(MAKEFILE_RULES) EXE=create-empty-corefile \
9+
C_SOURCES=create-empty-corefile.c
10+
11+
b.out:
12+
$(MAKE) VPATH=$(SRCDIR)/$* -I $(SRCDIR) -f $(SRCDIR)/bout.mk
13+
14+
include Makefile.rules

0 commit comments

Comments
 (0)