]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Target/ProcessLaunchInfo.cpp
Import LLDB as of upstream SVN 228549 (git 39760838)
[FreeBSD/FreeBSD.git] / source / Target / ProcessLaunchInfo.cpp
1 //===-- 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
10 #include "lldb/Host/Config.h"
11
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/Log.h"
14 #include "lldb/Target/ProcessLaunchInfo.h"
15 #include "lldb/Target/FileAction.h"
16 #include "lldb/Target/Target.h"
17
18 using namespace lldb;
19 using namespace lldb_private;
20
21 //----------------------------------------------------------------------------
22 // ProcessLaunchInfo member functions
23 //----------------------------------------------------------------------------
24
25 ProcessLaunchInfo::ProcessLaunchInfo () :
26     ProcessInfo(),
27     m_working_dir (),
28     m_plugin_name (),
29     m_flags (0),
30     m_file_actions (),
31     m_pty (new lldb_utility::PseudoTerminal),
32     m_resume_count (0),
33     m_monitor_callback (NULL),
34     m_monitor_callback_baton (NULL),
35     m_monitor_signals (false),
36     m_listener_sp (),
37     m_hijack_listener_sp ()
38 {
39 }
40
41 ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path,
42                                      const char *working_directory, uint32_t launch_flags) :
43     ProcessInfo(),
44     m_working_dir(),
45     m_plugin_name(),
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_listener_sp (),
54     m_hijack_listener_sp()
55 {
56     if (stdin_path)
57     {
58         FileAction file_action;
59         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     {
66         FileAction file_action;
67         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     {
74         FileAction file_action;
75         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
84 bool
85 ProcessLaunchInfo::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
96 bool
97 ProcessLaunchInfo::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
108 bool
109 ProcessLaunchInfo::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
120 bool
121 ProcessLaunchInfo::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
132 const FileAction *
133 ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const
134 {
135     if (idx < m_file_actions.size())
136         return &m_file_actions[idx];
137     return NULL;
138 }
139
140 const FileAction *
141 ProcessLaunchInfo::GetFileActionForFD(int fd) const
142 {
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
151 const char *
152 ProcessLaunchInfo::GetWorkingDirectory () const
153 {
154     if (m_working_dir.empty())
155         return NULL;
156     return m_working_dir.c_str();
157 }
158
159 void
160 ProcessLaunchInfo::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
168 const char *
169 ProcessLaunchInfo::GetProcessPluginName () const
170 {
171     if (m_plugin_name.empty())
172         return NULL;
173     return m_plugin_name.c_str();
174 }
175
176 void
177 ProcessLaunchInfo::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
185 const FileSpec &
186 ProcessLaunchInfo::GetShell () const
187 {
188     return m_shell;
189 }
190
191 void
192 ProcessLaunchInfo::SetShell (const FileSpec &shell)
193 {
194     m_shell = shell;
195     if (m_shell)
196     {
197         m_shell.ResolveExecutableLocation();
198         m_flags.Set (lldb::eLaunchFlagLaunchInShell);
199     }
200     else
201         m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
202 }
203
204 void
205 ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate)
206 {
207     if (separate)
208         m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
209     else
210         m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
211
212 }
213
214 void
215 ProcessLaunchInfo::Clear ()
216 {
217     ProcessInfo::Clear();
218     m_working_dir.clear();
219     m_plugin_name.clear();
220     m_shell.Clear();
221     m_flags.Clear();
222     m_file_actions.clear();
223     m_resume_count = 0;
224     m_listener_sp.reset();
225     m_hijack_listener_sp.reset();
226 }
227
228 void
229 ProcessLaunchInfo::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
238 bool
239 ProcessLaunchInfo::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
252 void
253 ProcessLaunchInfo::SetDetachOnError (bool enable)
254 {
255     if (enable)
256         m_flags.Set(lldb::eLaunchFlagDetachOnError);
257     else
258         m_flags.Clear(lldb::eLaunchFlagDetachOnError);
259 }
260
261 void
262 ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
263 {
264     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
265
266     // 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"
268     if (GetFileActionForFD(STDIN_FILENO) == NULL ||
269         GetFileActionForFD(STDOUT_FILENO) == NULL ||
270         GetFileActionForFD(STDERR_FILENO) == NULL)
271     {
272         if (log)
273             log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
274                          __FUNCTION__);
275
276         if (m_flags.Test(eLaunchFlagDisableSTDIO))
277         {
278             if (log)
279                 log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
280                              __FUNCTION__);
281             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             {
296                 // 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();
304             }
305
306             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
313             char path[PATH_MAX];
314             if (in_path && in_path.GetPath(path, sizeof(path)))
315             {
316                 AppendOpenFileAction(STDIN_FILENO, path, true, false);
317                 if (log)
318                     log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
319                                  __FUNCTION__,
320                                  in_path.GetPath().c_str ());
321             }
322
323             if (out_path && out_path.GetPath(path, sizeof(path)))
324             {
325                 AppendOpenFileAction(STDOUT_FILENO, path, false, true);
326                 if (log)
327                     log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
328                                  __FUNCTION__,
329                                  out_path.GetPath().c_str ());
330             }
331
332             if (err_path && err_path.GetPath(path, sizeof(path)))
333             {
334                 if (log)
335                     log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
336                                  __FUNCTION__,
337                                  err_path.GetPath().c_str ());
338                 AppendOpenFileAction(STDERR_FILENO, path, false, true);
339             }
340
341             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
347                 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))
355                 {
356                     const char *slave_path = m_pty->GetSlaveName(NULL, 0);
357
358                     // 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)
361                     {
362                         AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
363                     }
364
365                     // 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)
368                     {
369                         AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
370                     }
371
372                     // 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)
375                     {
376                         AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
377                     }
378                 }
379             }
380         }
381     }
382 }
383
384
385 bool
386 ProcessLaunchInfo::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     {
396         if (m_shell)
397         {
398             std::string shell_executable = m_shell.GetPath();
399
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;
405             shell_arguments.AppendArgument (shell_executable.c_str());
406             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
412             StreamString shell_command;
413             if (will_debug)
414             {
415                 // Add a modified PATH environment variable in case argv[0]
416                 // is a relative path.
417                 const char *argv0 = argv[0];
418                 FileSpec arg_spec(argv0, false);
419                 if (arg_spec.IsRelativeToCurrentWorkingDirectory())
420                 {
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
450                 if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
451                     shell_command.PutCString("exec");
452
453                 // Only Apple supports /usr/bin/arch being able to specify the architecture
454                 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
457                 {
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());
491             m_executable = m_shell;
492             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 }
506
507 Listener &
508 ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
509 {
510     if (m_listener_sp)
511         return *m_listener_sp;
512     else
513         return debugger.GetListener();
514 }