-
Notifications
You must be signed in to change notification settings - Fork 11.9k
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 #76683
Conversation
You can test this locally with the following command:git-clang-format --diff 25cd249355b0f3192ca5b0c69514ad68a1cb8897 61b46091e9f04ad628fe9605464080be8c9cf29a -- lldb/source/Plugins/Process/wasm/ProcessWasm.cpp lldb/source/Plugins/Process/wasm/ProcessWasm.h lldb/source/Plugins/Process/wasm/ThreadWasm.cpp lldb/source/Plugins/Process/wasm/ThreadWasm.h lldb/source/Plugins/Process/wasm/UnwindWasm.cpp lldb/source/Plugins/Process/wasm/UnwindWasm.h lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp lldb/source/Plugins/Process/wasm/wasmRegisterContext.h lldb/include/lldb/Target/Process.h lldb/source/Core/Value.cpp lldb/source/Expression/DWARFExpression.cpp lldb/source/Interpreter/CommandInterpreter.cpp lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h View the diff from clang-format here.diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 1693e390c2..8e8ea610b8 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -350,8 +350,7 @@ static offset_t GetOpcodeDataSize(const DataExtractor &data,
uint8_t wasm_op = data.GetU8(&offset);
if (wasm_op == 3) {
data.GetU32(&offset);
- }
- else {
+ } else {
data.GetULEB128(&offset);
}
return offset - data_offset;
@@ -2612,13 +2611,13 @@ bool DWARFExpression::Evaluate(
/* LLDB doesn't have an address space to represents WebAssembly Locals,
* GLobals and operand stacks.
- * We encode these elements into virtual registers:
+ * 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
+ * 3: Operand stack value
*/
if (wasm_op == 3) {
index = opcodes.GetU32(&offset);
diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
index 50d0bd37bb..63cf64f20b 100644
--- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
@@ -29,7 +29,8 @@
using namespace lldb;
using namespace lldb_private;
-using GetThreadDescriptionFunctionPtr = HRESULT (*)(HANDLE hThread, PWSTR *ppszThreadDescription);
+using GetThreadDescriptionFunctionPtr =
+ HRESULT (*)(HANDLE hThread, PWSTR *ppszThreadDescription);
TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
const HostThread &thread)
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
index d8ab6d6458..df6236a712 100644
--- a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
@@ -29,7 +29,8 @@ LLDB_PLUGIN_DEFINE(ProcessWasm)
ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp)
: ProcessGDBRemote(target_sp, listener_sp) {
/* always use linux signals for wasm process */
- m_unix_signals_sp = UnixSignals::Create(ArchSpec{"wasm32-unknown-unknown-wasm"});
+ m_unix_signals_sp =
+ UnixSignals::Create(ArchSpec{"wasm32-unknown-unknown-wasm"});
}
void ProcessWasm::Initialize() {
@@ -73,7 +74,7 @@ lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp,
}
bool ProcessWasm::CanDebug(lldb::TargetSP target_sp,
- bool plugin_specified_by_name) {
+ bool plugin_specified_by_name) {
if (plugin_specified_by_name)
return true;
@@ -143,7 +144,7 @@ size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
}
size_t ProcessWasm::WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr,
- void *buf, size_t buffer_size) {
+ void *buf, size_t buffer_size) {
char packet[64];
int packet_len =
::snprintf(packet, sizeof(packet), "qWasmMem:%d;%" PRIx64 ";%" PRIx64,
@@ -152,7 +153,8 @@ size_t ProcessWasm::WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr,
assert(packet_len + 1 < (int)sizeof(packet));
UNUSED_IF_ASSERT_DISABLED(packet_len);
StringExtractorGDBRemote response;
- if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response,
+ GetInterruptTimeout()) ==
GDBRemoteCommunication::PacketResult::Success) {
if (response.IsNormalResponse()) {
return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
@@ -164,7 +166,7 @@ size_t ProcessWasm::WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr,
}
size_t ProcessWasm::WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr,
- void *buf, size_t buffer_size) {
+ void *buf, size_t buffer_size) {
char packet[64];
int packet_len =
::snprintf(packet, sizeof(packet), "qWasmData:%d;%" PRIx64 ";%" PRIx64,
@@ -173,7 +175,8 @@ size_t ProcessWasm::WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr,
assert(packet_len + 1 < (int)sizeof(packet));
UNUSED_IF_ASSERT_DISABLED(packet_len);
StringExtractorGDBRemote response;
- if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response,
+ GetInterruptTimeout()) ==
GDBRemoteCommunication::PacketResult::Success) {
if (response.IsNormalResponse()) {
return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
index c4579390da..0d57934b9e 100644
--- a/lldb/source/Plugins/Process/wasm/ProcessWasm.h
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
@@ -26,11 +26,7 @@ namespace wasm {
//
// Struct wasm_addr_t provides this encoding using bitfields
//
-enum WasmAddressType {
- Memory = 0x00,
- Object = 0x01,
- Invalid = 0x03
-};
+enum WasmAddressType { Memory = 0x00, Object = 0x01, Invalid = 0x03 };
struct wasm_addr_t {
uint64_t offset : 32;
uint64_t module_id : 30;
@@ -96,11 +92,11 @@ public:
/// Read from the WebAssembly Memory space.
size_t WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr, void *buf,
- size_t buffer_size);
+ size_t buffer_size);
/// Read from the WebAssembly Data space.
size_t WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr, void *buf,
- size_t buffer_size);
+ size_t buffer_size);
/// Retrieve the current call stack from the WebAssembly remote process.
bool GetWasmCallStack(lldb::tid_t tid,
diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
index d9715dd23b..adcfba7400 100644
--- a/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
+++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
@@ -49,7 +49,8 @@ ThreadWasm::CreateRegisterContextForFrame(StackFrame *frame) {
concrete_frame_idx = frame->GetConcreteFrameIndex();
if (concrete_frame_idx == 0) {
- reg_ctx_sp = std::make_shared<WasmRegisterContext>(*this, concrete_frame_idx, wasm_process->GetRegisterInfo());
+ reg_ctx_sp = std::make_shared<WasmRegisterContext>(
+ *this, concrete_frame_idx, wasm_process->GetRegisterInfo());
} else {
reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
}
diff --git a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h
index 62bdf66c05..f60cc8e6a0 100644
--- a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h
+++ b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h
@@ -22,7 +22,7 @@ class WasmRegisterContext;
typedef std::shared_ptr<WasmRegisterContext> WasmRegisterContextSP;
enum WasmVirtualRegisterKinds {
- eLocal = 0, ///< wasm local
+ eLocal = 0, ///< wasm local
eGlobal, ///< wasm global
eOperandStack, ///< wasm operand stack
kNumWasmVirtualRegisterKinds
@@ -46,7 +46,7 @@ public:
~WasmRegisterContext() override;
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
- uint32_t num) override;
+ uint32_t num) override;
void InvalidateAllRegisters() override;
|
Store the last token parsed in the parser state so that the range parsed can utilize its end rather than the start of the token after parsed. This results in a tighter range (especially true in the case of comments, see ```mlir |%c4 = arith.constant 4 : index // Foo | ``` vs ```mlir |%c4 = arith.constant 4 : index| ``` ). Discovered while working on a little textual post processing tool.
Part of https://reviews.llvm.org/D158218 GCC_INSTALL_PREFIX is a rarely-used legacy option inherited from pre-CMake build system and has configuration file replacement nowadays. Many `clang/test/Driver` tests specify `--gcc-toolchain=` to prevent failures when `GCC_INSTALL_PREFIX` is specified: some contributors add them to fix tests and some just do cargo culting. This is not healthy for contributors adding cross compilation support for this rarely used option. `DEFAULT_SYSROOT` should in spirit be deprecated as well, but a relative path doesn't have good replacement, so don't deprecate it for now. Link: https://discourse.llvm.org/t/add-gcc-install-dir-deprecate-gcc-toolchain-and-remove-gcc-install-prefix/65091 Link: https://discourse.llvm.org/t/correct-cmake-parameters-for-building-clang-and-lld-for-riscv/72833 --- With `GCC_INSTALL_PREFIX=/usr`, `clang a.c` behaves like `clang --gcc-toolchain=/usr a.c`. Here is a simplified version of GCC installation detection code. ``` if (OPT_gcc_install_dir_EQ) return OPT_gcc_install_dir_EQ; if (OPT_gcc_triple) candidate_gcc_triples = {OPT_gcc_triple}; else candidate_gcc_triples = collectCandidateTriples(); if (OPT_gcc_toolchain) prefixes = {OPT_gcc_toolchain}; else prefixes = {OPT_sysroot/usr, OPT_sysroot}; for (prefix : prefixes) if "$prefix/lib/gcc" exists // also tries $prefix/lib/gcc-cross for (triple : candidate_gcc_triples) if "$prefix/lib/gcc/$triple" exists return "$prefix/lib/gcc/$triple/$version"; // pick the largest version ``` `--gcc-toolchain=` specifies a directory where `lib/gcc{,-cross}/$triple/$version` can be found. If you actually want to use a specific version of GCC, specify something like `--gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/11` in a configuration file. You can also specify `--gcc-triple=`. On Debian and its derivatives where the target triple omits the vendor part, the following ways are roughly equivalent, except that `--gcc-install-dir=` specifies a version as well: ``` clang --gcc-toolchain=/usr a.c clang --gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/11 a.c clang --gcc-triple=x86_64-linux-gnu a.c ```
…llvm#77532) To enable the condition variable, you have to define both UseConditionVariable and the ConditionVariableT. Otherwise, it'll be disabled. However, you may want to disable the condition variable by setting UseConditionVariable=false, for example, while measuring the performance and you want to turn it off temporarily. Instead of requiring the removal of the variable, examining its value makes more sense.
…instructions in computeMinimumValueSizes. (llvm#72679) After changes, that does not require support from InstCombine, we can drop some extra requirements for values-to-be-demoted. No need to check for external uses for roots/other instructions, just check that the no non-vectorized insertelement instruction, which may require widening.
StackSafetyAnalysis determines whether stack-allocated variables are guaranteed to be safe from memory access bugs and enables the removal of certain unneeded instrumentations. (hwasan enables StackSafetyAnalysis in https://reviews.llvm.org/D108381) Test updates: * asan-stack-safety.ll: test the -asan-use-stack-safety=1 default * lifetime-uar-uas.ll: switch to an indexed store to prevent StackSafetyAnalysis from optimizing out instrumentation for %c * alloca_vla_interact.cpp: add a load to prevent StackSafetyAnalysis from optimizing out `__asan_alloca_poison` for the VLA `array` * scariness_score_test.cpp: add -asan-use-stack-safety=0 to make a load of a `__asan_poison_memory_region`-poisoned local variable fail as intended. * other .ll tests: add -asan-use-stack-safety=0 Reviewers: kstoimenov, eugenis, vitalybuka Reviewed By: kstoimenov Pull Request: llvm#77210
We need to handle this at the CastExpr level.
…nimodular cones (llvm#77235) We implement a function that computes the generating function corresponding to a unimodular cone. The generating function for a polytope is obtained by summing these generating functions over all tangent cones.
This adds new isel patterns for Zacas that take priority over the pseudoinstructions we use for the A extension. Support for 2x XLen types will come in a separate patch since they need to be done differently.
This adds a new document that covers the HLSL approach to function calls and parameter semantics. At time of writing this document is a proposal for the implementation.
…acas. (llvm#77669) With Zacas we will use amocas.w which doesn't require the input to be sign extended.
…#77041) After llvm#75679, it is no longer necessary to add the `All` pseudo subcommand to the list of registered subcommands. The change causes the list to contain only real subcommands, i.e. an unnamed top-level subcommand and named ones. This simplifies the code a bit by removing some checks for this special case.
This was missed when mass-adding support for other LTO options in 0b51e64. Group the existing thinlto_cache_dir with these other options in a new group, next to the other LTO options. This skips adding the options --thinlto-emit-index-files and --thinlto-single-module=, which don't seem to have corresponding options on the lld-link level currently. This should fix mstorsjo/llvm-mingw#386.
…peline (llvm#77688) Rationale: Since this mini-pipeline may be used in alternative pipelines (viz. different from the default "sparsifier" pipeline) where unknown ops are handled by alternative bufferization methods that are downstream of this mini-pipeline, we allow unknown ops by default (failure to bufferize is eventually apparent by failing to convert to LLVM IR). This is part of enabling e2e testing for TORCH-MLIR tests using a sparsifier backend
Previously, we've been mentioning tests that were placed in their own files in corresponding `drNNxx.cpp` file. This patch makes sure we do this consistently, and improves upon existing practice by specifying the name of the file test is placed in.
… cmake configuration works These tests were slightly broken, in one case a failing test that now works. In the other case some accidentally left over code during a name change that broke compilation due to missing symbols.
Due to the inclusion of a header, a global type is was being shadowed, which upset GCC.
This is the follopw implementation to ARM-software/abi-aa#223 that supports this relocation in llvm and lld.
This is the followup implementation to riscv-non-isa/riscv-elf-psabi-doc#402 that supports this relocation in llvm and lld.
While landing llvm#76652, I realized I messed up a rebase/merge at some point and some of the changes I intended to land with llvm#76652 ended up in a different PR (llvm#76653) instead. This patch fixes the validation counters to how they were intended to land in llvm#76652.
The 'counted_by' attribute is used on flexible array members. The argument for the attribute is the name of the field member holding the count of elements in the flexible array. This information is used to improve the results of the array bound sanitizer and the '__builtin_dynamic_object_size' builtin. The 'count' field member must be within the same non-anonymous, enclosing struct as the flexible array member. For example: ``` struct bar; struct foo { int count; struct inner { struct { int count; /* The 'count' referenced by 'counted_by' */ }; struct { /* ... */ struct bar *array[] __attribute__((counted_by(count))); }; } baz; }; ``` This example specifies that the flexible array member 'array' has the number of elements allocated for it in 'count': ``` struct bar; struct foo { size_t count; /* ... */ struct bar *array[] __attribute__((counted_by(count))); }; ``` This establishes a relationship between 'array' and 'count'; specifically that 'p->array' must have *at least* 'p->count' number of elements available. It's the user's responsibility to ensure that this relationship is maintained throughout changes to the structure. In the following, the allocated array erroneously has fewer elements than what's specified by 'p->count'. This would result in an out-of-bounds access not not being detected: ``` struct foo *p; void foo_alloc(size_t count) { p = malloc(MAX(sizeof(struct foo), offsetof(struct foo, array[0]) + count * sizeof(struct bar *))); p->count = count + 42; } ``` The next example updates 'p->count', breaking the relationship requirement that 'p->array' must have at least 'p->count' number of elements available: ``` void use_foo(int index, int val) { p->count += 42; p->array[index] = val; /* The sanitizer can't properly check this access */ } ``` In this example, an update to 'p->count' maintains the relationship requirement: ``` void use_foo(int index, int val) { if (p->count == 0) return; --p->count; p->array[index] = val; } ```
To be consistent with f65265a.
Describe a limitation of the 'counted_by' attribute when used in unions. Also fix a errant typo.
Add a rewriter for DIExpressions & use it to run legalization patterns before exporting to llvm (because LLVM dialect allows DI Expressions that may not be valid in LLVM IR). The rewriter driver works similarly to the existing mlir rewriter drivers, except it operates on lists of DIExpressionElemAttr (i.e. DIExpressionAttr). Each rewrite pattern transforms a range of DIExpressionElemAttr into a new list of DIExpressionElemAttr. In addition, this PR sets up a place to add legalization patterns that are broadly applicable internally to the LLVM dialect, and they will always be applied prior to export. This PR adds one pattern for merging fragment operators. --------- Co-authored-by: Tobias Gysi <[email protected]>
…ofiles, with a focus on IRPGO. (llvm#76105)
…or RISCV and AMDGPU (llvm#77631) Both RISC-V and AMDGPU(GCN) deploy two VirtRegRewriter in their codegen pipeline. This test prematurely stops at the first one, which doesn't cleanup the virtual register map and cause an assertion failure. Ideally we can solve this by teaching `-stop-after` how to stop at the last instance of a Pass, but we're just marking XFAIL for these two targets for now.
Add Float16 to Vulkan's available capabilities, and guard Float16Buffer (Kernel-only capability) against being added outside OpenCL environments. Add tests to verify half and half vector types, and validate with spirv-val. Fixes llvm#66398
This reverts commit 18734f6. This caused a test suite failure on our bots: https://lab.llvm.org/buildbot/#/builders/184/builds/9407 ``` $ ~/stage1.install/bin/flang-new flush_1.f90 /usr/bin/ld: /home/david.spickett/stage1.install/lib/libFortranRuntime.a(extensions.cpp.o): in function `getlog_': extensions.cpp:(.text.getlog_+0x1c): undefined reference to `operator new(unsigned long)' /usr/bin/ld: extensions.cpp:(.text.getlog_+0x7c): undefined reference to `operator delete(void*)' /usr/bin/ld: extensions.cpp:(.text.getlog_+0xc4): undefined reference to `operator delete(void*)' /usr/bin/ld: extensions.cpp:(.text.getlog_+0xe8): undefined reference to `operator delete(void*)' flang-new: error: linker command failed with exit code 1 (use -v to see invocation) ```
This patch sorts the tests which check if SLEEF and ArmPL mappings are used, in the order of the math functions base names.
the second vector. Need to transform all elements in the long mask, if we decided to produce shorter version, some elements may still have incorrect inifices after transformation for the first vector in the permutation.
… not cast compatiable (llvm#71310) The simplify of bufferization.clone generates a memref.cast op, but the checks in simplify do not verify whether the operand types and return types of clone op is compatiable, leading to errors. This patch addresses this issue.
Fix a crash of `replace-with-veclib` pass, when the arguments of the TLI mapping do not match the original call. Now, it simply ignores such cases. Test require assertions as it accesses programmatically the debug log.
@llvm/pr-subscribers-lldb Author: Paolo Severini (paolosevMSFT) ChangesAdd support for source-level debugging of WebAssembly code that runs in a WebAssembly engine. The idea is to use the GDB-remote protocol to connect to a Wasm engine that implements a GDB-remote stub that offers the ability to access the engine runtime internal state. This protocol is already supported by the "WebAssembly Micro Runtime" and the WAMR team greatly contributed to this work. A WebAssembly debugging session can be started using the new command: The implementation is almost completely contained in Plugin classes and the only Wasm-specific changes to Core classes is in Patch is 40.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/76683.diff 17 Files Affected:
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 24c599e044c78f..587ae085b479b7 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1548,6 +1548,46 @@ class Process : public std::enable_shared_from_this<Process>,
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
Status &error);
+ /// Read of memory from a process.
+ ///
+ /// This function will read memory from the current process's address space
+ /// and remove any traps that may have been inserted into the memory.
+ ///
+ /// This overloads accepts an ExecutionContext as additional argument. By
+ /// default, it calls the previous overload without the ExecutionContext
+ /// argument, but it can be overridden by Process subclasses.
+ ///
+ /// \param[in] vm_addr
+ /// A virtual load address that indicates where to start reading
+ /// memory from.
+ ///
+ /// \param[out] buf
+ /// A byte buffer that is at least \a size bytes long that
+ /// will receive the memory bytes.
+ ///
+ /// \param[in] size
+ /// The number of bytes to read.
+ ///
+ /// \param[in] exe_ctx
+ /// The current execution context, if available.
+ ///
+ /// \param[out] error
+ /// An error that indicates the success or failure of this
+ /// operation. If error indicates success (error.Success()),
+ /// then the value returned can be trusted, otherwise zero
+ /// will be returned.
+ ///
+ /// \return
+ /// The number of bytes that were actually read into \a buf. If
+ /// the returned number is greater than zero, yet less than \a
+ /// size, then this function will get called again with \a
+ /// vm_addr, \a buf, and \a size updated appropriately. Zero is
+ /// returned in the case of an error.
+ virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ ExecutionContext *exe_ctx, Status &error) {
+ return ReadMemory(vm_addr, buf, size, error);
+ }
+
/// Read of memory from a process.
///
/// This function has the same semantics of ReadMemory except that it
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index 995cc934c82044..47a5fdee773886 100644
--- a/lldb/source/Core/Value.cpp
+++ b/lldb/source/Core/Value.cpp
@@ -552,7 +552,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
if (process) {
const size_t bytes_read =
- process->ReadMemory(address, dst, byte_size, error);
+ process->ReadMemory(address, dst, byte_size, exe_ctx, error);
if (bytes_read != byte_size)
error.SetErrorStringWithFormat(
"read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index fe4928d4f43a43..1693e390c2e920 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -346,6 +346,17 @@ 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) {
+ data.GetU32(&offset);
+ }
+ else {
+ data.GetULEB128(&offset);
+ }
+ return offset - data_offset;
+ }
+
default:
if (!dwarf_cu) {
return LLDB_INVALID_OFFSET;
@@ -2595,6 +2606,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
+ */
+ if (wasm_op == 3) {
+ index = opcodes.GetU32(&offset);
+ wasm_op = 1;
+ } else {
+ index = opcodes.GetULEB128(&offset);
+ }
+
+ reg_num = (((wasm_op + 1) & 0x03) << 30) | (index & 0x3fffffff);
+
+ 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(
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 00651df48b6224..bcacc7aabb66ca 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -794,6 +794,24 @@ void CommandInterpreter::LoadCommandDictionary() {
}
}
+ std::unique_ptr<CommandObjectRegexCommand> connect_wasm_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "wasm",
+ "Connect to a WebAssembly process via remote GDB server. "
+ "If no host is specifed, localhost is assumed.",
+ "wasm [<hostname>:]<portnum>", 0, false));
+ if (connect_wasm_cmd_up) {
+ if (connect_wasm_cmd_up->AddRegexCommand(
+ "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
+ "process connect --plugin wasm connect://%1:%2") &&
+ connect_wasm_cmd_up->AddRegexCommand(
+ "^([[:digit:]]+)$",
+ "process connect --plugin wasm connect://localhost:%1")) {
+ CommandObjectSP command_sp(connect_wasm_cmd_up.release());
+ m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
+ }
+ }
+
std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
new CommandObjectRegexCommand(
*this, "kdp-remote",
diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt
index a51d0f7afd1759..be109a303e8669 100644
--- a/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/CMakeLists.txt
@@ -19,3 +19,4 @@ add_subdirectory(elf-core)
add_subdirectory(mach-core)
add_subdirectory(minidump)
add_subdirectory(FreeBSDKernel)
+add_subdirectory(wasm)
diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
index ad67e764fe10f2..50d0bd37bb0a49 100644
--- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
@@ -29,8 +29,7 @@
using namespace lldb;
using namespace lldb_private;
-using GetThreadDescriptionFunctionPtr = HRESULT
-WINAPI (*)(HANDLE hThread, PWSTR *ppszThreadDescription);
+using GetThreadDescriptionFunctionPtr = HRESULT (*)(HANDLE hThread, PWSTR *ppszThreadDescription);
TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
const HostThread &thread)
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 316be471df9295..674bbc9ff4fd0b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -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,
@@ -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);
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index c1ea1cc7905587..0463e39b7a63a4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -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
diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
new file mode 100644
index 00000000000000..c47eec7464ed8a
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
@@ -0,0 +1,15 @@
+# This file comes from https://reviews.llvm.org/D78978.
+# Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+add_lldb_library(lldbPluginProcessWasm PLUGIN
+ ProcessWasm.cpp
+ ThreadWasm.cpp
+ UnwindWasm.cpp
+ wasmRegisterContext.cpp
+
+ LINK_LIBS
+ lldbCore
+ ${LLDB_PLUGINS}
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
new file mode 100644
index 00000000000000..d8ab6d645884c3
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
@@ -0,0 +1,295 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- ProcessWasm.cpp ---------------------------------------------------===//
+//
+// 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 "ProcessWasm.h"
+#include "ThreadWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Utility/DataBufferHeap.h"
+
+#include "lldb/Target/UnixSignals.h"
+#include "llvm/ADT/ArrayRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private::wasm;
+
+LLDB_PLUGIN_DEFINE(ProcessWasm)
+
+// ProcessGDBRemote constructor
+ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp)
+ : ProcessGDBRemote(target_sp, listener_sp) {
+ /* always use linux signals for wasm process */
+ m_unix_signals_sp = UnixSignals::Create(ArchSpec{"wasm32-unknown-unknown-wasm"});
+}
+
+void ProcessWasm::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+ });
+}
+
+void ProcessWasm::DebuggerInitialize(Debugger &debugger) {
+ ProcessGDBRemote::DebuggerInitialize(debugger);
+}
+
+// PluginInterface
+llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); }
+
+ConstString ProcessWasm::GetPluginNameStatic() {
+ static ConstString g_name("wasm");
+ return g_name;
+}
+
+const char *ProcessWasm::GetPluginDescriptionStatic() {
+ return "GDB Remote protocol based WebAssembly debugging plug-in.";
+}
+
+void ProcessWasm::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessWasm::CreateInstance);
+}
+
+lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp,
+ ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect) {
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == nullptr)
+ process_sp = std::make_shared<ProcessWasm>(target_sp, listener_sp);
+ return process_sp;
+}
+
+bool ProcessWasm::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ if (plugin_specified_by_name)
+ return true;
+
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module) {
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ return exe_objfile->GetArchitecture().GetMachine() == llvm::Triple::wasm32;
+ }
+ // However, if there is no wasm module, we return false, otherwise,
+ // we might use ProcessWasm to attach gdb remote.
+ return false;
+}
+
+std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) {
+ return std::make_shared<ThreadWasm>(*this, tid);
+}
+
+size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Status &error) {
+ wasm_addr_t wasm_addr(vm_addr);
+
+ switch (wasm_addr.GetType()) {
+ case WasmAddressType::Memory:
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Object:
+ // TODO ?
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Invalid:
+ default:
+ error.SetErrorStringWithFormat(
+ "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);
+ return 0;
+ }
+}
+
+size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ ExecutionContext *exe_ctx, Status &error) {
+ wasm_addr_t wasm_addr(vm_addr);
+
+ switch (wasm_addr.GetType()) {
+ case WasmAddressType::Memory: {
+ // If we don't have a valid module_id, this is actually a read from the
+ // Wasm memory space. We can calculate the module_id from the execution
+ // context.
+ if (wasm_addr.module_id == 0 && exe_ctx != nullptr) {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ assert(frame->CalculateTarget()->GetArchitecture().GetMachine() ==
+ llvm::Triple::wasm32);
+ wasm_addr.module_id = wasm_addr_t(frame->GetStackID().GetPC()).module_id;
+ wasm_addr.type = WasmAddressType::Memory;
+ }
+ if (WasmReadMemory(wasm_addr.module_id, wasm_addr.offset, buf, size))
+ return size;
+ error.SetErrorStringWithFormat("Wasm memory read failed for 0x%" PRIx64,
+ vm_addr);
+ return 0;
+ }
+ case WasmAddressType::Object:
+ // TODO ?
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Invalid:
+ default:
+ error.SetErrorStringWithFormat(
+ "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);
+ return 0;
+ }
+}
+
+size_t ProcessWasm::WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr,
+ void *buf, size_t buffer_size) {
+ char packet[64];
+ int packet_len =
+ ::snprintf(packet, sizeof(packet), "qWasmMem:%d;%" PRIx64 ";%" PRIx64,
+ wasm_module_id, static_cast<uint64_t>(addr),
+ static_cast<uint64_t>(buffer_size));
+ assert(packet_len + 1 < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
+ static_cast<uint8_t *>(buf), buffer_size),
+ '\xdd');
+ }
+ }
+ return 0;
+}
+
+size_t ProcessWasm::WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr,
+ void *buf, size_t buffer_size) {
+ char packet[64];
+ int packet_len =
+ ::snprintf(packet, sizeof(packet), "qWasmData:%d;%" PRIx64 ";%" PRIx64,
+ wasm_module_id, static_cast<uint64_t>(addr),
+ static_cast<uint64_t>(buffer_size));
+ assert(packet_len + 1 < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
+ static_cast<uint8_t *>(buf), buffer_size),
+ '\xdd');
+ }
+ }
+ return 0;
+}
+
+bool ProcessWasm::GetWasmLocal(int frame_index, int index, void *buf,
+ size_t buffer_size, size_t &size) {
+ StreamString packet;
+ packet.Printf("qWasmLocal:");
+ packet.Printf("%d;%d", frame_index, index);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ size = buffer_sp->GetByteSize();
+ if (size <= buffer_size) {
+ memcpy(buf, buffer_sp->GetBytes(), size);
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessWasm::GetWasmGlobal(int frame_index, int index, void *buf,
+ size_t buffer_size, size_t &size) {
+ StreamString packet;
+ packet.PutCString("qWasmGlobal:");
+ packet.Printf("%d;%d", frame_index, index);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ size = buffer_sp->GetByteSize();
+ if (size <= buffer_size) {
+ memcpy(buf, buffer_sp->GetBytes(), size);
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessWasm::GetWasmStackValue(int frame_index, int index, void *buf,
+ size_t buffer_size, size_t &size) {
+ StreamString packet;
+ packet.PutCString("qWasmStackValue:");
+ packet.Printf("%d;%d", frame_index, index);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ size = buffer_sp->GetByteSize();
+ if (size <= buffer_size) {
+ memcpy(buf, buffer_sp->GetBytes(), size);
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessWasm::GetWasmCallStack(lldb::tid_t tid,
+ std::vector<lldb::addr_t> &call_stack_pcs) {
+ call_stack_pcs.clear();
+ StreamString packet;
+ packet.Printf("qWasmCallStack:");
+ packet.Printf("%llx", tid);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ addr_t buf[1024 / sizeof(addr_t)];
+ size_t bytes = response.GetHexBytes(
+ llvm::MutableArrayRef<uint8_t>((uint8_t *)buf, sizeof(buf)), '\xdd');
+ if (bytes == 0) {
+ return false;
+ }
+
+ for (size_t i = 0; i < bytes / sizeof(addr_t); i++) {
+ call_stack_pcs.push_back(buf[i]);
+ }
+ return true;
+}
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
new file mode 100644
index 00000000000000..c4579390daf082
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
@@ -0,0 +1,135 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- ProcessWasm.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache L...
[truncated]
|
Add support for source-level debugging of WebAssembly code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for picking this up again. I was going to ask about testing and I see that Adrian asked a similar question on Phabricator in the original review. My recommendation would be to use GdbRemoteTestCaseBase
style tests for this, as they'll run on all the existing bots. If you want to integration test the stub this is actually going to talk to it would be great to have that running in CI too, but that's not a requirement to get this merged.
The support for DW_OP_WASM_location
seems like it can be hoisted out in a separate patch with its own dedicated test.
uint32_t index; | ||
|
||
/* LLDB doesn't have an address space to represents WebAssembly Locals, | ||
* GLobals and operand stacks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/GLobals/globals/
uint8_t wasm_op = opcodes.GetU8(&offset); | ||
uint32_t index; | ||
|
||
/* LLDB doesn't have an address space to represents WebAssembly Locals, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Locals/locals/
# This file comes from https://reviews.llvm.org/D78978. | ||
# Author: [@paolosev](https://reviews.llvm.org/p/paolosev/). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this
// This file comes from https://reviews.llvm.org/D78978. | ||
// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this here and everywhere else.
ConstString ProcessWasm::GetPluginNameStatic() { | ||
static ConstString g_name("wasm"); | ||
return g_name; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetPluginNameStatic
should return a llvm::StringRef
. Same for GetPluginDescriptionStatic
below.
case WasmAddressType::Memory: | ||
return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error); | ||
case WasmAddressType::Object: | ||
// TODO ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? :-)
assert(packet_len + 1 < (int)sizeof(packet)); | ||
UNUSED_IF_ASSERT_DISABLED(packet_len); | ||
StringExtractorGDBRemote response; | ||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) == |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge conflict marker?
// Each WebAssembly module has separated address spaces for Code and Memory. | ||
// A WebAssembly module also has a Data section which, when the module is | ||
// loaded, gets mapped into a region in the module Memory. | ||
// For the purpose of debugging, we can represent all these separated 32-bit | ||
// address spaces with a single virtual 64-bit address space. | ||
// | ||
// Struct wasm_addr_t provides this encoding using bitfields | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be Doxygen style comments (///
).
Memory = 0x00, | ||
Object = 0x01, | ||
Invalid = 0x03 | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Newline
}; | ||
|
||
/// ProcessWasm provides the access to the Wasm program state | ||
/// retrieved from the Wasm engine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spurious space
…m-project into WebAssembly2024
Add support for source-level debugging of WebAssembly code that runs in a WebAssembly engine.
The idea is to use the GDB-remote protocol to connect to a Wasm engine that implements a GDB-remote stub that offers the ability to access the engine runtime internal state. This protocol is already supported by the "WebAssembly Micro Runtime" and the WAMR team greatly contributed to this work.
A WebAssembly debugging session can be started using the new command:
wasm [<hostname>:]<portnum>
The implementation is almost completely contained in Plugin classes and the only Wasm-specific changes to Core classes is in
class DWARFExpression
that handles a new Wasm-specific DWARF opcode (DW_OP_WASM_location
) added to the DWARF standard.