I saw in the chrome devtools "what's new" that they are... sort of? un-beta-ing debugging wasm with devtools. You still need an extension, but it's otherwise intended to be "out of the box".
I found the process a bit less out of the box than I expected, so I thought I'd document the "gotchas" I hit for anyone else that wanted to play here.
TLDR
- Install https://goo.gle/wasm-debugging-extension and restart the browser
- Add path mapping for rust std lib source in extension options
- ... profit?
Simple .wasm app
For reference, here's the relevant code to get raw wasm32-unknown-unknown
building:
// src/lib.rs
#[no_mangle]
pub fn add(left: i32, right: i32) -> i32 {
assert!(left != 42, "would take too long");
left + right
}
# Cargo.toml
[package]
name = "wasm-debug-check"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
And a simple way to make sure we always build with --target wasm32-unknown-unknown
:
# .cargo/config.toml
[build]
target = "wasm32-unknown-unknown"
Now cargo build
will create target/wasm32-unknown-unknown/debug/${crate_name_with_underscores}.wasm
, including the required DWARF debugging info.
Simple web host
And just to close the circle on the other side:
index.html
```html
WASM Host
Good
Bad
```
Getting debugging working
This runs, but causing a panic with the "Bad" button will simply give a stack trace to the .wasm dissasembly, even though DWARF debugging info is definitely in the file!
> wabt-1.0.33\bin\wasm-objdump.exe target\wasm32-unknown-unknown\debug\wasm_debug_check.wasm -h
wasm_debug_check.wasm: file format wasm 0x1
Sections:
Type start=0x0000000a end=0x00000069 (size=0x0000005f) count: 15
Function start=0x0000006b end=0x000000cb (size=0x00000060) count: 95
Table start=0x000000cd end=0x000000d2 (size=0x00000005) count: 1
Memory start=0x000000d4 end=0x000000d7 (size=0x00000003) count: 1
Global start=0x000000d9 end=0x000000f2 (size=0x00000019) count: 3
Export start=0x000000f4 end=0x0000011f (size=0x0000002b) count: 4
Elem start=0x00000121 end=0x00000139 (size=0x00000018) count: 1
Code start=0x0000013d end=0x000046be (size=0x00004581) count: 95
Data start=0x000046c1 end=0x000049fb (size=0x0000033a) count: 1
Custom start=0x000049ff end=0x0006864a (size=0x00063c4b) ".debug_info"
Custom start=0x0006864d end=0x00068a15 (size=0x000003c8) ".debug_pubtypes"
Custom start=0x00068a19 end=0x00093087 (size=0x0002a66e) ".debug_ranges"
Custom start=0x0009308a end=0x00094219 (size=0x0000118f) ".debug_abbrev"
Custom start=0x0009421d end=0x000d9dfa (size=0x00045bdd) ".debug_line"
Custom start=0x000d9dfe end=0x001813af (size=0x000a75b1) ".debug_str"
Custom start=0x001813b3 end=0x001bf5d5 (size=0x0003e222) ".debug_pubnames"
Custom start=0x001bf5d8 end=0x001c0e54 (size=0x0000187c) "name"
Custom start=0x001c0e56 end=0x001c0ea3 (size=0x0000004d) "producers"
Note the chunky .debug_*
custom sections.
The linked article does mention this, you need the (annoyingly named) chrome extension "C/C++ DevTools Support", linked here: https://goo.gle/wasm-debugging-extension
Even more annoyingly, it seems you need to restart chrome before it actually kicks in! You'll know it's working when you see these console messages on loading the wasm file:
[C/C++ DevTools Support (DWARF)] Loading debug symbols for http://localhost:63343/wasm-debug-check/target/wasm32-unknown-unknown/debug/wasm_debug_check.wasm...
[C/C++ DevTools Support (DWARF)] Loaded debug symbols for http://localhost:63343/wasm-debug-check/target/wasm32-unknown-unknown/debug/wasm_debug_check.wasm, found 250 source file(s)
Unfortunately when you hit the "Bad" button again you'll still get assembly: this is because the actual wasm error is in rustc source code, which was compiled on a build machine, and thus the debug path will look like /rustc/{long-hex}/library/panic_abort/src/lib.rs
, and that's the exact path chrome will look for your source:
Could not load content for file:///rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/library/panic_abort/src/lib.rs (System error: net::ERR_FILE_NOT_FOUND)
To fix this, you need to remap the path using the devtool extension's options:
And add the path mapping there under the default path substitutions. On my machine this looks like:
- from:
/rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/
- to:
C:\Users\simon\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\
Note that you do not put the file://
prefix that is shown in the error messages, and that the path can be a normal windows path (but /C:/...
also works!?)
The easiest way to get the from path I've found is to copy from the file not found error, but you can get the to path with rustc --print sysroot
then /lib/rustlib/src/rust/
. You'll probably have to do this every time you update rust, so I'd love to hear if there's a nicer option here.
There is still some /cargo/...
references in the sources, but these are cargo installed packages from the CI build machine, so you probably won't have those installed. You can do essentially the same process to map that to your $CARGO_HOME (defaults to ~/.cargo
) and manually fetch them if you need to, but you are not likely to hit an error in the crates there, from what I can tell.
Cargo packages that you use are stored with full paths, so they should work out of the box.
Hang on, my filesystem paths are in the .wasm?
Only by default with debug builds (using profile.dev
), but not cargo build --release
, which does include debuginfo, but only the linked in debuginfo from the std library.
If you want to debug a bit nicer, you also can enable debug info in release with:
# Cargo.toml
...
[profile.release]
debug = true
In order to get more reproducible builds, or a small measure of privacy while still making debugging issues in production nicer, you can can remap the included paths of the code you build (but not link to!) with the --remap-path-prefix FROM=TO
option (be sure to use an absolute target path to remove your local path):
# .cargo/config.toml
rustflags = [
"--remap-path-prefix",
"src/=/app/",
]
And map back on your machine in the extension.
If you want multiple .wasm files that map to the same e.g. /app/
path, then you will want a module-specific mapping in the extension: remember your crate name will have any hyphens replaced by _
in the file name! Additionally, note that creating a module-specific mapping, will cause default mappings to be ignored, annoyingly. You'll have to copy them across.
Can I split the debug info to a separate file?
Not with the default rust tools: split-debuginfo
is seemingly ignored for wasm*
targets, unfortunately. You might have luck with symbolicator/crates/wasm-split at master · getsentry/symbolicator · GitHub