diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str')
4 files changed, 427 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/Makefile b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/Makefile new file mode 100644 index 00000000000..ad37346bbeb --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/Makefile @@ -0,0 +1,11 @@ +MAKE_DSYM := NO + +C_SOURCES := main.c + +all: a.out create-empty-corefile + +create-empty-corefile: + $(MAKE) -f $(MAKEFILE_RULES) EXE=create-empty-corefile \ + C_SOURCES=create-empty-corefile.c + +include Makefile.rules diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/TestKernVerStrLCNOTE.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/TestKernVerStrLCNOTE.py new file mode 100644 index 00000000000..80007438add --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/TestKernVerStrLCNOTE.py @@ -0,0 +1,99 @@ +"""Test that corefiles with an LC_NOTE "kern ver str" load command is used.""" + + + +import os +import re +import subprocess + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestKernVerStrLCNOTE(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM") + @skipIfDarwinEmbedded + @skipUnlessDarwin + def test_lc_note(self): + self.build() + self.test_exe = self.getBuildArtifact("a.out") + self.create_corefile = self.getBuildArtifact("create-empty-corefile") + self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") + self.corefile = self.getBuildArtifact("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.test_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") + + ### Create our dsym-for-uuid shell script which returns self.test_exe + ### and its dSYM when given self.test_exe's UUID. + shell_cmds = [ + '#! /bin/sh', + '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\\">"', + '', + '# the last arugment is probably the uuid', + 'while [ $# -gt 1 ]', + 'do', + ' shift', + 'done', + 'echo "<dict><key>$1</key><dict>"', + '', + 'if [ "$1" = "%s" ]' % aout_uuid, + 'then', + ' echo "<key>DBGArchitecture</key><string>x86_64</string>"', + ' echo "<key>DBGDSYMPath</key><string>%s.dSYM/Contents/Resources/DWARF/%s</string>"' % (self.test_exe, os.path.basename(self.test_exe)), + ' echo "<key>DBGSymbolRichExecutable</key><string>%s</string>"' % self.test_exe, + 'else', + ' echo "<key>DBGError</key><string>not found</string>"', + ' ret=1', + 'fi', + '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 + " " + self.corefile + " " + self.test_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! + + + self.target = self.dbg.CreateTarget('') + err = lldb.SBError() + self.process = self.target.LoadCore(self.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.test_exe) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/create-empty-corefile.cpp b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/create-empty-corefile.cpp new file mode 100644 index 00000000000..8a8115af967 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/create-empty-corefile.cpp @@ -0,0 +1,315 @@ +#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. +// If an existing binary is given as an optional 2nd 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. + + +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 ident) +{ + 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_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 != 2 && argc != 3) + { + fprintf (stderr, "usage: create-empty-corefile <output-core-name> [binary-to-copy-uuid-from]\n"); + fprintf (stderr, "Create a Mach-O corefile with an LC_NOTE 'kern ver str' load command/payload\n"); + fprintf (stderr, "If a binary is given as a second argument, the Mach-O UUID of that file will\n"); + fprintf (stderr, "be read and used in the corefile's LC_NOTE payload.\n"); + exit (1); + } + + std::string ident = "EFI UUID=3F9BA21F-55EA-356A-A349-BBA6F51FE8B1"; + if (argc == 3) + { + std::string uuid_from_file = get_uuid_from_binary (argv[2]); + if (!uuid_from_file.empty()) + { + ident = "EFI UUID="; + ident += uuid_from_file; + } + } + + // 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()); + add_lc_note_kern_ver_str_load_command (load_commands, payload, 0, ident); + 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; + + // Erease 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()); + add_lc_note_kern_ver_str_load_command (load_commands, payload, header_and_load_cmd_room, ident); + 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[1], "w"); + + if (f == nullptr) + { + fprintf (stderr, "Unable to open file %s for writing\n", argv[1]); + 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); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/main.c b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/main.c new file mode 100644 index 00000000000..70a72e0b80b --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/macosx/lc-note/kern-ver-str/main.c @@ -0,0 +1,2 @@ +#include <stdio.h> +int main () { puts ("this is the lc-note test program."); } |