blob: ba3768a3d5ebcf05431b9fd6cf828071a8f9f9fa [file]
//===----------------------------------------------------------------------===//
//
// 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(ThreadGDBRemote &thread,
uint32_t concrete_frame_idx,
DynamicRegisterInfoSP reg_info_sp)
: GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false,
false) {}
RegisterContextWasm::~RegisterContextWasm() = default;
uint32_t RegisterContextWasm::GetModuleID() {
return GetWasmModuleID(GetPC(LLDB_INVALID_ADDRESS));
}
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;
}
/// A local and an operand stack value belong to the frame, while a global
/// belongs to the module instance the frame is executing, which is named
/// directly wherever the stub accepts one.
static llvm::Expected<DataBufferSP>
ReadWasmValue(ProcessWasm &process, const WasmVirtualRegisterInfo &reg_info,
uint32_t frame_index, uint32_t module_id) {
if (reg_info.kind != eWasmTagGlobal)
return process.GetWasmVariable(reg_info.kind, frame_index, reg_info.index);
if (process.CanNameInstance(module_id))
return process.GetWasmGlobalForModule(module_id, reg_info.index);
return process.GetWasmGlobalForFrame(frame_index, reg_info.index);
}
bool RegisterContextWasm::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &value) {
ThreadWasm &wasm_thread = static_cast<ThreadWasm &>(GetThread());
// The only real register is the PC.
if (reg_info->name) {
// A caller frame's PC is the unwound return address, which the base
// register context cannot provide because it only sees the innermost
// frame's live PC. Use the PC the unwinder recorded for this frame.
if (m_concrete_frame_idx > 0) {
lldb::addr_t pc = wasm_thread.GetConcreteFramePC(m_concrete_frame_idx);
if (pc != LLDB_INVALID_ADDRESS) {
value.SetUInt(pc, reg_info->byte_size);
return true;
}
}
return GDBRemoteRegisterContext::ReadRegister(reg_info, value);
}
// Read the virtual registers.
ProcessWasm *process =
static_cast<ProcessWasm *>(wasm_thread.GetProcess().get());
if (!process)
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 =
ReadWasmValue(*process, *wasm_reg_info, frame_index, GetModuleID());
if (!maybe_buffer) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Process), maybe_buffer.takeError(),
"Failed to read Wasm value: {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;
}