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