-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #190.
- Loading branch information
Showing
1 changed file
with
119 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
This document describes the usage of coredump for post-mortem debugging with | ||
WebAssembly. | ||
|
||
Stability of this specification: **experimental**. | ||
|
||
# Idea | ||
|
||
When WebAssembly enters a trap, it starts unwinding and collects debugging | ||
information. For each stack frame, the state of the WebAssembly instance can be | ||
captured by collecting the values: | ||
- in locals (includes function parameters) | ||
- in globals | ||
- on the stack | ||
|
||
Along with an instruction binary offset (relative to the code section, as | ||
specified by [DWARF]). | ||
|
||
The post mortem analyze is done using the coredump file (that includes the | ||
collected values and the WebAssembly linear memory) and [DWARF] informations. | ||
Similar to the debugging flow with [gdb]. | ||
|
||
## Runtime support | ||
|
||
Most of the WebAssembly runtimes are already able to present a useful stacktrace | ||
on crash to the user. When they are configured to emit a coredump, they collect | ||
the debugging information and write a coredump file. | ||
|
||
An example output: | ||
``` | ||
$ wasmrun module.wasm | ||
Exit 1: Uncaught RuntimeError: memory access out of bounds (core dumped). | ||
``` | ||
A coredump file has been generated. | ||
|
||
For experimenting, runtime support is not strictly necessary. A tools can | ||
transform the Wasm binary to inject code that will manually unwind the stack and | ||
collect debugging information, for instance [wasm-edit coredump]. Such a | ||
transformation has important limitations; a trap caused by an invalid memory | ||
operation or exception in a host function might not be caught. | ||
|
||
## Security and privacy considerations | ||
|
||
Using the WebAssembly linear memory for debugging exposes the risk of seeing, | ||
manipulating and/or collecting sensitive informations. Handling of sensitive | ||
data is out of scope. | ||
|
||
No particular security considerations. | ||
|
||
## Debugger support | ||
|
||
[gdb] doesn't support Wasm coredump and it's unclear if it can. Wasm coredump | ||
differ from ELF coredump in a few significant ways: | ||
- Wasm semantics; usage of locals, globals and the stack. | ||
- The process image is only the Wasm linear memory. | ||
- etc. | ||
|
||
For experimenting, a custom tool has been built and mimics [gdb]: [wasmgdb]. | ||
|
||
# Coredump file format | ||
|
||
The generated coredump is a binary file containing: | ||
- a snapshot of the WebAssembly linear memory or relevant regions. | ||
- the `coredump` struct. | ||
|
||
The placement of the `coredump` struct within the coredump file is not defined | ||
yet. However, for the sake of argument we assume it's at offset 0. | ||
|
||
# `coredump` struct | ||
|
||
The coredump struct starts with the numbers of frame recorded and the combined | ||
size of all frames, followed by the frames themself. | ||
|
||
``` | ||
coredump ::= size:u32 cont:vec(frame) | ||
``` | ||
|
||
> implementer note: since the `frame` struct doesn't have a fixed size, the | ||
> `size` value can be used to append new frames because it's pointing at the end | ||
> of the `coredump`. | ||
``` | ||
frame ::= codeoffset:u32 | ||
locals:vec(local) | ||
globals:vec(global) | ||
stack:vec(stack) | ||
reserved:u32 | ||
``` | ||
|
||
The `reserved` bytes are decoded as an empty vector and reserved for future use. | ||
|
||
`vec` (same encoding as [Wasm Vectors]): | ||
``` | ||
vec(B) ::= n:u32 cont:B | ||
``` | ||
|
||
`u32` are encoding using LEB128, like [Wasm u32]. | ||
|
||
# Demo | ||
|
||
Please have a look at the demonstration using the experimental support and | ||
tooling: [demo]. | ||
|
||
# Useful links | ||
|
||
- [ELF coredump] | ||
- [Wasmer FrameInfo] | ||
|
||
[Wasm Vectors]: https://webassembly.github.io/spec/core/binary/conventions.html#binary-vec | ||
[ELF coredump]: https://www.gabriel.urdhr.fr/2015/05/29/core-file/ | ||
[Core dump on Wikipedia]: https://en.wikipedia.org/wiki/Core_dump | ||
[gdb]: https://linux.die.net/man/1/gdb | ||
[wasm-edit coredump]: https://github.com/xtuc/wasm-edit/blob/main/src/coredump.rs | ||
[wasm-edit]: https://github.com/xtuc/wasm-edit | ||
[wasmgdb]: https://github.com/xtuc/wasmgdb | ||
[DWARF]: https://yurydelendik.github.io/webassembly-dwarf | ||
[Wasmer FrameInfo]: https://docs.rs/wasmer/latest/wasmer/struct.FrameInfo.html | ||
[Wasm u32]: https://webassembly.github.io/spec/core/binary/values.html#binary-int | ||
[demo]: https://github.com/xtuc/wasmgdb/wiki/Demo |