Skip to content

Commit

Permalink
Trap handler changes to support s390x
Browse files Browse the repository at this point in the history
On s390x, SIGILL and SIGFPE are delivered with the PSW address
pointing *after* the faulting instruction, while SIGSEGV and
SIGBUS are delivered with the PSW address pointing *to* the
faulting instruction.  In order to support this, the common
code trap handler has to distinguish between those cases.

Also, enable SIGFPE on s390x (just like on x86).
  • Loading branch information
uweigand committed May 3, 2021
1 parent 92e0b6b commit d7402d8
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions crates/runtime/src/traphandlers/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ pub unsafe fn platform_init() {
// Handle `unreachable` instructions which execute `ud2` right now
register(&mut PREV_SIGILL, libc::SIGILL);

// x86 uses SIGFPE to report division by zero
if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") {
// x86 and s390x use SIGFPE to report division by zero
if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") || cfg!(target_arch = "s390x") {
register(&mut PREV_SIGFPE, libc::SIGFPE);
}

Expand Down Expand Up @@ -85,7 +85,7 @@ unsafe extern "C" fn trap_handler(
// Otherwise flag ourselves as handling a trap, do the trap
// handling, and reset our trap handling flag. Then we figure
// out what to do based on the result of the trap handling.
let pc = get_pc(context);
let pc = get_pc(context, signum);
let jmp_buf = info.jmp_buf_if_trap(pc, |handler| handler(signum, siginfo, context));

// Figure out what to do based on the result of this handling of
Expand Down Expand Up @@ -127,7 +127,7 @@ unsafe extern "C" fn trap_handler(
}
}

unsafe fn get_pc(cx: *mut libc::c_void) -> *const u8 {
unsafe fn get_pc(cx: *mut libc::c_void, _signum: libc::c_int) -> *const u8 {
cfg_if::cfg_if! {
if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
let cx = &*(cx as *const libc::ucontext_t);
Expand All @@ -138,6 +138,23 @@ unsafe fn get_pc(cx: *mut libc::c_void) -> *const u8 {
} else if #[cfg(all(any(target_os = "linux", target_os = "android"), target_arch = "aarch64"))] {
let cx = &*(cx as *const libc::ucontext_t);
cx.uc_mcontext.pc as *const u8
} else if #[cfg(all(target_os = "linux", target_arch = "s390x"))] {
// On s390x, SIGILL and SIGFPE are delivered with the PSW address
// pointing *after* the faulting instruction, while SIGSEGV and
// SIGBUS are delivered with the PSW address pointing *to* the
// faulting instruction. To handle this, the code generator registers
// any trap that results in one of "late" signals on the last byte
// of the instruction, and any trap that results in one of the "early"
// signals on the first byte of the instruction (as usual). This
// means we simply need to decrement the reported PSW address by
// one in the case of a "late" signal here to ensure we always
// correctly find the associated trap handler.
let trap_offset = match _signum {
libc::SIGILL | libc::SIGFPE => 1,
_ => 0,
};
let cx = &*(cx as *const libc::ucontext_t);
(cx.uc_mcontext.psw.addr - trap_offset) as *const u8
} else if #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))] {
let cx = &*(cx as *const libc::ucontext_t);
cx.uc_mcontext.mc_rip as *const u8
Expand Down

0 comments on commit d7402d8

Please sign in to comment.