brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · c182d3d Raw
252 lines · cpp
1//===-- PlatformQemuUser.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 "Plugins/Platform/QemuUser/PlatformQemuUser.h"10#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"11#include "lldb/Core/PluginManager.h"12#include "lldb/Host/FileSystem.h"13#include "lldb/Host/ProcessLaunchInfo.h"14#include "lldb/Interpreter/OptionValueProperties.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/LLDBLog.h"18#include "lldb/Utility/Listener.h"19#include "lldb/Utility/Log.h"20 21using namespace lldb;22using namespace lldb_private;23 24LLDB_PLUGIN_DEFINE(PlatformQemuUser)25 26namespace {27#define LLDB_PROPERTIES_platformqemuuser28#include "PlatformQemuUserProperties.inc"29 30enum {31#define LLDB_PROPERTIES_platformqemuuser32#include "PlatformQemuUserPropertiesEnum.inc"33};34 35class PluginProperties : public Properties {36public:37  PluginProperties() {38    m_collection_sp = std::make_shared<OptionValueProperties>(39        PlatformQemuUser::GetPluginNameStatic());40    m_collection_sp->Initialize(g_platformqemuuser_properties);41  }42 43  llvm::StringRef GetArchitecture() {44    return GetPropertyAtIndexAs<llvm::StringRef>(ePropertyArchitecture, "");45  }46 47  FileSpec GetEmulatorPath() {48    return GetPropertyAtIndexAs<FileSpec>(ePropertyEmulatorPath, {});49  }50 51  Args GetEmulatorArgs() {52    Args result;53    m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyEmulatorArgs, result);54    return result;55  }56 57  Environment GetEmulatorEnvVars() {58    Args args;59    m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyEmulatorEnvVars, args);60    return Environment(args);61  }62 63  Environment GetTargetEnvVars() {64    Args args;65    m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyTargetEnvVars, args);66    return Environment(args);67  }68};69 70} // namespace71 72static PluginProperties &GetGlobalProperties() {73  static PluginProperties g_settings;74  return g_settings;75}76 77llvm::StringRef PlatformQemuUser::GetPluginDescriptionStatic() {78  return "Platform for debugging binaries under user mode qemu";79}80 81void PlatformQemuUser::Initialize() {82  PluginManager::RegisterPlugin(83      GetPluginNameStatic(), GetPluginDescriptionStatic(),84      PlatformQemuUser::CreateInstance, PlatformQemuUser::DebuggerInitialize);85}86 87void PlatformQemuUser::Terminate() {88  PluginManager::UnregisterPlugin(PlatformQemuUser::CreateInstance);89}90 91void PlatformQemuUser::DebuggerInitialize(Debugger &debugger) {92  if (!PluginManager::GetSettingForPlatformPlugin(debugger,93                                                  GetPluginNameStatic())) {94    PluginManager::CreateSettingForPlatformPlugin(95        debugger, GetGlobalProperties().GetValueProperties(),96        "Properties for the qemu-user platform plugin.",97        /*is_global_property=*/true);98  }99}100 101PlatformSP PlatformQemuUser::CreateInstance(bool force, const ArchSpec *arch) {102  if (force)103    return PlatformSP(new PlatformQemuUser());104  return nullptr;105}106 107std::vector<ArchSpec>108PlatformQemuUser::GetSupportedArchitectures(const ArchSpec &process_host_arch) {109  llvm::Triple triple = HostInfo::GetArchitecture().GetTriple();110  triple.setEnvironment(llvm::Triple::UnknownEnvironment);111  triple.setArchName(GetGlobalProperties().GetArchitecture());112  if (triple.getArch() != llvm::Triple::UnknownArch)113    return {ArchSpec(triple)};114  return {};115}116 117static auto get_arg_range(const Args &args) {118  return llvm::make_range(args.GetArgumentArrayRef().begin(),119                          args.GetArgumentArrayRef().end());120}121 122// Returns the emulator environment which result in the desired environment123// being presented to the emulated process. We want to be careful about124// preserving the host environment, as it may contain entries (LD_LIBRARY_PATH,125// for example) needed for the operation of the emulator itself.126static Environment ComputeLaunchEnvironment(Environment target,127                                            Environment host) {128  std::vector<std::string> set_env;129  for (const auto &KV : target) {130    // If the host value differs from the target (or is unset), then set it131    // through QEMU_SET_ENV. Identical entries will be forwarded automatically.132    auto host_it = host.find(KV.first());133    if (host_it == host.end() || host_it->second != KV.second)134      set_env.push_back(Environment::compose(KV));135  }136  llvm::sort(set_env);137 138  std::vector<llvm::StringRef> unset_env;139  for (const auto &KV : host) {140    // If the target is missing some host entries, then unset them through141    // QEMU_UNSET_ENV.142    if (target.count(KV.first()) == 0)143      unset_env.push_back(KV.first());144  }145  llvm::sort(unset_env);146 147  // The actual QEMU_(UN)SET_ENV variables should not be forwarded to the148  // target.149  if (!set_env.empty()) {150    host["QEMU_SET_ENV"] = llvm::join(set_env, ",");151    unset_env.push_back("QEMU_SET_ENV");152  }153  if (!unset_env.empty()) {154    unset_env.push_back("QEMU_UNSET_ENV");155    host["QEMU_UNSET_ENV"] = llvm::join(unset_env, ",");156  }157  return host;158}159 160lldb::ProcessSP PlatformQemuUser::DebugProcess(ProcessLaunchInfo &launch_info,161                                               Debugger &debugger,162                                               Target &target, Status &error) {163  Log *log = GetLog(LLDBLog::Platform);164 165  // If platform.plugin.qemu-user.emulator-path is set, use it.166  FileSpec qemu = GetGlobalProperties().GetEmulatorPath();167  // If platform.plugin.qemu-user.emulator-path is not set, build the168  // executable name from platform.plugin.qemu-user.architecture.169  if (!qemu) {170    llvm::StringRef arch = GetGlobalProperties().GetArchitecture();171    // If platform.plugin.qemu-user.architecture is not set, build the172    // executable name from the target Triple's ArchName173    if (arch.empty())174      arch = target.GetArchitecture().GetTriple().getArchName();175    qemu.SetPath(("qemu-" + arch).str());176  }177  FileSystem::Instance().ResolveExecutableLocation(qemu);178 179  llvm::SmallString<0> socket_model, socket_path;180  HostInfo::GetProcessTempDir().GetPath(socket_model);181  llvm::sys::path::append(socket_model, "qemu-%%%%%%%%.socket");182  do {183    llvm::sys::fs::createUniquePath(socket_model, socket_path, false);184  } while (FileSystem::Instance().Exists(socket_path));185 186  Args args({qemu.GetPath(), "-g", socket_path});187  if (!launch_info.GetArg0().empty()) {188    args.AppendArgument("-0");189    args.AppendArgument(launch_info.GetArg0());190  }191  args.AppendArguments(GetGlobalProperties().GetEmulatorArgs());192  args.AppendArgument("--");193  args.AppendArgument(launch_info.GetExecutableFile().GetPath());194  for (size_t i = 1; i < launch_info.GetArguments().size(); ++i)195    args.AppendArgument(launch_info.GetArguments()[i].ref());196 197  LLDB_LOG(log, "{0} -> {1}", get_arg_range(launch_info.GetArguments()),198           get_arg_range(args));199 200  launch_info.SetArguments(args, true);201 202  Environment emulator_env = Host::GetEnvironment();203  if (const std::string &sysroot = GetSDKRootDirectory(); !sysroot.empty())204    emulator_env["QEMU_LD_PREFIX"] = sysroot;205  for (const auto &KV : GetGlobalProperties().GetEmulatorEnvVars())206    emulator_env[KV.first()] = KV.second;207  launch_info.GetEnvironment() = ComputeLaunchEnvironment(208      std::move(launch_info.GetEnvironment()), std::move(emulator_env));209 210  launch_info.SetLaunchInSeparateProcessGroup(true);211  launch_info.GetFlags().Clear(eLaunchFlagDebug);212  launch_info.SetMonitorProcessCallback(ProcessLaunchInfo::NoOpMonitorCallback);213 214  // This is automatically done for host platform in215  // Target::FinalizeFileActions, but we're not a host platform.216  llvm::Error Err = launch_info.SetUpPtyRedirection();217  LLDB_LOG_ERROR(log, std::move(Err), "SetUpPtyRedirection failed: {0}");218 219  error = Host::LaunchProcess(launch_info);220  if (error.Fail())221    return nullptr;222 223  ProcessSP process_sp = target.CreateProcess(224      launch_info.GetListener(),225      process_gdb_remote::ProcessGDBRemote::GetPluginNameStatic(), nullptr,226      true);227  if (!process_sp) {228    error = Status::FromErrorString("Failed to create GDB process");229    return nullptr;230  }231 232  process_sp->HijackProcessEvents(launch_info.GetHijackListener());233 234  error = process_sp->ConnectRemote(("unix-connect://" + socket_path).str());235  if (error.Fail())236    return nullptr;237 238  if (launch_info.GetPTY().GetPrimaryFileDescriptor() !=239      PseudoTerminal::invalid_fd)240    process_sp->SetSTDIOFileDescriptor(241        launch_info.GetPTY().ReleasePrimaryFileDescriptor());242 243  return process_sp;244}245 246Environment PlatformQemuUser::GetEnvironment() {247  Environment env = Host::GetEnvironment();248  for (const auto &KV : GetGlobalProperties().GetTargetEnvVars())249    env[KV.first()] = KV.second;250  return env;251}252