forked from bytecodealliance/wasmtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add core dump support to the runtime (bytecodealliance#6513)
* Add config method for whether or not to capture coredumps on trap * Add core dump support to the runtime This adds the machinery to capture a core dump when a trap occurs and attach it to the resulting anyhow::Error that gets bubbled up to the caller. I've created a CoreDumpStack structure in the runtime, which is currently just a backtrace until we design a way to recover the locals stack values when a trap occurs. When that CoreDumpStack gets converted to a wasmtime::WasmCoreDump, we add additional information from the Store such as globals, memories, and instance information. A lot of this is mechanistically similar to how backtraces are captured and attached to errors. Given that they both are attached as context to anyhow::Errors, setting coredump_on_trap to true will supercede any setting for wasm_backtrace. * Address some PR feedback * Fix docs * Switch WasmCoreDump to have vec of module names rather than Modules * Add smoketests for WasmCoreDump * clean up tests * Update memories and globals field to be store_ * add debug impl for wasmcoredump * Remove duplicate imports * ignore miri for wasm tests
- Loading branch information
1 parent
2c9a742
commit 31639dd
Showing
18 changed files
with
436 additions
and
32 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
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,38 @@ | ||
use wasm_encoder::CoreDumpValue; | ||
|
||
use crate::{Backtrace, VMRuntimeLimits}; | ||
|
||
use super::CallThreadState; | ||
|
||
/// A WebAssembly Coredump | ||
#[derive(Debug)] | ||
pub struct CoreDumpStack { | ||
/// The backtrace containing the stack frames for the CoreDump | ||
pub bt: Backtrace, | ||
|
||
/// Unimplemented | ||
/// The indices of the locals and operand_stack all map to each other (ie. | ||
/// index 0 is the locals for the first frame in the backtrace, etc) | ||
pub locals: Vec<Vec<CoreDumpValue>>, | ||
|
||
/// Unimplemented | ||
/// The operands for each stack frame | ||
pub operand_stack: Vec<Vec<CoreDumpValue>>, | ||
} | ||
|
||
impl CoreDumpStack { | ||
/// Capture a core dump of the current wasm state | ||
pub fn new( | ||
cts: &CallThreadState, | ||
limits: *const VMRuntimeLimits, | ||
trap_pc_and_fp: Option<(usize, usize)>, | ||
) -> Self { | ||
let bt = unsafe { Backtrace::new_with_trap_state(limits, cts, trap_pc_and_fp) }; | ||
|
||
Self { | ||
bt, | ||
locals: vec![], | ||
operand_stack: vec![], | ||
} | ||
} | ||
} |
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
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
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,115 @@ | ||
use std::fmt; | ||
|
||
use crate::{store::StoreOpaque, FrameInfo, Global, Instance, Memory, Module, WasmBacktrace}; | ||
|
||
/// Representation of a core dump of a WebAssembly module | ||
/// | ||
/// When the Config::coredump_on_trap option is enabled this structure is | ||
/// attached to the [`anyhow::Error`] returned from many Wasmtime functions that | ||
/// execute WebAssembly such as [`Instance::new`] or [`Func::call`]. This can be | ||
/// acquired with the [`anyhow::Error::downcast`] family of methods to | ||
/// programmatically inspect the coredump. Otherwise since it's part of the | ||
/// error returned this will get printed along with the rest of the error when | ||
/// the error is logged. | ||
/// | ||
/// Note that some state, such as Wasm locals or values on the operand stack, | ||
/// may be optimized away by the compiler or otherwise not recovered in the | ||
/// coredump. | ||
/// | ||
/// Capturing of wasm coredumps can be configured through the | ||
/// [`Config::coredump_on_trap`][crate::Config::coredump_on_trap] method. | ||
/// | ||
/// For more information about errors in wasmtime see the documentation of the | ||
/// [`Trap`][crate::Trap] type. | ||
/// | ||
/// [`Func::call`]: crate::Func::call | ||
/// [`Instance::new`]: crate::Instance::new | ||
pub struct WasmCoreDump { | ||
name: String, | ||
modules: Vec<Module>, | ||
instances: Vec<Instance>, | ||
store_memories: Vec<Memory>, | ||
store_globals: Vec<Global>, | ||
backtrace: WasmBacktrace, | ||
} | ||
|
||
impl WasmCoreDump { | ||
pub(crate) fn new(store: &StoreOpaque, backtrace: WasmBacktrace) -> WasmCoreDump { | ||
let modules: Vec<_> = store.modules().all_modules().cloned().collect(); | ||
let instances: Vec<Instance> = store.all_instances().collect(); | ||
let store_memories: Vec<Memory> = store.all_memories().collect(); | ||
let store_globals: Vec<Global> = store.all_globals().collect(); | ||
|
||
WasmCoreDump { | ||
name: String::from("store_name"), | ||
modules, | ||
instances, | ||
store_memories, | ||
store_globals, | ||
backtrace, | ||
} | ||
} | ||
|
||
/// The stack frames for the CoreDump | ||
pub fn frames(&self) -> &[FrameInfo] { | ||
self.backtrace.frames() | ||
} | ||
|
||
/// The names of the modules involved in the CoreDump | ||
pub fn modules(&self) -> &[Module] { | ||
self.modules.as_ref() | ||
} | ||
|
||
/// The instances involved in the CoreDump | ||
pub fn instances(&self) -> &[Instance] { | ||
self.instances.as_ref() | ||
} | ||
|
||
/// The imported globals that belong to the store, rather than a specific | ||
/// instance | ||
pub fn store_globals(&self) -> &[Global] { | ||
self.store_globals.as_ref() | ||
} | ||
|
||
/// The imported memories that belong to the store, rather than a specific | ||
/// instance. | ||
pub fn store_memories(&self) -> &[Memory] { | ||
self.store_memories.as_ref() | ||
} | ||
} | ||
|
||
impl fmt::Display for WasmCoreDump { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
writeln!(f, "wasm coredump generated while executing {}:", self.name)?; | ||
writeln!(f, "modules:")?; | ||
for module in self.modules.iter() { | ||
writeln!(f, " {}", module.name().unwrap_or("<module>"))?; | ||
} | ||
|
||
writeln!(f, "instances:")?; | ||
for instance in self.instances.iter() { | ||
writeln!(f, " {:?}", instance)?; | ||
} | ||
|
||
writeln!(f, "memories:")?; | ||
for memory in self.store_memories.iter() { | ||
writeln!(f, " {:?}", memory)?; | ||
} | ||
|
||
writeln!(f, "globals:")?; | ||
for global in self.store_globals.iter() { | ||
writeln!(f, " {:?}", global)?; | ||
} | ||
|
||
writeln!(f, "backtrace:")?; | ||
write!(f, "{}", self.backtrace)?; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl fmt::Debug for WasmCoreDump { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!(f, "<wasm core dump>") | ||
} | ||
} |
Oops, something went wrong.