debugging.md
1 # Debugging Rust-Generated WebAssembly 2 3 This section contains tips for debugging Rust-generated WebAssembly. 4 5 ## Building with Debug Symbols 6 7 > ⚡ When debugging, always make sure you are building with debug symbols! 8 9 If you don't have debug symbols enabled, then the `"name"` custom section won't 10 be present in the compiled `.wasm` binary, and stack traces will have function 11 names like `wasm-function[42]` rather than the Rust name of the function, like 12 `wasm_game_of_life::Universe::live_neighbor_count`. 13 14 When using a "debug" build (aka `wasm-pack build --debug` or `cargo build`) 15 debug symbols are enabled by default. 16 17 With a "release" build, debug symbols are not enabled by default. To enable 18 debug symbols, ensure that you `debug = true` in the `[profile.release]` section 19 of your `Cargo.toml`: 20 21 ```toml 22 [profile.release] 23 debug = true 24 ``` 25 26 ## Logging with the `console` APIs 27 28 Logging is one of the most effective tools we have for proving and disproving 29 hypotheses about why our programs are buggy. On the Web, [the `console.log` 30 function](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) is the 31 way to log messages to the browser's developer tools console. 32 33 We can use [the `web-sys` crate][web-sys] to get access to the `console` logging 34 functions: 35 36 ```rust 37 extern crate web_sys; 38 39 web_sys::console::log_1(&"Hello, world!".into()); 40 ``` 41 42 Alternatively, [the `console.error` 43 function](https://developer.mozilla.org/en-US/docs/Web/API/Console/error) has 44 the same signature as `console.log`, but developer tools tend to also capture 45 and display a stack trace alongside the logged message when `console.error` is 46 used. 47 48 ### References 49 50 * Using `console.log` with the `web-sys` crate: 51 * [`web_sys::console::log` takes an array of values to log](https://rustwasm.github.io/wasm-bindgen/api/web_sys/console/fn.log.html) 52 * [`web_sys::console::log_1` logs a single value](https://rustwasm.github.io/wasm-bindgen/api/web_sys/console/fn.log_1.html) 53 * [`web_sys::console::log_2` logs two values](https://rustwasm.github.io/wasm-bindgen/api/web_sys/console/fn.log_2.html) 54 * Etc... 55 * Using `console.error` with the `web-sys` crate: 56 * [`web_sys::console::error` takes an array of values to log](https://rustwasm.github.io/wasm-bindgen/api/web_sys/console/fn.error.html) 57 * [`web_sys::console::error_1` logs a single value](https://rustwasm.github.io/wasm-bindgen/api/web_sys/console/fn.error_1.html) 58 * [`web_sys::console::error_2` logs two values](https://rustwasm.github.io/wasm-bindgen/api/web_sys/console/fn.error_2.html) 59 * Etc... 60 * [The `console` object on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console) 61 * [Firefox Developer Tools — Web Console](https://developer.mozilla.org/en-US/docs/Tools/Web_Console) 62 * [Microsoft Edge Developer Tools — Console](https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide/console) 63 * [Get Started with the Chrome DevTools Console](https://developers.google.com/web/tools/chrome-devtools/console/get-started) 64 65 ## Logging Panics 66 67 [The `console_error_panic_hook` crate logs unexpected panics to the developer 68 console via `console.error`.][panic-hook] Rather than getting cryptic, 69 difficult-to-debug `RuntimeError: unreachable executed` error messages, this 70 gives you Rust's formatted panic message. 71 72 All you need to do is install the hook by calling 73 `console_error_panic_hook::set_once()` in an initialization function or common 74 code path: 75 76 ```rust 77 #[wasm_bindgen] 78 pub fn init_panic_hook() { 79 console_error_panic_hook::set_once(); 80 } 81 ``` 82 83 [panic-hook]: https://github.com/rustwasm/console_error_panic_hook 84 85 ## Using a Debugger 86 87 Unfortunately, the debugging story for WebAssembly is still immature. On most 88 Unix systems, [DWARF][dwarf] is used to encode the information that a debugger 89 needs to provide source-level inspection of a running program. There is an 90 alternative format that encodes similar information on Windows. Currently, there 91 is no equivalent for WebAssembly. Therefore, debuggers currently provide limited 92 utility, and we end up stepping through raw WebAssembly instructions emitted by 93 the compiler, rather than the Rust source text we authored. 94 95 > There is a [sub-charter of the W3C WebAssembly group for 96 > debugging][debugging-subcharter], so expect this story to improve in the 97 > future! 98 99 [debugging-subcharter]: https://github.com/WebAssembly/debugging 100 [dwarf]: http://dwarfstd.org/ 101 102 Nonetheless, debuggers are still useful for inspecting the JavaScript that 103 interacts with our WebAssembly, and inspecting raw wasm state. 104 105 ### References 106 107 * [Firefox Developer Tools — Debugger](https://developer.mozilla.org/en-US/docs/Tools/Debugger) 108 * [Microsoft Edge Developer Tools — Debugger](https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide/debugger) 109 * [Get Started with Debugging JavaScript in Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools/javascript/) 110 111 ## Avoid the Need to Debug WebAssembly in the First Place 112 113 If the bug is specific to interactions with JavaScript or Web APIs, then [write 114 tests with `wasm-bindgen-test`.][wbg-test] 115 116 If a bug does *not* involve interaction with JavaScript or Web APIs, then try to 117 reproduce it as a normal Rust `#[test]` function, where you can leverage your 118 OS's mature native tooling when debugging. Use testing crates like 119 [`quickcheck`][quickcheck] and its test case shrinkers to mechanically reduce 120 test cases. Ultimately, you will have an easier time finding and fixing bugs if 121 you can isolate them in a smaller test cases that don't require interacting with 122 JavaScript. 123 124 Note that in order to run native `#[test]`s without compiler and linker errors, 125 you will need to ensure that `"rlib"` is included in the `[lib.crate-type]` 126 array in your `Cargo.toml` file. 127 128 ```toml 129 [lib] 130 crate-type ["cdylib", "rlib"] 131 ``` 132 133 [quickcheck]: https://crates.io/crates/quickcheck 134 [web-sys]: https://rustwasm.github.io/wasm-bindgen/web-sys/index.html 135 [wbg-test]: https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/index.html