Skip to content

Commit b2e83f9

Browse files
committed
Handle all standalone combinations of LC_NOTEs w/ & w/o addr & uuid
Fill out ProcessMachCore::DoLoadCore to handle LC_NOTE hints with a UUID or with a UUID+address, and load the binary at the specified offset correctly. Add tests for all four combinations. Change DynamicLoaderStatic to not re-set a Section's load address in the Target if it's already been specified. Differential Revision: https://reviews.llvm.org/D99571 rdar://51490545 (cherry picked from commit 78a1412)
1 parent 7602cdd commit b2e83f9

File tree

4 files changed

+198
-115
lines changed

4 files changed

+198
-115
lines changed

lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "lldb/Core/PluginManager.h"
1111
#include "lldb/Core/Section.h"
1212
#include "lldb/Symbol/ObjectFile.h"
13+
#include "lldb/Target/SectionLoadList.h"
1314
#include "lldb/Target/Target.h"
1415

1516
#include "DynamicLoaderStatic.h"
@@ -109,6 +110,15 @@ void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() {
109110
// the file...
110111
SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
111112
if (section_sp) {
113+
// If this section already has a load address set in the target,
114+
// don't re-set it to the file address. Something may have
115+
// set it to a more correct value already.
116+
if (m_process->GetTarget()
117+
.GetSectionLoadList()
118+
.GetSectionLoadAddress(section_sp) !=
119+
LLDB_INVALID_ADDRESS) {
120+
continue;
121+
}
112122
if (m_process->GetTarget().SetSectionLoadAddress(
113123
section_sp, section_sp->GetFileAddress()))
114124
changed = true;

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

Lines changed: 106 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "lldb/Symbol/LocateSymbolFile.h"
2222
#include "lldb/Symbol/ObjectFile.h"
2323
#include "lldb/Target/MemoryRegionInfo.h"
24+
#include "lldb/Target/SectionLoadList.h"
2425
#include "lldb/Target/Target.h"
2526
#include "lldb/Target/Thread.h"
2627
#include "lldb/Utility/DataBuffer.h"
@@ -36,6 +37,7 @@
3637

3738
#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
3839
#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
40+
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
3941
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
4042

4143
#include <memory>
@@ -188,6 +190,59 @@ bool ProcessMachCore::GetDynamicLoaderAddress(lldb::addr_t addr) {
188190
return false;
189191
}
190192

193+
// We have a hint about a binary -- a UUID, possibly a load address.
194+
// Try to load a file with that UUID into lldb, and if we have a load
195+
// address, set it correctly. Else assume that the binary was loaded
196+
// with no slide.
197+
static bool load_standalone_binary(UUID uuid, addr_t addr, Target &target) {
198+
if (uuid.IsValid()) {
199+
ModuleSpec module_spec;
200+
module_spec.GetUUID() = uuid;
201+
202+
// Look up UUID in global module cache before attempting
203+
// dsymForUUID-like action.
204+
ModuleSP module_sp;
205+
Status error = ModuleList::GetSharedModule(module_spec, module_sp, nullptr,
206+
nullptr, nullptr);
207+
208+
if (!module_sp.get()) {
209+
// Force a a dsymForUUID lookup, if that tool is available.
210+
if (!module_spec.GetSymbolFileSpec())
211+
Symbols::DownloadObjectAndSymbolFile(module_spec, true);
212+
213+
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
214+
module_sp = std::make_shared<Module>(module_spec);
215+
}
216+
}
217+
218+
if (module_sp.get() && module_sp->GetObjectFile()) {
219+
target.SetArchitecture(module_sp->GetObjectFile()->GetArchitecture());
220+
target.GetImages().AppendIfNeeded(module_sp, false);
221+
222+
Address base_addr = module_sp->GetObjectFile()->GetBaseAddress();
223+
addr_t slide = 0;
224+
if (addr != LLDB_INVALID_ADDRESS && base_addr.IsValid()) {
225+
addr_t file_load_addr = base_addr.GetFileAddress();
226+
slide = addr - file_load_addr;
227+
}
228+
bool changed = false;
229+
module_sp->SetLoadAddress(target, slide, true, changed);
230+
231+
ModuleList added_module;
232+
added_module.Append(module_sp, false);
233+
target.ModulesDidLoad(added_module);
234+
235+
// Flush info in the process (stack frames, etc).
236+
ProcessSP process_sp(target.GetProcessSP());
237+
if (process_sp)
238+
process_sp->Flush();
239+
240+
return true;
241+
}
242+
}
243+
return false;
244+
}
245+
191246
// Process Control
192247
Status ProcessMachCore::DoLoadCore() {
193248
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
@@ -285,124 +340,76 @@ Status ProcessMachCore::DoLoadCore() {
285340
ObjectFile::BinaryType type;
286341
if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_addr,
287342
objfile_binary_uuid, type)) {
343+
if (log) {
344+
log->Printf(
345+
"ProcessMachCore::DoLoadCore: using binary hint from 'main bin spec' "
346+
"LC_NOTE with UUID %s address 0x%" PRIx64 " and type %d",
347+
objfile_binary_uuid.GetAsString().c_str(), objfile_binary_addr, type);
348+
}
288349
if (objfile_binary_addr != LLDB_INVALID_ADDRESS) {
289-
if (type == ObjectFile::eBinaryTypeUser)
350+
if (type == ObjectFile::eBinaryTypeUser) {
290351
m_dyld_addr = objfile_binary_addr;
291-
else
352+
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
353+
found_main_binary_definitively = true;
354+
}
355+
if (type == ObjectFile::eBinaryTypeKernel) {
292356
m_mach_kernel_addr = objfile_binary_addr;
293-
found_main_binary_definitively = true;
294-
LLDB_LOGF(log,
295-
"ProcessMachCore::DoLoadCore: using kernel address 0x%" PRIx64
296-
" from LC_NOTE 'main bin spec' load command.",
297-
m_mach_kernel_addr);
357+
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
358+
found_main_binary_definitively = true;
359+
}
360+
}
361+
if (!found_main_binary_definitively) {
362+
// ObjectFile::eBinaryTypeStandalone, undeclared types
363+
if (load_standalone_binary(objfile_binary_uuid, objfile_binary_addr,
364+
GetTarget())) {
365+
found_main_binary_definitively = true;
366+
m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
367+
}
298368
}
299369
}
300370

301371
// This checks for the presence of an LC_IDENT string in a core file;
302372
// LC_IDENT is very obsolete and should not be used in new code, but if the
303373
// load command is present, let's use the contents.
304-
std::string corefile_identifier = core_objfile->GetIdentifierString();
305-
if (!found_main_binary_definitively &&
306-
corefile_identifier.find("Darwin Kernel") != std::string::npos) {
307-
UUID uuid;
308-
addr_t addr = LLDB_INVALID_ADDRESS;
374+
UUID ident_uuid;
375+
addr_t ident_binary_addr = LLDB_INVALID_ADDRESS;
376+
if (!found_main_binary_definitively) {
377+
std::string corefile_identifier = core_objfile->GetIdentifierString();
378+
379+
// Search for UUID= and stext= strings in the identifier str.
309380
if (corefile_identifier.find("UUID=") != std::string::npos) {
310381
size_t p = corefile_identifier.find("UUID=") + strlen("UUID=");
311382
std::string uuid_str = corefile_identifier.substr(p, 36);
312-
uuid.SetFromStringRef(uuid_str);
383+
ident_uuid.SetFromStringRef(uuid_str);
384+
if (log)
385+
log->Printf("Got a UUID from LC_IDENT/kern ver str LC_NOTE: %s",
386+
ident_uuid.GetAsString().c_str());
313387
}
314388
if (corefile_identifier.find("stext=") != std::string::npos) {
315389
size_t p = corefile_identifier.find("stext=") + strlen("stext=");
316390
if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') {
317-
errno = 0;
318-
addr = ::strtoul(corefile_identifier.c_str() + p, nullptr, 16);
319-
if (errno != 0 || addr == 0)
320-
addr = LLDB_INVALID_ADDRESS;
391+
ident_binary_addr =
392+
::strtoul(corefile_identifier.c_str() + p, nullptr, 16);
393+
if (log)
394+
log->Printf("Got a load address from LC_IDENT/kern ver str "
395+
"LC_NOTE: 0x%" PRIx64,
396+
ident_binary_addr);
321397
}
322398
}
323-
if (uuid.IsValid() && addr != LLDB_INVALID_ADDRESS) {
324-
m_mach_kernel_addr = addr;
325-
found_main_binary_definitively = true;
326-
LLDB_LOGF(
327-
log,
328-
"ProcessMachCore::DoLoadCore: Using the kernel address 0x%" PRIx64
329-
" from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'",
330-
addr, corefile_identifier.c_str());
331-
}
332-
}
333399

334-
// In the case where we have an LC_NOTE specifying a standalone
335-
// binary with only a UUID (and no load address) (iBoot, EFI, etc),
336-
// then let's try to force a load of the binary and set its
337-
// load address to 0-offset.
338-
//
339-
// The two forms this can come in is either a
340-
// 'kern ver str' LC_NOTE with "EFI UUID=...."
341-
// 'main bin spec' LC_NOTE with UUID and no load address.
342-
343-
if (found_main_binary_definitively == false &&
344-
(corefile_identifier.find("EFI ") != std::string::npos ||
345-
(objfile_binary_uuid.IsValid() &&
346-
objfile_binary_addr == LLDB_INVALID_ADDRESS))) {
347-
UUID uuid;
348-
if (objfile_binary_uuid.IsValid()) {
349-
uuid = objfile_binary_uuid;
350-
LLDB_LOGF(log,
351-
"ProcessMachCore::DoLoadCore: Using the main bin spec "
352-
"LC_NOTE with UUID %s and no load address",
353-
uuid.GetAsString().c_str());
354-
} else {
355-
if (corefile_identifier.find("UUID=") != std::string::npos) {
356-
size_t p = corefile_identifier.find("UUID=") + strlen("UUID=");
357-
std::string uuid_str = corefile_identifier.substr(p, 36);
358-
uuid.SetFromStringRef(uuid_str);
359-
if (uuid.IsValid()) {
360-
LLDB_LOGF(log,
361-
"ProcessMachCore::DoLoadCore: Using the EFI "
362-
"from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'",
363-
corefile_identifier.c_str());
364-
}
365-
}
366-
}
367-
368-
if (uuid.IsValid()) {
369-
ModuleSpec module_spec;
370-
module_spec.GetUUID() = uuid;
371-
module_spec.GetArchitecture() = GetTarget().GetArchitecture();
372-
373-
// Lookup UUID locally, before attempting dsymForUUID-like action
374-
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
375-
module_spec.GetSymbolFileSpec() =
376-
Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
377-
if (module_spec.GetSymbolFileSpec()) {
378-
ModuleSpec executable_module_spec =
379-
Symbols::LocateExecutableObjectFile(module_spec);
380-
if (FileSystem::Instance().Exists(
381-
executable_module_spec.GetFileSpec())) {
382-
module_spec.GetFileSpec() = executable_module_spec.GetFileSpec();
383-
}
384-
}
385-
386-
// Force a a dsymForUUID lookup, if that tool is available.
387-
if (!module_spec.GetSymbolFileSpec())
388-
Symbols::DownloadObjectAndSymbolFile(module_spec, true);
389-
390-
// If we found a binary, load it at offset 0 and set our
391-
// dyld_plugin to be the static plugin.
392-
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
393-
ModuleSP module_sp(new Module(module_spec));
394-
if (module_sp.get() && module_sp->GetObjectFile()) {
395-
GetTarget().GetImages().AppendIfNeeded(module_sp, true);
396-
GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo);
397-
found_main_binary_definitively = true;
398-
bool changed = true;
399-
module_sp->SetLoadAddress(GetTarget(), 0, true, changed);
400-
ModuleList added_module;
401-
added_module.Append(module_sp, false);
402-
GetTarget().ModulesDidLoad(added_module);
403-
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
404-
found_main_binary_definitively = true;
405-
}
400+
// Search for a "Darwin Kernel" str indicating kernel; else treat as
401+
// standalone
402+
if (corefile_identifier.find("Darwin Kernel") != std::string::npos &&
403+
ident_uuid.IsValid() && ident_binary_addr != LLDB_INVALID_ADDRESS) {
404+
if (log)
405+
log->Printf("ProcessMachCore::DoLoadCore: Found kernel binary via "
406+
"LC_IDENT/kern ver str LC_NOTE");
407+
m_mach_kernel_addr = ident_binary_addr;
408+
found_main_binary_definitively = true;
409+
} else if (ident_uuid.IsValid()) {
410+
if (load_standalone_binary(ident_uuid, ident_binary_addr, GetTarget())) {
411+
found_main_binary_definitively = true;
412+
m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
406413
}
407414
}
408415
}

lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ def test_lc_note(self):
2626
self.create_corefile = self.getBuildArtifact("create-empty-corefile")
2727
self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh")
2828
self.aout_corefile = self.getBuildArtifact("aout.core")
29+
self.aout_corefile_addr = self.getBuildArtifact("aout.core_addr")
2930
self.bout_corefile = self.getBuildArtifact("bout.core")
31+
self.bout_corefile_addr = self.getBuildArtifact("bout.core_addr")
3032

3133
## We can hook in our dsym-for-uuid shell script to lldb with this env
3234
## var instead of requiring a defaults write.
@@ -98,9 +100,13 @@ def test_lc_note(self):
98100

99101
os.chmod(self.dsym_for_uuid, 0o755)
100102

103+
self.slide = 0x70000000000
104+
101105
### Create our corefile
102-
retcode = call(self.create_corefile + " version-string " + self.aout_corefile + " " + self.aout_exe, shell=True)
103-
retcode = call(self.create_corefile + " main-bin-spec " + self.bout_corefile + " " + self.bout_exe, shell=True)
106+
retcode = call(self.create_corefile + " version-string " + self.aout_corefile + " " + self.aout_exe + " 0xffffffffffffffff", shell=True)
107+
retcode = call(self.create_corefile + " main-bin-spec " + self.bout_corefile + " " + self.bout_exe + " 0xffffffffffffffff", shell=True)
108+
retcode = call(self.create_corefile + " version-string " + self.aout_corefile_addr + " " + self.aout_exe + (" 0x%x" % self.slide), shell=True)
109+
retcode = call(self.create_corefile + " main-bin-spec " + self.bout_corefile_addr + " " + self.bout_exe + (" 0x%x" % self.slide), shell=True)
104110

105111
### Now run lldb on the corefile
106112
### which will give us a UUID
@@ -111,23 +117,61 @@ def test_lc_note(self):
111117
# First, try the "kern ver str" corefile
112118
self.target = self.dbg.CreateTarget('')
113119
err = lldb.SBError()
120+
if self.TraceOn():
121+
self.runCmd("log enable lldb dyld")
122+
self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld"))
123+
114124
self.process = self.target.LoadCore(self.aout_corefile)
115125
self.assertEqual(self.process.IsValid(), True)
116126
if self.TraceOn():
117127
self.runCmd("image list")
128+
self.runCmd("target mod dump sections")
118129
self.assertEqual(self.target.GetNumModules(), 1)
119130
fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
120131
filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
121132
self.assertEqual(filepath, self.aout_exe)
122133

134+
# Second, try the "kern ver str" corefile where it loads at an address
135+
self.target = self.dbg.CreateTarget('')
136+
err = lldb.SBError()
137+
self.process = self.target.LoadCore(self.aout_corefile_addr)
138+
self.assertEqual(self.process.IsValid(), True)
139+
if self.TraceOn():
140+
self.runCmd("image list")
141+
self.runCmd("target mod dump sections")
142+
self.assertEqual(self.target.GetNumModules(), 1)
143+
fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
144+
filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
145+
self.assertEqual(filepath, self.aout_exe)
146+
main_sym = self.target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
147+
main_addr = main_sym.GetStartAddress()
148+
self.assertGreater(main_addr.GetLoadAddress(self.target), self.slide)
149+
self.assertNotEqual(main_addr.GetLoadAddress(self.target), lldb.LLDB_INVALID_ADDRESS)
123150

124-
# Second, try the "main bin spec" corefile
151+
# Third, try the "main bin spec" corefile
125152
self.target = self.dbg.CreateTarget('')
126153
self.process = self.target.LoadCore(self.bout_corefile)
127154
self.assertEqual(self.process.IsValid(), True)
128155
if self.TraceOn():
129156
self.runCmd("image list")
157+
self.runCmd("target mod dump sections")
158+
self.assertEqual(self.target.GetNumModules(), 1)
159+
fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
160+
filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
161+
self.assertEqual(filepath, self.bout_exe)
162+
163+
# Fourth, try the "main bin spec" corefile where it loads at an address
164+
self.target = self.dbg.CreateTarget('')
165+
self.process = self.target.LoadCore(self.bout_corefile_addr)
166+
self.assertEqual(self.process.IsValid(), True)
167+
if self.TraceOn():
168+
self.runCmd("image list")
169+
self.runCmd("target mod dump sections")
130170
self.assertEqual(self.target.GetNumModules(), 1)
131171
fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
132172
filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
133173
self.assertEqual(filepath, self.bout_exe)
174+
main_sym = self.target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
175+
main_addr = main_sym.GetStartAddress()
176+
self.assertGreater(main_addr.GetLoadAddress(self.target), self.slide)
177+
self.assertNotEqual(main_addr.GetLoadAddress(self.target), lldb.LLDB_INVALID_ADDRESS)

0 commit comments

Comments
 (0)