Files
llvm/lldb/source/Plugins/Process/wasm/RegisterContextWasm.cpp
Jonas Devlieghere f62370290a [lldb] Implement RegisterContextWasm (#151056)
This PR implements a register context for Wasm, which uses virtual
registers to resolve Wasm local, globals and stack values. The registers
are used to implement support for `DW_OP_WASM_location` in the DWARF
expression evaluator (#151010). This also adds a more comprehensive
test, showing that we can use this to show local variables.
2025-07-30 19:51:09 -07:00

110 lines
3.8 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "RegisterContextWasm.h"
#include "Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h"
#include "ProcessWasm.h"
#include "ThreadWasm.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "llvm/Support/Error.h"
#include <memory>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private::wasm;
RegisterContextWasm::RegisterContextWasm(
wasm::ThreadWasm &thread, uint32_t concrete_frame_idx,
GDBRemoteDynamicRegisterInfoSP reg_info_sp)
: GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false,
false) {}
RegisterContextWasm::~RegisterContextWasm() = default;
uint32_t RegisterContextWasm::ConvertRegisterKindToRegisterNumber(
lldb::RegisterKind kind, uint32_t num) {
return num;
}
size_t RegisterContextWasm::GetRegisterCount() {
// Wasm has no registers.
return 0;
}
const RegisterInfo *RegisterContextWasm::GetRegisterInfoAtIndex(size_t reg) {
uint32_t tag = GetWasmVirtualRegisterTag(reg);
if (tag == eWasmTagNotAWasmLocation)
return m_reg_info_sp->GetRegisterInfoAtIndex(
GetWasmVirtualRegisterIndex(reg));
auto it = m_register_map.find(reg);
if (it == m_register_map.end()) {
WasmVirtualRegisterKinds kind = static_cast<WasmVirtualRegisterKinds>(tag);
std::tie(it, std::ignore) = m_register_map.insert(
{reg, std::make_unique<WasmVirtualRegisterInfo>(
kind, GetWasmVirtualRegisterIndex(reg))});
}
return it->second.get();
}
size_t RegisterContextWasm::GetRegisterSetCount() { return 0; }
const RegisterSet *RegisterContextWasm::GetRegisterSet(size_t reg_set) {
// Wasm has no registers.
return nullptr;
}
bool RegisterContextWasm::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &value) {
// The only real registers is the PC.
if (reg_info->name)
return GDBRemoteRegisterContext::ReadRegister(reg_info, value);
// Read the virtual registers.
ThreadWasm *thread = static_cast<ThreadWasm *>(&GetThread());
ProcessWasm *process = static_cast<ProcessWasm *>(thread->GetProcess().get());
if (!thread)
return false;
uint32_t frame_index = m_concrete_frame_idx;
WasmVirtualRegisterInfo *wasm_reg_info =
static_cast<WasmVirtualRegisterInfo *>(
const_cast<RegisterInfo *>(reg_info));
llvm::Expected<DataBufferSP> maybe_buffer = process->GetWasmVariable(
wasm_reg_info->kind, frame_index, wasm_reg_info->index);
if (!maybe_buffer) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Process), maybe_buffer.takeError(),
"Failed to read Wasm local: {0}");
return false;
}
DataBufferSP buffer_sp = *maybe_buffer;
DataExtractor reg_data(buffer_sp, process->GetByteOrder(),
process->GetAddressByteSize());
wasm_reg_info->byte_size = buffer_sp->GetByteSize();
wasm_reg_info->encoding = lldb::eEncodingUint;
Status error = value.SetValueFromData(
*reg_info, reg_data, reg_info->byte_offset, /*partial_data_ok=*/false);
return error.Success();
}
void RegisterContextWasm::InvalidateAllRegisters() {}
bool RegisterContextWasm::WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &value) {
// The only real registers is the PC.
if (reg_info->name)
return GDBRemoteRegisterContext::WriteRegister(reg_info, value);
return false;
}