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