static void c_handler(Registers* pregs, void* fault_addr, size_t code, size_t flags) { // this exception handler is executed *after* VEH handler returned int result; Boolean iscrash = (DWORD)flags == EXCEPTION_NONCONTINUABLE; switch ((DWORD)code) { case STATUS_STACK_OVERFLOW: result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, iscrash); break; case STATUS_ACCESS_VIOLATION: result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, iscrash); 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: result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, iscrash); break; case JVMTI_EXCEPTION_STATUS: result = port_process_signal(PORT_SIGNAL_BREAKPOINT, pregs, fault_addr, iscrash); break; default: result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE); } port_tls_data_t* tlsdata = get_private_tls_data(); 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; } if (result > 0 /*Assert dialog*/|| FLAG_CORE) { // Prepare second catch of this exception to produce minidump (because // we've lost LPEXCEPTION_POINTERS structure) and/or show assert dialog if (FLAG_CORE) tlsdata->produce_core = TRUE; if (result > 0) tlsdata->debugger = TRUE; // To catch STACK_OVERFLOW port_thread_restore_guard_page(); return; // To produce exception again } _exit(-1); // We need neither dump nor assert dialog }
// exception catch support for JVMTI, also restore stack after Stack Overflow Error void jvmti_exception_catch_callback() { Registers regs = {0}; VM_thread *thread = p_TLS_vmthread; assert(thread); if (thread->regs) { regs = *(Registers*)thread->regs; } M2nFrame* m2n = (M2nFrame *) STD_ALLOCA(m2n_get_size()); m2n_push_suspended_frame(thread, m2n, ®s); M2nFrame* prev_m2n = m2n_get_previous_frame(m2n); StackIterator* si = (StackIterator*) STD_ALLOCA(si_size()); si_fill_from_registers(si, ®s, false, prev_m2n); // si_create_from_registers uses large stack space, // so guard page restored after its invoke, // but befor ti agent callback invokation, // because it should work on protected page. if (p_TLS_vmthread->restore_guard_page) { int res = port_thread_restore_guard_page(); if (res != 0) { Global_Env *env = VM_Global_State::loader_env; if (si_is_native(si)) { m2n_set_last_frame(prev_m2n); if ((interpreter_enabled() || (!prev_m2n) || (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { exn_raise_by_class(env->java_lang_StackOverflowError_Class); } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } p_TLS_vmthread->restore_guard_page = false; } if (!si_is_native(si)) { CodeChunkInfo* catch_cci = si_get_code_chunk_info(si); assert(catch_cci); Method* catch_method = catch_cci->get_method(); NativeCodePtr catch_method_location = si_get_ip(si); JIT* catch_method_jit = catch_cci->get_jit(); ManagedObject** exn_obj = (ManagedObject**) si_get_return_pointer(si); *exn_obj = jvmti_jit_exception_catch_event_callback_call( *exn_obj, catch_method_jit, catch_method, catch_method_location); } si_transfer_control(si); }
// exception catch callback to restore stack after Stack Overflow Error void exception_catch_callback() { Registers regs = {0}; VM_thread *thread = p_TLS_vmthread; assert(thread); if (thread->regs) { regs = *(Registers*)thread->regs; } M2nFrame* m2n = (M2nFrame *) STD_ALLOCA(m2n_get_size()); m2n_push_suspended_frame(thread, m2n, ®s); M2nFrame* prev_m2n = m2n_get_previous_frame(m2n); StackIterator* si = (StackIterator*) STD_ALLOCA(si_size()); si_fill_from_registers(si, ®s, false, prev_m2n); // si_create_from_registers uses large stack space, // so guard page restored after its invoke. if (p_TLS_vmthread->restore_guard_page) { int res = port_thread_restore_guard_page(); if (res != 0) { Global_Env *env = VM_Global_State::loader_env; if (si_is_native(si)) { m2n_set_last_frame(prev_m2n); if ((interpreter_enabled() || (!prev_m2n) || (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { exn_raise_by_class(env->java_lang_StackOverflowError_Class); } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } else { //si_free(si); exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } p_TLS_vmthread->restore_guard_page = false; } si_transfer_control(si); }
void exn_clear() { tmn_suspend_disable_recursive(); clear_exception_internal(); tmn_suspend_enable_recursive(); // This will restore quard stack if needed if (p_TLS_vmthread->restore_guard_page) { int res = port_thread_restore_guard_page(); // if guard stack can't be restored raise SOE if (res != 0) { Global_Env *env = VM_Global_State::loader_env; exn_raise_by_class(env->java_lang_StackOverflowError_Class); } p_TLS_vmthread->restore_guard_page = false; } }
void prepare_assert_dialog(Registers* regs) { // To catch STACK_OVERFLOW port_thread_restore_guard_page(); shutdown_signals(); }
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); }