wasmer_compiler/engine/trap/stack.rs
1use super::frame_info::{FRAME_INFO, GlobalFrameInfo};
2use backtrace::Backtrace;
3use wasmer_types::{FrameInfo, TrapCode};
4use wasmer_vm::Trap;
5
6/// Given a `Trap`, this function returns the Wasm trace and the trap code.
7pub fn get_trace_and_trapcode(trap: &Trap) -> (Vec<FrameInfo>, Option<TrapCode>) {
8 let info = FRAME_INFO.read().unwrap();
9 match &trap {
10 // A user error
11 Trap::User(_err) => (wasm_trace(&info, None, &Backtrace::new_unresolved()), None),
12 // A trap caused by the VM being Out of Memory
13 Trap::OOM { backtrace } => (wasm_trace(&info, None, backtrace), None),
14 // A trap caused by an error on the generated machine code for a Wasm function
15 Trap::Wasm {
16 pc,
17 signal_trap,
18 backtrace,
19 } => {
20 let trap_code = info
21 .lookup_trap_info(*pc)
22 .map_or(signal_trap.unwrap_or(TrapCode::StackOverflow), |info| {
23 info.trap_code
24 });
25
26 (wasm_trace(&info, Some(*pc), backtrace), Some(trap_code))
27 }
28 // A trap triggered manually from the Wasmer runtime
29 Trap::Lib {
30 trap_code,
31 backtrace,
32 } => (wasm_trace(&info, None, backtrace), Some(*trap_code)),
33 // An uncaught exception
34 Trap::UncaughtException { backtrace, .. } => (
35 wasm_trace(&info, None, backtrace),
36 Some(TrapCode::UncaughtException),
37 ),
38 }
39}
40
41/// Captures the current Wasm stack trace. Only useful when
42/// there are active Wasm frames on the stack, such as in
43/// libcalls or imported functions.
44pub fn wasm_trace_from_current_stack() -> Vec<FrameInfo> {
45 let info = FRAME_INFO.read().unwrap();
46 let backtrace = Backtrace::new_unresolved();
47 wasm_trace(&info, None, &backtrace)
48}
49
50fn wasm_trace(
51 info: &GlobalFrameInfo,
52 trap_pc: Option<usize>,
53 backtrace: &Backtrace,
54) -> Vec<FrameInfo> {
55 // Let's construct the trace
56 backtrace
57 .frames()
58 .iter()
59 .filter_map(|frame| {
60 let pc = frame.ip() as usize;
61 if pc == 0 {
62 None
63 } else {
64 // Note that we need to be careful about the pc we pass in here to
65 // lookup frame information. This program counter is used to
66 // translate back to an original source location in the origin wasm
67 // module. If this pc is the exact pc that the trap happened at,
68 // then we look up that pc precisely. Otherwise backtrace
69 // information typically points at the pc *after* the call
70 // instruction (because otherwise it's likely a call instruction on
71 // the stack). In that case we want to lookup information for the
72 // previous instruction (the call instruction) so we subtract one as
73 // the lookup.
74 let pc_to_lookup = if Some(pc) == trap_pc { pc } else { pc - 1 };
75 Some(pc_to_lookup)
76 }
77 })
78 .filter_map(|pc| info.lookup_frame_info(pc))
79 .collect::<Vec<_>>()
80}