jasonmolenda created this revision. jasonmolenda added a reviewer: jingham. jasonmolenda added a project: LLDB. Herald added a subscriber: JDevlieghere. Herald added a reviewer: JDevlieghere. jasonmolenda requested review of this revision.
This patch is primarily to ProcessMachCore to correctly load a firmware/standalone main binary in a corefile which is using the "main bin spec" LC_NOTE. There's already support for this for a "kern ver str" LC_NOTE that includes a UUID to load, this patch extends that to the other LC_NOTE and also sets the load address on the binary it locates to 0 (no-slide) as a default loading. I also stopped an unnecessary scan over the corefile looking for user-process dyld or kernel binaries once I'd already gotten one of these two LC_NOTEs. I also modified ObjectFile::GetCorefileMainBinaryInfo to pass up the type of binary that was specified, which was in the "main bin spec" but not returned previously. The test case is based on the one I wrote earlier for test/API/macosx/lc-note/kern-ver-str. It adds the ability to write both types of LC_NOTEs (kern ver str, main bin spec) and compiles two binaries (with random UUIDs). It creates a dsym-for-uuid.sh that recognizes the two UUIDs and points to the correct binaries/dSYMs, creates corefiles using the tool it built earlier, and runs lldb against the corefiles to confirm that the binaries are loaded correctly. It only runs on macOS x86_64 systems for now. I'm not sure there's anyone who's really interested in reviewing this one; ProcessMachCore is my back yard in the codebase :) but I'm open to any comments or suggestions, naturally. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D88282 Files: lldb/include/lldb/Symbol/ObjectFile.h lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp lldb/test/API/macosx/lc-note/firmware-corefile/Makefile lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py lldb/test/API/macosx/lc-note/firmware-corefile/bout.mk lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp lldb/test/API/macosx/lc-note/firmware-corefile/main.c
Index: lldb/test/API/macosx/lc-note/firmware-corefile/main.c =================================================================== --- /dev/null +++ lldb/test/API/macosx/lc-note/firmware-corefile/main.c @@ -0,0 +1,2 @@ +#include <stdio.h> +int main () { puts ("this is the lc-note test program."); } Index: lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp =================================================================== --- /dev/null +++ lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp @@ -0,0 +1,371 @@ +#include <stdio.h> +#include <stdlib.h> +#include <mach-o/loader.h> +#include <vector> +#include <string> +#include <mach/thread_status.h> +#include <string.h> +#include <uuid/uuid.h> + +// Create an empty corefile with a "kern ver str" LC_NOTE +// or a "main bin spec" LC_NOTE.. +// If an existing binary is given as a 3rd argument on the cmd line, +// the UUID from that binary will be encoded in the corefile. +// Otherwise a pre-set UUID will be put in the corefile that +// is created. + +struct main_bin_spec_payload { + uint32_t version; + uint32_t type; + uint64_t address; + uuid_t uuid; + uint32_t log2_pagesize; + uint32_t unused; +}; + + +union uint32_buf { + uint8_t bytebuf[4]; + uint32_t val; +}; + +union uint64_buf { + uint8_t bytebuf[8]; + uint64_t val; +}; + +void +add_uint64(std::vector<uint8_t> &buf, uint64_t val) +{ + uint64_buf conv; + conv.val = val; + for (int i = 0; i < 8; i++) + buf.push_back(conv.bytebuf[i]); +} + +void +add_uint32(std::vector<uint8_t> &buf, uint32_t val) +{ + uint32_buf conv; + conv.val = val; + for (int i = 0; i < 4; i++) + buf.push_back(conv.bytebuf[i]); +} + +std::vector<uint8_t> +x86_lc_thread_load_command () +{ + std::vector<uint8_t> data; + add_uint32 (data, LC_THREAD); // thread_command.cmd + add_uint32 (data, 184); // thread_command.cmdsize + add_uint32 (data, x86_THREAD_STATE64); // thread_command.flavor + add_uint32 (data, x86_THREAD_STATE64_COUNT); // thread_command.count + add_uint64 (data, 0x0000000000000000); // rax + add_uint64 (data, 0x0000000000000400); // rbx + add_uint64 (data, 0x0000000000000000); // rcx + add_uint64 (data, 0x0000000000000000); // rdx + add_uint64 (data, 0x0000000000000000); // rdi + add_uint64 (data, 0x0000000000000000); // rsi + add_uint64 (data, 0xffffff9246e2ba20); // rbp + add_uint64 (data, 0xffffff9246e2ba10); // rsp + add_uint64 (data, 0x0000000000000000); // r8 + add_uint64 (data, 0x0000000000000000); // r9 + add_uint64 (data, 0x0000000000000000); // r10 + add_uint64 (data, 0x0000000000000000); // r11 + add_uint64 (data, 0xffffff7f96ce5fe1); // r12 + add_uint64 (data, 0x0000000000000000); // r13 + add_uint64 (data, 0x0000000000000000); // r14 + add_uint64 (data, 0xffffff9246e2bac0); // r15 + add_uint64 (data, 0xffffff8015a8f6d0); // rip + add_uint64 (data, 0x0000000000011111); // rflags + add_uint64 (data, 0x0000000000022222); // cs + add_uint64 (data, 0x0000000000033333); // fs + add_uint64 (data, 0x0000000000044444); // gs + return data; +} + +void +add_lc_note_kern_ver_str_load_command (std::vector<std::vector<uint8_t> > &loadcmds, + std::vector<uint8_t> &payload, + int payload_file_offset, + std::string uuid) +{ + std::string ident = "EFI UUID="; + ident += uuid; + std::vector<uint8_t> loadcmd_data; + + add_uint32 (loadcmd_data, LC_NOTE); // note_command.cmd + add_uint32 (loadcmd_data, 40); // note_command.cmdsize + char lc_note_name[16]; + memset (lc_note_name, 0, 16); + strcpy (lc_note_name, "kern ver str"); + + // lc_note.data_owner + for (int i = 0; i < 16; i++) + loadcmd_data.push_back (lc_note_name[i]); + + // we start writing the payload at payload_file_offset to leave + // room at the start for the header & the load commands. + uint64_t current_payload_offset = payload.size() + payload_file_offset; + + add_uint64 (loadcmd_data, current_payload_offset); // note_command.offset + add_uint64 (loadcmd_data, 4 + ident.size() + 1); // note_command.size + + loadcmds.push_back (loadcmd_data); + + add_uint32 (payload, 1); // kerneL_version_string.version + for (int i = 0; i < ident.size() + 1; i++) + { + payload.push_back (ident[i]); + } +} + +void +add_lc_note_main_bin_spec_load_command (std::vector<std::vector<uint8_t> > &loadcmds, + std::vector<uint8_t> &payload, + int payload_file_offset, + std::string uuidstr) +{ + std::vector<uint8_t> loadcmd_data; + + add_uint32 (loadcmd_data, LC_NOTE); // note_command.cmd + add_uint32 (loadcmd_data, 40); // note_command.cmdsize + char lc_note_name[16]; + memset (lc_note_name, 0, 16); + strcpy (lc_note_name, "main bin spec"); + + // lc_note.data_owner + for (int i = 0; i < 16; i++) + loadcmd_data.push_back (lc_note_name[i]); + + // we start writing the payload at payload_file_offset to leave + // room at the start for the header & the load commands. + uint64_t current_payload_offset = payload.size() + payload_file_offset; + + add_uint64 (loadcmd_data, current_payload_offset); // note_command.offset + add_uint64 (loadcmd_data, sizeof (struct main_bin_spec_payload)); // note_command.size + + loadcmds.push_back (loadcmd_data); + + // Now write the "main bin spec" payload. + add_uint32 (payload, 1); // version + add_uint32 (payload, 3); // type == 3 [ firmware, standalone,e tc ] + add_uint64 (payload, UINT64_MAX); // load address unknown/unspecified + uuid_t uuid; + uuid_parse (uuidstr.c_str(), uuid); + for (int i = 0; i < sizeof (uuid_t); i++) + payload.push_back (uuid[i]); + add_uint32 (payload, 0); // log2_pagesize unspecified + add_uint32 (payload, 0); // unused +} + +void +add_lc_segment (std::vector<std::vector<uint8_t> > &loadcmds, + std::vector<uint8_t> &payload, + int payload_file_offset) +{ + std::vector<uint8_t> loadcmd_data; + struct segment_command_64 seg; + seg.cmd = LC_SEGMENT_64; + seg.cmdsize = sizeof (struct segment_command_64); // no sections + memset (seg.segname, 0, 16); + seg.vmaddr = 0xffffff7f96400000; + seg.vmsize = 4096; + seg.fileoff = payload.size() + payload_file_offset; + seg.filesize = 0; + seg.maxprot = 1; + seg.initprot = 1; + seg.nsects = 0; + seg.flags = 0; + + uint8_t *p = (uint8_t*) &seg; + for (int i = 0; i < sizeof (struct segment_command_64); i++) + { + loadcmd_data.push_back (*(p + i)); + } + loadcmds.push_back (loadcmd_data); +} + +std::string +get_uuid_from_binary (const char *fn) +{ + FILE *f = fopen(fn, "r"); + if (f == nullptr) + { + fprintf (stderr, "Unable to open binary '%s' to get uuid\n", fn); + exit(1); + } + uint32_t num_of_load_cmds = 0; + uint32_t size_of_load_cmds = 0; + std::string uuid; + off_t file_offset = 0; + + uint8_t magic[4]; + if (::fread (magic, 1, 4, f) != 4) + { + fprintf (stderr, "Failed to read magic number from input file %s\n", fn); + exit (1); + } + uint8_t magic_32_be[] = {0xfe, 0xed, 0xfa, 0xce}; + uint8_t magic_32_le[] = {0xce, 0xfa, 0xed, 0xfe}; + uint8_t magic_64_be[] = {0xfe, 0xed, 0xfa, 0xcf}; + uint8_t magic_64_le[] = {0xcf, 0xfa, 0xed, 0xfe}; + + if (memcmp (magic, magic_32_be, 4) == 0 || memcmp (magic, magic_64_be, 4) == 0) + { + fprintf (stderr, "big endian corefiles not supported\n"); + exit (1); + } + + ::fseeko (f, 0, SEEK_SET); + if (memcmp (magic, magic_32_le, 4) == 0) + { + struct mach_header mh; + if (::fread (&mh, 1, sizeof (mh), f) != sizeof (mh)) + { + fprintf (stderr, "error reading mach header from input file\n"); + exit (1); + } + if (mh.cputype != CPU_TYPE_X86_64) + { + fprintf (stderr, "This tool creates an x86_64 corefile but " + "the supplied binary '%s' is cputype 0x%x\n", + fn, (uint32_t) mh.cputype); + exit (1); + } + num_of_load_cmds = mh.ncmds; + size_of_load_cmds = mh.sizeofcmds; + file_offset += sizeof (struct mach_header); + } + else + { + struct mach_header_64 mh; + if (::fread (&mh, 1, sizeof (mh), f) != sizeof (mh)) + { + fprintf (stderr, "error reading mach header from input file\n"); + exit (1); + } + if (mh.cputype != CPU_TYPE_X86_64) + { + fprintf (stderr, "This tool creates an x86_64 corefile but " + "the supplied binary '%s' is cputype 0x%x\n", + fn, (uint32_t) mh.cputype); + exit (1); + } + num_of_load_cmds = mh.ncmds; + size_of_load_cmds = mh.sizeofcmds; + file_offset += sizeof (struct mach_header_64); + } + + off_t load_cmds_offset = file_offset; + + for (int i = 0; i < num_of_load_cmds && (file_offset - load_cmds_offset) < size_of_load_cmds; i++) + { + ::fseeko (f, file_offset, SEEK_SET); + uint32_t cmd; + uint32_t cmdsize; + ::fread (&cmd, sizeof (uint32_t), 1, f); + ::fread (&cmdsize, sizeof (uint32_t), 1, f); + if (cmd == LC_UUID) + { + struct uuid_command uuidcmd; + ::fseeko (f, file_offset, SEEK_SET); + if (::fread (&uuidcmd, 1, sizeof (uuidcmd), f) != sizeof (uuidcmd)) + { + fprintf (stderr, "Unable to read LC_UUID load command.\n"); + exit (1); + } + uuid_string_t uuidstr; + uuid_unparse (uuidcmd.uuid, uuidstr); + uuid = uuidstr; + break; + } + file_offset += cmdsize; + } + return uuid; +} + +int main (int argc, char **argv) +{ + if (argc != 4) + { + fprintf (stderr, "usage: create-empty-corefile version-string|main-bin-spec <output-core-name> <binary-to-copy-uuid-from>\n"); + fprintf (stderr, "Create a Mach-O corefile with an either LC_NOTE 'kern ver str' or \n"); + fprintf (stderr, "an LC_NOTE 'main bin spec' load command without an address specified, depending on\n"); + fprintf (stderr, "whether the 1st arg is version-string or main-bin-spec\n"); + exit (1); + } + if (strcmp (argv[1], "version-string") != 0 && strcmp (argv[1], "main-bin-spec") != 0) + { + fprintf (stderr, "arg1 was not version-string or main-bin-spec\n"); + exit (1); + } + + std::string uuid = get_uuid_from_binary (argv[3]); + + // An array of load commands (in the form of byte arrays) + std::vector<std::vector<uint8_t> > load_commands; + + // An array of corefile contents (page data, lc_note data, etc) + std::vector<uint8_t> payload; + + // First add all the load commands / payload so we can figure out how large + // the load commands will actually be. + load_commands.push_back (x86_lc_thread_load_command()); + if (strcmp (argv[1], "version-string") == 0) + add_lc_note_kern_ver_str_load_command (load_commands, payload, 0, uuid); + else + add_lc_note_main_bin_spec_load_command (load_commands, payload, 0, uuid); + add_lc_segment (load_commands, payload, 0); + + int size_of_load_commands = 0; + for (const auto &lc : load_commands) + size_of_load_commands += lc.size(); + + int header_and_load_cmd_room = sizeof (struct mach_header_64) + size_of_load_commands; + + // Erase the load commands / payload now that we know how much space is needed, + // redo it. + load_commands.clear(); + payload.clear(); + + load_commands.push_back (x86_lc_thread_load_command()); + + if (strcmp (argv[1], "version-string") == 0) + add_lc_note_kern_ver_str_load_command (load_commands, payload, header_and_load_cmd_room, uuid); + else + add_lc_note_main_bin_spec_load_command (load_commands, payload, header_and_load_cmd_room, uuid); + + add_lc_segment (load_commands, payload, header_and_load_cmd_room); + + struct mach_header_64 mh; + mh.magic = MH_MAGIC_64; + mh.cputype = CPU_TYPE_X86_64; + + mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL; + mh.filetype = MH_CORE; + mh.ncmds = load_commands.size(); + mh.sizeofcmds = size_of_load_commands; + mh.flags = 0; + mh.reserved = 0; + + + FILE *f = fopen (argv[2], "w"); + + if (f == nullptr) + { + fprintf (stderr, "Unable to open file %s for writing\n", argv[2]); + exit (1); + } + + fwrite (&mh, sizeof (struct mach_header_64), 1, f); + + for (const auto &lc : load_commands) + fwrite (lc.data(), lc.size(), 1, f); + + fseek (f, header_and_load_cmd_room, SEEK_SET); + + fwrite (payload.data(), payload.size(), 1, f); + + fclose (f); +} Index: lldb/test/API/macosx/lc-note/firmware-corefile/bout.mk =================================================================== --- /dev/null +++ lldb/test/API/macosx/lc-note/firmware-corefile/bout.mk @@ -0,0 +1,10 @@ +MAKE_DSYM := NO + +C_SOURCES := main.c +CFLAGS_EXTRAS := -Wl,-random_uuid + +EXE := b.out + +all: b.out + +include Makefile.rules Index: lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py =================================================================== --- /dev/null +++ lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py @@ -0,0 +1,133 @@ +"""Test that corefiles with LC_NOTE "kern ver str" and "main bin spec" load commands works.""" + + + +import os +import re +import subprocess + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestFirmwareCorefiles(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM") + @skipIf(archs=no_match(['x86_64'])) + @skipUnlessDarwin + def test_lc_note(self): + self.build() + self.aout_exe = self.getBuildArtifact("a.out") + self.bout_exe = self.getBuildArtifact("b.out") + self.create_corefile = self.getBuildArtifact("create-empty-corefile") + self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") + self.aout_corefile = self.getBuildArtifact("aout.core") + self.bout_corefile = self.getBuildArtifact("bout.core") + + ## We can hook in our dsym-for-uuid shell script to lldb with this env + ## var instead of requiring a defaults write. + os.environ['LLDB_APPLE_DSYMFORUUID_EXECUTABLE'] = self.dsym_for_uuid + self.addTearDownHook(lambda: os.environ.pop('LLDB_APPLE_DSYMFORUUID_EXECUTABLE', None)) + + dwarfdump_uuid_regex = re.compile( + 'UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*') + dwarfdump_cmd_output = subprocess.check_output( + ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True).decode("utf-8") + aout_uuid = None + for line in dwarfdump_cmd_output.splitlines(): + match = dwarfdump_uuid_regex.search(line) + if match: + aout_uuid = match.group(1) + self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out") + + dwarfdump_cmd_output = subprocess.check_output( + ('/usr/bin/dwarfdump --uuid "%s"' % self.bout_exe), shell=True).decode("utf-8") + bout_uuid = None + for line in dwarfdump_cmd_output.splitlines(): + match = dwarfdump_uuid_regex.search(line) + if match: + bout_uuid = match.group(1) + self.assertNotEqual(bout_uuid, None, "Could not get uuid of built b.out") + + ### Create our dsym-for-uuid shell script which returns self.aout_exe + ### or self.bout_exe, depending on the UUID on the command line. + shell_cmds = [ + '#! /bin/sh', + '# the last argument is the uuid', + 'while [ $# -gt 1 ]', + 'do', + ' shift', + 'done', + 'ret=0', + 'echo "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>"', + 'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"', + 'echo "<plist version=\\"1.0\\">"', + '', + 'if [ "$1" != "%s" -a "$1" != "%s" ]' % (aout_uuid, bout_uuid), + 'then', + ' echo "<key>DBGError</key><string>not found</string>"', + ' echo "</plist>"', + ' exit 1', + 'fi', + 'if [ "$1" = "%s" ]' % aout_uuid, + 'then', + ' uuid=%s' % aout_uuid, + ' bin=%s' % self.aout_exe, + ' dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.aout_exe, os.path.basename(self.aout_exe)), + 'else', + ' uuid=%s' % bout_uuid, + ' bin=%s' % self.bout_exe, + ' dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.bout_exe, os.path.basename(self.bout_exe)), + 'fi', + 'echo "<dict><key>$uuid</key><dict>"', + '', + 'echo "<key>DBGArchitecture</key><string>x86_64</string>"', + 'echo "<key>DBGDSYMPath</key><string>$dsym</string>"', + 'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"', + 'echo "</dict></dict></plist>"', + 'exit $ret' + ] + + with open(self.dsym_for_uuid, "w") as writer: + for l in shell_cmds: + writer.write(l + '\n') + + os.chmod(self.dsym_for_uuid, 0o755) + + ### Create our corefile + retcode = call(self.create_corefile + " version-string " + self.aout_corefile + " " + self.aout_exe, shell=True) + retcode = call(self.create_corefile + " main-bin-spec " + self.bout_corefile + " " + self.bout_exe, shell=True) + + ### Now run lldb on the corefile + ### which will give us a UUID + ### which we call dsym-for-uuid.sh with + ### which gives us a binary and dSYM + ### which lldb should load! + + # First, try the "kern ver str" corefile + self.target = self.dbg.CreateTarget('') + err = lldb.SBError() + self.process = self.target.LoadCore(self.aout_corefile) + self.assertEqual(self.process.IsValid(), True) + if self.TraceOn(): + self.runCmd("image list") + self.assertEqual(self.target.GetNumModules(), 1) + fspec = self.target.GetModuleAtIndex(0).GetFileSpec() + filepath = fspec.GetDirectory() + "/" + fspec.GetFilename() + self.assertEqual(filepath, self.aout_exe) + + + # Second, try the "main bin spec" corefile + self.target = self.dbg.CreateTarget('') + self.process = self.target.LoadCore(self.bout_corefile) + self.assertEqual(self.process.IsValid(), True) + if self.TraceOn(): + self.runCmd("image list") + self.assertEqual(self.target.GetNumModules(), 1) + fspec = self.target.GetModuleAtIndex(0).GetFileSpec() + filepath = fspec.GetDirectory() + "/" + fspec.GetFilename() + self.assertEqual(filepath, self.bout_exe) Index: lldb/test/API/macosx/lc-note/firmware-corefile/Makefile =================================================================== --- /dev/null +++ lldb/test/API/macosx/lc-note/firmware-corefile/Makefile @@ -0,0 +1,14 @@ +MAKE_DSYM := NO +C_SOURCES := main.c +CFLAGS_EXTRAS := -Wl,-random_uuid + +all: a.out b.out create-empty-corefile + +create-empty-corefile: + $(MAKE) -f $(MAKEFILE_RULES) EXE=create-empty-corefile \ + C_SOURCES=create-empty-corefile.c + +b.out: + $(MAKE) VPATH=$(SRCDIR)/$* -I $(SRCDIR) -f $(SRCDIR)/bout.mk + +include Makefile.rules Index: lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp =================================================================== --- lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -281,8 +281,9 @@ addr_t objfile_binary_addr; UUID objfile_binary_uuid; - if (core_objfile->GetCorefileMainBinaryInfo (objfile_binary_addr, objfile_binary_uuid)) - { + ObjectFile::BinaryType type; + if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_addr, + objfile_binary_uuid, type)) { if (objfile_binary_addr != LLDB_INVALID_ADDRESS) { m_mach_kernel_addr = objfile_binary_addr; @@ -293,7 +294,7 @@ m_mach_kernel_addr); } } - + // This checks for the presence of an LC_IDENT string in a core file; // LC_IDENT is very obsolete and should not be used in new code, but if the // load command is present, let's use the contents. @@ -326,58 +327,80 @@ addr, corefile_identifier.c_str()); } } - if (found_main_binary_definitively == false - && corefile_identifier.find("EFI ") != std::string::npos) { - UUID uuid; + + // In the case where we have an LC_NOTE specifying a standalone + // binary with only a UUID (and no load address) (iBoot, EFI, etc), + // then let's try to force a load of the binary and set its + // load address to 0-offset. + // + // The two forms this can come in is either a + // 'kern ver str' LC_NOTE with "EFI UUID=...." + // 'main bin spec' LC_NOTE with UUID and no load address. + + if (found_main_binary_definitively == false && + (corefile_identifier.find("EFI ") != std::string::npos || + (objfile_binary_uuid.IsValid() && + objfile_binary_addr == LLDB_INVALID_ADDRESS))) { + UUID uuid; + if (objfile_binary_uuid.IsValid()) { + uuid = objfile_binary_uuid; + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using the main bin spec " + "LC_NOTE with UUID %s and no load address", + uuid.GetAsString().c_str()); + } else { if (corefile_identifier.find("UUID=") != std::string::npos) { - size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); - std::string uuid_str = corefile_identifier.substr(p, 36); - uuid.SetFromStringRef(uuid_str); + size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); + std::string uuid_str = corefile_identifier.substr(p, 36); + uuid.SetFromStringRef(uuid_str); + if (uuid.IsValid()) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using the EFI " + "from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", + corefile_identifier.c_str()); + } } - if (uuid.IsValid()) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using the EFI " - "from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", - corefile_identifier.c_str()); - - // We're only given a UUID here, not a load address. - // But there are python scripts in the EFI binary's dSYM which - // know how to relocate the binary to the correct load address. - // lldb only needs to locate & load the binary + dSYM. - ModuleSpec module_spec; - module_spec.GetUUID() = uuid; - module_spec.GetArchitecture() = GetTarget().GetArchitecture(); - - // Lookup UUID locally, before attempting dsymForUUID like action - FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); - module_spec.GetSymbolFileSpec() = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); - if (module_spec.GetSymbolFileSpec()) { - ModuleSpec executable_module_spec = - Symbols::LocateExecutableObjectFile(module_spec); - if (FileSystem::Instance().Exists( - executable_module_spec.GetFileSpec())) { - module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); - } + } + + if (uuid.IsValid()) { + ModuleSpec module_spec; + module_spec.GetUUID() = uuid; + module_spec.GetArchitecture() = GetTarget().GetArchitecture(); + + // Lookup UUID locally, before attempting dsymForUUID-like action + FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); + module_spec.GetSymbolFileSpec() = + Symbols::LocateExecutableSymbolFile(module_spec, search_paths); + if (module_spec.GetSymbolFileSpec()) { + ModuleSpec executable_module_spec = + Symbols::LocateExecutableObjectFile(module_spec); + if (FileSystem::Instance().Exists( + executable_module_spec.GetFileSpec())) { + module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); } + } - // Force a a dsymForUUID lookup, if that tool is available. - if (!module_spec.GetSymbolFileSpec()) - Symbols::DownloadObjectAndSymbolFile(module_spec, true); - - if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { - ModuleSP module_sp(new Module(module_spec)); - if (module_sp.get() && module_sp->GetObjectFile()) { - // Get the current target executable - ModuleSP exe_module_sp(GetTarget().GetExecutableModule()); - - // Make sure you don't already have the right module loaded - // and they will be uniqued - if (exe_module_sp.get() != module_sp.get()) - GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo); - } + // Force a a dsymForUUID lookup, if that tool is available. + if (!module_spec.GetSymbolFileSpec()) + Symbols::DownloadObjectAndSymbolFile(module_spec, true); + + // If we found a binary, load it at offset 0 and set our + // dyld_plugin to be the static plugin. + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { + ModuleSP module_sp(new Module(module_spec)); + if (module_sp.get() && module_sp->GetObjectFile()) { + GetTarget().GetImages().AppendIfNeeded(module_sp, true); + GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo); + found_main_binary_definitively = true; + bool changed = true; + module_sp->SetLoadAddress(GetTarget(), 0, true, changed); + ModuleList added_module; + added_module.Append(module_sp, false); + GetTarget().ModulesDidLoad(added_module); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } } + } } if (!found_main_binary_definitively && @@ -440,35 +463,37 @@ } } - // If we found both a user-process dyld and a kernel binary, we need to - // decide which to prefer. - if (GetCorefilePreference() == eKernelCorefile) { - if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); - } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } - } else { - if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + if (m_dyld_plugin_name.IsEmpty()) { + // If we found both a user-process dyld and a kernel binary, we need to + // decide which to prefer. + if (GetCorefilePreference() == eKernelCorefile) { + if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using kernel corefile image " + "at 0x%" PRIx64, + m_mach_kernel_addr); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using user process dyld " + "image at 0x%" PRIx64, + m_dyld_addr); + m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); + } + } else { + if (m_dyld_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using user process dyld " + "image at 0x%" PRIx64, + m_dyld_addr); + m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); + } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using kernel corefile image " + "at 0x%" PRIx64, + m_mach_kernel_addr); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + } } } Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h =================================================================== --- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -112,7 +112,9 @@ std::string GetIdentifierString() override; - bool GetCorefileMainBinaryInfo (lldb::addr_t &address, lldb_private::UUID &uuid) override; + bool GetCorefileMainBinaryInfo(lldb::addr_t &address, + lldb_private::UUID &uuid, + ObjectFile::BinaryType &type) override; lldb::RegisterContextSP GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override; Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -5519,7 +5519,8 @@ return result; } -bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) { +bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid, + ObjectFile::BinaryType &type) { address = LLDB_INVALID_ADDRESS; uuid.Clear(); ModuleSP module_sp(GetModule()); @@ -5542,24 +5543,41 @@ // "main bin spec" (main binary specification) data payload is // formatted: // uint32_t version [currently 1] - // uint32_t type [0 == unspecified, 1 == kernel, 2 == user - // process] uint64_t address [ UINT64_MAX if address not - // specified ] uuid_t uuid [ all zero's if uuid not - // specified ] uint32_t log2_pagesize [ process page size in log base - // 2, e.g. 4k pages are 12. 0 for unspecified ] + // uint32_t type [0 == unspecified, 1 == kernel, + // 2 == user process, 3 == firmware ] + // uint64_t address [ UINT64_MAX if address not specified ] + // uuid_t uuid [ all zero's if uuid not specified ] + // uint32_t log2_pagesize [ process page size in log base + // 2, e.g. 4k pages are 12. + // 0 for unspecified ] + // uint32_t unused [ for alignment ] if (strcmp("main bin spec", data_owner) == 0 && size >= 32) { offset = fileoff; uint32_t version; if (m_data.GetU32(&offset, &version, 1) != nullptr && version == 1) { - uint32_t type = 0; + uint32_t binspec_type = 0; uuid_t raw_uuid; memset(raw_uuid, 0, sizeof(uuid_t)); - if (m_data.GetU32(&offset, &type, 1) && + if (m_data.GetU32(&offset, &binspec_type, 1) && m_data.GetU64(&offset, &address, 1) && m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) { uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t)); + switch (binspec_type) { + case 0: + type = eBinaryTypeUnknown; + break; + case 1: + type = eBinaryTypeKernel; + break; + case 2: + type = eBinaryTypeUser; + break; + case 3: + type = eBinaryTypeStandalone; + break; + } return true; } } Index: lldb/include/lldb/Symbol/ObjectFile.h =================================================================== --- lldb/include/lldb/Symbol/ObjectFile.h +++ lldb/include/lldb/Symbol/ObjectFile.h @@ -91,6 +91,17 @@ eStrataJIT }; + // If we have a corefile binary hint, this enum + // specifies the binary type which we can use to + // select the correct DynamicLoader plugin. + enum BinaryType { + eBinaryTypeInvalid = 0, + eBinaryTypeUnknown, + eBinaryTypeKernel, // kernel binary + eBinaryTypeUser, // user process binary + eBinaryTypeStandalone // standalone binary / firmware + }; + struct LoadableData { lldb::addr_t Dest; llvm::ArrayRef<uint8_t> Contents; @@ -500,12 +511,17 @@ /// If the uuid of the binary is specified, this will be set. /// If no UUID is available, will be cleared. /// + /// \param[out] type + /// Return the type of the binary, which will dictate which + /// DynamicLoader plugin should be used. + /// /// \return /// Returns true if either address or uuid has been set. - virtual bool GetCorefileMainBinaryInfo (lldb::addr_t &address, UUID &uuid) { - address = LLDB_INVALID_ADDRESS; - uuid.Clear(); - return false; + virtual bool GetCorefileMainBinaryInfo(lldb::addr_t &address, UUID &uuid, + ObjectFile::BinaryType &type) { + address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + return false; } virtual lldb::RegisterContextSP
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits