sel4_panicking/
lib.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7#![no_std]
8#![feature(cfg_target_thread_local)]
9#![feature(core_intrinsics)]
10#![feature(lang_items)]
11#![feature(panic_can_unwind)]
12#![feature(thread_local)]
13#![allow(internal_features)]
14
15#[cfg(feature = "alloc")]
16extern crate alloc;
17
18use core::intrinsics::catch_unwind as catch_unwind_intrinsic;
19use core::mem::ManuallyDrop;
20use core::panic::{PanicInfo, UnwindSafe};
21
22use sel4_panicking_env::{abort, debug_println};
23
24mod count;
25mod hook;
26mod strategy;
27
28use count::{count_panic, count_panic_caught};
29use hook::get_hook;
30use strategy::{panic_cleanup, start_panic};
31
32pub use hook::{set_hook, PanicHook};
33
34#[panic_handler]
35fn panic(info: &PanicInfo) -> ! {
36    if let Some(must_abort) = count_panic() {
37        debug_println!("{}", info);
38        abort!("{}", must_abort);
39    }
40    (get_hook())(info);
41    if info.can_unwind() {
42        let code = start_panic();
43        abort!("failed to initiate panic, error {}", code)
44    } else {
45        abort!("can't unwind this panic")
46    }
47}
48
49/// Like `std::panic::catch_unwind`.
50#[allow(clippy::result_unit_err)]
51pub fn catch_unwind<R, F: FnOnce() -> R + UnwindSafe>(f: F) -> Result<R, ()> {
52    union Data<F, R> {
53        f: ManuallyDrop<F>,
54        r: ManuallyDrop<R>,
55    }
56
57    let mut data = Data {
58        f: ManuallyDrop::new(f),
59    };
60
61    let data_ptr = (&raw mut data) as *mut u8;
62    unsafe {
63        return if catch_unwind_intrinsic(do_call::<F, R>, data_ptr, do_catch) == 0 {
64            Ok(ManuallyDrop::into_inner(data.r))
65        } else {
66            Err(())
67        };
68    }
69
70    #[inline]
71    fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
72        unsafe {
73            let data = data as *mut Data<F, R>;
74            let data = &mut (*data);
75            let f = ManuallyDrop::take(&mut data.f);
76            data.r = ManuallyDrop::new(f());
77        }
78    }
79
80    #[inline]
81    fn do_catch(_data: *mut u8, exception: *mut u8) {
82        panic_cleanup(exception);
83        count_panic_caught();
84    }
85}
86
87/// Like `std::panic::abort_unwind`.
88pub fn abort_unwind<F, R>(f: F) -> R
89where
90    F: FnOnce() -> R,
91{
92    extern "C" fn wrap<F, R>(f: F) -> R
93    where
94        F: FnOnce() -> R,
95    {
96        f()
97    }
98
99    wrap(f)
100}