/* * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// put OS-includes here # include <sys/types.h> # include <sys/mman.h> # include <pthread.h> # include <signal.h> # include <errno.h> # include <dlfcn.h> # include <stdlib.h> # include <stdio.h> # include <unistd.h> # include <sys/resource.h> # include <pthread.h> # include <sys/stat.h> # include <sys/time.h> # include <sys/utsname.h> # include <sys/socket.h> # include <sys/wait.h> # include <pwd.h> # include <poll.h> # include <ucontext.h> #ifndef AMD64 # include <fpu_control.h> #endif
char* os::non_memory_address_word() { // Must never look like an address returned by reserve_memory, // even in its subfields (as defined by the CPU immediate fields, // if the CPU splits constants across multiple instructions).
if (uc != NULL) {
epc = os::Posix::ucontext_get_pc(uc); if (ret_sp) *ret_sp = os::Linux::ucontext_get_sp(uc); if (ret_fp) *ret_fp = os::Linux::ucontext_get_fp(uc);
} else {
epc = NULL; if (ret_sp) *ret_sp = (intptr_t *)NULL; if (ret_fp) *ret_fp = (intptr_t *)NULL;
}
return epc;
}
frame os::fetch_frame_from_context(constvoid* ucVoid) {
intptr_t* sp;
intptr_t* fp;
address epc = fetch_frame_from_context(ucVoid, &sp, &fp); if (!is_readable_pointer(epc)) { // Try to recover from calling into bad memory // Assume new frame has not been set up, the same as // compiled frame stack bang return fetch_compiled_frame_from_context(ucVoid);
} return frame(sp, fp, epc);
}
// By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get // turned off by -fomit-frame-pointer,
frame os::get_sender_for_C_frame(frame* fr) { return frame(fr->sender_sp(), fr->link(), fr->sender_pc());
}
intptr_t* _get_previous_fp() { #ifdefined(__clang__)
intptr_t **ebp;
__asm__ __volatile__ ("mov %%" SPELL_REG_FP ", %0":"=r"(ebp):); #else register intptr_t **ebp __asm__ (SPELL_REG_FP); #endif // ebp is for this frame (_get_previous_fp). We want the ebp for the // caller of os::current_frame*(), so go up two frames. However, for // optimized builds, _get_previous_fp() will be inlined, so only go // up 1 frame in that case. #ifdef _NMT_NOINLINE_ return **(intptr_t***)ebp; #else return *ebp; #endif
}
frame os::current_frame() {
intptr_t* fp = _get_previous_fp();
frame myframe((intptr_t*)os::current_stack_pointer(),
(intptr_t*)fp,
CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable return frame();
} else { return os::get_sender_for_C_frame(&myframe);
}
}
// Utility functions
// From IA32 System Programming Guide enum {
trap_page_fault = 0xE
};
/* NOTE: does not seem to work on linux. if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { // can't decode this kind of signal info = NULL; } else { assert(sig == info->si_signo, "bad siginfo"); }
*/ // decide if this trap can be handled by a stub
address stub = NULL;
address pc = NULL;
//%note os_trap_1 if (info != NULL && uc != NULL && thread != NULL) {
pc = (address) os::Posix::ucontext_get_pc(uc);
if (sig == SIGSEGV && info->si_addr == 0 && info->si_code == SI_KERNEL) { // An irrecoverable SI_KERNEL SIGSEGV has occurred. // It's likely caused by dereferencing an address larger than TASK_SIZE. returnfalse;
}
// Handle ALL stack overflow variations here if (sig == SIGSEGV) {
address addr = (address) info->si_addr;
// check if fault address is within thread stack if (thread->is_in_full_stack(addr)) { // stack overflow if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { returntrue; // continue
}
}
}
if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { // Verify that OS save/restore AVX registers.
stub = VM_Version::cpuinfo_cont_addr();
}
if (thread->thread_state() == _thread_in_Java) { // Java thread running in Java code => find exception handler if any // a fault inside compiled code, the interpreter, or a stub
if (sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) {
stub = SharedRuntime::get_poll_stub(pc);
} elseif (sig == SIGBUS /* && info->si_code == BUS_OBJERR */) { // BugId 4454115: A read from a MappedByteBuffer can fault // here if the underlying file has been truncated. // Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob(pc);
CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL; bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc); if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) {
address next_pc = Assembler::locate_next_instruction(pc); if (is_unsafe_arraycopy) {
next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
}
stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
}
} else
#ifdef AMD64 if (sig == SIGFPE &&
(info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) {
stub =
SharedRuntime::
continuation_for_implicit_exception(thread,
pc,
SharedRuntime::
IMPLICIT_DIVIDE_BY_ZERO); #else if (sig == SIGFPE /* && info->si_code == FPE_INTDIV */) { // HACK: si_code does not work on linux 2.2.12-20!!! int op = pc[0]; if (op == 0xDB) { // FIST // TODO: The encoding of D2I in x86_32.ad can cause an exception // prior to the fist instruction if there was an invalid operation // pending. We want to dismiss that exception. From the win_32 // side it also seems that if it really was the fist causing // the exception that we do the d2i by hand with different // rounding. Seems kind of weird. // NOTE: that we take the exception at the NEXT floating point instruction.
assert(pc[0] == 0xDB, "not a FIST opcode");
assert(pc[1] == 0x14, "not a FIST opcode");
assert(pc[2] == 0x24, "not a FIST opcode"); returntrue;
} elseif (op == 0xF7) { // IDIV
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
} else { // TODO: handle more cases if we are using other x86 instructions // that can generate SIGFPE signal on linux.
tty->print_cr("unknown opcode 0x%X with SIGFPE.", op);
fatal("please update this code.");
} #endif// AMD64
} elseif (sig == SIGSEGV &&
MacroAssembler::uses_implicit_null_check(info->si_addr)) { // Determination of interpreter/vtable stub/compiled code null exception
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
}
} elseif ((thread->thread_state() == _thread_in_vm ||
thread->thread_state() == _thread_in_native) &&
(sig == SIGBUS && /* info->si_code == BUS_OBJERR && */
thread->doing_unsafe_access())) {
address next_pc = Assembler::locate_next_instruction(pc); if (UnsafeCopyMemory::contains_pc(pc)) {
next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
}
stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
}
// 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)) {
address addr = JNI_FastGetField::find_slowcase_pc(pc); if (addr != (address)-1) {
stub = addr;
}
}
}
#ifndef AMD64 // Execution protection violation // // This should be kept as the last step in the triage. We don't // have a dedicated trap number for a no-execute fault, so be // conservative and allow other handlers the first shot. // // Note: We don't test that info->si_code == SEGV_ACCERR here. // this si_code is so generic that it is almost meaningless; and // the si_code for this condition may change in the future. // Furthermore, a false-positive should be harmless. if (UnguardOnExecutionViolation > 0 &&
stub == NULL &&
(sig == SIGSEGV || sig == SIGBUS) &&
uc->uc_mcontext.gregs[REG_TRAPNO] == trap_page_fault) { int page_size = os::vm_page_size();
address addr = (address) info->si_addr;
address pc = os::Posix::ucontext_get_pc(uc); // Make sure the pc and the faulting address are sane. // // If an instruction spans a page boundary, and the page containing // the beginning of the instruction is executable but the following // page is not, the pc and the faulting address might be slightly // different - we still want to unguard the 2nd page in this case. // // 15 bytes seems to be a (very) safe value for max instruction size. bool pc_is_near_addr =
(pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); bool instr_spans_page_boundary =
(align_down((intptr_t) pc ^ (intptr_t) addr,
(intptr_t) page_size) > 0);
// In conservative mode, don't unguard unless the address is in the VM if (addr != last_addr &&
(UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) {
// Set memory to RWX and retry
address page_start = align_down(addr, page_size); bool res = os::protect_memory((char*) page_start, page_size,
os::MEM_PROT_RWX);
// Set last_addr so if we fault again at the same address, we don't end // up in an endless loop. // // There are two potential complications here. Two threads trapping at // the same address at the same time could cause one of the threads to // think it already unguarded, and abort the VM. Likely very rare. // // The other race involves two threads alternately trapping at // different addresses and failing to unguard the page, resulting in // an endless loop. This condition is probably even more unlikely than // the first. // // Although both cases could be avoided by using locks or thread local // last_addr, these solutions are unnecessary complication: this // handler is a best-effort safety net, not a complete solution. It is // disabled by default and should only be used as a workaround in case // we missed any no-execute-unsafe VM code.
last_addr = addr;
}
}
} #endif// !AMD64
if (stub != NULL) { // save all thread context in case we need to restore it if (thread != NULL) thread->set_saved_exception_pc(pc);
juint os::cpu_microcode_revision() { // Note: this code runs on startup, and therefore should not be slow, // see JDK-8283200.
juint result = 0;
// Attempt 1 (faster): Read the microcode version off the sysfs.
FILE *fp = os::fopen("/sys/devices/system/cpu/cpu0/microcode/version", "r"); if (fp) { int read = fscanf(fp, "%x", &result);
fclose(fp); if (read > 0) { return result;
}
}
// Attempt 2 (slower): Read the microcode version off the procfs.
fp = os::fopen("/proc/cpuinfo", "r"); if (fp) { char data[2048] = {0}; // lines should fit in 2K buf
size_t len = sizeof(data); while (!feof(fp)) { if (fgets(data, len, fp)) { if (strstr(data, "microcode") != NULL) { char* rev = strchr(data, ':'); if (rev != NULL) sscanf(rev + 1, "%x", &result); break;
}
}
}
fclose(fp);
}
// 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::fetch_frame_from_context(uc).pc();
print_instructions(st, pc, sizeof(char));
st->cr();
}
st->print_cr("Register to memory mapping:");
st->cr();
// this is horrendously verbose but the layout of the registers in the // context does not match how we defined our abstract Register set, so // we can't just iterate through the gregs area
// this is only for the "general purpose" registers
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.