1""" 2Test SBThread APIs. 3""" 4 5from __future__ import print_function 6 7 8import lldb 9from lldbsuite.test.decorators import * 10from lldbsuite.test.lldbtest import * 11from lldbsuite.test import lldbutil 12from lldbsuite.test.lldbutil import get_stopped_thread, get_caller_symbol 13 14 15class ThreadAPITestCase(TestBase): 16 17 mydir = TestBase.compute_mydir(__file__) 18 19 def test_get_process(self): 20 """Test Python SBThread.GetProcess() API.""" 21 self.build() 22 self.get_process() 23 24 def test_get_stop_description(self): 25 """Test Python SBThread.GetStopDescription() API.""" 26 self.build() 27 self.get_stop_description() 28 29 def test_run_to_address(self): 30 """Test Python SBThread.RunToAddress() API.""" 31 # We build a different executable than the default build() does. 32 d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name} 33 self.build(dictionary=d) 34 self.setTearDownCleanup(dictionary=d) 35 self.run_to_address(self.exe_name) 36 37 @skipIfAsan # The output looks different under ASAN. 38 @expectedFailureAll(oslist=["linux"], archs=['arm'], bugnumber="llvm.org/pr45892") 39 @expectedFailureAll(oslist=["windows"]) 40 def test_step_out_of_malloc_into_function_b(self): 41 """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b().""" 42 # We build a different executable than the default build() does. 43 d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name} 44 self.build(dictionary=d) 45 self.setTearDownCleanup(dictionary=d) 46 self.step_out_of_malloc_into_function_b(self.exe_name) 47 48 def test_step_over_3_times(self): 49 """Test Python SBThread.StepOver() API.""" 50 # We build a different executable than the default build() does. 51 d = {'CXX_SOURCES': 'main2.cpp', 'EXE': self.exe_name} 52 self.build(dictionary=d) 53 self.setTearDownCleanup(dictionary=d) 54 self.step_over_3_times(self.exe_name) 55 56 def setUp(self): 57 # Call super's setUp(). 58 TestBase.setUp(self) 59 # Find the line number within main.cpp to break inside main(). 60 self.break_line = line_number( 61 "main.cpp", "// Set break point at this line and check variable 'my_char'.") 62 # Find the line numbers within main2.cpp for 63 # step_out_of_malloc_into_function_b() and step_over_3_times(). 64 self.step_out_of_malloc = line_number( 65 "main2.cpp", "// thread step-out of malloc into function b.") 66 self.after_3_step_overs = line_number( 67 "main2.cpp", "// we should reach here after 3 step-over's.") 68 69 # We'll use the test method name as the exe_name for executable 70 # compiled from main2.cpp. 71 self.exe_name = self.testMethodName 72 73 def get_process(self): 74 """Test Python SBThread.GetProcess() API.""" 75 exe = self.getBuildArtifact("a.out") 76 77 target = self.dbg.CreateTarget(exe) 78 self.assertTrue(target, VALID_TARGET) 79 80 breakpoint = target.BreakpointCreateByLocation( 81 "main.cpp", self.break_line) 82 self.assertTrue(breakpoint, VALID_BREAKPOINT) 83 self.runCmd("breakpoint list") 84 85 # Launch the process, and do not stop at the entry point. 86 process = target.LaunchSimple( 87 None, None, self.get_process_working_directory()) 88 89 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 90 self.assertTrue( 91 thread.IsValid(), 92 "There should be a thread stopped due to breakpoint") 93 self.runCmd("process status") 94 95 proc_of_thread = thread.GetProcess() 96 self.trace("proc_of_thread:", proc_of_thread) 97 self.assertEqual(proc_of_thread.GetProcessID(), process.GetProcessID()) 98 99 def get_stop_description(self): 100 """Test Python SBThread.GetStopDescription() API.""" 101 exe = self.getBuildArtifact("a.out") 102 103 target = self.dbg.CreateTarget(exe) 104 self.assertTrue(target, VALID_TARGET) 105 106 breakpoint = target.BreakpointCreateByLocation( 107 "main.cpp", self.break_line) 108 self.assertTrue(breakpoint, VALID_BREAKPOINT) 109 #self.runCmd("breakpoint list") 110 111 # Launch the process, and do not stop at the entry point. 112 process = target.LaunchSimple( 113 None, None, self.get_process_working_directory()) 114 115 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 116 self.assertTrue( 117 thread.IsValid(), 118 "There should be a thread stopped due to breakpoint") 119 120 # Get the stop reason. GetStopDescription expects that we pass in the size of the description 121 # we expect plus an additional byte for the null terminator. 122 123 # Test with a buffer that is exactly as large as the expected stop reason. 124 self.assertEqual("breakpoint 1.1", thread.GetStopDescription(len('breakpoint 1.1') + 1)) 125 126 # Test some smaller buffer sizes. 127 self.assertEqual("breakpoint", thread.GetStopDescription(len('breakpoint') + 1)) 128 self.assertEqual("break", thread.GetStopDescription(len('break') + 1)) 129 self.assertEqual("b", thread.GetStopDescription(len('b') + 1)) 130 131 # Test that we can pass in a much larger size and still get the right output. 132 self.assertEqual("breakpoint 1.1", thread.GetStopDescription(len('breakpoint 1.1') + 100)) 133 134 def step_out_of_malloc_into_function_b(self, exe_name): 135 """Test Python SBThread.StepOut() API to step out of a malloc call where the call site is at function b().""" 136 exe = self.getBuildArtifact(exe_name) 137 138 target = self.dbg.CreateTarget(exe) 139 self.assertTrue(target, VALID_TARGET) 140 141 breakpoint = target.BreakpointCreateByName('malloc') 142 self.assertTrue(breakpoint, VALID_BREAKPOINT) 143 144 # Launch the process, and do not stop at the entry point. 145 process = target.LaunchSimple( 146 None, None, self.get_process_working_directory()) 147 148 while True: 149 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 150 self.assertTrue( 151 thread.IsValid(), 152 "There should be a thread stopped due to breakpoint") 153 caller_symbol = get_caller_symbol(thread) 154 if not caller_symbol: 155 self.fail( 156 "Test failed: could not locate the caller symbol of malloc") 157 158 # Our top frame may be an inlined function in malloc() (e.g., on 159 # FreeBSD). Apply a simple heuristic of stepping out until we find 160 # a non-malloc caller 161 while caller_symbol.startswith("malloc"): 162 thread.StepOut() 163 self.assertTrue(thread.IsValid(), 164 "Thread valid after stepping to outer malloc") 165 caller_symbol = get_caller_symbol(thread) 166 167 if caller_symbol == "b(int)": 168 break 169 process.Continue() 170 171 # On Linux malloc calls itself in some case. Remove the breakpoint because we don't want 172 # to hit it during step-out. 173 target.BreakpointDelete(breakpoint.GetID()) 174 175 thread.StepOut() 176 self.runCmd("thread backtrace") 177 self.assertEqual( 178 thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), self.step_out_of_malloc, 179 "step out of malloc into function b is successful") 180 181 def step_over_3_times(self, exe_name): 182 """Test Python SBThread.StepOver() API.""" 183 exe = self.getBuildArtifact(exe_name) 184 185 target = self.dbg.CreateTarget(exe) 186 self.assertTrue(target, VALID_TARGET) 187 188 breakpoint = target.BreakpointCreateByLocation( 189 'main2.cpp', self.step_out_of_malloc) 190 self.assertTrue(breakpoint, VALID_BREAKPOINT) 191 self.runCmd("breakpoint list") 192 193 # Launch the process, and do not stop at the entry point. 194 process = target.LaunchSimple( 195 None, None, self.get_process_working_directory()) 196 197 self.assertTrue(process, PROCESS_IS_VALID) 198 199 # Frame #0 should be on self.step_out_of_malloc. 200 self.assertEqual(process.GetState(), lldb.eStateStopped) 201 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 202 self.assertTrue( 203 thread.IsValid(), 204 "There should be a thread stopped due to breakpoint condition") 205 self.runCmd("thread backtrace") 206 frame0 = thread.GetFrameAtIndex(0) 207 lineEntry = frame0.GetLineEntry() 208 self.assertEqual(lineEntry.GetLine(), self.step_out_of_malloc) 209 210 thread.StepOver() 211 thread.StepOver() 212 thread.StepOver() 213 self.runCmd("thread backtrace") 214 215 # Verify that we are stopped at the correct source line number in 216 # main2.cpp. 217 frame0 = thread.GetFrameAtIndex(0) 218 lineEntry = frame0.GetLineEntry() 219 self.assertEqual(thread.GetStopReason(), lldb.eStopReasonPlanComplete) 220 # Expected failure with clang as the compiler. 221 # rdar://problem/9223880 222 # 223 # Which has been fixed on the lldb by compensating for inaccurate line 224 # table information with r140416. 225 self.assertEqual(lineEntry.GetLine(), self.after_3_step_overs) 226 227 def run_to_address(self, exe_name): 228 """Test Python SBThread.RunToAddress() API.""" 229 exe = self.getBuildArtifact(exe_name) 230 231 target = self.dbg.CreateTarget(exe) 232 self.assertTrue(target, VALID_TARGET) 233 234 breakpoint = target.BreakpointCreateByLocation( 235 'main2.cpp', self.step_out_of_malloc) 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 process = target.LaunchSimple( 241 None, None, self.get_process_working_directory()) 242 243 self.assertTrue(process, PROCESS_IS_VALID) 244 245 # Frame #0 should be on self.step_out_of_malloc. 246 self.assertEqual(process.GetState(), lldb.eStateStopped) 247 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 248 self.assertTrue( 249 thread.IsValid(), 250 "There should be a thread stopped due to breakpoint condition") 251 self.runCmd("thread backtrace") 252 frame0 = thread.GetFrameAtIndex(0) 253 lineEntry = frame0.GetLineEntry() 254 self.assertEqual(lineEntry.GetLine(), self.step_out_of_malloc) 255 256 # Get the start/end addresses for this line entry. 257 start_addr = lineEntry.GetStartAddress().GetLoadAddress(target) 258 end_addr = lineEntry.GetEndAddress().GetLoadAddress(target) 259 if self.TraceOn(): 260 print("start addr:", hex(start_addr)) 261 print("end addr:", hex(end_addr)) 262 263 # Disable the breakpoint. 264 self.assertTrue(target.DisableAllBreakpoints()) 265 self.runCmd("breakpoint list") 266 267 thread.StepOver() 268 thread.StepOver() 269 thread.StepOver() 270 self.runCmd("thread backtrace") 271 272 # Now ask SBThread to run to the address 'start_addr' we got earlier, which 273 # corresponds to self.step_out_of_malloc line entry's start address. 274 thread.RunToAddress(start_addr) 275 self.runCmd("process status") 276 #self.runCmd("thread backtrace") 277