1"""Test that corefiles with LC_NOTE "kern ver str" and "main bin spec" load commands works."""
2
3
4
5import os
6import re
7import subprocess
8
9import lldb
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14
15class TestFirmwareCorefiles(TestBase):
16
17    mydir = TestBase.compute_mydir(__file__)
18
19    def initial_setup(self):
20        self.build()
21        self.aout_exe = self.getBuildArtifact("a.out")
22        self.aout_exe_basename = "a.out"
23        self.create_corefile = self.getBuildArtifact("create-empty-corefile")
24        self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh")
25        self.verstr_corefile = self.getBuildArtifact("verstr.core")
26        self.verstr_corefile_addr = self.getBuildArtifact("verstr-addr.core")
27        self.binspec_corefile = self.getBuildArtifact("binspec.core")
28        self.binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core")
29
30        ## We can hook in our dsym-for-uuid shell script to lldb with this env
31        ## var instead of requiring a defaults write.
32        os.environ['LLDB_APPLE_DSYMFORUUID_EXECUTABLE'] = self.dsym_for_uuid
33        self.addTearDownHook(lambda: os.environ.pop('LLDB_APPLE_DSYMFORUUID_EXECUTABLE', None))
34
35        self.runCmd("settings set target.load-script-from-symbol-file true")
36        self.addTearDownHook(lambda: self.runCmd("settings set target.load-script-from-symbol-file false"))
37
38        dsym_python_dir = '%s.dSYM/Contents/Resources/Python' % (self.aout_exe)
39        os.makedirs(dsym_python_dir)
40        python_os_plugin_path = os.path.join(self.getSourceDir(),
41                                             'operating_system.py')
42        python_init = [
43                'def __lldb_init_module(debugger, internal_dict):',
44                '  debugger.HandleCommand(\'settings set target.process.python-os-plugin-path %s\')' % python_os_plugin_path,
45                ]
46        with open(dsym_python_dir + "/a_out.py", "w") as writer:
47            for l in python_init:
48                writer.write(l + '\n')
49
50        dwarfdump_uuid_regex = re.compile(
51            'UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*')
52        dwarfdump_cmd_output = subprocess.check_output(
53                ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True).decode("utf-8")
54        aout_uuid = None
55        for line in dwarfdump_cmd_output.splitlines():
56            match = dwarfdump_uuid_regex.search(line)
57            if match:
58                aout_uuid = match.group(1)
59        self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out")
60
61        ###  Create our dsym-for-uuid shell script which returns self.aout_exe
62        shell_cmds = [
63                '#! /bin/sh',
64                '# the last argument is the uuid',
65                'while [ $# -gt 1 ]',
66                'do',
67                '  shift',
68                'done',
69                'ret=0',
70                'echo "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>"',
71                'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"',
72                'echo "<plist version=\\"1.0\\">"',
73                '',
74                'if [ "$1" != "%s" ]' % (aout_uuid),
75                'then',
76                '  echo "<key>DBGError</key><string>not found</string>"',
77                '  echo "</plist>"',
78                '  exit 1',
79                'fi',
80                '  uuid=%s' % aout_uuid,
81                '  bin=%s' % self.aout_exe,
82                '  dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.aout_exe, os.path.basename(self.aout_exe)),
83                'echo "<dict><key>$uuid</key><dict>"',
84                '',
85                'echo "<key>DBGDSYMPath</key><string>$dsym</string>"',
86                'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"',
87                'echo "</dict></dict></plist>"',
88                'exit $ret'
89                ]
90
91        with open(self.dsym_for_uuid, "w") as writer:
92            for l in shell_cmds:
93                writer.write(l + '\n')
94
95        os.chmod(self.dsym_for_uuid, 0o755)
96
97        self.slide = 0x70000000000
98
99        ### Create our corefile
100        # 0xffffffffffffffff means load address unknown
101        retcode = call(self.create_corefile + " version-string " + self.verstr_corefile + " " + self.aout_exe + " 0xffffffffffffffff", shell=True)
102        retcode = call(self.create_corefile + " version-string " + self.verstr_corefile_addr + " " + self.aout_exe + (" 0x%x" % self.slide), shell=True)
103        retcode = call(self.create_corefile + " main-bin-spec " + self.binspec_corefile + " " + self.aout_exe + " 0xffffffffffffffff", shell=True)
104        retcode = call(self.create_corefile + " main-bin-spec " + self.binspec_corefile_addr + " " + self.aout_exe + (" 0x%x" % self.slide), shell=True)
105
106    @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
107    @skipIf(archs=no_match(['x86_64']))
108    @skipUnlessDarwin
109    def test_lc_note_version_string(self):
110        self.initial_setup()
111
112        if self.TraceOn():
113            self.runCmd("log enable lldb dyld host")
114            self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
115
116        ### Now run lldb on the corefile
117        ### which will give us a UUID
118        ### which we call dsym-for-uuid.sh with
119        ### which gives us a binary and dSYM
120        ### which lldb should load!
121
122        # First, try the "kern ver str" corefile
123        self.target = self.dbg.CreateTarget('')
124        err = lldb.SBError()
125        if self.TraceOn():
126            self.runCmd("script print('loading corefile %s')" % self.verstr_corefile)
127        self.process = self.target.LoadCore(self.verstr_corefile)
128        self.assertEqual(self.process.IsValid(), True)
129        if self.TraceOn():
130            self.runCmd("image list")
131            self.runCmd("target mod dump sections")
132        self.assertEqual(self.target.GetNumModules(), 1)
133        fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
134        self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
135        self.process.Kill()
136        self.process = None
137        self.target.Clear()
138        self.target = None
139        self.dbg.MemoryPressureDetected()
140
141        # Second, try the "kern ver str" corefile where it loads at an address
142        self.target = self.dbg.CreateTarget('')
143        err = lldb.SBError()
144        if self.TraceOn():
145            self.runCmd("script print('loading corefile %s')" % self.verstr_corefile_addr)
146        self.process = self.target.LoadCore(self.verstr_corefile_addr)
147        self.assertEqual(self.process.IsValid(), True)
148        if self.TraceOn():
149            self.runCmd("image list")
150            self.runCmd("target mod dump sections")
151        self.assertEqual(self.target.GetNumModules(), 1)
152        fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
153        self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
154        main_sym = self.target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
155        main_addr = main_sym.GetStartAddress()
156        self.assertGreater(main_addr.GetLoadAddress(self.target), self.slide)
157        self.assertNotEqual(main_addr.GetLoadAddress(self.target), lldb.LLDB_INVALID_ADDRESS)
158        self.process.Kill()
159        self.process = None
160        self.target.Clear()
161        self.target = None
162        self.dbg.MemoryPressureDetected()
163
164    @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
165    @skipIf(archs=no_match(['x86_64']))
166    @skipUnlessDarwin
167    def test_lc_note_main_bin_spec(self):
168        self.initial_setup()
169
170        if self.TraceOn():
171            self.runCmd("log enable lldb dyld host")
172            self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
173
174        # Third, try the "main bin spec" corefile
175        self.target = self.dbg.CreateTarget('')
176        if self.TraceOn():
177            self.runCmd("script print('loading corefile %s')" % self.binspec_corefile)
178        self.process = self.target.LoadCore(self.binspec_corefile)
179        self.assertEqual(self.process.IsValid(), True)
180        if self.TraceOn():
181            self.runCmd("image list")
182            self.runCmd("target mod dump sections")
183        self.assertEqual(self.target.GetNumModules(), 1)
184        fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
185        self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
186        self.process.Kill()
187        self.process = None
188        self.target.Clear()
189        self.target = None
190        self.dbg.MemoryPressureDetected()
191
192        # Fourth, try the "main bin spec" corefile where it loads at an address
193        self.target = self.dbg.CreateTarget('')
194        if self.TraceOn():
195            self.runCmd("script print('loading corefile %s')" % self.binspec_corefile_addr)
196        self.process = self.target.LoadCore(self.binspec_corefile_addr)
197        self.assertEqual(self.process.IsValid(), True)
198        if self.TraceOn():
199            self.runCmd("image list")
200            self.runCmd("target mod dump sections")
201        self.assertEqual(self.target.GetNumModules(), 1)
202        fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
203        self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
204        main_sym = self.target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
205        main_addr = main_sym.GetStartAddress()
206        self.assertGreater(main_addr.GetLoadAddress(self.target), self.slide)
207        self.assertNotEqual(main_addr.GetLoadAddress(self.target), lldb.LLDB_INVALID_ADDRESS)
208        self.process.Kill()
209        self.process = None
210        self.target.Clear()
211        self.target = None
212        self.dbg.MemoryPressureDetected()
213
214    @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
215    @skipIf(archs=no_match(['x86_64']))
216    @skipUnlessDarwin
217    def test_lc_note_main_bin_spec_os_plugin(self):
218        self.initial_setup()
219
220        if self.TraceOn():
221            self.runCmd("log enable lldb dyld host")
222            self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
223        # Now load the binary and confirm that we load the OS plugin.
224        self.target = self.dbg.CreateTarget('')
225
226        if self.TraceOn():
227            self.runCmd("script print('loading corefile %s with OS plugin')" % self.binspec_corefile_addr)
228        self.process = self.target.LoadCore(self.binspec_corefile_addr)
229        self.assertEqual(self.process.IsValid(), True)
230        if self.TraceOn():
231            self.runCmd("image list")
232            self.runCmd("target mod dump sections")
233            self.runCmd("thread list")
234        self.assertEqual(self.target.GetNumModules(), 1)
235        fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
236        self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
237
238        # Verify our OS plug-in threads showed up
239        thread = self.process.GetThreadByID(0x111111111)
240        self.assertTrue(thread.IsValid(),
241                "Make sure there is a thread 0x111111111 after we load the python OS plug-in")
242        thread = self.process.GetThreadByID(0x222222222)
243        self.assertTrue(thread.IsValid(),
244                "Make sure there is a thread 0x222222222 after we load the python OS plug-in")
245        thread = self.process.GetThreadByID(0x333333333)
246        self.assertTrue(thread.IsValid(),
247                "Make sure there is a thread 0x333333333 after we load the python OS plug-in")
248
249        self.process.Kill()
250        self.process = None
251        self.target.Clear()
252        self.target = None
253        self.dbg.MemoryPressureDetected()
254