void os::print_context(outputStream *st, void *context) { if (context == NULL) return; ucontext_t* uc = (ucontext_t*)context; sigcontext* sc = (sigcontext*)context; st->print_cr("Registers:"); st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_O0], SIG_REGS(sc).u_regs[CON_O1], SIG_REGS(sc).u_regs[CON_O2], SIG_REGS(sc).u_regs[CON_O3]); st->print_cr(" O4=" INTPTR_FORMAT " O5=" INTPTR_FORMAT " O6=" INTPTR_FORMAT " O7=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_O4], SIG_REGS(sc).u_regs[CON_O5], SIG_REGS(sc).u_regs[CON_O6], SIG_REGS(sc).u_regs[CON_O7]); st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_G1], SIG_REGS(sc).u_regs[CON_G2], SIG_REGS(sc).u_regs[CON_G3], SIG_REGS(sc).u_regs[CON_G4]); st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT " G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_G5], SIG_REGS(sc).u_regs[CON_G6], SIG_REGS(sc).u_regs[CON_G7], SIG_REGS(sc).y); st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, SIG_PC(sc), SIG_NPC(sc)); st->cr(); st->cr(); intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); st->cr(); // Note: it may be unsafe to inspect memory near pc. For example, pc may // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Linux::ucontext_get_pc(uc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); }
static inline void set_cont_address(sigcontext* ctx, address addr) { SIG_PC(ctx) = (intptr_t)addr; SIG_NPC(ctx) = (intptr_t)(addr+4); }
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(); }
address os::Linux::ucontext_get_pc(ucontext_t* uc) { return (address) SIG_PC((sigcontext*)uc); }
void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) { sigcontext_t* ctx = (sigcontext_t*) uc; SIG_PC(ctx) = (intptr_t)addr; SIG_NPC(ctx) = (intptr_t)(addr+4); }
void os::print_context(outputStream *st, void *context) { if (context == NULL) return; ucontext_t* uc = (ucontext_t*)context; sigcontext* sc = (sigcontext*)context; st->print_cr("Registers:"); st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_G1], SIG_REGS(sc).u_regs[CON_G2], SIG_REGS(sc).u_regs[CON_G3], SIG_REGS(sc).u_regs[CON_G4]); st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT " G7=" INTPTR_FORMAT " Y=0x%x", SIG_REGS(sc).u_regs[CON_G5], SIG_REGS(sc).u_regs[CON_G6], SIG_REGS(sc).u_regs[CON_G7], SIG_REGS(sc).y); st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_O0], SIG_REGS(sc).u_regs[CON_O1], SIG_REGS(sc).u_regs[CON_O2], SIG_REGS(sc).u_regs[CON_O3]); st->print_cr(" O4=" INTPTR_FORMAT " O5=" INTPTR_FORMAT " O6=" INTPTR_FORMAT " O7=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_O4], SIG_REGS(sc).u_regs[CON_O5], SIG_REGS(sc).u_regs[CON_O6], SIG_REGS(sc).u_regs[CON_O7]); intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT, sp[L0->sp_offset_in_saved_window()], sp[L1->sp_offset_in_saved_window()], sp[L2->sp_offset_in_saved_window()], sp[L3->sp_offset_in_saved_window()]); st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT, sp[L4->sp_offset_in_saved_window()], sp[L5->sp_offset_in_saved_window()], sp[L6->sp_offset_in_saved_window()], sp[L7->sp_offset_in_saved_window()]); st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT " I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT, sp[I0->sp_offset_in_saved_window()], sp[I1->sp_offset_in_saved_window()], sp[I2->sp_offset_in_saved_window()], sp[I3->sp_offset_in_saved_window()]); st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT " I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT, sp[I4->sp_offset_in_saved_window()], sp[I5->sp_offset_in_saved_window()], sp[I6->sp_offset_in_saved_window()], sp[I7->sp_offset_in_saved_window()]); st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, SIG_PC(sc), SIG_NPC(sc)); st->cr(); st->cr(); st->print_cr("Top of Stack: (sp=" INTPTR_FORMAT ")", p2i(sp)); print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); st->cr(); // Note: it may be unsafe to inspect memory near pc. For example, pc may // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Linux::ucontext_get_pc(uc); st->print_cr("Instructions: (pc=" INTPTR_FORMAT ")", p2i(pc)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); }