1 //! Throw action computation (handler search). 2 //! 3 //! In order to throw exceptions from within Cranelift-compiled code, 4 //! we provide a runtime function helper meant to be called by host 5 //! code that is invoked by guest code. 6 //! 7 //! The helper below must be provided a delimited range on the stack 8 //! corresponding to Cranelift frames above the current host code. It 9 //! will look for any handlers in this code, given a closure that 10 //! knows how to use an absolute PC to look up a module's exception 11 //! table and its start-of-code-segment. If a handler is found, the 12 //! helper below will return the SP, FP and PC that must be 13 //! restored. Architecture-specific helpers are provided to jump to 14 //! this new context with payload values. Otherwise, if no handler is 15 //! found, the return type indicates this, and it is the caller's 16 //! responsibility to invoke alternative behavior (e.g., abort the 17 //! program or unwind all the way to initial Cranelift-code entry). 18 19 use crate::{Frame, Unwind}; 20 use core::ops::ControlFlow; 21 22 /// Description of a frame on the stack that is ready to catch an exception. 23 #[derive(Debug)] 24 pub struct Handler { 25 /// Program counter of handler return point. 26 pub pc: usize, 27 /// Stack pointer to restore before jumping to handler. 28 pub sp: usize, 29 /// Frame pointer to restore before jumping to handler. 30 pub fp: usize, 31 } 32 33 impl Handler { 34 /// Implementation of stack-walking to find a handler. 35 /// 36 /// This function searches for a handler in the given range of stack 37 /// frames, starting from the throw stub and up to a specified entry 38 /// frame. 39 /// 40 /// # Safety 41 /// 42 /// The safety of this function is the same as [`crate::visit_frames`] where the 43 /// values passed in configuring the frame pointer walk must be correct and 44 /// Wasm-defined for this to not have UB. find<F: Fn(&Frame) -> Option<(usize, usize)>>( unwind: &dyn Unwind, frame_handler: F, exit_pc: usize, exit_trampoline_frame: usize, entry_frame: usize, ) -> Option<Handler>45 pub unsafe fn find<F: Fn(&Frame) -> Option<(usize, usize)>>( 46 unwind: &dyn Unwind, 47 frame_handler: F, 48 exit_pc: usize, 49 exit_trampoline_frame: usize, 50 entry_frame: usize, 51 ) -> Option<Handler> { 52 // SAFETY: the safety of `visit_frames` relies on the correctness of the 53 // parameters passed in which is forwarded as a contract to this function 54 // tiself. 55 let result = unsafe { 56 crate::stackwalk::visit_frames( 57 unwind, 58 exit_pc, 59 exit_trampoline_frame, 60 entry_frame, 61 |frame| { 62 log::trace!("visit_frame: frame {frame:?}"); 63 if let Some((handler_pc, handler_sp)) = frame_handler(&frame) { 64 return ControlFlow::Break(Handler { 65 pc: handler_pc, 66 sp: handler_sp, 67 fp: frame.fp(), 68 }); 69 } 70 ControlFlow::Continue(()) 71 }, 72 ) 73 }; 74 match result { 75 ControlFlow::Break(handler) => Some(handler), 76 ControlFlow::Continue(()) => None, 77 } 78 } 79 } 80