LLDB  mainline
ProcessLaunchInfo.cpp
Go to the documentation of this file.
1 //===-- ProcessLaunchInfo.cpp -----------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <climits>
10 
11 #include "lldb/Host/Config.h"
12 #include "lldb/Host/FileAction.h"
13 #include "lldb/Host/FileSystem.h"
14 #include "lldb/Host/HostInfo.h"
16 #include "lldb/Utility/Log.h"
18 
19 #include "llvm/Support/ConvertUTF.h"
20 #include "llvm/Support/FileSystem.h"
21 
22 #if !defined(_WIN32)
23 #include <limits.h>
24 #endif
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 // ProcessLaunchInfo member functions
30 
31 ProcessLaunchInfo::ProcessLaunchInfo()
32  : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0),
33  m_file_actions(), m_pty(new PseudoTerminal), m_resume_count(0),
34  m_monitor_callback(nullptr), m_monitor_callback_baton(nullptr),
35  m_monitor_signals(false), m_listener_sp(), m_hijack_listener_sp() {}
36 
38  const FileSpec &stdout_file_spec,
39  const FileSpec &stderr_file_spec,
40  const FileSpec &working_directory,
41  uint32_t launch_flags)
42  : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags),
46  if (stdin_file_spec) {
47  FileAction file_action;
48  const bool read = true;
49  const bool write = false;
50  if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))
51  AppendFileAction(file_action);
52  }
53  if (stdout_file_spec) {
54  FileAction file_action;
55  const bool read = false;
56  const bool write = true;
57  if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))
58  AppendFileAction(file_action);
59  }
60  if (stderr_file_spec) {
61  FileAction file_action;
62  const bool read = false;
63  const bool write = true;
64  if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))
65  AppendFileAction(file_action);
66  }
67  if (working_directory)
68  SetWorkingDirectory(working_directory);
69 }
70 
72  FileAction file_action;
73  if (file_action.Close(fd)) {
74  AppendFileAction(file_action);
75  return true;
76  }
77  return false;
78 }
79 
81  FileAction file_action;
82  if (file_action.Duplicate(fd, dup_fd)) {
83  AppendFileAction(file_action);
84  return true;
85  }
86  return false;
87 }
88 
89 bool ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,
90  bool read, bool write) {
91  FileAction file_action;
92  if (file_action.Open(fd, file_spec, read, write)) {
93  AppendFileAction(file_action);
94  return true;
95  }
96  return false;
97 }
98 
100  bool write) {
101  FileAction file_action;
102  if (file_action.Open(fd, FileSpec(FileSystem::DEV_NULL), read, write)) {
103  AppendFileAction(file_action);
104  return true;
105  }
106  return false;
107 }
108 
110  if (idx < m_file_actions.size())
111  return &m_file_actions[idx];
112  return nullptr;
113 }
114 
116  for (size_t idx = 0, count = m_file_actions.size(); idx < count; ++idx) {
117  if (m_file_actions[idx].GetFD() == fd)
118  return &m_file_actions[idx];
119  }
120  return nullptr;
121 }
122 
124  return m_working_dir;
125 }
126 
128  m_working_dir = working_dir;
129 }
130 
132  return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str());
133 }
134 
135 void ProcessLaunchInfo::SetProcessPluginName(llvm::StringRef plugin) {
136  m_plugin_name = plugin;
137 }
138 
139 const FileSpec &ProcessLaunchInfo::GetShell() const { return m_shell; }
140 
142  m_shell = shell;
143  if (m_shell) {
145  m_flags.Set(lldb::eLaunchFlagLaunchInShell);
146  } else
147  m_flags.Clear(lldb::eLaunchFlagLaunchInShell);
148 }
149 
151  if (separate)
152  m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
153  else
154  m_flags.Clear(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
155 }
156 
158  if (expand)
159  m_flags.Set(lldb::eLaunchFlagShellExpandArguments);
160  else
161  m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);
162 }
163 
167  m_plugin_name.clear();
168  m_shell.Clear();
169  m_flags.Clear();
170  m_file_actions.clear();
171  m_resume_count = 0;
172  m_listener_sp.reset();
173  m_hijack_listener_sp.reset();
174 }
175 
177  const Host::MonitorChildProcessCallback &callback, bool monitor_signals) {
178  m_monitor_callback = callback;
179  m_monitor_signals = monitor_signals;
180 }
181 
182 bool ProcessLaunchInfo::NoOpMonitorCallback(lldb::pid_t pid, bool exited, int signal, int status) {
184  LLDB_LOG(log, "pid = {0}, exited = {1}, signal = {2}, status = {3}", pid,
185  exited, signal, status);
186  return true;
187 }
188 
193  return true;
194  }
195  return false;
196 }
197 
199  if (enable)
200  m_flags.Set(lldb::eLaunchFlagDetachOnError);
201  else
202  m_flags.Clear(lldb::eLaunchFlagDetachOnError);
203 }
204 
207  LLDB_LOG(log, "Generating a pty to use for stdin/out/err");
208 
209  int open_flags = O_RDWR | O_NOCTTY;
210 #if !defined(_WIN32)
211  // We really shouldn't be specifying platform specific flags that are
212  // intended for a system call in generic code. But this will have to
213  // do for now.
214  open_flags |= O_CLOEXEC;
215 #endif
216  if (!m_pty->OpenFirstAvailableMaster(open_flags, nullptr, 0)) {
217  return llvm::createStringError(llvm::inconvertibleErrorCode(),
218  "PTY::OpenFirstAvailableMaster failed");
219  }
220  const FileSpec slave_file_spec(m_pty->GetSlaveName(nullptr, 0));
221 
222  // Only use the slave tty if we don't have anything specified for
223  // input and don't have an action for stdin
224  if (GetFileActionForFD(STDIN_FILENO) == nullptr)
225  AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false);
226 
227  // Only use the slave tty if we don't have anything specified for
228  // output and don't have an action for stdout
229  if (GetFileActionForFD(STDOUT_FILENO) == nullptr)
230  AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true);
231 
232  // Only use the slave tty if we don't have anything specified for
233  // error and don't have an action for stderr
234  if (GetFileActionForFD(STDERR_FILENO) == nullptr)
235  AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true);
236  return llvm::Error::success();
237 }
238 
240  Status &error, bool localhost, bool will_debug,
241  bool first_arg_is_full_shell_command, int32_t num_resumes) {
242  error.Clear();
243 
244  if (GetFlags().Test(eLaunchFlagLaunchInShell)) {
245  if (m_shell) {
246  std::string shell_executable = m_shell.GetPath();
247 
248  const char **argv = GetArguments().GetConstArgumentVector();
249  if (argv == nullptr || argv[0] == nullptr)
250  return false;
251  Args shell_arguments;
252  std::string safe_arg;
253  shell_arguments.AppendArgument(shell_executable);
254  const llvm::Triple &triple = GetArchitecture().GetTriple();
255  if (triple.getOS() == llvm::Triple::Win32 &&
256  !triple.isWindowsCygwinEnvironment())
257  shell_arguments.AppendArgument(llvm::StringRef("/C"));
258  else
259  shell_arguments.AppendArgument(llvm::StringRef("-c"));
260 
261  StreamString shell_command;
262  if (will_debug) {
263  // Add a modified PATH environment variable in case argv[0] is a
264  // relative path.
265  const char *argv0 = argv[0];
266  FileSpec arg_spec(argv0);
267  if (arg_spec.IsRelative()) {
268  // We have a relative path to our executable which may not work if we
269  // just try to run "a.out" (without it being converted to "./a.out")
270  FileSpec working_dir = GetWorkingDirectory();
271  // Be sure to put quotes around PATH's value in case any paths have
272  // spaces...
273  std::string new_path("PATH=\"");
274  const size_t empty_path_len = new_path.size();
275 
276  if (working_dir) {
277  new_path += working_dir.GetPath();
278  } else {
279  llvm::SmallString<64> cwd;
280  if (! llvm::sys::fs::current_path(cwd))
281  new_path += cwd;
282  }
283  std::string curr_path;
284  if (HostInfo::GetEnvironmentVar("PATH", curr_path)) {
285  if (new_path.size() > empty_path_len)
286  new_path += ':';
287  new_path += curr_path;
288  }
289  new_path += "\" ";
290  shell_command.PutCString(new_path);
291  }
292 
293  if (triple.getOS() != llvm::Triple::Win32 ||
294  triple.isWindowsCygwinEnvironment())
295  shell_command.PutCString("exec");
296 
297  // Only Apple supports /usr/bin/arch being able to specify the
298  // architecture
299  if (GetArchitecture().IsValid() && // Valid architecture
300  GetArchitecture().GetTriple().getVendor() ==
301  llvm::Triple::Apple && // Apple only
302  GetArchitecture().GetCore() !=
303  ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
304  {
305  shell_command.Printf(" /usr/bin/arch -arch %s",
306  GetArchitecture().GetArchitectureName());
307  // Set the resume count to 2:
308  // 1 - stop in shell
309  // 2 - stop in /usr/bin/arch
310  // 3 - then we will stop in our program
311  SetResumeCount(num_resumes + 1);
312  } else {
313  // Set the resume count to 1:
314  // 1 - stop in shell
315  // 2 - then we will stop in our program
316  SetResumeCount(num_resumes);
317  }
318  }
319 
320  if (first_arg_is_full_shell_command) {
321  // There should only be one argument that is the shell command itself
322  // to be used as is
323  if (argv[0] && !argv[1])
324  shell_command.Printf("%s", argv[0]);
325  else
326  return false;
327  } else {
328  for (size_t i = 0; argv[i] != nullptr; ++i) {
329  const char *arg =
330  Args::GetShellSafeArgument(m_shell, argv[i], safe_arg);
331  shell_command.Printf(" %s", arg);
332  }
333  }
334  shell_arguments.AppendArgument(shell_command.GetString());
336  m_arguments = shell_arguments;
337  return true;
338  } else {
339  error.SetErrorString("invalid shell path");
340  }
341  } else {
342  error.SetErrorString("not launching in shell");
343  }
344  return false;
345 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
A command line argument class.
Definition: Args.h:32
bool ResolveExecutableLocation(FileSpec &file_spec)
Call into the Host to see if it can help find the file.
bool ProcessIDIsValid() const
Definition: ProcessInfo.h:72
#define LIBLLDB_LOG_PROCESS
Definition: Logging.h:15
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
static bool NoOpMonitorCallback(lldb::pid_t pid, bool exited, int signal, int status)
A Monitor callback which does not take any action on process events.
std::vector< FileAction > m_file_actions
bool AppendSuppressFileAction(int fd, bool read, bool write)
llvm::Error Error
A file utility class.
Definition: FileSpec.h:55
A pseudo terminal helper class.
void Clear()
Clears the object state.
Definition: FileSpec.cpp:285
Host::MonitorChildProcessCallback m_monitor_callback
#define LLDB_LOG(log,...)
Definition: Log.h:209
static FileSystem & Instance()
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:431
ValueType Clear(ValueType mask=~(ValueType) 0)
Clear one or more flags.
Definition: Flags.h:72
void SetProcessPluginName(llvm::StringRef plugin)
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:57
bool AppendOpenFileAction(int fd, const FileSpec &file_spec, bool read, bool write)
static bool separate(size_t count)
Definition: UUID.cpp:24
void Clear()
Clear the object state.
Definition: Status.cpp:167
void SetLaunchInSeparateProcessGroup(bool separate)
llvm::StringRef GetString() const
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:241
bool Open(int fd, const FileSpec &file_spec, bool read, bool write)
Definition: FileAction.cpp:33
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
const FileAction * GetFileActionForFD(int fd) const
ArchSpec & GetArchitecture()
Definition: ProcessInfo.h:62
void AppendFileAction(const FileAction &info)
ValueType Set(ValueType mask)
Set one or more flags by logical OR&#39;ing mask with the current flags.
Definition: Flags.h:84
static const char * GetShellSafeArgument(const FileSpec &shell, const char *unsafe_arg, std::string &safe_arg)
Definition: Args.cpp:413
bool ConvertArgumentsForLaunchingInShell(Status &error, bool localhost, bool will_debug, bool first_arg_is_full_shell_command, int32_t num_resumes)
const FileSpec & GetWorkingDirectory() const
static HostThread StartMonitoringChildProcess(const MonitorChildProcessCallback &callback, lldb::pid_t pid, bool monitor_signals)
Start monitoring a child process.
void SetWorkingDirectory(const FileSpec &working_dir)
Definition: SBAddress.h:15
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
Definition: Args.cpp:321
uint64_t pid_t
Definition: lldb-types.h:85
bool Duplicate(int fd, int dup_fd)
Definition: FileAction.cpp:61
const FileSpec & GetShell() const
std::shared_ptr< PseudoTerminal > m_pty
bool IsRelative() const
Returns true if the filespec represents a relative path.
Definition: FileSpec.cpp:503
const char ** GetConstArgumentVector() const
Gets the argument vector.
Definition: Args.cpp:278
std::function< bool(lldb::pid_t pid, bool exited, int signal, int status)> MonitorChildProcessCallback
Definition: Host.h:68
static const char * DEV_NULL
Definition: FileSystem.h:31
const FileAction * GetFileActionAtIndex(size_t idx) const
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:376
void SetMonitorProcessCallback(const Host::MonitorChildProcessCallback &callback, bool monitor_signals)
#define O_NOCTTY
void SetShell(const FileSpec &shell)
lldb::pid_t GetProcessID() const
Definition: ProcessInfo.h:68
const char * GetProcessPluginName() const
bool AppendDuplicateFileAction(int fd, int dup_fd)
An error handling class.
Definition: Status.h:44