]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Target/ProcessLaunchInfo.cpp
Vendor import of stripped lldb trunk r256633:
[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/Host/FileSystem.h"
15 #include "lldb/Target/ProcessLaunchInfo.h"
16 #include "lldb/Target/FileAction.h"
17 #include "lldb/Target/Target.h"
18
19 #if !defined(_WIN32)
20 #include <limits.h>
21 #endif
22
23 using namespace lldb;
24 using namespace lldb_private;
25
26 //----------------------------------------------------------------------------
27 // ProcessLaunchInfo member functions
28 //----------------------------------------------------------------------------
29
30 ProcessLaunchInfo::ProcessLaunchInfo () :
31     ProcessInfo(),
32     m_working_dir (),
33     m_plugin_name (),
34     m_flags (0),
35     m_file_actions (),
36     m_pty (new lldb_utility::PseudoTerminal),
37     m_resume_count (0),
38     m_monitor_callback (NULL),
39     m_monitor_callback_baton (NULL),
40     m_monitor_signals (false),
41     m_listener_sp (),
42     m_hijack_listener_sp ()
43 {
44 }
45
46 ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,
47                                      const FileSpec &stdout_file_spec,
48                                      const FileSpec &stderr_file_spec,
49                                      const FileSpec &working_directory,
50                                      uint32_t launch_flags) :
51     ProcessInfo(),
52     m_working_dir(),
53     m_plugin_name(),
54     m_flags(launch_flags),
55     m_file_actions(),
56     m_pty(new lldb_utility::PseudoTerminal),
57     m_resume_count(0),
58     m_monitor_callback(NULL),
59     m_monitor_callback_baton(NULL),
60     m_monitor_signals(false),
61     m_listener_sp (),
62     m_hijack_listener_sp()
63 {
64     if (stdin_file_spec)
65     {
66         FileAction file_action;
67         const bool read = true;
68         const bool write = false;
69         if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))
70             AppendFileAction (file_action);
71     }
72     if (stdout_file_spec)
73     {
74         FileAction file_action;
75         const bool read = false;
76         const bool write = true;
77         if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))
78             AppendFileAction (file_action);
79     }
80     if (stderr_file_spec)
81     {
82         FileAction file_action;
83         const bool read = false;
84         const bool write = true;
85         if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))
86             AppendFileAction (file_action);
87     }
88     if (working_directory)
89         SetWorkingDirectory(working_directory);
90 }
91
92 bool
93 ProcessLaunchInfo::AppendCloseFileAction (int fd)
94 {
95     FileAction file_action;
96     if (file_action.Close (fd))
97     {
98         AppendFileAction (file_action);
99         return true;
100     }
101     return false;
102 }
103
104 bool
105 ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd)
106 {
107     FileAction file_action;
108     if (file_action.Duplicate (fd, dup_fd))
109     {
110         AppendFileAction (file_action);
111         return true;
112     }
113     return false;
114 }
115
116 bool
117 ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,
118                                         bool read, bool write)
119 {
120     FileAction file_action;
121     if (file_action.Open(fd, file_spec, read, write))
122     {
123         AppendFileAction (file_action);
124         return true;
125     }
126     return false;
127 }
128
129 bool
130 ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write)
131 {
132     FileAction file_action;
133     if (file_action.Open(fd, FileSpec{FileSystem::DEV_NULL, false}, read, write))
134     {
135         AppendFileAction (file_action);
136         return true;
137     }
138     return false;
139 }
140
141 const FileAction *
142 ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const
143 {
144     if (idx < m_file_actions.size())
145         return &m_file_actions[idx];
146     return NULL;
147 }
148
149 const FileAction *
150 ProcessLaunchInfo::GetFileActionForFD(int fd) const
151 {
152     for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx)
153     {
154         if (m_file_actions[idx].GetFD () == fd)
155             return &m_file_actions[idx];
156     }
157     return NULL;
158 }
159
160 const FileSpec &
161 ProcessLaunchInfo::GetWorkingDirectory() const
162 {
163     return m_working_dir;
164 }
165
166 void
167 ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir)
168 {
169     m_working_dir = working_dir;
170 }
171
172 const char *
173 ProcessLaunchInfo::GetProcessPluginName () const
174 {
175     if (m_plugin_name.empty())
176         return NULL;
177     return m_plugin_name.c_str();
178 }
179
180 void
181 ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
182 {
183     if (plugin && plugin[0])
184         m_plugin_name.assign (plugin);
185     else
186         m_plugin_name.clear();
187 }
188
189 const FileSpec &
190 ProcessLaunchInfo::GetShell () const
191 {
192     return m_shell;
193 }
194
195 void
196 ProcessLaunchInfo::SetShell (const FileSpec &shell)
197 {
198     m_shell = shell;
199     if (m_shell)
200     {
201         m_shell.ResolveExecutableLocation();
202         m_flags.Set (lldb::eLaunchFlagLaunchInShell);
203     }
204     else
205         m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
206 }
207
208 void
209 ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate)
210 {
211     if (separate)
212         m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
213     else
214         m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
215 }
216
217 void
218 ProcessLaunchInfo::SetShellExpandArguments (bool expand)
219 {
220     if (expand)
221         m_flags.Set(lldb::eLaunchFlagShellExpandArguments);
222     else
223         m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);
224 }
225
226 void
227 ProcessLaunchInfo::Clear ()
228 {
229     ProcessInfo::Clear();
230     m_working_dir.Clear();
231     m_plugin_name.clear();
232     m_shell.Clear();
233     m_flags.Clear();
234     m_file_actions.clear();
235     m_resume_count = 0;
236     m_listener_sp.reset();
237     m_hijack_listener_sp.reset();
238 }
239
240 void
241 ProcessLaunchInfo::SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
242                            void *baton,
243                            bool monitor_signals)
244 {
245     m_monitor_callback = callback;
246     m_monitor_callback_baton = baton;
247     m_monitor_signals = monitor_signals;
248 }
249
250 bool
251 ProcessLaunchInfo::MonitorProcess () const
252 {
253     if (m_monitor_callback && ProcessIDIsValid())
254     {
255         Host::StartMonitoringChildProcess (m_monitor_callback,
256                                            m_monitor_callback_baton,
257                                            GetProcessID(),
258                                            m_monitor_signals);
259         return true;
260     }
261     return false;
262 }
263
264 void
265 ProcessLaunchInfo::SetDetachOnError (bool enable)
266 {
267     if (enable)
268         m_flags.Set(lldb::eLaunchFlagDetachOnError);
269     else
270         m_flags.Clear(lldb::eLaunchFlagDetachOnError);
271 }
272
273 void
274 ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
275 {
276     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
277
278     // If nothing for stdin or stdout or stderr was specified, then check the process for any default
279     // settings that were set with "settings set"
280     if (GetFileActionForFD(STDIN_FILENO) == NULL ||
281         GetFileActionForFD(STDOUT_FILENO) == NULL ||
282         GetFileActionForFD(STDERR_FILENO) == NULL)
283     {
284         if (log)
285             log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
286                          __FUNCTION__);
287
288         if (m_flags.Test(eLaunchFlagLaunchInTTY))
289         {
290             // Do nothing, if we are launching in a remote terminal
291             // no file actions should be done at all.
292             return;
293         }
294
295         if (m_flags.Test(eLaunchFlagDisableSTDIO))
296         {
297             if (log)
298                 log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
299                              __FUNCTION__);
300             AppendSuppressFileAction (STDIN_FILENO , true, false);
301             AppendSuppressFileAction (STDOUT_FILENO, false, true);
302             AppendSuppressFileAction (STDERR_FILENO, false, true);
303         }
304         else
305         {
306             // Check for any values that might have gotten set with any of:
307             // (lldb) settings set target.input-path
308             // (lldb) settings set target.output-path
309             // (lldb) settings set target.error-path
310             FileSpec in_file_spec;
311             FileSpec out_file_spec;
312             FileSpec err_file_spec;
313             if (target)
314             {
315                 // Only override with the target settings if we don't already have
316                 // an action for in, out or error
317                 if (GetFileActionForFD(STDIN_FILENO) == NULL)
318                     in_file_spec = target->GetStandardInputPath();
319                 if (GetFileActionForFD(STDOUT_FILENO) == NULL)
320                     out_file_spec = target->GetStandardOutputPath();
321                 if (GetFileActionForFD(STDERR_FILENO) == NULL)
322                     err_file_spec = target->GetStandardErrorPath();
323             }
324
325             if (log)
326                 log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'",
327                              __FUNCTION__,
328                               in_file_spec ?  in_file_spec.GetCString() : "<null>",
329                              out_file_spec ? out_file_spec.GetCString() : "<null>",
330                              err_file_spec ? err_file_spec.GetCString() : "<null>");
331
332             if (in_file_spec)
333             {
334                 AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false);
335                 if (log)
336                     log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
337                                  __FUNCTION__, in_file_spec.GetCString());
338             }
339
340             if (out_file_spec)
341             {
342                 AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true);
343                 if (log)
344                     log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
345                                  __FUNCTION__, out_file_spec.GetCString());
346             }
347
348             if (err_file_spec)
349             {
350                 AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true);
351                 if (log)
352                     log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
353                                  __FUNCTION__, err_file_spec.GetCString());
354             }
355
356             if (default_to_use_pty && (!in_file_spec || !out_file_spec || !err_file_spec))
357             {
358                 if (log)
359                     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",
360                                  __FUNCTION__);
361
362                 int open_flags = O_RDWR | O_NOCTTY;
363 #if !defined(_MSC_VER)
364                 // We really shouldn't be specifying platform specific flags
365                 // that are intended for a system call in generic code.  But
366                 // this will have to do for now.
367                 open_flags |= O_CLOEXEC;
368 #endif
369                 if (m_pty->OpenFirstAvailableMaster(open_flags, NULL, 0))
370                 {
371                     const FileSpec slave_file_spec{m_pty->GetSlaveName(NULL, 0), false};
372
373                     // Only use the slave tty if we don't have anything specified for
374                     // input and don't have an action for stdin
375                     if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == NULL)
376                     {
377                         AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false);
378                     }
379
380                     // Only use the slave tty if we don't have anything specified for
381                     // output and don't have an action for stdout
382                     if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == NULL)
383                     {
384                         AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true);
385                     }
386
387                     // Only use the slave tty if we don't have anything specified for
388                     // error and don't have an action for stderr
389                     if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == NULL)
390                     {
391                         AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true);
392                     }
393                 }
394             }
395         }
396     }
397 }
398
399
400 bool
401 ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
402                                                         bool localhost,
403                                                         bool will_debug,
404                                                         bool first_arg_is_full_shell_command,
405                                                         int32_t num_resumes)
406 {
407     error.Clear();
408
409     if (GetFlags().Test (eLaunchFlagLaunchInShell))
410     {
411         if (m_shell)
412         {
413             std::string shell_executable = m_shell.GetPath();
414
415             const char **argv = GetArguments().GetConstArgumentVector ();
416             if (argv == NULL || argv[0] == NULL)
417                 return false;
418             Args shell_arguments;
419             std::string safe_arg;
420             shell_arguments.AppendArgument (shell_executable.c_str());
421             const llvm::Triple &triple = GetArchitecture().GetTriple();
422             if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment())
423                 shell_arguments.AppendArgument("/C");
424             else
425                 shell_arguments.AppendArgument("-c");
426
427             StreamString shell_command;
428             if (will_debug)
429             {
430                 // Add a modified PATH environment variable in case argv[0]
431                 // is a relative path.
432                 const char *argv0 = argv[0];
433                 FileSpec arg_spec(argv0, false);
434                 if (arg_spec.IsRelative())
435                 {
436                     // We have a relative path to our executable which may not work if
437                     // we just try to run "a.out" (without it being converted to "./a.out")
438                     FileSpec working_dir = GetWorkingDirectory();
439                     // Be sure to put quotes around PATH's value in case any paths have spaces...
440                     std::string new_path("PATH=\"");
441                     const size_t empty_path_len = new_path.size();
442
443                     if (working_dir)
444                     {
445                         new_path += working_dir.GetPath();
446                     }
447                     else
448                     {
449                         char current_working_dir[PATH_MAX];
450                         const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
451                         if (cwd && cwd[0])
452                             new_path += cwd;
453                     }
454                     const char *curr_path = getenv("PATH");
455                     if (curr_path)
456                     {
457                         if (new_path.size() > empty_path_len)
458                             new_path += ':';
459                         new_path += curr_path;
460                     }
461                     new_path += "\" ";
462                     shell_command.PutCString(new_path.c_str());
463                 }
464
465                 if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
466                     shell_command.PutCString("exec");
467
468                 // Only Apple supports /usr/bin/arch being able to specify the architecture
469                 if (GetArchitecture().IsValid() &&                                          // Valid architecture
470                     GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple &&     // Apple only
471                     GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h)          // Don't do this for x86_64h
472                 {
473                     shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
474                     // Set the resume count to 2:
475                     // 1 - stop in shell
476                     // 2 - stop in /usr/bin/arch
477                     // 3 - then we will stop in our program
478                     SetResumeCount(num_resumes + 1);
479                 }
480                 else
481                 {
482                     // Set the resume count to 1:
483                     // 1 - stop in shell
484                     // 2 - then we will stop in our program
485                     SetResumeCount(num_resumes);
486                 }
487             }
488
489             if (first_arg_is_full_shell_command)
490             {
491                 // There should only be one argument that is the shell command itself to be used as is
492                 if (argv[0] && !argv[1])
493                     shell_command.Printf("%s", argv[0]);
494                 else
495                     return false;
496             }
497             else
498             {
499                 for (size_t i=0; argv[i] != NULL; ++i)
500                 {
501                     const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
502                     shell_command.Printf(" %s", arg);
503                 }
504             }
505             shell_arguments.AppendArgument (shell_command.GetString().c_str());
506             m_executable = m_shell;
507             m_arguments = shell_arguments;
508             return true;
509         }
510         else
511         {
512             error.SetErrorString ("invalid shell path");
513         }
514     }
515     else
516     {
517         error.SetErrorString ("not launching in shell");
518     }
519     return false;
520 }
521
522 Listener &
523 ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
524 {
525     if (m_listener_sp)
526         return *m_listener_sp;
527     else
528         return debugger.GetListener();
529 }