blob: 334a43eb9c1190ae18b5a295efe76b2c7315037c [file] [log] [blame]
Todd Fiala6d6b55d2014-06-30 00:30:53 +00001//===-- ProcessLaunchInfo.cpp -----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Eugene Zelenko9394d7722016-02-18 00:10:17 +000010// C Includes
11// C++ Includes
12#include <climits>
Todd Fiala2850b1b2014-06-30 23:51:35 +000013
Eugene Zelenko9394d7722016-02-18 00:10:17 +000014// Other libraries and framework includes
15// Project includes
Greg Clayton8012cad2014-11-17 19:39:20 +000016#include "lldb/Core/Debugger.h"
Todd Fiala75f47c32014-10-11 21:42:09 +000017#include "lldb/Core/Log.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000018#include "lldb/Host/Config.h"
Zachary Turner4eff2d32015-10-14 21:37:36 +000019#include "lldb/Host/FileSystem.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000020#include "lldb/Host/HostInfo.h"
Zachary Turner696b5282014-08-14 16:01:25 +000021#include "lldb/Target/FileAction.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000022#include "lldb/Target/ProcessLaunchInfo.h"
Todd Fiala6d6b55d2014-06-30 00:30:53 +000023#include "lldb/Target/Target.h"
24
Zachary Turner190fadc2016-03-22 17:58:09 +000025#include "llvm/Support/ConvertUTF.h"
Pavel Labath1d5855b2017-01-23 15:56:45 +000026#include "llvm/Support/FileSystem.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000027
28#if !defined(_WIN32)
29#include <limits.h>
30#endif
31
Todd Fiala6d6b55d2014-06-30 00:30:53 +000032using namespace lldb;
33using namespace lldb_private;
34
35//----------------------------------------------------------------------------
Todd Fiala6d6b55d2014-06-30 00:30:53 +000036// ProcessLaunchInfo member functions
37//----------------------------------------------------------------------------
38
Kate Stoneb9c1b512016-09-06 20:57:50 +000039ProcessLaunchInfo::ProcessLaunchInfo()
40 : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0),
41 m_file_actions(), m_pty(new lldb_utility::PseudoTerminal),
42 m_resume_count(0), m_monitor_callback(nullptr),
43 m_monitor_callback_baton(nullptr), m_monitor_signals(false),
44 m_listener_sp(), m_hijack_listener_sp() {}
Todd Fiala6d6b55d2014-06-30 00:30:53 +000045
Chaoren Lind3173f32015-05-29 19:52:29 +000046ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,
47 const FileSpec &stdout_file_spec,
48 const FileSpec &stderr_file_spec,
49 const FileSpec &working_directory,
Kate Stoneb9c1b512016-09-06 20:57:50 +000050 uint32_t launch_flags)
51 : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags),
52 m_file_actions(), m_pty(new lldb_utility::PseudoTerminal),
53 m_resume_count(0), m_monitor_callback(nullptr),
54 m_monitor_callback_baton(nullptr), m_monitor_signals(false),
55 m_listener_sp(), m_hijack_listener_sp() {
56 if (stdin_file_spec) {
Todd Fiala6d6b55d2014-06-30 00:30:53 +000057 FileAction file_action;
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 const bool read = true;
59 const bool write = false;
60 if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))
61 AppendFileAction(file_action);
62 }
63 if (stdout_file_spec) {
Todd Fiala6d6b55d2014-06-30 00:30:53 +000064 FileAction file_action;
Kate Stoneb9c1b512016-09-06 20:57:50 +000065 const bool read = false;
66 const bool write = true;
67 if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))
68 AppendFileAction(file_action);
69 }
70 if (stderr_file_spec) {
Todd Fiala6d6b55d2014-06-30 00:30:53 +000071 FileAction file_action;
Kate Stoneb9c1b512016-09-06 20:57:50 +000072 const bool read = false;
73 const bool write = true;
74 if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))
75 AppendFileAction(file_action);
76 }
77 if (working_directory)
78 SetWorkingDirectory(working_directory);
Todd Fiala6d6b55d2014-06-30 00:30:53 +000079}
80
Kate Stoneb9c1b512016-09-06 20:57:50 +000081bool ProcessLaunchInfo::AppendCloseFileAction(int fd) {
82 FileAction file_action;
83 if (file_action.Close(fd)) {
84 AppendFileAction(file_action);
85 return true;
86 }
87 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000088}
89
Kate Stoneb9c1b512016-09-06 20:57:50 +000090bool ProcessLaunchInfo::AppendDuplicateFileAction(int fd, int dup_fd) {
91 FileAction file_action;
92 if (file_action.Duplicate(fd, dup_fd)) {
93 AppendFileAction(file_action);
94 return true;
95 }
96 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000097}
98
Kate Stoneb9c1b512016-09-06 20:57:50 +000099bool ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,
100 bool read, bool write) {
101 FileAction file_action;
102 if (file_action.Open(fd, file_spec, read, write)) {
103 AppendFileAction(file_action);
104 return true;
105 }
106 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000107}
108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109bool ProcessLaunchInfo::AppendSuppressFileAction(int fd, bool read,
110 bool write) {
111 FileAction file_action;
112 if (file_action.Open(fd, FileSpec{FileSystem::DEV_NULL, false}, read,
113 write)) {
114 AppendFileAction(file_action);
115 return true;
116 }
117 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000118}
119
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120const FileAction *ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const {
121 if (idx < m_file_actions.size())
122 return &m_file_actions[idx];
123 return nullptr;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000124}
125
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126const FileAction *ProcessLaunchInfo::GetFileActionForFD(int fd) const {
127 for (size_t idx = 0, count = m_file_actions.size(); idx < count; ++idx) {
128 if (m_file_actions[idx].GetFD() == fd)
129 return &m_file_actions[idx];
130 }
131 return nullptr;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000132}
133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134const FileSpec &ProcessLaunchInfo::GetWorkingDirectory() const {
135 return m_working_dir;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000136}
137
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138void ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir) {
139 m_working_dir = working_dir;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000140}
141
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142const char *ProcessLaunchInfo::GetProcessPluginName() const {
143 return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str());
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000144}
145
Zachary Turnerfe114832016-11-12 16:56:47 +0000146void ProcessLaunchInfo::SetProcessPluginName(llvm::StringRef plugin) {
147 m_plugin_name = plugin;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000148}
149
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150const FileSpec &ProcessLaunchInfo::GetShell() const { return m_shell; }
151
152void ProcessLaunchInfo::SetShell(const FileSpec &shell) {
153 m_shell = shell;
154 if (m_shell) {
155 m_shell.ResolveExecutableLocation();
156 m_flags.Set(lldb::eLaunchFlagLaunchInShell);
157 } else
158 m_flags.Clear(lldb::eLaunchFlagLaunchInShell);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000159}
160
Kate Stoneb9c1b512016-09-06 20:57:50 +0000161void ProcessLaunchInfo::SetLaunchInSeparateProcessGroup(bool separate) {
162 if (separate)
163 m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
164 else
165 m_flags.Clear(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
166}
167
168void ProcessLaunchInfo::SetShellExpandArguments(bool expand) {
169 if (expand)
170 m_flags.Set(lldb::eLaunchFlagShellExpandArguments);
171 else
172 m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);
173}
174
175void ProcessLaunchInfo::Clear() {
176 ProcessInfo::Clear();
177 m_working_dir.Clear();
178 m_plugin_name.clear();
179 m_shell.Clear();
180 m_flags.Clear();
181 m_file_actions.clear();
182 m_resume_count = 0;
183 m_listener_sp.reset();
184 m_hijack_listener_sp.reset();
185}
186
187void ProcessLaunchInfo::SetMonitorProcessCallback(
188 const Host::MonitorChildProcessCallback &callback, bool monitor_signals) {
189 m_monitor_callback = callback;
190 m_monitor_signals = monitor_signals;
191}
192
193bool ProcessLaunchInfo::MonitorProcess() const {
194 if (m_monitor_callback && ProcessIDIsValid()) {
195 Host::StartMonitoringChildProcess(m_monitor_callback, GetProcessID(),
196 m_monitor_signals);
197 return true;
198 }
199 return false;
200}
201
202void ProcessLaunchInfo::SetDetachOnError(bool enable) {
203 if (enable)
204 m_flags.Set(lldb::eLaunchFlagDetachOnError);
205 else
206 m_flags.Clear(lldb::eLaunchFlagDetachOnError);
207}
208
209void ProcessLaunchInfo::FinalizeFileActions(Target *target,
210 bool default_to_use_pty) {
211 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
212
213 // If nothing for stdin or stdout or stderr was specified, then check the
214 // process for any default
215 // settings that were set with "settings set"
216 if (GetFileActionForFD(STDIN_FILENO) == nullptr ||
217 GetFileActionForFD(STDOUT_FILENO) == nullptr ||
218 GetFileActionForFD(STDERR_FILENO) == nullptr) {
219 if (log)
220 log->Printf("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr "
221 "was not set, evaluating default handling",
222 __FUNCTION__);
223
224 if (m_flags.Test(eLaunchFlagLaunchInTTY)) {
225 // Do nothing, if we are launching in a remote terminal
226 // no file actions should be done at all.
227 return;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000228 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000229
Kate Stoneb9c1b512016-09-06 20:57:50 +0000230 if (m_flags.Test(eLaunchFlagDisableSTDIO)) {
231 if (log)
232 log->Printf("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding "
233 "suppression action for stdin, stdout and stderr",
234 __FUNCTION__);
235 AppendSuppressFileAction(STDIN_FILENO, true, false);
236 AppendSuppressFileAction(STDOUT_FILENO, false, true);
237 AppendSuppressFileAction(STDERR_FILENO, false, true);
238 } else {
239 // Check for any values that might have gotten set with any of:
240 // (lldb) settings set target.input-path
241 // (lldb) settings set target.output-path
242 // (lldb) settings set target.error-path
243 FileSpec in_file_spec;
244 FileSpec out_file_spec;
245 FileSpec err_file_spec;
246 if (target) {
247 // Only override with the target settings if we don't already have
248 // an action for in, out or error
249 if (GetFileActionForFD(STDIN_FILENO) == nullptr)
250 in_file_spec = target->GetStandardInputPath();
251 if (GetFileActionForFD(STDOUT_FILENO) == nullptr)
252 out_file_spec = target->GetStandardOutputPath();
253 if (GetFileActionForFD(STDERR_FILENO) == nullptr)
254 err_file_spec = target->GetStandardErrorPath();
255 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000256
Kate Stoneb9c1b512016-09-06 20:57:50 +0000257 if (log)
258 log->Printf("ProcessLaunchInfo::%s target stdin='%s', target "
259 "stdout='%s', stderr='%s'",
260 __FUNCTION__,
261 in_file_spec ? in_file_spec.GetCString() : "<null>",
262 out_file_spec ? out_file_spec.GetCString() : "<null>",
263 err_file_spec ? err_file_spec.GetCString() : "<null>");
Todd Fiala75f47c32014-10-11 21:42:09 +0000264
Kate Stoneb9c1b512016-09-06 20:57:50 +0000265 if (in_file_spec) {
266 AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false);
Todd Fiala75f47c32014-10-11 21:42:09 +0000267 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000268 log->Printf(
269 "ProcessLaunchInfo::%s appended stdin open file action for %s",
270 __FUNCTION__, in_file_spec.GetCString());
271 }
Todd Fiala75f47c32014-10-11 21:42:09 +0000272
Kate Stoneb9c1b512016-09-06 20:57:50 +0000273 if (out_file_spec) {
274 AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true);
275 if (log)
276 log->Printf(
277 "ProcessLaunchInfo::%s appended stdout open file action for %s",
278 __FUNCTION__, out_file_spec.GetCString());
279 }
Greg Claytonbf91f712015-07-10 18:04:46 +0000280
Kate Stoneb9c1b512016-09-06 20:57:50 +0000281 if (err_file_spec) {
282 AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true);
283 if (log)
284 log->Printf(
285 "ProcessLaunchInfo::%s appended stderr open file action for %s",
286 __FUNCTION__, err_file_spec.GetCString());
287 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000288
Kate Stoneb9c1b512016-09-06 20:57:50 +0000289 if (default_to_use_pty &&
290 (!in_file_spec || !out_file_spec || !err_file_spec)) {
291 if (log)
292 log->Printf("ProcessLaunchInfo::%s default_to_use_pty is set, and at "
293 "least one stdin/stderr/stdout is unset, so generating a "
294 "pty to use for it",
295 __FUNCTION__);
Todd Fiala75f47c32014-10-11 21:42:09 +0000296
Kate Stoneb9c1b512016-09-06 20:57:50 +0000297 int open_flags = O_RDWR | O_NOCTTY;
Hafiz Abid Qadeerf6ee79c2016-12-15 15:00:41 +0000298#if !defined(_WIN32)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000299 // We really shouldn't be specifying platform specific flags
300 // that are intended for a system call in generic code. But
301 // this will have to do for now.
302 open_flags |= O_CLOEXEC;
Zachary Turner362a8132015-02-04 19:11:48 +0000303#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 if (m_pty->OpenFirstAvailableMaster(open_flags, nullptr, 0)) {
305 const FileSpec slave_file_spec{m_pty->GetSlaveName(nullptr, 0),
306 false};
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000307
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308 // Only use the slave tty if we don't have anything specified for
309 // input and don't have an action for stdin
310 if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == nullptr) {
311 AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false);
312 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000313
Kate Stoneb9c1b512016-09-06 20:57:50 +0000314 // Only use the slave tty if we don't have anything specified for
315 // output and don't have an action for stdout
316 if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == nullptr) {
317 AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true);
318 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000319
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320 // Only use the slave tty if we don't have anything specified for
321 // error and don't have an action for stderr
322 if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == nullptr) {
323 AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true);
324 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000325 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000326 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000327 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000328 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000329}
330
Kate Stoneb9c1b512016-09-06 20:57:50 +0000331bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell(
332 Error &error, bool localhost, bool will_debug,
333 bool first_arg_is_full_shell_command, int32_t num_resumes) {
334 error.Clear();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000335
Kate Stoneb9c1b512016-09-06 20:57:50 +0000336 if (GetFlags().Test(eLaunchFlagLaunchInShell)) {
337 if (m_shell) {
338 std::string shell_executable = m_shell.GetPath();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000339
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340 const char **argv = GetArguments().GetConstArgumentVector();
341 if (argv == nullptr || argv[0] == nullptr)
342 return false;
343 Args shell_arguments;
344 std::string safe_arg;
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000345 shell_arguments.AppendArgument(shell_executable);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000346 const llvm::Triple &triple = GetArchitecture().GetTriple();
347 if (triple.getOS() == llvm::Triple::Win32 &&
348 !triple.isWindowsCygwinEnvironment())
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000349 shell_arguments.AppendArgument(llvm::StringRef("/C"));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000350 else
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000351 shell_arguments.AppendArgument(llvm::StringRef("-c"));
Zachary Turner270e99a2014-12-08 21:36:42 +0000352
Kate Stoneb9c1b512016-09-06 20:57:50 +0000353 StreamString shell_command;
354 if (will_debug) {
355 // Add a modified PATH environment variable in case argv[0]
356 // is a relative path.
357 const char *argv0 = argv[0];
358 FileSpec arg_spec(argv0, false);
359 if (arg_spec.IsRelative()) {
360 // We have a relative path to our executable which may not work if
361 // we just try to run "a.out" (without it being converted to
362 // "./a.out")
363 FileSpec working_dir = GetWorkingDirectory();
364 // Be sure to put quotes around PATH's value in case any paths have
365 // spaces...
366 std::string new_path("PATH=\"");
367 const size_t empty_path_len = new_path.size();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000368
Kate Stoneb9c1b512016-09-06 20:57:50 +0000369 if (working_dir) {
370 new_path += working_dir.GetPath();
371 } else {
Pavel Labath1d5855b2017-01-23 15:56:45 +0000372 llvm::SmallString<64> cwd;
373 if (! llvm::sys::fs::current_path(cwd))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000374 new_path += cwd;
375 }
376 std::string curr_path;
377 if (HostInfo::GetEnvironmentVar("PATH", curr_path)) {
378 if (new_path.size() > empty_path_len)
379 new_path += ':';
380 new_path += curr_path;
381 }
382 new_path += "\" ";
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000383 shell_command.PutCString(new_path);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000384 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000385
386 if (triple.getOS() != llvm::Triple::Win32 ||
387 triple.isWindowsCygwinEnvironment())
388 shell_command.PutCString("exec");
389
390 // Only Apple supports /usr/bin/arch being able to specify the
391 // architecture
392 if (GetArchitecture().IsValid() && // Valid architecture
393 GetArchitecture().GetTriple().getVendor() ==
394 llvm::Triple::Apple && // Apple only
395 GetArchitecture().GetCore() !=
396 ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
397 {
398 shell_command.Printf(" /usr/bin/arch -arch %s",
399 GetArchitecture().GetArchitectureName());
400 // Set the resume count to 2:
401 // 1 - stop in shell
402 // 2 - stop in /usr/bin/arch
403 // 3 - then we will stop in our program
404 SetResumeCount(num_resumes + 1);
405 } else {
406 // Set the resume count to 1:
407 // 1 - stop in shell
408 // 2 - then we will stop in our program
409 SetResumeCount(num_resumes);
410 }
411 }
412
413 if (first_arg_is_full_shell_command) {
414 // There should only be one argument that is the shell command itself to
415 // be used as is
416 if (argv[0] && !argv[1])
417 shell_command.Printf("%s", argv[0]);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000418 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000419 return false;
420 } else {
421 for (size_t i = 0; argv[i] != nullptr; ++i) {
422 const char *arg =
423 Args::GetShellSafeArgument(m_shell, argv[i], safe_arg);
424 shell_command.Printf(" %s", arg);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000425 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000426 }
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000427 shell_arguments.AppendArgument(shell_command.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000428 m_executable = m_shell;
429 m_arguments = shell_arguments;
430 return true;
431 } else {
432 error.SetErrorString("invalid shell path");
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000433 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000434 } else {
435 error.SetErrorString("not launching in shell");
436 }
437 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000438}
Greg Clayton8012cad2014-11-17 19:39:20 +0000439
Kate Stoneb9c1b512016-09-06 20:57:50 +0000440ListenerSP ProcessLaunchInfo::GetListenerForProcess(Debugger &debugger) {
441 if (m_listener_sp)
442 return m_listener_sp;
443 else
444 return debugger.GetListener();
Greg Clayton8012cad2014-11-17 19:39:20 +0000445}