Skip to content

Commit

Permalink
Trap handler changes to support s390x (#2871)
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 authored May 3, 2021
1 parent e1cc1a6 commit dfb1bc4
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 dfb1bc4

Please sign in to comment.