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 impl crate::Handler {
44 /// Resume execution at the given PC, SP, and FP, with the given
45 /// payload values, according to the tail-call ABI's exception
46 /// scheme. Note that this scheme does not restore any other
47 /// registers, so the given state is all that we need.
48 ///
49 /// # Safety
50 ///
51 /// This method requires:
52 ///
53 /// - the `sp` and `fp` to correspond to an active stack frame
54 /// (above the current function), in code using Cranelift's
55 /// `tail` calling convention.
56 ///
57 /// - The `pc` to correspond to a `try_call` handler
58 /// destination, as emitted in Cranelift metadata, or
59 /// otherwise a target that is expecting the tail-call ABI's
60 /// exception ABI.
61 ///
62 /// - The Rust frames between the unwind destination and this
63 /// frame to be unwind-safe: that is, they cannot have `Drop`
64 /// handlers for which safety requires that they run.
65 ///
66 /// - The Cranelift-generated `try_call` that we're unwinding to was
67 /// invoking the callee with the `tail` calling convention.
68 pub unsafe fn resume_tailcc(
69 &self,
70 payload1: usize,
71 payload2: usize,
72 ) -> ! {
73 // Without this ASAN seems to nondeterministically trigger an
74 // internal assertion when running tests with threads. Not entirely
75 // clear what's going on here but it seems related to the fact that
76 // there's Rust code on the stack which is never cleaned up due to
77 // the jump out of `imp::resume_to_exception_handler`.
78 //
79 // This function is documented as something that should be called to
80 // clean up the entire thread's shadow memory and stack which isn't
81 // exactly what we want but this at least seems to resolve ASAN
82 // issues for now. Probably a heavy hammer but better than false
83 // positives I suppose...
84 #[cfg(asan)]
85 {
86 unsafe extern "C" {
87 fn __asan_handle_no_return();
88 }
89 unsafe {
90 __asan_handle_no_return();
91 }
92 }
93 unsafe {
94 imp::resume_to_exception_handler(self.pc, self.sp, self.fp, payload1, payload2)
95 }
96 }
97 }
98
99 /// Get the return address in the function at the next-older
100 /// frame from the given FP.
101 ///
102 /// # Safety
103 ///
104 /// - Requires that `fp` is a valid frame-pointer value for an
105 /// active stack frame (above the current function), in code
106 /// using Cranelift's `tail` calling convention.
107 use imp::get_next_older_pc_from_fp;
108
109 /// The offset of the saved old-FP value in a frame, from the
110 /// location pointed to by a given FP.
111 const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = imp::NEXT_OLDER_FP_FROM_FP_OFFSET;
112
113 /// The offset of the next older SP value, from the value of a
114 /// given FP.
115 const NEXT_OLDER_SP_FROM_FP_OFFSET: usize = imp::NEXT_OLDER_SP_FROM_FP_OFFSET;
116
117 /// Assert that the given `fp` is aligned as expected by the
118 /// host platform's implementation of the Cranelift tail-call
119 /// ABI.
120 use imp::assert_fp_is_aligned;
121
122 /// If we have the above host-specific implementations, we can
123 /// implement `Unwind`.
124 pub struct UnwindHost;
125
126 unsafe impl crate::stackwalk::Unwind for UnwindHost {
127 fn next_older_fp_from_fp_offset(&self) -> usize {
128 NEXT_OLDER_FP_FROM_FP_OFFSET
129 }
130 fn next_older_sp_from_fp_offset(&self) -> usize {
131 NEXT_OLDER_SP_FROM_FP_OFFSET
132 }
133 unsafe fn get_next_older_pc_from_fp(&self, fp: usize) -> usize {
134 unsafe {
135 get_next_older_pc_from_fp(fp)
136 }
137 }
138 fn assert_fp_is_aligned(&self, fp: usize) {
139 assert_fp_is_aligned(fp)
140 }
141 }
142 }
143}