-
Notifications
You must be signed in to change notification settings - Fork 16
/
panic_handler.rs
103 lines (89 loc) · 2.57 KB
/
panic_handler.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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<usize> = Cell::new(0);
#[link(name = "c")]
unsafe 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 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: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode {
let data = unsafe { &mut *(arg as *mut CallbackData) };
data.counter += 1;
eprintln!(
"{:4}:{:#19x} - <unknown>",
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<dyn Any + Send>) -> ! {
if PANIC_COUNT.get() >= 1 {
stack_trace();
eprintln!("thread panicked while processing panic. aborting.");
crate::util::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);
crate::util::abort();
}
#[panic_handler]
fn panic(info: &PanicInfo<'_>) -> ! {
eprintln!("{}", info);
struct NoPayload;
do_panic(Box::new(NoPayload))
}
#[track_caller]
pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
eprintln!("panicked at {}", Location::caller());
do_panic(Box::new(msg))
}