use crate::backtrace::{FrameInfo, WasmBacktrace};
use crate::instance::Instance;
use crate::module::code::Code;
use crate::store::StoreInner;
use crate::trap::Trap;
use crate::Error;
use super::frame::{Delimiter, Frame};
use super::Execution;
pub(crate) fn frame_info(
inner: &StoreInner,
instance: Instance,
func_index: u32,
code: &Code,
ip: u32,
) -> Option<FrameInfo> {
let module = inner.try_instance(instance)?.module.clone();
let code_offset = code.offsets().and_then(|o| o.get(ip as usize).copied());
Some(FrameInfo::new(module, func_index, code_offset))
}
fn build(inner: &StoreInner, frames: &[Frame], top_ip: Option<u32>) -> WasmBacktrace {
let last_real = frames.iter().rposition(|f| f.delimiter.is_none());
let mut infos = Vec::new();
let mut boundaries = Vec::new();
for (i, f) in frames.iter().enumerate().rev() {
match f.delimiter {
Some(Delimiter::HostReentry) => boundaries.push(infos.len()),
Some(Delimiter::TopLevel) => {} None => {
let ip = match top_ip {
Some(ip) if Some(i) == last_real => ip,
_ => f.ip.saturating_sub(1),
};
if let Some(info) = frame_info(inner, f.instance, f.func_index, &f.code, ip) {
infos.push(info);
}
}
}
}
WasmBacktrace::from_frames_with_boundaries(infos, boundaries)
}
pub(crate) fn from_parked(inner: &StoreInner) -> WasmBacktrace {
build(inner, inner.parked_exec().frames(), None)
}
impl Execution {
pub(crate) fn frames(&self) -> &[Frame] {
&self.frames
}
pub(super) fn capture_backtrace(&self, inner: &StoreInner, top_ip: u32) -> WasmBacktrace {
build(inner, &self.frames, Some(top_ip))
}
pub(super) fn attach_trap_backtrace(&self, inner: &StoreInner, err: Error, ip: u32) -> Error {
if !inner.engine().wasm_backtrace_enabled() {
return err;
}
match err.downcast_ref::<Trap>().copied() {
Some(trap) => Error::new(self.capture_backtrace(inner, ip)).context(trap),
None => err, }
}
pub(super) fn attach_suspension_backtrace(&self, inner: &StoreInner, err: Error) -> Error {
match self.frames.last() {
Some(f) => self.attach_trap_backtrace(inner, err, f.ip),
None => err,
}
}
}