"""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): @skipIf( debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM", ) @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) @skipIfRemote @skipUnlessDarwin def test_lc_note_version_string(self): self.build() aout_exe_basename = "a.out" aout_exe = self.getBuildArtifact(aout_exe_basename) verstr_corefile = self.getBuildArtifact("verstr.core") verstr_corefile_invalid_ident = self.getBuildArtifact( "verstr-invalid-ident.core" ) verstr_corefile_addr = self.getBuildArtifact("verstr-addr.core") create_corefile = self.getBuildArtifact("create-empty-corefile") slide = 0x70000000000 call( create_corefile + " version-string " + verstr_corefile + " " + aout_exe + " 0xffffffffffffffff 0xffffffffffffffff", shell=True, ) call( create_corefile + " version-string " + verstr_corefile_invalid_ident + ' "" ' + "0xffffffffffffffff 0xffffffffffffffff", shell=True, ) call( create_corefile + " version-string " + verstr_corefile_addr + " " + aout_exe + (" 0x%x" % slide) + " 0xffffffffffffffff", shell=True, ) if self.TraceOn(): self.runCmd("log enable lldb dyld host") self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) # Register the a.out binary with this UUID in lldb's global module # cache, then throw the Target away. target = self.dbg.CreateTarget(aout_exe) self.dbg.DeleteTarget(target) # First, try the "kern ver str" corefile target = self.dbg.CreateTarget("") err = lldb.SBError() if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % verstr_corefile) process = target.LoadCore(verstr_corefile) self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") self.assertEqual(target.GetNumModules(), 1) fspec = target.GetModuleAtIndex(0).GetFileSpec() self.assertEqual(fspec.GetFilename(), aout_exe_basename) self.dbg.DeleteTarget(target) # Second, try the "kern ver str" corefile which has an invalid ident, # make sure we don't crash. target = self.dbg.CreateTarget("") err = lldb.SBError() if self.TraceOn(): self.runCmd( "script print('loading corefile %s')" % verstr_corefile_invalid_ident ) process = target.LoadCore(verstr_corefile_invalid_ident) self.assertTrue(process.IsValid()) # Third, try the "kern ver str" corefile where it loads at an address target = self.dbg.CreateTarget("") err = lldb.SBError() if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % verstr_corefile_addr) process = target.LoadCore(verstr_corefile_addr) self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") self.assertEqual(target.GetNumModules(), 1) fspec = target.GetModuleAtIndex(0).GetFileSpec() self.assertEqual(fspec.GetFilename(), aout_exe_basename) main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny) main_addr = main_sym.GetStartAddress() self.assertGreater(main_addr.GetLoadAddress(target), slide) self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS) self.dbg.DeleteTarget(target) @skipIf( debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM", ) @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) @skipIfRemote @skipUnlessDarwin def test_lc_note_main_bin_spec(self): self.build() aout_exe_basename = "a.out" aout_exe = self.getBuildArtifact(aout_exe_basename) create_corefile = self.getBuildArtifact("create-empty-corefile") binspec_corefile = self.getBuildArtifact("binspec.core") binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core") binspec_corefile_slideonly = self.getBuildArtifact( "binspec-addr-slideonly.core" ) slide = 0x70000000000 ### Create our corefile # 0xffffffffffffffff means load address unknown call( create_corefile + " main-bin-spec " + binspec_corefile + " " + aout_exe + " 0xffffffffffffffff 0xffffffffffffffff", shell=True, ) call( create_corefile + " main-bin-spec " + binspec_corefile_addr + " " + aout_exe + (" 0x%x" % slide) + " 0xffffffffffffffff", shell=True, ) call( create_corefile + " main-bin-spec " + binspec_corefile_slideonly + " " + aout_exe + " 0xffffffffffffffff" + (" 0x%x" % slide), shell=True, ) if self.TraceOn(): self.runCmd("log enable lldb dyld host") self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) # Register the a.out binary with this UUID in lldb's global module # cache, then throw the Target away. target = self.dbg.CreateTarget(aout_exe) self.dbg.DeleteTarget(target) # First, try the "main bin spec" corefile target = self.dbg.CreateTarget("") if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % binspec_corefile) process = target.LoadCore(binspec_corefile) self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") self.assertEqual(target.GetNumModules(), 1) fspec = target.GetModuleAtIndex(0).GetFileSpec() self.assertEqual(fspec.GetFilename(), aout_exe_basename) self.dbg.DeleteTarget(target) # Second, try the "main bin spec" corefile where it loads at an address target = self.dbg.CreateTarget("") if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % binspec_corefile_addr) process = target.LoadCore(binspec_corefile_addr) self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") self.assertEqual(target.GetNumModules(), 1) fspec = target.GetModuleAtIndex(0).GetFileSpec() self.assertEqual(fspec.GetFilename(), aout_exe_basename) main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny) main_addr = main_sym.GetStartAddress() self.assertGreater(main_addr.GetLoadAddress(target), slide) self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS) self.dbg.DeleteTarget(target) # Third, try the "main bin spec" corefile where it loads at a slide target = self.dbg.CreateTarget("") if self.TraceOn(): self.runCmd( "script print('loading corefile %s')" % binspec_corefile_slideonly ) process = target.LoadCore(binspec_corefile_slideonly) self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") self.assertEqual(target.GetNumModules(), 1) fspec = target.GetModuleAtIndex(0).GetFileSpec() self.assertEqual(fspec.GetFilename(), aout_exe_basename) main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny) main_addr = main_sym.GetStartAddress() self.assertGreater(main_addr.GetLoadAddress(target), slide) self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS) self.dbg.DeleteTarget(target) @skipIf( debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM", ) @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) @skipIfRemote @skipUnlessDarwin def test_lc_note_main_bin_spec_os_plugin(self): self.build() aout_exe = self.getBuildArtifact("a.out") aout_exe_basename = "a.out" create_corefile = self.getBuildArtifact("create-empty-corefile") binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core") slide = 0x70000000000 ### Create our corefile # 0xffffffffffffffff means load address unknown call( create_corefile + " main-bin-spec " + binspec_corefile_addr + " " + aout_exe + (" 0x%x" % slide) + " 0xffffffffffffffff", shell=True, ) ## We can hook in our dsym-for-uuid shell script to lldb with this env ## var instead of requiring a defaults write. dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") os.environ["LLDB_APPLE_DSYMFORUUID_EXECUTABLE"] = dsym_for_uuid if self.TraceOn(): print("Setting env var LLDB_APPLE_DSYMFORUUID_EXECUTABLE=" + dsym_for_uuid) self.addTearDownHook( lambda: os.environ.pop("LLDB_APPLE_DSYMFORUUID_EXECUTABLE", None) ) self.runCmd("settings set target.load-script-from-symbol-file true") self.addTearDownHook( lambda: self.runCmd( "settings set target.load-script-from-symbol-file false" ) ) dsym_python_dir = os.path.join( "%s.dSYM" % aout_exe, "Contents", "Resources", "Python" ) os.makedirs(dsym_python_dir) python_os_plugin_path = os.path.join(self.getSourceDir(), "operating_system.py") python_init = [ "def __lldb_init_module(debugger, internal_dict):", " debugger.HandleCommand('settings set target.process.python-os-plugin-path %s')" % python_os_plugin_path, ] with open(os.path.join(dsym_python_dir, "a_out.py"), "w") as writer: for l in python_init: writer.write(l + "\n") dwarfdump_uuid_regex = re.compile("UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*") dwarfdump_cmd_output = subprocess.check_output( ('/usr/bin/dwarfdump --uuid "%s"' % 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") ### Create our dsym-for-uuid shell script which returns aout_exe shell_cmds = [ "#! /bin/sh", "# the last argument is the uuid", "while [ $# -gt 1 ]", "do", " shift", "done", "ret=0", 'echo ""', 'echo ""', 'echo ""', "", 'if [ "$1" != "%s" ]' % (aout_uuid), "then", ' echo "DBGErrornot found"', ' echo ""', " exit 1", "fi", " uuid=%s" % aout_uuid, " bin=%s" % aout_exe, " dsym=%s.dSYM/Contents/Resources/DWARF/%s" % (aout_exe, os.path.basename(aout_exe)), 'echo "$uuid"', "", 'echo "DBGDSYMPath$dsym"', 'echo "DBGSymbolRichExecutable$bin"', 'echo ""', "exit $ret", ] with open(dsym_for_uuid, "w") as writer: for l in shell_cmds: writer.write(l + "\n") os.chmod(dsym_for_uuid, 0o755) ### 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! if self.TraceOn(): self.runCmd("log enable lldb dyld host") self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) # Now load the binary and confirm that we load the OS plugin. target = self.dbg.CreateTarget("") if self.TraceOn(): self.runCmd( "script print('loading corefile %s with OS plugin')" % binspec_corefile_addr ) process = target.LoadCore(binspec_corefile_addr) self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") self.runCmd("thread list") self.assertEqual(target.GetNumModules(), 1) fspec = target.GetModuleAtIndex(0).GetFileSpec() self.assertEqual(fspec.GetFilename(), aout_exe_basename) # Verify our OS plug-in threads showed up thread = process.GetThreadByID(0x111111111) self.assertTrue( thread.IsValid(), "Make sure there is a thread 0x111111111 after we load the python OS plug-in", ) thread = process.GetThreadByID(0x222222222) self.assertTrue( thread.IsValid(), "Make sure there is a thread 0x222222222 after we load the python OS plug-in", ) thread = process.GetThreadByID(0x333333333) self.assertTrue( thread.IsValid(), "Make sure there is a thread 0x333333333 after we load the python OS plug-in", ) self.runCmd("settings clear target.process.python-os-plugin-path") self.dbg.DeleteTarget(target)