inline static bool checkPrefetch(sigcontext* uc, address pc) { if (pc == (address) Fetch32PFI) { set_cont_address(uc, address(Fetch32Resume)); return true; } if (pc == (address) FetchNPFI) { set_cont_address(uc, address(FetchNResume)); return true; } return false; }
inline static bool checkPrefetch(sigcontext* uc, address pc) { if (StubRoutines::is_safefetch_fault(pc)) { set_cont_address(uc, address(StubRoutines::continuation_for_safefetch_fault(pc))); return true; } return false; }
extern "C" JNIEXPORT int JVM_handle_linux_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrecognized) { // in fact this isn't ucontext_t* at all, but struct sigcontext* // but Linux porting layer uses ucontext_t, so to minimize code change // we cast as needed ucontext_t* ucFake = (ucontext_t*) ucVoid; sigcontext* uc = (sigcontext*)ucVoid; Thread* t = ThreadLocalStorage::get_thread_slow(); SignalHandlerMark shm(t); // Note: it's not uncommon that JNI code uses signal/sigset to install // then restore certain signal handler (e.g. to temporarily block SIGPIPE, // or have a SIGILL handler when detecting CPU type). When that happens, // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To // avoid unnecessary crash when libjsig is not preloaded, try handle signals // that do not require siginfo/ucontext first. if (sig == SIGPIPE || sig == SIGXFSZ) { // allow chained handler to go first if (os::Linux::chained_handler(sig, info, ucVoid)) { return true; } else { if (PrintMiscellaneous && (WizardMode || Verbose)) { char buf[64]; warning("Ignoring %s - see bugs 4229104 or 646499219", os::exception_name(sig, buf, sizeof(buf))); } return true; } } JavaThread* thread = NULL; VMThread* vmthread = NULL; if (os::Linux::signal_handlers_are_installed) { if (t != NULL ){ if(t->is_Java_thread()) { thread = (JavaThread*)t; } else if(t->is_VM_thread()){ vmthread = (VMThread *)t; } } } // decide if this trap can be handled by a stub address stub = NULL; address pc = NULL; address npc = NULL; //%note os_trap_1 if (info != NULL && uc != NULL && thread != NULL) { pc = address(SIG_PC(uc)); npc = address(SIG_NPC(uc)); // Check to see if we caught the safepoint code in the // process of write protecting the memory serialization page. // It write enables the page immediately after protecting it // so we can just return to retry the write. if ((sig == SIGSEGV) && checkSerializePage(thread, (address)info->si_addr)) { // Block current thread until the memory serialize page permission restored. os::block_on_serialize_page_trap(); return 1; } if (checkPrefetch(uc, pc)) { return 1; } // Handle ALL stack overflow variations here if (sig == SIGSEGV) { if (checkOverflow(uc, pc, (address)info->si_addr, thread, &stub)) { return 1; } } if (sig == SIGBUS && thread->thread_state() == _thread_in_vm && thread->doing_unsafe_access()) { stub = StubRoutines::handler_for_unsafe_access(); } if (thread->thread_state() == _thread_in_Java) { do { // Java thread running in Java code => find exception handler if any // a fault inside compiled code, the interpreter, or a stub if ((sig == SIGSEGV) && checkPollingPage(pc, (address)info->si_addr, &stub)) { break; } if ((sig == SIGBUS) && checkByteBuffer(pc, &stub)) { break; } if ((sig == SIGSEGV || sig == SIGBUS) && checkVerifyOops(pc, (address)info->si_addr, &stub)) { break; } if ((sig == SIGSEGV) && checkZombie(uc, &pc, &stub)) { break; } if ((sig == SIGILL) && checkICMiss(uc, &pc, &stub)) { break; } if ((sig == SIGFPE) && checkFPFault(pc, info->si_code, thread, &stub)) { break; } if ((sig == SIGSEGV) && checkNullPointer(pc, (intptr_t)info->si_addr, thread, &stub)) { break; } } while (0); // jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in // and the heap gets shrunk before the field access. if ((sig == SIGSEGV) || (sig == SIGBUS)) { checkFastJNIAccess(pc, &stub); } } if (stub != NULL) { // save all thread context in case we need to restore it thread->set_saved_exception_pc(pc); thread->set_saved_exception_npc(npc); set_cont_address(uc, stub); return true; } } // signal-chaining if (os::Linux::chained_handler(sig, info, ucVoid)) { return true; } if (!abort_if_unrecognized) { // caller wants another chance, so give it to him return false; } if (pc == NULL && uc != NULL) { pc = os::Linux::ucontext_get_pc((ucontext_t*)uc); } // unmask current signal sigset_t newset; sigemptyset(&newset); sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); VMError err(t, sig, pc, info, ucVoid); err.report_and_die(); ShouldNotReachHere(); }