blob: b841b2c066a3ebe85b215173d39d0055d30f581d [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
Todd Fiala2850b1b2014-06-30 23:51:35 +000010#include "lldb/Host/Config.h"
11
Greg Clayton8012cad2014-11-17 19:39:20 +000012#include "lldb/Core/Debugger.h"
Todd Fiala75f47c32014-10-11 21:42:09 +000013#include "lldb/Core/Log.h"
Zachary Turner696b5282014-08-14 16:01:25 +000014#include "lldb/Target/ProcessLaunchInfo.h"
15#include "lldb/Target/FileAction.h"
Todd Fiala6d6b55d2014-06-30 00:30:53 +000016#include "lldb/Target/Target.h"
17
18using namespace lldb;
19using namespace lldb_private;
20
21//----------------------------------------------------------------------------
Todd Fiala6d6b55d2014-06-30 00:30:53 +000022// ProcessLaunchInfo member functions
23//----------------------------------------------------------------------------
24
25ProcessLaunchInfo::ProcessLaunchInfo () :
26 ProcessInfo(),
27 m_working_dir (),
28 m_plugin_name (),
Todd Fiala6d6b55d2014-06-30 00:30:53 +000029 m_flags (0),
30 m_file_actions (),
Zachary Turner44e442b2014-09-12 22:38:39 +000031 m_pty (new lldb_utility::PseudoTerminal),
Todd Fiala6d6b55d2014-06-30 00:30:53 +000032 m_resume_count (0),
33 m_monitor_callback (NULL),
34 m_monitor_callback_baton (NULL),
35 m_monitor_signals (false),
Greg Clayton8012cad2014-11-17 19:39:20 +000036 m_listener_sp (),
Todd Fiala6d6b55d2014-06-30 00:30:53 +000037 m_hijack_listener_sp ()
38{
39}
40
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000041ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path,
Zachary Turnercf3f3682014-09-12 23:10:33 +000042 const char *working_directory, uint32_t launch_flags) :
43 ProcessInfo(),
44 m_working_dir(),
45 m_plugin_name(),
Zachary Turnercf3f3682014-09-12 23:10:33 +000046 m_flags(launch_flags),
47 m_file_actions(),
48 m_pty(new lldb_utility::PseudoTerminal),
49 m_resume_count(0),
50 m_monitor_callback(NULL),
51 m_monitor_callback_baton(NULL),
52 m_monitor_signals(false),
Greg Clayton8012cad2014-11-17 19:39:20 +000053 m_listener_sp (),
Zachary Turnercf3f3682014-09-12 23:10:33 +000054 m_hijack_listener_sp()
Todd Fiala6d6b55d2014-06-30 00:30:53 +000055{
56 if (stdin_path)
57 {
Zachary Turner696b5282014-08-14 16:01:25 +000058 FileAction file_action;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000059 const bool read = true;
60 const bool write = false;
61 if (file_action.Open(STDIN_FILENO, stdin_path, read, write))
62 AppendFileAction (file_action);
63 }
64 if (stdout_path)
65 {
Zachary Turner696b5282014-08-14 16:01:25 +000066 FileAction file_action;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000067 const bool read = false;
68 const bool write = true;
69 if (file_action.Open(STDOUT_FILENO, stdout_path, read, write))
70 AppendFileAction (file_action);
71 }
72 if (stderr_path)
73 {
Zachary Turner696b5282014-08-14 16:01:25 +000074 FileAction file_action;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000075 const bool read = false;
76 const bool write = true;
77 if (file_action.Open(STDERR_FILENO, stderr_path, read, write))
78 AppendFileAction (file_action);
79 }
80 if (working_directory)
81 SetWorkingDirectory(working_directory);
82}
83
84bool
85ProcessLaunchInfo::AppendCloseFileAction (int fd)
86{
87 FileAction file_action;
88 if (file_action.Close (fd))
89 {
90 AppendFileAction (file_action);
91 return true;
92 }
93 return false;
94}
95
96bool
97ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd)
98{
99 FileAction file_action;
100 if (file_action.Duplicate (fd, dup_fd))
101 {
102 AppendFileAction (file_action);
103 return true;
104 }
105 return false;
106}
107
108bool
109ProcessLaunchInfo::AppendOpenFileAction (int fd, const char *path, bool read, bool write)
110{
111 FileAction file_action;
112 if (file_action.Open (fd, path, read, write))
113 {
114 AppendFileAction (file_action);
115 return true;
116 }
117 return false;
118}
119
120bool
121ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write)
122{
123 FileAction file_action;
124 if (file_action.Open (fd, "/dev/null", read, write))
125 {
126 AppendFileAction (file_action);
127 return true;
128 }
129 return false;
130}
131
Zachary Turner696b5282014-08-14 16:01:25 +0000132const FileAction *
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000133ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000134{
135 if (idx < m_file_actions.size())
136 return &m_file_actions[idx];
137 return NULL;
138}
139
Zachary Turner696b5282014-08-14 16:01:25 +0000140const FileAction *
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000141ProcessLaunchInfo::GetFileActionForFD(int fd) const
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000142{
143 for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx)
144 {
145 if (m_file_actions[idx].GetFD () == fd)
146 return &m_file_actions[idx];
147 }
148 return NULL;
149}
150
151const char *
152ProcessLaunchInfo::GetWorkingDirectory () const
153{
154 if (m_working_dir.empty())
155 return NULL;
156 return m_working_dir.c_str();
157}
158
159void
160ProcessLaunchInfo::SetWorkingDirectory (const char *working_dir)
161{
162 if (working_dir && working_dir[0])
163 m_working_dir.assign (working_dir);
164 else
165 m_working_dir.clear();
166}
167
168const char *
169ProcessLaunchInfo::GetProcessPluginName () const
170{
171 if (m_plugin_name.empty())
172 return NULL;
173 return m_plugin_name.c_str();
174}
175
176void
177ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
178{
179 if (plugin && plugin[0])
180 m_plugin_name.assign (plugin);
181 else
182 m_plugin_name.clear();
183}
184
Zachary Turner10687b02014-10-20 17:46:43 +0000185const FileSpec &
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000186ProcessLaunchInfo::GetShell () const
187{
Zachary Turner10687b02014-10-20 17:46:43 +0000188 return m_shell;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000189}
190
191void
Zachary Turner10687b02014-10-20 17:46:43 +0000192ProcessLaunchInfo::SetShell (const FileSpec &shell)
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000193{
Zachary Turner10687b02014-10-20 17:46:43 +0000194 m_shell = shell;
195 if (m_shell)
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000196 {
Zachary Turner10687b02014-10-20 17:46:43 +0000197 m_shell.ResolveExecutableLocation();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000198 m_flags.Set (lldb::eLaunchFlagLaunchInShell);
199 }
200 else
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000201 m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000202}
203
204void
205ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate)
206{
207 if (separate)
208 m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
209 else
210 m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
211
212}
213
214void
215ProcessLaunchInfo::Clear ()
216{
217 ProcessInfo::Clear();
218 m_working_dir.clear();
219 m_plugin_name.clear();
Zachary Turner10687b02014-10-20 17:46:43 +0000220 m_shell.Clear();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000221 m_flags.Clear();
222 m_file_actions.clear();
223 m_resume_count = 0;
Greg Clayton8012cad2014-11-17 19:39:20 +0000224 m_listener_sp.reset();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000225 m_hijack_listener_sp.reset();
226}
227
228void
229ProcessLaunchInfo::SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
230 void *baton,
231 bool monitor_signals)
232{
233 m_monitor_callback = callback;
234 m_monitor_callback_baton = baton;
235 m_monitor_signals = monitor_signals;
236}
237
238bool
239ProcessLaunchInfo::MonitorProcess () const
240{
241 if (m_monitor_callback && ProcessIDIsValid())
242 {
243 Host::StartMonitoringChildProcess (m_monitor_callback,
244 m_monitor_callback_baton,
245 GetProcessID(),
246 m_monitor_signals);
247 return true;
248 }
249 return false;
250}
251
252void
253ProcessLaunchInfo::SetDetachOnError (bool enable)
254{
255 if (enable)
256 m_flags.Set(lldb::eLaunchFlagDetachOnError);
257 else
258 m_flags.Clear(lldb::eLaunchFlagDetachOnError);
259}
260
261void
262ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
263{
Todd Fiala75f47c32014-10-11 21:42:09 +0000264 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
265
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000266 // If nothing for stdin or stdout or stderr was specified, then check the process for any default
267 // settings that were set with "settings set"
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000268 if (GetFileActionForFD(STDIN_FILENO) == NULL ||
269 GetFileActionForFD(STDOUT_FILENO) == NULL ||
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000270 GetFileActionForFD(STDERR_FILENO) == NULL)
271 {
Todd Fiala75f47c32014-10-11 21:42:09 +0000272 if (log)
273 log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
274 __FUNCTION__);
275
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000276 if (m_flags.Test(eLaunchFlagDisableSTDIO))
277 {
Todd Fiala75f47c32014-10-11 21:42:09 +0000278 if (log)
279 log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
280 __FUNCTION__);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000281 AppendSuppressFileAction (STDIN_FILENO , true, false);
282 AppendSuppressFileAction (STDOUT_FILENO, false, true);
283 AppendSuppressFileAction (STDERR_FILENO, false, true);
284 }
285 else
286 {
287 // Check for any values that might have gotten set with any of:
288 // (lldb) settings set target.input-path
289 // (lldb) settings set target.output-path
290 // (lldb) settings set target.error-path
291 FileSpec in_path;
292 FileSpec out_path;
293 FileSpec err_path;
294 if (target)
295 {
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000296 // Only override with the target settings if we don't already have
297 // an action for in, out or error
298 if (GetFileActionForFD(STDIN_FILENO) == NULL)
299 in_path = target->GetStandardInputPath();
300 if (GetFileActionForFD(STDOUT_FILENO) == NULL)
301 out_path = target->GetStandardOutputPath();
302 if (GetFileActionForFD(STDERR_FILENO) == NULL)
303 err_path = target->GetStandardErrorPath();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000304 }
305
Todd Fiala75f47c32014-10-11 21:42:09 +0000306 if (log)
307 log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'",
308 __FUNCTION__,
309 in_path ? in_path.GetPath().c_str () : "<null>",
310 out_path ? out_path.GetPath().c_str () : "<null>",
311 err_path ? err_path.GetPath().c_str () : "<null>");
312
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000313 char path[PATH_MAX];
314 if (in_path && in_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000315 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000316 AppendOpenFileAction(STDIN_FILENO, path, true, false);
Todd Fiala75f47c32014-10-11 21:42:09 +0000317 if (log)
318 log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
319 __FUNCTION__,
320 in_path.GetPath().c_str ());
321 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000322
323 if (out_path && out_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000324 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000325 AppendOpenFileAction(STDOUT_FILENO, path, false, true);
Todd Fiala75f47c32014-10-11 21:42:09 +0000326 if (log)
327 log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
328 __FUNCTION__,
329 out_path.GetPath().c_str ());
330 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000331
332 if (err_path && err_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000333 {
334 if (log)
335 log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
336 __FUNCTION__,
337 err_path.GetPath().c_str ());
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000338 AppendOpenFileAction(STDERR_FILENO, path, false, true);
Todd Fiala75f47c32014-10-11 21:42:09 +0000339 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000340
Todd Fiala75f47c32014-10-11 21:42:09 +0000341 if (default_to_use_pty && (!in_path || !out_path || !err_path))
342 {
343 if (log)
344 log->Printf ("ProcessLaunchInfo::%s default_to_use_pty is set, and at least one stdin/stderr/stdout is unset, so generating a pty to use for it",
345 __FUNCTION__);
346
Zachary Turner362a8132015-02-04 19:11:48 +0000347 int open_flags = O_RDWR | O_NOCTTY;
348#if !defined(_MSC_VER)
349 // We really shouldn't be specifying platform specific flags
350 // that are intended for a system call in generic code. But
351 // this will have to do for now.
352 open_flags |= O_CLOEXEC;
353#endif
354 if (m_pty->OpenFirstAvailableMaster(open_flags, NULL, 0))
Todd Fiala75f47c32014-10-11 21:42:09 +0000355 {
Zachary Turner44e442b2014-09-12 22:38:39 +0000356 const char *slave_path = m_pty->GetSlaveName(NULL, 0);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000357
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000358 // Only use the slave tty if we don't have anything specified for
359 // input and don't have an action for stdin
360 if (!in_path && GetFileActionForFD(STDIN_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000361 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000362 AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
363 }
364
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000365 // Only use the slave tty if we don't have anything specified for
366 // output and don't have an action for stdout
367 if (!out_path && GetFileActionForFD(STDOUT_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000368 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000369 AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
370 }
371
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000372 // Only use the slave tty if we don't have anything specified for
373 // error and don't have an action for stderr
374 if (!err_path && GetFileActionForFD(STDERR_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000375 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000376 AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
377 }
378 }
379 }
380 }
381 }
382}
383
384
385bool
386ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
387 bool localhost,
388 bool will_debug,
389 bool first_arg_is_full_shell_command,
390 int32_t num_resumes)
391{
392 error.Clear();
393
394 if (GetFlags().Test (eLaunchFlagLaunchInShell))
395 {
Zachary Turner10687b02014-10-20 17:46:43 +0000396 if (m_shell)
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000397 {
Zachary Turner10687b02014-10-20 17:46:43 +0000398 std::string shell_executable = m_shell.GetPath();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000399
400 const char **argv = GetArguments().GetConstArgumentVector ();
401 if (argv == NULL || argv[0] == NULL)
402 return false;
403 Args shell_arguments;
404 std::string safe_arg;
Zachary Turner10687b02014-10-20 17:46:43 +0000405 shell_arguments.AppendArgument (shell_executable.c_str());
Zachary Turner270e99a2014-12-08 21:36:42 +0000406 const llvm::Triple &triple = GetArchitecture().GetTriple();
407 if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment())
408 shell_arguments.AppendArgument("/C");
409 else
410 shell_arguments.AppendArgument("-c");
411
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000412 StreamString shell_command;
413 if (will_debug)
414 {
415 // Add a modified PATH environment variable in case argv[0]
Zachary Turner270e99a2014-12-08 21:36:42 +0000416 // is a relative path.
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000417 const char *argv0 = argv[0];
Zachary Turner270e99a2014-12-08 21:36:42 +0000418 FileSpec arg_spec(argv0, false);
419 if (arg_spec.IsRelativeToCurrentWorkingDirectory())
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000420 {
421 // We have a relative path to our executable which may not work if
422 // we just try to run "a.out" (without it being converted to "./a.out")
423 const char *working_dir = GetWorkingDirectory();
424 // Be sure to put quotes around PATH's value in case any paths have spaces...
425 std::string new_path("PATH=\"");
426 const size_t empty_path_len = new_path.size();
427
428 if (working_dir && working_dir[0])
429 {
430 new_path += working_dir;
431 }
432 else
433 {
434 char current_working_dir[PATH_MAX];
435 const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
436 if (cwd && cwd[0])
437 new_path += cwd;
438 }
439 const char *curr_path = getenv("PATH");
440 if (curr_path)
441 {
442 if (new_path.size() > empty_path_len)
443 new_path += ':';
444 new_path += curr_path;
445 }
446 new_path += "\" ";
447 shell_command.PutCString(new_path.c_str());
448 }
449
Zachary Turner270e99a2014-12-08 21:36:42 +0000450 if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
451 shell_command.PutCString("exec");
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000452
453 // Only Apple supports /usr/bin/arch being able to specify the architecture
Greg Claytonbc766682014-08-12 21:38:59 +0000454 if (GetArchitecture().IsValid() && // Valid architecture
455 GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only
456 GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000457 {
458 shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
459 // Set the resume count to 2:
460 // 1 - stop in shell
461 // 2 - stop in /usr/bin/arch
462 // 3 - then we will stop in our program
463 SetResumeCount(num_resumes + 1);
464 }
465 else
466 {
467 // Set the resume count to 1:
468 // 1 - stop in shell
469 // 2 - then we will stop in our program
470 SetResumeCount(num_resumes);
471 }
472 }
473
474 if (first_arg_is_full_shell_command)
475 {
476 // There should only be one argument that is the shell command itself to be used as is
477 if (argv[0] && !argv[1])
478 shell_command.Printf("%s", argv[0]);
479 else
480 return false;
481 }
482 else
483 {
484 for (size_t i=0; argv[i] != NULL; ++i)
485 {
486 const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
487 shell_command.Printf(" %s", arg);
488 }
489 }
490 shell_arguments.AppendArgument (shell_command.GetString().c_str());
Zachary Turner10687b02014-10-20 17:46:43 +0000491 m_executable = m_shell;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000492 m_arguments = shell_arguments;
493 return true;
494 }
495 else
496 {
497 error.SetErrorString ("invalid shell path");
498 }
499 }
500 else
501 {
502 error.SetErrorString ("not launching in shell");
503 }
504 return false;
505}
Greg Clayton8012cad2014-11-17 19:39:20 +0000506
507Listener &
508ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
509{
510 if (m_listener_sp)
511 return *m_listener_sp;
512 else
513 return debugger.GetListener();
514}