1"""Test that corefiles with LC_NOTE "kern ver str" and "main bin spec" load commands works.""" 2 3 4import os 5import re 6import subprocess 7 8import lldb 9from lldbsuite.test.decorators import * 10from lldbsuite.test.lldbtest import * 11from lldbsuite.test import lldbutil 12 13 14class TestFirmwareCorefiles(TestBase): 15 @skipIf( 16 debug_info=no_match(["dsym"]), 17 bugnumber="This test is looking explicitly for a dSYM", 18 ) 19 @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) 20 @skipIfRemote 21 @skipUnlessDarwin 22 def test_lc_note_version_string(self): 23 self.build() 24 aout_exe_basename = "a.out" 25 aout_exe = self.getBuildArtifact(aout_exe_basename) 26 verstr_corefile = self.getBuildArtifact("verstr.core") 27 verstr_corefile_invalid_ident = self.getBuildArtifact( 28 "verstr-invalid-ident.core" 29 ) 30 verstr_corefile_addr = self.getBuildArtifact("verstr-addr.core") 31 create_corefile = self.getBuildArtifact("create-empty-corefile") 32 slide = 0x70000000000 33 call( 34 create_corefile 35 + " version-string " 36 + verstr_corefile 37 + " " 38 + aout_exe 39 + " 0xffffffffffffffff 0xffffffffffffffff", 40 shell=True, 41 ) 42 call( 43 create_corefile 44 + " version-string " 45 + verstr_corefile_invalid_ident 46 + ' "" ' 47 + "0xffffffffffffffff 0xffffffffffffffff", 48 shell=True, 49 ) 50 call( 51 create_corefile 52 + " version-string " 53 + verstr_corefile_addr 54 + " " 55 + aout_exe 56 + (" 0x%x" % slide) 57 + " 0xffffffffffffffff", 58 shell=True, 59 ) 60 61 if self.TraceOn(): 62 self.runCmd("log enable lldb dyld host") 63 self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) 64 65 # Register the a.out binary with this UUID in lldb's global module 66 # cache, then throw the Target away. 67 target = self.dbg.CreateTarget(aout_exe) 68 self.dbg.DeleteTarget(target) 69 70 # First, try the "kern ver str" corefile 71 target = self.dbg.CreateTarget("") 72 err = lldb.SBError() 73 if self.TraceOn(): 74 self.runCmd("script print('loading corefile %s')" % verstr_corefile) 75 process = target.LoadCore(verstr_corefile) 76 self.assertTrue(process.IsValid()) 77 if self.TraceOn(): 78 self.runCmd("image list") 79 self.runCmd("target mod dump sections") 80 self.assertEqual(target.GetNumModules(), 1) 81 fspec = target.GetModuleAtIndex(0).GetFileSpec() 82 self.assertEqual(fspec.GetFilename(), aout_exe_basename) 83 self.dbg.DeleteTarget(target) 84 85 # Second, try the "kern ver str" corefile which has an invalid ident, 86 # make sure we don't crash. 87 target = self.dbg.CreateTarget("") 88 err = lldb.SBError() 89 if self.TraceOn(): 90 self.runCmd( 91 "script print('loading corefile %s')" % verstr_corefile_invalid_ident 92 ) 93 process = target.LoadCore(verstr_corefile_invalid_ident) 94 self.assertTrue(process.IsValid()) 95 96 # Third, try the "kern ver str" corefile where it loads at an address 97 target = self.dbg.CreateTarget("") 98 err = lldb.SBError() 99 if self.TraceOn(): 100 self.runCmd("script print('loading corefile %s')" % verstr_corefile_addr) 101 process = target.LoadCore(verstr_corefile_addr) 102 self.assertTrue(process.IsValid()) 103 if self.TraceOn(): 104 self.runCmd("image list") 105 self.runCmd("target mod dump sections") 106 self.assertEqual(target.GetNumModules(), 1) 107 fspec = target.GetModuleAtIndex(0).GetFileSpec() 108 self.assertEqual(fspec.GetFilename(), aout_exe_basename) 109 main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny) 110 main_addr = main_sym.GetStartAddress() 111 self.assertGreater(main_addr.GetLoadAddress(target), slide) 112 self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS) 113 self.dbg.DeleteTarget(target) 114 115 @skipIf( 116 debug_info=no_match(["dsym"]), 117 bugnumber="This test is looking explicitly for a dSYM", 118 ) 119 @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) 120 @skipIfRemote 121 @skipUnlessDarwin 122 def test_lc_note_main_bin_spec(self): 123 self.build() 124 aout_exe_basename = "a.out" 125 aout_exe = self.getBuildArtifact(aout_exe_basename) 126 create_corefile = self.getBuildArtifact("create-empty-corefile") 127 binspec_corefile = self.getBuildArtifact("binspec.core") 128 binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core") 129 binspec_corefile_slideonly = self.getBuildArtifact( 130 "binspec-addr-slideonly.core" 131 ) 132 133 slide = 0x70000000000 134 135 ### Create our corefile 136 # 0xffffffffffffffff means load address unknown 137 call( 138 create_corefile 139 + " main-bin-spec " 140 + binspec_corefile 141 + " " 142 + aout_exe 143 + " 0xffffffffffffffff 0xffffffffffffffff", 144 shell=True, 145 ) 146 call( 147 create_corefile 148 + " main-bin-spec " 149 + binspec_corefile_addr 150 + " " 151 + aout_exe 152 + (" 0x%x" % slide) 153 + " 0xffffffffffffffff", 154 shell=True, 155 ) 156 call( 157 create_corefile 158 + " main-bin-spec " 159 + binspec_corefile_slideonly 160 + " " 161 + aout_exe 162 + " 0xffffffffffffffff" 163 + (" 0x%x" % slide), 164 shell=True, 165 ) 166 167 if self.TraceOn(): 168 self.runCmd("log enable lldb dyld host") 169 self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) 170 171 # Register the a.out binary with this UUID in lldb's global module 172 # cache, then throw the Target away. 173 target = self.dbg.CreateTarget(aout_exe) 174 self.dbg.DeleteTarget(target) 175 176 # First, try the "main bin spec" corefile 177 target = self.dbg.CreateTarget("") 178 if self.TraceOn(): 179 self.runCmd("script print('loading corefile %s')" % binspec_corefile) 180 process = target.LoadCore(binspec_corefile) 181 self.assertTrue(process.IsValid()) 182 if self.TraceOn(): 183 self.runCmd("image list") 184 self.runCmd("target mod dump sections") 185 self.assertEqual(target.GetNumModules(), 1) 186 fspec = target.GetModuleAtIndex(0).GetFileSpec() 187 self.assertEqual(fspec.GetFilename(), aout_exe_basename) 188 self.dbg.DeleteTarget(target) 189 190 # Second, try the "main bin spec" corefile where it loads at an address 191 target = self.dbg.CreateTarget("") 192 if self.TraceOn(): 193 self.runCmd("script print('loading corefile %s')" % binspec_corefile_addr) 194 process = target.LoadCore(binspec_corefile_addr) 195 self.assertTrue(process.IsValid()) 196 if self.TraceOn(): 197 self.runCmd("image list") 198 self.runCmd("target mod dump sections") 199 self.assertEqual(target.GetNumModules(), 1) 200 fspec = target.GetModuleAtIndex(0).GetFileSpec() 201 self.assertEqual(fspec.GetFilename(), aout_exe_basename) 202 main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny) 203 main_addr = main_sym.GetStartAddress() 204 self.assertGreater(main_addr.GetLoadAddress(target), slide) 205 self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS) 206 self.dbg.DeleteTarget(target) 207 208 # Third, try the "main bin spec" corefile where it loads at a slide 209 target = self.dbg.CreateTarget("") 210 if self.TraceOn(): 211 self.runCmd( 212 "script print('loading corefile %s')" % binspec_corefile_slideonly 213 ) 214 process = target.LoadCore(binspec_corefile_slideonly) 215 self.assertTrue(process.IsValid()) 216 if self.TraceOn(): 217 self.runCmd("image list") 218 self.runCmd("target mod dump sections") 219 self.assertEqual(target.GetNumModules(), 1) 220 fspec = target.GetModuleAtIndex(0).GetFileSpec() 221 self.assertEqual(fspec.GetFilename(), aout_exe_basename) 222 main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny) 223 main_addr = main_sym.GetStartAddress() 224 self.assertGreater(main_addr.GetLoadAddress(target), slide) 225 self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS) 226 self.dbg.DeleteTarget(target) 227 228 @skipIf( 229 debug_info=no_match(["dsym"]), 230 bugnumber="This test is looking explicitly for a dSYM", 231 ) 232 @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) 233 @skipIfRemote 234 @skipUnlessDarwin 235 def test_lc_note_main_bin_spec_os_plugin(self): 236 self.build() 237 aout_exe = self.getBuildArtifact("a.out") 238 aout_exe_basename = "a.out" 239 create_corefile = self.getBuildArtifact("create-empty-corefile") 240 binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core") 241 242 slide = 0x70000000000 243 244 ### Create our corefile 245 # 0xffffffffffffffff means load address unknown 246 call( 247 create_corefile 248 + " main-bin-spec " 249 + binspec_corefile_addr 250 + " " 251 + aout_exe 252 + (" 0x%x" % slide) 253 + " 0xffffffffffffffff", 254 shell=True, 255 ) 256 257 ## We can hook in our dsym-for-uuid shell script to lldb with this env 258 ## var instead of requiring a defaults write. 259 dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") 260 os.environ["LLDB_APPLE_DSYMFORUUID_EXECUTABLE"] = dsym_for_uuid 261 if self.TraceOn(): 262 print("Setting env var LLDB_APPLE_DSYMFORUUID_EXECUTABLE=" + dsym_for_uuid) 263 self.addTearDownHook( 264 lambda: os.environ.pop("LLDB_APPLE_DSYMFORUUID_EXECUTABLE", None) 265 ) 266 267 self.runCmd("settings set target.load-script-from-symbol-file true") 268 self.addTearDownHook( 269 lambda: self.runCmd( 270 "settings set target.load-script-from-symbol-file false" 271 ) 272 ) 273 274 dsym_python_dir = os.path.join( 275 "%s.dSYM" % aout_exe, "Contents", "Resources", "Python" 276 ) 277 os.makedirs(dsym_python_dir) 278 python_os_plugin_path = os.path.join(self.getSourceDir(), "operating_system.py") 279 python_init = [ 280 "def __lldb_init_module(debugger, internal_dict):", 281 " debugger.HandleCommand('settings set target.process.python-os-plugin-path %s')" 282 % python_os_plugin_path, 283 ] 284 with open(os.path.join(dsym_python_dir, "a_out.py"), "w") as writer: 285 for l in python_init: 286 writer.write(l + "\n") 287 288 dwarfdump_uuid_regex = re.compile("UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*") 289 dwarfdump_cmd_output = subprocess.check_output( 290 ('/usr/bin/dwarfdump --uuid "%s"' % aout_exe), shell=True 291 ).decode("utf-8") 292 aout_uuid = None 293 for line in dwarfdump_cmd_output.splitlines(): 294 match = dwarfdump_uuid_regex.search(line) 295 if match: 296 aout_uuid = match.group(1) 297 self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out") 298 299 ### Create our dsym-for-uuid shell script which returns aout_exe 300 shell_cmds = [ 301 "#! /bin/sh", 302 "# the last argument is the uuid", 303 "while [ $# -gt 1 ]", 304 "do", 305 " shift", 306 "done", 307 "ret=0", 308 'echo "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>"', 309 'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"', 310 'echo "<plist version=\\"1.0\\">"', 311 "", 312 'if [ "$1" != "%s" ]' % (aout_uuid), 313 "then", 314 ' echo "<key>DBGError</key><string>not found</string>"', 315 ' echo "</plist>"', 316 " exit 1", 317 "fi", 318 " uuid=%s" % aout_uuid, 319 " bin=%s" % aout_exe, 320 " dsym=%s.dSYM/Contents/Resources/DWARF/%s" 321 % (aout_exe, os.path.basename(aout_exe)), 322 'echo "<dict><key>$uuid</key><dict>"', 323 "", 324 'echo "<key>DBGDSYMPath</key><string>$dsym</string>"', 325 'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"', 326 'echo "</dict></dict></plist>"', 327 "exit $ret", 328 ] 329 330 with open(dsym_for_uuid, "w") as writer: 331 for l in shell_cmds: 332 writer.write(l + "\n") 333 334 os.chmod(dsym_for_uuid, 0o755) 335 336 ### Now run lldb on the corefile 337 ### which will give us a UUID 338 ### which we call dsym-for-uuid.sh with 339 ### which gives us a binary and dSYM 340 ### which lldb should load! 341 342 if self.TraceOn(): 343 self.runCmd("log enable lldb dyld host") 344 self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) 345 # Now load the binary and confirm that we load the OS plugin. 346 target = self.dbg.CreateTarget("") 347 348 if self.TraceOn(): 349 self.runCmd( 350 "script print('loading corefile %s with OS plugin')" 351 % binspec_corefile_addr 352 ) 353 354 process = target.LoadCore(binspec_corefile_addr) 355 self.assertTrue(process.IsValid()) 356 if self.TraceOn(): 357 self.runCmd("image list") 358 self.runCmd("target mod dump sections") 359 self.runCmd("thread list") 360 self.assertEqual(target.GetNumModules(), 1) 361 fspec = target.GetModuleAtIndex(0).GetFileSpec() 362 self.assertEqual(fspec.GetFilename(), aout_exe_basename) 363 364 # Verify our OS plug-in threads showed up 365 thread = process.GetThreadByID(0x111111111) 366 self.assertTrue( 367 thread.IsValid(), 368 "Make sure there is a thread 0x111111111 after we load the python OS plug-in", 369 ) 370 thread = process.GetThreadByID(0x222222222) 371 self.assertTrue( 372 thread.IsValid(), 373 "Make sure there is a thread 0x222222222 after we load the python OS plug-in", 374 ) 375 thread = process.GetThreadByID(0x333333333) 376 self.assertTrue( 377 thread.IsValid(), 378 "Make sure there is a thread 0x333333333 after we load the python OS plug-in", 379 ) 380 381 self.runCmd("settings clear target.process.python-os-plugin-path") 382 self.dbg.DeleteTarget(target) 383