/* * Copyright (c) 2008, 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> # include <fpu_control.h> # include <asm/ptrace.h>
#define SPELL_REG_SP "sp"
#ifndef __thumb__ enum { // Offset to add to frame::_fp when dealing with non-thumb C frames
C_frame_offset = -1,
}; #endif
// Don't #define SPELL_REG_FP for thumb because it is not safe to use, so this makes sure we never fetch it. #ifndef __thumb__ #define SPELL_REG_FP "fp" #endif
char* os::non_memory_address_word() { // Must never look like an address returned by reserve_memory return (char*) -1;
}
#if NGREG == 16 // These definitions are based on the observation that until // the certain version of GCC mcontext_t was defined as // a structure containing gregs[NGREG] array with 16 elements. // In later GCC versions mcontext_t was redefined as struct sigcontext, // along with NGREG constant changed to 18. #define arm_pc gregs[15] #define arm_sp gregs[13] #define arm_fp gregs[11] #define arm_r0 gregs[0] #endif
bool is_safe_for_fp(address pc) { #ifdef __thumb__ if (CodeCache::find_blob(pc) != NULL) { returntrue;
} // For thumb C frames, given an fp we have no idea how to access the frame contents. returnfalse; #else // Calling os::address_is_in_vm() here leads to a dladdr call. Calling any libc // function during os::get_native_stack() can result in a deadlock if JFR is // enabled. For now, be more lenient and allow all pc's. There are other // frame sanity checks in shared code, and to date they have been sufficient // for other platforms. //return os::address_is_in_vm(pc); returntrue; #endif
}
if (uc != NULL) {
epc = os::Posix::ucontext_get_pc(uc); if (ret_sp) *ret_sp = os::Linux::ucontext_get_sp(uc); if (ret_fp) {
intptr_t* fp = os::Linux::ucontext_get_fp(uc); #ifndef __thumb__ if (CodeCache::find_blob(epc) == NULL) { // It's a C frame. We need to adjust the fp.
fp += C_frame_offset;
} #endif // Clear FP when stack walking is dangerous so that // the frame created will not be walked. // However, ensure FP is set correctly when reliable and // potentially necessary. if (!is_safe_for_fp(epc)) { // FP unreliable
fp = (intptr_t *)NULL;
}
*ret_fp = fp;
}
} else {
epc = NULL; if (ret_sp) *ret_sp = (intptr_t *)NULL; if (ret_fp) *ret_fp = (intptr_t *)NULL;
}
frame os::get_sender_for_C_frame(frame* fr) { #ifdef __thumb__ // We can't reliably get anything from a thumb C frame. return frame(); #else
address pc = fr->sender_pc(); if (! is_safe_for_fp(pc)) { return frame(fr->sender_sp(), (intptr_t *)NULL, pc);
} else { return frame(fr->sender_sp(), fr->link() + C_frame_offset, pc);
} #endif
}
// // This actually returns two frames up. It does not return os::current_frame(), // which is the actual current frame. Nor does it return os::get_native_stack(), // which is the caller. It returns whoever called os::get_native_stack(). Not // very intuitive, but consistent with how this API is implemented on other // platforms. //
frame os::current_frame() { #ifdef __thumb__ // We can't reliably get anything from a thumb C frame. return frame(); #else register intptr_t* fp __asm__ (SPELL_REG_FP); // fp is for os::current_frame. We want the fp for our caller.
frame myframe((intptr_t*)os::current_stack_pointer(), fp + C_frame_offset,
CAST_FROM_FN_PTR(address, os::current_frame));
frame caller_frame = os::get_sender_for_C_frame(&myframe);
if (os::is_first_C_frame(&caller_frame)) { // stack is not walkable // Assert below was added because it does not seem like this can ever happen. // How can this frame ever be the first C frame since it is called from C code? // If it does ever happen, undo the assert and comment here on when/why it happens.
assert(false, "this should never happen"); return frame();
}
if (info != NULL && uc != NULL && thread != NULL) {
pc = (address) os::Posix::ucontext_get_pc(uc);
// 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
StackOverflow* overflow_state = thread->stack_overflow_state(); if (overflow_state->in_stack_yellow_reserved_zone(addr)) {
overflow_state->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { // Throw a stack overflow exception. Guard pages will be re-enabled // while unwinding the stack.
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
} else { // Thread was in the vm or native code. Return and try to finish. returntrue;
}
} elseif (overflow_state->in_stack_red_zone(addr)) { // Fatal red zone violation. Disable the guard pages and fall through // to the exception handling code below.
overflow_state->disable_stack_red_zone();
tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
} else { // Accessing stack address below sp may cause SEGV if current // thread has MAP_GROWSDOWN stack. This should only happen when // current thread was created by user code with MAP_GROWSDOWN flag // and then attached to VM. See notes in os_linux.cpp. if (thread->osthread()->expanding_stack() == 0) {
thread->osthread()->set_expanding_stack(); if (os::Linux::manually_expand_stack(thread, addr)) {
thread->osthread()->clear_expanding_stack(); returntrue;
}
thread->osthread()->clear_expanding_stack();
} else {
fatal("recursive segv. expanding stack.");
}
}
}
}
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) { // 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; if ((nm != NULL && nm->has_unsafe_access()) || (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc))) {
unsafe_access = true;
}
} elseif (sig == SIGSEGV &&
MacroAssembler::uses_implicit_null_check(info->si_addr)) { // Determination of interpreter/vtable stub/compiled code null exception
CodeBlob* cb = CodeCache::find_blob(pc); if (cb != NULL) {
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
}
} elseif (sig == SIGILL && *(int *)pc == NativeInstruction::not_entrant_illegal_instruction) { // Not entrant
stub = SharedRuntime::get_handle_wrong_method_stub();
}
} elseif ((thread->thread_state() == _thread_in_vm ||
thread->thread_state() == _thread_in_native) &&
sig == SIGBUS && thread->doing_unsafe_access()) {
unsafe_access = true;
}
// 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;
}
}
}
if (unsafe_access && stub == NULL) { // it can be an unsafe access and we haven't found // any other suitable exception reason, // so assume it is an unsafe access.
address next_pc = pc + Assembler::InstructionSize; if (UnsafeCopyMemory::contains_pc(pc)) {
next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
} #ifdef __thumb__ if (uc->uc_mcontext.arm_cpsr & PSR_T_BIT) {
next_pc = (address)((intptr_t)next_pc | 0x1);
} #endif
if (stub != NULL) { #ifdef __thumb__ if (uc->uc_mcontext.arm_cpsr & PSR_T_BIT) {
intptr_t p = (intptr_t)pc | 0x1;
pc = (address)p;
// Clear Thumb mode bit if we're redirected into the ARM ISA based code if (((intptr_t)stub & 0x1) == 0) {
uc->uc_mcontext.arm_cpsr &= ~PSR_T_BIT;
}
} else { // No Thumb2 compiled stubs are triggered from ARM ISA compiled JIT'd code today. // The support needs to be added if that changes
assert((((intptr_t)stub & 0x1) == 0), "can't return to Thumb code");
} #endif
// save all thread context in case we need to restore it if (thread != NULL) thread->set_saved_exception_pc(pc);
// 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::Posix::ucontext_get_pc(uc);
print_instructions(st, pc, Assembler::InstructionSize);
st->cr();
}
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.