2017-02-01 22:30:40 +08:00
|
|
|
//===-- ProcessLauncherLinux.cpp --------------------------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-02-01 22:30:40 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
|
|
|
|
#include "lldb/Host/Host.h"
|
|
|
|
#include "lldb/Host/HostProcess.h"
|
|
|
|
#include "lldb/Host/Pipe.h"
|
Move FileAction, ProcessInfo and ProcessLaunchInfo from Target to Host
Summary:
These classes describe the details of the process we are about to
launch, and so they are naturally used by the launching code in the Host
module. Previously they were present in Target because that is the most
important (but by far not the only) user of the launching code.
Since the launching code has other customers, must of which do not care
about Targets, it makes sense to move these classes to the Host layer,
next to the launching code.
This move reduces the number of times that Target is included from host
to 8 (it used to be 14).
Reviewers: zturner, clayborg, jingham, davide, teemperor
Subscribers: emaste, mgorny, lldb-commits
Differential Revision: https://reviews.llvm.org/D56602
llvm-svn: 353047
2019-02-04 22:28:08 +08:00
|
|
|
#include "lldb/Host/ProcessLaunchInfo.h"
|
2017-03-23 02:40:07 +08:00
|
|
|
#include "lldb/Utility/FileSpec.h"
|
2017-03-04 04:56:28 +08:00
|
|
|
#include "lldb/Utility/Log.h"
|
2017-06-06 22:06:17 +08:00
|
|
|
#include "llvm/Support/Errno.h"
|
2017-02-01 22:30:40 +08:00
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#include <sys/wait.h>
|
2017-07-18 21:14:01 +08:00
|
|
|
#include <unistd.h>
|
2017-02-01 22:30:40 +08:00
|
|
|
|
|
|
|
#include <sstream>
|
2017-07-18 22:03:47 +08:00
|
|
|
#include <csignal>
|
2017-02-01 22:30:40 +08:00
|
|
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
#include <android/api-level.h>
|
2017-02-02 00:43:22 +08:00
|
|
|
#define PT_TRACE_ME PTRACE_TRACEME
|
2017-02-01 22:30:40 +08:00
|
|
|
#endif
|
|
|
|
|
2017-09-16 10:19:21 +08:00
|
|
|
#if defined(__ANDROID_API__) && __ANDROID_API__ < 15
|
2017-02-01 22:30:40 +08:00
|
|
|
#include <linux/personality.h>
|
|
|
|
#elif defined(__linux__)
|
|
|
|
#include <sys/personality.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
Add Utility/Environment class for handling... environments
Summary:
There was some confusion in the code about how to represent process
environment. Most of the code (ab)used the Args class for this purpose,
but some of it used a more basic StringList class instead. In either
case, the fact that the underlying abstraction did not provide primitive
operations for the typical environment operations meant that even a
simple operation like checking for an environment variable value was
several lines of code.
This patch adds a separate Environment class, which is essentialy a
llvm::StringMap<std::string> in disguise. To standard StringMap
functionality, it adds a couple of new functions, which are specific to
the environment use case:
- (most important) envp conversion for passing into execve() and likes.
Instead of trying to maintain a constantly up-to-date envp view, it
provides a function which creates a envp view on demand, with the
expectation that this will be called as the very last thing before
handing the value to the system function.
- insert(StringRef KeyEqValue) - splits KeyEqValue into (key, value)
pair and inserts it into the environment map.
- compose(value_type KeyValue) - takes a map entry and converts in back
into "KEY=VALUE" representation.
With this interface most of the environment-manipulating code becomes
one-liners. The only tricky part was maintaining compatibility in
SBLaunchInfo, which expects that the environment entries are accessible
by index and that the returned const char* is backed by the launch info
object (random access into maps is hard and the map stores the entry in
a deconstructed form, so we cannot just return a .c_str() value). To
solve this, I have the SBLaunchInfo convert the environment into the
"envp" form, and use it to answer the environment queries. Extra code is
added to make sure the envp version is always in sync.
(This also improves the layering situation as Args was in the Interpreter module
whereas Environment is in Utility.)
Reviewers: zturner, davide, jingham, clayborg
Subscribers: emaste, lldb-commits, mgorny
Differential Revision: https://reviews.llvm.org/D41359
llvm-svn: 322174
2018-01-10 19:57:31 +08:00
|
|
|
static void FixupEnvironment(Environment &env) {
|
2017-02-01 22:30:40 +08:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
// If there is no PATH variable specified inside the environment then set the
|
|
|
|
// path to /system/bin. It is required because the default path used by
|
|
|
|
// execve() is wrong on android.
|
Add Utility/Environment class for handling... environments
Summary:
There was some confusion in the code about how to represent process
environment. Most of the code (ab)used the Args class for this purpose,
but some of it used a more basic StringList class instead. In either
case, the fact that the underlying abstraction did not provide primitive
operations for the typical environment operations meant that even a
simple operation like checking for an environment variable value was
several lines of code.
This patch adds a separate Environment class, which is essentialy a
llvm::StringMap<std::string> in disguise. To standard StringMap
functionality, it adds a couple of new functions, which are specific to
the environment use case:
- (most important) envp conversion for passing into execve() and likes.
Instead of trying to maintain a constantly up-to-date envp view, it
provides a function which creates a envp view on demand, with the
expectation that this will be called as the very last thing before
handing the value to the system function.
- insert(StringRef KeyEqValue) - splits KeyEqValue into (key, value)
pair and inserts it into the environment map.
- compose(value_type KeyValue) - takes a map entry and converts in back
into "KEY=VALUE" representation.
With this interface most of the environment-manipulating code becomes
one-liners. The only tricky part was maintaining compatibility in
SBLaunchInfo, which expects that the environment entries are accessible
by index and that the returned const char* is backed by the launch info
object (random access into maps is hard and the map stores the entry in
a deconstructed form, so we cannot just return a .c_str() value). To
solve this, I have the SBLaunchInfo convert the environment into the
"envp" form, and use it to answer the environment queries. Extra code is
added to make sure the envp version is always in sync.
(This also improves the layering situation as Args was in the Interpreter module
whereas Environment is in Utility.)
Reviewers: zturner, davide, jingham, clayborg
Subscribers: emaste, lldb-commits, mgorny
Differential Revision: https://reviews.llvm.org/D41359
llvm-svn: 322174
2018-01-10 19:57:31 +08:00
|
|
|
env.try_emplace("PATH", "/system/bin");
|
2017-02-01 22:30:40 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd,
|
|
|
|
const char *operation) {
|
2017-06-20 16:11:37 +08:00
|
|
|
int err = errno;
|
|
|
|
llvm::raw_fd_ostream os(error_fd, true);
|
|
|
|
os << operation << " failed: " << llvm::sys::StrError(err);
|
|
|
|
os.flush();
|
2017-02-01 22:30:40 +08:00
|
|
|
_exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DisableASLRIfRequested(int error_fd, const ProcessLaunchInfo &info) {
|
|
|
|
#if defined(__linux__)
|
|
|
|
if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) {
|
|
|
|
const unsigned long personality_get_current = 0xffffffff;
|
|
|
|
int value = personality(personality_get_current);
|
|
|
|
if (value == -1)
|
|
|
|
ExitWithError(error_fd, "personality get");
|
|
|
|
|
|
|
|
value = personality(ADDR_NO_RANDOMIZE | value);
|
|
|
|
if (value == -1)
|
|
|
|
ExitWithError(error_fd, "personality set");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DupDescriptor(int error_fd, const FileSpec &file_spec, int fd,
|
|
|
|
int flags) {
|
2019-03-22 03:35:55 +08:00
|
|
|
int target_fd = llvm::sys::RetryAfterSignal(-1, ::open,
|
|
|
|
file_spec.GetCString(), flags, 0666);
|
2017-02-01 22:30:40 +08:00
|
|
|
|
|
|
|
if (target_fd == -1)
|
|
|
|
ExitWithError(error_fd, "DupDescriptor-open");
|
|
|
|
|
|
|
|
if (target_fd == fd)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (::dup2(target_fd, fd) == -1)
|
|
|
|
ExitWithError(error_fd, "DupDescriptor-dup2");
|
|
|
|
|
|
|
|
::close(target_fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
|
|
|
|
const ProcessLaunchInfo &info) {
|
|
|
|
if (info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)) {
|
|
|
|
if (setpgid(0, 0) != 0)
|
|
|
|
ExitWithError(error_fd, "setpgid");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < info.GetNumFileActions(); ++i) {
|
|
|
|
const FileAction &action = *info.GetFileActionAtIndex(i);
|
|
|
|
switch (action.GetAction()) {
|
|
|
|
case FileAction::eFileActionClose:
|
|
|
|
if (close(action.GetFD()) != 0)
|
|
|
|
ExitWithError(error_fd, "close");
|
|
|
|
break;
|
|
|
|
case FileAction::eFileActionDuplicate:
|
|
|
|
if (dup2(action.GetFD(), action.GetActionArgument()) == -1)
|
|
|
|
ExitWithError(error_fd, "dup2");
|
|
|
|
break;
|
|
|
|
case FileAction::eFileActionOpen:
|
|
|
|
DupDescriptor(error_fd, action.GetFileSpec(), action.GetFD(),
|
|
|
|
action.GetActionArgument());
|
|
|
|
break;
|
|
|
|
case FileAction::eFileActionNone:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char **argv = info.GetArguments().GetConstArgumentVector();
|
|
|
|
|
|
|
|
// Change working directory
|
|
|
|
if (info.GetWorkingDirectory() &&
|
|
|
|
0 != ::chdir(info.GetWorkingDirectory().GetCString()))
|
|
|
|
ExitWithError(error_fd, "chdir");
|
|
|
|
|
|
|
|
DisableASLRIfRequested(error_fd, info);
|
Add Utility/Environment class for handling... environments
Summary:
There was some confusion in the code about how to represent process
environment. Most of the code (ab)used the Args class for this purpose,
but some of it used a more basic StringList class instead. In either
case, the fact that the underlying abstraction did not provide primitive
operations for the typical environment operations meant that even a
simple operation like checking for an environment variable value was
several lines of code.
This patch adds a separate Environment class, which is essentialy a
llvm::StringMap<std::string> in disguise. To standard StringMap
functionality, it adds a couple of new functions, which are specific to
the environment use case:
- (most important) envp conversion for passing into execve() and likes.
Instead of trying to maintain a constantly up-to-date envp view, it
provides a function which creates a envp view on demand, with the
expectation that this will be called as the very last thing before
handing the value to the system function.
- insert(StringRef KeyEqValue) - splits KeyEqValue into (key, value)
pair and inserts it into the environment map.
- compose(value_type KeyValue) - takes a map entry and converts in back
into "KEY=VALUE" representation.
With this interface most of the environment-manipulating code becomes
one-liners. The only tricky part was maintaining compatibility in
SBLaunchInfo, which expects that the environment entries are accessible
by index and that the returned const char* is backed by the launch info
object (random access into maps is hard and the map stores the entry in
a deconstructed form, so we cannot just return a .c_str() value). To
solve this, I have the SBLaunchInfo convert the environment into the
"envp" form, and use it to answer the environment queries. Extra code is
added to make sure the envp version is always in sync.
(This also improves the layering situation as Args was in the Interpreter module
whereas Environment is in Utility.)
Reviewers: zturner, davide, jingham, clayborg
Subscribers: emaste, lldb-commits, mgorny
Differential Revision: https://reviews.llvm.org/D41359
llvm-svn: 322174
2018-01-10 19:57:31 +08:00
|
|
|
Environment env = info.GetEnvironment();
|
2017-02-01 22:30:40 +08:00
|
|
|
FixupEnvironment(env);
|
Add Utility/Environment class for handling... environments
Summary:
There was some confusion in the code about how to represent process
environment. Most of the code (ab)used the Args class for this purpose,
but some of it used a more basic StringList class instead. In either
case, the fact that the underlying abstraction did not provide primitive
operations for the typical environment operations meant that even a
simple operation like checking for an environment variable value was
several lines of code.
This patch adds a separate Environment class, which is essentialy a
llvm::StringMap<std::string> in disguise. To standard StringMap
functionality, it adds a couple of new functions, which are specific to
the environment use case:
- (most important) envp conversion for passing into execve() and likes.
Instead of trying to maintain a constantly up-to-date envp view, it
provides a function which creates a envp view on demand, with the
expectation that this will be called as the very last thing before
handing the value to the system function.
- insert(StringRef KeyEqValue) - splits KeyEqValue into (key, value)
pair and inserts it into the environment map.
- compose(value_type KeyValue) - takes a map entry and converts in back
into "KEY=VALUE" representation.
With this interface most of the environment-manipulating code becomes
one-liners. The only tricky part was maintaining compatibility in
SBLaunchInfo, which expects that the environment entries are accessible
by index and that the returned const char* is backed by the launch info
object (random access into maps is hard and the map stores the entry in
a deconstructed form, so we cannot just return a .c_str() value). To
solve this, I have the SBLaunchInfo convert the environment into the
"envp" form, and use it to answer the environment queries. Extra code is
added to make sure the envp version is always in sync.
(This also improves the layering situation as Args was in the Interpreter module
whereas Environment is in Utility.)
Reviewers: zturner, davide, jingham, clayborg
Subscribers: emaste, lldb-commits, mgorny
Differential Revision: https://reviews.llvm.org/D41359
llvm-svn: 322174
2018-01-10 19:57:31 +08:00
|
|
|
Environment::Envp envp = env.getEnvp();
|
2017-02-01 22:30:40 +08:00
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// Clear the signal mask to prevent the child from being affected by any
|
|
|
|
// masking done by the parent.
|
2017-02-01 22:30:40 +08:00
|
|
|
sigset_t set;
|
|
|
|
if (sigemptyset(&set) != 0 ||
|
|
|
|
pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
|
|
|
|
ExitWithError(error_fd, "pthread_sigmask");
|
|
|
|
|
|
|
|
if (info.GetFlags().Test(eLaunchFlagDebug)) {
|
2018-05-23 18:10:36 +08:00
|
|
|
// Do not inherit setgid powers.
|
|
|
|
if (setgid(getgid()) != 0)
|
|
|
|
ExitWithError(error_fd, "setgid");
|
|
|
|
|
2017-02-01 22:30:40 +08:00
|
|
|
// HACK:
|
|
|
|
// Close everything besides stdin, stdout, and stderr that has no file
|
|
|
|
// action to avoid leaking. Only do this when debugging, as elsewhere we
|
2018-05-01 00:49:04 +08:00
|
|
|
// actually rely on passing open descriptors to child processes.
|
2017-02-01 22:30:40 +08:00
|
|
|
for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
|
|
|
|
if (!info.GetFileActionForFD(fd) && fd != error_fd)
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
// Start tracing this child that is about to exec.
|
|
|
|
if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
|
|
|
|
ExitWithError(error_fd, "ptrace");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute. We should never return...
|
Add Utility/Environment class for handling... environments
Summary:
There was some confusion in the code about how to represent process
environment. Most of the code (ab)used the Args class for this purpose,
but some of it used a more basic StringList class instead. In either
case, the fact that the underlying abstraction did not provide primitive
operations for the typical environment operations meant that even a
simple operation like checking for an environment variable value was
several lines of code.
This patch adds a separate Environment class, which is essentialy a
llvm::StringMap<std::string> in disguise. To standard StringMap
functionality, it adds a couple of new functions, which are specific to
the environment use case:
- (most important) envp conversion for passing into execve() and likes.
Instead of trying to maintain a constantly up-to-date envp view, it
provides a function which creates a envp view on demand, with the
expectation that this will be called as the very last thing before
handing the value to the system function.
- insert(StringRef KeyEqValue) - splits KeyEqValue into (key, value)
pair and inserts it into the environment map.
- compose(value_type KeyValue) - takes a map entry and converts in back
into "KEY=VALUE" representation.
With this interface most of the environment-manipulating code becomes
one-liners. The only tricky part was maintaining compatibility in
SBLaunchInfo, which expects that the environment entries are accessible
by index and that the returned const char* is backed by the launch info
object (random access into maps is hard and the map stores the entry in
a deconstructed form, so we cannot just return a .c_str() value). To
solve this, I have the SBLaunchInfo convert the environment into the
"envp" form, and use it to answer the environment queries. Extra code is
added to make sure the envp version is always in sync.
(This also improves the layering situation as Args was in the Interpreter module
whereas Environment is in Utility.)
Reviewers: zturner, davide, jingham, clayborg
Subscribers: emaste, lldb-commits, mgorny
Differential Revision: https://reviews.llvm.org/D41359
llvm-svn: 322174
2018-01-10 19:57:31 +08:00
|
|
|
execve(argv[0], const_cast<char *const *>(argv), envp);
|
2017-02-01 22:30:40 +08:00
|
|
|
|
|
|
|
#if defined(__linux__)
|
|
|
|
if (errno == ETXTBSY) {
|
2018-10-05 06:33:39 +08:00
|
|
|
// On android M and earlier we can get this error because the adb daemon
|
2018-05-01 00:49:04 +08:00
|
|
|
// can hold a write handle on the executable even after it has finished
|
|
|
|
// uploading it. This state lasts only a short time and happens only when
|
|
|
|
// there are many concurrent adb commands being issued, such as when
|
|
|
|
// running the test suite. (The file remains open when someone does an "adb
|
|
|
|
// shell" command in the fork() child before it has had a chance to exec.)
|
|
|
|
// Since this state should clear up quickly, wait a while and then give it
|
|
|
|
// one more go.
|
2017-02-01 22:30:40 +08:00
|
|
|
usleep(50000);
|
Add Utility/Environment class for handling... environments
Summary:
There was some confusion in the code about how to represent process
environment. Most of the code (ab)used the Args class for this purpose,
but some of it used a more basic StringList class instead. In either
case, the fact that the underlying abstraction did not provide primitive
operations for the typical environment operations meant that even a
simple operation like checking for an environment variable value was
several lines of code.
This patch adds a separate Environment class, which is essentialy a
llvm::StringMap<std::string> in disguise. To standard StringMap
functionality, it adds a couple of new functions, which are specific to
the environment use case:
- (most important) envp conversion for passing into execve() and likes.
Instead of trying to maintain a constantly up-to-date envp view, it
provides a function which creates a envp view on demand, with the
expectation that this will be called as the very last thing before
handing the value to the system function.
- insert(StringRef KeyEqValue) - splits KeyEqValue into (key, value)
pair and inserts it into the environment map.
- compose(value_type KeyValue) - takes a map entry and converts in back
into "KEY=VALUE" representation.
With this interface most of the environment-manipulating code becomes
one-liners. The only tricky part was maintaining compatibility in
SBLaunchInfo, which expects that the environment entries are accessible
by index and that the returned const char* is backed by the launch info
object (random access into maps is hard and the map stores the entry in
a deconstructed form, so we cannot just return a .c_str() value). To
solve this, I have the SBLaunchInfo convert the environment into the
"envp" form, and use it to answer the environment queries. Extra code is
added to make sure the envp version is always in sync.
(This also improves the layering situation as Args was in the Interpreter module
whereas Environment is in Utility.)
Reviewers: zturner, davide, jingham, clayborg
Subscribers: emaste, lldb-commits, mgorny
Differential Revision: https://reviews.llvm.org/D41359
llvm-svn: 322174
2018-01-10 19:57:31 +08:00
|
|
|
execve(argv[0], const_cast<char *const *>(argv), envp);
|
2017-02-01 22:30:40 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ...unless exec fails. In which case we definitely need to end the child
|
|
|
|
// here.
|
|
|
|
ExitWithError(error_fd, "execve");
|
|
|
|
}
|
|
|
|
|
|
|
|
HostProcess
|
|
|
|
ProcessLauncherPosixFork::LaunchProcess(const ProcessLaunchInfo &launch_info,
|
2017-05-12 12:51:55 +08:00
|
|
|
Status &error) {
|
2017-02-01 22:30:40 +08:00
|
|
|
char exe_path[PATH_MAX];
|
|
|
|
launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
|
|
|
|
|
|
|
|
// A pipe used by the child process to report errors.
|
|
|
|
PipePosix pipe;
|
|
|
|
const bool child_processes_inherit = false;
|
|
|
|
error = pipe.CreateNew(child_processes_inherit);
|
|
|
|
if (error.Fail())
|
|
|
|
return HostProcess();
|
|
|
|
|
|
|
|
::pid_t pid = ::fork();
|
|
|
|
if (pid == -1) {
|
|
|
|
// Fork failed
|
2017-06-06 22:06:17 +08:00
|
|
|
error.SetErrorStringWithFormatv("Fork failed with error message: {0}",
|
|
|
|
llvm::sys::StrError());
|
2017-02-01 22:30:40 +08:00
|
|
|
return HostProcess(LLDB_INVALID_PROCESS_ID);
|
|
|
|
}
|
|
|
|
if (pid == 0) {
|
|
|
|
// child process
|
|
|
|
pipe.CloseReadFileDescriptor();
|
|
|
|
ChildFunc(pipe.ReleaseWriteFileDescriptor(), launch_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// parent process
|
|
|
|
|
|
|
|
pipe.CloseWriteFileDescriptor();
|
|
|
|
char buf[1000];
|
|
|
|
int r = read(pipe.GetReadFileDescriptor(), buf, sizeof buf);
|
|
|
|
|
|
|
|
if (r == 0)
|
|
|
|
return HostProcess(pid); // No error. We're done.
|
|
|
|
|
|
|
|
error.SetErrorString(buf);
|
|
|
|
|
2019-03-22 03:35:55 +08:00
|
|
|
llvm::sys::RetryAfterSignal(-1, waitpid, pid, nullptr, 0);
|
2017-02-01 22:30:40 +08:00
|
|
|
|
|
|
|
return HostProcess();
|
|
|
|
}
|