xref: /llvm-project/lldb/test/API/commands/process/launch/TestProcessLaunch.py (revision e952728f88c8b0e0208dc991dd9a04fe8c211cfb)
199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest lldb process launch flags.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtimport os
699451b44SJordan Rupprecht
799451b44SJordan Rupprechtimport lldb
899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1099451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
11*e952728fSwalter erquinigofrom pathlib import Path
1299451b44SJordan Rupprecht
1399451b44SJordan Rupprecht
1499451b44SJordan Rupprechtclass ProcessLaunchTestCase(TestBase):
1599451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1699451b44SJordan Rupprecht
1799451b44SJordan Rupprecht    def setUp(self):
1899451b44SJordan Rupprecht        # Call super's setUp().
1999451b44SJordan Rupprecht        TestBase.setUp(self)
2099451b44SJordan Rupprecht        self.runCmd("settings set auto-confirm true")
2199451b44SJordan Rupprecht
2299451b44SJordan Rupprecht    def tearDown(self):
2399451b44SJordan Rupprecht        self.runCmd("settings clear auto-confirm")
2499451b44SJordan Rupprecht        TestBase.tearDown(self)
2599451b44SJordan Rupprecht
2666ae40ebSRaphael Isemann    @skipIfRemote
2799451b44SJordan Rupprecht    def test_io(self):
2899451b44SJordan Rupprecht        """Test that process launch I/O redirection flags work properly."""
2999451b44SJordan Rupprecht        self.build()
3099451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
312238dcc3SJonas Devlieghere        self.expect("file " + exe, patterns=["Current executable set to .*a.out"])
3299451b44SJordan Rupprecht
3399451b44SJordan Rupprecht        in_file = os.path.join(self.getSourceDir(), "input-file.txt")
3499451b44SJordan Rupprecht        out_file = lldbutil.append_to_process_working_directory(self, "output-test.out")
3599451b44SJordan Rupprecht        err_file = lldbutil.append_to_process_working_directory(self, "output-test.err")
3699451b44SJordan Rupprecht
3799451b44SJordan Rupprecht        # Make sure the output files do not exist before launching the process
3899451b44SJordan Rupprecht        try:
3999451b44SJordan Rupprecht            os.remove(out_file)
4099451b44SJordan Rupprecht        except OSError:
4199451b44SJordan Rupprecht            pass
4299451b44SJordan Rupprecht
4399451b44SJordan Rupprecht        try:
4499451b44SJordan Rupprecht            os.remove(err_file)
4599451b44SJordan Rupprecht        except OSError:
4699451b44SJordan Rupprecht            pass
4799451b44SJordan Rupprecht
4899451b44SJordan Rupprecht        launch_command = "process launch -i '{0}' -o '{1}' -e '{2}' -w '{3}'".format(
492238dcc3SJonas Devlieghere            in_file, out_file, err_file, self.get_process_working_directory()
502238dcc3SJonas Devlieghere        )
5199451b44SJordan Rupprecht
5299451b44SJordan Rupprecht        if lldb.remote_platform:
532238dcc3SJonas Devlieghere            self.runCmd(
542238dcc3SJonas Devlieghere                'platform put-file "{local}" "{remote}"'.format(
552238dcc3SJonas Devlieghere                    local=in_file, remote=in_file
562238dcc3SJonas Devlieghere                )
572238dcc3SJonas Devlieghere            )
5899451b44SJordan Rupprecht
592238dcc3SJonas Devlieghere        self.expect(launch_command, patterns=["Process .* launched: .*a.out"])
6099451b44SJordan Rupprecht
6199451b44SJordan Rupprecht        success = True
6299451b44SJordan Rupprecht        err_msg = ""
6399451b44SJordan Rupprecht
6499451b44SJordan Rupprecht        out = lldbutil.read_file_on_target(self, out_file)
6599451b44SJordan Rupprecht        if out != "This should go to stdout.\n":
6699451b44SJordan Rupprecht            success = False
672238dcc3SJonas Devlieghere            err_msg = (
682238dcc3SJonas Devlieghere                err_msg + "    ERROR: stdout file does not contain correct output.\n"
692238dcc3SJonas Devlieghere            )
7099451b44SJordan Rupprecht
7199451b44SJordan Rupprecht        err = lldbutil.read_file_on_target(self, err_file)
7299451b44SJordan Rupprecht        if err != "This should go to stderr.\n":
7399451b44SJordan Rupprecht            success = False
742238dcc3SJonas Devlieghere            err_msg = (
752238dcc3SJonas Devlieghere                err_msg + "    ERROR: stderr file does not contain correct output.\n"
762238dcc3SJonas Devlieghere            )
7799451b44SJordan Rupprecht
7899451b44SJordan Rupprecht        if not success:
7999451b44SJordan Rupprecht            self.fail(err_msg)
8099451b44SJordan Rupprecht
8199451b44SJordan Rupprecht    # rdar://problem/9056462
8299451b44SJordan Rupprecht    # The process launch flag '-w' for setting the current working directory
8399451b44SJordan Rupprecht    # not working?
8466ae40ebSRaphael Isemann    @skipIfRemote
8598257c30SMichał Górny    @expectedFailureAll(oslist=["freebsd", "linux"], bugnumber="llvm.org/pr20265")
8699451b44SJordan Rupprecht    @expectedFailureNetBSD
8799451b44SJordan Rupprecht    def test_set_working_dir_nonexisting(self):
8899451b44SJordan Rupprecht        """Test that '-w dir' fails to set the working dir when running the inferior with a dir which doesn't exist."""
892238dcc3SJonas Devlieghere        d = {"CXX_SOURCES": "print_cwd.cpp"}
9099451b44SJordan Rupprecht        self.build(dictionary=d)
9199451b44SJordan Rupprecht        self.setTearDownCleanup(d)
9299451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
9399451b44SJordan Rupprecht        self.runCmd("file " + exe)
9499451b44SJordan Rupprecht
952238dcc3SJonas Devlieghere        mywd = "my_working_dir"
9699451b44SJordan Rupprecht        out_file_name = "my_working_dir_test.out"
9799451b44SJordan Rupprecht        err_file_name = "my_working_dir_test.err"
9899451b44SJordan Rupprecht
9999451b44SJordan Rupprecht        my_working_dir_path = self.getBuildArtifact(mywd)
10099451b44SJordan Rupprecht        out_file_path = os.path.join(my_working_dir_path, out_file_name)
10199451b44SJordan Rupprecht        err_file_path = os.path.join(my_working_dir_path, err_file_name)
10299451b44SJordan Rupprecht
10399451b44SJordan Rupprecht        # Check that we get an error when we have a nonexisting path
1042238dcc3SJonas Devlieghere        invalid_dir_path = mywd + "z"
10599451b44SJordan Rupprecht        launch_command = "process launch -w %s -o %s -e %s" % (
1062238dcc3SJonas Devlieghere            invalid_dir_path,
1072238dcc3SJonas Devlieghere            out_file_path,
1082238dcc3SJonas Devlieghere            err_file_path,
1092238dcc3SJonas Devlieghere        )
11099451b44SJordan Rupprecht
11199451b44SJordan Rupprecht        self.expect(
1122238dcc3SJonas Devlieghere            launch_command,
1132238dcc3SJonas Devlieghere            error=True,
1142238dcc3SJonas Devlieghere            patterns=["error:.* No such file or directory: %s" % invalid_dir_path],
1152238dcc3SJonas Devlieghere        )
11699451b44SJordan Rupprecht
11766ae40ebSRaphael Isemann    @skipIfRemote
11899451b44SJordan Rupprecht    def test_set_working_dir_existing(self):
11999451b44SJordan Rupprecht        """Test that '-w dir' sets the working dir when running the inferior."""
1202238dcc3SJonas Devlieghere        d = {"CXX_SOURCES": "print_cwd.cpp"}
12199451b44SJordan Rupprecht        self.build(dictionary=d)
12299451b44SJordan Rupprecht        self.setTearDownCleanup(d)
12399451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
12499451b44SJordan Rupprecht        self.runCmd("file " + exe)
12599451b44SJordan Rupprecht
1262238dcc3SJonas Devlieghere        mywd = "my_working_dir"
12799451b44SJordan Rupprecht        out_file_name = "my_working_dir_test.out"
12899451b44SJordan Rupprecht        err_file_name = "my_working_dir_test.err"
12999451b44SJordan Rupprecht
13099451b44SJordan Rupprecht        my_working_dir_path = self.getBuildArtifact(mywd)
13199451b44SJordan Rupprecht        lldbutil.mkdir_p(my_working_dir_path)
13299451b44SJordan Rupprecht        out_file_path = os.path.join(my_working_dir_path, out_file_name)
13399451b44SJordan Rupprecht        err_file_path = os.path.join(my_working_dir_path, err_file_name)
13499451b44SJordan Rupprecht
13599451b44SJordan Rupprecht        # Make sure the output files do not exist before launching the process
13699451b44SJordan Rupprecht        try:
13799451b44SJordan Rupprecht            os.remove(out_file_path)
13899451b44SJordan Rupprecht            os.remove(err_file_path)
13999451b44SJordan Rupprecht        except OSError:
14099451b44SJordan Rupprecht            pass
14199451b44SJordan Rupprecht
14299451b44SJordan Rupprecht        launch_command = "process launch -w %s -o %s -e %s" % (
1432238dcc3SJonas Devlieghere            my_working_dir_path,
1442238dcc3SJonas Devlieghere            out_file_path,
1452238dcc3SJonas Devlieghere            err_file_path,
1462238dcc3SJonas Devlieghere        )
14799451b44SJordan Rupprecht
1482238dcc3SJonas Devlieghere        self.expect(launch_command, patterns=["Process .* launched: .*a.out"])
14999451b44SJordan Rupprecht
15099451b44SJordan Rupprecht        success = True
15199451b44SJordan Rupprecht        err_msg = ""
15299451b44SJordan Rupprecht
15399451b44SJordan Rupprecht        # Check to see if the 'stdout' file was created
15499451b44SJordan Rupprecht        try:
15599451b44SJordan Rupprecht            out_f = open(out_file_path)
15699451b44SJordan Rupprecht        except IOError:
15799451b44SJordan Rupprecht            success = False
15899451b44SJordan Rupprecht            err_msg = err_msg + "ERROR: stdout file was not created.\n"
15999451b44SJordan Rupprecht        else:
16099451b44SJordan Rupprecht            # Check to see if the 'stdout' file contains the right output
16199451b44SJordan Rupprecht            line = out_f.readline()
16299451b44SJordan Rupprecht            if self.TraceOn():
16399451b44SJordan Rupprecht                print("line:", line)
16499451b44SJordan Rupprecht            if not re.search(mywd, line):
16599451b44SJordan Rupprecht                success = False
1662238dcc3SJonas Devlieghere                err_msg = (
1672238dcc3SJonas Devlieghere                    err_msg + "The current working directory was not set correctly.\n"
1682238dcc3SJonas Devlieghere                )
16999451b44SJordan Rupprecht                out_f.close()
17099451b44SJordan Rupprecht
17199451b44SJordan Rupprecht        # Try to delete the 'stdout' and 'stderr' files
17299451b44SJordan Rupprecht        try:
17399451b44SJordan Rupprecht            os.remove(out_file_path)
17499451b44SJordan Rupprecht            os.remove(err_file_path)
17599451b44SJordan Rupprecht        except OSError:
17699451b44SJordan Rupprecht            pass
17799451b44SJordan Rupprecht
17899451b44SJordan Rupprecht        if not success:
17999451b44SJordan Rupprecht            self.fail(err_msg)
18099451b44SJordan Rupprecht
18199451b44SJordan Rupprecht    def test_environment_with_special_char(self):
18299451b44SJordan Rupprecht        """Test that environment variables containing '*' and '}' are handled correctly by the inferior."""
1832238dcc3SJonas Devlieghere        source = "print_env.cpp"
1842238dcc3SJonas Devlieghere        d = {"CXX_SOURCES": source}
18599451b44SJordan Rupprecht        self.build(dictionary=d)
18699451b44SJordan Rupprecht        self.setTearDownCleanup(d)
18799451b44SJordan Rupprecht
1882238dcc3SJonas Devlieghere        evil_var = "INIT*MIDDLE}TAIL"
18999451b44SJordan Rupprecht
19054c26872SRaphael Isemann        target = self.createTestTarget()
19199451b44SJordan Rupprecht        main_source_spec = lldb.SBFileSpec(source)
19299451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateBySourceRegex(
1932238dcc3SJonas Devlieghere            "// Set breakpoint here.", main_source_spec
1942238dcc3SJonas Devlieghere        )
19599451b44SJordan Rupprecht
1962238dcc3SJonas Devlieghere        process = target.LaunchSimple(
1972238dcc3SJonas Devlieghere            None, ["EVIL=" + evil_var], self.get_process_working_directory()
1982238dcc3SJonas Devlieghere        )
1992238dcc3SJonas Devlieghere        self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
20099451b44SJordan Rupprecht
2012238dcc3SJonas Devlieghere        threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint)
20299451b44SJordan Rupprecht        self.assertEqual(len(threads), 1)
20399451b44SJordan Rupprecht        frame = threads[0].GetFrameAtIndex(0)
20499451b44SJordan Rupprecht        sbvalue = frame.EvaluateExpression("evil")
20599451b44SJordan Rupprecht        value = sbvalue.GetSummary().strip('"')
20699451b44SJordan Rupprecht
20799451b44SJordan Rupprecht        self.assertEqual(value, evil_var)
20899451b44SJordan Rupprecht        process.Continue()
2091b8c7352SJonas Devlieghere        self.assertState(process.GetState(), lldb.eStateExited, PROCESS_EXITED)
210*e952728fSwalter erquinigo
211*e952728fSwalter erquinigo    @skipIfRemote
212*e952728fSwalter erquinigo    def test_target_launch_working_dir_prop(self):
213*e952728fSwalter erquinigo        """Test that the setting `target.launch-working-dir` is correctly used when launching a process."""
214*e952728fSwalter erquinigo        d = {"CXX_SOURCES": "print_cwd.cpp"}
215*e952728fSwalter erquinigo        self.build(dictionary=d)
216*e952728fSwalter erquinigo        self.setTearDownCleanup(d)
217*e952728fSwalter erquinigo        exe = self.getBuildArtifact("a.out")
218*e952728fSwalter erquinigo        self.runCmd("file " + exe)
219*e952728fSwalter erquinigo
220*e952728fSwalter erquinigo        mywd = "my_working_dir"
221*e952728fSwalter erquinigo        out_file_name = "my_working_dir_test.out"
222*e952728fSwalter erquinigo
223*e952728fSwalter erquinigo        my_working_dir_path = self.getBuildArtifact(mywd)
224*e952728fSwalter erquinigo        lldbutil.mkdir_p(my_working_dir_path)
225*e952728fSwalter erquinigo        out_file_path = os.path.join(my_working_dir_path, out_file_name)
226*e952728fSwalter erquinigo        another_working_dir_path = Path(
227*e952728fSwalter erquinigo            os.path.join(my_working_dir_path, "..")
228*e952728fSwalter erquinigo        ).resolve()
229*e952728fSwalter erquinigo
230*e952728fSwalter erquinigo        # If -w is not passed to process launch, then the setting will be used.
231*e952728fSwalter erquinigo        self.runCmd(
232*e952728fSwalter erquinigo            f"settings set target.launch-working-dir {another_working_dir_path}"
233*e952728fSwalter erquinigo        )
234*e952728fSwalter erquinigo        launch_command = f"process launch -o {out_file_path}"
235*e952728fSwalter erquinigo
236*e952728fSwalter erquinigo        self.expect(
237*e952728fSwalter erquinigo            launch_command,
238*e952728fSwalter erquinigo            patterns=["Process .* launched: .*a.out"],
239*e952728fSwalter erquinigo        )
240*e952728fSwalter erquinigo
241*e952728fSwalter erquinigo        out = lldbutil.read_file_on_target(self, out_file_path)
242*e952728fSwalter erquinigo
243*e952728fSwalter erquinigo        self.assertIn(f"stdout: {another_working_dir_path}", out)
244*e952728fSwalter erquinigo
245*e952728fSwalter erquinigo        # If -w is passed to process launch, that value will be used instead of the setting.
246*e952728fSwalter erquinigo        launch_command = f"process launch -w {my_working_dir_path} -o {out_file_path}"
247*e952728fSwalter erquinigo
248*e952728fSwalter erquinigo        self.expect(
249*e952728fSwalter erquinigo            launch_command,
250*e952728fSwalter erquinigo            patterns=["Process .* launched: .*a.out"],
251*e952728fSwalter erquinigo        )
252*e952728fSwalter erquinigo
253*e952728fSwalter erquinigo        out = lldbutil.read_file_on_target(self, out_file_path)
254*e952728fSwalter erquinigo        self.assertIn(f"stdout: {my_working_dir_path}", out)
255*e952728fSwalter erquinigo
256*e952728fSwalter erquinigo        # If set to empty, then LLDB's cwd will be used to launch the process.
257*e952728fSwalter erquinigo        self.runCmd(f"settings set target.launch-working-dir ''")
258*e952728fSwalter erquinigo        launch_command = f"process launch -o {out_file_path}"
259*e952728fSwalter erquinigo
260*e952728fSwalter erquinigo        self.expect(
261*e952728fSwalter erquinigo            launch_command,
262*e952728fSwalter erquinigo            patterns=["Process .* launched: .*a.out"],
263*e952728fSwalter erquinigo        )
264*e952728fSwalter erquinigo
265*e952728fSwalter erquinigo        out = lldbutil.read_file_on_target(self, out_file_path)
266*e952728fSwalter erquinigo        self.assertNotIn(f"stdout: {another_working_dir_path}", out)
267