Path: blob/main/crates/unwinder/src/arch/mod.rs
1693 views
//! Architecture-specific runtime support corresponding to details of1//! Cranelift codegen or ABI support.2//!3//! This crate houses any architecture-specific tidbits required when4//! building a runtime that executes Cranelift-produced code.5//!6//! All architectures have the same interface when exposed to the rest of the7//! crate.89cfg_if::cfg_if! {10if #[cfg(target_arch = "x86_64")] {11mod x86;12use x86 as imp;13} else if #[cfg(target_arch = "aarch64")] {14mod aarch64;15use aarch64 as imp;16} else if #[cfg(target_arch = "s390x")] {17mod s390x;18use s390x as imp;19} else if #[cfg(target_arch = "riscv64")] {20mod riscv64;21use riscv64 as imp;22}23}2425// Re re-export functions from the `imp` module with one set of `pub26// use` declarations here so we can share doc-comments.2728cfg_if::cfg_if! {29if #[cfg(any(30target_arch = "x86_64",31target_arch = "aarch64",32target_arch = "s390x",33target_arch = "riscv64"34))] {35/// Get the current stack pointer (at the time this function is36/// executing). This may be used to check, e.g., approximate space37/// remaining on a stack, but cannot be relied upon for anything exact38/// because the stack pointer from *within this function* is read and39/// the frame is later popped.40pub use imp::get_stack_pointer;4142impl crate::Handler {43/// Resume execution at the given PC, SP, and FP, with the given44/// payload values, according to the tail-call ABI's exception45/// scheme. Note that this scheme does not restore any other46/// registers, so the given state is all that we need.47///48/// # Safety49///50/// This method requires:51///52/// - the `sp` and `fp` to correspond to an active stack frame53/// (above the current function), in code using Cranelift's54/// `tail` calling convention.55///56/// - The `pc` to correspond to a `try_call` handler57/// destination, as emitted in Cranelift metadata, or58/// otherwise a target that is expecting the tail-call ABI's59/// exception ABI.60///61/// - The Rust frames between the unwind destination and this62/// frame to be unwind-safe: that is, they cannot have `Drop`63/// handlers for which safety requires that they run.64///65/// - The Cranelift-generated `try_call` that we're unwinding to was66/// invoking the callee with the `tail` calling convention.67pub unsafe fn resume_tailcc(68&self,69payload1: usize,70payload2: usize,71) -> ! {72// Without this ASAN seems to nondeterministically trigger an73// internal assertion when running tests with threads. Not entirely74// clear what's going on here but it seems related to the fact that75// there's Rust code on the stack which is never cleaned up due to76// the jump out of `imp::resume_to_exception_handler`.77//78// This function is documented as something that should be called to79// clean up the entire thread's shadow memory and stack which isn't80// exactly what we want but this at least seems to resolve ASAN81// issues for now. Probably a heavy hammer but better than false82// positives I suppose...83#[cfg(asan)]84{85unsafe extern "C" {86fn __asan_handle_no_return();87}88unsafe {89__asan_handle_no_return();90}91}92unsafe {93imp::resume_to_exception_handler(self.pc, self.sp, self.fp, payload1, payload2)94}95}96}9798/// Get the return address in the function at the next-older99/// frame from the given FP.100///101/// # Safety102///103/// - Requires that `fp` is a valid frame-pointer value for an104/// active stack frame (above the current function), in code105/// using Cranelift's `tail` calling convention.106use imp::get_next_older_pc_from_fp;107108/// The offset of the saved old-FP value in a frame, from the109/// location pointed to by a given FP.110const NEXT_OLDER_FP_FROM_FP_OFFSET: usize = imp::NEXT_OLDER_FP_FROM_FP_OFFSET;111112/// The offset of the next older SP value, from the value of a113/// given FP.114const NEXT_OLDER_SP_FROM_FP_OFFSET: usize = imp::NEXT_OLDER_SP_FROM_FP_OFFSET;115116/// Assert that the given `fp` is aligned as expected by the117/// host platform's implementation of the Cranelift tail-call118/// ABI.119use imp::assert_fp_is_aligned;120121/// If we have the above host-specific implementations, we can122/// implement `Unwind`.123pub struct UnwindHost;124125unsafe impl crate::stackwalk::Unwind for UnwindHost {126fn next_older_fp_from_fp_offset(&self) -> usize {127NEXT_OLDER_FP_FROM_FP_OFFSET128}129fn next_older_sp_from_fp_offset(&self) -> usize {130NEXT_OLDER_SP_FROM_FP_OFFSET131}132unsafe fn get_next_older_pc_from_fp(&self, fp: usize) -> usize {133unsafe {134get_next_older_pc_from_fp(fp)135}136}137fn assert_fp_is_aligned(&self, fp: usize) {138assert_fp_is_aligned(fp)139}140}141}142}143144145