641 lines · cpp
1//===-- Host.cpp ----------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9// C includes10#include <cerrno>11#include <climits>12#include <cstdlib>13#include <sys/types.h>14 15#ifndef _WIN3216#include <dlfcn.h>17#include <grp.h>18#include <netdb.h>19#include <pwd.h>20#include <spawn.h>21#include <sys/stat.h>22#include <sys/wait.h>23#include <unistd.h>24#endif25 26#if defined(__APPLE__)27#include <mach-o/dyld.h>28#include <mach/mach_init.h>29#include <mach/mach_port.h>30#endif31 32#if defined(__FreeBSD__)33#include <pthread_np.h>34#endif35 36#if defined(__NetBSD__)37#include <lwp.h>38#endif39 40#include <csignal>41 42#include "lldb/Host/FileAction.h"43#include "lldb/Host/FileSystem.h"44#include "lldb/Host/Host.h"45#include "lldb/Host/HostInfo.h"46#include "lldb/Host/HostProcess.h"47#include "lldb/Host/MonitoringProcessLauncher.h"48#include "lldb/Host/ProcessLaunchInfo.h"49#include "lldb/Host/ProcessLauncher.h"50#include "lldb/Host/ThreadLauncher.h"51#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"52#include "lldb/Utility/FileSpec.h"53#include "lldb/Utility/LLDBLog.h"54#include "lldb/Utility/Log.h"55#include "lldb/Utility/Predicate.h"56#include "lldb/Utility/Status.h"57#include "lldb/lldb-private-forward.h"58#include "llvm/ADT/SmallString.h"59#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX60#include "llvm/Support/Errno.h"61#include "llvm/Support/FileSystem.h"62 63#if defined(_WIN32)64#include "lldb/Host/windows/ConnectionGenericFileWindows.h"65#include "lldb/Host/windows/ProcessLauncherWindows.h"66#else67#include "lldb/Host/posix/ProcessLauncherPosixFork.h"68#endif69 70#if defined(__APPLE__)71#ifndef _POSIX_SPAWN_DISABLE_ASLR72#define _POSIX_SPAWN_DISABLE_ASLR 0x010073#endif74 75extern "C" {76int __pthread_chdir(const char *path);77int __pthread_fchdir(int fildes);78}79 80#endif81 82using namespace lldb;83using namespace lldb_private;84 85#if !defined(__APPLE__) && !defined(_WIN32)86// The system log is currently only meaningful on Darwin and Windows.87// On Darwin, this means os_log. On Windows this means Events Viewer.88// The meaning of a "system log" isn't as clear on other platforms, and89// therefore we don't providate a default implementation. Vendors are free90// to implement this function if they have a use for it.91void Host::SystemLog(Severity severity, llvm::StringRef message) {}92#endif93 94static constexpr Log::Category g_categories[] = {95 {{"system"}, {"system log"}, SystemLog::System}};96 97static Log::Channel g_system_channel(g_categories, SystemLog::System);98static Log g_system_log(g_system_channel);99 100template <> Log::Channel &lldb_private::LogChannelFor<SystemLog>() {101 return g_system_channel;102}103 104void LogChannelSystem::Initialize() {105 g_system_log.Enable(std::make_shared<SystemLogHandler>());106}107 108void LogChannelSystem::Terminate() { g_system_log.Disable(); }109 110#if !defined(__APPLE__) && !defined(_WIN32)111extern "C" char **environ;112 113Environment Host::GetEnvironment() { return Environment(environ); }114 115static thread_result_t116MonitorChildProcessThreadFunction(::pid_t pid,117 Host::MonitorChildProcessCallback callback);118 119llvm::Expected<HostThread> Host::StartMonitoringChildProcess(120 const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {121 char thread_name[256];122 ::snprintf(thread_name, sizeof(thread_name),123 "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);124 assert(pid <= UINT32_MAX);125 return ThreadLauncher::LaunchThread(thread_name, [pid, callback] {126 return MonitorChildProcessThreadFunction(pid, callback);127 });128}129 130#ifndef __linux__131// Scoped class that will disable thread canceling when it is constructed, and132// exception safely restore the previous value it when it goes out of scope.133class ScopedPThreadCancelDisabler {134public:135 ScopedPThreadCancelDisabler() {136 // Disable the ability for this thread to be cancelled137 int err = ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m_old_state);138 if (err != 0)139 m_old_state = -1;140 }141 142 ~ScopedPThreadCancelDisabler() {143 // Restore the ability for this thread to be cancelled to what it144 // previously was.145 if (m_old_state != -1)146 ::pthread_setcancelstate(m_old_state, 0);147 }148 149private:150 int m_old_state; // Save the old cancelability state.151};152#endif // __linux__153 154#ifdef __linux__155static thread_local volatile sig_atomic_t g_usr1_called;156 157static void SigUsr1Handler(int) { g_usr1_called = 1; }158#endif // __linux__159 160static bool CheckForMonitorCancellation() {161#ifdef __linux__162 if (g_usr1_called) {163 g_usr1_called = 0;164 return true;165 }166#else167 ::pthread_testcancel();168#endif169 return false;170}171 172static thread_result_t173MonitorChildProcessThreadFunction(::pid_t pid,174 Host::MonitorChildProcessCallback callback) {175 Log *log = GetLog(LLDBLog::Process);176 LLDB_LOG(log, "pid = {0}", pid);177 178 int status = -1;179 180#ifdef __linux__181 // This signal is only used to interrupt the thread from waitpid182 struct sigaction sigUsr1Action;183 memset(&sigUsr1Action, 0, sizeof(sigUsr1Action));184 sigUsr1Action.sa_handler = SigUsr1Handler;185 ::sigaction(SIGUSR1, &sigUsr1Action, nullptr);186#endif // __linux__187 188 while (true) {189 log = GetLog(LLDBLog::Process);190 LLDB_LOG(log, "::waitpid({0}, &status, 0)...", pid);191 192 if (CheckForMonitorCancellation())193 return nullptr;194 195 const ::pid_t wait_pid = ::waitpid(pid, &status, 0);196 197 LLDB_LOG(log, "::waitpid({0}, &status, 0) => pid = {1}, status = {2:x}",198 pid, wait_pid, status);199 200 if (CheckForMonitorCancellation())201 return nullptr;202 203 if (wait_pid != -1)204 break;205 if (errno != EINTR) {206 LLDB_LOG(log, "pid = {0}, thread exiting because waitpid failed ({1})...",207 pid, llvm::sys::StrError());208 return nullptr;209 }210 }211 212 int signal = 0;213 int exit_status = 0;214 if (WIFEXITED(status)) {215 exit_status = WEXITSTATUS(status);216 } else if (WIFSIGNALED(status)) {217 signal = WTERMSIG(status);218 exit_status = -1;219 } else {220 llvm_unreachable("Unknown status");221 }222 223 // Scope for pthread_cancel_disabler224 {225#ifndef __linux__226 ScopedPThreadCancelDisabler pthread_cancel_disabler;227#endif228 229 if (callback)230 callback(pid, signal, exit_status);231 }232 233 LLDB_LOG(GetLog(LLDBLog::Process), "pid = {0} thread exiting...", pid);234 return nullptr;235}236 237#endif // #if !defined (__APPLE__) && !defined (_WIN32)238 239lldb::pid_t Host::GetCurrentProcessID() { return ::getpid(); }240 241#ifndef _WIN32242 243lldb::thread_t Host::GetCurrentThread() {244 return lldb::thread_t(pthread_self());245}246 247const char *Host::GetSignalAsCString(int signo) {248 switch (signo) {249 case SIGHUP:250 return "SIGHUP"; // 1 hangup251 case SIGINT:252 return "SIGINT"; // 2 interrupt253 case SIGQUIT:254 return "SIGQUIT"; // 3 quit255 case SIGILL:256 return "SIGILL"; // 4 illegal instruction (not reset when caught)257 case SIGTRAP:258 return "SIGTRAP"; // 5 trace trap (not reset when caught)259 case SIGABRT:260 return "SIGABRT"; // 6 abort()261#if defined(SIGPOLL)262#if !defined(SIGIO) || (SIGPOLL != SIGIO)263 // Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to264 // fail with 'multiple define cases with same value'265 case SIGPOLL:266 return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported)267#endif268#endif269#if defined(SIGEMT)270 case SIGEMT:271 return "SIGEMT"; // 7 EMT instruction272#endif273 case SIGFPE:274 return "SIGFPE"; // 8 floating point exception275 case SIGKILL:276 return "SIGKILL"; // 9 kill (cannot be caught or ignored)277 case SIGBUS:278 return "SIGBUS"; // 10 bus error279 case SIGSEGV:280 return "SIGSEGV"; // 11 segmentation violation281 case SIGSYS:282 return "SIGSYS"; // 12 bad argument to system call283 case SIGPIPE:284 return "SIGPIPE"; // 13 write on a pipe with no one to read it285 case SIGALRM:286 return "SIGALRM"; // 14 alarm clock287 case SIGTERM:288 return "SIGTERM"; // 15 software termination signal from kill289 case SIGURG:290 return "SIGURG"; // 16 urgent condition on IO channel291 case SIGSTOP:292 return "SIGSTOP"; // 17 sendable stop signal not from tty293 case SIGTSTP:294 return "SIGTSTP"; // 18 stop signal from tty295 case SIGCONT:296 return "SIGCONT"; // 19 continue a stopped process297 case SIGCHLD:298 return "SIGCHLD"; // 20 to parent on child stop or exit299 case SIGTTIN:300 return "SIGTTIN"; // 21 to readers pgrp upon background tty read301 case SIGTTOU:302 return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP)303#if defined(SIGIO)304 case SIGIO:305 return "SIGIO"; // 23 input/output possible signal306#endif307 case SIGXCPU:308 return "SIGXCPU"; // 24 exceeded CPU time limit309 case SIGXFSZ:310 return "SIGXFSZ"; // 25 exceeded file size limit311 case SIGVTALRM:312 return "SIGVTALRM"; // 26 virtual time alarm313 case SIGPROF:314 return "SIGPROF"; // 27 profiling time alarm315#if defined(SIGWINCH)316 case SIGWINCH:317 return "SIGWINCH"; // 28 window size changes318#endif319#if defined(SIGINFO)320 case SIGINFO:321 return "SIGINFO"; // 29 information request322#endif323 case SIGUSR1:324 return "SIGUSR1"; // 30 user defined signal 1325 case SIGUSR2:326 return "SIGUSR2"; // 31 user defined signal 2327 default:328 break;329 }330 return nullptr;331}332 333#endif334 335#if !defined(__APPLE__) // see Host.mm336 337bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) {338 bundle.Clear();339 return false;340}341 342bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; }343#endif344 345#ifndef _WIN32346 347FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {348 FileSpec module_filespec;349 Dl_info info;350 if (::dladdr(host_addr, &info)) {351 if (info.dli_fname) {352 module_filespec.SetFile(info.dli_fname, FileSpec::Style::native);353 FileSystem::Instance().Resolve(module_filespec);354 }355 }356 return module_filespec;357}358 359#endif360 361#if !defined(__linux__)362bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) {363 return false;364}365#endif366 367struct ShellInfo {368 ShellInfo() : process_reaped(false) {}369 370 lldb_private::Predicate<bool> process_reaped;371 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;372 int signo = -1;373 int status = -1;374};375 376static void377MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid,378 int signo, // Zero for no signal379 int status) // Exit value of process if signal is zero380{381 shell_info->pid = pid;382 shell_info->signo = signo;383 shell_info->status = status;384 // Let the thread running Host::RunShellCommand() know that the process385 // exited and that ShellInfo has been filled in by broadcasting to it386 shell_info->process_reaped.SetValue(true, eBroadcastAlways);387}388 389Status Host::RunShellCommand(llvm::StringRef command,390 const FileSpec &working_dir, int *status_ptr,391 int *signo_ptr, std::string *command_output_ptr,392 const Timeout<std::micro> &timeout,393 bool run_in_shell, bool hide_stderr) {394 return RunShellCommand(llvm::StringRef(), Args(command), working_dir,395 status_ptr, signo_ptr, command_output_ptr, timeout,396 run_in_shell, hide_stderr);397}398 399Status Host::RunShellCommand(llvm::StringRef shell_path,400 llvm::StringRef command,401 const FileSpec &working_dir, int *status_ptr,402 int *signo_ptr, std::string *command_output_ptr,403 const Timeout<std::micro> &timeout,404 bool run_in_shell, bool hide_stderr) {405 return RunShellCommand(shell_path, Args(command), working_dir, status_ptr,406 signo_ptr, command_output_ptr, timeout, run_in_shell,407 hide_stderr);408}409 410Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir,411 int *status_ptr, int *signo_ptr,412 std::string *command_output_ptr,413 const Timeout<std::micro> &timeout,414 bool run_in_shell, bool hide_stderr) {415 return RunShellCommand(llvm::StringRef(), args, working_dir, status_ptr,416 signo_ptr, command_output_ptr, timeout, run_in_shell,417 hide_stderr);418}419 420Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args,421 const FileSpec &working_dir, int *status_ptr,422 int *signo_ptr, std::string *command_output_ptr,423 const Timeout<std::micro> &timeout,424 bool run_in_shell, bool hide_stderr) {425 Status error;426 ProcessLaunchInfo launch_info;427 launch_info.SetArchitecture(HostInfo::GetArchitecture());428 if (run_in_shell) {429 // Run the command in a shell430 FileSpec shell = HostInfo::GetDefaultShell();431 if (!shell_path.empty())432 shell.SetPath(shell_path);433 434 launch_info.SetShell(shell);435 launch_info.GetArguments().AppendArguments(args);436 const bool will_debug = false;437 const bool first_arg_is_full_shell_command = false;438 launch_info.ConvertArgumentsForLaunchingInShell(439 error, will_debug, first_arg_is_full_shell_command, 0);440 } else {441 // No shell, just run it442 const bool first_arg_is_executable = true;443 launch_info.SetArguments(args, first_arg_is_executable);444 }445 446 launch_info.GetEnvironment() = Host::GetEnvironment();447 448 if (working_dir)449 launch_info.SetWorkingDirectory(working_dir);450 llvm::SmallString<64> output_file_path;451 452 if (command_output_ptr) {453 // Create a temporary file to get the stdout/stderr and redirect the output454 // of the command into this file. We will later read this file if all goes455 // well and fill the data into "command_output_ptr"456 if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) {457 tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%");458 llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),459 output_file_path);460 } else {461 llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "",462 output_file_path);463 }464 }465 466 FileSpec output_file_spec(output_file_path.str());467 // Set up file descriptors.468 launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);469 if (output_file_spec)470 launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_spec, false,471 true);472 else473 launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);474 475 if (output_file_spec && !hide_stderr)476 launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);477 else478 launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);479 480 std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo());481 launch_info.SetMonitorProcessCallback(482 std::bind(MonitorShellCommand, shell_info_sp, std::placeholders::_1,483 std::placeholders::_2, std::placeholders::_3));484 485 error = LaunchProcess(launch_info);486 const lldb::pid_t pid = launch_info.GetProcessID();487 488 if (error.Success() && pid == LLDB_INVALID_PROCESS_ID)489 error = Status::FromErrorString("failed to get process ID");490 491 if (error.Success()) {492 if (!shell_info_sp->process_reaped.WaitForValueEqualTo(true, timeout)) {493 error = Status::FromErrorString(494 "timed out waiting for shell command to complete");495 496 // Kill the process since it didn't complete within the timeout specified497 Kill(pid, SIGKILL);498 // Wait for the monitor callback to get the message499 shell_info_sp->process_reaped.WaitForValueEqualTo(500 true, std::chrono::seconds(1));501 } else {502 if (status_ptr)503 *status_ptr = shell_info_sp->status;504 505 if (signo_ptr)506 *signo_ptr = shell_info_sp->signo;507 508 if (command_output_ptr) {509 command_output_ptr->clear();510 uint64_t file_size =511 FileSystem::Instance().GetByteSize(output_file_spec);512 if (file_size > 0) {513 if (file_size > command_output_ptr->max_size()) {514 error = Status::FromErrorStringWithFormat(515 "shell command output is too large to fit into a std::string");516 } else {517 WritableDataBufferSP Buffer =518 FileSystem::Instance().CreateWritableDataBuffer(519 output_file_spec);520 if (error.Success())521 command_output_ptr->assign(522 reinterpret_cast<char *>(Buffer->GetBytes()),523 Buffer->GetByteSize());524 }525 }526 }527 }528 }529 530 llvm::sys::fs::remove(output_file_spec.GetPath());531 return error;532}533 534// The functions below implement process launching for non-Apple-based535// platforms536#if !defined(__APPLE__)537Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {538 std::unique_ptr<ProcessLauncher> delegate_launcher;539#if defined(_WIN32)540 delegate_launcher.reset(new ProcessLauncherWindows());541#else542 delegate_launcher.reset(new ProcessLauncherPosixFork());543#endif544 MonitoringProcessLauncher launcher(std::move(delegate_launcher));545 546 Status error;547 HostProcess process = launcher.LaunchProcess(launch_info, error);548 549 // TODO(zturner): It would be better if the entire HostProcess were returned550 // instead of writing it into this structure.551 launch_info.SetProcessID(process.GetProcessId());552 553 return error;554}555#endif // !defined(__APPLE__)556 557#ifndef _WIN32558void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); }559 560#endif561 562#if !defined(__APPLE__)563llvm::Error Host::OpenFileInExternalEditor(llvm::StringRef editor,564 const FileSpec &file_spec,565 uint32_t line_no) {566 return llvm::errorCodeToError(567 std::error_code(ENOTSUP, std::system_category()));568}569 570bool Host::IsInteractiveGraphicSession() { return false; }571#endif572 573std::unique_ptr<Connection> Host::CreateDefaultConnection(llvm::StringRef url) {574#if defined(_WIN32)575 if (url.starts_with("file://"))576 return std::unique_ptr<Connection>(new ConnectionGenericFile());577#endif578 return std::unique_ptr<Connection>(new ConnectionFileDescriptor());579}580 581#if defined(LLVM_ON_UNIX)582WaitStatus WaitStatus::Decode(int wstatus) {583 if (WIFEXITED(wstatus))584 return {Exit, uint8_t(WEXITSTATUS(wstatus))};585 else if (WIFSIGNALED(wstatus))586 return {Signal, uint8_t(WTERMSIG(wstatus))};587 else if (WIFSTOPPED(wstatus))588 return {Stop, uint8_t(WSTOPSIG(wstatus))};589 llvm_unreachable("Unknown wait status");590}591#endif592 593void llvm::format_provider<WaitStatus>::format(const WaitStatus &WS,594 raw_ostream &OS,595 StringRef Options) {596 if (Options == "g") {597 char type;598 switch (WS.type) {599 case WaitStatus::Exit:600 type = 'W';601 break;602 case WaitStatus::Signal:603 type = 'X';604 break;605 case WaitStatus::Stop:606 type = 'S';607 break;608 }609 OS << formatv("{0}{1:x-2}", type, WS.status);610 return;611 }612 613 assert(Options.empty());614 const char *desc;615 switch (WS.type) {616 case WaitStatus::Exit:617 desc = "Exited with status";618 break;619 case WaitStatus::Signal:620 desc = "Killed by signal";621 break;622 case WaitStatus::Stop:623 desc = "Stopped by signal";624 break;625 }626 OS << desc << " " << int(WS.status);627}628 629uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,630 ProcessInstanceInfoList &process_infos) {631 return FindProcessesImpl(match_info, process_infos);632}633 634char SystemLogHandler::ID;635 636SystemLogHandler::SystemLogHandler() {}637 638void SystemLogHandler::Emit(llvm::StringRef message) {639 Host::SystemLog(lldb::eSeverityInfo, message);640}641