Browse Source

feat: add a custom hook interface for begin_panic (#1)

* feat: add a custom hook interface for begin_panic

* fix: fix cargo clippy for dragonos

---------

Signed-off-by: Godones <[email protected]> 
Co-authored-by: longjin <[email protected]>
LoGin 4 months ago
parent
commit
4eb845da62
4 changed files with 56 additions and 4 deletions
  1. 30 1
      src/panic.rs
  2. 6 2
      src/panicking.rs
  3. 1 0
      src/personality.rs
  4. 19 1
      src/unwinder/mod.rs

+ 30 - 1
src/panic.rs

@@ -1,6 +1,8 @@
 use alloc::boxed::Box;
 use core::any::Any;
+use core::marker::PhantomData;
 use core::mem::MaybeUninit;
+use core::ptr::null_mut;
 
 use crate::abi::*;
 #[cfg(feature = "panic-handler")]
@@ -60,7 +62,34 @@ unsafe impl Exception for RustPanic {
 }
 
 pub fn begin_panic(payload: Box<dyn Any + Send>) -> UnwindReasonCode {
-    crate::panicking::begin_panic(RustPanic(payload, DropGuard))
+    crate::panicking::begin_panic(RustPanic(payload, DropGuard), None, null_mut())
+}
+
+pub fn begin_panic_with_hook<T: UserUnwindTrace>(
+    payload: Box<dyn Any + Send>,
+    arg: *mut T::Arg,
+) -> UnwindReasonCode {
+    crate::panicking::begin_panic(
+        RustPanic(payload, DropGuard),
+        Some(DefaultUnwindTrace::<T>::user_unwind_trace),
+        arg as _,
+    )
+}
+
+pub trait UserUnwindTrace {
+    type Arg;
+    fn trace(ctx: &UnwindContext<'_>, arg: *mut Self::Arg) -> UnwindReasonCode;
+}
+
+struct DefaultUnwindTrace<T>(PhantomData<T>);
+
+impl<T: UserUnwindTrace> DefaultUnwindTrace<T> {
+    extern "C" fn user_unwind_trace(
+        ctx: &UnwindContext<'_>,
+        arg: *mut core::ffi::c_void,
+    ) -> UnwindReasonCode {
+        T::trace(ctx, arg as *mut T::Arg)
+    }
 }
 
 pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {

+ 6 - 2
src/panicking.rs

@@ -9,7 +9,11 @@ pub unsafe trait Exception {
     unsafe fn unwrap(ex: *mut UnwindException) -> Self;
 }
 
-pub fn begin_panic<E: Exception>(exception: E) -> UnwindReasonCode {
+pub fn begin_panic<E: Exception>(
+    exception: E,
+    trace: Option<UnwindTraceFn>,
+    trace_argument: *mut core::ffi::c_void,
+) -> UnwindReasonCode {
     unsafe extern "C" fn exception_cleanup<E: Exception>(
         _unwind_code: UnwindReasonCode,
         exception: *mut UnwindException,
@@ -21,7 +25,7 @@ pub fn begin_panic<E: Exception>(exception: E) -> UnwindReasonCode {
     unsafe {
         (*ex).exception_class = u64::from_ne_bytes(E::CLASS);
         (*ex).exception_cleanup = Some(exception_cleanup::<E>);
-        _Unwind_RaiseException(ex)
+        _Unwind_RaiseException(ex, trace, trace_argument)
     }
 }
 

+ 1 - 0
src/personality.rs

@@ -146,6 +146,7 @@ fn find_eh_action(
     Ok(EHAction::Terminate)
 }
 
+#[cfg(target_os = "none")]
 #[lang = "eh_personality"]
 unsafe fn rust_eh_personality(
     version: c_int,

+ 19 - 1
src/unwinder/mod.rs

@@ -4,6 +4,7 @@ mod frame;
 
 use core::ffi::c_void;
 use core::ptr;
+use core::ptr::null_mut;
 use gimli::Register;
 
 use crate::abi::*;
@@ -151,6 +152,8 @@ macro_rules! try2 {
 #[unsafe(no_mangle)]
 pub unsafe extern "C-unwind" fn _Unwind_RaiseException(
     exception: *mut UnwindException,
+    trace: Option<UnwindTraceFn>,
+    trace_argument: *mut core::ffi::c_void,
 ) -> UnwindReasonCode {
     with_context(|saved_ctx| {
         // Phase 1: Search for handler
@@ -158,6 +161,21 @@ pub unsafe extern "C-unwind" fn _Unwind_RaiseException(
         let mut signal = false;
         loop {
             if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) {
+                if let Some(trace) = trace {
+                    let code = trace(
+                        &UnwindContext {
+                            frame: Some(&frame),
+                            ctx: &mut ctx,
+                            signal,
+                        },
+                        trace_argument,
+                    );
+                    match code {
+                        UnwindReasonCode::NO_REASON => (),
+                        _ => return UnwindReasonCode::FATAL_PHASE1_ERROR,
+                    }
+                }
+
                 if let Some(personality) = frame.personality() {
                     let result = unsafe {
                         personality(
@@ -367,7 +385,7 @@ pub unsafe extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
     exception: *mut UnwindException,
 ) -> UnwindReasonCode {
     let stop = match unsafe { (*exception).private_1 } {
-        None => return unsafe { _Unwind_RaiseException(exception) },
+        None => return unsafe { _Unwind_RaiseException(exception, None, null_mut()) },
         Some(v) => v,
     };