blob: 1b6a9c98c5f3275592b51f07f0f8090abd477243 [file] [view] [edit]
# Debugging and Testing LLDB with WebAssembly
LLDB debugs WebAssembly through a standalone Wasm runtime. The runtime executes
the module and serves a GDB remote stub. LLDB's `wasm` platform launches the
runtime, picks a free TCP port and connects to the stub on it. The LLDB API test
suite uses the same setup to compile its test programs to WebAssembly and run
them.
This page covers configuring LLDB and the `wasm` platform. For building a
runtime, see the runtime's own documentation.
## Prerequisites
- A [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) release, which provides
the WASI sysroot, the wasm `compiler-rt` builtins and a `wasm-ld`.
- A Wasm runtime that serves a GDB remote stub. WAMR and WasmKit are shown
below.
## Choosing a compiler
Test programs are built for `wasm32-wasip1`, which both the wasi-sdk clang and
an upstream in-tree clang can target. `LLDB_TEST_COMPILER` picks one. It
defaults to the in-tree `clang` whenever clang is part of the build.
Prefer the in-tree clang, since it matches the LLDB under test and exercises
in-tree DWARF and codegen changes. Unlike the wasi-sdk clang, it needs two
things supplied:
- `wasm-ld`. Enable LLD in the build and it lands next to `clang`, where the
driver looks before `PATH`. Without LLD, symlink the wasi-sdk's `wasm-ld` into
that same directory.
- The wasm `compiler-rt` builtins, through `LLDB_TEST_RESOURCE_DIR` pointed at
the wasi-sdk's clang resource directory.
Both compilers need the WASI sysroot, passed as `LLDB_TEST_SYSROOT`.
## Configuring the platform
The `wasm` platform is selected with `--platform-name wasm`. The global
[`platform.plugin.wasm`](/use/settings.md#wasm) settings `runtime-path`,
`port-arg`, `env-arg` and `runtime-args` describe how to invoke the runtime.
`env-arg` is optional. Set it to forward the launch environment
(`target.env-vars`, `process launch -E`).
LLDB assembles the runtime's command line as:
```
<runtime-path> <runtime-args...> <port-arg><port> <env-arg><key=value>... <module> <inferior-args...>
```
`runtime-args` precedes the port argument, so a runtime that dispatches on a
leading subcommand names that subcommand there. `port-arg` has to carry the port
in a single argument, because LLDB concatenates the two. `env-arg` is repeated
once per environment variable, for example `--env=A=1 --env=B=2`.
A runtime's diagnostics share the inferior's standard error, so a verbose
runtime breaks tests that match program output. Use its quietest logging.
Most of these values begin with a dash, so the `settings set` examples below
pass `--` first to stop the command from reading them as its own options.
## Example runtimes
### WAMR
[WAMR](https://github.com/bytecodealliance/wasm-micro-runtime)'s `iwasm` takes
the debug server address as `host:port`. Its default heap and stack are small
enough that some tests trap, so raise them.
```
settings set -- platform.plugin.wasm.runtime-path /path/to/iwasm
settings set -- platform.plugin.wasm.runtime-args --heap-size=1048576 --stack-size=1048576 -v=0
settings set -- platform.plugin.wasm.port-arg -g=127.0.0.1:
settings set -- platform.plugin.wasm.env-arg --env=
```
### WasmKit
[WasmKit](https://github.com/swiftwasm/WasmKit)'s CLI takes a bare port number
and defaults to quiet, so `run` is all it needs beyond the port. That subcommand
has to come first, which is what `runtime-args` is for.
```
settings set -- platform.plugin.wasm.runtime-path /path/to/wasmkit-cli
settings set -- platform.plugin.wasm.runtime-args run
settings set -- platform.plugin.wasm.port-arg --debugger-port=
settings set -- platform.plugin.wasm.env-arg --env=
```
:::{note}
WasmKit's debugger support is behind the `WasmDebuggingSupport` package trait.
A CLI built without it rejects `--debugger-port` as an unknown option. Build
with
`swift build -c release --product wasmkit-cli --traits WasmDebuggingSupport`,
adding whichever other traits you need.
:::
## Running the test suite
Point the test suite at the sysroot and the resource directory, and pass the
target and platform configuration through `LLDB_TEST_USER_ARGS`:
```
$ cmake -G Ninja \
-DLLDB_TEST_SYSROOT=/path/to/wasi-sdk/share/wasi-sysroot \
-DLLDB_TEST_RESOURCE_DIR=/path/to/wasi-sdk/lib/clang/<version> \
-DLLDB_TEST_USER_ARGS="--triple;wasm32-wasip1;--platform-name;wasm;--setting;platform.plugin.wasm.runtime-path=/path/to/iwasm;--setting;platform.plugin.wasm.port-arg=-g=127.0.0.1:;--setting;platform.plugin.wasm.env-arg=--env=;--setting;platform.plugin.wasm.runtime-args=--heap-size=1048576 --stack-size=1048576 -v=0" \
<other options>
$ ninja check-lldb-api
```
`lldb-dotest` takes the same configuration as command line arguments, which is
easier if you keep the build configured for the host. There `-C`, `--sysroot`
and `--resource-dir` replace the three CMake variables. Also pass a separate
`--build-dir` so Wasm and host inferiors do not share an output directory.
The triple, platform and runtime settings reach only the API tests, so
`check-lldb-unit` is unaffected and `check-lldb-shell` still builds for the
host. `LLDB_TEST_SYSROOT` is the exception, since the shell tests also read it
as their host sysroot. Keep the Wasm sysroot out of a build that runs them.