Debugging WebAssembly with Core Dumps
Wasmtime can be configured to generate the standard Wasm core dump
format whenever guest Wasm programs trap. These core dumps can then be
consumed by external tooling (such as wasmgdb
) for post-mortem analysis.
This page focuses on generating and inspecting core dumps via the Wasmtime
command-line interface. For details on how to generate core dumps via the
wasmtime
embedding API, see Core Dumps in a Rust
Embedding.
First, we need to compile some code to Wasm that can trap. Consider the following Rust code:
// trap.rs fn main() { foo(42); } fn foo(x: u32) { bar(x); } fn bar(x: u32) { baz(x); } fn baz(x: u32) { assert!(x != 42); }
We can compile it to Wasm with the following command:
$ rustc --target wasm32-wasip1 -o ./trap.wasm ./trap.rs
Next, we can run it in Wasmtime and capture a core dump when it traps:
$ wasmtime -D coredump=./trap.coredump ./trap.wasm
thread 'main' panicked at /home/nick/scratch/trap.rs:14:5:
assertion failed: x != 42
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Error: failed to run main module `/home/nick/scratch/trap.wasm`
Caused by:
0: core dumped at /home/nick/scratch/trap.coredump
1: failed to invoke command default
2: wasm coredump generated while executing store_name:
modules:
<module>
instances:
Instance(store=1, index=1)
memories:
Memory(store=1, index=1)
globals:
Global(store=1, index=0)
backtrace:
error while executing at wasm backtrace:
0: 0x5961 - <unknown>!__rust_start_panic
1: 0x562a - <unknown>!rust_panic
2: 0x555d - <unknown>!std::panicking::rust_panic_with_hook::h58e7d0b3d70e95b6
3: 0x485d - <unknown>!std::panicking::begin_panic_handler::{{closure}}::h1853004619879cfd
4: 0x47bd - <unknown>!std::sys_common::backtrace::__rust_end_short_backtrace::hed32bc5557405634
5: 0x4f02 - <unknown>!rust_begin_unwind
6: 0xac01 - <unknown>!core::panicking::panic_fmt::h53ca5bf48b428895
7: 0xb1c5 - <unknown>!core::panicking::panic::h62c2c2bb054da7e1
8: 0x661 - <unknown>!trap::baz::h859f39b65389c077
9: 0x616 - <unknown>!trap::bar::h7ad12f9c5b730d17
10: 0x60a - <unknown>!trap::foo::ha69c95723611c1a0
11: 0x5fe - <unknown>!trap::main::hdfcd9f2d150fc3dc
12: 0x434 - <unknown>!core::ops::function::FnOnce::call_once::h24336e950fb97d1e
13: 0x40b - <unknown>!std::sys_common::backtrace::__rust_begin_short_backtrace::h2b37384d2b1a57ff
14: 0x4ec - <unknown>!std::rt::lang_start::{{closure}}::he86eb1b6ac6d7501
15: 0x24f7 - <unknown>!std::rt::lang_start_internal::h21f6a1d8f3633b54
16: 0x497 - <unknown>!std::rt::lang_start::h7d256f21902ff32b
17: 0x687 - <unknown>!__main_void
18: 0x3e6 - <unknown>!_start
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
You now have a core dump at ./trap.coredump
that can be consumed by external
tooling to do post-mortem analysis of the failure.