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 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 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’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’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.