1"""Test corefiles with "main bin spec"/"load binary" with only vmaddrs 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 TestMultipleBinaryCorefile(TestBase): 15 def initial_setup(self): 16 self.build() 17 self.aout_exe_basename = "a.out" 18 self.libone_exe_basename = "libone.dylib" 19 self.libtwo_exe_basename = "libtwo.dylib" 20 self.aout_exe = self.getBuildArtifact(self.aout_exe_basename) 21 self.aout_slide = 0x5000 22 self.libone_exe = self.getBuildArtifact(self.libone_exe_basename) 23 self.libone_slide = 0x100840000 24 self.libtwo_exe = self.getBuildArtifact(self.libtwo_exe_basename) 25 self.libtwo_slide = 0 26 self.corefile = self.getBuildArtifact("multiple-binaries.core") 27 self.create_corefile = self.getBuildArtifact("create-multibin-corefile") 28 cmd = "%s %s %s@%x %s@%x %s@%x" % ( 29 self.create_corefile, 30 self.corefile, 31 self.aout_exe, 32 self.aout_slide, 33 self.libone_exe, 34 self.libone_slide, 35 self.libtwo_exe, 36 self.libtwo_slide, 37 ) 38 if self.TraceOn(): 39 print("Creating corefile with command %s") 40 call(cmd, shell=True) 41 42 def load_corefile_and_test(self): 43 target = self.dbg.CreateTarget("") 44 err = lldb.SBError() 45 if self.TraceOn(): 46 print("loading corefile %s" % self.corefile) 47 process = target.LoadCore(self.corefile) 48 self.assertTrue(process.IsValid()) 49 if self.TraceOn(): 50 print("image list after loading corefile:") 51 self.runCmd("image list") 52 53 ## We don't have libone.dylib in the global module cache or from 54 ## dsymForUUID, and lldb will not read the binary out of memory. 55 self.assertEqual(target.GetNumModules(), 2) 56 fspec = target.GetModuleAtIndex(0).GetFileSpec() 57 self.assertEqual(fspec.GetFilename(), self.aout_exe_basename) 58 59 fspec = target.GetModuleAtIndex(1).GetFileSpec() 60 self.assertEqual(fspec.GetFilename(), self.libtwo_exe_basename) 61 62 # Executables "always" have this base address 63 aout_load = ( 64 target.GetModuleAtIndex(0) 65 .GetObjectFileHeaderAddress() 66 .GetLoadAddress(target) 67 ) 68 self.assertEqual(aout_load, 0x100000000 + self.aout_slide) 69 70 # Value from Makefile 71 libtwo_load = ( 72 target.GetModuleAtIndex(1) 73 .GetObjectFileHeaderAddress() 74 .GetLoadAddress(target) 75 ) 76 self.assertEqual(libtwo_load, self.libtwo_slide) 77 78 self.dbg.DeleteTarget(target) 79 self.dbg.Clear() 80 81 NO_DEBUG_INFO_TESTCASE = True 82 83 @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) 84 @skipIfRemote 85 @skipUnlessDarwin 86 def test_corefile_binaries_dsymforuuid(self): 87 self.initial_setup() 88 89 if self.TraceOn(): 90 self.runCmd("log enable lldb dyld host") 91 self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) 92 93 ## We can hook in our dsym-for-uuid shell script to lldb with this env 94 ## var instead of requiring a defaults write. 95 dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh") 96 os.environ["LLDB_APPLE_DSYMFORUUID_EXECUTABLE"] = dsym_for_uuid 97 if self.TraceOn(): 98 print("Setting env var LLDB_APPLE_DSYMFORUUID_EXECUTABLE=" + dsym_for_uuid) 99 self.addTearDownHook( 100 lambda: os.environ.pop("LLDB_APPLE_DSYMFORUUID_EXECUTABLE", None) 101 ) 102 103 self.runCmd("settings set target.load-script-from-symbol-file true") 104 self.addTearDownHook( 105 lambda: self.runCmd( 106 "settings set target.load-script-from-symbol-file false" 107 ) 108 ) 109 110 dwarfdump_uuid_regex = re.compile("UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*") 111 dwarfdump_cmd_output = subprocess.check_output( 112 ('/usr/bin/dwarfdump --uuid "%s"' % self.libtwo_exe), shell=True 113 ).decode("utf-8") 114 libtwo_uuid = None 115 for line in dwarfdump_cmd_output.splitlines(): 116 match = dwarfdump_uuid_regex.search(line) 117 if match: 118 libtwo_uuid = match.group(1) 119 self.assertNotEqual( 120 libtwo_uuid, None, "Could not get uuid of built libtwo.dylib" 121 ) 122 dwarfdump_cmd_output = subprocess.check_output( 123 ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True 124 ).decode("utf-8") 125 aout_uuid = None 126 for line in dwarfdump_cmd_output.splitlines(): 127 match = dwarfdump_uuid_regex.search(line) 128 if match: 129 aout_uuid = match.group(1) 130 self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out") 131 132 ### Create our dsym-for-uuid shell script which returns aout_exe 133 shell_cmds = [ 134 "#! /bin/sh", 135 "# the last argument is the uuid", 136 "while [ $# -gt 1 ]", 137 "do", 138 " shift", 139 "done", 140 'echo "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>"', 141 'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"', 142 'echo "<plist version=\\"1.0\\">"', 143 'echo " <dict>"', 144 'echo " <key>$1</key>"', 145 'echo " <dict>"', 146 "", 147 'if [ "$1" != "%s" -a "$1" != "%s" ]' % (libtwo_uuid, aout_uuid), 148 "then", 149 ' echo " <key>DBGError</key>"', 150 ' echo " <string>not found by $0</string>"', 151 ' echo " </dict>"', 152 ' echo " </dict>"', 153 ' echo "</plist>"', 154 " exit 0", 155 "fi", 156 # UUID matches libtwo.dylib 157 'if [ "$1" = "%s" ]' % (libtwo_uuid), 158 "then", 159 " uuid=%s" % libtwo_uuid, 160 " bin=%s" % self.libtwo_exe, 161 " dsym=%s.dSYM/Contents/Resources/DWARF/%s" 162 % (self.libtwo_exe, os.path.basename(self.libtwo_exe)), 163 "fi", 164 # UUID matches a.out 165 'if [ "$1" = "%s" ]' % (aout_uuid), 166 "then", 167 " uuid=%s" % aout_uuid, 168 " bin=%s" % self.aout_exe, 169 " dsym=%s.dSYM/Contents/Resources/DWARF/%s" 170 % (self.aout_exe, os.path.basename(self.aout_exe)), 171 "fi", 172 "", 173 'echo " <key>DBGDSYMPath</key>"', 174 'echo " <string>$dsym</string>"', 175 'echo " <key>DBGSymbolRichExecutable</key>"', 176 'echo " <string>$bin</string>"', 177 'echo " </dict>"', 178 'echo " </dict>"', 179 'echo "</plist>"', 180 "exit 0", 181 ] 182 183 with open(dsym_for_uuid, "w") as writer: 184 for l in shell_cmds: 185 writer.write(l + "\n") 186 187 os.chmod(dsym_for_uuid, 0o755) 188 189 # Register TWO of our binaries, but require dsymForUUID to find the third. 190 target = self.dbg.CreateTarget(self.aout_exe, "", "", False, lldb.SBError()) 191 self.dbg.DeleteTarget(target) 192 193 if self.TraceOn(): 194 print("Global image list, before loading corefile:") 195 self.runCmd("image list -g") 196 197 self.load_corefile_and_test() 198 199 @skipIf(archs=no_match(["x86_64", "arm64", "arm64e", "aarch64"])) 200 @skipIfRemote 201 @skipUnlessDarwin 202 def test_corefile_binaries_preloaded(self): 203 self.initial_setup() 204 205 if self.TraceOn(): 206 self.runCmd("log enable lldb dyld host") 207 self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host")) 208 209 # Register all three binaries in lldb's global module 210 # cache, then throw the Targets away. 211 target = self.dbg.CreateTarget(self.aout_exe, "", "", False, lldb.SBError()) 212 self.dbg.DeleteTarget(target) 213 target = self.dbg.CreateTarget(self.libtwo_exe, "", "", False, lldb.SBError()) 214 self.dbg.DeleteTarget(target) 215 216 if self.TraceOn(): 217 print("Global image list, before loading corefile:") 218 self.runCmd("image list -g") 219 220 self.load_corefile_and_test() 221