1"""Test stepping over vrs. hitting breakpoints & subsequent stepping in various forms.""" 2 3 4import lldb 5from lldbsuite.test.decorators import * 6from lldbsuite.test.lldbtest import * 7from lldbsuite.test import lldbutil 8 9 10class TestCStepping(TestBase): 11 def setUp(self): 12 # Call super's setUp(). 13 TestBase.setUp(self) 14 # Find the line numbers that we will step to in main: 15 self.main_source = "main.c" 16 17 @add_test_categories(["pyapi", "basic_process"]) 18 @expectedFailureAll(oslist=["freebsd"], bugnumber="llvm.org/pr17932") 19 @expectedFailureAll(oslist=["linux"], archs=no_match(["i386", "x86_64"])) 20 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24777") 21 @expectedFailureNetBSD 22 def test_and_python_api(self): 23 """Test stepping over vrs. hitting breakpoints & subsequent stepping in various forms.""" 24 self.build() 25 exe = self.getBuildArtifact("a.out") 26 27 target = self.dbg.CreateTarget(exe) 28 self.assertTrue(target, VALID_TARGET) 29 30 self.main_source_spec = lldb.SBFileSpec(self.main_source) 31 32 breakpoints_to_disable = [] 33 34 break_1_in_main = target.BreakpointCreateBySourceRegex( 35 "// frame select 2, thread step-out while stopped at .c.1..", 36 self.main_source_spec, 37 ) 38 self.assertTrue(break_1_in_main, VALID_BREAKPOINT) 39 breakpoints_to_disable.append(break_1_in_main) 40 41 break_in_a = target.BreakpointCreateBySourceRegex( 42 "// break here to stop in a before calling b", self.main_source_spec 43 ) 44 self.assertTrue(break_in_a, VALID_BREAKPOINT) 45 breakpoints_to_disable.append(break_in_a) 46 47 break_in_b = target.BreakpointCreateBySourceRegex( 48 "// thread step-out while stopped at .c.2..", self.main_source_spec 49 ) 50 self.assertTrue(break_in_b, VALID_BREAKPOINT) 51 breakpoints_to_disable.append(break_in_b) 52 53 break_in_c = target.BreakpointCreateBySourceRegex( 54 "// Find the line number of function .c. here.", self.main_source_spec 55 ) 56 self.assertTrue(break_in_c, VALID_BREAKPOINT) 57 breakpoints_to_disable.append(break_in_c) 58 59 # Now launch the process, and do not stop at entry point. 60 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 61 62 self.assertTrue(process, PROCESS_IS_VALID) 63 64 # The stop reason of the thread should be breakpoint. 65 threads = lldbutil.get_threads_stopped_at_breakpoint(process, break_1_in_main) 66 67 if len(threads) != 1: 68 self.fail("Failed to stop at first breakpoint in main.") 69 70 thread = threads[0] 71 72 # Get the stop id and for fun make sure it increases: 73 old_stop_id = process.GetStopID() 74 75 # Now step over, which should cause us to hit the breakpoint in "a" 76 thread.StepOver() 77 78 # The stop reason of the thread should be breakpoint. 79 threads = lldbutil.get_threads_stopped_at_breakpoint(process, break_in_a) 80 if len(threads) != 1: 81 self.fail("Failed to stop at breakpoint in a.") 82 83 # Check that the stop ID increases: 84 new_stop_id = process.GetStopID() 85 self.assertGreater(new_stop_id, old_stop_id, "Stop ID increases monotonically.") 86 87 thread = threads[0] 88 89 # Step over, and we should hit the breakpoint in b: 90 thread.StepOver() 91 92 threads = lldbutil.get_threads_stopped_at_breakpoint(process, break_in_b) 93 if len(threads) != 1: 94 self.fail("Failed to stop at breakpoint in b.") 95 thread = threads[0] 96 97 # Now try running some function, and make sure that we still end up in the same place 98 # and with the same stop reason. 99 frame = thread.GetFrameAtIndex(0) 100 current_line = frame.GetLineEntry().GetLine() 101 current_file = frame.GetLineEntry().GetFileSpec() 102 current_bp = thread.stop_reason_data 103 104 stop_id_before_expression = process.GetStopID() 105 stop_id_before_including_expressions = process.GetStopID(True) 106 107 frame.EvaluateExpression("(int) printf (print_string)") 108 109 frame = thread.GetFrameAtIndex(0) 110 self.assertEqual( 111 current_line, 112 frame.GetLineEntry().GetLine(), 113 "The line stayed the same after expression.", 114 ) 115 self.assertEqual( 116 current_file, 117 frame.GetLineEntry().GetFileSpec(), 118 "The file stayed the same after expression.", 119 ) 120 self.assertEqual( 121 thread.GetStopReason(), 122 lldb.eStopReasonBreakpoint, 123 "We still say we stopped for a breakpoint.", 124 ) 125 self.assertEqual( 126 thread.stop_reason_data, 127 current_bp, 128 "And it is the same breakpoint.", 129 ) 130 131 # Also make sure running the expression didn't change the public stop id 132 # but did change if we are asking for expression stops as well. 133 stop_id_after_expression = process.GetStopID() 134 stop_id_after_including_expressions = process.GetStopID(True) 135 136 self.assertEqual( 137 stop_id_before_expression, 138 stop_id_after_expression, 139 "Expression calling doesn't change stop ID", 140 ) 141 142 self.assertGreater( 143 stop_id_after_including_expressions, 144 stop_id_before_including_expressions, 145 "Stop ID including expressions increments over expression call.", 146 ) 147 148 # Do the same thing with an expression that's going to crash, and make 149 # sure we are still unchanged. 150 151 frame.EvaluateExpression("((char *) 0)[0] = 'a'") 152 153 frame = thread.GetFrameAtIndex(0) 154 self.assertEqual( 155 current_line, 156 frame.GetLineEntry().GetLine(), 157 "The line stayed the same after expression.", 158 ) 159 self.assertEqual( 160 current_file, 161 frame.GetLineEntry().GetFileSpec(), 162 "The file stayed the same after expression.", 163 ) 164 self.assertEqual( 165 thread.GetStopReason(), 166 lldb.eStopReasonBreakpoint, 167 "We still say we stopped for a breakpoint.", 168 ) 169 self.assertTrue( 170 thread.GetStopReasonDataAtIndex(0) == current_bp[0] 171 and thread.GetStopReasonDataAtIndex(1) == current_bp[1], 172 "And it is the same breakpoint.", 173 ) 174 175 # Now continue and make sure we just complete the step: 176 # Disable all our breakpoints first - sometimes the compiler puts two line table entries in for the 177 # breakpoint a "b" and we don't want to hit that. 178 for bkpt in breakpoints_to_disable: 179 bkpt.SetEnabled(False) 180 181 process.Continue() 182 183 self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "a") 184 self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonPlanComplete) 185 186 # And one more time should get us back to main: 187 process.Continue() 188 189 self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "main") 190 self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonPlanComplete) 191 192 # Now make sure we can call a function, break in the called function, 193 # then have "continue" get us back out again: 194 frame = thread.GetFrameAtIndex(0) 195 frame = thread.GetFrameAtIndex(0) 196 current_line = frame.GetLineEntry().GetLine() 197 current_file = frame.GetLineEntry().GetFileSpec() 198 199 break_in_b.SetEnabled(True) 200 options = lldb.SBExpressionOptions() 201 options.SetIgnoreBreakpoints(False) 202 options.SetFetchDynamicValue(False) 203 options.SetUnwindOnError(False) 204 frame.EvaluateExpression("b (4)", options) 205 206 threads = lldbutil.get_threads_stopped_at_breakpoint(process, break_in_b) 207 208 if len(threads) != 1: 209 self.fail("Failed to stop at breakpoint in b when calling b.") 210 thread = threads[0] 211 212 # So do a step over here to make sure we can still do that: 213 214 thread.StepOver() 215 216 # See that we are still in b: 217 func_name = thread.GetFrameAtIndex(0).GetFunctionName() 218 self.assertEqual(func_name, "b", "Should be in 'b', were in %s" % (func_name)) 219 220 # Okay, now if we continue, we will finish off our function call and we 221 # should end up back in "a" as if nothing had happened: 222 process.Continue() 223 224 self.assertEqual( 225 thread.GetFrameAtIndex(0).GetLineEntry().GetLine(), current_line 226 ) 227 self.assertEqual( 228 thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec(), current_file 229 ) 230 231 # Now we are going to test step in targeting a function: 232 233 break_in_b.SetEnabled(False) 234 235 break_before_complex_1 = target.BreakpointCreateBySourceRegex( 236 "// Stop here to try step in targeting b.", self.main_source_spec 237 ) 238 self.assertTrue(break_before_complex_1, VALID_BREAKPOINT) 239 240 break_before_complex_2 = target.BreakpointCreateBySourceRegex( 241 "// Stop here to try step in targeting complex.", self.main_source_spec 242 ) 243 self.assertTrue(break_before_complex_2, VALID_BREAKPOINT) 244 245 break_before_complex_3 = target.BreakpointCreateBySourceRegex( 246 "// Stop here to step targeting b and hitting breakpoint.", 247 self.main_source_spec, 248 ) 249 self.assertTrue(break_before_complex_3, VALID_BREAKPOINT) 250 251 break_before_complex_4 = target.BreakpointCreateBySourceRegex( 252 "// Stop here to make sure bogus target steps over.", self.main_source_spec 253 ) 254 self.assertTrue(break_before_complex_4, VALID_BREAKPOINT) 255 256 threads = lldbutil.continue_to_breakpoint(process, break_before_complex_1) 257 self.assertEqual(len(threads), 1) 258 thread = threads[0] 259 break_before_complex_1.SetEnabled(False) 260 261 thread.StepInto("b") 262 self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "b") 263 264 # Now continue out and stop at the next call to complex. This time 265 # step all the way into complex: 266 threads = lldbutil.continue_to_breakpoint(process, break_before_complex_2) 267 self.assertEqual(len(threads), 1) 268 thread = threads[0] 269 break_before_complex_2.SetEnabled(False) 270 271 thread.StepInto("complex") 272 self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "complex") 273 274 # Now continue out and stop at the next call to complex. This time 275 # enable breakpoints in a and c and then step targeting b: 276 threads = lldbutil.continue_to_breakpoint(process, break_before_complex_3) 277 self.assertEqual(len(threads), 1) 278 thread = threads[0] 279 break_before_complex_3.SetEnabled(False) 280 281 break_at_start_of_a = target.BreakpointCreateByName("a") 282 break_at_start_of_c = target.BreakpointCreateByName("c") 283 284 thread.StepInto("b") 285 threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonBreakpoint) 286 287 self.assertEqual(len(threads), 1) 288 thread = threads[0] 289 stop_break_id = thread.GetStopReasonDataAtIndex(0) 290 self.assertTrue( 291 stop_break_id == break_at_start_of_a.GetID() 292 or stop_break_id == break_at_start_of_c.GetID() 293 ) 294 295 break_at_start_of_a.SetEnabled(False) 296 break_at_start_of_c.SetEnabled(False) 297 298 process.Continue() 299 self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "b") 300 301 # Now continue out and stop at the next call to complex. This time 302 # enable breakpoints in a and c and then step targeting b: 303 threads = lldbutil.continue_to_breakpoint(process, break_before_complex_4) 304 self.assertEqual(len(threads), 1) 305 thread = threads[0] 306 break_before_complex_4.SetEnabled(False) 307 308 thread.StepInto("NoSuchFunction") 309 self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "main") 310