LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception) { DWORD code = nt_exception->ExceptionRecord->ExceptionCode; void* fault_addr = nt_exception->ExceptionRecord->ExceptionAddress; Registers regs; // Convert NT context to Registers port_thread_context_to_regs(®s, nt_exception->ContextRecord); // Check if TLS structure is set - probably we should produce minidump port_tls_data_t* tlsdata = get_private_tls_data(); if (!tlsdata) // Tread is not attached - attach thread temporarily { int res; tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); if (tlsdata) // Try to attach the thread res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0); if (!tlsdata || res != 0) { // Can't process correctly; perform default actions if (FLAG_CORE) create_minidump(nt_exception); if (FLAG_DBG) { show_debugger_dialog(); // Workaround; EXCEPTION_CONTINUE_SEARCH does not work _exit(-1); return EXCEPTION_CONTINUE_SEARCH; // Assert dialog } _exit(-1); } // SO for alien thread can't be processed out of VEH if (code == STATUS_STACK_OVERFLOW && sd_is_handler_registered(PORT_SIGNAL_STACK_OVERFLOW)) { int result; size_t alt_stack_size = ALT_PAGES_COUNT*tlsdata->guard_page_size; void* alt_stack = map_alt_stack(alt_stack_size); void* stack_bottom = (void*)((POINTER_SIZE_INT)alt_stack + alt_stack_size); if (alt_stack) result = (int)(POINTER_SIZE_INT)port_call_alt_stack( port_process_signal, stack_bottom, 4, PORT_SIGNAL_STACK_OVERFLOW, ®s, fault_addr, FALSE); else result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, ®s, fault_addr, FALSE); if (result == 0) { if (port_thread_detach_temporary() == 0) STD_FREE(tlsdata); if (alt_stack) unmap_alt_stack(alt_stack, alt_stack_size); return EXCEPTION_CONTINUE_EXECUTION; } if (FLAG_CORE) { if (alt_stack) port_call_alt_stack(create_minidump, stack_bottom, 1, nt_exception); else create_minidump(nt_exception); } if (alt_stack) unmap_alt_stack(alt_stack, alt_stack_size); if (result > 0) { show_debugger_dialog(); // Workaround; EXCEPTION_CONTINUE_SEARCH does not work _exit(-1); shutdown_signals(); return EXCEPTION_CONTINUE_SEARCH; // Assert dialog } _exit(-1); } } if (tlsdata->produce_core) { create_minidump(nt_exception); if (!tlsdata->debugger) _exit(-1); } if (tlsdata->debugger) { show_debugger_dialog(); // Workaround _exit(-1); // Go to handler to restore CRT/VEH settings and crash once again // port_set_longjump_regs(&prepare_assert_dialog, ®s, 1, ®s); // port_thread_regs_to_context(nt_exception->ContextRecord, ®s); // return EXCEPTION_CONTINUE_EXECUTION; } switch (code) { case STATUS_STACK_OVERFLOW: if (!sd_is_handler_registered(PORT_SIGNAL_STACK_OVERFLOW)) return EXCEPTION_CONTINUE_SEARCH; break; case STATUS_ACCESS_VIOLATION: if (!sd_is_handler_registered(PORT_SIGNAL_GPF)) return EXCEPTION_CONTINUE_SEARCH; break; case JVMTI_EXCEPTION_STATUS: if (!sd_is_handler_registered(PORT_SIGNAL_BREAKPOINT)) return EXCEPTION_CONTINUE_SEARCH; break; case STATUS_INTEGER_DIVIDE_BY_ZERO: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_INT_OVERFLOW: if (!sd_is_handler_registered(PORT_SIGNAL_ARITHMETIC)) return EXCEPTION_CONTINUE_SEARCH; break; default: return EXCEPTION_CONTINUE_SEARCH; } if (code == STATUS_STACK_OVERFLOW) { tlsdata->guard_page_set = FALSE; // GUARD_PAGE was cleared by OS if (!tlsdata->restore_guard_page) tlsdata->restore_guard_page = TRUE; } // Prepare to transfering control out of VEH handler port_set_longjump_regs(&c_handler, ®s, 4, ®s, nt_exception->ExceptionRecord->ExceptionAddress, (void*)(size_t)nt_exception->ExceptionRecord->ExceptionCode, (void*)(size_t)nt_exception->ExceptionRecord->ExceptionFlags); // Convert prepared Registers back to NT context port_thread_regs_to_context(nt_exception->ContextRecord, ®s); // Return from VEH - presumably continue execution return EXCEPTION_CONTINUE_EXECUTION; }
static void general_signal_handler(int signum, siginfo_t* info, void* context) { Registers regs; if (!context) return; // Convert OS context to Registers port_thread_context_to_regs(®s, (ucontext_t*)context); void* fault_addr = info ? info->si_addr : NULL; // Check if SIGSEGV is produced by port_read/write_memory port_tls_data_t* tlsdata = get_private_tls_data(); if (tlsdata && tlsdata->violation_flag) { tlsdata->violation_flag = 0; regs.set_ip(tlsdata->restart_address); return; } if (!tlsdata) // Tread is not attached - attach thread temporarily { int res; tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); if (tlsdata) // Try to attach the thread res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0); if (!tlsdata || res != 0) { // Can't process correctly; perform default actions if (FLAG_DBG) { bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } if (FLAG_CORE && signum != SIGABRT) // SIGABRT can't be rethrown { signal(signum, SIG_DFL); // setup default handler return; } _exit(-1); } // SIGSEGV can represent SO which can't be processed out of signal handler if (signum == SIGSEGV && // This can occur only when a user set an alternative stack is_stack_overflow(tlsdata, fault_addr)) { int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, ®s, fault_addr, FALSE); if (result == 0) { if (port_thread_detach_temporary() == 0) STD_FREE(tlsdata); return; } if (result > 0) tlsdata->debugger = TRUE; else { if (FLAG_CORE) { // Rethrow crash to generate core signal(signum, SIG_DFL); // setup default handler return; } _exit(-1); } } } if (tlsdata->debugger) { bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } if (signum == SIGABRT && // SIGABRT can't be trown again from c_handler FLAG_DBG) { // So attaching GDB right here bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } if (signum == SIGSEGV && is_stack_overflow(tlsdata, fault_addr)) { // Second SO while previous SO is not processed yet - is GPF if (tlsdata->restore_guard_page) tlsdata->restore_guard_page = FALSE; else { // To process signal on protected stack area port_thread_clear_guard_page(); // Note: the call above does not disable alternative stack // It can't be made while we are on alternative stack // Alt stack will be disabled explicitly in c_handler() tlsdata->restore_guard_page = TRUE; } } // Prepare registers for transfering control out of signal handler void* callback = (void*)&c_handler; port_set_longjump_regs(callback, ®s, 3, ®s, (void*)(size_t)signum, fault_addr); // Convert prepared Registers back to OS context port_thread_regs_to_context((ucontext_t*)context, ®s); // Return from signal handler to go to C handler }