blob: ddfd62911482da85bc732840b972ae906573b3d5 [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"
270 if (GetFileActionForFD(STDIN_FILENO) == NULL || GetFileActionForFD(STDOUT_FILENO) == NULL ||
271 GetFileActionForFD(STDERR_FILENO) == NULL)
272 {
Todd Fiala75f47c32014-10-11 21:42:09 +0000273 if (log)
274 log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
275 __FUNCTION__);
276
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000277 if (m_flags.Test(eLaunchFlagDisableSTDIO))
278 {
Todd Fiala75f47c32014-10-11 21:42:09 +0000279 if (log)
280 log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
281 __FUNCTION__);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000282 AppendSuppressFileAction (STDIN_FILENO , true, false);
283 AppendSuppressFileAction (STDOUT_FILENO, false, true);
284 AppendSuppressFileAction (STDERR_FILENO, false, true);
285 }
286 else
287 {
288 // Check for any values that might have gotten set with any of:
289 // (lldb) settings set target.input-path
290 // (lldb) settings set target.output-path
291 // (lldb) settings set target.error-path
292 FileSpec in_path;
293 FileSpec out_path;
294 FileSpec err_path;
295 if (target)
296 {
297 in_path = target->GetStandardInputPath();
298 out_path = target->GetStandardOutputPath();
299 err_path = target->GetStandardErrorPath();
300 }
301
Todd Fiala75f47c32014-10-11 21:42:09 +0000302 if (log)
303 log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'",
304 __FUNCTION__,
305 in_path ? in_path.GetPath().c_str () : "<null>",
306 out_path ? out_path.GetPath().c_str () : "<null>",
307 err_path ? err_path.GetPath().c_str () : "<null>");
308
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000309 char path[PATH_MAX];
310 if (in_path && in_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000311 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000312 AppendOpenFileAction(STDIN_FILENO, path, true, false);
Todd Fiala75f47c32014-10-11 21:42:09 +0000313 if (log)
314 log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
315 __FUNCTION__,
316 in_path.GetPath().c_str ());
317 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000318
319 if (out_path && out_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000320 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000321 AppendOpenFileAction(STDOUT_FILENO, path, false, true);
Todd Fiala75f47c32014-10-11 21:42:09 +0000322 if (log)
323 log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
324 __FUNCTION__,
325 out_path.GetPath().c_str ());
326 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000327
328 if (err_path && err_path.GetPath(path, sizeof(path)))
Todd Fiala75f47c32014-10-11 21:42:09 +0000329 {
330 if (log)
331 log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
332 __FUNCTION__,
333 err_path.GetPath().c_str ());
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000334 AppendOpenFileAction(STDERR_FILENO, path, false, true);
Todd Fiala75f47c32014-10-11 21:42:09 +0000335 }
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000336
Todd Fiala75f47c32014-10-11 21:42:09 +0000337 if (default_to_use_pty && (!in_path || !out_path || !err_path))
338 {
339 if (log)
340 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",
341 __FUNCTION__);
342
343 if (m_pty->OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0))
344 {
Zachary Turner44e442b2014-09-12 22:38:39 +0000345 const char *slave_path = m_pty->GetSlaveName(NULL, 0);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000346
Todd Fiala75f47c32014-10-11 21:42:09 +0000347 if (!in_path)
348 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000349 AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
350 }
351
Todd Fiala75f47c32014-10-11 21:42:09 +0000352 if (!out_path)
353 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000354 AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
355 }
356
Todd Fiala75f47c32014-10-11 21:42:09 +0000357 if (!err_path)
358 {
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000359 AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
360 }
361 }
362 }
363 }
364 }
365}
366
367
368bool
369ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
370 bool localhost,
371 bool will_debug,
372 bool first_arg_is_full_shell_command,
373 int32_t num_resumes)
374{
375 error.Clear();
376
377 if (GetFlags().Test (eLaunchFlagLaunchInShell))
378 {
379 const char *shell_executable = GetShell();
380 if (shell_executable)
381 {
382 char shell_resolved_path[PATH_MAX];
383
384 if (localhost)
385 {
386 FileSpec shell_filespec (shell_executable, true);
387
388 if (!shell_filespec.Exists())
389 {
390 // Resolve the path in case we just got "bash", "sh" or "tcsh"
391 if (!shell_filespec.ResolveExecutableLocation ())
392 {
393 error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
394 return false;
395 }
396 }
397 shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
398 shell_executable = shell_resolved_path;
399 }
400
401 const char **argv = GetArguments().GetConstArgumentVector ();
402 if (argv == NULL || argv[0] == NULL)
403 return false;
404 Args shell_arguments;
405 std::string safe_arg;
406 shell_arguments.AppendArgument (shell_executable);
407 shell_arguments.AppendArgument ("-c");
408 StreamString shell_command;
409 if (will_debug)
410 {
411 // Add a modified PATH environment variable in case argv[0]
412 // is a relative path
413 const char *argv0 = argv[0];
414 if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
415 {
416 // We have a relative path to our executable which may not work if
417 // we just try to run "a.out" (without it being converted to "./a.out")
418 const char *working_dir = GetWorkingDirectory();
419 // Be sure to put quotes around PATH's value in case any paths have spaces...
420 std::string new_path("PATH=\"");
421 const size_t empty_path_len = new_path.size();
422
423 if (working_dir && working_dir[0])
424 {
425 new_path += working_dir;
426 }
427 else
428 {
429 char current_working_dir[PATH_MAX];
430 const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
431 if (cwd && cwd[0])
432 new_path += cwd;
433 }
434 const char *curr_path = getenv("PATH");
435 if (curr_path)
436 {
437 if (new_path.size() > empty_path_len)
438 new_path += ':';
439 new_path += curr_path;
440 }
441 new_path += "\" ";
442 shell_command.PutCString(new_path.c_str());
443 }
444
445 shell_command.PutCString ("exec");
446
447 // Only Apple supports /usr/bin/arch being able to specify the architecture
Greg Claytonbc766682014-08-12 21:38:59 +0000448 if (GetArchitecture().IsValid() && // Valid architecture
449 GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only
450 GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000451 {
452 shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
453 // Set the resume count to 2:
454 // 1 - stop in shell
455 // 2 - stop in /usr/bin/arch
456 // 3 - then we will stop in our program
457 SetResumeCount(num_resumes + 1);
458 }
459 else
460 {
461 // Set the resume count to 1:
462 // 1 - stop in shell
463 // 2 - then we will stop in our program
464 SetResumeCount(num_resumes);
465 }
466 }
467
468 if (first_arg_is_full_shell_command)
469 {
470 // There should only be one argument that is the shell command itself to be used as is
471 if (argv[0] && !argv[1])
472 shell_command.Printf("%s", argv[0]);
473 else
474 return false;
475 }
476 else
477 {
478 for (size_t i=0; argv[i] != NULL; ++i)
479 {
480 const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
481 shell_command.Printf(" %s", arg);
482 }
483 }
484 shell_arguments.AppendArgument (shell_command.GetString().c_str());
485 m_executable.SetFile(shell_executable, false);
486 m_arguments = shell_arguments;
487 return true;
488 }
489 else
490 {
491 error.SetErrorString ("invalid shell path");
492 }
493 }
494 else
495 {
496 error.SetErrorString ("not launching in shell");
497 }
498 return false;
499}