[Lldb-commits] [lldb] f212032 - Add support for a "load binary" LC_NOTE in mach-o corefiles
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Mon Dec 13 13:22:03 PST 2021
Author: Jason Molenda
Date: 2021-12-13T13:21:56-08:00
New Revision: f2120328e81879bf14d2a5c381749a11577fa304
URL: https://github.com/llvm/llvm-project/commit/f2120328e81879bf14d2a5c381749a11577fa304
DIFF: https://github.com/llvm/llvm-project/commit/f2120328e81879bf14d2a5c381749a11577fa304.diff
LOG: Add support for a "load binary" LC_NOTE in mach-o corefiles
Add lldb support for a Mach-O "load binary" LC_NOTE which provides
a UUID, load address/slide, and possibly a name of a binary that
should be loaded when examining the core.
struct load_binary
{
uint32_t version; // currently 1
uuid_t uuid; // all zeroes if uuid not specified
uint64_t load_address; // virtual address where the macho is loaded, UINT64_MAX if unavail
uint64_t slide; // slide to be applied to file address to get load address, 0 if unavail
char name_cstring[]; // must be nul-byte terminated c-string, '\0' alone if name unavail
} __attribute__((packed));
Differential Revision: https://reviews.llvm.org/D115494
rdar://85069250
Added:
Modified:
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py
lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c
Removed:
################################################################################
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 29cc399f7c2f1..e0087dbd4941e 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -6973,6 +6973,23 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
}
image_infos.all_image_infos.push_back(image_entry);
}
+ } else if (strcmp("load binary", data_owner) == 0) {
+ uint32_t version = m_data.GetU32(&fileoff);
+ if (version == 1) {
+ uuid_t uuid;
+ memcpy(&uuid, m_data.GetData(&fileoff, sizeof(uuid_t)),
+ sizeof(uuid_t));
+ uint64_t load_address = m_data.GetU64(&fileoff);
+ uint64_t slide = m_data.GetU64(&fileoff);
+ std::string filename = m_data.GetCStr(&fileoff);
+
+ MachOCorefileImageEntry image_entry;
+ image_entry.filename = filename;
+ image_entry.uuid = UUID::fromData(uuid, sizeof(uuid_t));
+ image_entry.load_address = load_address;
+ image_entry.slide = slide;
+ image_infos.all_image_infos.push_back(image_entry);
+ }
}
}
offset = cmd_offset + lc.cmdsize;
@@ -6983,29 +7000,42 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
bool ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) {
MachOCorefileAllImageInfos image_infos = GetCorefileAllImageInfos();
- bool added_images = false;
- if (image_infos.IsValid()) {
- for (const MachOCorefileImageEntry &image : image_infos.all_image_infos) {
- ModuleSpec module_spec;
- module_spec.GetUUID() = image.uuid;
- module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
- if (image.currently_executing) {
- Symbols::DownloadObjectAndSymbolFile(module_spec, true);
- if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
- process.GetTarget().GetOrCreateModule(module_spec, false);
- }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ ModuleList added_modules;
+ for (const MachOCorefileImageEntry &image : image_infos.all_image_infos) {
+ ModuleSpec module_spec;
+ module_spec.GetUUID() = image.uuid;
+ module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
+ if (image.currently_executing) {
+ Symbols::DownloadObjectAndSymbolFile(module_spec, true);
+ if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
+ process.GetTarget().GetOrCreateModule(module_spec, false);
}
- Status error;
- ModuleSP module_sp =
- process.GetTarget().GetOrCreateModule(module_spec, false, &error);
- if (!module_sp.get() || !module_sp->GetObjectFile()) {
- if (image.load_address != LLDB_INVALID_ADDRESS) {
- module_sp = process.ReadModuleFromMemory(module_spec.GetFileSpec(),
- image.load_address);
- }
+ }
+ Status error;
+ ModuleSP module_sp =
+ process.GetTarget().GetOrCreateModule(module_spec, false, &error);
+ if (!module_sp.get() || !module_sp->GetObjectFile()) {
+ if (image.load_address != LLDB_INVALID_ADDRESS) {
+ module_sp = process.ReadModuleFromMemory(module_spec.GetFileSpec(),
+ image.load_address);
}
- if (module_sp.get()) {
- added_images = true;
+ }
+ if (module_sp.get()) {
+ // Will call ModulesDidLoad with all modules once they've all
+ // been added to the Target with load addresses. Don't notify
+ // here, before the load address is set.
+ const bool notify = false;
+ process.GetTarget().GetImages().AppendIfNeeded(module_sp, notify);
+ added_modules.Append(module_sp, notify);
+ if (image.segment_load_addresses.size() > 0) {
+ if (log) {
+ std::string uuidstr = image.uuid.GetAsString();
+ log->Printf("ObjectFileMachO::LoadCoreFileImages adding binary '%s' "
+ "UUID %s with section load addresses",
+ image.filename.c_str(), uuidstr.c_str());
+ }
for (auto name_vmaddr_tuple : image.segment_load_addresses) {
SectionList *sectlist = module_sp->GetObjectFile()->GetSectionList();
if (sectlist) {
@@ -7017,8 +7047,47 @@ bool ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) {
}
}
}
+ } else if (image.load_address != LLDB_INVALID_ADDRESS) {
+ if (log) {
+ std::string uuidstr = image.uuid.GetAsString();
+ log->Printf("ObjectFileMachO::LoadCoreFileImages adding binary '%s' "
+ "UUID %s with load address 0x%" PRIx64,
+ image.filename.c_str(), uuidstr.c_str(),
+ image.load_address);
+ }
+ const bool address_is_slide = false;
+ bool changed = false;
+ module_sp->SetLoadAddress(process.GetTarget(), image.load_address,
+ address_is_slide, changed);
+ } else if (image.slide != 0) {
+ if (log) {
+ std::string uuidstr = image.uuid.GetAsString();
+ log->Printf("ObjectFileMachO::LoadCoreFileImages adding binary '%s' "
+ "UUID %s with slide amount 0x%" PRIx64,
+ image.filename.c_str(), uuidstr.c_str(), image.slide);
+ }
+ const bool address_is_slide = true;
+ bool changed = false;
+ module_sp->SetLoadAddress(process.GetTarget(), image.slide,
+ address_is_slide, changed);
+ } else {
+ if (log) {
+ std::string uuidstr = image.uuid.GetAsString();
+ log->Printf("ObjectFileMachO::LoadCoreFileImages adding binary '%s' "
+ "UUID %s at its file address, no slide applied",
+ image.filename.c_str(), uuidstr.c_str());
+ }
+ const bool address_is_slide = true;
+ bool changed = false;
+ module_sp->SetLoadAddress(process.GetTarget(), 0, address_is_slide,
+ changed);
}
}
}
- return added_images;
+ if (added_modules.GetSize() > 0) {
+ process.GetTarget().ModulesDidLoad(added_modules);
+ process.Flush();
+ return true;
+ }
+ return false;
}
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
index b3a941a957222..084b0ac110ba1 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -225,7 +225,8 @@ class ObjectFileMachO : public lldb_private::ObjectFile {
std::string filename;
lldb_private::UUID uuid;
lldb::addr_t load_address = LLDB_INVALID_ADDRESS;
- bool currently_executing;
+ lldb::addr_t slide = 0;
+ bool currently_executing = false;
std::vector<std::tuple<lldb_private::ConstString, lldb::addr_t>>
segment_load_addresses;
};
diff --git a/lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py b/lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py
index 7540763faa0f7..d3b086191ca52 100644
--- a/lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py
+++ b/lldb/test/API/macosx/corefile-default-ptrauth/TestCorefileDefaultPtrauth.py
@@ -18,6 +18,7 @@ class TestCorefileDefaultPtrauth(TestBase):
@skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
@skipIf(archs=no_match(['arm64','arm64e']))
@skipUnlessDarwin
+ @skipIfRemote
def test_lc_note(self):
self.build()
self.test_exe = self.getBuildArtifact("a.out")
@@ -32,16 +33,18 @@ def test_lc_note(self):
## to fall back on its old default value for Darwin arm64 ABIs
## to correctly strip the bits.
+ # Create a Target with our main executable binary to get it
+ # seeded in lldb's global module cache. Then delete the Target.
+ # This way when the corefile searches for a binary with its UUID,
+ # it'll be found by that search.
+ initial_target = self.dbg.CreateTarget(self.test_exe)
+ self.dbg.DeleteTarget(initial_target)
+
self.target = self.dbg.CreateTarget('')
err = lldb.SBError()
self.process = self.target.LoadCore(self.corefile)
self.assertEqual(self.process.IsValid(), True)
- modspec = lldb.SBModuleSpec()
- modspec.SetFileSpec(lldb.SBFileSpec(self.test_exe, True))
- m = self.target.AddModule(modspec)
- self.assertTrue(m.IsValid())
- self.target.SetModuleLoadAddress (m, 0)
-
+
# target variable should show us both the actual function
# pointer with ptrauth bits and the symbol it resolves to,
# with the ptrauth bits stripped, e.g.
diff --git a/lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c b/lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c
index c1052e1b18446..e5168089b87d2 100644
--- a/lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c
+++ b/lldb/test/API/macosx/corefile-default-ptrauth/create-corefile.c
@@ -6,6 +6,7 @@
#include <mach/machine/thread_state.h>
#include <inttypes.h>
#include <sys/syslimits.h>
+#include <uuid/uuid.h>
// Given an executable binary with
// "fmain" (a function pointer to main)
@@ -55,6 +56,28 @@ int main(int argc, char **argv)
}
pclose (nm);
+ sprintf (buf, "dwarfdump -u '%s'", argv[1]);
+ FILE *dwarfdump = popen(buf, "r");
+ if (!dwarfdump) {
+ fprintf (stderr, "Unable to run dwarfdump -u on '%s'\n", argv[1]);
+ exit (1);
+ }
+ uuid_t uuid;
+ uuid_clear (uuid);
+ while (fgets (buf, sizeof(buf), dwarfdump)) {
+ if (strncmp (buf, "UUID: ", 6) == 0) {
+ buf[6 + 36] = '\0';
+ if (uuid_parse (buf + 6, uuid) != 0) {
+ fprintf (stderr, "Unable to parse UUID in '%s'\n", buf);
+ exit (1);
+ }
+ }
+ }
+ if (uuid_is_null(uuid)) {
+ fprintf (stderr, "Got a null uuid for the binary\n");
+ exit (1);
+ }
+
if (main_addr == 0 || fmain_addr == 0) {
fprintf(stderr, "Unable to find address of main or fmain in %s.\n",
argv[1]);
@@ -65,7 +88,9 @@ int main(int argc, char **argv)
// 1. mach header
// 2. LC_THREAD load command
// 3. LC_SEGMENT_64 load command
- // 4. memory segment contents
+ // 4. LC_NOTE load command
+ // 5. memory segment contents
+ // 6. "load binary" note contents
// struct thread_command {
// uint32_t cmd;
@@ -80,13 +105,14 @@ int main(int argc, char **argv)
mh.cputype = CPU_TYPE_ARM64;
mh.cpusubtype = CPU_SUBTYPE_ARM64E;
mh.filetype = MH_CORE;
- mh.ncmds = 2; // LC_THREAD, LC_SEGMENT_64
- mh.sizeofcmds = size_of_thread_cmd + sizeof(struct segment_command_64);
+ mh.ncmds = 3; // LC_THREAD, LC_SEGMENT_64, LC_NOTE
+ mh.sizeofcmds = size_of_thread_cmd + sizeof(struct segment_command_64) + sizeof(struct note_command);
mh.flags = 0;
mh.reserved = 0;
fwrite(&mh, sizeof (mh), 1, out);
+ struct note_command lcnote;
struct segment_command_64 seg;
seg.cmd = LC_SEGMENT_64;
seg.cmdsize = sizeof(seg);
@@ -94,7 +120,7 @@ int main(int argc, char **argv)
seg.vmaddr = fmain_addr;
seg.vmsize = 8;
// Offset to segment contents
- seg.fileoff = sizeof (mh) + size_of_thread_cmd + sizeof(seg);
+ seg.fileoff = sizeof (mh) + size_of_thread_cmd + sizeof(seg) + sizeof(lcnote);
seg.filesize = 8;
seg.maxprot = 3;
seg.initprot = 3;
@@ -116,15 +142,47 @@ int main(int argc, char **argv)
memset (®state, 0, sizeof (regstate));
fwrite (®state, sizeof (regstate), 1, out);
+ lcnote.cmd = LC_NOTE;
+ lcnote.cmdsize = sizeof (lcnote);
+ strcpy (lcnote.data_owner, "load binary");
+
+ // 8 is the size of the LC_SEGMENT contents
+ lcnote.offset = sizeof (mh) + size_of_thread_cmd + sizeof(seg) + sizeof(lcnote) + 8;
+
+ // struct load_binary
+ // {
+ // uint32_t version; // currently 1
+ // uuid_t uuid; // all zeroes if uuid not specified
+ // uint64_t load_address; // virtual address where the macho is loaded, UINT64_MAX if unavail
+ // uint64_t slide; // slide to be applied to file address to get load address, 0 if unavail
+ // char name_cstring[]; // must be nul-byte terminated c-string, '\0' alone if name unavail
+ // } __attribute__((packed));
+ lcnote.size = 4 + 16 + 8 + 8 + sizeof("a.out");
+
+ fwrite (&lcnote, sizeof(lcnote), 1, out);
+
+ // Write the contents of the memory segment
// Or together a random PAC value from a system using 39 bits
// of addressing with the address of main(). lldb will need
// to correctly strip off the high bits to find the address of
// main.
uint64_t segment_contents = 0xe46bff0000000000 | main_addr;
-
fwrite (&segment_contents, sizeof (segment_contents), 1, out);
+ // Now write the contents of the "load binary" LC_NOTE.
+ {
+ uint32_t version = 1;
+ fwrite (&version, sizeof (version), 1, out);
+ fwrite (&uuid, sizeof (uuid), 1, out);
+ uint64_t load_address = UINT64_MAX;
+ fwrite (&load_address, sizeof (load_address), 1, out);
+ uint64_t slide = 0;
+ fwrite (&slide, sizeof (slide), 1, out);
+ strcpy (buf, "a.out");
+ fwrite (buf, 6, 1, out);
+ }
+
fclose (out);
exit (0);
More information about the lldb-commits
mailing list