brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.7 KiB · 62bcf44 Raw
168 lines · cpp
1//===----------------------------------------------------------------------===//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 "ProcessWasm.h"10#include "ThreadWasm.h"11#include "lldb/Core/Module.h"12#include "lldb/Core/PluginManager.h"13#include "lldb/Core/Value.h"14#include "lldb/Utility/DataBufferHeap.h"15 16#include "lldb/Target/UnixSignals.h"17 18using namespace lldb;19using namespace lldb_private;20using namespace lldb_private::process_gdb_remote;21using namespace lldb_private::wasm;22 23LLDB_PLUGIN_DEFINE(ProcessWasm)24 25ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp)26    : ProcessGDBRemote(target_sp, listener_sp) {27  assert(target_sp);28  // Wasm doesn't have any Unix-like signals as a platform concept, but pretend29  // like it does to appease LLDB.30  m_unix_signals_sp = UnixSignals::Create(target_sp->GetArchitecture());31}32 33void ProcessWasm::Initialize() {34  static llvm::once_flag g_once_flag;35 36  llvm::call_once(g_once_flag, []() {37    PluginManager::RegisterPlugin(GetPluginNameStatic(),38                                  GetPluginDescriptionStatic(), CreateInstance,39                                  DebuggerInitialize);40  });41}42 43void ProcessWasm::DebuggerInitialize(Debugger &debugger) {44  ProcessGDBRemote::DebuggerInitialize(debugger);45}46 47llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); }48 49llvm::StringRef ProcessWasm::GetPluginNameStatic() { return "wasm"; }50 51llvm::StringRef ProcessWasm::GetPluginDescriptionStatic() {52  return "GDB Remote protocol based WebAssembly debugging plug-in.";53}54 55void ProcessWasm::Terminate() {56  PluginManager::UnregisterPlugin(ProcessWasm::CreateInstance);57}58 59lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp,60                                            ListenerSP listener_sp,61                                            const FileSpec *crash_file_path,62                                            bool can_connect) {63  if (crash_file_path == nullptr)64    return std::make_shared<ProcessWasm>(target_sp, listener_sp);65  return {};66}67 68bool ProcessWasm::CanDebug(lldb::TargetSP target_sp,69                           bool plugin_specified_by_name) {70  if (plugin_specified_by_name)71    return true;72 73  if (Module *exe_module = target_sp->GetExecutableModulePointer()) {74    if (ObjectFile *exe_objfile = exe_module->GetObjectFile())75      return exe_objfile->GetArchitecture().GetMachine() ==76             llvm::Triple::wasm32;77  }78 79  // However, if there is no wasm module, we return false, otherwise,80  // we might use ProcessWasm to attach gdb remote.81  return false;82}83 84std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) {85  return std::make_shared<ThreadWasm>(*this, tid);86}87 88size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,89                               Status &error) {90  wasm_addr_t wasm_addr(vm_addr);91 92  switch (wasm_addr.GetType()) {93  case WasmAddressType::Memory:94  case WasmAddressType::Object:95    return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);96  case WasmAddressType::Invalid:97    error.FromErrorStringWithFormat(98        "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);99    return 0;100  }101  llvm_unreachable("Fully covered switch above");102}103 104llvm::Expected<std::vector<lldb::addr_t>>105ProcessWasm::GetWasmCallStack(lldb::tid_t tid) {106  StreamString packet;107  packet.Printf("qWasmCallStack:");108  packet.Printf("%" PRIx64, tid);109 110  StringExtractorGDBRemote response;111  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=112      GDBRemoteCommunication::PacketResult::Success)113    return llvm::createStringError("failed to send qWasmCallStack");114 115  if (!response.IsNormalResponse())116    return llvm::createStringError("failed to get response for qWasmCallStack");117 118  WritableDataBufferSP data_buffer_sp =119      std::make_shared<DataBufferHeap>(response.GetStringRef().size() / 2, 0);120  const size_t bytes = response.GetHexBytes(data_buffer_sp->GetData(), '\xcc');121  if (bytes == 0 || bytes % sizeof(uint64_t) != 0)122    return llvm::createStringError("invalid response for qWasmCallStack");123 124  // To match the Wasm specification, the addresses are encoded in little endian125  // byte order.126  DataExtractor data(data_buffer_sp, lldb::eByteOrderLittle,127                     GetAddressByteSize());128  lldb::offset_t offset = 0;129  std::vector<lldb::addr_t> call_stack_pcs;130  while (offset < bytes)131    call_stack_pcs.push_back(data.GetU64(&offset));132 133  return call_stack_pcs;134}135 136llvm::Expected<lldb::DataBufferSP>137ProcessWasm::GetWasmVariable(WasmVirtualRegisterKinds kind, int frame_index,138                             int index) {139  StreamString packet;140  switch (kind) {141  case eWasmTagLocal:142    packet.Printf("qWasmLocal:");143    break;144  case eWasmTagGlobal:145    packet.Printf("qWasmGlobal:");146    break;147  case eWasmTagOperandStack:148    packet.PutCString("qWasmStackValue:");149    break;150  case eWasmTagNotAWasmLocation:151    return llvm::createStringError("not a Wasm location");152  }153  packet.Printf("%d;%d", frame_index, index);154 155  StringExtractorGDBRemote response;156  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=157      GDBRemoteCommunication::PacketResult::Success)158    return llvm::createStringError("failed to send Wasm variable");159 160  if (!response.IsNormalResponse())161    return llvm::createStringError("failed to get response for Wasm variable");162 163  WritableDataBufferSP buffer_sp(164      new DataBufferHeap(response.GetStringRef().size() / 2, 0));165  response.GetHexBytes(buffer_sp->GetData(), '\xcc');166  return buffer_sp;167}168