wasmtime_internal_unwinder/arch/
mod.rs

1//! Architecture-specific runtime support corresponding to details of
2//! Cranelift codegen or ABI support.
3//!
4//! This crate houses any architecture-specific tidbits required when
5//! building a runtime that executes Cranelift-produced code.
6//!
7//! All architectures have the same interface when exposed to the rest of the
8//! crate.
9
10cfg_if::cfg_if! {
11    if #[cfg(target_arch = "x86_64")] {
12        mod x86;
13        use x86 as imp;
14    } else if #[cfg(target_arch = "aarch64")] {
15        mod aarch64;
16        use aarch64 as imp;
17    } else if #[cfg(target_arch = "s390x")] {
18        mod s390x;
19        use s390x as imp;
20    } else if #[cfg(target_arch = "riscv64")] {
21        mod riscv64;
22        use riscv64 as imp;
23    }
24}
25
26// Re re-export functions from the `imp` module with one set of `pub
27// use` declarations here so we can share doc-comments.
28
29cfg_if::cfg_if! {
30    if #[cfg(any(
31        target_arch = "x86_64",
32        target_arch = "aarch64",
33        target_arch = "s390x",
34        target_arch = "riscv64"
35    ))] {
36        /// Get the current stack pointer (at the time this function is
37        /// executing). This may be used to check, e.g., approximate space
38        /// remaining on a stack, but cannot be relied upon for anything exact
39        /// because the stack pointer from *within this function* is read and
40        /// the frame is later popped.
41        pub use imp::get_stack_pointer;
42
43        /// Resume execution at the given PC, SP, and FP, with the given
44        /// payload values, according to the tail-call ABI's exception
45        /// scheme. Note that this scheme does not restore any other
46        /// registers, so the given state is all that we need.
47        ///
48        /// # Safety
49        ///
50        /// This method requires:
51        ///
52        /// - the `sp` and `fp` to correspond to an active stack frame
53        ///   (above the current function), in code using Cranelift's
54        ///   `tail` calling convention.
55        ///
56        /// - The `pc` to correspond to a `try_call` handler
57        ///   destination, as emitted in Cranelift metadata, or
58        ///   otherwise a target that is expecting the tail-call ABI's
59        ///   exception ABI.
60        ///
61        /// - The Rust frames between the unwind destination and this
62        ///   frame to be unwind-safe: that is, they cannot have `Drop`
63        ///   handlers for which safety requires that they run.
64        pub unsafe fn resume_to_exception_handler(
65            pc: usize,
66            sp: usize,
67            fp: usize,
68            payload1: usize,
69            payload2: usize,
70        ) -> ! {
71            // Without this ASAN seems to nondeterministically trigger an
72            // internal assertion when running tests with threads. Not entirely
73            // clear what's going on here but it seems related to the fact that
74            // there's Rust code on the stack which is never cleaned up due to
75            // the jump out of `imp::resume_to_exception_handler`.
76            //
77            // This function is documented as something that should be called to
78            // clean up the entire thread's shadow memory and stack which isn't
79            // exactly what we want but this at least seems to resolve ASAN
80            // issues for now. Probably a heavy hammer but better than false
81            // positives I suppose...
82            #[cfg(asan)]
83            {
84                unsafe extern "C" {
85                    fn __asan_handle_no_return();
86                }
87                unsafe {
88                    __asan_handle_no_return();
89                }
90            }
91            unsafe {
92                imp::resume_to_exception_handler(pc, sp, fp, payload1, payload2)
93            }
94        }
95
96        /// Get the return address in the function at the next-older
97        /// frame from the given FP.
98        ///
99        /// # Safety
100        ///
101        /// - Requires that `fp` is a valid frame-pointer value for an
102        ///   active stack frame (above the current function), in code
103        ///   using Cranelift's `tail` calling convention.
104        pub use imp::get_next_older_pc_from_fp;
105
106
107        /// The offset of the saved old-FP value in a frame, from the
108        /// location pointed to by a given FP.
109        pub const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = imp::NEXT_OLDER_FP_FROM_FP_OFFSET;
110
111        /// The offset of the next older SP value, from the value of a
112        /// given FP.
113        pub const NEXT_OLDER_SP_FROM_FP_OFFSET: usize = imp::NEXT_OLDER_SP_FROM_FP_OFFSET;
114
115        /// Assert that the given `fp` is aligned as expected by the
116        /// host platform's implementation of the Cranelift tail-call
117        /// ABI.
118        pub use imp::assert_fp_is_aligned;
119
120        /// If we have the above host-specific implementations, we can
121        /// implement `Unwind`.
122        pub struct UnwindHost;
123
124        unsafe impl crate::stackwalk::Unwind for UnwindHost {
125            fn next_older_fp_from_fp_offset(&self) -> usize {
126                NEXT_OLDER_FP_FROM_FP_OFFSET
127            }
128            fn next_older_sp_from_fp_offset(&self) -> usize {
129                NEXT_OLDER_SP_FROM_FP_OFFSET
130            }
131            unsafe fn get_next_older_pc_from_fp(&self, fp: usize) -> usize {
132                unsafe {
133                    get_next_older_pc_from_fp(fp)
134                }
135            }
136            fn assert_fp_is_aligned(&self, fp: usize) {
137                assert_fp_is_aligned(fp)
138            }
139        }
140    }
141}