wasmtime/runtime/vm/
unwind.rs

1//! Support for low-level primitives of unwinding the stack.
2
3#[cfg(has_host_compiler_backend)]
4use crate::runtime::vm::arch;
5
6/// Implementation necessary to unwind the stack, used by `Backtrace`.
7pub unsafe trait Unwind {
8    /// Returns the offset, from the current frame pointer, of where to get to
9    /// the previous frame pointer on the stack.
10    fn next_older_fp_from_fp_offset(&self) -> usize;
11
12    /// Load the return address of a frame given the frame pointer for that
13    /// frame.
14    unsafe fn get_next_older_pc_from_fp(&self, fp: usize) -> usize;
15
16    /// Debug assertion that the frame pointer is aligned.
17    fn assert_fp_is_aligned(&self, fp: usize);
18}
19
20/// A host-backed implementation of unwinding, using the native platform ABI
21/// that Cranelift has.
22#[cfg(has_host_compiler_backend)]
23pub struct UnwindHost;
24
25#[cfg(has_host_compiler_backend)]
26unsafe impl Unwind for UnwindHost {
27    fn next_older_fp_from_fp_offset(&self) -> usize {
28        arch::NEXT_OLDER_FP_FROM_FP_OFFSET
29    }
30    unsafe fn get_next_older_pc_from_fp(&self, fp: usize) -> usize {
31        arch::get_next_older_pc_from_fp(fp)
32    }
33    fn assert_fp_is_aligned(&self, fp: usize) {
34        arch::assert_fp_is_aligned(fp)
35    }
36}
37
38/// An implementation specifically designed for unwinding Pulley's runtime stack
39/// (which might not match the native host).
40pub struct UnwindPulley;
41
42unsafe impl Unwind for UnwindPulley {
43    fn next_older_fp_from_fp_offset(&self) -> usize {
44        0
45    }
46    unsafe fn get_next_older_pc_from_fp(&self, fp: usize) -> usize {
47        // The calling convention always pushes the return pointer (aka the PC
48        // of the next older frame) just before this frame.
49        *(fp as *mut usize).offset(1)
50    }
51    fn assert_fp_is_aligned(&self, fp: usize) {
52        let expected = if cfg!(target_pointer_width = "32") {
53            8
54        } else {
55            16
56        };
57        assert_eq!(fp % expected, 0, "stack should always be aligned");
58    }
59}