brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.4 KiB · d5704ee Raw
333 lines · cpp
1//===-- source/Host/windows/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#include "lldb/Host/windows/AutoHandle.h"10#include "lldb/Host/windows/windows.h"11#include <cstdio>12 13#include "lldb/Host/FileSystem.h"14#include "lldb/Host/Host.h"15#include "lldb/Host/HostInfo.h"16#include "lldb/Host/ProcessLaunchInfo.h"17#include "lldb/Utility/DataBufferHeap.h"18#include "lldb/Utility/DataExtractor.h"19#include "lldb/Utility/Log.h"20#include "lldb/Utility/ProcessInfo.h"21#include "lldb/Utility/Status.h"22#include "lldb/Utility/StreamString.h"23#include "lldb/Utility/StructuredData.h"24 25#include "llvm/ADT/StringRef.h"26#include "llvm/Support/ConvertUTF.h"27 28// Windows includes29#include <tlhelp32.h>30 31using namespace lldb;32using namespace lldb_private;33 34using llvm::sys::windows::UTF8ToUTF16;35 36static bool GetTripleForProcess(const FileSpec &executable,37                                llvm::Triple &triple) {38  // Open the PE File as a binary file, and parse just enough information to39  // determine the machine type.40  auto imageBinaryP = FileSystem::Instance().Open(41      executable, File::eOpenOptionReadOnly, lldb::eFilePermissionsUserRead);42  if (!imageBinaryP)43    return llvm::errorToBool(imageBinaryP.takeError());44  File &imageBinary = *imageBinaryP.get();45  imageBinary.SeekFromStart(0x3c);46  int32_t peOffset = 0;47  uint32_t peHead = 0;48  uint16_t machineType = 0;49  size_t readSize = sizeof(peOffset);50  imageBinary.Read(&peOffset, readSize);51  imageBinary.SeekFromStart(peOffset);52  imageBinary.Read(&peHead, readSize);53  if (peHead != 0x00004550) // "PE\0\0", little-endian54    return false;           // Status: Can't find PE header55  readSize = 2;56  imageBinary.Read(&machineType, readSize);57  triple.setVendor(llvm::Triple::PC);58  triple.setOS(llvm::Triple::Win32);59  triple.setArch(llvm::Triple::UnknownArch);60  if (machineType == 0x8664)61    triple.setArch(llvm::Triple::x86_64);62  else if (machineType == 0x14c)63    triple.setArch(llvm::Triple::x86);64  else if (machineType == 0x1c4)65    triple.setArch(llvm::Triple::arm);66  else if (machineType == 0xaa64)67    triple.setArch(llvm::Triple::aarch64);68 69  return true;70}71 72static bool GetExecutableForProcess(const AutoHandle &handle,73                                    std::string &path) {74  // Get the process image path.  MAX_PATH isn't long enough, paths can75  // actually be up to 32KB.76  std::vector<wchar_t> buffer(PATH_MAX);77  DWORD dwSize = buffer.size();78  if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize))79    return false;80  return llvm::convertWideToUTF8(buffer.data(), path);81}82 83static void GetProcessExecutableAndTriple(const AutoHandle &handle,84                                          ProcessInstanceInfo &process) {85  // We may not have permissions to read the path from the process.  So start86  // off by setting the executable file to whatever Toolhelp32 gives us, and87  // then try to enhance this with more detailed information, but fail88  // gracefully.89  std::string executable;90  llvm::Triple triple;91  triple.setVendor(llvm::Triple::PC);92  triple.setOS(llvm::Triple::Win32);93  triple.setArch(llvm::Triple::UnknownArch);94  if (GetExecutableForProcess(handle, executable)) {95    FileSpec executableFile(executable.c_str());96    process.SetExecutableFile(executableFile, true);97    GetTripleForProcess(executableFile, triple);98  }99  process.SetArchitecture(ArchSpec(triple));100 101  // TODO(zturner): Add the ability to get the process user name.102}103 104lldb::thread_t Host::GetCurrentThread() {105  return lldb::thread_t(::GetCurrentThread());106}107 108void Host::Kill(lldb::pid_t pid, int signo) {109  AutoHandle handle(::OpenProcess(PROCESS_TERMINATE, FALSE, pid), nullptr);110  if (handle.IsValid())111    ::TerminateProcess(handle.get(), 1);112}113 114const char *Host::GetSignalAsCString(int signo) { return NULL; }115 116FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) {117  FileSpec module_filespec;118 119  HMODULE hmodule = NULL;120  if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,121                           (LPCTSTR)host_addr, &hmodule))122    return module_filespec;123 124  std::vector<wchar_t> buffer(PATH_MAX);125  DWORD chars_copied = 0;126  do {127    chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size());128    if (chars_copied == buffer.size() &&129        ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)130      buffer.resize(buffer.size() * 2);131  } while (chars_copied >= buffer.size());132  std::string path;133  if (!llvm::convertWideToUTF8(buffer.data(), path))134    return module_filespec;135  module_filespec.SetFile(path, FileSpec::Style::native);136  return module_filespec;137}138 139uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,140                                 ProcessInstanceInfoList &process_infos) {141  process_infos.clear();142 143  AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));144  if (!snapshot.IsValid())145    return 0;146 147  PROCESSENTRY32W pe = {};148  pe.dwSize = sizeof(PROCESSENTRY32W);149  if (Process32FirstW(snapshot.get(), &pe)) {150    do {151      AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,152                                      pe.th32ProcessID),153                        nullptr);154 155      ProcessInstanceInfo process;156      std::string exeFile;157      llvm::convertWideToUTF8(pe.szExeFile, exeFile);158      process.SetExecutableFile(FileSpec(exeFile), true);159      process.SetProcessID(pe.th32ProcessID);160      process.SetParentProcessID(pe.th32ParentProcessID);161      GetProcessExecutableAndTriple(handle, process);162 163      if (match_info.MatchAllProcesses() || match_info.Matches(process))164        process_infos.push_back(process);165    } while (Process32NextW(snapshot.get(), &pe));166  }167  return process_infos.size();168}169 170bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {171  process_info.Clear();172 173  AutoHandle handle(174      ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),175      nullptr);176  if (!handle.IsValid())177    return false;178 179  process_info.SetProcessID(pid);180  GetProcessExecutableAndTriple(handle, process_info);181 182  // Need to read the PEB to get parent process and command line arguments.183 184  AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));185  if (!snapshot.IsValid())186    return false;187 188  PROCESSENTRY32W pe;189  pe.dwSize = sizeof(PROCESSENTRY32W);190  if (Process32FirstW(snapshot.get(), &pe)) {191    do {192      if (pe.th32ProcessID == pid) {193        process_info.SetParentProcessID(pe.th32ParentProcessID);194        return true;195      }196    } while (Process32NextW(snapshot.get(), &pe));197  }198 199  return false;200}201 202llvm::Expected<HostThread> Host::StartMonitoringChildProcess(203    const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid) {204  return HostThread();205}206 207Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {208  Status error;209  if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) {210    FileSpec expand_tool_spec = HostInfo::GetSupportExeDir();211    if (!expand_tool_spec) {212      error = Status::FromErrorString(213          "could not find support executable directory for "214          "the lldb-argdumper tool");215      return error;216    }217    expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");218    if (!FileSystem::Instance().Exists(expand_tool_spec)) {219      error = Status::FromErrorString("could not find the lldb-argdumper tool");220      return error;221    }222 223    std::string quoted_cmd_string;224    launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);225    std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');226    StreamString expand_command;227 228    expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(),229                          quoted_cmd_string.c_str());230 231    int status;232    std::string output;233    std::string command = expand_command.GetString().str();234    Status e =235        RunShellCommand(command.c_str(), launch_info.GetWorkingDirectory(),236                        &status, nullptr, &output, std::chrono::seconds(10));237 238    if (e.Fail())239      return e;240 241    if (status != 0) {242      error = Status::FromErrorStringWithFormat(243          "lldb-argdumper exited with error %d", status);244      return error;245    }246 247    auto data_sp = StructuredData::ParseJSON(output);248    if (!data_sp) {249      error = Status::FromErrorString("invalid JSON");250      return error;251    }252 253    auto dict_sp = data_sp->GetAsDictionary();254    if (!dict_sp) {255      error = Status::FromErrorString("invalid JSON");256      return error;257    }258 259    auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");260    if (!args_sp) {261      error = Status::FromErrorString("invalid JSON");262      return error;263    }264 265    auto args_array_sp = args_sp->GetAsArray();266    if (!args_array_sp) {267      error = Status::FromErrorString("invalid JSON");268      return error;269    }270 271    launch_info.GetArguments().Clear();272 273    for (size_t i = 0; i < args_array_sp->GetSize(); i++) {274      auto item_sp = args_array_sp->GetItemAtIndex(i);275      if (!item_sp)276        continue;277      auto str_sp = item_sp->GetAsString();278      if (!str_sp)279        continue;280 281      launch_info.GetArguments().AppendArgument(str_sp->GetValue());282    }283  }284 285  return error;286}287 288Environment Host::GetEnvironment() {289  Environment env;290  // The environment block on Windows is a contiguous buffer of NULL terminated291  // strings, where the end of the environment block is indicated by two292  // consecutive NULLs.293  LPWCH environment_block = ::GetEnvironmentStringsW();294  while (*environment_block != L'\0') {295    std::string current_var;296    auto current_var_size = wcslen(environment_block) + 1;297    if (!llvm::convertWideToUTF8(environment_block, current_var)) {298      environment_block += current_var_size;299      continue;300    }301    if (current_var[0] != '=')302      env.insert(current_var);303 304    environment_block += current_var_size;305  }306  return env;307}308 309void Host::SystemLog(Severity severity, llvm::StringRef message) {310  if (message.empty())311    return;312 313  std::string log_msg;314  llvm::raw_string_ostream stream(log_msg);315 316  switch (severity) {317  case lldb::eSeverityWarning:318    stream << "[Warning] ";319    break;320  case lldb::eSeverityError:321    stream << "[Error] ";322    break;323  case lldb::eSeverityInfo:324    stream << "[Info] ";325    break;326  }327 328  stream << message;329  stream.flush();330 331  OutputDebugStringA(log_msg.c_str());332}333