HostProcess ProcessLauncherAndroid::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) { // TODO: Handle other launch parameters specified in launc_info char exe_path[PATH_MAX]; launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); lldb::pid_t pid = ::fork(); if (pid == static_cast<lldb::pid_t>(-1)) { // Fork failed error.SetErrorStringWithFormat("Fork failed with error message: %s", strerror(errno)); return HostProcess(LLDB_INVALID_PROCESS_ID); } else if (pid == 0) { if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO)) { const char* path = file_action->GetPath(); if (path && ::strlen(path)) if (!DupDescriptor(path, STDIN_FILENO, O_RDONLY)) exit(-1); } if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDOUT_FILENO)) { const char* path = file_action->GetPath(); if (path && ::strlen(path)) if (!DupDescriptor(path, STDOUT_FILENO, O_WRONLY | O_CREAT | O_TRUNC)) exit(-1); } if (const lldb_private::FileAction *file_action = launch_info.GetFileActionForFD(STDERR_FILENO)) { const char* path = file_action->GetPath(); if (path && ::strlen(path)) if (!DupDescriptor(path, STDERR_FILENO, O_WRONLY | O_CREAT | O_TRUNC)) exit(-1); } // Child process const char **argv = launch_info.GetArguments().GetConstArgumentVector(); Args env = launch_info.GetEnvironmentEntries(); FixupEnvironment(env); const char **envp = env.GetConstArgumentVector(); const char *working_dir = launch_info.GetWorkingDirectory(); if (working_dir != nullptr && working_dir[0]) { if (::chdir(working_dir) != 0) exit(-1); } execve(argv[0], const_cast<char *const *>(argv), const_cast<char *const *>(envp)); exit(-1); } return HostProcess(pid); }
Error ProcessPOSIX::DoLaunch (Module *module, ProcessLaunchInfo &launch_info) { Error error; assert(m_monitor == NULL); const char* working_dir = launch_info.GetWorkingDirectory(); if (working_dir) { FileSpec WorkingDir(working_dir, true); if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory) { error.SetErrorStringWithFormat("No such file or directory: %s", working_dir); return error; } } SetPrivateState(eStateLaunching); const lldb_private::FileAction *file_action; // Default of NULL will mean to use existing open file descriptors const char *stdin_path = NULL; const char *stdout_path = NULL; const char *stderr_path = NULL; const char * dbg_pts_path = launch_info.GetPTY().GetSlaveName(NULL,0); file_action = launch_info.GetFileActionForFD (STDIN_FILENO); stdin_path = GetFilePath(file_action, stdin_path, dbg_pts_path); file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); stdout_path = GetFilePath(file_action, stdout_path, dbg_pts_path); file_action = launch_info.GetFileActionForFD (STDERR_FILENO); stderr_path = GetFilePath(file_action, stderr_path, dbg_pts_path); m_monitor = new ProcessMonitor (this, module, launch_info.GetArguments().GetConstArgumentVector(), launch_info.GetEnvironmentEntries().GetConstArgumentVector(), stdin_path, stdout_path, stderr_path, working_dir, launch_info, error); m_module = module; if (!error.Success()) return error; SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); SetID(m_monitor->GetPID()); return error; }
Error ProcessFreeBSD::DoLaunch (Module *module, ProcessLaunchInfo &launch_info) { Error error; assert(m_monitor == NULL); FileSpec working_dir = launch_info.GetWorkingDirectory(); if (working_dir && (!working_dir.ResolvePath() || working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) { error.SetErrorStringWithFormat("No such file or directory: %s", working_dir.GetCString()); return error; } SetPrivateState(eStateLaunching); const lldb_private::FileAction *file_action; // Default of empty will mean to use existing open file descriptors FileSpec stdin_file_spec{}; FileSpec stdout_file_spec{}; FileSpec stderr_file_spec{}; const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false}; file_action = launch_info.GetFileActionForFD (STDIN_FILENO); stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); file_action = launch_info.GetFileActionForFD (STDERR_FILENO); stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); m_monitor = new ProcessMonitor(this, module, launch_info.GetArguments().GetConstArgumentVector(), launch_info.GetEnvironmentEntries().GetConstArgumentVector(), stdin_file_spec, stdout_file_spec, stderr_file_spec, working_dir, launch_info, error); m_module = module; if (!error.Success()) return error; int terminal = m_monitor->GetTerminalFD(); if (terminal >= 0) { // The reader thread will close the file descriptor when done, so we pass it a copy. int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); if (stdio == -1) { error.SetErrorToErrno(); return error; } SetSTDIOFileDescriptor(stdio); } SetID(m_monitor->GetPID()); return error; }
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); Environment env = info.GetEnvironment(); FixupEnvironment(env); Environment::Envp envp = env.getEnvp(); // Clear the signal mask to prevent the child from being affected by any // masking done by the parent. sigset_t set; if (sigemptyset(&set) != 0 || pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0) ExitWithError(error_fd, "pthread_sigmask"); if (info.GetFlags().Test(eLaunchFlagDebug)) { // Do not inherit setgid powers. if (setgid(getgid()) != 0) ExitWithError(error_fd, "setgid"); // HACK: // Close everything besides stdin, stdout, and stderr that has no file // action to avoid leaking. Only do this when debugging, as elsewhere we // actually rely on passing open descriptors to child processes. 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... execve(argv[0], const_cast<char *const *>(argv), envp); #if defined(__linux__) if (errno == ETXTBSY) { // On android M and earlier we can get this error because the adb daemon // 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. usleep(50000); execve(argv[0], const_cast<char *const *>(argv), envp); } #endif // ...unless exec fails. In which case we definitely need to end the child // here. ExitWithError(error_fd, "execve"); }
Status ProcessFreeBSD::DoLaunch(Module *module, ProcessLaunchInfo &launch_info) { Status error; assert(m_monitor == NULL); FileSpec working_dir = launch_info.GetWorkingDirectory(); if (working_dir) { FileSystem::Instance().Resolve(working_dir); if (!FileSystem::Instance().IsDirectory(working_dir.GetPath())) { error.SetErrorStringWithFormat("No such file or directory: %s", working_dir.GetCString()); return error; } } SetPrivateState(eStateLaunching); const lldb_private::FileAction *file_action; // Default of empty will mean to use existing open file descriptors FileSpec stdin_file_spec{}; FileSpec stdout_file_spec{}; FileSpec stderr_file_spec{}; const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL, 0)}; file_action = launch_info.GetFileActionForFD(STDIN_FILENO); stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); file_action = launch_info.GetFileActionForFD(STDERR_FILENO); stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); m_monitor = new ProcessMonitor( this, module, launch_info.GetArguments().GetConstArgumentVector(), launch_info.GetEnvironment(), stdin_file_spec, stdout_file_spec, stderr_file_spec, working_dir, launch_info, error); m_module = module; if (!error.Success()) return error; int terminal = m_monitor->GetTerminalFD(); if (terminal >= 0) { // The reader thread will close the file descriptor when done, so we pass it a // copy. #ifdef F_DUPFD_CLOEXEC int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); if (stdio == -1) { error.SetErrorToErrno(); return error; } #else // Special case when F_DUPFD_CLOEXEC does not exist (Debian kFreeBSD) int stdio = fcntl(terminal, F_DUPFD, 0); if (stdio == -1) { error.SetErrorToErrno(); return error; } stdio = fcntl(terminal, F_SETFD, FD_CLOEXEC); if (stdio == -1) { error.SetErrorToErrno(); return error; } #endif SetSTDIOFileDescriptor(stdio); } SetID(m_monitor->GetPID()); return error; }
static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd, const ProcessLaunchInfo &info) { // First, make sure we disable all logging. If we are logging to stdout, our // logs can be // mistaken for inferior output. Log::DisableAllLogChannels(nullptr); // Do not inherit setgid powers. if (setgid(getgid()) != 0) ExitWithError(error_fd, "setgid"); 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"); // Disable ASLR if requested. 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"); } Args env = info.GetEnvironmentEntries(); FixupEnvironment(env); const char **envp = env.GetConstArgumentVector(); // Clear the signal mask to prevent the child from being affected by // any masking done by the parent. sigset_t set; if (sigemptyset(&set) != 0 || pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0) ExitWithError(error_fd, "pthread_sigmask"); if (info.GetFlags().Test(eLaunchFlagDebug)) { // HACK: // Close everything besides stdin, stdout, and stderr that has no file // action to avoid leaking. Only do this when debugging, as elsewhere we // actually rely on // passing open descriptors to child processes. 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(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) ExitWithError(error_fd, "ptrace"); } // Execute. We should never return... execve(argv[0], const_cast<char *const *>(argv), const_cast<char *const *>(envp)); if (errno == ETXTBSY) { // On android M and earlier we can get this error because the adb deamon 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. usleep(50000); execve(argv[0], const_cast<char *const *>(argv), const_cast<char *const *>(envp)); } // ...unless exec fails. In which case we definitely need to end the child // here. ExitWithError(error_fd, "execve"); }