267 lines · python
1"""2Test lldb process launch flags.3"""4 5import os6 7import lldb8from lldbsuite.test.decorators import *9from lldbsuite.test.lldbtest import *10from lldbsuite.test import lldbutil11from pathlib import Path12 13 14class ProcessLaunchTestCase(TestBase):15 NO_DEBUG_INFO_TESTCASE = True16 17 def setUp(self):18 # Call super's setUp().19 TestBase.setUp(self)20 self.runCmd("settings set auto-confirm true")21 22 def tearDown(self):23 self.runCmd("settings clear auto-confirm")24 TestBase.tearDown(self)25 26 @skipIfRemote27 def test_io(self):28 """Test that process launch I/O redirection flags work properly."""29 self.build()30 exe = self.getBuildArtifact("a.out")31 self.expect("file " + exe, patterns=["Current executable set to .*a.out"])32 33 in_file = os.path.join(self.getSourceDir(), "input-file.txt")34 out_file = lldbutil.append_to_process_working_directory(self, "output-test.out")35 err_file = lldbutil.append_to_process_working_directory(self, "output-test.err")36 37 # Make sure the output files do not exist before launching the process38 try:39 os.remove(out_file)40 except OSError:41 pass42 43 try:44 os.remove(err_file)45 except OSError:46 pass47 48 launch_command = "process launch -i '{0}' -o '{1}' -e '{2}' -w '{3}'".format(49 in_file, out_file, err_file, self.get_process_working_directory()50 )51 52 if lldb.remote_platform:53 self.runCmd(54 'platform put-file "{local}" "{remote}"'.format(55 local=in_file, remote=in_file56 )57 )58 59 self.expect(launch_command, patterns=["Process .* launched: .*a.out"])60 61 success = True62 err_msg = ""63 64 out = lldbutil.read_file_on_target(self, out_file)65 if out != "This should go to stdout.\n":66 success = False67 err_msg = (68 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 = False74 err_msg = (75 err_msg + " ERROR: stderr file does not contain correct output.\n"76 )77 78 if not success:79 self.fail(err_msg)80 81 # rdar://problem/905646282 # The process launch flag '-w' for setting the current working directory83 # not working?84 @skipIfRemote85 @expectedFailureAll(oslist=["freebsd", "linux"], bugnumber="llvm.org/pr20265")86 @expectedFailureNetBSD87 def test_set_working_dir_nonexisting(self):88 """Test that '-w dir' fails to set the working dir when running the inferior with a dir which doesn't exist."""89 d = {"CXX_SOURCES": "print_cwd.cpp"}90 self.build(dictionary=d)91 self.setTearDownCleanup(d)92 exe = self.getBuildArtifact("a.out")93 self.runCmd("file " + exe)94 95 mywd = "my_working_dir"96 out_file_name = "my_working_dir_test.out"97 err_file_name = "my_working_dir_test.err"98 99 my_working_dir_path = self.getBuildArtifact(mywd)100 out_file_path = os.path.join(my_working_dir_path, out_file_name)101 err_file_path = os.path.join(my_working_dir_path, err_file_name)102 103 # Check that we get an error when we have a nonexisting path104 invalid_dir_path = mywd + "z"105 launch_command = "process launch -w %s -o %s -e %s" % (106 invalid_dir_path,107 out_file_path,108 err_file_path,109 )110 111 self.expect(112 launch_command,113 error=True,114 patterns=["error:.* No such file or directory: %s" % invalid_dir_path],115 )116 117 @skipIfRemote118 def test_set_working_dir_existing(self):119 """Test that '-w dir' sets the working dir when running the inferior."""120 d = {"CXX_SOURCES": "print_cwd.cpp"}121 self.build(dictionary=d)122 self.setTearDownCleanup(d)123 exe = self.getBuildArtifact("a.out")124 self.runCmd("file " + exe)125 126 mywd = "my_working_dir"127 out_file_name = "my_working_dir_test.out"128 err_file_name = "my_working_dir_test.err"129 130 my_working_dir_path = self.getBuildArtifact(mywd)131 lldbutil.mkdir_p(my_working_dir_path)132 out_file_path = os.path.join(my_working_dir_path, out_file_name)133 err_file_path = os.path.join(my_working_dir_path, err_file_name)134 135 # Make sure the output files do not exist before launching the process136 try:137 os.remove(out_file_path)138 os.remove(err_file_path)139 except OSError:140 pass141 142 launch_command = "process launch -w %s -o %s -e %s" % (143 my_working_dir_path,144 out_file_path,145 err_file_path,146 )147 148 self.expect(launch_command, patterns=["Process .* launched: .*a.out"])149 150 success = True151 err_msg = ""152 153 # Check to see if the 'stdout' file was created154 try:155 out_f = open(out_file_path)156 except IOError:157 success = False158 err_msg = err_msg + "ERROR: stdout file was not created.\n"159 else:160 # Check to see if the 'stdout' file contains the right output161 line = out_f.readline()162 if self.TraceOn():163 print("line:", line)164 if not re.search(mywd, line):165 success = False166 err_msg = (167 err_msg + "The current working directory was not set correctly.\n"168 )169 out_f.close()170 171 # Try to delete the 'stdout' and 'stderr' files172 try:173 os.remove(out_file_path)174 os.remove(err_file_path)175 except OSError:176 pass177 178 if not success:179 self.fail(err_msg)180 181 def test_environment_with_special_char(self):182 """Test that environment variables containing '*' and '}' are handled correctly by the inferior."""183 source = "print_env.cpp"184 d = {"CXX_SOURCES": source}185 self.build(dictionary=d)186 self.setTearDownCleanup(d)187 188 evil_var = "INIT*MIDDLE}TAIL"189 190 target = self.createTestTarget()191 main_source_spec = lldb.SBFileSpec(source)192 breakpoint = target.BreakpointCreateBySourceRegex(193 "// Set breakpoint here.", main_source_spec194 )195 196 process = target.LaunchSimple(197 None, ["EVIL=" + evil_var], self.get_process_working_directory()198 )199 self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)200 201 threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint)202 self.assertEqual(len(threads), 1)203 frame = threads[0].GetFrameAtIndex(0)204 sbvalue = frame.EvaluateExpression("evil")205 value = sbvalue.GetSummary().strip('"')206 207 self.assertEqual(value, evil_var)208 process.Continue()209 self.assertState(process.GetState(), lldb.eStateExited, PROCESS_EXITED)210 211 @skipIfRemote212 def test_target_launch_working_dir_prop(self):213 """Test that the setting `target.launch-working-dir` is correctly used when launching a process."""214 d = {"CXX_SOURCES": "print_cwd.cpp"}215 self.build(dictionary=d)216 self.setTearDownCleanup(d)217 exe = self.getBuildArtifact("a.out")218 self.runCmd("file " + exe)219 220 mywd = "my_working_dir"221 out_file_name = "my_working_dir_test.out"222 223 my_working_dir_path = Path(self.getBuildArtifact(mywd)).resolve()224 lldbutil.mkdir_p(my_working_dir_path)225 out_file_path = os.path.join(my_working_dir_path, out_file_name)226 another_working_dir_path = Path(227 os.path.join(my_working_dir_path, "..")228 ).resolve()229 230 # If -w is not passed to process launch, then the setting will be used.231 self.runCmd(232 f"settings set target.launch-working-dir {another_working_dir_path}"233 )234 launch_command = f"process launch -o {out_file_path}"235 236 self.expect(237 launch_command,238 patterns=["Process .* launched: .*a.out"],239 )240 241 out = lldbutil.read_file_on_target(self, out_file_path)242 243 self.assertIn(f"stdout: {another_working_dir_path}", out)244 245 # If -w is passed to process launch, that value will be used instead of the setting.246 launch_command = f"process launch -w {my_working_dir_path} -o {out_file_path}"247 248 self.expect(249 launch_command,250 patterns=["Process .* launched: .*a.out"],251 )252 253 out = lldbutil.read_file_on_target(self, out_file_path)254 self.assertIn(f"stdout: {my_working_dir_path}", out)255 256 # If set to empty, then LLDB's cwd will be used to launch the process.257 self.runCmd(f"settings set target.launch-working-dir ''")258 launch_command = f"process launch -o {out_file_path}"259 260 self.expect(261 launch_command,262 patterns=["Process .* launched: .*a.out"],263 )264 265 out = lldbutil.read_file_on_target(self, out_file_path)266 self.assertNotIn(f"stdout: {another_working_dir_path}", out)267