#![doc = include_str!("../README.md")]
#![allow(unsafe_code)]
mod error;
pub use error::Error;
#[cfg(feature = "debug-print")]
#[macro_export]
macro_rules! debug_print {
($s:literal) => {
let cstr = concat!(file!(), ":", line!(), " ", $s, "\n");
$crate::write_stderr(cstr);
};
}
#[cfg(not(feature = "debug-print"))]
#[macro_export]
macro_rules! debug_print {
($s:literal) => {};
}
#[inline]
pub fn write_stderr(s: &'static str) {
unsafe {
#[cfg(target_os = "windows")]
libc::write(2, s.as_ptr().cast(), s.len() as u32);
#[cfg(not(target_os = "windows"))]
libc::write(2, s.as_ptr().cast(), s.len());
}
}
cfg_if::cfg_if! {
if #[cfg(all(unix, not(target_os = "macos")))] {
pub mod unix;
}
}
pub use crash_context::CrashContext;
pub enum CrashEventResult {
Handled(bool),
#[cfg(any(
target_os = "linux",
target_os = "android",
all(target_os = "windows", target_arch = "x86_64"),
))]
Jump {
jmp_buf: *mut jmp::JmpBuf,
value: i32,
},
}
impl From<bool> for CrashEventResult {
fn from(b: bool) -> Self {
Self::Handled(b)
}
}
pub unsafe trait CrashEvent: Send + Sync {
fn on_crash(&self, context: &CrashContext) -> CrashEventResult;
}
#[inline]
pub unsafe fn make_crash_event<F>(closure: F) -> Box<dyn CrashEvent>
where
F: Send + Sync + Fn(&CrashContext) -> CrashEventResult + 'static,
{
struct Wrapper<F> {
inner: F,
}
unsafe impl<F> CrashEvent for Wrapper<F>
where
F: Send + Sync + Fn(&CrashContext) -> CrashEventResult,
{
fn on_crash(&self, context: &CrashContext) -> CrashEventResult {
(self.inner)(context)
}
}
Box::new(Wrapper { inner: closure })
}
#[inline]
pub unsafe fn make_single_crash_event<F>(closure: F) -> Box<dyn CrashEvent>
where
F: Send + Sync + FnOnce(&CrashContext) -> CrashEventResult + 'static,
{
struct Wrapper<F> {
inner: parking_lot::Mutex<Option<F>>,
}
unsafe impl<F> CrashEvent for Wrapper<F>
where
F: Send + Sync + FnOnce(&CrashContext) -> CrashEventResult,
{
fn on_crash(&self, context: &CrashContext) -> CrashEventResult {
if let Some(inner) = self.inner.lock().take() {
(inner)(context)
} else {
false.into()
}
}
}
Box::new(Wrapper {
inner: parking_lot::Mutex::new(Some(closure)),
})
}
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
mod linux;
pub use linux::{CrashHandler, Signal, jmp};
} else if #[cfg(target_os = "windows")] {
mod windows;
#[cfg(target_arch = "x86_64")]
pub use windows::jmp;
pub use windows::{CrashHandler, ExceptionCode};
} else if #[cfg(target_os = "macos")] {
mod mac;
pub use mac::{CrashHandler, ExceptionType};
}
}