]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Target/ProcessLaunchInfo.cpp
Import LLDB as of upstream SVN r225923 (git 2b588ecd)
[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                 if (m_pty->OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0))
348                 {
349                     const char *slave_path = m_pty->GetSlaveName(NULL, 0);
350
351                     // 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)
354                     {
355                         AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
356                     }
357
358                     // 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)
361                     {
362                         AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
363                     }
364
365                     // 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)
368                     {
369                         AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
370                     }
371                 }
372             }
373         }
374     }
375 }
376
377
378 bool
379 ProcessLaunchInfo::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     {
389         if (m_shell)
390         {
391             std::string shell_executable = m_shell.GetPath();
392
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;
398             shell_arguments.AppendArgument (shell_executable.c_str());
399             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
405             StreamString shell_command;
406             if (will_debug)
407             {
408                 // Add a modified PATH environment variable in case argv[0]
409                 // is a relative path.
410                 const char *argv0 = argv[0];
411                 FileSpec arg_spec(argv0, false);
412                 if (arg_spec.IsRelativeToCurrentWorkingDirectory())
413                 {
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
443                 if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
444                     shell_command.PutCString("exec");
445
446                 // Only Apple supports /usr/bin/arch being able to specify the architecture
447                 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
450                 {
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());
484             m_executable = m_shell;
485             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 }
499
500 Listener &
501 ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
502 {
503     if (m_listener_sp)
504         return *m_listener_sp;
505     else
506         return debugger.GetListener();
507 }