1"""
2Test lldb process launch flags.
3"""
4
5from __future__ import print_function
6
7import os
8
9import lldb
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14import six
15
16
17class ProcessLaunchTestCase(TestBase):
18    NO_DEBUG_INFO_TESTCASE = True
19
20    def setUp(self):
21        # Call super's setUp().
22        TestBase.setUp(self)
23        self.runCmd("settings set auto-confirm true")
24
25    def tearDown(self):
26        self.runCmd("settings clear auto-confirm")
27        TestBase.tearDown(self)
28
29    @skipIfRemote
30    def test_io(self):
31        """Test that process launch I/O redirection flags work properly."""
32        self.build()
33        exe = self.getBuildArtifact("a.out")
34        self.expect("file " + exe,
35                    patterns=["Current executable set to .*a.out"])
36
37        in_file = os.path.join(self.getSourceDir(), "input-file.txt")
38        out_file = lldbutil.append_to_process_working_directory(self, "output-test.out")
39        err_file = lldbutil.append_to_process_working_directory(self, "output-test.err")
40
41        # Make sure the output files do not exist before launching the process
42        try:
43            os.remove(out_file)
44        except OSError:
45            pass
46
47        try:
48            os.remove(err_file)
49        except OSError:
50            pass
51
52        launch_command = "process launch -i '{0}' -o '{1}' -e '{2}' -w '{3}'".format(
53                in_file, out_file, err_file, self.get_process_working_directory())
54
55        if lldb.remote_platform:
56            self.runCmd('platform put-file "{local}" "{remote}"'.format(
57                local=in_file, remote=in_file))
58
59        self.expect(launch_command,
60                    patterns=["Process .* launched: .*a.out"])
61
62        success = True
63        err_msg = ""
64
65        out = lldbutil.read_file_on_target(self, out_file)
66        if out != "This should go to stdout.\n":
67            success = False
68            err_msg = err_msg + "    ERROR: stdout file does not contain correct output.\n"
69
70
71        err = lldbutil.read_file_on_target(self, err_file)
72        if err != "This should go to stderr.\n":
73            success = False
74            err_msg = err_msg + "    ERROR: stderr file does not contain correct output.\n"
75
76        if not success:
77            self.fail(err_msg)
78
79    # rdar://problem/9056462
80    # The process launch flag '-w' for setting the current working directory
81    # not working?
82    @skipIfRemote
83    @expectedFailureAll(oslist=["freebsd", "linux"], bugnumber="llvm.org/pr20265")
84    @expectedFailureNetBSD
85    def test_set_working_dir_nonexisting(self):
86        """Test that '-w dir' fails to set the working dir when running the inferior with a dir which doesn't exist."""
87        d = {'CXX_SOURCES': 'print_cwd.cpp'}
88        self.build(dictionary=d)
89        self.setTearDownCleanup(d)
90        exe = self.getBuildArtifact("a.out")
91        self.runCmd("file " + exe)
92
93        mywd = 'my_working_dir'
94        out_file_name = "my_working_dir_test.out"
95        err_file_name = "my_working_dir_test.err"
96
97        my_working_dir_path = self.getBuildArtifact(mywd)
98        out_file_path = os.path.join(my_working_dir_path, out_file_name)
99        err_file_path = os.path.join(my_working_dir_path, err_file_name)
100
101        # Check that we get an error when we have a nonexisting path
102        invalid_dir_path = mywd + 'z'
103        launch_command = "process launch -w %s -o %s -e %s" % (
104            invalid_dir_path, out_file_path, err_file_path)
105
106        self.expect(
107            launch_command, error=True, patterns=[
108                "error:.* No such file or directory: %s" %
109                invalid_dir_path])
110
111    @skipIfRemote
112    def test_set_working_dir_existing(self):
113        """Test that '-w dir' sets the working dir when running the inferior."""
114        d = {'CXX_SOURCES': 'print_cwd.cpp'}
115        self.build(dictionary=d)
116        self.setTearDownCleanup(d)
117        exe = self.getBuildArtifact("a.out")
118        self.runCmd("file " + exe)
119
120        mywd = 'my_working_dir'
121        out_file_name = "my_working_dir_test.out"
122        err_file_name = "my_working_dir_test.err"
123
124        my_working_dir_path = self.getBuildArtifact(mywd)
125        lldbutil.mkdir_p(my_working_dir_path)
126        out_file_path = os.path.join(my_working_dir_path, out_file_name)
127        err_file_path = os.path.join(my_working_dir_path, err_file_name)
128
129        # Make sure the output files do not exist before launching the process
130        try:
131            os.remove(out_file_path)
132            os.remove(err_file_path)
133        except OSError:
134            pass
135
136        launch_command = "process launch -w %s -o %s -e %s" % (
137            my_working_dir_path, out_file_path, err_file_path)
138
139        self.expect(launch_command,
140                    patterns=["Process .* launched: .*a.out"])
141
142        success = True
143        err_msg = ""
144
145        # Check to see if the 'stdout' file was created
146        try:
147            out_f = open(out_file_path)
148        except IOError:
149            success = False
150            err_msg = err_msg + "ERROR: stdout file was not created.\n"
151        else:
152            # Check to see if the 'stdout' file contains the right output
153            line = out_f.readline()
154            if self.TraceOn():
155                print("line:", line)
156            if not re.search(mywd, line):
157                success = False
158                err_msg = err_msg + "The current working directory was not set correctly.\n"
159                out_f.close()
160
161        # Try to delete the 'stdout' and 'stderr' files
162        try:
163            os.remove(out_file_path)
164            os.remove(err_file_path)
165        except OSError:
166            pass
167
168        if not success:
169            self.fail(err_msg)
170
171    def test_environment_with_special_char(self):
172        """Test that environment variables containing '*' and '}' are handled correctly by the inferior."""
173        source = 'print_env.cpp'
174        d = {'CXX_SOURCES': source}
175        self.build(dictionary=d)
176        self.setTearDownCleanup(d)
177
178        evil_var = 'INIT*MIDDLE}TAIL'
179
180        target = self.createTestTarget()
181        main_source_spec = lldb.SBFileSpec(source)
182        breakpoint = target.BreakpointCreateBySourceRegex(
183            '// Set breakpoint here.', main_source_spec)
184
185        process = target.LaunchSimple(None,
186                                      ['EVIL=' + evil_var],
187                                      self.get_process_working_directory())
188        self.assertEqual(
189            process.GetState(),
190            lldb.eStateStopped,
191            PROCESS_STOPPED)
192
193        threads = lldbutil.get_threads_stopped_at_breakpoint(
194            process, breakpoint)
195        self.assertEqual(len(threads), 1)
196        frame = threads[0].GetFrameAtIndex(0)
197        sbvalue = frame.EvaluateExpression("evil")
198        value = sbvalue.GetSummary().strip('"')
199
200        self.assertEqual(value, evil_var)
201        process.Continue()
202        self.assertState(process.GetState(), lldb.eStateExited, PROCESS_EXITED)
203