xref: /llvm-project/lldb/test/API/macosx/lc-note/multiple-binary-corefile/TestMultipleBinaryCorefile.py (revision 1eeeab82c6eb185f5139e633a59c2dbcb15616e4)
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