2019-03-02 17:00:05 -08:00
|
|
|
use libc::{c_void, siginfo_t};
|
|
|
|
use nix::sys::signal::{
|
|
|
|
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
|
|
|
|
};
|
|
|
|
|
2019-03-02 10:56:02 -08:00
|
|
|
/// `__register_frame` and `__deregister_frame` on macos take a single fde as an
|
|
|
|
/// argument, so we need to parse the fde table here.
|
|
|
|
///
|
|
|
|
/// This is a pretty direct port of llvm's fde handling code:
|
|
|
|
/// https://llvm.org/doxygen/RTDyldMemoryManager_8cpp_source.html.
|
2019-03-03 15:34:20 -06:00
|
|
|
#[allow(clippy::cast_ptr_alignment)]
|
2019-03-02 10:56:02 -08:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) {
|
|
|
|
unsafe fn process_fde(entry: *mut u8, visitor: extern "C" fn(*mut u8)) -> *mut u8 {
|
|
|
|
let mut p = entry;
|
|
|
|
let length = (p as *const u32).read_unaligned();
|
|
|
|
p = p.add(4);
|
|
|
|
let offset = (p as *const u32).read_unaligned();
|
|
|
|
|
|
|
|
if offset != 0 {
|
|
|
|
visitor(entry);
|
|
|
|
}
|
|
|
|
p.add(length as usize)
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut p = addr;
|
|
|
|
let end = p.add(size);
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if p >= end {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = process_fde(p, visitor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) {
|
|
|
|
visitor(addr);
|
|
|
|
}
|
2019-03-02 17:00:05 -08:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
fn throw_trap(ty: i32) -> !;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn install_signal_handler() {
|
|
|
|
let sa = SigAction::new(
|
|
|
|
SigHandler::SigAction(signal_trap_handler),
|
2019-03-02 19:08:15 -08:00
|
|
|
SaFlags::SA_ONSTACK | SaFlags::SA_SIGINFO,
|
2019-03-02 17:00:05 -08:00
|
|
|
SigSet::empty(),
|
|
|
|
);
|
|
|
|
sigaction(SIGFPE, &sa).unwrap();
|
|
|
|
sigaction(SIGILL, &sa).unwrap();
|
|
|
|
sigaction(SIGSEGV, &sa).unwrap();
|
|
|
|
sigaction(SIGBUS, &sa).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" fn signal_trap_handler(
|
|
|
|
signum: ::nix::libc::c_int,
|
|
|
|
siginfo: *mut siginfo_t,
|
|
|
|
ucontext: *mut c_void,
|
|
|
|
) {
|
|
|
|
unsafe {
|
2019-03-03 02:15:53 -08:00
|
|
|
/// Apparently, we can unwind from arbitary instructions, as long
|
|
|
|
/// as we don't need to catch the exception inside the function that
|
|
|
|
/// was interrupted.
|
|
|
|
///
|
|
|
|
/// This works on macos, not sure about linux.
|
|
|
|
throw_trap(2);
|
2019-03-02 17:00:05 -08:00
|
|
|
}
|
|
|
|
}
|