1"""
2Test SBTarget APIs.
3"""
4
5import os, time
6import re
7import unittest2
8import lldb, lldbutil
9from lldbtest import *
10
11class TargetAPITestCase(TestBase):
12
13    mydir = os.path.join("python_api", "target")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @python_api_test
17    @dsym_test
18    def test_find_global_variables_with_dsym(self):
19        """Exercise SBTaget.FindGlobalVariables() API."""
20        d = {'EXE': 'a.out'}
21        self.buildDsym(dictionary=d)
22        self.setTearDownCleanup(dictionary=d)
23        self.find_global_variables('a.out')
24
25    #rdar://problem/9700873
26    # Find global variable value fails for dwarf if inferior not started
27    # (Was CrashTracer: [USER] 1 crash in Python at _lldb.so: lldb_private::MemoryCache::Read + 94)
28    #
29    # It does not segfaults now.  But for dwarf, the variable value is None if
30    # the inferior process does not exist yet.  The radar has been updated.
31    #@unittest232.skip("segmentation fault -- skipping")
32    @python_api_test
33    @dwarf_test
34    def test_find_global_variables_with_dwarf(self):
35        """Exercise SBTarget.FindGlobalVariables() API."""
36        d = {'EXE': 'b.out'}
37        self.buildDwarf(dictionary=d)
38        self.setTearDownCleanup(dictionary=d)
39        self.find_global_variables('b.out')
40
41    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
42    @python_api_test
43    @dsym_test
44    def test_find_functions_with_dsym(self):
45        """Exercise SBTaget.FindFunctions() API."""
46        d = {'EXE': 'a.out'}
47        self.buildDsym(dictionary=d)
48        self.setTearDownCleanup(dictionary=d)
49        self.find_functions('a.out')
50
51    @python_api_test
52    @dwarf_test
53    def test_find_functions_with_dwarf(self):
54        """Exercise SBTarget.FindFunctions() API."""
55        d = {'EXE': 'b.out'}
56        self.buildDwarf(dictionary=d)
57        self.setTearDownCleanup(dictionary=d)
58        self.find_functions('b.out')
59
60    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
61    @python_api_test
62    @dsym_test
63    def test_get_description_with_dsym(self):
64        """Exercise SBTaget.GetDescription() API."""
65        self.buildDsym()
66        self.get_description()
67
68    @python_api_test
69    @dwarf_test
70    def test_get_description_with_dwarf(self):
71        """Exercise SBTarget.GetDescription() API."""
72        self.buildDwarf()
73        self.get_description()
74
75    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
76    @python_api_test
77    @dsym_test
78    def test_launch_new_process_and_redirect_stdout_with_dsym(self):
79        """Exercise SBTaget.Launch() API."""
80        self.buildDsym()
81        self.launch_new_process_and_redirect_stdout()
82
83    @python_api_test
84    @dwarf_test
85    def test_launch_new_process_and_redirect_stdout_with_dwarf(self):
86        """Exercise SBTarget.Launch() API."""
87        self.buildDwarf()
88        self.launch_new_process_and_redirect_stdout()
89
90    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
91    @python_api_test
92    @dsym_test
93    def test_resolve_symbol_context_with_address_with_dsym(self):
94        """Exercise SBTaget.ResolveSymbolContextForAddress() API."""
95        self.buildDsym()
96        self.resolve_symbol_context_with_address()
97
98    @python_api_test
99    @dwarf_test
100    def test_resolve_symbol_context_with_address_with_dwarf(self):
101        """Exercise SBTarget.ResolveSymbolContextForAddress() API."""
102        self.buildDwarf()
103        self.resolve_symbol_context_with_address()
104
105    def setUp(self):
106        # Call super's setUp().
107        TestBase.setUp(self)
108        # Find the line number to of function 'c'.
109        self.line1 = line_number('main.c', '// Find the line number for breakpoint 1 here.')
110        self.line2 = line_number('main.c', '// Find the line number for breakpoint 2 here.')
111
112    def find_global_variables(self, exe_name):
113        """Exercise SBTaget.FindGlobalVariables() API."""
114        exe = os.path.join(os.getcwd(), exe_name)
115
116        # Create a target by the debugger.
117        target = self.dbg.CreateTarget(exe)
118        self.assertTrue(target, VALID_TARGET)
119
120        #rdar://problem/9700873
121        # Find global variable value fails for dwarf if inferior not started
122        # (Was CrashTracer: [USER] 1 crash in Python at _lldb.so: lldb_private::MemoryCache::Read + 94)
123        #
124        # Remove the lines to create a breakpoint and to start the inferior
125        # which are workarounds for the dwarf case.
126
127        breakpoint = target.BreakpointCreateByLocation('main.c', self.line1)
128        self.assertTrue(breakpoint, VALID_BREAKPOINT)
129
130        # Now launch the process, and do not stop at entry point.
131        process = target.LaunchSimple(None, None, os.getcwd())
132        self.assertTrue(process, PROCESS_IS_VALID)
133        # Make sure we hit our breakpoint:
134        thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint)
135        self.assertTrue (len(thread_list) == 1)
136
137        value_list = target.FindGlobalVariables('my_global_var_of_char_type', 3)
138        self.assertTrue(value_list.GetSize() == 1)
139        my_global_var = value_list.GetValueAtIndex(0)
140        self.DebugSBValue(my_global_var)
141        self.assertTrue(my_global_var)
142        self.expect(my_global_var.GetName(), exe=False,
143            startstr = "my_global_var_of_char_type")
144        self.expect(my_global_var.GetTypeName(), exe=False,
145            startstr = "char")
146        self.expect(my_global_var.GetValue(), exe=False,
147            startstr = "'X'")
148
149        # While we are at it, let's also exercise the similar SBModule.FindGlobalVariables() API.
150        for m in target.module_iter():
151            if m.GetFileSpec().GetDirectory() == os.getcwd() and m.GetFileSpec().GetFilename() == exe_name:
152                value_list = m.FindGlobalVariables(target, 'my_global_var_of_char_type', 3)
153                self.assertTrue(value_list.GetSize() == 1)
154                self.assertTrue(value_list.GetValueAtIndex(0).GetValue() == "'X'")
155                break
156
157    def find_functions(self, exe_name):
158        """Exercise SBTaget.FindFunctions() API."""
159        exe = os.path.join(os.getcwd(), exe_name)
160
161        # Create a target by the debugger.
162        target = self.dbg.CreateTarget(exe)
163        self.assertTrue(target, VALID_TARGET)
164
165        list = target.FindFunctions('c', lldb.eFunctionNameTypeAuto)
166        self.assertTrue(list.GetSize() == 1)
167
168        for sc in list:
169            self.assertTrue(sc.GetModule().GetFileSpec().GetFilename() == exe_name)
170            self.assertTrue(sc.GetSymbol().GetName() == 'c')
171
172    def get_description(self):
173        """Exercise SBTaget.GetDescription() API."""
174        exe = os.path.join(os.getcwd(), "a.out")
175
176        # Create a target by the debugger.
177        target = self.dbg.CreateTarget(exe)
178        self.assertTrue(target, VALID_TARGET)
179
180        from lldbutil import get_description
181
182        # get_description() allows no option to mean lldb.eDescriptionLevelBrief.
183        desc = get_description(target)
184        #desc = get_description(target, option=lldb.eDescriptionLevelBrief)
185        if not desc:
186            self.fail("SBTarget.GetDescription() failed")
187        self.expect(desc, exe=False,
188            substrs = ['a.out'])
189        self.expect(desc, exe=False, matching=False,
190            substrs = ['Target', 'Module', 'Breakpoint'])
191
192        desc = get_description(target, option=lldb.eDescriptionLevelFull)
193        if not desc:
194            self.fail("SBTarget.GetDescription() failed")
195        self.expect(desc, exe=False,
196            substrs = ['a.out', 'Target', 'Module', 'Breakpoint'])
197
198
199    def launch_new_process_and_redirect_stdout(self):
200        """Exercise SBTaget.Launch() API with redirected stdout."""
201        exe = os.path.join(os.getcwd(), "a.out")
202
203        # Create a target by the debugger.
204        target = self.dbg.CreateTarget(exe)
205        self.assertTrue(target, VALID_TARGET)
206
207        # Add an extra twist of stopping the inferior in a breakpoint, and then continue till it's done.
208        # We should still see the entire stdout redirected once the process is finished.
209        line = line_number('main.c', '// a(3) -> c(3)')
210        breakpoint = target.BreakpointCreateByLocation('main.c', line)
211
212        # Now launch the process, do not stop at entry point, and redirect stdout to "stdout.txt" file.
213        # The inferior should run to completion after "process.Continue()" call.
214        error = lldb.SBError()
215        process = target.Launch (self.dbg.GetListener(), None, None, None, "stdout.txt", None, None, 0, False, error)
216        process.Continue()
217        #self.runCmd("process status")
218
219        # The 'stdout.txt' file should now exist.
220        self.assertTrue(os.path.isfile("stdout.txt"),
221                        "'stdout.txt' exists due to redirected stdout via SBTarget.Launch() API.")
222
223        # Read the output file produced by running the program.
224        with open('stdout.txt', 'r') as f:
225            output = f.read()
226
227        # Let's delete the 'stdout.txt' file as a cleanup step.
228        try:
229            os.remove("stdout.txt")
230            pass
231        except OSError:
232            pass
233
234        self.expect(output, exe=False,
235            substrs = ["a(1)", "b(2)", "a(3)"])
236
237
238    def resolve_symbol_context_with_address(self):
239        """Exercise SBTaget.ResolveSymbolContextForAddress() API."""
240        exe = os.path.join(os.getcwd(), "a.out")
241
242        # Create a target by the debugger.
243        target = self.dbg.CreateTarget(exe)
244        self.assertTrue(target, VALID_TARGET)
245
246        # Now create the two breakpoints inside function 'a'.
247        breakpoint1 = target.BreakpointCreateByLocation('main.c', self.line1)
248        breakpoint2 = target.BreakpointCreateByLocation('main.c', self.line2)
249        #print "breakpoint1:", breakpoint1
250        #print "breakpoint2:", breakpoint2
251        self.assertTrue(breakpoint1 and
252                        breakpoint1.GetNumLocations() == 1,
253                        VALID_BREAKPOINT)
254        self.assertTrue(breakpoint2 and
255                        breakpoint2.GetNumLocations() == 1,
256                        VALID_BREAKPOINT)
257
258        # Now launch the process, and do not stop at entry point.
259        process = target.LaunchSimple(None, None, os.getcwd())
260        self.assertTrue(process, PROCESS_IS_VALID)
261
262        # Frame #0 should be on self.line1.
263        self.assertTrue(process.GetState() == lldb.eStateStopped)
264        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
265        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
266        #self.runCmd("process status")
267        frame0 = thread.GetFrameAtIndex(0)
268        lineEntry = frame0.GetLineEntry()
269        self.assertTrue(lineEntry.GetLine() == self.line1)
270
271        address1 = lineEntry.GetStartAddress()
272
273        # Continue the inferior, the breakpoint 2 should be hit.
274        process.Continue()
275        self.assertTrue(process.GetState() == lldb.eStateStopped)
276        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
277        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
278        #self.runCmd("process status")
279        frame0 = thread.GetFrameAtIndex(0)
280        lineEntry = frame0.GetLineEntry()
281        self.assertTrue(lineEntry.GetLine() == self.line2)
282
283        address2 = lineEntry.GetStartAddress()
284
285        #print "address1:", address1
286        #print "address2:", address2
287
288        # Now call SBTarget.ResolveSymbolContextForAddress() with the addresses from our line entry.
289        context1 = target.ResolveSymbolContextForAddress(address1, lldb.eSymbolContextEverything)
290        context2 = target.ResolveSymbolContextForAddress(address2, lldb.eSymbolContextEverything)
291
292        self.assertTrue(context1 and context2)
293        #print "context1:", context1
294        #print "context2:", context2
295
296        # Verify that the context point to the same function 'a'.
297        symbol1 = context1.GetSymbol()
298        symbol2 = context2.GetSymbol()
299        self.assertTrue(symbol1 and symbol2)
300        #print "symbol1:", symbol1
301        #print "symbol2:", symbol2
302
303        from lldbutil import get_description
304        desc1 = get_description(symbol1)
305        desc2 = get_description(symbol2)
306        self.assertTrue(desc1 and desc2 and desc1 == desc2,
307                        "The two addresses should resolve to the same symbol")
308
309
310if __name__ == '__main__':
311    import atexit
312    lldb.SBDebugger.Initialize()
313    atexit.register(lambda: lldb.SBDebugger.Terminate())
314    unittest2.main()
315