199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest lldb-vscode setBreakpoints request
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprecht
699451b44SJordan Rupprechtimport unittest2
799451b44SJordan Rupprechtimport vscode
899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1099451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1199451b44SJordan Rupprechtimport lldbvscode_testcase
1299451b44SJordan Rupprechtimport os
1399451b44SJordan Rupprechtimport shutil
1499451b44SJordan Rupprechtimport subprocess
1599451b44SJordan Rupprechtimport tempfile
1699451b44SJordan Rupprechtimport threading
1799451b44SJordan Rupprechtimport time
1899451b44SJordan Rupprecht
1999451b44SJordan Rupprecht
2099451b44SJordan Rupprechtdef spawn_and_wait(program, delay):
2199451b44SJordan Rupprecht    if delay:
2299451b44SJordan Rupprecht        time.sleep(delay)
2399451b44SJordan Rupprecht    process = subprocess.Popen([program],
2499451b44SJordan Rupprecht                               stdin=subprocess.PIPE,
2599451b44SJordan Rupprecht                               stdout=subprocess.PIPE,
2699451b44SJordan Rupprecht                               stderr=subprocess.PIPE)
2799451b44SJordan Rupprecht    process.wait()
2899451b44SJordan Rupprecht
2999451b44SJordan Rupprecht
3099451b44SJordan Rupprechtclass TestVSCode_attach(lldbvscode_testcase.VSCodeTestCaseBase):
3199451b44SJordan Rupprecht
3299451b44SJordan Rupprecht    def set_and_hit_breakpoint(self, continueToExit=True):
3399451b44SJordan Rupprecht        source = 'main.c'
3499451b44SJordan Rupprecht        breakpoint1_line = line_number(source, '// breakpoint 1')
3599451b44SJordan Rupprecht        lines = [breakpoint1_line]
36e9264b74SKazuaki Ishizaki        # Set breakpoint in the thread function so we can step the threads
3799451b44SJordan Rupprecht        breakpoint_ids = self.set_source_breakpoints(source, lines)
3899451b44SJordan Rupprecht        self.assertEqual(len(breakpoint_ids), len(lines),
3999451b44SJordan Rupprecht                         "expect correct number of breakpoints")
4099451b44SJordan Rupprecht        self.continue_to_breakpoints(breakpoint_ids)
4199451b44SJordan Rupprecht        if continueToExit:
4299451b44SJordan Rupprecht            self.continue_to_exit()
4399451b44SJordan Rupprecht
4499451b44SJordan Rupprecht    @skipIfWindows
4599451b44SJordan Rupprecht    @skipIfNetBSD # Hangs on NetBSD as well
4614fb3179SJonas Devlieghere    @skipIfRemote
4799451b44SJordan Rupprecht    def test_by_pid(self):
4899451b44SJordan Rupprecht        '''
4999451b44SJordan Rupprecht            Tests attaching to a process by process ID.
5099451b44SJordan Rupprecht        '''
5199451b44SJordan Rupprecht        self.build_and_create_debug_adaptor()
5299451b44SJordan Rupprecht        program = self.getBuildArtifact("a.out")
5399451b44SJordan Rupprecht        self.process = subprocess.Popen([program],
5499451b44SJordan Rupprecht                                        stdin=subprocess.PIPE,
5599451b44SJordan Rupprecht                                        stdout=subprocess.PIPE,
5699451b44SJordan Rupprecht                                        stderr=subprocess.PIPE)
5799451b44SJordan Rupprecht        self.attach(pid=self.process.pid)
5899451b44SJordan Rupprecht        self.set_and_hit_breakpoint(continueToExit=True)
5999451b44SJordan Rupprecht
6099451b44SJordan Rupprecht    @skipIfWindows
6199451b44SJordan Rupprecht    @skipIfNetBSD # Hangs on NetBSD as well
6214fb3179SJonas Devlieghere    @skipIfRemote
6399451b44SJordan Rupprecht    def test_by_name(self):
6499451b44SJordan Rupprecht        '''
6599451b44SJordan Rupprecht            Tests attaching to a process by process name.
6699451b44SJordan Rupprecht        '''
6799451b44SJordan Rupprecht        self.build_and_create_debug_adaptor()
6899451b44SJordan Rupprecht        orig_program = self.getBuildArtifact("a.out")
6999451b44SJordan Rupprecht        # Since we are going to attach by process name, we need a unique
7099451b44SJordan Rupprecht        # process name that has minimal chance to match a process that is
7199451b44SJordan Rupprecht        # already running. To do this we use tempfile.mktemp() to give us a
7299451b44SJordan Rupprecht        # full path to a location where we can copy our executable. We then
7399451b44SJordan Rupprecht        # run this copy to ensure we don't get the error "more that one
7499451b44SJordan Rupprecht        # process matches 'a.out'".
7599451b44SJordan Rupprecht        program = tempfile.mktemp()
7699451b44SJordan Rupprecht        shutil.copyfile(orig_program, program)
7799451b44SJordan Rupprecht        shutil.copymode(orig_program, program)
7899451b44SJordan Rupprecht
7999451b44SJordan Rupprecht        # Use a file as a synchronization point between test and inferior.
8099451b44SJordan Rupprecht        pid_file_path = lldbutil.append_to_process_working_directory(self,
8199451b44SJordan Rupprecht            "pid_file_%d" % (int(time.time())))
8299451b44SJordan Rupprecht
8399451b44SJordan Rupprecht        def cleanup():
8499451b44SJordan Rupprecht            if os.path.exists(program):
8599451b44SJordan Rupprecht                os.unlink(program)
8699451b44SJordan Rupprecht            self.run_platform_command("rm %s" % (pid_file_path))
8799451b44SJordan Rupprecht        # Execute the cleanup function during test case tear down.
8899451b44SJordan Rupprecht        self.addTearDownHook(cleanup)
8999451b44SJordan Rupprecht
9099451b44SJordan Rupprecht        popen = self.spawnSubprocess(program, [pid_file_path])
9199451b44SJordan Rupprecht
9299451b44SJordan Rupprecht        pid = lldbutil.wait_for_file_on_target(self, pid_file_path)
9399451b44SJordan Rupprecht
9499451b44SJordan Rupprecht        self.attach(program=program)
9599451b44SJordan Rupprecht        self.set_and_hit_breakpoint(continueToExit=True)
9699451b44SJordan Rupprecht
9799451b44SJordan Rupprecht    @skipUnlessDarwin
9899451b44SJordan Rupprecht    @skipIfDarwin
9999451b44SJordan Rupprecht    @skipIfNetBSD # Hangs on NetBSD as well
10099451b44SJordan Rupprecht    def test_by_name_waitFor(self):
10199451b44SJordan Rupprecht        '''
10299451b44SJordan Rupprecht            Tests attaching to a process by process name and waiting for the
10399451b44SJordan Rupprecht            next instance of a process to be launched, ingoring all current
10499451b44SJordan Rupprecht            ones.
10599451b44SJordan Rupprecht        '''
10699451b44SJordan Rupprecht        self.build_and_create_debug_adaptor()
10799451b44SJordan Rupprecht        program = self.getBuildArtifact("a.out")
10899451b44SJordan Rupprecht        self.spawn_thread = threading.Thread(target=spawn_and_wait,
10999451b44SJordan Rupprecht                                             args=(program, 1.0,))
11099451b44SJordan Rupprecht        self.spawn_thread.start()
11199451b44SJordan Rupprecht        self.attach(program=program, waitFor=True)
11299451b44SJordan Rupprecht        self.set_and_hit_breakpoint(continueToExit=True)
11399451b44SJordan Rupprecht
11499451b44SJordan Rupprecht    @skipIfWindows
11599451b44SJordan Rupprecht    @skipIfDarwin
11699451b44SJordan Rupprecht    @skipIfNetBSD # Hangs on NetBSD as well
1171f780c99SMuhammad Omair Javaid    @skipIf(archs=["arm", "aarch64"]) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5527/steps/test/logs/stdio
11899451b44SJordan Rupprecht    def test_commands(self):
11999451b44SJordan Rupprecht        '''
12099451b44SJordan Rupprecht            Tests the "initCommands", "preRunCommands", "stopCommands",
12174ab1da0SWalter Erquinigo            "exitCommands", "terminateCommands" and "attachCommands"
12274ab1da0SWalter Erquinigo            that can be passed during attach.
12399451b44SJordan Rupprecht
12499451b44SJordan Rupprecht            "initCommands" are a list of LLDB commands that get executed
12599451b44SJordan Rupprecht            before the targt is created.
12699451b44SJordan Rupprecht            "preRunCommands" are a list of LLDB commands that get executed
12799451b44SJordan Rupprecht            after the target has been created and before the launch.
12899451b44SJordan Rupprecht            "stopCommands" are a list of LLDB commands that get executed each
12999451b44SJordan Rupprecht            time the program stops.
13099451b44SJordan Rupprecht            "exitCommands" are a list of LLDB commands that get executed when
13199451b44SJordan Rupprecht            the process exits
13299451b44SJordan Rupprecht            "attachCommands" are a list of LLDB commands that get executed and
13399451b44SJordan Rupprecht            must have a valid process in the selected target in LLDB after
13499451b44SJordan Rupprecht            they are done executing. This allows custom commands to create any
13599451b44SJordan Rupprecht            kind of debug session.
13674ab1da0SWalter Erquinigo            "terminateCommands" are a list of LLDB commands that get executed when
13774ab1da0SWalter Erquinigo            the debugger session terminates.
13899451b44SJordan Rupprecht        '''
13999451b44SJordan Rupprecht        self.build_and_create_debug_adaptor()
14099451b44SJordan Rupprecht        program = self.getBuildArtifact("a.out")
14199451b44SJordan Rupprecht        # Here we just create a target and launch the process as a way to test
14299451b44SJordan Rupprecht        # if we are able to use attach commands to create any kind of a target
14399451b44SJordan Rupprecht        # and use it for debugging
14499451b44SJordan Rupprecht        attachCommands = [
14599451b44SJordan Rupprecht            'target create -d "%s"' % (program),
146e7a3c4c1SPavel Labath            'process launch --stop-at-entry'
14799451b44SJordan Rupprecht        ]
14899451b44SJordan Rupprecht        initCommands = ['target list', 'platform list']
14999451b44SJordan Rupprecht        preRunCommands = ['image list a.out', 'image dump sections a.out']
15079fbbeb4SWalter Erquinigo        postRunCommands = ['help trace', 'help process trace']
15199451b44SJordan Rupprecht        stopCommands = ['frame variable', 'bt']
15299451b44SJordan Rupprecht        exitCommands = ['expr 2+3', 'expr 3+4']
15374ab1da0SWalter Erquinigo        terminateCommands = ['expr 4+2']
15499451b44SJordan Rupprecht        self.attach(program=program,
15599451b44SJordan Rupprecht                    attachCommands=attachCommands,
15699451b44SJordan Rupprecht                    initCommands=initCommands,
15799451b44SJordan Rupprecht                    preRunCommands=preRunCommands,
15899451b44SJordan Rupprecht                    stopCommands=stopCommands,
15974ab1da0SWalter Erquinigo                    exitCommands=exitCommands,
16079fbbeb4SWalter Erquinigo                    terminateCommands=terminateCommands,
16179fbbeb4SWalter Erquinigo                    postRunCommands=postRunCommands)
16299451b44SJordan Rupprecht        # Get output from the console. This should contain both the
16399451b44SJordan Rupprecht        # "initCommands" and the "preRunCommands".
16499451b44SJordan Rupprecht        output = self.get_console()
16599451b44SJordan Rupprecht        # Verify all "initCommands" were found in console output
16699451b44SJordan Rupprecht        self.verify_commands('initCommands', output, initCommands)
16799451b44SJordan Rupprecht        # Verify all "preRunCommands" were found in console output
16899451b44SJordan Rupprecht        self.verify_commands('preRunCommands', output, preRunCommands)
16979fbbeb4SWalter Erquinigo        # Verify all "postRunCommands" were found in console output
17079fbbeb4SWalter Erquinigo        self.verify_commands('postRunCommands', output, postRunCommands)
17199451b44SJordan Rupprecht
17299451b44SJordan Rupprecht        functions = ['main']
17399451b44SJordan Rupprecht        breakpoint_ids = self.set_function_breakpoints(functions)
174b3a0c4d7SRaphael Isemann        self.assertEquals(len(breakpoint_ids), len(functions),
17599451b44SJordan Rupprecht                        "expect one breakpoint")
17699451b44SJordan Rupprecht        self.continue_to_breakpoints(breakpoint_ids)
17799451b44SJordan Rupprecht        output = self.get_console(timeout=1.0)
17899451b44SJordan Rupprecht        self.verify_commands('stopCommands', output, stopCommands)
17999451b44SJordan Rupprecht
18099451b44SJordan Rupprecht        # Continue after launch and hit the "pause()" call and stop the target.
18199451b44SJordan Rupprecht        # Get output from the console. This should contain both the
18299451b44SJordan Rupprecht        # "stopCommands" that were run after we stop.
18399451b44SJordan Rupprecht        self.vscode.request_continue()
18499451b44SJordan Rupprecht        time.sleep(0.5)
18599451b44SJordan Rupprecht        self.vscode.request_pause()
18699451b44SJordan Rupprecht        self.vscode.wait_for_stopped()
18799451b44SJordan Rupprecht        output = self.get_console(timeout=1.0)
18899451b44SJordan Rupprecht        self.verify_commands('stopCommands', output, stopCommands)
18999451b44SJordan Rupprecht
19099451b44SJordan Rupprecht        # Continue until the program exits
19199451b44SJordan Rupprecht        self.continue_to_exit()
19299451b44SJordan Rupprecht        # Get output from the console. This should contain both the
19399451b44SJordan Rupprecht        # "exitCommands" that were run after the second breakpoint was hit
19474ab1da0SWalter Erquinigo        # and the "terminateCommands" due to the debugging session ending
19574ab1da0SWalter Erquinigo        output = self.collect_console(duration=1.0)
19699451b44SJordan Rupprecht        self.verify_commands('exitCommands', output, exitCommands)
19774ab1da0SWalter Erquinigo        self.verify_commands('terminateCommands', output, terminateCommands)
19874ab1da0SWalter Erquinigo
19974ab1da0SWalter Erquinigo    @skipIfWindows
2008e084223SWalter Erquinigo    @skipIfDarwin
20174ab1da0SWalter Erquinigo    @skipIfNetBSD # Hangs on NetBSD as well
2021f780c99SMuhammad Omair Javaid    @skipIf(archs=["arm", "aarch64"]) # Example of a flaky run http://lab.llvm.org:8011/builders/lldb-aarch64-ubuntu/builds/5517/steps/test/logs/stdio
20374ab1da0SWalter Erquinigo    def test_terminate_commands(self):
20474ab1da0SWalter Erquinigo        '''
20574ab1da0SWalter Erquinigo            Tests that the "terminateCommands", that can be passed during
20674ab1da0SWalter Erquinigo            attach, are run when the debugger is disconnected.
20774ab1da0SWalter Erquinigo        '''
20874ab1da0SWalter Erquinigo        self.build_and_create_debug_adaptor()
20974ab1da0SWalter Erquinigo        program = self.getBuildArtifact("a.out")
21074ab1da0SWalter Erquinigo        # Here we just create a target and launch the process as a way to test
21174ab1da0SWalter Erquinigo        # if we are able to use attach commands to create any kind of a target
21274ab1da0SWalter Erquinigo        # and use it for debugging
21374ab1da0SWalter Erquinigo        attachCommands = [
21474ab1da0SWalter Erquinigo            'target create -d "%s"' % (program),
215*c41c5746SGreg Clayton            'process launch --stop-at-entry'
21674ab1da0SWalter Erquinigo        ]
21774ab1da0SWalter Erquinigo        terminateCommands = ['expr 4+2']
21874ab1da0SWalter Erquinigo        self.attach(program=program,
21974ab1da0SWalter Erquinigo                    attachCommands=attachCommands,
22074ab1da0SWalter Erquinigo                    terminateCommands=terminateCommands,
22174ab1da0SWalter Erquinigo                    disconnectAutomatically=False)
22274ab1da0SWalter Erquinigo        self.get_console()
22374ab1da0SWalter Erquinigo        # Once it's disconnected the console should contain the
22474ab1da0SWalter Erquinigo        # "terminateCommands"
22574ab1da0SWalter Erquinigo        self.vscode.request_disconnect(terminateDebuggee=True)
22674ab1da0SWalter Erquinigo        output = self.collect_console(duration=1.0)
22774ab1da0SWalter Erquinigo        self.verify_commands('terminateCommands', output, terminateCommands)
228