xref: /llvm-project/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py (revision c954306ef763eb25f06432324889bde98735963d)
101263c6cSJonas Devlieghere"""
201263c6cSJonas DevlieghereTest lldb-dap setBreakpoints request
301263c6cSJonas Devlieghere"""
401263c6cSJonas Devlieghere
501263c6cSJonas Devlieghereimport dap_server
610664813SWalter Erquinigoimport lldbdap_testcase
710664813SWalter Erquinigofrom lldbsuite.test import lldbutil
801263c6cSJonas Devliegherefrom lldbsuite.test.decorators import *
901263c6cSJonas Devliegherefrom lldbsuite.test.lldbtest import *
1001263c6cSJonas Devlieghere
1101263c6cSJonas Devlieghere
12bab10981SMiro Buckodef get_subprocess(root_process, process_name):
13bab10981SMiro Bucko    queue = [root_process]
14ef2ca97fSMiro Bucko    while queue:
15bab10981SMiro Bucko        process = queue.pop()
16ef2ca97fSMiro Bucko        if process.name() == process_name:
17ef2ca97fSMiro Bucko            return process
18ef2ca97fSMiro Bucko        queue.extend(process.children())
19ef2ca97fSMiro Bucko
20ef2ca97fSMiro Bucko    self.assertTrue(False, "No subprocess with name %s found" % process_name)
21ef2ca97fSMiro Bucko
2201263c6cSJonas Devlieghereclass TestDAP_console(lldbdap_testcase.DAPTestCaseBase):
2310664813SWalter Erquinigo    def check_lldb_command(
2410664813SWalter Erquinigo        self, lldb_command, contains_string, assert_msg, command_escape_prefix="`"
2510664813SWalter Erquinigo    ):
2601263c6cSJonas Devlieghere        response = self.dap_server.request_evaluate(
2710664813SWalter Erquinigo            f"{command_escape_prefix}{lldb_command}", context="repl"
2801263c6cSJonas Devlieghere        )
2901263c6cSJonas Devlieghere        output = response["body"]["result"]
3001263c6cSJonas Devlieghere        self.assertIn(
3101263c6cSJonas Devlieghere            contains_string,
3201263c6cSJonas Devlieghere            output,
3301263c6cSJonas Devlieghere            (
3401263c6cSJonas Devlieghere                """Verify %s by checking the command output:\n"""
3501263c6cSJonas Devlieghere                """'''\n%s'''\nfor the string: "%s" """
3601263c6cSJonas Devlieghere                % (assert_msg, output, contains_string)
3701263c6cSJonas Devlieghere            ),
3801263c6cSJonas Devlieghere        )
3901263c6cSJonas Devlieghere
4001263c6cSJonas Devlieghere    def test_scopes_variables_setVariable_evaluate(self):
4101263c6cSJonas Devlieghere        """
4201263c6cSJonas Devlieghere        Tests that the "scopes" request causes the currently selected
4301263c6cSJonas Devlieghere        thread and frame to be updated. There are no DAP packets that tell
4401263c6cSJonas Devlieghere        lldb-dap which thread and frame are selected other than the
4501263c6cSJonas Devlieghere        "scopes" request. lldb-dap will now select the thread and frame
4601263c6cSJonas Devlieghere        for the latest "scopes" request that it receives.
4701263c6cSJonas Devlieghere
4801263c6cSJonas Devlieghere        The LLDB command interpreter needs to have the right thread and
4901263c6cSJonas Devlieghere        frame selected so that commands executed in the debug console act
5001263c6cSJonas Devlieghere        on the right scope. This applies both to the expressions that are
5101263c6cSJonas Devlieghere        evaluated and the lldb commands that start with the backtick
5201263c6cSJonas Devlieghere        character.
5301263c6cSJonas Devlieghere        """
5401263c6cSJonas Devlieghere        program = self.getBuildArtifact("a.out")
5501263c6cSJonas Devlieghere        self.build_and_launch(program)
5601263c6cSJonas Devlieghere        source = "main.cpp"
5701263c6cSJonas Devlieghere        breakpoint1_line = line_number(source, "// breakpoint 1")
5801263c6cSJonas Devlieghere        lines = [breakpoint1_line]
5901263c6cSJonas Devlieghere        # Set breakpoint in the thread function so we can step the threads
6001263c6cSJonas Devlieghere        breakpoint_ids = self.set_source_breakpoints(source, lines)
6101263c6cSJonas Devlieghere        self.assertEqual(
6201263c6cSJonas Devlieghere            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
6301263c6cSJonas Devlieghere        )
6401263c6cSJonas Devlieghere        self.continue_to_breakpoints(breakpoint_ids)
6501263c6cSJonas Devlieghere        # Cause a "scopes" to be sent for frame zero which should update the
6601263c6cSJonas Devlieghere        # selected thread and frame to frame 0.
6701263c6cSJonas Devlieghere        self.dap_server.get_local_variables(frameIndex=0)
6801263c6cSJonas Devlieghere        # Verify frame #0 is selected in the command interpreter by running
6901263c6cSJonas Devlieghere        # the "frame select" command with no frame index which will print the
7001263c6cSJonas Devlieghere        # currently selected frame.
7101263c6cSJonas Devlieghere        self.check_lldb_command("frame select", "frame #0", "frame 0 is selected")
7201263c6cSJonas Devlieghere
7301263c6cSJonas Devlieghere        # Cause a "scopes" to be sent for frame one which should update the
7401263c6cSJonas Devlieghere        # selected thread and frame to frame 1.
7501263c6cSJonas Devlieghere        self.dap_server.get_local_variables(frameIndex=1)
7601263c6cSJonas Devlieghere        # Verify frame #1 is selected in the command interpreter by running
7701263c6cSJonas Devlieghere        # the "frame select" command with no frame index which will print the
7801263c6cSJonas Devlieghere        # currently selected frame.
7901263c6cSJonas Devlieghere
8001263c6cSJonas Devlieghere        self.check_lldb_command("frame select", "frame #1", "frame 1 is selected")
8110664813SWalter Erquinigo
8210664813SWalter Erquinigo    def test_custom_escape_prefix(self):
8310664813SWalter Erquinigo        program = self.getBuildArtifact("a.out")
8410664813SWalter Erquinigo        self.build_and_launch(program, commandEscapePrefix="::")
8510664813SWalter Erquinigo        source = "main.cpp"
8610664813SWalter Erquinigo        breakpoint1_line = line_number(source, "// breakpoint 1")
8710664813SWalter Erquinigo        breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line])
8810664813SWalter Erquinigo        self.continue_to_breakpoints(breakpoint_ids)
8910664813SWalter Erquinigo
9010664813SWalter Erquinigo        self.check_lldb_command(
9110664813SWalter Erquinigo            "help",
9210664813SWalter Erquinigo            "For more information on any command",
9310664813SWalter Erquinigo            "Help can be invoked",
9410664813SWalter Erquinigo            command_escape_prefix="::",
9510664813SWalter Erquinigo        )
9610664813SWalter Erquinigo
9710664813SWalter Erquinigo    def test_empty_escape_prefix(self):
9810664813SWalter Erquinigo        program = self.getBuildArtifact("a.out")
9910664813SWalter Erquinigo        self.build_and_launch(program, commandEscapePrefix="")
10010664813SWalter Erquinigo        source = "main.cpp"
10110664813SWalter Erquinigo        breakpoint1_line = line_number(source, "// breakpoint 1")
10210664813SWalter Erquinigo        breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line])
10310664813SWalter Erquinigo        self.continue_to_breakpoints(breakpoint_ids)
10410664813SWalter Erquinigo
10510664813SWalter Erquinigo        self.check_lldb_command(
10610664813SWalter Erquinigo            "help",
10710664813SWalter Erquinigo            "For more information on any command",
10810664813SWalter Erquinigo            "Help can be invoked",
10910664813SWalter Erquinigo            command_escape_prefix="",
11010664813SWalter Erquinigo        )
111ef2ca97fSMiro Bucko
112ef2ca97fSMiro Bucko    @skipIfWindows
113ef2ca97fSMiro Bucko    def test_exit_status_message_sigterm(self):
114ef2ca97fSMiro Bucko        source = "main.cpp"
115ef2ca97fSMiro Bucko        program = self.getBuildArtifact("a.out")
116ef2ca97fSMiro Bucko        self.build_and_launch(program, commandEscapePrefix="")
117ef2ca97fSMiro Bucko        breakpoint1_line = line_number(source, "// breakpoint 1")
118ef2ca97fSMiro Bucko        breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line])
119ef2ca97fSMiro Bucko        self.continue_to_breakpoints(breakpoint_ids)
120ef2ca97fSMiro Bucko
121ef2ca97fSMiro Bucko        # Kill lldb-server process.
122ef2ca97fSMiro Bucko        process_name = (
123ef2ca97fSMiro Bucko            "debugserver" if platform.system() in ["Darwin"] else "lldb-server"
124ef2ca97fSMiro Bucko        )
125bab10981SMiro Bucko
126bab10981SMiro Bucko        try:
127bab10981SMiro Bucko            import psutil
128bab10981SMiro Bucko        except ImportError:
129bab10981SMiro Bucko            print(
130bab10981SMiro Bucko                "psutil not installed, please install using 'pip install psutil'. "
131bab10981SMiro Bucko                "Skipping test_exit_status_message_sigterm test.",
132bab10981SMiro Bucko                file=sys.stderr,
133bab10981SMiro Bucko            )
134bab10981SMiro Bucko            return
135bab10981SMiro Bucko        process = get_subprocess(psutil.Process(os.getpid()), process_name)
136ef2ca97fSMiro Bucko        process.terminate()
137ef2ca97fSMiro Bucko        process.wait()
138ef2ca97fSMiro Bucko
139ef2ca97fSMiro Bucko        # Get the console output
140*11a4d43fSMiro Bucko        console_output = self.collect_console(
141*11a4d43fSMiro Bucko            timeout_secs=10.0, pattern="exited with status"
142*11a4d43fSMiro Bucko        )
143ef2ca97fSMiro Bucko
144ef2ca97fSMiro Bucko        # Verify the exit status message is printed.
145ef2ca97fSMiro Bucko        self.assertIn(
146ef2ca97fSMiro Bucko            "exited with status = -1 (0xffffffff) debugserver died with signal SIGTERM",
147ef2ca97fSMiro Bucko            console_output,
148ef2ca97fSMiro Bucko            "Exit status does not contain message 'exited with status'",
149ef2ca97fSMiro Bucko        )
150ef2ca97fSMiro Bucko
151ef2ca97fSMiro Bucko    def test_exit_status_message_ok(self):
152ef2ca97fSMiro Bucko        program = self.getBuildArtifact("a.out")
153ef2ca97fSMiro Bucko        self.build_and_launch(program, commandEscapePrefix="")
154ef2ca97fSMiro Bucko        self.continue_to_exit()
155ef2ca97fSMiro Bucko
156ef2ca97fSMiro Bucko        # Get the console output
157*11a4d43fSMiro Bucko        console_output = self.collect_console(
158*11a4d43fSMiro Bucko            timeout_secs=10.0, pattern="exited with status"
159*11a4d43fSMiro Bucko        )
160ef2ca97fSMiro Bucko
161ef2ca97fSMiro Bucko        # Verify the exit status message is printed.
162ef2ca97fSMiro Bucko        self.assertIn(
163ef2ca97fSMiro Bucko            "exited with status = 0 (0x00000000)",
164ef2ca97fSMiro Bucko            console_output,
165ef2ca97fSMiro Bucko            "Exit status does not contain message 'exited with status'",
166ef2ca97fSMiro Bucko        )
167