1""" 2Test breakpoint conditions with 'breakpoint modify -c <expr> id'. 3""" 4 5import lldb 6from lldbsuite.test.decorators import * 7from lldbsuite.test.lldbtest import * 8from lldbsuite.test import lldbutil 9 10 11class BreakpointConditionsTestCase(TestBase): 12 13 mydir = TestBase.compute_mydir(__file__) 14 15 def test_breakpoint_condition_and_run_command(self): 16 """Exercise breakpoint condition with 'breakpoint modify -c <expr> id'.""" 17 self.build() 18 self.breakpoint_conditions() 19 20 def test_breakpoint_condition_inline_and_run_command(self): 21 """Exercise breakpoint condition inline with 'breakpoint set'.""" 22 self.build() 23 self.breakpoint_conditions(inline=True) 24 25 @add_test_categories(['pyapi']) 26 def test_breakpoint_condition_and_python_api(self): 27 """Use Python APIs to set breakpoint conditions.""" 28 self.build() 29 self.breakpoint_conditions_python() 30 31 @add_test_categories(['pyapi']) 32 def test_breakpoint_invalid_condition_and_python_api(self): 33 """Use Python APIs to set breakpoint conditions.""" 34 self.build() 35 self.breakpoint_invalid_conditions_python() 36 37 def setUp(self): 38 # Call super's setUp(). 39 TestBase.setUp(self) 40 # Find the line number to of function 'c'. 41 self.line1 = line_number( 42 'main.c', '// Find the line number of function "c" here.') 43 self.line2 = line_number( 44 'main.c', "// Find the line number of c's parent call here.") 45 46 def breakpoint_conditions(self, inline=False): 47 """Exercise breakpoint condition with 'breakpoint modify -c <expr> id'.""" 48 exe = self.getBuildArtifact("a.out") 49 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 50 51 if inline: 52 # Create a breakpoint by function name 'c' and set the condition. 53 lldbutil.run_break_set_by_symbol( 54 self, 55 "c", 56 extra_options="-c 'val == 3'", 57 num_expected_locations=1, 58 sym_exact=True) 59 else: 60 # Create a breakpoint by function name 'c'. 61 lldbutil.run_break_set_by_symbol( 62 self, "c", num_expected_locations=1, sym_exact=True) 63 64 # And set a condition on the breakpoint to stop on when 'val == 3'. 65 self.runCmd("breakpoint modify -c 'val == 3' 1") 66 67 # Now run the program. 68 self.runCmd("run", RUN_SUCCEEDED) 69 70 # The process should be stopped at this point. 71 self.expect("process status", PROCESS_STOPPED, 72 patterns=['Process .* stopped']) 73 74 # 'frame variable --show-types val' should return 3 due to breakpoint condition. 75 self.expect( 76 "frame variable --show-types val", 77 VARIABLES_DISPLAYED_CORRECTLY, 78 startstr='(int) val = 3') 79 80 # Also check the hit count, which should be 3, by design. 81 self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE, 82 substrs=["resolved = 1", 83 "Condition: val == 3", 84 "hit count = 1"]) 85 86 # The frame #0 should correspond to main.c:36, the executable statement 87 # in function name 'c'. And the parent frame should point to 88 # main.c:24. 89 self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT_CONDITION, 90 #substrs = ["stop reason = breakpoint"], 91 patterns=["frame #0.*main.c:%d" % self.line1, 92 "frame #1.*main.c:%d" % self.line2]) 93 94 # Test that "breakpoint modify -c ''" clears the condition for the last 95 # created breakpoint, so that when the breakpoint hits, val == 1. 96 self.runCmd("process kill") 97 self.runCmd("breakpoint modify -c ''") 98 self.expect( 99 "breakpoint list -f", 100 BREAKPOINT_STATE_CORRECT, 101 matching=False, 102 substrs=["Condition:"]) 103 104 # Now run the program again. 105 self.runCmd("run", RUN_SUCCEEDED) 106 107 # The process should be stopped at this point. 108 self.expect("process status", PROCESS_STOPPED, 109 patterns=['Process .* stopped']) 110 111 # 'frame variable --show-types val' should return 1 since it is the first breakpoint hit. 112 self.expect( 113 "frame variable --show-types val", 114 VARIABLES_DISPLAYED_CORRECTLY, 115 startstr='(int) val = 1') 116 117 self.runCmd("process kill") 118 119 def breakpoint_conditions_python(self): 120 """Use Python APIs to set breakpoint conditions.""" 121 target = self.createTestTarget() 122 123 # Now create a breakpoint on main.c by name 'c'. 124 breakpoint = target.BreakpointCreateByName('c', 'a.out') 125 self.trace("breakpoint:", breakpoint) 126 self.assertTrue(breakpoint and 127 breakpoint.GetNumLocations() == 1, 128 VALID_BREAKPOINT) 129 130 # We didn't associate a thread index with the breakpoint, so it should 131 # be invalid. 132 self.assertEqual(breakpoint.GetThreadIndex(), lldb.UINT32_MAX, 133 "The thread index should be invalid") 134 # The thread name should be invalid, too. 135 self.assertTrue(breakpoint.GetThreadName() is None, 136 "The thread name should be invalid") 137 138 # Let's set the thread index for this breakpoint and verify that it is, 139 # indeed, being set correctly. 140 # There's only one thread for the process. 141 breakpoint.SetThreadIndex(1) 142 self.assertEqual(breakpoint.GetThreadIndex(), 1, 143 "The thread index has been set correctly") 144 145 # Get the breakpoint location from breakpoint after we verified that, 146 # indeed, it has one location. 147 location = breakpoint.GetLocationAtIndex(0) 148 self.assertTrue(location and 149 location.IsEnabled(), 150 VALID_BREAKPOINT_LOCATION) 151 152 # Set the condition on the breakpoint location. 153 location.SetCondition('val == 3') 154 self.expect(location.GetCondition(), exe=False, 155 startstr='val == 3') 156 157 # Now launch the process, and do not stop at entry point. 158 process = target.LaunchSimple( 159 None, None, self.get_process_working_directory()) 160 self.assertTrue(process, PROCESS_IS_VALID) 161 162 # Frame #0 should be on self.line1 and the break condition should hold. 163 from lldbsuite.test.lldbutil import get_stopped_thread 164 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 165 self.assertTrue( 166 thread.IsValid(), 167 "There should be a thread stopped due to breakpoint condition") 168 frame0 = thread.GetFrameAtIndex(0) 169 var = frame0.FindValue('val', lldb.eValueTypeVariableArgument) 170 self.assertTrue(frame0.GetLineEntry().GetLine() == self.line1 and 171 var.GetValue() == '3') 172 173 # The hit count for the breakpoint should be 1. 174 self.assertEqual(breakpoint.GetHitCount(), 1) 175 176 # Test that the condition expression didn't create a result variable: 177 options = lldb.SBExpressionOptions() 178 value = frame0.EvaluateExpression("$0", options) 179 self.assertTrue(value.GetError().Fail(), 180 "Conditions should not make result variables.") 181 process.Continue() 182 183 def breakpoint_invalid_conditions_python(self): 184 """Use Python APIs to set breakpoint conditions.""" 185 exe = self.getBuildArtifact("a.out") 186 187 # Create a target by the debugger. 188 target = self.dbg.CreateTarget(exe) 189 self.assertTrue(target, VALID_TARGET) 190 191 # Now create a breakpoint on main.c by name 'c'. 192 breakpoint = target.BreakpointCreateByName('c', 'a.out') 193 self.trace("breakpoint:", breakpoint) 194 self.assertTrue(breakpoint and 195 breakpoint.GetNumLocations() == 1, 196 VALID_BREAKPOINT) 197 198 # Set the condition on the breakpoint. 199 breakpoint.SetCondition('no_such_variable == not_this_one_either') 200 self.expect(breakpoint.GetCondition(), exe=False, 201 startstr='no_such_variable == not_this_one_either') 202 203 # Now launch the process, and do not stop at entry point. 204 process = target.LaunchSimple( 205 None, None, self.get_process_working_directory()) 206 self.assertTrue(process, PROCESS_IS_VALID) 207 208 # Frame #0 should be on self.line1 and the break condition should hold. 209 from lldbsuite.test.lldbutil import get_stopped_thread 210 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 211 self.assertTrue( 212 thread.IsValid(), 213 "There should be a thread stopped due to breakpoint condition") 214 frame0 = thread.GetFrameAtIndex(0) 215 var = frame0.FindValue('val', lldb.eValueTypeVariableArgument) 216 self.assertEqual(frame0.GetLineEntry().GetLine(), self.line1) 217 218 # The hit count for the breakpoint should be 1. 219 self.assertEqual(breakpoint.GetHitCount(), 1) 220