Skip to content

[lldb] Implement WebAssembly debugging #77949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,14 @@ class Process : public std::enable_shared_from_this<Process>,
/// platforms where there is a difference (only Arm Thumb at this time).
lldb::addr_t FixAnyAddress(lldb::addr_t pc);

/// Some targets might use bits in a code address to represent additional
/// information; for example WebAssembly targets have a different memory space
/// per module and have a different address space per memory and code.
virtual lldb::addr_t FixMemoryAddress(lldb::addr_t address,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above we have FixCodeAddres() and FixDataAddress(). Will this function fix any kind of address, or just a code address? If it is just code, then maybe we can just modify the above FixCodeAddress(...) and add the StackFrame to that API which can default to nullptr.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought to add a new function because Process::FixCodeAddress, Process::FixDataAddress, Process::FixAnyAddress by default forward the call to ABI::FixCodeAddress, ABI::FixDataAddress, ABI::FixAnyAddress, which are implemented by plugin-specific ABIs like ABISysV_arm, ABIMacOSX_arm. But here we are not really dealing with a different ABI, it is more a custom representation of Wasm memory addresses used between the debugger and the Wasm engine.

If you prefer, we could reuse Process::FixAnyAddress, making it virtual and overriding it in ProcessWasm.

StackFrame *stack_frame) const {
return address;
}

/// Get the Modification ID of the process.
///
/// \return
Expand Down Expand Up @@ -1933,9 +1941,9 @@ class Process : public std::enable_shared_from_this<Process>,
/// the instruction has completed executing.
bool GetWatchpointReportedAfter();

lldb::ModuleSP ReadModuleFromMemory(const FileSpec &file_spec,
lldb::addr_t header_addr,
size_t size_to_read = 512);
virtual lldb::ModuleSP ReadModuleFromMemory(const FileSpec &file_spec,
lldb::addr_t header_addr,
size_t size_to_read = 512);

/// Attempt to get the attributes for a region of memory in the process.
///
Expand Down
5 changes: 3 additions & 2 deletions lldb/source/Core/Value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,9 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
Process *process = exe_ctx->GetProcessPtr();

if (process) {
const size_t bytes_read =
process->ReadMemory(address, dst, byte_size, error);
const size_t bytes_read = process->ReadMemory(
process->FixMemoryAddress(address, exe_ctx->GetFramePtr()), dst,
byte_size, error);
if (bytes_read != byte_size)
error.SetErrorStringWithFormat(
"read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",
Expand Down
46 changes: 46 additions & 0 deletions lldb/source/Expression/DWARFExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"

#include "Plugins/Process/wasm/wasmRegisterContext.h"
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
#include "Plugins/SymbolFile/DWARF/DWARFWasm.h"

using namespace lldb;
using namespace lldb_private;
Expand Down Expand Up @@ -346,6 +348,16 @@ static offset_t GetOpcodeDataSize(const DataExtractor &data,
return (offset - data_offset) + subexpr_len;
}

case DW_OP_WASM_location: {
DWARFWasmLocation wasm_location =
static_cast<DWARFWasmLocation>(data.GetU8(&offset));
if (wasm_location == DWARFWasmLocation::eGlobalU32)
data.GetU32(&offset);
else
data.GetULEB128(&offset);
return offset - data_offset;
}

default:
if (!dwarf_cu) {
return LLDB_INVALID_OFFSET;
Expand Down Expand Up @@ -2594,6 +2606,40 @@ bool DWARFExpression::Evaluate(
break;
}

case DW_OP_WASM_location: {
uint8_t wasm_op = opcodes.GetU8(&offset);
if (wasm_op > DWARFWasmLocation::eGlobalU32) {
if (error_ptr)
error_ptr->SetErrorString("Invalid Wasm location index");
return false;
}
DWARFWasmLocation wasm_location = static_cast<DWARFWasmLocation>(wasm_op);

/* LLDB doesn't have an address space to represents WebAssembly locals,
* globals and operand stacks.
* We encode these elements into virtual registers:
* | WasmVirtualRegisterKinds: 2 bits | index: 30 bits |
*/
uint32_t index;
if (wasm_location == DWARFWasmLocation::eGlobalU32) {
index = opcodes.GetU32(&offset);
} else {
index = opcodes.GetULEB128(&offset);
}
wasm::WasmVirtualRegisterKinds register_tag =
wasm::WasmVirtualRegisterInfo::VirtualRegisterKindFromDWARFLocation(
wasm_location);
reg_num = (register_tag << wasm::WasmRegisterContext::kTagShift) |
(index & wasm::WasmRegisterContext::kIndexMask);

if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
stack.push_back(tmp);
else
return false;

break;
}

default:
if (dwarf_cu) {
if (dwarf_cu->GetSymbolFileDWARF().ParseVendorDWARFOpcode(
Expand Down
4 changes: 3 additions & 1 deletion lldb/source/Expression/Materializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,9 @@ class EntityResultVariable : public Materializer::Entity {
const size_t pvar_byte_size = ret->GetByteSize().value_or(0);
uint8_t *pvar_data = ret->GetValueBytes();

map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
map.ReadMemory(pvar_data,
process_sp->FixMemoryAddress(address, frame_sp.get()),
pvar_byte_size, read_error);

if (!read_error.Success()) {
err.SetErrorString(
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/Process/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ add_subdirectory(elf-core)
add_subdirectory(mach-core)
add_subdirectory(minidump)
add_subdirectory(FreeBSDKernel)
add_subdirectory(wasm)
Original file line number Diff line number Diff line change
Expand Up @@ -1628,6 +1628,11 @@ void ProcessGDBRemote::ParseExpeditedRegisters(
}
}

std::shared_ptr<ThreadGDBRemote>
ProcessGDBRemote::CreateThread(lldb::tid_t tid) {
return std::make_shared<ThreadGDBRemote>(*this, tid);
}

ThreadSP ProcessGDBRemote::SetThreadStopInfo(
lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map,
uint8_t signo, const std::string &thread_name, const std::string &reason,
Expand All @@ -1652,7 +1657,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(

if (!thread_sp) {
// Create the thread if we need to
thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
thread_sp = CreateThread(tid);
m_thread_list_real.AddThread(thread_sp);
}
}
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ class ProcessGDBRemote : public Process,
MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp,
lldb::pid_t pid, int signo, int exit_status);

virtual std::shared_ptr<ThreadGDBRemote> CreateThread(lldb::tid_t tid);

lldb::StateType SetThreadStopInfo(StringExtractor &stop_packet);

bool
Expand Down
12 changes: 12 additions & 0 deletions lldb/source/Plugins/Process/wasm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
add_lldb_library(lldbPluginProcessWasm PLUGIN
ProcessWasm.cpp
ThreadWasm.cpp
UnwindWasm.cpp
wasmRegisterContext.cpp

LINK_LIBS
lldbCore
${LLDB_PLUGINS}
LINK_COMPONENTS
Support
)
Loading