use core::ffi::c_void;
use core::ops::{BitAnd, BitOr};
use yaxpeax_x86;
use yaxpeax_x86::long_mode::{RegSpec, Operand, Instruction, register_class};
use yaxpeax_arch::{AddressBase, Decoder, LengthedInstruction};
#[repr(C)]
struct stack_t {
ss_sp: *const c_void,
ss_flags: i32,
ss_size: usize,
}
#[repr(C)]
struct ucontext {
uc_flags: u32,
uc_link: *const ucontext,
uc_stack: stack_t,
uc_mcontext: sigcontext,
}
#[repr(C)]
struct _fpstate {
cwd: u16,
swd: u16,
ftw: u16,
fop: u16,
rip: u64,
rdp: u64,
mxcsr: u32,
mxcr_mask: u32,
_st: [_fpxreg; 8],
_xmm: [_xmmreg; 16],
}
#[repr(C)]
struct _fpxreg {
items: [u16; 8]
}
#[repr(C)]
struct _xmmreg {
element: [u32; 4]
}
#[repr(C)]
struct sigcontext {
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
rdi: u64,
rsi: u64,
rbp: u64,
rbx: u64,
rdx: u64,
rax: u64,
rcx: u64,
rsp: u64,
rip: u64,
eflags: u64,
cs: u16,
gs: u16,
fs: u16,
__pad0: u16,
err: u64,
trapno: u64,
oldmask: u64,
cr2: u64,
fpstate: *const _fpstate,
}
#[repr(C)]
struct sigfault_t {
_addr: *const c_void,
_trapno: i32,
}
#[repr(C)]
struct siginfo_sigfault_t {
si_signo: i32,
si_errno: i32,
si_code: i32,
_sifields: sigfault_t,
}
#[derive(Copy, Clone)]
pub struct RegU64(u64);
impl RegU64 {
const fn new(addr: u64) -> Self {
RegU64(addr)
}
#[inline(always)]
pub fn load(&self) -> u64 {
unsafe {
core::ptr::read(self.0 as *const u64)
}
}
#[inline(always)]
pub fn store(&self, v: u64) {
unsafe {
core::ptr::write(self.0 as *mut u64, v)
}
}
#[inline(always)]
pub fn add(&self, other: u64) -> u64 {
u64::wrapping_add(self.load(), other)
}
#[inline(always)]
pub fn sub(&self, other: u64) -> u64 {
u64::wrapping_sub(self.load(), other)
}
#[inline(always)]
pub fn add_assign(&self, other: u64) {
self.store(self.add(other));
}
#[inline(always)]
pub fn sub_assign(&self, other: u64) {
self.store(self.sub(other));
}
#[inline(always)]
pub fn bitand(&self, other: u64) -> u64 {
self.load() & other
}
#[inline(always)]
pub fn bitor(&self, other: u64) -> u64 {
self.load() | other
}
#[inline(always)]
pub fn bitxor(&self, other: u64) -> u64 {
self.load() ^ other
}
#[inline(always)]
pub fn bitand_assign(&self, other: u64) {
self.store(self.bitand(other))
}
#[inline(always)]
pub fn bitor_assign(&self, other: u64) {
self.store(self.bitor(other))
}
#[inline(always)]
pub fn bitxor_assign(&self, other: u64) {
self.store(self.bitxor(other))
}
}
trait UcontextExt {
fn read_reg(&self, reg: RegSpec) -> u64;
fn write_reg(&mut self, reg: RegSpec, value: u64);
fn do_binop<F: FnOnce(&ucontext, u64, u64) -> (u64, u64)>(&mut self, instr: &Instruction, addr: u64, f: F);
}
impl UcontextExt for ucontext {
fn read_reg(&self, reg: RegSpec) -> u64 {
if reg == RegSpec::RIP {
self.uc_mcontext.rip
} else if reg.class() == register_class::RFLAGS {
self.uc_mcontext.eflags
} else if reg.class() == register_class::Q {
match reg.num() {
0 => self.uc_mcontext.rax,
1 => self.uc_mcontext.rcx,
2 => self.uc_mcontext.rdx,
3 => self.uc_mcontext.rbx,
4 => self.uc_mcontext.rsp,
5 => self.uc_mcontext.rbp,
6 => self.uc_mcontext.rsi,
7 => self.uc_mcontext.rdi,
8 => self.uc_mcontext.r8,
9 => self.uc_mcontext.r9,
10 => self.uc_mcontext.r10,
11 => self.uc_mcontext.r11,
12 => self.uc_mcontext.r12,
13 => self.uc_mcontext.r13,
14 => self.uc_mcontext.r14,
15 => self.uc_mcontext.r15,
_ => { unreachable!("sins"); }
}
} else {
panic!("crimes");
}
}
fn write_reg(&mut self, reg: RegSpec, value: u64) {
if reg == RegSpec::RIP {
self.uc_mcontext.rip = value;
} else if reg.class() == register_class::RFLAGS {
self.uc_mcontext.eflags = value;
} else if reg.class() == register_class::Q {
match reg.num() {
0 => { self.uc_mcontext.rax = value; },
1 => { self.uc_mcontext.rcx = value; },
2 => { self.uc_mcontext.rdx = value; },
3 => { self.uc_mcontext.rbx = value; },
4 => { self.uc_mcontext.rsp = value; },
5 => { self.uc_mcontext.rbp = value; },
6 => { self.uc_mcontext.rsi = value; },
7 => { self.uc_mcontext.rdi = value; },
8 => { self.uc_mcontext.r8 = value; },
9 => { self.uc_mcontext.r9 = value; },
10 => { self.uc_mcontext.r10 = value; },
11 => { self.uc_mcontext.r11 = value; },
12 => { self.uc_mcontext.r12 = value; },
13 => { self.uc_mcontext.r13 = value; },
14 => { self.uc_mcontext.r14 = value; },
15 => { self.uc_mcontext.r15 = value; },
_ => { unreachable!("sins"); }
}
} else {
panic!("crimes");
}
}
fn do_binop<F: FnOnce(&ucontext, u64, u64) -> (u64, u64)>(&mut self, instr: &Instruction, addr: u64, f: F) {
let lreg = match instr.operand(0) {
Operand::Register(l) => l,
_ => reg_for(addr),
};
let l = self.read_reg(lreg);
let (_rreg, r) = match instr.operand(1) {
Operand::ImmediateU64(u) => (None, u),
Operand::ImmediateI64(u) => (None, u as u64),
Operand::ImmediateU32(u) => (None, u as u64),
Operand::ImmediateI32(u) => (None, u as i64 as u64),
Operand::ImmediateU16(u) => (None, u as u64),
Operand::ImmediateI16(u) => (None, u as i64 as u64),
Operand::ImmediateU8(u) => (None, u as u64),
Operand::ImmediateI8(u) => (None, u as i64 as u64),
Operand::Register(r) => {
(Some(r), self.read_reg(r))
}
_ => {
let r = reg_for(addr);
(Some(r), self.read_reg(r))
}
};
let (flags, v) = f(self, l, r);
self.write_reg(lreg, v);
self.write_reg(RegSpec::rflags(), flags);
}
}
fn reg_for(offset: u64) -> RegSpec {
if offset == 128 {
RegSpec::rip()
} else if offset == 136 {
RegSpec::rflags()
} else {
RegSpec::q((offset / 8) as u8)
}
}
const CF: u64 = 0x0001;
const PF: u64 = 0x0004;
const AF: u64 = 0x0010;
const ZF: u64 = 0x0040;
const SF: u64 = 0x0080;
const OF: u64 = 0x0800;
const BITWISE_FLAGS: u64 = CF | PF | ZF | SF | OF;
const ARITHMETIC_FLAGS: u64 = AF | BITWISE_FLAGS;
const BITWISE_MASK: u64 = !BITWISE_FLAGS;
const ARITHMETIC_MASK: u64 = !ARITHMETIC_FLAGS;
fn do_arithmetic_flags(x: u64, y: u64, f: fn(u64, u64) -> (u64, bool)) -> (u64, u64) {
let (v, of) = f(x, y);
let mut flags = 0u64;
let pf = (v as u8).count_ones();
if pf % 2 == 0 {
flags |= PF;
}
if v > 0x8000_0000_0000_0000 {
flags |= SF;
}
if v == 0 {
flags |= ZF;
}
if of {
flags |= CF;
}
let (xs, ys, vs) = (
x & 0x8000_0000_0000_0000 != 0,
y & 0x8000_0000_0000_0000 != 0,
x & 0x8000_0000_0000_0000 != 0,
);
if xs == ys && xs != vs {
flags |= OF;
}
if f(x & 0b1111, y & 0b1111).0 >= 0b1_0000 {
flags |= AF;
}
(v, flags)
}
fn do_arithmetic_flags_with_carry(x: u64, y: u64, f: fn(u64, u64) -> (u64, bool), carry: bool) -> (u64, u64) {
let c = if carry { 1 } else { 0 };
let (v, of1) = f(x, y);
let (v, of2) = f(v, c);
let of = of1 || of2;
let mut flags = 0u64;
let pf = (v as u8).count_ones();
if pf % 2 == 0 {
flags |= PF;
}
if v > 0x8000_0000_0000_0000 {
flags |= SF;
}
if v == 0 {
flags |= ZF;
}
if of {
flags |= CF;
}
let (xs, ys, vs) = (
x & 0x8000_0000_0000_0000 != 0,
y & 0x8000_0000_0000_0000 != 0,
x & 0x8000_0000_0000_0000 != 0,
);
if xs == ys && xs != vs {
flags |= OF;
}
if f(f(x & 0b1111, y & 0b1111).0, c).0 >= 0b1_0000 {
flags |= AF;
}
(v, flags)
}
fn do_bitwise_flags(x: u64, y: u64, f: fn(u64, u64) -> u64) -> (u64, u64) {
let v = f(x, y);
let mut flags = 0u64;
let pf = (v as u8).count_ones();
if pf % 2 == 0 {
flags |= PF;
}
if v > 0x8000_0000_0000_0000 {
flags |= SF;
}
if v == 0 {
flags |= ZF;
}
(v, flags)
}
extern "C" fn of_impl(_signum: i32, siginfo_ptr: *mut siginfo_sigfault_t, ucontext_ptr: *mut c_void) {
let siginfo_ptr = siginfo_ptr as *mut siginfo_sigfault_t;
let ucontext_ptr = ucontext_ptr as *mut ucontext;
let ucontext = unsafe { ucontext_ptr.as_mut().expect("ucontext is set") } ;
let fault_rip = ucontext.uc_mcontext.rip;
let addr = unsafe { siginfo_ptr.as_mut().expect("siginfo valid")._sifields._addr } as usize as u64;
let rip_slice = unsafe { core::slice::from_raw_parts(fault_rip as *const u8, 16) };
let instr = yaxpeax_x86::long_mode::InstDecoder::default().decode(rip_slice.iter().cloned()).unwrap();
ucontext.uc_mcontext.rip = ucontext.uc_mcontext.rip.wrapping_add((0 + instr.len()).to_linear() as u64);
use yaxpeax_x86::long_mode::Opcode;
if instr.operand_count() == 0 {
return;
};
match instr.opcode() {
Opcode::MOV => {
ucontext.do_binop(&instr, addr, |ctx, _x, y| {
(ctx.read_reg(RegSpec::rflags()), y)
});
}
Opcode::ADD => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (v, flags) = do_arithmetic_flags(x, y, u64::overflowing_add);
(((ctx.read_reg(RegSpec::rflags()) & ARITHMETIC_MASK) | flags), v)
});
}
Opcode::SUB => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (v, flags) = do_arithmetic_flags(x, y, u64::overflowing_sub);
(((ctx.read_reg(RegSpec::rflags()) & ARITHMETIC_MASK) | flags), v)
});
}
Opcode::ADC => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (v, flags) = do_arithmetic_flags_with_carry(x, y, u64::overflowing_add, (ctx.read_reg(RegSpec::rflags()) & CF) != 0);
(((ctx.read_reg(RegSpec::rflags()) & ARITHMETIC_MASK) | flags), v)
});
}
Opcode::SBB => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (v, flags) = do_arithmetic_flags_with_carry(x, y, u64::overflowing_sub, (ctx.read_reg(RegSpec::rflags()) & CF) != 0);
(((ctx.read_reg(RegSpec::rflags()) & ARITHMETIC_MASK) | flags), v)
});
}
Opcode::OR => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (v, flags) = do_bitwise_flags(x, y, BitOr::bitor);
(((ctx.read_reg(RegSpec::rflags()) & BITWISE_MASK) | flags), v)
});
}
Opcode::AND => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (v, flags) = do_bitwise_flags(x, y, BitOr::bitor);
(((ctx.read_reg(RegSpec::rflags()) & BITWISE_MASK) | flags), v)
});
}
Opcode::CMP => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (_v, flags) = do_arithmetic_flags(x, y, u64::overflowing_sub);
(((ctx.read_reg(RegSpec::rflags()) & ARITHMETIC_MASK) | flags), x)
});
}
Opcode::TEST => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let (_v, flags) = do_bitwise_flags(x, y, BitAnd::bitand);
(((ctx.read_reg(RegSpec::rflags()) & BITWISE_MASK) | flags), x)
});
}
Opcode::NOT => {
let lreg = match instr.operand(0) {
Operand::Register(l) => l,
_ => reg_for(addr),
};
let l = ucontext.read_reg(lreg);
let l = !l;
ucontext.write_reg(lreg, l);
}
Opcode::MOVSX_b => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let l = x & 0xffff_ffff_ffff_0000;
let r = (y & 0xff) as i8 as i16 as u64;
(ctx.read_reg(RegSpec::rflags()), l | r)
});
}
Opcode::MOVSX_w => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let l = x & 0xffff_ffff_0000_0000;
let r = (y & 0xffff) as i16 as i32 as u64;
(ctx.read_reg(RegSpec::rflags()), l | r)
});
}
Opcode::MOVZX_b => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let l = x & 0xffff_ffff_ffff_0000;
let r = y & 0xff;
(ctx.read_reg(RegSpec::rflags()), l | r)
});
}
Opcode::MOVZX_w => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let l = x & 0xffff_ffff_0000_0000;
let r = y & 0xffff;
(ctx.read_reg(RegSpec::rflags()), l | r)
});
}
Opcode::JMP => {
let lreg = match instr.operand(0) {
Operand::ImmediateI8(i) => {
let rip = ucontext.read_reg(RegSpec::rip()).wrapping_add(i as u64);
ucontext.write_reg(RegSpec::rip(), rip);
return;
}
Operand::ImmediateI32(i) => {
let rip = ucontext.read_reg(RegSpec::rip()).wrapping_add(i as u64);
ucontext.write_reg(RegSpec::rip(), rip);
return;
}
Operand::Register(l) => l,
_ => reg_for(addr),
};
let l = ucontext.read_reg(lreg);
ucontext.write_reg(RegSpec::rip(), l);
}
Opcode::CALL => {
let mut rsp = ucontext.read_reg(RegSpec::rsp());
rsp -= 8;
unsafe { *(rsp as *mut u64) = ucontext.read_reg(RegSpec::rip()) };
ucontext.write_reg(RegSpec::rsp(), rsp);
let lreg = match instr.operand(0) {
Operand::ImmediateI32(i) => {
let rip = ucontext.read_reg(RegSpec::rip()).wrapping_add(i as u64);
ucontext.write_reg(RegSpec::rip(), rip);
return;
}
Operand::Register(l) => l,
_ => reg_for(addr),
};
let l = ucontext.read_reg(lreg);
ucontext.write_reg(RegSpec::rip(), l);
}
Opcode::RETURN => {
let mut rsp = ucontext.read_reg(RegSpec::rsp());
let ra = unsafe { *(rsp as *const u64) };
rsp += 8;
ucontext.write_reg(RegSpec::rsp(), rsp);
ucontext.write_reg(RegSpec::rip(), ra);
}
Opcode::CMOVA => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::above(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVB => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::below(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVG => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::greater(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVGE => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::greater_equal(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVL => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::greater_equal(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVLE => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::greater(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVNA => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::above(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVNB => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::below(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVNO => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::overflow(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVNP => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::parity(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVNS => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::signed(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVNZ => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if !predicate::zero(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVO => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::overflow(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVP => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::parity(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVS => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::signed(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
Opcode::CMOVZ => {
ucontext.do_binop(&instr, addr, |ctx, x, y| {
let rflags = ctx.read_reg(RegSpec::rflags());
if predicate::zero(rflags) {
(ctx.read_reg(RegSpec::rflags()), y)
} else {
(ctx.read_reg(RegSpec::rflags()), x)
}
});
}
_ => {
panic!("unhandled instruction: {}", instr);
}
}
}
mod predicate {
pub(crate) fn above(flags: u64) -> bool {
flags & (crate::of::CF | crate::of::ZF) == 0
}
pub(crate) fn below(flags: u64) -> bool {
flags & crate::of::CF != 0
}
pub(crate) fn greater(flags: u64) -> bool {
let bits = flags & (crate::of::SF | crate::of::OF);
bits & crate::of::ZF == 0 && (bits == 0 || bits == crate::of::SF | crate::of::OF)
}
pub(crate) fn greater_equal(flags: u64) -> bool {
let bits = flags & (crate::of::SF | crate::of::OF);
bits == 0 || bits == crate::of::SF | crate::of::OF
}
pub(crate) fn overflow(flags: u64) -> bool {
flags & crate::of::OF != 0
}
pub(crate) fn parity(flags: u64) -> bool {
flags & crate::of::PF != 0
}
pub(crate) fn signed(flags: u64) -> bool {
flags & crate::of::SF != 0
}
pub(crate) fn zero(flags: u64) -> bool {
flags & crate::of::ZF != 0
}
}
pub mod registers {
use crate::of::RegU64;
pub static RAX: RegU64 = RegU64::new(0);
pub static RCX: RegU64 = RegU64::new(8);
pub static RDX: RegU64 = RegU64::new(16);
pub static RBX: RegU64 = RegU64::new(24);
pub static RSP: RegU64 = RegU64::new(32);
pub static RBP: RegU64 = RegU64::new(40);
pub static RSI: RegU64 = RegU64::new(48);
pub static RDI: RegU64 = RegU64::new(56);
pub static R8: RegU64 = RegU64::new(64);
pub static R9: RegU64 = RegU64::new(72);
pub static R10: RegU64 = RegU64::new(80);
pub static R11: RegU64 = RegU64::new(88);
pub static R12: RegU64 = RegU64::new(96);
pub static R13: RegU64 = RegU64::new(104);
pub static R14: RegU64 = RegU64::new(112);
pub static R15: RegU64 = RegU64::new(120);
pub static RIP: RegU64 = RegU64::new(128);
pub static RFLAGS: RegU64 = RegU64::new(136);
}
#[no_mangle]
pub unsafe extern "C" fn map_registers() {
fn __sigmask(sig: u32) -> u64 {
1u64 << ((sig as u64 - 1) % ((8 * core::mem::size_of::<u32>()) as u64))
}
let mut sa = core::mem::MaybeUninit::<libc::sigaction>::uninit();
libc::sigaction(libc::SIGSEGV, core::ptr::null_mut(), sa.as_mut_ptr());
let mut sa = sa.assume_init();
libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
sa.sa_flags = libc::SA_SIGINFO | libc::SA_RESTART | libc::SA_ONSTACK;
sa.sa_sigaction = of_impl as usize;
libc::sigaction(libc::SIGSEGV, &sa as *const libc::sigaction, core::ptr::null_mut());
libc::sigaction(libc::SIGBUS, &sa as *const libc::sigaction, core::ptr::null_mut());
let altstack = libc::stack_t {
ss_sp: ALTSTACK.as_mut_ptr() as *mut c_void,
ss_flags: 0,
ss_size: ALTSTACK.len(),
};
libc::sigaltstack(&altstack as *const libc::stack_t, core::ptr::null_mut());
}
static mut ALTSTACK: [u8; 8192] = [0; 8192];