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