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