Backtrace WebAssembly function JIT frames (#759)
* Create backtrace * Extend unwind information with FDE data. * Expose backtrace via API/Trap * wasmtime_call returns not-str * Return Arc<JITFrameTag> * rename frame -> function * Fix windows crashes and unwrap UNWIND_HISTORY_TABLE * mmaps -> entries * pass a backtrace in ActionOutcome * add test_trap_stack_overflow * Update cranelift version.
This commit is contained in:
@@ -147,7 +147,7 @@ impl WrappedCallable for WasmtimeFn {
|
||||
.map_err(|e| Trap::new(format!("trampoline error: {:?}", e)))?;
|
||||
|
||||
// Call the trampoline.
|
||||
if let Err(message) = unsafe {
|
||||
if let Err(error) = unsafe {
|
||||
self.instance.with_signals_on(|| {
|
||||
wasmtime_runtime::wasmtime_call_trampoline(
|
||||
vmctx,
|
||||
@@ -156,8 +156,12 @@ impl WrappedCallable for WasmtimeFn {
|
||||
)
|
||||
})
|
||||
} {
|
||||
let trap =
|
||||
take_api_trap().unwrap_or_else(|| Trap::new(format!("call error: {}", message)));
|
||||
let message = error.0;
|
||||
let backtrace = error.1;
|
||||
|
||||
let trap = take_api_trap().unwrap_or_else(|| {
|
||||
Trap::new_with_trace(format!("call error: {}", message), backtrace)
|
||||
});
|
||||
return Err(trap);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ use wasmtime_environ::entity::{EntityRef, PrimaryMap};
|
||||
use wasmtime_environ::ir::types;
|
||||
use wasmtime_environ::isa::TargetIsa;
|
||||
use wasmtime_environ::wasm::{DefinedFuncIndex, FuncIndex};
|
||||
use wasmtime_environ::{ir, settings, CompiledFunction, Export, Module, TrapInformation};
|
||||
use wasmtime_environ::{
|
||||
ir, settings, CompiledFunction, CompiledFunctionUnwindInfo, Export, Module, TrapInformation,
|
||||
};
|
||||
use wasmtime_jit::trampoline::ir::{
|
||||
ExternalName, Function, InstBuilder, MemFlags, StackSlotData, StackSlotKind,
|
||||
};
|
||||
@@ -136,6 +138,7 @@ fn make_trampoline(
|
||||
|
||||
let mut context = Context::new();
|
||||
context.func = Function::with_name_signature(ExternalName::user(0, 0), signature.clone());
|
||||
context.func.collect_frame_layout_info();
|
||||
|
||||
let ss = context.func.create_stack_slot(StackSlotData::new(
|
||||
StackSlotKind::ExplicitSlot,
|
||||
@@ -213,8 +216,7 @@ fn make_trampoline(
|
||||
.map_err(|error| pretty_error(&context.func, Some(isa), error))
|
||||
.expect("compile_and_emit");
|
||||
|
||||
let mut unwind_info = Vec::new();
|
||||
context.emit_unwind_info(isa, &mut unwind_info);
|
||||
let unwind_info = CompiledFunctionUnwindInfo::new(isa, &context);
|
||||
|
||||
let traps = trap_sink.traps;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::instance::Instance;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use wasmtime_runtime::{get_backtrace, Backtrace, BacktraceFrame};
|
||||
|
||||
/// A struct representing an aborted instruction execution, with a message
|
||||
/// indicating the cause.
|
||||
@@ -26,10 +27,21 @@ impl Trap {
|
||||
/// assert_eq!("unexpected error", trap.message());
|
||||
/// ```
|
||||
pub fn new<I: Into<String>>(message: I) -> Self {
|
||||
Self::new_with_trace(message, get_backtrace())
|
||||
}
|
||||
|
||||
pub(crate) fn new_with_trace<I: Into<String>>(message: I, backtrace: Backtrace) -> Self {
|
||||
let mut trace = Vec::with_capacity(backtrace.len());
|
||||
for i in 0..backtrace.len() {
|
||||
// Don't include frames without backtrace info.
|
||||
if let Some(info) = FrameInfo::try_from(backtrace[i]) {
|
||||
trace.push(info);
|
||||
}
|
||||
}
|
||||
Trap {
|
||||
inner: Arc::new(TrapInner {
|
||||
message: message.into(),
|
||||
trace: Vec::new(),
|
||||
trace,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -62,22 +74,42 @@ impl fmt::Display for Trap {
|
||||
impl std::error::Error for Trap {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FrameInfo;
|
||||
pub struct FrameInfo {
|
||||
module_name: Option<String>,
|
||||
func_index: u32,
|
||||
}
|
||||
|
||||
impl FrameInfo {
|
||||
pub fn instance(&self) -> *const Instance {
|
||||
unimplemented!("FrameInfo::instance");
|
||||
}
|
||||
|
||||
pub fn func_index() -> usize {
|
||||
unimplemented!("FrameInfo::func_index");
|
||||
pub fn func_index(&self) -> u32 {
|
||||
self.func_index
|
||||
}
|
||||
|
||||
pub fn func_offset() -> usize {
|
||||
pub fn func_offset(&self) -> usize {
|
||||
unimplemented!("FrameInfo::func_offset");
|
||||
}
|
||||
|
||||
pub fn module_offset() -> usize {
|
||||
pub fn module_offset(&self) -> usize {
|
||||
unimplemented!("FrameInfo::module_offset");
|
||||
}
|
||||
|
||||
pub fn module_name(&self) -> Option<&str> {
|
||||
self.module_name.as_deref()
|
||||
}
|
||||
|
||||
pub(crate) fn try_from(backtrace: BacktraceFrame) -> Option<FrameInfo> {
|
||||
if let Some(tag) = backtrace.tag() {
|
||||
let func_index = tag.func_index as u32;
|
||||
let module_name = tag.module_id.clone();
|
||||
Some(FrameInfo {
|
||||
func_index,
|
||||
module_name,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user