Skip to content
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

[lldb] Implement WebAssembly debugging #77949

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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 @@ -1926,9 +1934,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
40 changes: 40 additions & 0 deletions lldb/source/Expression/DWARFExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,15 @@ static offset_t GetOpcodeDataSize(const DataExtractor &data,
return (offset - data_offset) + subexpr_len;
}

case DW_OP_WASM_location: {
uint8_t wasm_op = data.GetU8(&offset);
if (wasm_op == 3)
paolosevMSFT marked this conversation as resolved.
Show resolved Hide resolved
data.GetU32(&offset);
else
data.GetULEB128(&offset);
return offset - data_offset;
}

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

case DW_OP_WASM_location: {
uint8_t wasm_op = opcodes.GetU8(&offset);
uint32_t index;

/* LLDB doesn't have an address space to represents WebAssembly locals,
* globals and operand stacks.
* We encode these elements into virtual registers:
* | tag: 2 bits | index: 30 bits |
* where tag is:
* 0: Not a WebAssembly location
* 1: Local
* 2: Global
* 3: Operand stack value
paolosevMSFT marked this conversation as resolved.
Show resolved Hide resolved
*/
if (wasm_op == 3) {
paolosevMSFT marked this conversation as resolved.
Show resolved Hide resolved
index = opcodes.GetU32(&offset);
wasm_op = 2; // Global
paolosevMSFT marked this conversation as resolved.
Show resolved Hide resolved
} else {
index = opcodes.GetULEB128(&offset);
}

reg_num = (((wasm_op + 1) & 0x03) << 30) | (index & 0x3fffffff);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we adding 1 to the wasm_op? Can't we just set it correctly above?

Also it would be nice to have an enum or constant for 0x03 like kWasmOpMask, and for 30 like `kWasmOpShift'


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
Loading