brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.1 KiB · 3309800 Raw
435 lines · python
1"""2Test lldb-dap setBreakpoints request3"""4 5from dap_server import Source6import shutil7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil10import lldbdap_testcase11import os12 13 14class TestDAP_setBreakpoints(lldbdap_testcase.DAPTestCaseBase):15    def setUp(self):16        lldbdap_testcase.DAPTestCaseBase.setUp(self)17 18        self.main_basename = "main-copy.cpp"19        self.main_path = os.path.realpath(self.getBuildArtifact(self.main_basename))20 21    @skipIfWindows22    def test_source_map(self):23        """24        This test simulates building two files in a folder, and then moving25        each source to a different folder. Then, the debug session is started26        with the corresponding source maps to have breakpoints and frames27        working.28        """29        self.build_and_create_debug_adapter()30 31        other_basename = "other-copy.c"32        other_path = self.getBuildArtifact(other_basename)33 34        source_folder = os.path.dirname(self.main_path)35 36        new_main_folder = os.path.join(source_folder, "moved_main")37        new_other_folder = os.path.join(source_folder, "moved_other")38 39        new_main_path = os.path.join(new_main_folder, self.main_basename)40        new_other_path = os.path.join(new_other_folder, other_basename)41 42        # move the sources43        os.mkdir(new_main_folder)44        os.mkdir(new_other_folder)45        shutil.move(self.main_path, new_main_path)46        shutil.move(other_path, new_other_path)47 48        main_line = line_number("main.cpp", "break 12")49        other_line = line_number("other.c", "break other")50 51        program = self.getBuildArtifact("a.out")52        source_map = [53            [source_folder, new_main_folder],54            [source_folder, new_other_folder],55        ]56        self.launch(program, sourceMap=source_map)57 58        # breakpoint in main.cpp59        response = self.dap_server.request_setBreakpoints(60            Source.build(path=new_main_path), [main_line]61        )62        breakpoints = response["body"]["breakpoints"]63        self.assertEqual(len(breakpoints), 1)64        breakpoint = breakpoints[0]65        self.assertEqual(breakpoint["line"], main_line)66        self.assertTrue(breakpoint["verified"])67        self.assertEqual(self.main_basename, breakpoint["source"]["name"])68        self.assertEqual(new_main_path, breakpoint["source"]["path"])69 70        # 2nd breakpoint, which is from a dynamically loaded library71        response = self.dap_server.request_setBreakpoints(72            Source.build(path=new_other_path), [other_line]73        )74        breakpoints = response["body"]["breakpoints"]75        breakpoint = breakpoints[0]76        self.assertEqual(breakpoint["line"], other_line)77        self.assertFalse(breakpoint["verified"])78        self.assertEqual(other_basename, breakpoint["source"]["name"])79        self.assertEqual(new_other_path, breakpoint["source"]["path"])80        other_breakpoint_id = breakpoint["id"]81 82        self.dap_server.request_continue()83        self.verify_breakpoint_hit([other_breakpoint_id])84 85        # 2nd breakpoint again, which should be valid at this point86        response = self.dap_server.request_setBreakpoints(87            Source.build(path=new_other_path), [other_line]88        )89        breakpoints = response["body"]["breakpoints"]90        breakpoint = breakpoints[0]91        self.assertEqual(breakpoint["line"], other_line)92        self.assertTrue(breakpoint["verified"])93        self.assertEqual(other_basename, breakpoint["source"]["name"])94        self.assertEqual(new_other_path, breakpoint["source"]["path"])95 96        # now we check the stack trace making sure that we got mapped source paths97        frames = self.dap_server.request_stackTrace()["body"]["stackFrames"]98 99        self.assertEqual(frames[0]["source"]["name"], other_basename)100        self.assertEqual(frames[0]["source"]["path"], new_other_path)101 102        self.assertEqual(frames[1]["source"]["name"], self.main_basename)103        self.assertEqual(frames[1]["source"]["path"], new_main_path)104 105    @skipIfWindows106    def test_set_and_clear(self):107        """Tests setting and clearing source file and line breakpoints.108        This packet is a bit tricky on the debug adapter side since there109        is no "clearBreakpoints" packet. Source file and line breakpoints110        are set by sending a "setBreakpoints" packet with a source file111        specified and zero or more source lines. If breakpoints have been112        set in the source file before, any existing breakpoints must remain113        set, and any new breakpoints must be created, and any breakpoints114        that were in previous requests and are not in the current request115        must be removed. This function tests this setting and clearing116        and makes sure things happen correctly. It doesn't test hitting117        breakpoints and the functionality of each breakpoint, like118        'conditions' and 'hitCondition' settings."""119        first_line = line_number("main.cpp", "break 12")120        second_line = line_number("main.cpp", "break 13")121        third_line = line_number("main.cpp", "break 14")122        lines = [first_line, third_line, second_line]123 124        # Visual Studio Code Debug Adapters have no way to specify the file125        # without launching or attaching to a process, so we must start a126        # process in order to be able to set breakpoints.127        program = self.getBuildArtifact("a.out")128        self.build_and_launch(program)129 130        # Set 3 breakpoints and verify that they got set correctly131        response = self.dap_server.request_setBreakpoints(132            Source.build(path=self.main_path), lines133        )134        line_to_id = {}135        breakpoints = response["body"]["breakpoints"]136        self.assertEqual(137            len(breakpoints),138            len(lines),139            "expect %u source breakpoints" % (len(lines)),140        )141        for index, breakpoint in enumerate(breakpoints):142            line = breakpoint["line"]143            self.assertEqual(line, lines[index])144            # Store the "id" of the breakpoint that was set for later145            line_to_id[line] = breakpoint["id"]146            self.assertTrue(breakpoint["verified"], "expect breakpoint verified")147 148        # There is no breakpoint delete packet, clients just send another149        # setBreakpoints packet with the same source file with fewer lines.150        # Below we remove the second line entry and call the setBreakpoints151        # function again. We want to verify that any breakpoints that were set152        # before still have the same "id". This means we didn't clear the153        # breakpoint and set it again at the same location. We also need to154        # verify that the second line location was actually removed.155        lines.remove(second_line)156        # Set 2 breakpoints and verify that the previous breakpoints that were157        # set above are still set.158        response = self.dap_server.request_setBreakpoints(159            Source.build(path=self.main_path), lines160        )161        breakpoints = response["body"]["breakpoints"]162        self.assertEqual(163            len(breakpoints),164            len(lines),165            "expect %u source breakpoints" % (len(lines)),166        )167        for index, breakpoint in enumerate(breakpoints):168            line = breakpoint["line"]169            self.assertEqual(line, lines[index])170            # Verify the same breakpoints are still set within LLDB by171            # making sure the breakpoint ID didn't change172            self.assertEqual(173                line_to_id[line],174                breakpoint["id"],175                "verify previous breakpoints stayed the same",176            )177            self.assertTrue(breakpoint["verified"], "expect breakpoint still verified")178 179        # Now get the full list of breakpoints set in the target and verify180        # we have only 2 breakpoints set. The response above could have told181        # us about 2 breakpoints, but we want to make sure we don't have the182        # third one still set in the target183        response = self.dap_server.request_testGetTargetBreakpoints()184        breakpoints = response["body"]["breakpoints"]185        self.assertEqual(186            len(breakpoints),187            len(lines),188            "expect %u source breakpoints" % (len(lines)),189        )190        for breakpoint in breakpoints:191            line = breakpoint["line"]192            # Verify the same breakpoints are still set within LLDB by193            # making sure the breakpoint ID didn't change194            self.assertEqual(195                line_to_id[line],196                breakpoint["id"],197                "verify previous breakpoints stayed the same",198            )199            self.assertIn(line, lines, "line expected in lines array")200            self.assertTrue(breakpoint["verified"], "expect breakpoint still verified")201 202        # Now clear all breakpoints for the source file by passing down an203        # empty lines array204        lines = []205        response = self.dap_server.request_setBreakpoints(206            Source.build(path=self.main_path), lines207        )208        breakpoints = response["body"]["breakpoints"]209        self.assertEqual(210            len(breakpoints),211            len(lines),212            "expect %u source breakpoints" % (len(lines)),213        )214 215        # Verify with the target that all breakpoints have been cleared216        response = self.dap_server.request_testGetTargetBreakpoints()217        breakpoints = response["body"]["breakpoints"]218        self.assertEqual(219            len(breakpoints),220            len(lines),221            "expect %u source breakpoints" % (len(lines)),222        )223 224        # Now set a breakpoint again in the same source file and verify it225        # was added.226        lines = [second_line]227        response = self.dap_server.request_setBreakpoints(228            Source.build(path=self.main_path), lines229        )230        if response:231            breakpoints = response["body"]["breakpoints"]232            self.assertEqual(233                len(breakpoints),234                len(lines),235                "expect %u source breakpoints" % (len(lines)),236            )237            for breakpoint in breakpoints:238                line = breakpoint["line"]239                self.assertIn(line, lines, "line expected in lines array")240                self.assertTrue(241                    breakpoint["verified"], "expect breakpoint still verified"242                )243 244        # Now get the full list of breakpoints set in the target and verify245        # we have only 2 breakpoints set. The response above could have told246        # us about 2 breakpoints, but we want to make sure we don't have the247        # third one still set in the target248        response = self.dap_server.request_testGetTargetBreakpoints()249        if response:250            breakpoints = response["body"]["breakpoints"]251            self.assertEqual(252                len(breakpoints),253                len(lines),254                "expect %u source breakpoints" % (len(lines)),255            )256            for breakpoint in breakpoints:257                line = breakpoint["line"]258                self.assertIn(line, lines, "line expected in lines array")259                self.assertTrue(260                    breakpoint["verified"], "expect breakpoint still verified"261                )262 263    @skipIfWindows264    def test_clear_breakpoints_unset_breakpoints(self):265        """Test clearing breakpoints like test_set_and_clear, but clear266        breakpoints by omitting the breakpoints array instead of sending an267        empty one."""268        lines = [269            line_number("main.cpp", "break 12"),270            line_number("main.cpp", "break 13"),271        ]272 273        # Visual Studio Code Debug Adapters have no way to specify the file274        # without launching or attaching to a process, so we must start a275        # process in order to be able to set breakpoints.276        program = self.getBuildArtifact("a.out")277        self.build_and_launch(program)278 279        # Set one breakpoint and verify that it got set correctly.280        response = self.dap_server.request_setBreakpoints(281            Source.build(path=self.main_path), lines282        )283        line_to_id = {}284        breakpoints = response["body"]["breakpoints"]285        self.assertEqual(286            len(breakpoints), len(lines), "expect %u source breakpoints" % (len(lines))287        )288        for index, breakpoint in enumerate(breakpoints):289            line = breakpoint["line"]290            self.assertEqual(line, lines[index])291            # Store the "id" of the breakpoint that was set for later292            line_to_id[line] = breakpoint["id"]293            self.assertTrue(breakpoint["verified"], "expect breakpoint verified")294 295        # Now clear all breakpoints for the source file by not setting the296        # lines array.297        lines = None298        response = self.dap_server.request_setBreakpoints(299            Source.build(path=self.main_path), lines300        )301        breakpoints = response["body"]["breakpoints"]302        self.assertEqual(len(breakpoints), 0, "expect no source breakpoints")303 304        # Verify with the target that all breakpoints have been cleared.305        response = self.dap_server.request_testGetTargetBreakpoints()306        breakpoints = response["body"]["breakpoints"]307        self.assertEqual(len(breakpoints), 0, "expect no source breakpoints")308 309    @skipIfWindows310    def test_functionality(self):311        """Tests hitting breakpoints and the functionality of a single312        breakpoint, like 'conditions' and 'hitCondition' settings."""313        loop_line = line_number("main.cpp", "// break loop")314 315        program = self.getBuildArtifact("a.out")316        self.build_and_launch(program)317        # Set a breakpoint at the loop line with no condition and no318        # hitCondition319        breakpoint_ids = self.set_source_breakpoints(self.main_path, [loop_line])320        self.assertEqual(len(breakpoint_ids), 1, "expect one breakpoint")321        self.dap_server.request_continue()322 323        # Verify we hit the breakpoint we just set324        self.verify_breakpoint_hit(breakpoint_ids)325 326        # Make sure i is zero at first breakpoint327        i = int(self.dap_server.get_local_variable_value("i"))328        self.assertEqual(i, 0, "i != 0 after hitting breakpoint")329 330        # Update the condition on our breakpoint331        new_breakpoint_ids = self.set_source_breakpoints(332            self.main_path, [loop_line], [{"condition": "i==4"}]333        )334        self.assertEqual(335            breakpoint_ids,336            new_breakpoint_ids,337            "existing breakpoint should have its condition " "updated",338        )339 340        self.continue_to_breakpoints(breakpoint_ids)341        i = int(self.dap_server.get_local_variable_value("i"))342        self.assertEqual(i, 4, "i != 4 showing conditional works")343 344        new_breakpoint_ids = self.set_source_breakpoints(345            self.main_path, [loop_line], [{"hitCondition": "2"}]346        )347 348        self.assertEqual(349            breakpoint_ids,350            new_breakpoint_ids,351            "existing breakpoint should have its condition " "updated",352        )353 354        # Continue with a hitCondition of 2 and expect it to skip 1 value355        self.continue_to_breakpoints(breakpoint_ids)356        i = int(self.dap_server.get_local_variable_value("i"))357        self.assertEqual(i, 6, "i != 6 showing hitCondition works")358 359        # continue after hitting our hitCondition and make sure it only goes360        # up by 1361        self.continue_to_breakpoints(breakpoint_ids)362        i = int(self.dap_server.get_local_variable_value("i"))363        self.assertEqual(i, 7, "i != 7 showing post hitCondition hits every time")364 365    @skipIfWindows366    def test_column_breakpoints(self):367        """Test setting multiple breakpoints in the same line at different columns."""368        loop_line = line_number("main.cpp", "// break loop")369 370        program = self.getBuildArtifact("a.out")371        self.build_and_launch(program)372 373        # Set two breakpoints on the loop line at different columns.374        columns = [13, 39]375        response = self.dap_server.request_setBreakpoints(376            Source.build(path=self.main_path),377            [loop_line, loop_line],378            list({"column": c} for c in columns),379        )380 381        # Verify the breakpoints were set correctly382        breakpoints = response["body"]["breakpoints"]383        breakpoint_ids = []384        self.assertEqual(385            len(breakpoints),386            len(columns),387            "expect %u source breakpoints" % (len(columns)),388        )389        for index, breakpoint in enumerate(breakpoints):390            self.assertEqual(breakpoint["line"], loop_line)391            self.assertEqual(breakpoint["column"], columns[index])392            self.assertTrue(breakpoint["verified"], "expect breakpoint verified")393            breakpoint_ids.append(breakpoint["id"])394 395        # Continue to the first breakpoint,396        self.continue_to_breakpoints([breakpoint_ids[0]])397 398        # We should have stopped right before the call to `twelve`.399        # Step into and check we are inside `twelve`.400        self.stepIn()401        func_name = self.get_stackFrames()[0]["name"]402        self.assertEqual(func_name, "twelve(int)")403 404        # Continue to the second breakpoint.405        self.continue_to_breakpoints([breakpoint_ids[1]])406 407        # We should have stopped right before the call to `fourteen`.408        # Step into and check we are inside `fourteen`.409        self.stepIn()410        func_name = self.get_stackFrames()[0]["name"]411        self.assertEqual(func_name, "a::fourteen(int)")412 413    @skipIfWindows414    def test_hit_multiple_breakpoints(self):415        """Test that if we hit multiple breakpoints at the same address, they416        all appear in the stop reason."""417        breakpoint_lines = [418            line_number("main.cpp", "// break non-breakpointable line"),419            line_number("main.cpp", "// before loop"),420        ]421 422        program = self.getBuildArtifact("a.out")423        self.build_and_launch(program)424 425        # Set a pair of breakpoints that will both resolve to the same address.426        breakpoint_ids = [427            int(bp_id)428            for bp_id in self.set_source_breakpoints(self.main_path, breakpoint_lines)429        ]430        self.assertEqual(len(breakpoint_ids), 2, "expected two breakpoints")431        self.dap_server.request_continue()432        print(breakpoint_ids)433        # Verify we hit both of the breakpoints we just set434        self.verify_all_breakpoints_hit(breakpoint_ids)435