blob: 3f22a4ea0184e9e0a50225108ba60096868e449e [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
Pavel Labath493c3a12015-02-04 10:36:57 +0000347 if (m_pty->OpenFirstAvailableMaster(O_RDWR | O_NOCTTY | O_CLOEXEC, NULL, 0))
Todd Fiala75f47c32014-10-11 21:42:09 +0000348 {
Zachary Turner44e442b2014-09-12 22:38:39 +0000349 const char *slave_path = m_pty->GetSlaveName(NULL, 0);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000350
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000351 // Only use the slave tty if we don't have anything specified for
352 // input and don't have an action for stdin
353 if (!in_path && GetFileActionForFD(STDIN_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000354 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000355 AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
356 }
357
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000358 // Only use the slave tty if we don't have anything specified for
359 // output and don't have an action for stdout
360 if (!out_path && GetFileActionForFD(STDOUT_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000361 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000362 AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
363 }
364
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000365 // Only use the slave tty if we don't have anything specified for
366 // error and don't have an action for stderr
367 if (!err_path && GetFileActionForFD(STDERR_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000368 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000369 AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
370 }
371 }
372 }
373 }
374 }
375}
376
377
378bool
379ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
380 bool localhost,
381 bool will_debug,
382 bool first_arg_is_full_shell_command,
383 int32_t num_resumes)
384{
385 error.Clear();
386
387 if (GetFlags().Test (eLaunchFlagLaunchInShell))
388 {
Zachary Turner10687b02014-10-20 17:46:43 +0000389 if (m_shell)
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000390 {
Zachary Turner10687b02014-10-20 17:46:43 +0000391 std::string shell_executable = m_shell.GetPath();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000392
393 const char **argv = GetArguments().GetConstArgumentVector ();
394 if (argv == NULL || argv[0] == NULL)
395 return false;
396 Args shell_arguments;
397 std::string safe_arg;
Zachary Turner10687b02014-10-20 17:46:43 +0000398 shell_arguments.AppendArgument (shell_executable.c_str());
Zachary Turner270e99a2014-12-08 21:36:42 +0000399 const llvm::Triple &triple = GetArchitecture().GetTriple();
400 if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment())
401 shell_arguments.AppendArgument("/C");
402 else
403 shell_arguments.AppendArgument("-c");
404
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000405 StreamString shell_command;
406 if (will_debug)
407 {
408 // Add a modified PATH environment variable in case argv[0]
Zachary Turner270e99a2014-12-08 21:36:42 +0000409 // is a relative path.
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000410 const char *argv0 = argv[0];
Zachary Turner270e99a2014-12-08 21:36:42 +0000411 FileSpec arg_spec(argv0, false);
412 if (arg_spec.IsRelativeToCurrentWorkingDirectory())
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000413 {
414 // We have a relative path to our executable which may not work if
415 // we just try to run "a.out" (without it being converted to "./a.out")
416 const char *working_dir = GetWorkingDirectory();
417 // Be sure to put quotes around PATH's value in case any paths have spaces...
418 std::string new_path("PATH=\"");
419 const size_t empty_path_len = new_path.size();
420
421 if (working_dir && working_dir[0])
422 {
423 new_path += working_dir;
424 }
425 else
426 {
427 char current_working_dir[PATH_MAX];
428 const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
429 if (cwd && cwd[0])
430 new_path += cwd;
431 }
432 const char *curr_path = getenv("PATH");
433 if (curr_path)
434 {
435 if (new_path.size() > empty_path_len)
436 new_path += ':';
437 new_path += curr_path;
438 }
439 new_path += "\" ";
440 shell_command.PutCString(new_path.c_str());
441 }
442
Zachary Turner270e99a2014-12-08 21:36:42 +0000443 if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
444 shell_command.PutCString("exec");
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000445
446 // Only Apple supports /usr/bin/arch being able to specify the architecture
Greg Claytonbc766682014-08-12 21:38:59 +0000447 if (GetArchitecture().IsValid() && // Valid architecture
448 GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only
449 GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000450 {
451 shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
452 // Set the resume count to 2:
453 // 1 - stop in shell
454 // 2 - stop in /usr/bin/arch
455 // 3 - then we will stop in our program
456 SetResumeCount(num_resumes + 1);
457 }
458 else
459 {
460 // Set the resume count to 1:
461 // 1 - stop in shell
462 // 2 - then we will stop in our program
463 SetResumeCount(num_resumes);
464 }
465 }
466
467 if (first_arg_is_full_shell_command)
468 {
469 // There should only be one argument that is the shell command itself to be used as is
470 if (argv[0] && !argv[1])
471 shell_command.Printf("%s", argv[0]);
472 else
473 return false;
474 }
475 else
476 {
477 for (size_t i=0; argv[i] != NULL; ++i)
478 {
479 const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
480 shell_command.Printf(" %s", arg);
481 }
482 }
483 shell_arguments.AppendArgument (shell_command.GetString().c_str());
Zachary Turner10687b02014-10-20 17:46:43 +0000484 m_executable = m_shell;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000485 m_arguments = shell_arguments;
486 return true;
487 }
488 else
489 {
490 error.SetErrorString ("invalid shell path");
491 }
492 }
493 else
494 {
495 error.SetErrorString ("not launching in shell");
496 }
497 return false;
498}
Greg Clayton8012cad2014-11-17 19:39:20 +0000499
500Listener &
501ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
502{
503 if (m_listener_sp)
504 return *m_listener_sp;
505 else
506 return debugger.GetListener();
507}