brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.6 KiB · 605561c Raw
699 lines · python
1"""2Test lldb breakpoint command add/list/delete.3"""4 5 6import lldb7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil, lldbplatformutil10import json11import os12import side_effect13 14 15class BreakpointCommandTestCase(TestBase):16    NO_DEBUG_INFO_TESTCASE = True17 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_test36    def test_breakpoints_with_relative_path_line_tables(self):37        """38        Test that we can set breakpoints using a full or partial path when39        line tables in the debug information has relative paths where the40        relative path is either fully contained in the specified path, or if41        the specified path also a relative path that is shorter than the42        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.out47        0x0000000100003f94: a/b/c/main.cpp:148        0x0000000100003fb0: a/b/c/main.cpp:2:349        0x0000000100003fb8: a/b/c/main.cpp:2:350 51        So the line table contains relative paths. We should be able to set52        breakpoints with any source path that matches this path which53        includes paths that are longer than "a/b/c/main.cpp", but also any54        relative path that is shorter than this while all specified relative55        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 YAML64        target = self.dbg.CreateTarget(obj_path)65        # We now have debug information with line table paths that start are66        # "./a/b/c/main.cpp".67 68        # Make sure that all of the following paths create a breakpoint69        # successfully. We have paths that are longer than our path, and also70        # 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_test114    def test_breakpoints_with_bad_aranges(self):115        """116        Test that we can set breakpoints in a file that has an invalid117        .debug_aranges. Older versions of LLDB would find a line entry118        in the line table and then would use the start address of the line119        entry to do an address lookup on the entry from the line table. If120        this address to symbol context lookup would fail, due to a bad121        .debug_aranges, it would cause the breakpoint to not get resolved.122        Verify that even in these conditions we are able to resolve a123        breakpoint.124 125        The "bad_aranges.yaml" contains a line table that is:126 127        Line table for /tmp/ab/main.cpp in `a.out128        0x0000000100003f94: /tmp/ab/main.cpp:1129        0x0000000100003fb0: /tmp/ab/main.cpp:2:3130        0x0000000100003fb8: /tmp/ab/main.cpp:2:3131 132        The .debug_aranges has one range for this compile unit that is133        invalid: [0x0000000200003f94-0x0000000200003fb8). This will cause134        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 YAML143        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?" prompt160        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=True172        )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=True193        )194        lldbutil.run_break_set_by_file_and_line(195            self, "main.c", self.line, num_expected_locations=1, loc_exact=True196        )197        lldbutil.run_break_set_by_file_and_line(198            self, "main.c", self.line, num_expected_locations=1, loc_exact=True199        )200        # Breakpoint 4 - set at the same location as breakpoint 1 to test201        # setting breakpoint commands on two breakpoints at a time202        lldbutil.run_break_set_by_file_and_line(203            self, None, self.line, num_expected_locations=1, loc_exact=True204        )205        # Make sure relative path source breakpoints work as expected. We test206        # 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=True209        )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 get239        # no breakpoint locations240        lldbutil.run_break_set_by_file_and_line(241            self, "invalid/main.c", self.line, num_expected_locations=0, loc_exact=True242        )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_effect259 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.line273            ],274            patterns=[275                "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1"276                % self.line277            ],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.line286            ],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 expression327        # 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=2332        )333 334        lldbutil.run_break_set_by_regexp(335            self, r"._MyFunction", extra_options="-f a.c", num_expected_locations=1336        )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 = None362        side_effect.bktptcmd = None363        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.line407            ],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 counts423        # 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=True434        )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 = None443        side_effect.bp_loc = None444        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_effect498 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_test585    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.out592        0x0000000100003f94: a/b/c/main.cpp:1593        0x0000000100003fb0: a/b/c/main.cpp:2:3594        0x0000000100003fb8: a/b/c/main.cpp:2:3595        """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 YAML603        target = self.dbg.CreateTarget(obj_path)604        # We now have debug information with line table paths that start are605        # "./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 info614        # 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 breakpoint643        # 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=True664        )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 the687        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=-2694        )695        self.runCmd("run")696        self.assertIsNotNone(697            lldbutil.get_one_thread_stopped_at_breakpoint_id(self.process(), bpid)698        )699