blob: 5b6d1a8ddc41fe8557d5a3ce15f122deb6599fe0 [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
Todd Fiala75f47c32014-10-11 21:42:09 +000012#include "lldb/Core/Log.h"
Zachary Turner696b5282014-08-14 16:01:25 +000013#include "lldb/Target/ProcessLaunchInfo.h"
14#include "lldb/Target/FileAction.h"
Todd Fiala6d6b55d2014-06-30 00:30:53 +000015#include "lldb/Target/Target.h"
16
17using namespace lldb;
18using namespace lldb_private;
19
20//----------------------------------------------------------------------------
Todd Fiala6d6b55d2014-06-30 00:30:53 +000021// ProcessLaunchInfo member functions
22//----------------------------------------------------------------------------
23
24ProcessLaunchInfo::ProcessLaunchInfo () :
25 ProcessInfo(),
26 m_working_dir (),
27 m_plugin_name (),
28 m_shell (),
29 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),
36 m_hijack_listener_sp ()
37{
38}
39
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000040ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path,
Zachary Turnercf3f3682014-09-12 23:10:33 +000041 const char *working_directory, uint32_t launch_flags) :
42 ProcessInfo(),
43 m_working_dir(),
44 m_plugin_name(),
45 m_shell(),
46 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),
53 m_hijack_listener_sp()
Todd Fiala6d6b55d2014-06-30 00:30:53 +000054{
55 if (stdin_path)
56 {
Zachary Turner696b5282014-08-14 16:01:25 +000057 FileAction file_action;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000058 const bool read = true;
59 const bool write = false;
60 if (file_action.Open(STDIN_FILENO, stdin_path, read, write))
61 AppendFileAction (file_action);
62 }
63 if (stdout_path)
64 {
Zachary Turner696b5282014-08-14 16:01:25 +000065 FileAction file_action;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000066 const bool read = false;
67 const bool write = true;
68 if (file_action.Open(STDOUT_FILENO, stdout_path, read, write))
69 AppendFileAction (file_action);
70 }
71 if (stderr_path)
72 {
Zachary Turner696b5282014-08-14 16:01:25 +000073 FileAction file_action;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000074 const bool read = false;
75 const bool write = true;
76 if (file_action.Open(STDERR_FILENO, stderr_path, read, write))
77 AppendFileAction (file_action);
78 }
79 if (working_directory)
80 SetWorkingDirectory(working_directory);
81}
82
83bool
84ProcessLaunchInfo::AppendCloseFileAction (int fd)
85{
86 FileAction file_action;
87 if (file_action.Close (fd))
88 {
89 AppendFileAction (file_action);
90 return true;
91 }
92 return false;
93}
94
95bool
96ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd)
97{
98 FileAction file_action;
99 if (file_action.Duplicate (fd, dup_fd))
100 {
101 AppendFileAction (file_action);
102 return true;
103 }
104 return false;
105}
106
107bool
108ProcessLaunchInfo::AppendOpenFileAction (int fd, const char *path, bool read, bool write)
109{
110 FileAction file_action;
111 if (file_action.Open (fd, path, read, write))
112 {
113 AppendFileAction (file_action);
114 return true;
115 }
116 return false;
117}
118
119bool
120ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write)
121{
122 FileAction file_action;
123 if (file_action.Open (fd, "/dev/null", read, write))
124 {
125 AppendFileAction (file_action);
126 return true;
127 }
128 return false;
129}
130
Zachary Turner696b5282014-08-14 16:01:25 +0000131const FileAction *
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000132ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000133{
134 if (idx < m_file_actions.size())
135 return &m_file_actions[idx];
136 return NULL;
137}
138
Zachary Turner696b5282014-08-14 16:01:25 +0000139const FileAction *
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000140ProcessLaunchInfo::GetFileActionForFD(int fd) const
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000141{
142 for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx)
143 {
144 if (m_file_actions[idx].GetFD () == fd)
145 return &m_file_actions[idx];
146 }
147 return NULL;
148}
149
150const char *
151ProcessLaunchInfo::GetWorkingDirectory () const
152{
153 if (m_working_dir.empty())
154 return NULL;
155 return m_working_dir.c_str();
156}
157
158void
159ProcessLaunchInfo::SetWorkingDirectory (const char *working_dir)
160{
161 if (working_dir && working_dir[0])
162 m_working_dir.assign (working_dir);
163 else
164 m_working_dir.clear();
165}
166
167const char *
168ProcessLaunchInfo::GetProcessPluginName () const
169{
170 if (m_plugin_name.empty())
171 return NULL;
172 return m_plugin_name.c_str();
173}
174
175void
176ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
177{
178 if (plugin && plugin[0])
179 m_plugin_name.assign (plugin);
180 else
181 m_plugin_name.clear();
182}
183
184const char *
185ProcessLaunchInfo::GetShell () const
186{
187 if (m_shell.empty())
188 return NULL;
189 return m_shell.c_str();
190}
191
192void
193ProcessLaunchInfo::SetShell (const char * path)
194{
195 if (path && path[0])
196 {
197 m_shell.assign (path);
198 m_flags.Set (lldb::eLaunchFlagLaunchInShell);
199 }
200 else
201 {
202 m_shell.clear();
203 m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
204 }
205}
206
207void
208ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate)
209{
210 if (separate)
211 m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
212 else
213 m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
214
215}
216
217void
218ProcessLaunchInfo::Clear ()
219{
220 ProcessInfo::Clear();
221 m_working_dir.clear();
222 m_plugin_name.clear();
223 m_shell.clear();
224 m_flags.Clear();
225 m_file_actions.clear();
226 m_resume_count = 0;
227 m_hijack_listener_sp.reset();
228}
229
230void
231ProcessLaunchInfo::SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
232 void *baton,
233 bool monitor_signals)
234{
235 m_monitor_callback = callback;
236 m_monitor_callback_baton = baton;
237 m_monitor_signals = monitor_signals;
238}
239
240bool
241ProcessLaunchInfo::MonitorProcess () const
242{
243 if (m_monitor_callback && ProcessIDIsValid())
244 {
245 Host::StartMonitoringChildProcess (m_monitor_callback,
246 m_monitor_callback_baton,
247 GetProcessID(),
248 m_monitor_signals);
249 return true;
250 }
251 return false;
252}
253
254void
255ProcessLaunchInfo::SetDetachOnError (bool enable)
256{
257 if (enable)
258 m_flags.Set(lldb::eLaunchFlagDetachOnError);
259 else
260 m_flags.Clear(lldb::eLaunchFlagDetachOnError);
261}
262
263void
264ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
265{
Todd Fiala75f47c32014-10-11 21:42:09 +0000266 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
267
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000268 // If nothing for stdin or stdout or stderr was specified, then check the process for any default
269 // settings that were set with "settings set"
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000270 if (GetFileActionForFD(STDIN_FILENO) == NULL ||
271 GetFileActionForFD(STDOUT_FILENO) == NULL ||
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000272 GetFileActionForFD(STDERR_FILENO) == NULL)
273 {
Todd Fiala75f47c32014-10-11 21:42:09 +0000274 if (log)
275 log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
276 __FUNCTION__);
277
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000278 if (m_flags.Test(eLaunchFlagDisableSTDIO))
279 {
Todd Fiala75f47c32014-10-11 21:42:09 +0000280 if (log)
281 log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
282 __FUNCTION__);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000283 AppendSuppressFileAction (STDIN_FILENO , true, false);
284 AppendSuppressFileAction (STDOUT_FILENO, false, true);
285 AppendSuppressFileAction (STDERR_FILENO, false, true);
286 }
287 else
288 {
289 // Check for any values that might have gotten set with any of:
290 // (lldb) settings set target.input-path
291 // (lldb) settings set target.output-path
292 // (lldb) settings set target.error-path
293 FileSpec in_path;
294 FileSpec out_path;
295 FileSpec err_path;
296 if (target)
297 {
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000298 // Only override with the target settings if we don't already have
299 // an action for in, out or error
300 if (GetFileActionForFD(STDIN_FILENO) == NULL)
301 in_path = target->GetStandardInputPath();
302 if (GetFileActionForFD(STDOUT_FILENO) == NULL)
303 out_path = target->GetStandardOutputPath();
304 if (GetFileActionForFD(STDERR_FILENO) == NULL)
305 err_path = target->GetStandardErrorPath();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000306 }
307
Todd Fiala75f47c32014-10-11 21:42:09 +0000308 if (log)
309 log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'",
310 __FUNCTION__,
311 in_path ? in_path.GetPath().c_str () : "<null>",
312 out_path ? out_path.GetPath().c_str () : "<null>",
313 err_path ? err_path.GetPath().c_str () : "<null>");
314
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000315 char path[PATH_MAX];
316 if (in_path && in_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000317 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000318 AppendOpenFileAction(STDIN_FILENO, path, true, false);
Todd Fiala75f47c32014-10-11 21:42:09 +0000319 if (log)
320 log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
321 __FUNCTION__,
322 in_path.GetPath().c_str ());
323 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000324
325 if (out_path && out_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000326 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000327 AppendOpenFileAction(STDOUT_FILENO, path, false, true);
Todd Fiala75f47c32014-10-11 21:42:09 +0000328 if (log)
329 log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
330 __FUNCTION__,
331 out_path.GetPath().c_str ());
332 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000333
334 if (err_path && err_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000335 {
336 if (log)
337 log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
338 __FUNCTION__,
339 err_path.GetPath().c_str ());
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000340 AppendOpenFileAction(STDERR_FILENO, path, false, true);
Todd Fiala75f47c32014-10-11 21:42:09 +0000341 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000342
Todd Fiala75f47c32014-10-11 21:42:09 +0000343 if (default_to_use_pty && (!in_path || !out_path || !err_path))
344 {
345 if (log)
346 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",
347 __FUNCTION__);
348
349 if (m_pty->OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0))
350 {
Zachary Turner44e442b2014-09-12 22:38:39 +0000351 const char *slave_path = m_pty->GetSlaveName(NULL, 0);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000352
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000353 // Only use the slave tty if we don't have anything specified for
354 // input and don't have an action for stdin
355 if (!in_path && GetFileActionForFD(STDIN_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000356 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000357 AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
358 }
359
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000360 // Only use the slave tty if we don't have anything specified for
361 // output and don't have an action for stdout
362 if (!out_path && GetFileActionForFD(STDOUT_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000363 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000364 AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
365 }
366
Greg Claytonb8e9b8b2014-10-14 20:18:05 +0000367 // Only use the slave tty if we don't have anything specified for
368 // error and don't have an action for stderr
369 if (!err_path && GetFileActionForFD(STDERR_FILENO) == NULL)
Todd Fiala75f47c32014-10-11 21:42:09 +0000370 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000371 AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
372 }
373 }
374 }
375 }
376 }
377}
378
379
380bool
381ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
382 bool localhost,
383 bool will_debug,
384 bool first_arg_is_full_shell_command,
385 int32_t num_resumes)
386{
387 error.Clear();
388
389 if (GetFlags().Test (eLaunchFlagLaunchInShell))
390 {
391 const char *shell_executable = GetShell();
392 if (shell_executable)
393 {
394 char shell_resolved_path[PATH_MAX];
395
396 if (localhost)
397 {
398 FileSpec shell_filespec (shell_executable, true);
399
400 if (!shell_filespec.Exists())
401 {
402 // Resolve the path in case we just got "bash", "sh" or "tcsh"
403 if (!shell_filespec.ResolveExecutableLocation ())
404 {
405 error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
406 return false;
407 }
408 }
409 shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
410 shell_executable = shell_resolved_path;
411 }
412
413 const char **argv = GetArguments().GetConstArgumentVector ();
414 if (argv == NULL || argv[0] == NULL)
415 return false;
416 Args shell_arguments;
417 std::string safe_arg;
418 shell_arguments.AppendArgument (shell_executable);
419 shell_arguments.AppendArgument ("-c");
420 StreamString shell_command;
421 if (will_debug)
422 {
423 // Add a modified PATH environment variable in case argv[0]
424 // is a relative path
425 const char *argv0 = argv[0];
426 if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
427 {
428 // We have a relative path to our executable which may not work if
429 // we just try to run "a.out" (without it being converted to "./a.out")
430 const char *working_dir = GetWorkingDirectory();
431 // Be sure to put quotes around PATH's value in case any paths have spaces...
432 std::string new_path("PATH=\"");
433 const size_t empty_path_len = new_path.size();
434
435 if (working_dir && working_dir[0])
436 {
437 new_path += working_dir;
438 }
439 else
440 {
441 char current_working_dir[PATH_MAX];
442 const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
443 if (cwd && cwd[0])
444 new_path += cwd;
445 }
446 const char *curr_path = getenv("PATH");
447 if (curr_path)
448 {
449 if (new_path.size() > empty_path_len)
450 new_path += ':';
451 new_path += curr_path;
452 }
453 new_path += "\" ";
454 shell_command.PutCString(new_path.c_str());
455 }
456
457 shell_command.PutCString ("exec");
458
459 // Only Apple supports /usr/bin/arch being able to specify the architecture
Greg Claytonbc766682014-08-12 21:38:59 +0000460 if (GetArchitecture().IsValid() && // Valid architecture
461 GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only
462 GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000463 {
464 shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
465 // Set the resume count to 2:
466 // 1 - stop in shell
467 // 2 - stop in /usr/bin/arch
468 // 3 - then we will stop in our program
469 SetResumeCount(num_resumes + 1);
470 }
471 else
472 {
473 // Set the resume count to 1:
474 // 1 - stop in shell
475 // 2 - then we will stop in our program
476 SetResumeCount(num_resumes);
477 }
478 }
479
480 if (first_arg_is_full_shell_command)
481 {
482 // There should only be one argument that is the shell command itself to be used as is
483 if (argv[0] && !argv[1])
484 shell_command.Printf("%s", argv[0]);
485 else
486 return false;
487 }
488 else
489 {
490 for (size_t i=0; argv[i] != NULL; ++i)
491 {
492 const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
493 shell_command.Printf(" %s", arg);
494 }
495 }
496 shell_arguments.AppendArgument (shell_command.GetString().c_str());
497 m_executable.SetFile(shell_executable, false);
498 m_arguments = shell_arguments;
499 return true;
500 }
501 else
502 {
503 error.SetErrorString ("invalid shell path");
504 }
505 }
506 else
507 {
508 error.SetErrorString ("not launching in shell");
509 }
510 return false;
511}