brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.1 KiB · 49159cc Raw
343 lines · cpp
1//===-- ProcessLaunchInfo.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#include <climits>10 11#include "lldb/Host/Config.h"12#include "lldb/Host/FileAction.h"13#include "lldb/Host/FileSystem.h"14#include "lldb/Host/HostInfo.h"15#include "lldb/Host/ProcessLaunchInfo.h"16#include "lldb/Utility/LLDBLog.h"17#include "lldb/Utility/Log.h"18#include "lldb/Utility/StreamString.h"19 20#include "llvm/Support/ConvertUTF.h"21#include "llvm/Support/FileSystem.h"22 23#if !defined(_WIN32)24#include <climits>25#endif26 27using namespace lldb;28using namespace lldb_private;29 30// ProcessLaunchInfo member functions31 32ProcessLaunchInfo::ProcessLaunchInfo()33    : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0),34      m_file_actions(), m_pty(new PseudoTerminal), m_monitor_callback(nullptr) {35}36 37ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,38                                     const FileSpec &stdout_file_spec,39                                     const FileSpec &stderr_file_spec,40                                     const FileSpec &working_directory,41                                     uint32_t launch_flags)42    : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags),43      m_file_actions(), m_pty(new PseudoTerminal) {44  if (stdin_file_spec) {45    FileAction file_action;46    const bool read = true;47    const bool write = false;48    if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))49      AppendFileAction(file_action);50  }51  if (stdout_file_spec) {52    FileAction file_action;53    const bool read = false;54    const bool write = true;55    if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))56      AppendFileAction(file_action);57  }58  if (stderr_file_spec) {59    FileAction file_action;60    const bool read = false;61    const bool write = true;62    if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))63      AppendFileAction(file_action);64  }65  if (working_directory)66    SetWorkingDirectory(working_directory);67}68 69bool ProcessLaunchInfo::AppendCloseFileAction(int fd) {70  FileAction file_action;71  if (file_action.Close(fd)) {72    AppendFileAction(file_action);73    return true;74  }75  return false;76}77 78bool ProcessLaunchInfo::AppendDuplicateFileAction(int fd, int dup_fd) {79  FileAction file_action;80  if (file_action.Duplicate(fd, dup_fd)) {81    AppendFileAction(file_action);82    return true;83  }84  return false;85}86 87bool ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,88                                             bool read, bool write) {89  FileAction file_action;90  if (file_action.Open(fd, file_spec, read, write)) {91    AppendFileAction(file_action);92    return true;93  }94  return false;95}96 97bool ProcessLaunchInfo::AppendSuppressFileAction(int fd, bool read,98                                                 bool write) {99  FileAction file_action;100  if (file_action.Open(fd, FileSpec(FileSystem::DEV_NULL), read, write)) {101    AppendFileAction(file_action);102    return true;103  }104  return false;105}106 107const FileAction *ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const {108  if (idx < m_file_actions.size())109    return &m_file_actions[idx];110  return nullptr;111}112 113const FileAction *ProcessLaunchInfo::GetFileActionForFD(int fd) const {114  for (size_t idx = 0, count = m_file_actions.size(); idx < count; ++idx) {115    if (m_file_actions[idx].GetFD() == fd)116      return &m_file_actions[idx];117  }118  return nullptr;119}120 121const FileSpec &ProcessLaunchInfo::GetWorkingDirectory() const {122  return m_working_dir;123}124 125void ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir) {126  m_working_dir = working_dir;127}128 129llvm::StringRef ProcessLaunchInfo::GetProcessPluginName() const {130  return llvm::StringRef(m_plugin_name);131}132 133void ProcessLaunchInfo::SetProcessPluginName(llvm::StringRef plugin) {134  m_plugin_name = std::string(plugin);135}136 137const FileSpec &ProcessLaunchInfo::GetShell() const { return m_shell; }138 139void ProcessLaunchInfo::SetShell(const FileSpec &shell) {140  m_shell = shell;141  if (m_shell) {142    FileSystem::Instance().ResolveExecutableLocation(m_shell);143    m_flags.Set(lldb::eLaunchFlagLaunchInShell);144  } else145    m_flags.Clear(lldb::eLaunchFlagLaunchInShell);146}147 148void ProcessLaunchInfo::SetLaunchInSeparateProcessGroup(bool separate) {149  if (separate)150    m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);151  else152    m_flags.Clear(lldb::eLaunchFlagLaunchInSeparateProcessGroup);153}154 155void ProcessLaunchInfo::SetShellExpandArguments(bool expand) {156  if (expand)157    m_flags.Set(lldb::eLaunchFlagShellExpandArguments);158  else159    m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);160}161 162void ProcessLaunchInfo::Clear() {163  ProcessInfo::Clear();164  m_working_dir.Clear();165  m_plugin_name.clear();166  m_shell.Clear();167  m_flags.Clear();168  m_file_actions.clear();169  m_resume_count = 0;170  m_listener_sp.reset();171  m_hijack_listener_sp.reset();172}173 174void ProcessLaunchInfo::NoOpMonitorCallback(lldb::pid_t pid, int signal,175                                            int status) {176  Log *log = GetLog(LLDBLog::Process);177  LLDB_LOG(log, "pid = {0}, signal = {1}, status = {2}", pid, signal, status);178}179 180bool ProcessLaunchInfo::MonitorProcess() const {181  if (m_monitor_callback && ProcessIDIsValid()) {182    llvm::Expected<HostThread> maybe_thread =183        Host::StartMonitoringChildProcess(m_monitor_callback, GetProcessID());184    if (!maybe_thread)185      LLDB_LOG_ERROR(GetLog(LLDBLog::Host), maybe_thread.takeError(),186                     "failed to launch host thread: {0}");187    return true;188  }189  return false;190}191 192void ProcessLaunchInfo::SetDetachOnError(bool enable) {193  if (enable)194    m_flags.Set(lldb::eLaunchFlagDetachOnError);195  else196    m_flags.Clear(lldb::eLaunchFlagDetachOnError);197}198 199llvm::Error ProcessLaunchInfo::SetUpPtyRedirection() {200  Log *log = GetLog(LLDBLog::Process);201 202  bool stdin_free = GetFileActionForFD(STDIN_FILENO) == nullptr;203  bool stdout_free = GetFileActionForFD(STDOUT_FILENO) == nullptr;204  bool stderr_free = GetFileActionForFD(STDERR_FILENO) == nullptr;205  bool any_free = stdin_free || stdout_free || stderr_free;206  if (!any_free)207    return llvm::Error::success();208 209  LLDB_LOG(log, "Generating a pty to use for stdin/out/err");210 211  int open_flags = O_RDWR | O_NOCTTY;212#if !defined(_WIN32)213  // We really shouldn't be specifying platform specific flags that are214  // intended for a system call in generic code.  But this will have to215  // do for now.216  open_flags |= O_CLOEXEC;217#endif218  if (llvm::Error Err = m_pty->OpenFirstAvailablePrimary(open_flags))219    return Err;220 221  const FileSpec secondary_file_spec(m_pty->GetSecondaryName());222 223  if (stdin_free)224    AppendOpenFileAction(STDIN_FILENO, secondary_file_spec, true, false);225 226  if (stdout_free)227    AppendOpenFileAction(STDOUT_FILENO, secondary_file_spec, false, true);228 229  if (stderr_free)230    AppendOpenFileAction(STDERR_FILENO, secondary_file_spec, false, true);231  return llvm::Error::success();232}233 234bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell(235    Status &error, bool will_debug, bool first_arg_is_full_shell_command,236    uint32_t num_resumes) {237  error.Clear();238 239  if (GetFlags().Test(eLaunchFlagLaunchInShell)) {240    if (m_shell) {241      std::string shell_executable = m_shell.GetPath();242 243      const char **argv = GetArguments().GetConstArgumentVector();244      if (argv == nullptr || argv[0] == nullptr)245        return false;246      Args shell_arguments;247      shell_arguments.AppendArgument(shell_executable);248      const llvm::Triple &triple = GetArchitecture().GetTriple();249      if (triple.getOS() == llvm::Triple::Win32 &&250          !triple.isWindowsCygwinEnvironment())251        shell_arguments.AppendArgument(llvm::StringRef("/C"));252      else253        shell_arguments.AppendArgument(llvm::StringRef("-c"));254 255      StreamString shell_command;256      if (will_debug) {257        // Add a modified PATH environment variable in case argv[0] is a258        // relative path.259        const char *argv0 = argv[0];260        FileSpec arg_spec(argv0);261        if (arg_spec.IsRelative()) {262          // We have a relative path to our executable which may not work if we263          // just try to run "a.out" (without it being converted to "./a.out")264          FileSpec working_dir = GetWorkingDirectory();265          // Be sure to put quotes around PATH's value in case any paths have266          // spaces...267          std::string new_path("PATH=\"");268          const size_t empty_path_len = new_path.size();269 270          if (working_dir) {271            new_path += working_dir.GetPath();272          } else {273            llvm::SmallString<64> cwd;274            if (! llvm::sys::fs::current_path(cwd))275              new_path += cwd;276          }277          std::string curr_path;278          if (HostInfo::GetEnvironmentVar("PATH", curr_path)) {279            if (new_path.size() > empty_path_len)280              new_path += ':';281            new_path += curr_path;282          }283          new_path += "\" ";284          shell_command.PutCString(new_path);285        }286 287        if (triple.getOS() != llvm::Triple::Win32 ||288            triple.isWindowsCygwinEnvironment())289          shell_command.PutCString("exec");290 291        // Only Apple supports /usr/bin/arch being able to specify the292        // architecture293        if (GetArchitecture().IsValid() && // Valid architecture294            GetArchitecture().GetTriple().getVendor() ==295                llvm::Triple::Apple && // Apple only296            GetArchitecture().GetCore() !=297                ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h298        {299          shell_command.Printf(" /usr/bin/arch -arch %s",300                               GetArchitecture().GetArchitectureName());301          // Set the resume count to 2:302          // 1 - stop in shell303          // 2 - stop in /usr/bin/arch304          // 3 - then we will stop in our program305          SetResumeCount(num_resumes + 1);306        } else {307          // Set the resume count to 1:308          // 1 - stop in shell309          // 2 - then we will stop in our program310          SetResumeCount(num_resumes);311        }312      }313 314      if (first_arg_is_full_shell_command) {315        // There should only be one argument that is the shell command itself316        // to be used as is317        if (argv[0] && !argv[1])318          shell_command.Printf("%s", argv[0]);319        else320          return false;321      } else {322        for (size_t i = 0; argv[i] != nullptr; ++i) {323          std::string safe_arg = Args::GetShellSafeArgument(m_shell, argv[i]);324          if (safe_arg.empty())325            safe_arg = "\"\"";326          // Add a space to separate this arg from the previous one.327          shell_command.PutCString(" ");328          shell_command.PutCString(safe_arg);329        }330      }331      shell_arguments.AppendArgument(shell_command.GetString());332      m_executable = m_shell;333      m_arguments = shell_arguments;334      return true;335    } else {336      error = Status::FromErrorString("invalid shell path");337    }338  } else {339    error = Status::FromErrorString("not launching in shell");340  }341  return false;342}343