Panic utilities

This commit is contained in:
Gary Guo 2021-08-26 10:51:55 +01:00
parent 487ca98456
commit af031eb4b1
4 changed files with 108 additions and 5 deletions

View File

@ -21,6 +21,7 @@ hide-trace = []
personality = [] personality = []
personality-dummy = [] personality-dummy = []
print = ["libc"] print = ["libc"]
panic = ["alloc"]
system-alloc = [] system-alloc = []
default = ["dwarf-expr", "hide-trace", "fde-phdr", "fde-registry"] default = ["dwarf-expr", "hide-trace", "fde-phdr", "fde-registry"]

View File

@ -10,7 +10,7 @@ use crate::util::*;
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub struct UnwindReasonCode(c_int); pub struct UnwindReasonCode(pub c_int);
#[allow(unused)] #[allow(unused)]
impl UnwindReasonCode { impl UnwindReasonCode {
@ -27,7 +27,7 @@ impl UnwindReasonCode {
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub struct UnwindAction(c_int); pub struct UnwindAction(pub c_int);
impl UnwindAction { impl UnwindAction {
pub const SEARCH_PHASE: Self = Self(1); pub const SEARCH_PHASE: Self = Self(1);
@ -78,6 +78,19 @@ pub struct UnwindException {
private_unused: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE - 2], private_unused: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE - 2],
} }
impl UnwindException {
#[inline]
pub fn new() -> UnwindException {
UnwindException {
exception_class: 0,
exception_cleanup: None,
private_1: None,
private_2: 0,
private_unused: [0; Arch::UNWIND_PRIVATE_DATA_SIZE - 2],
}
}
}
pub type UnwindTraceFn = pub type UnwindTraceFn =
unsafe extern "C" fn(ctx: &mut UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode; unsafe extern "C" fn(ctx: &mut UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode;

View File

@ -5,6 +5,7 @@
any(feature = "personality", feature = "personality-dummy"), any(feature = "personality", feature = "personality-dummy"),
feature(lang_items) feature(lang_items)
)] )]
#![cfg_attr(feature = "panic", feature(core_intrinsics))]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
#![warn(unsafe_op_in_unsafe_fn)] #![warn(unsafe_op_in_unsafe_fn)]
#![no_std] #![no_std]
@ -12,7 +13,8 @@
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;
mod abi; pub mod abi;
mod arch; mod arch;
mod find_fde; mod find_fde;
mod frame; mod frame;
@ -26,7 +28,8 @@ mod personality;
#[cfg(feature = "personality-dummy")] #[cfg(feature = "personality-dummy")]
mod personality_dummy; mod personality_dummy;
#[cfg(feature = "panic")]
pub mod panic;
#[cfg(feature = "system-alloc")] #[cfg(feature = "system-alloc")]
mod system_alloc; mod system_alloc;
pub use abi::*;

86
src/panic.rs Normal file
View File

@ -0,0 +1,86 @@
use alloc::boxed::Box;
use core::any::Any;
use core::mem::ManuallyDrop;
use crate::abi::*;
#[repr(C)]
struct Exception {
exception: UnwindException,
payload: Box<dyn Any + Send>,
}
const RUST_EXCEPTION_CLASS: u64 = u64::from_be_bytes(*b"MOZ\0RUST");
pub fn begin_panic(payload: Box<dyn Any + Send>) -> UnwindReasonCode {
unsafe extern "C" fn exception_cleanup(
_unwind_code: UnwindReasonCode,
exception: *mut UnwindException,
) {
unsafe {
let _ = Box::from_raw(exception as *mut Exception);
}
core::intrinsics::abort();
}
let mut unwind_ex = UnwindException::new();
unwind_ex.exception_class = RUST_EXCEPTION_CLASS;
unwind_ex.exception_cleanup = Some(exception_cleanup);
let exception = Box::new(Exception {
exception: unwind_ex,
payload,
});
_Unwind_RaiseException(unsafe { &mut *(Box::into_raw(exception) as *mut UnwindException) })
}
#[cold]
unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
let exception = payload as *mut UnwindException;
if unsafe { (*exception).exception_class } != RUST_EXCEPTION_CLASS {
unsafe { _Unwind_DeleteException(exception) };
core::intrinsics::abort();
}
let unwind_ex = unsafe { Box::from_raw(exception as *mut Exception) };
unwind_ex.payload
}
pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
union Data<F, R> {
f: ManuallyDrop<F>,
r: ManuallyDrop<R>,
p: ManuallyDrop<Box<dyn Any + Send>>,
}
let mut data = Data {
f: ManuallyDrop::new(f),
};
let data_ptr = &mut data as *mut _ as *mut u8;
unsafe {
return if core::intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
Ok(ManuallyDrop::into_inner(data.r))
} else {
Err(ManuallyDrop::into_inner(data.p))
};
}
#[inline]
fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
unsafe {
let data = data as *mut Data<F, R>;
let data = &mut (*data);
let f = ManuallyDrop::take(&mut data.f);
data.r = ManuallyDrop::new(f());
}
}
#[inline]
fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
unsafe {
let data = data as *mut Data<F, R>;
let data = &mut (*data);
let obj = cleanup(payload);
data.p = ManuallyDrop::new(obj);
}
}
}