1""" 2Test breakpoint names. 3""" 4 5 6import os 7import lldb 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test import lldbutil 11 12 13class BreakpointNames(TestBase): 14 NO_DEBUG_INFO_TESTCASE = True 15 16 @add_test_categories(["pyapi"]) 17 def test_setting_names(self): 18 """Use Python APIs to test that we can set breakpoint names.""" 19 self.build() 20 self.setup_target() 21 self.do_check_names() 22 23 def test_illegal_names(self): 24 """Use Python APIs to test that we don't allow illegal names.""" 25 self.build() 26 self.setup_target() 27 self.do_check_illegal_names() 28 29 def test_using_names(self): 30 """Use Python APIs to test that operations on names works correctly.""" 31 self.build() 32 self.setup_target() 33 self.do_check_using_names() 34 35 def test_configuring_names(self): 36 """Use Python APIs to test that configuring options on breakpoint names works correctly.""" 37 self.build() 38 self.make_a_dummy_name() 39 self.setup_target() 40 self.do_check_configuring_names() 41 42 def test_configuring_permissions_sb(self): 43 """Use Python APIs to test that configuring permissions on names works correctly.""" 44 self.build() 45 self.setup_target() 46 self.do_check_configuring_permissions_sb() 47 48 def test_configuring_permissions_cli(self): 49 """Use Python APIs to test that configuring permissions on names works correctly.""" 50 self.build() 51 self.setup_target() 52 self.do_check_configuring_permissions_cli() 53 54 def setup_target(self): 55 exe = self.getBuildArtifact("a.out") 56 57 # Create a targets we are making breakpoint in and copying to: 58 self.target = self.dbg.CreateTarget(exe) 59 self.assertTrue(self.target, VALID_TARGET) 60 self.main_file_spec = lldb.SBFileSpec( 61 os.path.join(self.getSourceDir(), "main.c") 62 ) 63 64 def check_name_in_target(self, bkpt_name): 65 name_list = lldb.SBStringList() 66 self.target.GetBreakpointNames(name_list) 67 found_it = False 68 for name in name_list: 69 if name == bkpt_name: 70 found_it = True 71 break 72 self.assertTrue( 73 found_it, "Didn't find the name %s in the target's name list:" % (bkpt_name) 74 ) 75 76 def setUp(self): 77 # Call super's setUp(). 78 TestBase.setUp(self) 79 80 # These are the settings we're going to be putting into names & breakpoints: 81 self.bp_name_string = "ABreakpoint" 82 self.is_one_shot = True 83 self.ignore_count = 1000 84 self.condition = "1 == 2" 85 self.auto_continue = True 86 self.tid = 0xAAAA 87 self.tidx = 10 88 self.thread_name = "Fooey" 89 self.queue_name = "Blooey" 90 self.cmd_list = lldb.SBStringList() 91 self.cmd_list.AppendString("frame var") 92 self.cmd_list.AppendString("bt") 93 self.help_string = "I do something interesting" 94 95 def do_check_names(self): 96 """Use Python APIs to check that we can set & retrieve breakpoint names""" 97 bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) 98 bkpt_name = "ABreakpoint" 99 other_bkpt_name = "_AnotherBreakpoint" 100 101 # Add a name and make sure we match it: 102 success = bkpt.AddNameWithErrorHandling(bkpt_name) 103 self.assertSuccess(success, "We couldn't add a legal name to a breakpoint.") 104 105 matches = bkpt.MatchesName(bkpt_name) 106 self.assertTrue(matches, "We didn't match the name we just set") 107 108 # Make sure we don't match irrelevant names: 109 matches = bkpt.MatchesName("NotABreakpoint") 110 self.assertTrue(not matches, "We matched a name we didn't set.") 111 112 # Make sure the name is also in the target: 113 self.check_name_in_target(bkpt_name) 114 115 # Add another name, make sure that works too: 116 bkpt.AddNameWithErrorHandling(other_bkpt_name) 117 118 matches = bkpt.MatchesName(bkpt_name) 119 self.assertTrue( 120 matches, "Adding a name means we didn't match the name we just set" 121 ) 122 self.check_name_in_target(other_bkpt_name) 123 124 # Remove the name and make sure we no longer match it: 125 bkpt.RemoveName(bkpt_name) 126 matches = bkpt.MatchesName(bkpt_name) 127 self.assertTrue(not matches, "We still match a name after removing it.") 128 129 # Make sure the name list has the remaining name: 130 name_list = lldb.SBStringList() 131 bkpt.GetNames(name_list) 132 num_names = name_list.GetSize() 133 self.assertEqual( 134 num_names, 1, "Name list has %d items, expected 1." % (num_names) 135 ) 136 137 name = name_list.GetStringAtIndex(0) 138 self.assertEqual( 139 name, 140 other_bkpt_name, 141 "Remaining name was: %s expected %s." % (name, other_bkpt_name), 142 ) 143 144 def do_check_illegal_names(self): 145 """Use Python APIs to check that we reject illegal names.""" 146 bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) 147 bad_names = [ 148 "-CantStartWithADash", 149 "1CantStartWithANumber", 150 "^CantStartWithNonAlpha", 151 "CantHave-ADash", 152 "Cant Have Spaces", 153 ] 154 for bad_name in bad_names: 155 success = bkpt.AddNameWithErrorHandling(bad_name) 156 self.assertTrue( 157 success.Fail(), "We allowed an illegal name: %s" % (bad_name) 158 ) 159 bp_name = lldb.SBBreakpointName(self.target, bad_name) 160 self.assertFalse( 161 bp_name.IsValid(), 162 "We made a breakpoint name with an illegal name: %s" % (bad_name), 163 ) 164 165 retval = lldb.SBCommandReturnObject() 166 self.dbg.GetCommandInterpreter().HandleCommand( 167 "break set -n whatever -N '%s'" % (bad_name), retval 168 ) 169 self.assertTrue( 170 not retval.Succeeded(), 171 "break set succeeded with: illegal name: %s" % (bad_name), 172 ) 173 174 def do_check_using_names(self): 175 """Use Python APIs to check names work in place of breakpoint ID's.""" 176 177 # Create a dummy breakpoint to use up ID 1 178 _ = self.target.BreakpointCreateByLocation(self.main_file_spec, 30) 179 180 # Create a breakpoint to test with 181 bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) 182 bkpt_name = "ABreakpoint" 183 bkpt_id = bkpt.GetID() 184 other_bkpt_name = "_AnotherBreakpoint" 185 186 # Add a name and make sure we match it: 187 success = bkpt.AddNameWithErrorHandling(bkpt_name) 188 self.assertSuccess(success, "We couldn't add a legal name to a breakpoint.") 189 190 bkpts = lldb.SBBreakpointList(self.target) 191 self.target.FindBreakpointsByName(bkpt_name, bkpts) 192 193 self.assertEqual(bkpts.GetSize(), 1, "One breakpoint matched.") 194 found_bkpt = bkpts.GetBreakpointAtIndex(0) 195 self.assertEqual(bkpt.GetID(), found_bkpt.GetID(), "The right breakpoint.") 196 self.assertEqual(bkpt.GetID(), bkpt_id, "With the same ID as before.") 197 198 retval = lldb.SBCommandReturnObject() 199 self.dbg.GetCommandInterpreter().HandleCommand( 200 "break disable %s" % (bkpt_name), retval 201 ) 202 self.assertTrue( 203 retval.Succeeded(), "break disable failed with: %s." % (retval.GetError()) 204 ) 205 self.assertTrue(not bkpt.IsEnabled(), "We didn't disable the breakpoint.") 206 207 # Also make sure we don't apply commands to non-matching names: 208 self.dbg.GetCommandInterpreter().HandleCommand( 209 "break modify --one-shot 1 %s" % (other_bkpt_name), retval 210 ) 211 self.assertTrue( 212 retval.Succeeded(), "break modify failed with: %s." % (retval.GetError()) 213 ) 214 self.assertTrue( 215 not bkpt.IsOneShot(), "We applied one-shot to the wrong breakpoint." 216 ) 217 218 def check_option_values(self, bp_object): 219 self.assertEqual(bp_object.IsOneShot(), self.is_one_shot, "IsOneShot") 220 self.assertEqual(bp_object.GetIgnoreCount(), self.ignore_count, "IgnoreCount") 221 self.assertEqual(bp_object.GetCondition(), self.condition, "Condition") 222 self.assertEqual( 223 bp_object.GetAutoContinue(), self.auto_continue, "AutoContinue" 224 ) 225 self.assertEqual(bp_object.GetThreadID(), self.tid, "Thread ID") 226 self.assertEqual(bp_object.GetThreadIndex(), self.tidx, "Thread Index") 227 self.assertEqual(bp_object.GetThreadName(), self.thread_name, "Thread Name") 228 self.assertEqual(bp_object.GetQueueName(), self.queue_name, "Queue Name") 229 set_cmds = lldb.SBStringList() 230 bp_object.GetCommandLineCommands(set_cmds) 231 self.assertEqual( 232 set_cmds.GetSize(), self.cmd_list.GetSize(), "Size of command line commands" 233 ) 234 for idx in range(0, set_cmds.GetSize()): 235 self.assertEqual( 236 self.cmd_list.GetStringAtIndex(idx), 237 set_cmds.GetStringAtIndex(idx), 238 "Command %d" % (idx), 239 ) 240 241 def make_a_dummy_name(self): 242 "This makes a breakpoint name in the dummy target to make sure it gets copied over" 243 244 dummy_target = self.dbg.GetDummyTarget() 245 self.assertTrue(dummy_target.IsValid(), "Dummy target was not valid.") 246 247 def cleanup(): 248 self.dbg.GetDummyTarget().DeleteBreakpointName(self.bp_name_string) 249 250 # Execute the cleanup function during test case tear down. 251 self.addTearDownHook(cleanup) 252 253 # Now find it in the dummy target, and make sure these settings took: 254 bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string) 255 # Make sure the name is right: 256 self.assertEqual( 257 bp_name.GetName(), 258 self.bp_name_string, 259 "Wrong bp_name: %s" % (bp_name.GetName()), 260 ) 261 bp_name.SetOneShot(self.is_one_shot) 262 bp_name.SetIgnoreCount(self.ignore_count) 263 bp_name.SetCondition(self.condition) 264 bp_name.SetAutoContinue(self.auto_continue) 265 bp_name.SetThreadID(self.tid) 266 bp_name.SetThreadIndex(self.tidx) 267 bp_name.SetThreadName(self.thread_name) 268 bp_name.SetQueueName(self.queue_name) 269 bp_name.SetCommandLineCommands(self.cmd_list) 270 271 # Now look it up again, and make sure it got set correctly. 272 bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string) 273 self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.") 274 self.check_option_values(bp_name) 275 276 def do_check_configuring_names(self): 277 """Use Python APIs to check that configuring breakpoint names works correctly.""" 278 other_bp_name_string = "AnotherBreakpointName" 279 cl_bp_name_string = "CLBreakpointName" 280 281 # Now find the version copied in from the dummy target, and make sure these settings took: 282 bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) 283 self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.") 284 self.check_option_values(bp_name) 285 286 # Now add this name to a breakpoint, and make sure it gets configured properly 287 bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) 288 success = bkpt.AddNameWithErrorHandling(self.bp_name_string) 289 self.assertSuccess(success, "Couldn't add this name to the breakpoint") 290 self.check_option_values(bkpt) 291 292 # Now make a name from this breakpoint, and make sure the new name is properly configured: 293 new_name = lldb.SBBreakpointName(bkpt, other_bp_name_string) 294 self.assertTrue( 295 new_name.IsValid(), "Couldn't make a valid bp_name from a breakpoint." 296 ) 297 self.check_option_values(bkpt) 298 299 # Now change the name's option and make sure it gets propagated to 300 # the breakpoint: 301 new_auto_continue = not self.auto_continue 302 bp_name.SetAutoContinue(new_auto_continue) 303 self.assertEqual( 304 bp_name.GetAutoContinue(), 305 new_auto_continue, 306 "Couldn't change auto-continue on the name", 307 ) 308 self.assertEqual( 309 bkpt.GetAutoContinue(), 310 new_auto_continue, 311 "Option didn't propagate to the breakpoint.", 312 ) 313 314 # Now make this same breakpoint name - but from the command line 315 cmd_str = ( 316 "breakpoint name configure %s -o %d -i %d -c '%s' -G %d -t %d -x %d -T '%s' -q '%s' -H '%s'" 317 % ( 318 cl_bp_name_string, 319 self.is_one_shot, 320 self.ignore_count, 321 self.condition, 322 self.auto_continue, 323 self.tid, 324 self.tidx, 325 self.thread_name, 326 self.queue_name, 327 self.help_string, 328 ) 329 ) 330 for cmd in self.cmd_list: 331 cmd_str += " -C '%s'" % (cmd) 332 333 self.runCmd(cmd_str, check=True) 334 # Now look up this name again and check its options: 335 cl_name = lldb.SBBreakpointName(self.target, cl_bp_name_string) 336 self.check_option_values(cl_name) 337 # Also check the help string: 338 self.assertEqual( 339 self.help_string, cl_name.GetHelpString(), "Help string didn't match" 340 ) 341 # Change the name and make sure that works: 342 new_help = "I do something even more interesting" 343 cl_name.SetHelpString(new_help) 344 self.assertEqual(new_help, cl_name.GetHelpString(), "SetHelpString didn't") 345 346 # We should have three names now, make sure the target can list them: 347 name_list = lldb.SBStringList() 348 self.target.GetBreakpointNames(name_list) 349 for name_string in [ 350 self.bp_name_string, 351 other_bp_name_string, 352 cl_bp_name_string, 353 ]: 354 self.assertIn( 355 name_string, name_list, "Didn't find %s in names" % (name_string) 356 ) 357 358 # Delete the name from the current target. Make sure that works and deletes the 359 # name from the breakpoint as well: 360 self.target.DeleteBreakpointName(self.bp_name_string) 361 name_list.Clear() 362 self.target.GetBreakpointNames(name_list) 363 self.assertNotIn( 364 self.bp_name_string, 365 name_list, 366 "Didn't delete %s from a real target" % (self.bp_name_string), 367 ) 368 # Also make sure the name got removed from breakpoints holding it: 369 self.assertFalse( 370 bkpt.MatchesName(self.bp_name_string), 371 "Didn't remove the name from the breakpoint.", 372 ) 373 374 # Test that deleting the name we injected into the dummy target works (there's also a 375 # cleanup that will do this, but that won't test the result... 376 dummy_target = self.dbg.GetDummyTarget() 377 dummy_target.DeleteBreakpointName(self.bp_name_string) 378 name_list.Clear() 379 dummy_target.GetBreakpointNames(name_list) 380 self.assertNotIn( 381 self.bp_name_string, 382 name_list, 383 "Didn't delete %s from the dummy target" % (self.bp_name_string), 384 ) 385 # Also make sure the name got removed from breakpoints holding it: 386 self.assertFalse( 387 bkpt.MatchesName(self.bp_name_string), 388 "Didn't remove the name from the breakpoint.", 389 ) 390 391 def check_permission_results(self, bp_name): 392 self.assertFalse(bp_name.GetAllowDelete(), "Didn't set allow delete.") 393 protected_bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) 394 protected_id = protected_bkpt.GetID() 395 396 unprotected_bkpt = self.target.BreakpointCreateByLocation( 397 self.main_file_spec, 10 398 ) 399 unprotected_id = unprotected_bkpt.GetID() 400 401 success = protected_bkpt.AddNameWithErrorHandling(self.bp_name_string) 402 self.assertSuccess(success, "Couldn't add this name to the breakpoint") 403 404 self.target.DisableAllBreakpoints() 405 self.assertTrue( 406 protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled" 407 ) 408 self.assertFalse( 409 unprotected_bkpt.IsEnabled(), 410 "Protected too many breakpoints from disabling.", 411 ) 412 413 # Try from the command line too: 414 unprotected_bkpt.SetEnabled(True) 415 result = lldb.SBCommandReturnObject() 416 self.dbg.GetCommandInterpreter().HandleCommand("break disable", result) 417 self.assertTrue(result.Succeeded()) 418 self.assertTrue( 419 protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled" 420 ) 421 self.assertFalse( 422 unprotected_bkpt.IsEnabled(), 423 "Protected too many breakpoints from disabling.", 424 ) 425 426 self.target.DeleteAllBreakpoints() 427 bkpt = self.target.FindBreakpointByID(protected_id) 428 self.assertTrue( 429 bkpt.IsValid(), "Didn't keep the breakpoint from being deleted." 430 ) 431 bkpt = self.target.FindBreakpointByID(unprotected_id) 432 self.assertFalse( 433 bkpt.IsValid(), "Protected too many breakpoints from deletion." 434 ) 435 436 # Remake the unprotected breakpoint and try again from the command line: 437 unprotected_bkpt = self.target.BreakpointCreateByLocation( 438 self.main_file_spec, 10 439 ) 440 unprotected_id = unprotected_bkpt.GetID() 441 442 self.dbg.GetCommandInterpreter().HandleCommand("break delete -f", result) 443 self.assertTrue(result.Succeeded()) 444 bkpt = self.target.FindBreakpointByID(protected_id) 445 self.assertTrue( 446 bkpt.IsValid(), "Didn't keep the breakpoint from being deleted." 447 ) 448 bkpt = self.target.FindBreakpointByID(unprotected_id) 449 self.assertFalse( 450 bkpt.IsValid(), "Protected too many breakpoints from deletion." 451 ) 452 453 def do_check_configuring_permissions_sb(self): 454 bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) 455 456 # Make a breakpoint name with delete disallowed: 457 bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) 458 self.assertTrue( 459 bp_name.IsValid(), "Failed to make breakpoint name for valid name." 460 ) 461 462 bp_name.SetAllowDelete(False) 463 bp_name.SetAllowDisable(False) 464 bp_name.SetAllowList(False) 465 self.check_permission_results(bp_name) 466 467 def do_check_configuring_permissions_cli(self): 468 # Make the name with the right options using the command line: 469 self.runCmd( 470 "breakpoint name configure -L 0 -D 0 -A 0 %s" % (self.bp_name_string), 471 check=True, 472 ) 473 # Now look up the breakpoint we made, and check that it works. 474 bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) 475 self.assertTrue( 476 bp_name.IsValid(), "Didn't make a breakpoint name we could find." 477 ) 478 self.check_permission_results(bp_name) 479