static int set_guard_page(port_tls_data_t* tlsdata, Boolean set) { int res; if (!tlsdata) tlsdata = get_private_tls_data(); if (!tlsdata) return -1; if (!tlsdata->guard_page_addr) return 0; if ((set && tlsdata->guard_page_set) || (!set && !tlsdata->guard_page_set)) return 0; // Already in needed state res = mprotect(tlsdata->guard_page_addr, tlsdata->guard_page_size, set ? PROT_NONE : (PROT_READ | PROT_WRITE | PROT_EXEC)); if (res != 0) return errno; if (set) { res = set_alt_stack(tlsdata, TRUE); if (res != 0) return res; } tlsdata->guard_page_set = set; return 0; }
static void c_handler(Registers* pregs, size_t signum, void* fault_addr) { // this exception handler is executed *after* OS signal handler returned int result; port_tls_data_t* tlsdata = get_private_tls_data(); switch ((int)signum) { case SIGSEGV: if (tlsdata->restore_guard_page) { // Now it's safe to disable alternative stack set_alt_stack(tlsdata, FALSE); result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, FALSE); } else result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE); break; case SIGFPE: result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, FALSE); break; case SIGTRAP: // Correct return address pregs->set_ip((void*)((POINTER_SIZE_INT)pregs->get_ip() - 1)); result = port_process_signal(PORT_SIGNAL_BREAKPOINT, pregs, fault_addr, FALSE); break; case SIGINT: result = port_process_signal(PORT_SIGNAL_CTRL_C, pregs, fault_addr, FALSE); break; case SIGQUIT: result = port_process_signal(PORT_SIGNAL_QUIT, pregs, fault_addr, FALSE); break; case SIGABRT: result = port_process_signal(PORT_SIGNAL_ABORT, NULL, fault_addr, FALSE); break; default: result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE); } if (result == 0) { // Restore guard page if needed if (tlsdata->restore_guard_page) { port_thread_restore_guard_page(); tlsdata->restore_guard_page = FALSE; if (port_thread_detach_temporary() == 0) STD_FREE(tlsdata); } return; } // We've got a crash if (signum == SIGSEGV) { port_thread_restore_guard_page(); // To catch SO again tlsdata->restore_guard_page = FALSE; } if (result > 0) // invoke debugger { // Prepare second catch of signal to attach GDB from signal handler //assert(tlsdata); // Should be attached - provided by general_signal_handler tlsdata->debugger = TRUE; return; // To produce signal again } // result < 0 - exit process if (FLAG_CORE) { // Return to the same place to produce the same crash and generate core signal(signum, SIG_DFL); // setup default handler return; } // No core needed - simply terminate _exit(-1); }