diff --git a/Cargo.toml b/Cargo.toml index 8d4a937..d1e873e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ personality = [] personality-dummy = [] print = ["libc"] panic = ["alloc"] +panic-handler = ["print", "panic"] system-alloc = [] default = ["dwarf-expr", "hide-trace", "fde-phdr", "fde-registry"] diff --git a/src/lib.rs b/src/lib.rs index 74476dc..1e2e323 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ feature(lang_items) )] #![cfg_attr(feature = "panic", feature(core_intrinsics))] +#![cfg_attr(feature = "panic-handler", feature(thread_local))] #![warn(rust_2018_idioms)] #![warn(unsafe_op_in_unsafe_fn)] #![no_std] @@ -31,5 +32,8 @@ mod personality_dummy; #[cfg(feature = "panic")] pub mod panic; +#[cfg(feature = "panic-handler")] +pub mod panic_handler; + #[cfg(feature = "system-alloc")] mod system_alloc; diff --git a/src/panic.rs b/src/panic.rs index c441254..039c0b1 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -3,6 +3,8 @@ use core::any::Any; use core::mem::ManuallyDrop; use crate::abi::*; +#[cfg(feature = "panic-handler")] +pub use crate::panic_handler::*; #[repr(C)] struct Exception { @@ -20,7 +22,14 @@ pub fn begin_panic(payload: Box) -> UnwindReasonCode { unsafe { let _ = Box::from_raw(exception as *mut Exception); } - core::intrinsics::abort(); + #[cfg(feature = "panic-handler")] + { + drop_panic(); + } + #[cfg(not(feature = "panic-handler"))] + { + core::intrinsics::abort(); + } } let mut unwind_ex = UnwindException::new(); @@ -38,7 +47,18 @@ unsafe fn cleanup(payload: *mut u8) -> Box { let exception = payload as *mut UnwindException; if unsafe { (*exception).exception_class } != RUST_EXCEPTION_CLASS { unsafe { _Unwind_DeleteException(exception) }; - core::intrinsics::abort(); + #[cfg(feature = "panic-handler")] + { + foreign_exception(); + } + #[cfg(not(feature = "panic-handler"))] + { + core::intrinsics::abort(); + } + } + #[cfg(feature = "panic-handler")] + { + panic_caught(); } let unwind_ex = unsafe { Box::from_raw(exception as *mut Exception) }; unwind_ex.payload diff --git a/src/panic_handler.rs b/src/panic_handler.rs new file mode 100644 index 0000000..3913668 --- /dev/null +++ b/src/panic_handler.rs @@ -0,0 +1,48 @@ +use crate::print::*; +use alloc::boxed::Box; +use core::any::Any; +use core::cell::Cell; +use core::panic::{Location, PanicInfo}; + +#[thread_local] +static PANIC_COUNT: Cell = Cell::new(0); + +#[link(name = "c")] +extern "C" {} + +pub(crate) fn drop_panic() { + eprintln!("Rust panics must be rethrown"); +} + +pub(crate) fn foreign_exception() { + eprintln!("Rust cannot catch foreign exceptions"); +} + +pub(crate) fn panic_caught() { + PANIC_COUNT.set(0); +} + +fn do_panic(msg: Box) -> ! { + if PANIC_COUNT.get() >= 1 { + eprintln!("thread panicked while processing panic. aborting."); + core::intrinsics::abort(); + } + PANIC_COUNT.set(1); + let code = crate::panic::begin_panic(Box::new(msg)); + eprintln!("failed to initiate panic, error {}", code.0); + core::intrinsics::abort(); +} + +#[panic_handler] +fn panic(info: &PanicInfo<'_>) -> ! { + eprintln!("{}", info); + + struct NoPayload; + do_panic(Box::new(NoPayload)) +} + +#[track_caller] +pub fn panic_any(msg: M) -> ! { + eprintln!("panicked at {}", Location::caller()); + do_panic(Box::new(msg)) +}