blob: f9d0b78cacccb50cf1e5be5f191533a479d2f517 [file] [log] [blame]
Todd Fiala6d6b55d2014-06-30 00:30:53 +00001//===-- ProcessLaunchInfo.cpp -----------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Todd Fiala6d6b55d2014-06-30 00:30:53 +00006//
7//===----------------------------------------------------------------------===//
8
Eugene Zelenko9394d7722016-02-18 00:10:17 +00009#include <climits>
Todd Fiala2850b1b2014-06-30 23:51:35 +000010
Zachary Turner190fadc2016-03-22 17:58:09 +000011#include "lldb/Host/Config.h"
Zachary Turner4eff2d32015-10-14 21:37:36 +000012#include "lldb/Host/FileSystem.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000013#include "lldb/Host/HostInfo.h"
Zachary Turner696b5282014-08-14 16:01:25 +000014#include "lldb/Target/FileAction.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000015#include "lldb/Target/ProcessLaunchInfo.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000016#include "lldb/Utility/Log.h"
Zachary Turner2f3df612017-04-06 21:28:29 +000017#include "lldb/Utility/StreamString.h"
Todd Fiala6d6b55d2014-06-30 00:30:53 +000018
Zachary Turner190fadc2016-03-22 17:58:09 +000019#include "llvm/Support/ConvertUTF.h"
Pavel Labath1d5855b2017-01-23 15:56:45 +000020#include "llvm/Support/FileSystem.h"
Zachary Turner190fadc2016-03-22 17:58:09 +000021
22#if !defined(_WIN32)
23#include <limits.h>
24#endif
25
Todd Fiala6d6b55d2014-06-30 00:30:53 +000026using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------------
Todd Fiala6d6b55d2014-06-30 00:30:53 +000030// ProcessLaunchInfo member functions
31//----------------------------------------------------------------------------
32
Kate Stoneb9c1b512016-09-06 20:57:50 +000033ProcessLaunchInfo::ProcessLaunchInfo()
34 : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0),
Pavel Labath07d6f882017-12-11 10:09:14 +000035 m_file_actions(), m_pty(new PseudoTerminal), m_resume_count(0),
36 m_monitor_callback(nullptr), m_monitor_callback_baton(nullptr),
37 m_monitor_signals(false), m_listener_sp(), m_hijack_listener_sp() {}
Todd Fiala6d6b55d2014-06-30 00:30:53 +000038
Chaoren Lind3173f32015-05-29 19:52:29 +000039ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,
40 const FileSpec &stdout_file_spec,
41 const FileSpec &stderr_file_spec,
42 const FileSpec &working_directory,
Kate Stoneb9c1b512016-09-06 20:57:50 +000043 uint32_t launch_flags)
44 : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags),
Pavel Labath07d6f882017-12-11 10:09:14 +000045 m_file_actions(), m_pty(new PseudoTerminal), m_resume_count(0),
46 m_monitor_callback(nullptr), m_monitor_callback_baton(nullptr),
47 m_monitor_signals(false), m_listener_sp(), m_hijack_listener_sp() {
Kate Stoneb9c1b512016-09-06 20:57:50 +000048 if (stdin_file_spec) {
Todd Fiala6d6b55d2014-06-30 00:30:53 +000049 FileAction file_action;
Kate Stoneb9c1b512016-09-06 20:57:50 +000050 const bool read = true;
51 const bool write = false;
52 if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))
53 AppendFileAction(file_action);
54 }
55 if (stdout_file_spec) {
Todd Fiala6d6b55d2014-06-30 00:30:53 +000056 FileAction file_action;
Kate Stoneb9c1b512016-09-06 20:57:50 +000057 const bool read = false;
58 const bool write = true;
59 if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))
60 AppendFileAction(file_action);
61 }
62 if (stderr_file_spec) {
Todd Fiala6d6b55d2014-06-30 00:30:53 +000063 FileAction file_action;
Kate Stoneb9c1b512016-09-06 20:57:50 +000064 const bool read = false;
65 const bool write = true;
66 if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))
67 AppendFileAction(file_action);
68 }
69 if (working_directory)
70 SetWorkingDirectory(working_directory);
Todd Fiala6d6b55d2014-06-30 00:30:53 +000071}
72
Kate Stoneb9c1b512016-09-06 20:57:50 +000073bool ProcessLaunchInfo::AppendCloseFileAction(int fd) {
74 FileAction file_action;
75 if (file_action.Close(fd)) {
76 AppendFileAction(file_action);
77 return true;
78 }
79 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000080}
81
Kate Stoneb9c1b512016-09-06 20:57:50 +000082bool ProcessLaunchInfo::AppendDuplicateFileAction(int fd, int dup_fd) {
83 FileAction file_action;
84 if (file_action.Duplicate(fd, dup_fd)) {
85 AppendFileAction(file_action);
86 return true;
87 }
88 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000089}
90
Kate Stoneb9c1b512016-09-06 20:57:50 +000091bool ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,
92 bool read, bool write) {
93 FileAction file_action;
94 if (file_action.Open(fd, file_spec, read, write)) {
95 AppendFileAction(file_action);
96 return true;
97 }
98 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +000099}
100
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101bool ProcessLaunchInfo::AppendSuppressFileAction(int fd, bool read,
102 bool write) {
103 FileAction file_action;
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000104 if (file_action.Open(fd, FileSpec(FileSystem::DEV_NULL), read, write)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105 AppendFileAction(file_action);
106 return true;
107 }
108 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000109}
110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111const FileAction *ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const {
112 if (idx < m_file_actions.size())
113 return &m_file_actions[idx];
114 return nullptr;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000115}
116
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117const FileAction *ProcessLaunchInfo::GetFileActionForFD(int fd) const {
118 for (size_t idx = 0, count = m_file_actions.size(); idx < count; ++idx) {
119 if (m_file_actions[idx].GetFD() == fd)
120 return &m_file_actions[idx];
121 }
122 return nullptr;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000123}
124
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125const FileSpec &ProcessLaunchInfo::GetWorkingDirectory() const {
126 return m_working_dir;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000127}
128
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129void ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir) {
130 m_working_dir = working_dir;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000131}
132
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133const char *ProcessLaunchInfo::GetProcessPluginName() const {
134 return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str());
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000135}
136
Zachary Turnerfe114832016-11-12 16:56:47 +0000137void ProcessLaunchInfo::SetProcessPluginName(llvm::StringRef plugin) {
138 m_plugin_name = plugin;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000139}
140
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141const FileSpec &ProcessLaunchInfo::GetShell() const { return m_shell; }
142
143void ProcessLaunchInfo::SetShell(const FileSpec &shell) {
144 m_shell = shell;
145 if (m_shell) {
Jonas Devlieghere2c22c802018-11-01 17:09:22 +0000146 FileSystem::Instance().ResolveExecutableLocation(m_shell);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 m_flags.Set(lldb::eLaunchFlagLaunchInShell);
148 } else
149 m_flags.Clear(lldb::eLaunchFlagLaunchInShell);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000150}
151
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152void ProcessLaunchInfo::SetLaunchInSeparateProcessGroup(bool separate) {
153 if (separate)
154 m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
155 else
156 m_flags.Clear(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
157}
158
159void ProcessLaunchInfo::SetShellExpandArguments(bool expand) {
160 if (expand)
161 m_flags.Set(lldb::eLaunchFlagShellExpandArguments);
162 else
163 m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);
164}
165
166void ProcessLaunchInfo::Clear() {
167 ProcessInfo::Clear();
168 m_working_dir.Clear();
169 m_plugin_name.clear();
170 m_shell.Clear();
171 m_flags.Clear();
172 m_file_actions.clear();
173 m_resume_count = 0;
174 m_listener_sp.reset();
175 m_hijack_listener_sp.reset();
176}
177
178void ProcessLaunchInfo::SetMonitorProcessCallback(
179 const Host::MonitorChildProcessCallback &callback, bool monitor_signals) {
180 m_monitor_callback = callback;
181 m_monitor_signals = monitor_signals;
182}
183
Pavel Labath245dd2e2018-05-15 13:42:26 +0000184bool ProcessLaunchInfo::NoOpMonitorCallback(lldb::pid_t pid, bool exited, int signal, int status) {
185 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS);
186 LLDB_LOG(log, "pid = {0}, exited = {1}, signal = {2}, status = {3}", pid,
187 exited, signal, status);
188 return true;
189}
190
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191bool ProcessLaunchInfo::MonitorProcess() const {
192 if (m_monitor_callback && ProcessIDIsValid()) {
193 Host::StartMonitoringChildProcess(m_monitor_callback, GetProcessID(),
194 m_monitor_signals);
195 return true;
196 }
197 return false;
198}
199
200void ProcessLaunchInfo::SetDetachOnError(bool enable) {
201 if (enable)
202 m_flags.Set(lldb::eLaunchFlagDetachOnError);
203 else
204 m_flags.Clear(lldb::eLaunchFlagDetachOnError);
205}
206
Pavel Labath8e55dde2019-01-08 11:55:19 +0000207llvm::Error ProcessLaunchInfo::SetUpPtyRedirection() {
208 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS);
209 LLDB_LOG(log, "Generating a pty to use for stdin/out/err");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210
Pavel Labath8e55dde2019-01-08 11:55:19 +0000211 int open_flags = O_RDWR | O_NOCTTY;
Hafiz Abid Qadeerf6ee79c2016-12-15 15:00:41 +0000212#if !defined(_WIN32)
Pavel Labath8e55dde2019-01-08 11:55:19 +0000213 // We really shouldn't be specifying platform specific flags that are
214 // intended for a system call in generic code. But this will have to
215 // do for now.
216 open_flags |= O_CLOEXEC;
Zachary Turner362a8132015-02-04 19:11:48 +0000217#endif
Pavel Labath8e55dde2019-01-08 11:55:19 +0000218 if (!m_pty->OpenFirstAvailableMaster(open_flags, nullptr, 0)) {
219 return llvm::createStringError(llvm::inconvertibleErrorCode(),
220 "PTY::OpenFirstAvailableMaster failed");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221 }
Pavel Labath8e55dde2019-01-08 11:55:19 +0000222 const FileSpec slave_file_spec(m_pty->GetSlaveName(nullptr, 0));
223
224 // Only use the slave tty if we don't have anything specified for
225 // input and don't have an action for stdin
226 if (GetFileActionForFD(STDIN_FILENO) == nullptr)
227 AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false);
228
229 // Only use the slave tty if we don't have anything specified for
230 // output and don't have an action for stdout
231 if (GetFileActionForFD(STDOUT_FILENO) == nullptr)
232 AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true);
233
234 // Only use the slave tty if we don't have anything specified for
235 // error and don't have an action for stderr
236 if (GetFileActionForFD(STDERR_FILENO) == nullptr)
237 AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true);
238 return llvm::Error::success();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000239}
240
Kate Stoneb9c1b512016-09-06 20:57:50 +0000241bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell(
Zachary Turner97206d52017-05-12 04:51:55 +0000242 Status &error, bool localhost, bool will_debug,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000243 bool first_arg_is_full_shell_command, int32_t num_resumes) {
244 error.Clear();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000245
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246 if (GetFlags().Test(eLaunchFlagLaunchInShell)) {
247 if (m_shell) {
248 std::string shell_executable = m_shell.GetPath();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000249
Kate Stoneb9c1b512016-09-06 20:57:50 +0000250 const char **argv = GetArguments().GetConstArgumentVector();
251 if (argv == nullptr || argv[0] == nullptr)
252 return false;
253 Args shell_arguments;
254 std::string safe_arg;
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000255 shell_arguments.AppendArgument(shell_executable);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000256 const llvm::Triple &triple = GetArchitecture().GetTriple();
257 if (triple.getOS() == llvm::Triple::Win32 &&
258 !triple.isWindowsCygwinEnvironment())
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000259 shell_arguments.AppendArgument(llvm::StringRef("/C"));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000260 else
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000261 shell_arguments.AppendArgument(llvm::StringRef("-c"));
Zachary Turner270e99a2014-12-08 21:36:42 +0000262
Kate Stoneb9c1b512016-09-06 20:57:50 +0000263 StreamString shell_command;
264 if (will_debug) {
Adrian Prantl05097242018-04-30 16:49:04 +0000265 // Add a modified PATH environment variable in case argv[0] is a
266 // relative path.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000267 const char *argv0 = argv[0];
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000268 FileSpec arg_spec(argv0);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269 if (arg_spec.IsRelative()) {
Adrian Prantl05097242018-04-30 16:49:04 +0000270 // We have a relative path to our executable which may not work if we
271 // just try to run "a.out" (without it being converted to "./a.out")
Kate Stoneb9c1b512016-09-06 20:57:50 +0000272 FileSpec working_dir = GetWorkingDirectory();
273 // Be sure to put quotes around PATH's value in case any paths have
274 // spaces...
275 std::string new_path("PATH=\"");
276 const size_t empty_path_len = new_path.size();
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000277
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278 if (working_dir) {
279 new_path += working_dir.GetPath();
280 } else {
Pavel Labath1d5855b2017-01-23 15:56:45 +0000281 llvm::SmallString<64> cwd;
282 if (! llvm::sys::fs::current_path(cwd))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000283 new_path += cwd;
284 }
285 std::string curr_path;
286 if (HostInfo::GetEnvironmentVar("PATH", curr_path)) {
287 if (new_path.size() > empty_path_len)
288 new_path += ':';
289 new_path += curr_path;
290 }
291 new_path += "\" ";
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000292 shell_command.PutCString(new_path);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000293 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000294
295 if (triple.getOS() != llvm::Triple::Win32 ||
296 triple.isWindowsCygwinEnvironment())
297 shell_command.PutCString("exec");
298
299 // Only Apple supports /usr/bin/arch being able to specify the
300 // architecture
301 if (GetArchitecture().IsValid() && // Valid architecture
302 GetArchitecture().GetTriple().getVendor() ==
303 llvm::Triple::Apple && // Apple only
304 GetArchitecture().GetCore() !=
305 ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
306 {
307 shell_command.Printf(" /usr/bin/arch -arch %s",
308 GetArchitecture().GetArchitectureName());
309 // Set the resume count to 2:
310 // 1 - stop in shell
311 // 2 - stop in /usr/bin/arch
312 // 3 - then we will stop in our program
313 SetResumeCount(num_resumes + 1);
314 } else {
315 // Set the resume count to 1:
316 // 1 - stop in shell
317 // 2 - then we will stop in our program
318 SetResumeCount(num_resumes);
319 }
320 }
321
322 if (first_arg_is_full_shell_command) {
Adrian Prantl05097242018-04-30 16:49:04 +0000323 // There should only be one argument that is the shell command itself
324 // to be used as is
Kate Stoneb9c1b512016-09-06 20:57:50 +0000325 if (argv[0] && !argv[1])
326 shell_command.Printf("%s", argv[0]);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000327 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000328 return false;
329 } else {
330 for (size_t i = 0; argv[i] != nullptr; ++i) {
331 const char *arg =
332 Args::GetShellSafeArgument(m_shell, argv[i], safe_arg);
333 shell_command.Printf(" %s", arg);
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000334 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 }
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000336 shell_arguments.AppendArgument(shell_command.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000337 m_executable = m_shell;
338 m_arguments = shell_arguments;
339 return true;
340 } else {
341 error.SetErrorString("invalid shell path");
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000342 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000343 } else {
344 error.SetErrorString("not launching in shell");
345 }
346 return false;
Todd Fiala6d6b55d2014-06-30 00:30:53 +0000347}