1""" 2Test that breakpoints (reason = breakpoint) have more priority than 3plan completion (reason = step in/out/over) when reporting stop reason after step, 4in particular 'step out' and 'step over', and in addition 'step in'. 5Check for correct StopReason when stepping to the line with breakpoint, 6which should be eStopReasonBreakpoint in general, 7and eStopReasonPlanComplete when breakpoint's condition fails or it is disabled. 8""" 9 10 11import unittest 12import lldb 13from lldbsuite.test.decorators import * 14from lldbsuite.test.lldbtest import * 15from lldbsuite.test import lldbutil 16 17 18class ThreadPlanUserBreakpointsTestCase(TestBase): 19 def setUp(self): 20 TestBase.setUp(self) 21 22 # Build and run to starting breakpoint 23 self.build() 24 src = lldb.SBFileSpec("main.cpp") 25 (self.target, self.process, self.thread, _) = lldbutil.run_to_source_breakpoint( 26 self, "// Start from here", src 27 ) 28 29 # Setup two more breakpoints 30 self.breakpoints = [ 31 self.target.BreakpointCreateBySourceRegex("breakpoint_%i" % i, src) 32 for i in range(2) 33 ] 34 self.assertTrue( 35 all(bp and bp.GetNumLocations() == 1 for bp in self.breakpoints), 36 VALID_BREAKPOINT, 37 ) 38 39 def check_correct_stop_reason(self, breakpoint_idx, condition): 40 self.assertState(self.process.GetState(), lldb.eStateStopped) 41 if condition: 42 # All breakpoints active, stop reason is breakpoint 43 thread1 = lldbutil.get_one_thread_stopped_at_breakpoint( 44 self.process, self.breakpoints[breakpoint_idx] 45 ) 46 self.assertEqual( 47 self.thread, thread1, "Didn't stop at breakpoint %i." % breakpoint_idx 48 ) 49 else: 50 # Breakpoints are inactive, stop reason is plan complete 51 self.assertEqual( 52 self.thread.GetStopReason(), 53 lldb.eStopReasonPlanComplete, 54 "Expected stop reason to be step into/over/out for inactive breakpoint %i line." 55 % breakpoint_idx, 56 ) 57 58 def change_breakpoints(self, action): 59 for bp in self.breakpoints: 60 action(bp) 61 62 def check_thread_plan_user_breakpoint(self, condition, set_up_breakpoint_func): 63 # Make breakpoints active/inactive in different ways 64 self.change_breakpoints(lambda bp: set_up_breakpoint_func(condition, bp)) 65 66 self.thread.StepInto() 67 # We should be stopped at the breakpoint_0 line with the correct stop reason 68 self.check_correct_stop_reason(0, condition) 69 70 # This step-over creates a step-out from `func_1` plan 71 self.thread.StepOver() 72 # We should be stopped at the breakpoint_1 line with the correct stop reason 73 self.check_correct_stop_reason(1, condition) 74 75 # Check explicit step-out 76 # Make sure we install the breakpoint at the right address: 77 # step-out might stop on different lines, if the compiler 78 # did or did not emit more instructions after the return 79 return_addr = self.thread.GetFrameAtIndex(1).GetPC() 80 step_out_breakpoint = self.target.BreakpointCreateByAddress(return_addr) 81 self.assertTrue(step_out_breakpoint, VALID_BREAKPOINT) 82 set_up_breakpoint_func(condition, step_out_breakpoint) 83 self.breakpoints.append(step_out_breakpoint) 84 self.thread.StepOut() 85 # We should be stopped somewhere in the main frame with the correct stop reason 86 self.check_correct_stop_reason(2, condition) 87 88 # Run the process until termination 89 self.process.Continue() 90 self.assertState(self.process.GetState(), lldb.eStateExited) 91 92 def set_up_breakpoints_condition(self, condition, bp): 93 # Set breakpoint condition to true/false 94 conditionStr = "true" if condition else "false" 95 bp.SetCondition(conditionStr) 96 97 def set_up_breakpoints_enable(self, condition, bp): 98 # Enable/disable breakpoint 99 bp.SetEnabled(condition) 100 101 def set_up_breakpoints_callback(self, condition, bp): 102 # Set breakpoint callback to return True/False 103 bp.SetScriptCallbackBody("return %s" % condition) 104 105 def test_thread_plan_user_breakpoint_conditional_active(self): 106 # Test with breakpoints having true condition 107 self.check_thread_plan_user_breakpoint( 108 condition=True, set_up_breakpoint_func=self.set_up_breakpoints_condition 109 ) 110 111 def test_thread_plan_user_breakpoint_conditional_inactive(self): 112 # Test with breakpoints having false condition 113 self.check_thread_plan_user_breakpoint( 114 condition=False, set_up_breakpoint_func=self.set_up_breakpoints_condition 115 ) 116 117 def test_thread_plan_user_breakpoint_unconditional_active(self): 118 # Test with breakpoints enabled unconditionally 119 self.check_thread_plan_user_breakpoint( 120 condition=True, set_up_breakpoint_func=self.set_up_breakpoints_enable 121 ) 122 123 def test_thread_plan_user_breakpoint_unconditional_inactive(self): 124 # Test with breakpoints disabled unconditionally 125 self.check_thread_plan_user_breakpoint( 126 condition=False, set_up_breakpoint_func=self.set_up_breakpoints_enable 127 ) 128 129 def test_thread_plan_user_breakpoint_callback_active(self): 130 # Test with breakpoints with callback that returns 'True' 131 self.check_thread_plan_user_breakpoint( 132 condition=True, set_up_breakpoint_func=self.set_up_breakpoints_callback 133 ) 134 135 def test_thread_plan_user_breakpoint_callback_inactive(self): 136 # Test with breakpoints with callback that returns 'False' 137 self.check_thread_plan_user_breakpoint( 138 condition=False, set_up_breakpoint_func=self.set_up_breakpoints_callback 139 ) 140