TestThreadAPI.py revision 7cd134af161941808cfe20eaf96d1b6ecf833e7e
1"""
2Test SBThread APIs.
3"""
4
5import os, time
6import unittest2
7import lldb
8from lldbutil import get_stopped_thread, get_caller_symbol
9from lldbtest import *
10
11class ThreadAPITestCase(TestBase):
12
13    mydir = os.path.join("python_api", "thread")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @python_api_test
17    def test_get_process_with_dsym(self):
18        """Test Python SBThread.GetProcess() API."""
19        self.buildDsym()
20        self.get_process()
21
22    @python_api_test
23    def test_get_process_with_dwarf(self):
24        """Test Python SBThread.GetProcess() API."""
25        self.buildDwarf()
26        self.get_process()
27
28    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
29    @python_api_test
30    def test_get_stop_description_with_dsym(self):
31        """Test Python SBThread.GetStopDescription() API."""
32        self.buildDsym()
33        self.get_stop_description()
34
35    @python_api_test
36    def test_get_stop_description_with_dwarf(self):
37        """Test Python SBThread.GetStopDescription() API."""
38        self.buildDwarf()
39        self.get_stop_description()
40
41    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
42    @python_api_test
43    def test_run_to_address_with_dsym(self):
44        """Test Python SBThread.RunToAddress() API."""
45        # We build a different executable than the default buildDwarf() does.
46        d = {'CXX_SOURCES': 'main2.cpp'}
47        self.buildDsym(dictionary=d)
48        self.setTearDownCleanup(dictionary=d)
49        self.run_to_address()
50
51    @python_api_test
52    def test_run_to_address_with_dwarf(self):
53        """Test Python SBThread.RunToAddress() API."""
54        # We build a different executable than the default buildDwarf() does.
55        d = {'CXX_SOURCES': 'main2.cpp'}
56        self.buildDwarf(dictionary=d)
57        self.setTearDownCleanup(dictionary=d)
58        self.run_to_address()
59
60    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
61    @python_api_test
62    def test_step_out_of_malloc_into_function_b_with_dsym(self):
63        """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
64        # We build a different executable than the default buildDsym() does.
65        d = {'CXX_SOURCES': 'main2.cpp'}
66        self.buildDsym(dictionary=d)
67        self.setTearDownCleanup(dictionary=d)
68        self.step_out_of_malloc_into_function_b()
69
70    @python_api_test
71    def test_step_out_of_malloc_into_function_b_with_dwarf(self):
72        """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
73        # We build a different executable than the default buildDwarf() does.
74        d = {'CXX_SOURCES': 'main2.cpp'}
75        self.buildDwarf(dictionary=d)
76        self.setTearDownCleanup(dictionary=d)
77        self.step_out_of_malloc_into_function_b()
78
79    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
80    @python_api_test
81    def test_step_over_3_times_with_dsym(self):
82        """Test Python SBThread.StepOver() API."""
83        # We build a different executable than the default buildDsym() does.
84        d = {'CXX_SOURCES': 'main2.cpp'}
85        self.buildDsym(dictionary=d)
86        self.setTearDownCleanup(dictionary=d)
87        self.step_over_3_times()
88
89    @python_api_test
90    def test_step_over_3_times_with_dwarf(self):
91        """Test Python SBThread.StepOver() API."""
92        # We build a different executable than the default buildDwarf() does.
93        d = {'CXX_SOURCES': 'main2.cpp'}
94        self.buildDwarf(dictionary=d)
95        self.setTearDownCleanup(dictionary=d)
96        self.step_over_3_times()
97
98    def setUp(self):
99        # Call super's setUp().
100        TestBase.setUp(self)
101        # Find the line number within main.cpp to break inside main().
102        self.line = line_number("main.cpp", "// Set break point at this line and check variable 'my_char'.")
103        # Find the line numbers within main2.cpp for step_over_3_times() and step_out_of_malloc_into_function_b().
104        self.line2 = line_number("main2.cpp", "// thread step-out of malloc into function b.")
105        self.line3 = line_number("main2.cpp", "// we should reach here after 3 step-over's.")
106
107    def get_process(self):
108        """Test Python SBThread.GetProcess() API."""
109        exe = os.path.join(os.getcwd(), "a.out")
110
111        target = self.dbg.CreateTarget(exe)
112        self.assertTrue(target, VALID_TARGET)
113
114        breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line)
115        self.assertTrue(breakpoint, VALID_BREAKPOINT)
116        self.runCmd("breakpoint list")
117
118        # Launch the process, and do not stop at the entry point.
119        self.process = target.LaunchSimple(None, None, os.getcwd())
120
121        thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
122        self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
123        self.runCmd("process status")
124
125        proc_of_thread = thread.GetProcess()
126        #print "proc_of_thread:", proc_of_thread
127        self.assertTrue(proc_of_thread.GetProcessID() == self.process.GetProcessID())
128
129    def get_stop_description(self):
130        """Test Python SBThread.GetStopDescription() API."""
131        exe = os.path.join(os.getcwd(), "a.out")
132
133        target = self.dbg.CreateTarget(exe)
134        self.assertTrue(target, VALID_TARGET)
135
136        breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line)
137        self.assertTrue(breakpoint, VALID_BREAKPOINT)
138        #self.runCmd("breakpoint list")
139
140        # Launch the process, and do not stop at the entry point.
141        self.process = target.LaunchSimple(None, None, os.getcwd())
142
143        thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
144        self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
145        #self.runCmd("process status")
146
147        # Due to the typemap magic (see lldb.swig), we pass in an (int)length to GetStopDescription
148        # and expect to get a Python string as the result object!
149        # The 100 is just an arbitrary number specifying the buffer size.
150        stop_description = thread.GetStopDescription(100)
151        self.expect(stop_description, exe=False,
152            startstr = 'breakpoint')
153
154    def step_out_of_malloc_into_function_b(self):
155        """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b()."""
156        exe = os.path.join(os.getcwd(), "a.out")
157
158        target = self.dbg.CreateTarget(exe)
159        self.assertTrue(target, VALID_TARGET)
160
161        breakpoint = target.BreakpointCreateByName('malloc')
162        self.assertTrue(breakpoint, VALID_BREAKPOINT)
163        self.runCmd("breakpoint list")
164
165        # Launch the process, and do not stop at the entry point.
166        self.process = target.LaunchSimple(None, None, os.getcwd())
167
168        while True:
169            thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
170            self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
171            caller_symbol = get_caller_symbol(thread)
172            #print "caller symbol of malloc:", caller_symbol
173            if not caller_symbol:
174                self.fail("Test failed: could not locate the caller symbol of malloc")
175            if caller_symbol == "b(int)":
176                break
177            #self.runCmd("thread backtrace")
178            #self.runCmd("process status")
179            self.process.Continue()
180
181        thread.StepOut()
182        self.runCmd("thread backtrace")
183        #self.runCmd("process status")
184        self.assertTrue(thread.GetFrameAtIndex(0).GetLineEntry().GetLine() == self.line2,
185                        "step out of malloc into function b is successful")
186
187    def step_over_3_times(self):
188        """Test Python SBThread.StepOver() API."""
189        exe = os.path.join(os.getcwd(), "a.out")
190
191        target = self.dbg.CreateTarget(exe)
192        self.assertTrue(target, VALID_TARGET)
193
194        breakpoint = target.BreakpointCreateByLocation('main2.cpp', self.line2)
195        self.assertTrue(breakpoint, VALID_BREAKPOINT)
196        self.runCmd("breakpoint list")
197
198        # Launch the process, and do not stop at the entry point.
199        self.process = target.LaunchSimple(None, None, os.getcwd())
200
201        self.assertTrue(self.process, PROCESS_IS_VALID)
202
203        # Frame #0 should be on self.line2.
204        self.assertTrue(self.process.GetState() == lldb.eStateStopped)
205        thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
206        self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint condition")
207        self.runCmd("thread backtrace")
208        frame0 = thread.GetFrameAtIndex(0)
209        lineEntry = frame0.GetLineEntry()
210        self.assertTrue(lineEntry.GetLine() == self.line2)
211
212        thread.StepOver()
213        thread.StepOver()
214        thread.StepOver()
215        self.runCmd("thread backtrace")
216
217        # Verify that we are stopped at the correct source line number in main2.cpp.
218        frame0 = thread.GetFrameAtIndex(0)
219        lineEntry = frame0.GetLineEntry()
220        self.assertTrue(thread.GetStopReason() == lldb.eStopReasonPlanComplete)
221        self.assertTrue(lineEntry.GetLine() == self.line3)
222
223    def run_to_address(self):
224        """Test Python SBThread.RunToAddress() API."""
225        # We build a different executable than the default buildDwarf() does.
226        d = {'CXX_SOURCES': 'main2.cpp'}
227        self.buildDwarf(dictionary=d)
228        self.setTearDownCleanup(dictionary=d)
229
230        exe = os.path.join(os.getcwd(), "a.out")
231
232        target = self.dbg.CreateTarget(exe)
233        self.assertTrue(target, VALID_TARGET)
234
235        breakpoint = target.BreakpointCreateByLocation('main2.cpp', self.line2)
236        self.assertTrue(breakpoint, VALID_BREAKPOINT)
237        self.runCmd("breakpoint list")
238
239        # Launch the process, and do not stop at the entry point.
240        self.process = target.LaunchSimple(None, None, os.getcwd())
241
242        self.assertTrue(self.process, PROCESS_IS_VALID)
243
244        # Frame #0 should be on self.line2.
245        self.assertTrue(self.process.GetState() == lldb.eStateStopped)
246        thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
247        self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint condition")
248        self.runCmd("thread backtrace")
249        frame0 = thread.GetFrameAtIndex(0)
250        lineEntry = frame0.GetLineEntry()
251        self.assertTrue(lineEntry.GetLine() == self.line2)
252
253        # Get the start/end addresses for this line entry.
254        start_addr = lineEntry.GetStartAddress().GetLoadAddress(target)
255        end_addr = lineEntry.GetEndAddress().GetLoadAddress(target)
256        if self.TraceOn():
257            print "start addr:", hex(start_addr)
258            print "end addr:", hex(end_addr)
259
260        # Disable the breakpoint.
261        self.assertTrue(target.DisableAllBreakpoints())
262        self.runCmd("breakpoint list")
263
264        thread.StepOver()
265        thread.StepOver()
266        thread.StepOver()
267        self.runCmd("thread backtrace")
268
269        # Now ask SBThread to run to the address 'start_addr' we got earlier, which
270        # corresponds to self.line2 line entry's start address.
271        thread.RunToAddress(start_addr)
272        self.runCmd("process status")
273        #self.runCmd("thread backtrace")
274
275
276if __name__ == '__main__':
277    import atexit
278    lldb.SBDebugger.Initialize()
279    atexit.register(lambda: lldb.SBDebugger.Terminate())
280    unittest2.main()
281