1""" 2Test lldb breakpoint command add/list/delete. 3""" 4 5 6 7import lldb 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test import lldbutil 11import side_effect 12 13 14class BreakpointCommandTestCase(TestBase): 15 16 NO_DEBUG_INFO_TESTCASE = True 17 mydir = TestBase.compute_mydir(__file__) 18 19 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") 20 @skipIfReproducer # side_effect bypasses reproducer 21 def not_test_breakpoint_command_sequence(self): 22 """Test a sequence of breakpoint command add, list, and delete.""" 23 self.build() 24 self.breakpoint_command_sequence() 25 26 @skipIf(oslist=["windows"], bugnumber="llvm.org/pr44431") 27 @skipIfReproducer # side_effect bypasses reproducer 28 def test_script_parameters(self): 29 """Test a sequence of breakpoint command add, list, and delete.""" 30 self.build() 31 self.breakpoint_command_script_parameters() 32 33 def test_commands_on_creation(self): 34 self.build() 35 self.breakpoint_commands_on_creation() 36 37 def setUp(self): 38 # Call super's setUp(). 39 TestBase.setUp(self) 40 # Find the line number to break inside main(). 41 self.line = line_number('main.c', '// Set break point at this line.') 42 # disable "There is a running process, kill it and restart?" prompt 43 self.runCmd("settings set auto-confirm true") 44 self.addTearDownHook( 45 lambda: self.runCmd("settings clear auto-confirm")) 46 47 def test_delete_all_breakpoints(self): 48 """Test that deleting all breakpoints works.""" 49 self.build() 50 exe = self.getBuildArtifact("a.out") 51 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 52 53 lldbutil.run_break_set_by_symbol(self, "main") 54 lldbutil.run_break_set_by_file_and_line( 55 self, "main.c", self.line, num_expected_locations=1, loc_exact=True) 56 57 self.runCmd("run", RUN_SUCCEEDED) 58 59 self.runCmd("breakpoint delete") 60 self.runCmd("process continue") 61 self.expect("process status", PROCESS_STOPPED, 62 patterns=['Process .* exited with status = 0']) 63 64 65 def breakpoint_command_sequence(self): 66 """Test a sequence of breakpoint command add, list, and delete.""" 67 exe = self.getBuildArtifact("a.out") 68 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 69 70 # Add three breakpoints on the same line. The first time we don't specify the file, 71 # since the default file is the one containing main: 72 lldbutil.run_break_set_by_file_and_line( 73 self, None, self.line, num_expected_locations=1, loc_exact=True) 74 lldbutil.run_break_set_by_file_and_line( 75 self, "main.c", self.line, num_expected_locations=1, loc_exact=True) 76 lldbutil.run_break_set_by_file_and_line( 77 self, "main.c", self.line, num_expected_locations=1, loc_exact=True) 78 # Breakpoint 4 - set at the same location as breakpoint 1 to test 79 # setting breakpoint commands on two breakpoints at a time 80 lldbutil.run_break_set_by_file_and_line( 81 self, None, self.line, num_expected_locations=1, loc_exact=True) 82 # Make sure relative path source breakpoints work as expected. We test 83 # with partial paths with and without "./" prefixes. 84 lldbutil.run_break_set_by_file_and_line( 85 self, "./main.c", self.line, 86 num_expected_locations=1, loc_exact=True) 87 lldbutil.run_break_set_by_file_and_line( 88 self, "breakpoint_command/main.c", self.line, 89 num_expected_locations=1, loc_exact=True) 90 lldbutil.run_break_set_by_file_and_line( 91 self, "./breakpoint_command/main.c", self.line, 92 num_expected_locations=1, loc_exact=True) 93 lldbutil.run_break_set_by_file_and_line( 94 self, "breakpoint/breakpoint_command/main.c", self.line, 95 num_expected_locations=1, loc_exact=True) 96 lldbutil.run_break_set_by_file_and_line( 97 self, "./breakpoint/breakpoint_command/main.c", self.line, 98 num_expected_locations=1, loc_exact=True) 99 # Test relative breakpoints with incorrect paths and make sure we get 100 # no breakpoint locations 101 lldbutil.run_break_set_by_file_and_line( 102 self, "invalid/main.c", self.line, 103 num_expected_locations=0, loc_exact=True) 104 lldbutil.run_break_set_by_file_and_line( 105 self, "./invalid/main.c", self.line, 106 num_expected_locations=0, loc_exact=True) 107 # Now add callbacks for the breakpoints just created. 108 self.runCmd( 109 "breakpoint command add -s command -o 'frame variable --show-types --scope' 1 4") 110 self.runCmd( 111 "breakpoint command add -s python -o 'import side_effect; side_effect.one_liner = \"one liner was here\"' 2") 112 113 import side_effect 114 self.runCmd("command script import --allow-reload ./bktptcmd.py") 115 116 self.runCmd( 117 "breakpoint command add --python-function bktptcmd.function 3") 118 119 # Check that the breakpoint commands are correctly set. 120 121 # The breakpoint list now only contains breakpoint 1. 122 self.expect( 123 "breakpoint list", "Breakpoints 1 & 2 created", substrs=[ 124 "2: file = 'main.c', line = %d, exact_match = 0, locations = 1" % 125 self.line], patterns=[ 126 "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1" % 127 self.line]) 128 129 self.expect( 130 "breakpoint list -f", 131 "Breakpoints 1 & 2 created", 132 substrs=[ 133 "2: file = 'main.c', line = %d, exact_match = 0, locations = 1" % 134 self.line], 135 patterns=[ 136 "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1" % 137 self.line, 138 "1.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" % 139 self.line, 140 "2.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" % 141 self.line]) 142 143 self.expect("breakpoint command list 1", "Breakpoint 1 command ok", 144 substrs=["Breakpoint commands:", 145 "frame variable --show-types --scope"]) 146 self.expect("breakpoint command list 2", "Breakpoint 2 command ok", 147 substrs=["Breakpoint commands (Python):", 148 "import side_effect", 149 "side_effect.one_liner"]) 150 self.expect("breakpoint command list 3", "Breakpoint 3 command ok", 151 substrs=["Breakpoint commands (Python):", 152 "bktptcmd.function(frame, bp_loc, internal_dict)"]) 153 154 self.expect("breakpoint command list 4", "Breakpoint 4 command ok", 155 substrs=["Breakpoint commands:", 156 "frame variable --show-types --scope"]) 157 158 self.runCmd("breakpoint delete 4") 159 160 # Next lets try some other breakpoint kinds. First break with a regular expression 161 # and then specify only one file. The first time we should get two locations, 162 # the second time only one: 163 164 lldbutil.run_break_set_by_regexp( 165 self, r"._MyFunction", num_expected_locations=2) 166 167 lldbutil.run_break_set_by_regexp( 168 self, 169 r"._MyFunction", 170 extra_options="-f a.c", 171 num_expected_locations=1) 172 173 lldbutil.run_break_set_by_regexp( 174 self, 175 r"._MyFunction", 176 extra_options="-f a.c -f b.c", 177 num_expected_locations=2) 178 179 # Now try a source regex breakpoint: 180 lldbutil.run_break_set_by_source_regexp( 181 self, 182 r"is about to return [12]0", 183 extra_options="-f a.c -f b.c", 184 num_expected_locations=2) 185 186 lldbutil.run_break_set_by_source_regexp( 187 self, 188 r"is about to return [12]0", 189 extra_options="-f a.c", 190 num_expected_locations=1) 191 192 # Reset our canary variables and run the program. 193 side_effect.one_liner = None 194 side_effect.bktptcmd = None 195 self.runCmd("run", RUN_SUCCEEDED) 196 197 # Check the value of canary variables. 198 self.assertEquals("one liner was here", side_effect.one_liner) 199 self.assertEquals("function was here", side_effect.bktptcmd) 200 201 # Finish the program. 202 self.runCmd("process continue") 203 204 # Remove the breakpoint command associated with breakpoint 1. 205 self.runCmd("breakpoint command delete 1") 206 207 # Remove breakpoint 2. 208 self.runCmd("breakpoint delete 2") 209 210 self.expect( 211 "breakpoint command list 1", 212 startstr="Breakpoint 1 does not have an associated command.") 213 self.expect( 214 "breakpoint command list 2", 215 error=True, 216 startstr="error: '2' is not a currently valid breakpoint ID.") 217 218 # The breakpoint list now only contains breakpoint 1. 219 self.expect( 220 "breakpoint list -f", 221 "Breakpoint 1 exists", 222 patterns=[ 223 "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1, resolved = 1" % 224 self.line, 225 "hit count = 1"]) 226 227 # Not breakpoint 2. 228 self.expect( 229 "breakpoint list -f", 230 "No more breakpoint 2", 231 matching=False, 232 substrs=[ 233 "2: file = 'main.c', line = %d, exact_match = 0, locations = 1, resolved = 1" % 234 self.line]) 235 236 # Run the program again, with breakpoint 1 remaining. 237 self.runCmd("run", RUN_SUCCEEDED) 238 239 # We should be stopped again due to breakpoint 1. 240 241 # The stop reason of the thread should be breakpoint. 242 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, 243 substrs=['stopped', 244 'stop reason = breakpoint']) 245 246 # The breakpoint should have a hit count of 2. 247 self.expect("breakpoint list -f", BREAKPOINT_HIT_TWICE, 248 substrs=['resolved, hit count = 2']) 249 250 def breakpoint_command_script_parameters(self): 251 """Test that the frame and breakpoint location are being properly passed to the script breakpoint command function.""" 252 exe = self.getBuildArtifact("a.out") 253 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 254 255 # Add a breakpoint. 256 lldbutil.run_break_set_by_file_and_line( 257 self, "main.c", self.line, num_expected_locations=1, loc_exact=True) 258 259 # Now add callbacks for the breakpoints just created. 260 self.runCmd("breakpoint command add -s python -o 'import side_effect; side_effect.frame = str(frame); side_effect.bp_loc = str(bp_loc)' 1") 261 262 # Reset canary variables and run. 263 side_effect.frame = None 264 side_effect.bp_loc = None 265 self.runCmd("run", RUN_SUCCEEDED) 266 267 self.expect(side_effect.frame, exe=False, startstr="frame #0:") 268 self.expect(side_effect.bp_loc, exe=False, 269 patterns=["1.* where = .*main .* resolved, hit count = 1"]) 270 271 def breakpoint_commands_on_creation(self): 272 """Test that setting breakpoint commands when creating the breakpoint works""" 273 exe = self.getBuildArtifact("a.out") 274 target = self.dbg.CreateTarget(exe) 275 self.assertTrue(target.IsValid(), "Created an invalid target.") 276 277 # Add a breakpoint. 278 lldbutil.run_break_set_by_file_and_line( 279 self, "main.c", self.line, num_expected_locations=1, loc_exact=True, 280 extra_options='-C bt -C "thread list" -C continue') 281 282 bkpt = target.FindBreakpointByID(1) 283 self.assertTrue(bkpt.IsValid(), "Couldn't find breakpoint 1") 284 com_list = lldb.SBStringList() 285 bkpt.GetCommandLineCommands(com_list) 286 self.assertEqual(com_list.GetSize(), 3, "Got the wrong number of commands") 287 self.assertEqual(com_list.GetStringAtIndex(0), "bt", "First bt") 288 self.assertEqual(com_list.GetStringAtIndex(1), "thread list", "Next thread list") 289 self.assertEqual(com_list.GetStringAtIndex(2), "continue", "Last continue") 290 291 def test_breakpoint_delete_disabled(self): 292 """Test 'break delete --disabled' works""" 293 self.build() 294 exe = self.getBuildArtifact("a.out") 295 target = self.dbg.CreateTarget(exe) 296 self.assertTrue(target.IsValid(), "Created an invalid target.") 297 298 bp_1 = target.BreakpointCreateByName("main") 299 bp_2 = target.BreakpointCreateByName("not_here") 300 bp_3 = target.BreakpointCreateByName("main") 301 bp_3.AddName("DeleteMeNot") 302 303 bp_1.SetEnabled(False) 304 bp_3.SetEnabled(False) 305 306 bp_id_1 = bp_1.GetID() 307 bp_id_2 = bp_2.GetID() 308 bp_id_3 = bp_3.GetID() 309 310 self.runCmd("breakpoint delete --disabled DeleteMeNot") 311 312 bp_1 = target.FindBreakpointByID(bp_id_1) 313 self.assertFalse(bp_1.IsValid(), "Didn't delete disabled breakpoint 1") 314 315 bp_2 = target.FindBreakpointByID(bp_id_2) 316 self.assertTrue(bp_2.IsValid(), "Deleted enabled breakpoint 2") 317 318 bp_3 = target.FindBreakpointByID(bp_id_3) 319 self.assertTrue(bp_3.IsValid(), "DeleteMeNot didn't protect disabled breakpoint 3") 320