1""" 2Test lldb breakpoint command add/list/delete. 3""" 4 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil, lldbplatformutil 10import json 11import os 12import side_effect 13 14 15class BreakpointCommandTestCase(TestBase): 16 NO_DEBUG_INFO_TESTCASE = True 17 18 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") 19 def test_breakpoint_command_sequence(self): 20 """Test a sequence of breakpoint command add, list, and delete.""" 21 self.build() 22 self.breakpoint_command_sequence() 23 24 @skipIf(oslist=["windows"], bugnumber="llvm.org/pr44431") 25 def test_script_parameters(self): 26 """Test a sequence of breakpoint command add, list, and delete.""" 27 self.build() 28 self.breakpoint_command_script_parameters() 29 30 def test_commands_on_creation(self): 31 self.build() 32 self.breakpoint_commands_on_creation() 33 34 @skipIf(oslist=["windows"]) 35 @no_debug_info_test 36 def test_breakpoints_with_relative_path_line_tables(self): 37 """ 38 Test that we can set breakpoints using a full or partial path when 39 line tables in the debug information has relative paths where the 40 relative path is either fully contained in the specified path, or if 41 the specified path also a relative path that is shorter than the 42 path in the debug info. 43 44 The "relative.yaml" contains a line table that is: 45 46 Line table for a/b/c/main.cpp in `a.out 47 0x0000000100003f94: a/b/c/main.cpp:1 48 0x0000000100003fb0: a/b/c/main.cpp:2:3 49 0x0000000100003fb8: a/b/c/main.cpp:2:3 50 51 So the line table contains relative paths. We should be able to set 52 breakpoints with any source path that matches this path which 53 includes paths that are longer than "a/b/c/main.cpp", but also any 54 relative path that is shorter than this while all specified relative 55 path components still match. 56 """ 57 src_dir = self.getSourceDir() 58 yaml_path = os.path.join(src_dir, "relative.yaml") 59 yaml_base, ext = os.path.splitext(yaml_path) 60 obj_path = self.getBuildArtifact("a.out") 61 self.yaml2obj(yaml_path, obj_path) 62 63 # Create a target with the object file we just created from YAML 64 target = self.dbg.CreateTarget(obj_path) 65 # We now have debug information with line table paths that start are 66 # "./a/b/c/main.cpp". 67 68 # Make sure that all of the following paths create a breakpoint 69 # successfully. We have paths that are longer than our path, and also 70 # that are shorter where all relative directories still match. 71 valid_paths = [ 72 "/x/a/b/c/main.cpp", 73 "/x/y/a/b/c/main.cpp", 74 "./x/y/a/b/c/main.cpp", 75 "x/y/a/b/c/main.cpp", 76 "./y/a/b/c/main.cpp", 77 "y/a/b/c/main.cpp", 78 "./a/b/c/main.cpp", 79 "a/b/c/main.cpp", 80 "./b/c/main.cpp", 81 "b/c/main.cpp", 82 "./c/main.cpp", 83 "c/main.cpp", 84 "./main.cpp", 85 "main.cpp", 86 ] 87 for path in valid_paths: 88 bkpt = target.BreakpointCreateByLocation(path, 2) 89 self.assertGreater( 90 bkpt.GetNumLocations(), 91 0, 92 'Couldn\'t resolve breakpoint using full path "%s" in executate "%s" with ' 93 "debug info that has relative path with matching suffix" 94 % (path, self.getBuildArtifact("a.out")), 95 ) 96 invalid_paths = [ 97 "/x/b/c/main.cpp", 98 "/x/c/main.cpp", 99 "/x/main.cpp", 100 "./x/y/a/d/c/main.cpp", 101 ] 102 # Reset source map. 103 self.runCmd("settings clear target.source-map") 104 for path in invalid_paths: 105 bkpt = target.BreakpointCreateByLocation(path, 2) 106 self.assertEqual( 107 bkpt.GetNumLocations(), 108 0, 109 'Incorrectly resolved a breakpoint using full path "%s" with ' 110 "debug info that has relative path with matching suffix" % (path), 111 ) 112 113 @no_debug_info_test 114 def test_breakpoints_with_bad_aranges(self): 115 """ 116 Test that we can set breakpoints in a file that has an invalid 117 .debug_aranges. Older versions of LLDB would find a line entry 118 in the line table and then would use the start address of the line 119 entry to do an address lookup on the entry from the line table. If 120 this address to symbol context lookup would fail, due to a bad 121 .debug_aranges, it would cause the breakpoint to not get resolved. 122 Verify that even in these conditions we are able to resolve a 123 breakpoint. 124 125 The "bad_aranges.yaml" contains a line table that is: 126 127 Line table for /tmp/ab/main.cpp in `a.out 128 0x0000000100003f94: /tmp/ab/main.cpp:1 129 0x0000000100003fb0: /tmp/ab/main.cpp:2:3 130 0x0000000100003fb8: /tmp/ab/main.cpp:2:3 131 132 The .debug_aranges has one range for this compile unit that is 133 invalid: [0x0000000200003f94-0x0000000200003fb8). This will cause 134 the resolving of the addresses to fail. 135 """ 136 src_dir = self.getSourceDir() 137 yaml_path = os.path.join(src_dir, "bad_aranges.yaml") 138 yaml_base, ext = os.path.splitext(yaml_path) 139 obj_path = self.getBuildArtifact("a.out") 140 self.yaml2obj(yaml_path, obj_path) 141 142 # Create a target with the object file we just created from YAML 143 target = self.dbg.CreateTarget(obj_path) 144 src_path = "/tmp/ab/main.cpp" 145 bkpt = target.BreakpointCreateByLocation(src_path, 2) 146 self.assertGreater( 147 bkpt.GetNumLocations(), 148 0, 149 'Couldn\'t resolve breakpoint using "%s" in executate "%s" with ' 150 "debug info that has a bad .debug_aranges section" 151 % (src_path, self.getBuildArtifact("a.out")), 152 ) 153 154 def setUp(self): 155 # Call super's setUp(). 156 TestBase.setUp(self) 157 # Find the line number to break inside main(). 158 self.line = line_number("main.c", "// Set break point at this line.") 159 # disable "There is a running process, kill it and restart?" prompt 160 self.runCmd("settings set auto-confirm true") 161 self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm")) 162 163 def test_delete_all_breakpoints(self): 164 """Test that deleting all breakpoints works.""" 165 self.build() 166 exe = self.getBuildArtifact("a.out") 167 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 168 169 lldbutil.run_break_set_by_symbol(self, "main") 170 lldbutil.run_break_set_by_file_and_line( 171 self, "main.c", self.line, num_expected_locations=1, loc_exact=True 172 ) 173 174 self.runCmd("run", RUN_SUCCEEDED) 175 176 self.runCmd("breakpoint delete") 177 self.runCmd("process continue") 178 self.expect( 179 "process status", 180 PROCESS_STOPPED, 181 patterns=["Process .* exited with status = 0"], 182 ) 183 184 def breakpoint_command_sequence(self): 185 """Test a sequence of breakpoint command add, list, and delete.""" 186 exe = self.getBuildArtifact("a.out") 187 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 188 189 # Add three breakpoints on the same line. The first time we don't specify the file, 190 # since the default file is the one containing main: 191 lldbutil.run_break_set_by_file_and_line( 192 self, None, self.line, num_expected_locations=1, loc_exact=True 193 ) 194 lldbutil.run_break_set_by_file_and_line( 195 self, "main.c", self.line, num_expected_locations=1, loc_exact=True 196 ) 197 lldbutil.run_break_set_by_file_and_line( 198 self, "main.c", self.line, num_expected_locations=1, loc_exact=True 199 ) 200 # Breakpoint 4 - set at the same location as breakpoint 1 to test 201 # setting breakpoint commands on two breakpoints at a time 202 lldbutil.run_break_set_by_file_and_line( 203 self, None, self.line, num_expected_locations=1, loc_exact=True 204 ) 205 # Make sure relative path source breakpoints work as expected. We test 206 # with partial paths with and without "./" prefixes. 207 lldbutil.run_break_set_by_file_and_line( 208 self, "./main.c", self.line, num_expected_locations=1, loc_exact=True 209 ) 210 lldbutil.run_break_set_by_file_and_line( 211 self, 212 "breakpoint_command/main.c", 213 self.line, 214 num_expected_locations=1, 215 loc_exact=True, 216 ) 217 lldbutil.run_break_set_by_file_and_line( 218 self, 219 "./breakpoint_command/main.c", 220 self.line, 221 num_expected_locations=1, 222 loc_exact=True, 223 ) 224 lldbutil.run_break_set_by_file_and_line( 225 self, 226 "breakpoint/breakpoint_command/main.c", 227 self.line, 228 num_expected_locations=1, 229 loc_exact=True, 230 ) 231 lldbutil.run_break_set_by_file_and_line( 232 self, 233 "./breakpoint/breakpoint_command/main.c", 234 self.line, 235 num_expected_locations=1, 236 loc_exact=True, 237 ) 238 # Test relative breakpoints with incorrect paths and make sure we get 239 # no breakpoint locations 240 lldbutil.run_break_set_by_file_and_line( 241 self, "invalid/main.c", self.line, num_expected_locations=0, loc_exact=True 242 ) 243 lldbutil.run_break_set_by_file_and_line( 244 self, 245 "./invalid/main.c", 246 self.line, 247 num_expected_locations=0, 248 loc_exact=True, 249 ) 250 # Now add callbacks for the breakpoints just created. 251 self.runCmd( 252 "breakpoint command add -s command -o 'frame variable --show-types --scope' 1 4" 253 ) 254 self.runCmd( 255 "breakpoint command add -s python -o 'import side_effect; side_effect.one_liner = \"one liner was here\"' 2" 256 ) 257 258 import side_effect 259 260 self.runCmd("command script import --allow-reload ./bktptcmd.py") 261 262 self.runCmd("breakpoint command add --python-function bktptcmd.function 3") 263 264 # Check that the breakpoint commands are correctly set. 265 266 # The breakpoint list now only contains breakpoint 1. 267 self.expect( 268 "breakpoint list", 269 "Breakpoints 1 & 2 created", 270 substrs=[ 271 "2: file = 'main.c', line = %d, exact_match = 0, locations = 1" 272 % self.line 273 ], 274 patterns=[ 275 "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1" 276 % self.line 277 ], 278 ) 279 280 self.expect( 281 "breakpoint list -f", 282 "Breakpoints 1 & 2 created", 283 substrs=[ 284 "2: file = 'main.c', line = %d, exact_match = 0, locations = 1" 285 % self.line 286 ], 287 patterns=[ 288 "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1" 289 % self.line, 290 "1.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" % self.line, 291 "2.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" % self.line, 292 ], 293 ) 294 295 self.expect( 296 "breakpoint command list 1", 297 "Breakpoint 1 command ok", 298 substrs=["Breakpoint commands:", "frame variable --show-types --scope"], 299 ) 300 self.expect( 301 "breakpoint command list 2", 302 "Breakpoint 2 command ok", 303 substrs=[ 304 "Breakpoint commands (Python):", 305 "import side_effect", 306 "side_effect.one_liner", 307 ], 308 ) 309 self.expect( 310 "breakpoint command list 3", 311 "Breakpoint 3 command ok", 312 substrs=[ 313 "Breakpoint commands (Python):", 314 "bktptcmd.function(frame, bp_loc, internal_dict)", 315 ], 316 ) 317 318 self.expect( 319 "breakpoint command list 4", 320 "Breakpoint 4 command ok", 321 substrs=["Breakpoint commands:", "frame variable --show-types --scope"], 322 ) 323 324 self.runCmd("breakpoint delete 4") 325 326 # Next lets try some other breakpoint kinds. First break with a regular expression 327 # and then specify only one file. The first time we should get two locations, 328 # the second time only one: 329 330 lldbutil.run_break_set_by_regexp( 331 self, r"._MyFunction", num_expected_locations=2 332 ) 333 334 lldbutil.run_break_set_by_regexp( 335 self, r"._MyFunction", extra_options="-f a.c", num_expected_locations=1 336 ) 337 338 lldbutil.run_break_set_by_regexp( 339 self, 340 r"._MyFunction", 341 extra_options="-f a.c -f b.c", 342 num_expected_locations=2, 343 ) 344 345 # Now try a source regex breakpoint: 346 lldbutil.run_break_set_by_source_regexp( 347 self, 348 r"is about to return [12]0", 349 extra_options="-f a.c -f b.c", 350 num_expected_locations=2, 351 ) 352 353 lldbutil.run_break_set_by_source_regexp( 354 self, 355 r"is about to return [12]0", 356 extra_options="-f a.c", 357 num_expected_locations=1, 358 ) 359 360 # Reset our canary variables and run the program. 361 side_effect.one_liner = None 362 side_effect.bktptcmd = None 363 self.runCmd("run", RUN_SUCCEEDED) 364 365 # Check the value of canary variables. 366 self.assertEqual("one liner was here", side_effect.one_liner) 367 self.assertEqual("function was here", side_effect.bktptcmd) 368 369 # Finish the program. 370 self.runCmd("process continue") 371 372 # Remove the breakpoint command associated with breakpoint 1. 373 self.runCmd("breakpoint command delete 1") 374 375 # Remove breakpoint 2. 376 self.runCmd("breakpoint delete 2") 377 378 self.expect( 379 "breakpoint command list 1", 380 startstr="Breakpoint 1 does not have an associated command.", 381 ) 382 self.expect( 383 "breakpoint command list 2", 384 error=True, 385 startstr="error: '2' is not a currently valid breakpoint ID.", 386 ) 387 388 # The breakpoint list now only contains breakpoint 1. 389 self.expect( 390 "breakpoint list -f", 391 "Breakpoint 1 exists", 392 patterns=[ 393 "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1, resolved = 1" 394 % self.line, 395 "hit count = 1", 396 ], 397 ) 398 399 # Not breakpoint 2. 400 self.expect( 401 "breakpoint list -f", 402 "No more breakpoint 2", 403 matching=False, 404 substrs=[ 405 "2: file = 'main.c', line = %d, exact_match = 0, locations = 1, resolved = 1" 406 % self.line 407 ], 408 ) 409 410 # Run the program again, with breakpoint 1 remaining. 411 self.runCmd("run", RUN_SUCCEEDED) 412 413 # We should be stopped again due to breakpoint 1. 414 415 # The stop reason of the thread should be breakpoint. 416 self.expect( 417 "thread list", 418 STOPPED_DUE_TO_BREAKPOINT, 419 substrs=["stopped", "stop reason = breakpoint"], 420 ) 421 422 # The breakpoint should have a hit count of 1, since we reset counts 423 # for each run. 424 lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1) 425 426 def breakpoint_command_script_parameters(self): 427 """Test that the frame and breakpoint location are being properly passed to the script breakpoint command function.""" 428 exe = self.getBuildArtifact("a.out") 429 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 430 431 # Add a breakpoint. 432 lldbutil.run_break_set_by_file_and_line( 433 self, "main.c", self.line, num_expected_locations=1, loc_exact=True 434 ) 435 436 # Now add callbacks for the breakpoints just created. 437 self.runCmd( 438 "breakpoint command add -s python -o 'import side_effect; side_effect.frame = str(frame); side_effect.bp_loc = str(bp_loc)' 1" 439 ) 440 441 # Reset canary variables and run. 442 side_effect.frame = None 443 side_effect.bp_loc = None 444 self.runCmd("run", RUN_SUCCEEDED) 445 446 self.expect(side_effect.frame, exe=False, startstr="frame #0:") 447 self.expect( 448 side_effect.bp_loc, 449 exe=False, 450 patterns=["1.* where = .*main .* resolved,( hardware,)? hit count = 1"], 451 ) 452 453 def breakpoint_commands_on_creation(self): 454 """Test that setting breakpoint commands when creating the breakpoint works""" 455 target = self.createTestTarget() 456 457 # Add a breakpoint. 458 lldbutil.run_break_set_by_file_and_line( 459 self, 460 "main.c", 461 self.line, 462 num_expected_locations=1, 463 loc_exact=True, 464 extra_options='-C bt -C "thread list" -C continue', 465 ) 466 467 bkpt = target.FindBreakpointByID(1) 468 self.assertTrue(bkpt.IsValid(), "Couldn't find breakpoint 1") 469 com_list = lldb.SBStringList() 470 bkpt.GetCommandLineCommands(com_list) 471 self.assertEqual(com_list.GetSize(), 3, "Got the wrong number of commands") 472 self.assertEqual(com_list.GetStringAtIndex(0), "bt", "First bt") 473 self.assertEqual( 474 com_list.GetStringAtIndex(1), "thread list", "Next thread list" 475 ) 476 self.assertEqual(com_list.GetStringAtIndex(2), "continue", "Last continue") 477 478 def test_add_commands_by_breakpoint_name(self): 479 """Make sure that when you specify a breakpoint name to "break command add" 480 it gets added to all the breakpoints marked with that name.""" 481 self.build() 482 target = self.createTestTarget() 483 484 bp_ids = [] 485 bp_names = ["main", "not_here", "main"] 486 for bp_name in bp_names: 487 bp = target.BreakpointCreateByName(bp_name) 488 bp.AddName("MyBKPTS") 489 bp_ids.append(bp.GetID()) 490 # First do it with a script one-liner: 491 self.runCmd("breakpoint command add -s py -o 'print(\"some command\")' MyBKPTS") 492 for id in bp_ids: 493 self.expect( 494 "breakpoint command list {0}".format(id), patterns=["some command"] 495 ) 496 # Now do the same thing with a python function: 497 import side_effect 498 499 self.runCmd("command script import --allow-reload ./bktptcmd.py") 500 501 self.runCmd( 502 "breakpoint command add --python-function bktptcmd.function MyBKPTS" 503 ) 504 for id in bp_ids: 505 self.expect( 506 "breakpoint command list {0}".format(id), patterns=["bktptcmd.function"] 507 ) 508 509 def test_breakpoint_delete_disabled(self): 510 """Test 'break delete --disabled' works""" 511 self.build() 512 target = self.createTestTarget() 513 514 bp_1 = target.BreakpointCreateByName("main") 515 bp_2 = target.BreakpointCreateByName("not_here") 516 bp_3 = target.BreakpointCreateByName("main") 517 bp_3.AddName("DeleteMeNot") 518 519 bp_1.SetEnabled(False) 520 bp_3.SetEnabled(False) 521 522 bp_id_1 = bp_1.GetID() 523 bp_id_2 = bp_2.GetID() 524 bp_id_3 = bp_3.GetID() 525 526 self.runCmd("breakpoint delete --disabled DeleteMeNot") 527 528 bp_1 = target.FindBreakpointByID(bp_id_1) 529 self.assertFalse(bp_1.IsValid(), "Didn't delete disabled breakpoint 1") 530 531 bp_2 = target.FindBreakpointByID(bp_id_2) 532 self.assertTrue(bp_2.IsValid(), "Deleted enabled breakpoint 2") 533 534 bp_3 = target.FindBreakpointByID(bp_id_3) 535 self.assertTrue( 536 bp_3.IsValid(), "DeleteMeNot didn't protect disabled breakpoint 3" 537 ) 538 539 # Reset the first breakpoint, disable it, and do this again with no protected name: 540 bp_1 = target.BreakpointCreateByName("main") 541 542 bp_1.SetEnabled(False) 543 544 bp_id_1 = bp_1.GetID() 545 546 self.runCmd("breakpoint delete --disabled") 547 548 bp_1 = target.FindBreakpointByID(bp_id_1) 549 self.assertFalse(bp_1.IsValid(), "Didn't delete disabled breakpoint 1") 550 551 bp_2 = target.FindBreakpointByID(bp_id_2) 552 self.assertTrue(bp_2.IsValid(), "Deleted enabled breakpoint 2") 553 554 bp_3 = target.FindBreakpointByID(bp_id_3) 555 self.assertFalse(bp_3.IsValid(), "Didn't delete disabled breakpoint 3") 556 557 def get_source_map_json(self): 558 stream = lldb.SBStream() 559 self.dbg.GetSetting("target.source-map").GetAsJSON(stream) 560 return json.loads(stream.GetData()) 561 562 def verify_source_map_entry_pair(self, entry, original, replacement): 563 self.assertEqual( 564 entry[0], original, "source map entry 'original' does not match" 565 ) 566 self.assertEqual( 567 entry[1], replacement, "source map entry 'replacement' does not match" 568 ) 569 570 def verify_source_map_deduce_statistics(self, target, expected_count): 571 stream = lldb.SBStream() 572 res = target.GetStatistics().GetAsJSON(stream) 573 self.assertTrue(res.Success()) 574 debug_stats = json.loads(stream.GetData()) 575 self.assertIn( 576 "targets", 577 debug_stats, 578 'Make sure the "targets" key in in target.GetStatistics()', 579 ) 580 target_stats = debug_stats["targets"][0] 581 self.assertNotEqual(target_stats, None) 582 self.assertEqual(target_stats["sourceMapDeduceCount"], expected_count) 583 584 @no_debug_info_test 585 def test_breakpoints_auto_source_map_relative(self): 586 """ 587 Test that with target.auto-source-map-relative settings. 588 589 The "relative.yaml" contains a line table that is: 590 591 Line table for a/b/c/main.cpp in `a.out 592 0x0000000100003f94: a/b/c/main.cpp:1 593 0x0000000100003fb0: a/b/c/main.cpp:2:3 594 0x0000000100003fb8: a/b/c/main.cpp:2:3 595 """ 596 src_dir = self.getSourceDir() 597 yaml_path = os.path.join(src_dir, "relative.yaml") 598 yaml_base, ext = os.path.splitext(yaml_path) 599 obj_path = self.getBuildArtifact("a.out") 600 self.yaml2obj(yaml_path, obj_path) 601 602 # Create a target with the object file we just created from YAML 603 target = self.dbg.CreateTarget(obj_path) 604 # We now have debug information with line table paths that start are 605 # "./a/b/c/main.cpp". 606 607 source_map_json = self.get_source_map_json() 608 self.assertEqual( 609 len(source_map_json), 0, "source map should be empty initially" 610 ) 611 self.verify_source_map_deduce_statistics(target, 0) 612 613 # Verify auto deduced source map when file path in debug info 614 # is a suffix of request breakpoint file path. 615 # Note the path must be absolute. 616 path = ( 617 "/x/y/a/b/c/main.cpp" 618 if lldbplatformutil.getHostPlatform() != "windows" 619 else r"C:\x\y\a\b\c\main.cpp" 620 ) 621 bp = target.BreakpointCreateByLocation(path, 2) 622 self.assertGreater( 623 bp.GetNumLocations(), 624 0, 625 'Couldn\'t resolve breakpoint using full path "%s" in executate "%s" with ' 626 "debug info that has relative path with matching suffix" 627 % (path, self.getBuildArtifact("a.out")), 628 ) 629 630 source_map_json = self.get_source_map_json() 631 self.assertEqual(len(source_map_json), 1, "source map should not be empty") 632 self.verify_source_map_entry_pair( 633 source_map_json[0], 634 ".", 635 "/x/y" if lldbplatformutil.getHostPlatform() != "windows" else r"C:\x\y", 636 ) 637 self.verify_source_map_deduce_statistics(target, 1) 638 639 # Reset source map. 640 self.runCmd("settings clear target.source-map") 641 642 # Verify source map will not auto deduced when file path of request breakpoint 643 # equals the file path in debug info. 644 path = "a/b/c/main.cpp" 645 bp = target.BreakpointCreateByLocation(path, 2) 646 self.assertGreater( 647 bp.GetNumLocations(), 648 0, 649 'Couldn\'t resolve breakpoint using full path "%s" in executate "%s" with ' 650 "debug info that has relative path with matching suffix" 651 % (path, self.getBuildArtifact("a.out")), 652 ) 653 654 source_map_json = self.get_source_map_json() 655 self.assertEqual(len(source_map_json), 0, "source map should not be deduced") 656 657 def test_breakpoint_statistics_hitcount(self): 658 """Test breakpoints statistics have hitCount field.""" 659 self.build() 660 target = self.createTestTarget() 661 662 lldbutil.run_break_set_by_file_and_line( 663 self, "main.c", self.line, num_expected_locations=1, loc_exact=True 664 ) 665 666 stream = lldb.SBStream() 667 res = target.GetStatistics().GetAsJSON(stream) 668 self.assertTrue(res.Success()) 669 debug_stats = json.loads(stream.GetData()) 670 self.assertIn( 671 "targets", 672 debug_stats, 673 'Make sure the "targets" key in in target.GetStatistics()', 674 ) 675 target_stats = debug_stats["targets"][0] 676 self.assertNotEqual(target_stats, None) 677 678 breakpoints_stats = target_stats["breakpoints"] 679 self.assertNotEqual(breakpoints_stats, None) 680 for breakpoint_stats in breakpoints_stats: 681 self.assertIn("hitCount", breakpoint_stats) 682 683 @skipIf(oslist=no_match(["linux"])) 684 def test_break_at__dl_debug_state(self): 685 """ 686 Test lldb is able to stop at _dl_debug_state if it is set before the 687 process is launched. 688 """ 689 self.build() 690 exe = self.getBuildArtifact("a.out") 691 self.runCmd("target create %s" % exe) 692 bpid = lldbutil.run_break_set_by_symbol( 693 self, "_dl_debug_state", num_expected_locations=-2 694 ) 695 self.runCmd("run") 696 self.assertIsNotNone( 697 lldbutil.get_one_thread_stopped_at_breakpoint_id(self.process(), bpid) 698 ) 699