| """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.assertEqual(process.IsValid(), True) |
| 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.assertEqual(process.IsValid(), True) |
| |
| # 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.assertEqual(process.IsValid(), True) |
| 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.assertEqual(process.IsValid(), True) |
| 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.assertEqual(process.IsValid(), True) |
| 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.assertEqual(process.IsValid(), True) |
| 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 "<?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" ]' % (aout_uuid), |
| "then", |
| ' echo "<key>DBGError</key><string>not found</string>"', |
| ' echo "</plist>"', |
| " 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 "<dict><key>$uuid</key><dict>"', |
| "", |
| 'echo "<key>DBGDSYMPath</key><string>$dsym</string>"', |
| 'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"', |
| 'echo "</dict></dict></plist>"', |
| "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.assertEqual(process.IsValid(), True) |
| 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) |