brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.6 KiB · 510f9c7 Raw
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&LTOSTOP)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