factor/native/unix/signal.c

64 lines
1.9 KiB
C

#include "../factor.h"
#include "mach_signal.h"
// this function tests if a given faulting location is in a poison page. The
// page address is taken from area + round_up_to_page_size(area_size) +
// pagesize*offset
static bool in_page(void *fault, void *i_area, CELL area_size, int offset)
{
const int pagesize = getpagesize();
intptr_t area = (intptr_t) i_area;
area += pagesize * ((area_size + (pagesize - 1)) / pagesize);
area += offset * pagesize;
const int page = area / pagesize;
const int fault_page = (intptr_t)fault / pagesize;
return page == fault_page;
}
void signal_handler(int signal, siginfo_t* siginfo, void* uap)
{
if(in_page(siginfo->si_addr, (void *) ds_bot, 0, -1))
signal_stack_error(false, false);
else if(in_page(siginfo->si_addr, (void *) ds_bot, ds_size, 0))
signal_stack_error(false, true);
else if(in_page(siginfo->si_addr, (void *) cs_bot, 0, -1))
signal_stack_error(true, false);
else if(in_page(siginfo->si_addr, (void *) cs_bot, cs_size, 0))
signal_stack_error(true, true);
else
signal_error(signal);
}
static void sigaction_safe(int signum, const struct sigaction *act, struct sigaction *oldact)
{
int ret;
do
{
ret = sigaction(signum, act, oldact);
} while(ret == -1 && errno == EINTR);
}
void init_signals(void)
{
struct sigaction custom_sigaction;
struct sigaction ign_sigaction;
sigemptyset(&custom_sigaction.sa_mask);
custom_sigaction.sa_sigaction = signal_handler;
custom_sigaction.sa_flags = SA_SIGINFO;
sigaction_safe(SIGABRT,&custom_sigaction,NULL);
sigaction_safe(SIGFPE,&custom_sigaction,NULL);
sigaction_safe(SIGBUS,&custom_sigaction,NULL);
sigaction_safe(SIGQUIT,&custom_sigaction,NULL);
sigaction_safe(SIGSEGV,&custom_sigaction,NULL);
sigemptyset(&ign_sigaction.sa_mask);
ign_sigaction.sa_handler = SIG_IGN;
sigaction_safe(SIGPIPE,&ign_sigaction,NULL);
#ifdef __APPLE__
mach_initialize();
#endif
}