diff --git a/example/src/main.rs b/example/src/main.rs index 77cbb4b..0683dd4 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -36,16 +36,20 @@ fn bar() { foo() } +fn main() { + let _ = unwind::panic::catch_unwind(|| { + bar(); + println!("done"); + }); + println!("caught"); + let _p = PanicOnDrop; + foo(); +} + #[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +fn start(_argc: isize, _argv: *const *const u8) -> isize { unwind::panic::catch_unwind(|| { - let _ = unwind::panic::catch_unwind(|| { - bar(); - println!("done"); - }); - println!("caught"); - let _p = PanicOnDrop; - foo(); + main(); 0 }) .unwrap_or(101) diff --git a/src/panic_handler.rs b/src/panic_handler.rs index 3913668..a7dbcd1 100644 --- a/src/panic_handler.rs +++ b/src/panic_handler.rs @@ -1,8 +1,11 @@ +use crate::abi::*; use crate::print::*; use alloc::boxed::Box; use core::any::Any; use core::cell::Cell; +use core::ffi::c_void; use core::panic::{Location, PanicInfo}; +use core::sync::atomic::{AtomicI32, Ordering}; #[thread_local] static PANIC_COUNT: Cell = Cell::new(0); @@ -22,12 +25,63 @@ pub(crate) fn panic_caught() { PANIC_COUNT.set(0); } +fn check_env() -> bool { + static ENV: AtomicI32 = AtomicI32::new(-1); + + let env = ENV.load(Ordering::Relaxed); + if env != -1 { + return env != 0; + } + + let val = unsafe { + let ptr = libc::getenv(b"RUST_BACKTRACE\0".as_ptr() as _); + if ptr.is_null() { + b"" + } else { + let len = libc::strlen(ptr); + core::slice::from_raw_parts(ptr as *const u8, len) + } + }; + let (note, env) = match val { + b"" => (true, false), + b"1" | b"full" => (false, true), + _ => (false, false), + }; + + // Issue a note for the first panic. + if ENV.swap(env as _, Ordering::Relaxed) == -1 && note { + eprintln!("note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace"); + } + env +} + +fn stack_trace() { + struct CallbackData { + counter: usize, + } + extern "C" fn callback( + unwind_ctx: &mut UnwindContext<'_>, + arg: *mut c_void, + ) -> UnwindReasonCode { + let data = unsafe { &mut *(arg as *mut CallbackData) }; + data.counter += 1; + eprintln!("{:4}:{:#19x} - ", data.counter, _Unwind_GetIP(unwind_ctx)); + UnwindReasonCode::NO_REASON + } + let mut data = CallbackData { counter: 0 }; + _Unwind_Backtrace(callback, &mut data as *mut _ as _); +} + fn do_panic(msg: Box) -> ! { if PANIC_COUNT.get() >= 1 { + stack_trace(); eprintln!("thread panicked while processing panic. aborting."); core::intrinsics::abort(); } PANIC_COUNT.set(1); + if check_env() { + stack_trace(); + } let code = crate::panic::begin_panic(Box::new(msg)); eprintln!("failed to initiate panic, error {}", code.0); core::intrinsics::abort();