Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/unwinder/src/arch/mod.rs
1693 views
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
10
cfg_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
29
cfg_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
}
144
145