8255711: Fix and unify hotspot signal handlers
Reviewed-by: coleenp, gziemski, dholmes
This commit is contained in:
parent
d99e1f6c29
commit
dd8e4ffbe5
@ -21,7 +21,7 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
JVM_handle_linux_signal
|
||||
JVM_handle_aix_signal
|
||||
numa_error
|
||||
numa_warn
|
||||
sysThreadAvailableStackWithSlack
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "jvm.h"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -71,10 +72,6 @@ extern "C" {
|
||||
static sigset_t check_signal_done;
|
||||
static bool check_signals = true;
|
||||
|
||||
// This boolean allows users to forward their own non-matching signals
|
||||
// to JVM_handle_bsd_signal/JVM_handle_linux_signal, harmlessly.
|
||||
static bool signal_handlers_are_installed = false;
|
||||
|
||||
debug_only(static bool signal_sets_initialized = false);
|
||||
static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs;
|
||||
struct sigaction sigact[NSIG];
|
||||
@ -261,6 +258,8 @@ static const struct {
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const char* get_signal_name(int sig, char* out, size_t outlen);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// sun.misc.Signal support
|
||||
|
||||
@ -313,6 +312,8 @@ static int check_pending_signals() {
|
||||
}
|
||||
} while (threadIsSuspended);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return 0; // Satisfy compiler
|
||||
}
|
||||
|
||||
int os::signal_wait() {
|
||||
@ -408,50 +409,6 @@ bool PosixSignals::chained_handler(int sig, siginfo_t* siginfo, void* context) {
|
||||
return chained;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// signal handling (except suspend/resume)
|
||||
|
||||
// This routine may be used by user applications as a "hook" to catch signals.
|
||||
// The user-defined signal handler must pass unrecognized signals to this
|
||||
// routine, and if it returns true (non-zero), then the signal handler must
|
||||
// return immediately. If the flag "abort_if_unrecognized" is true, then this
|
||||
// routine will never retun false (zero), but instead will execute a VM panic
|
||||
// routine kill the process.
|
||||
//
|
||||
// If this routine returns false, it is OK to call it again. This allows
|
||||
// the user-defined signal handler to perform checks either before or after
|
||||
// the VM performs its own checks. Naturally, the user code would be making
|
||||
// a serious error if it tried to handle an exception (such as a null check
|
||||
// or breakpoint) that the VM was generating for its own correct operation.
|
||||
//
|
||||
// This routine may recognize any of the following kinds of signals:
|
||||
// SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1.
|
||||
// It should be consulted by handlers for any of those signals.
|
||||
//
|
||||
// The caller of this routine must pass in the three arguments supplied
|
||||
// to the function referred to in the "sa_sigaction" (not the "sa_handler")
|
||||
// field of the structure passed to sigaction(). This routine assumes that
|
||||
// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART.
|
||||
//
|
||||
// Note that the VM will print warnings if it detects conflicting signal
|
||||
// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers".
|
||||
//
|
||||
|
||||
#if defined(BSD)
|
||||
extern "C" JNIEXPORT int JVM_handle_bsd_signal(int signo, siginfo_t* siginfo,
|
||||
void* ucontext,
|
||||
int abort_if_unrecognized);
|
||||
#elif defined(AIX)
|
||||
extern "C" JNIEXPORT int JVM_handle_aix_signal(int signo, siginfo_t* siginfo,
|
||||
void* ucontext,
|
||||
int abort_if_unrecognized);
|
||||
#else
|
||||
extern "C" JNIEXPORT int JVM_handle_linux_signal(int signo, siginfo_t* siginfo,
|
||||
void* ucontext,
|
||||
int abort_if_unrecognized);
|
||||
#endif
|
||||
|
||||
|
||||
///// Synchronous (non-deferrable) error signals (ILL, SEGV, FPE, BUS, TRAP):
|
||||
|
||||
// These signals are special because they cannot be deferred and, if they
|
||||
@ -502,21 +459,151 @@ void PosixSignals::unblock_error_signals() {
|
||||
::pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
}
|
||||
|
||||
// Renamed from 'signalHandler' to avoid collision with other shared libs.
|
||||
static void javaSignalHandler(int sig, siginfo_t* info, void* uc) {
|
||||
assert(info != NULL && uc != NULL, "it must be old kernel");
|
||||
class ErrnoPreserver: public StackObj {
|
||||
const int _saved;
|
||||
public:
|
||||
ErrnoPreserver() : _saved(errno) {}
|
||||
~ErrnoPreserver() { errno = _saved; }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// JVM_handle_(linux|aix|bsd)_signal()
|
||||
|
||||
// This routine is the shared part of the central hotspot signal handler. It can
|
||||
// also be called by a user application, if a user application prefers to do
|
||||
// signal handling itself - in that case it needs to pass signals the VM
|
||||
// internally uses on to the VM first.
|
||||
//
|
||||
// The user-defined signal handler must pass unrecognized signals to this
|
||||
// routine, and if it returns true (non-zero), then the signal handler must
|
||||
// return immediately. If the flag "abort_if_unrecognized" is true, then this
|
||||
// routine will never return false (zero), but instead will execute a VM panic
|
||||
// routine to kill the process.
|
||||
//
|
||||
// If this routine returns false, it is OK to call it again. This allows
|
||||
// the user-defined signal handler to perform checks either before or after
|
||||
// the VM performs its own checks. Naturally, the user code would be making
|
||||
// a serious error if it tried to handle an exception (such as a null check
|
||||
// or breakpoint) that the VM was generating for its own correct operation.
|
||||
//
|
||||
// This routine may recognize any of the following kinds of signals:
|
||||
// SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1.
|
||||
// It should be consulted by handlers for any of those signals.
|
||||
//
|
||||
// The caller of this routine must pass in the three arguments supplied
|
||||
// to the function referred to in the "sa_sigaction" (not the "sa_handler")
|
||||
// field of the structure passed to sigaction(). This routine assumes that
|
||||
// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART.
|
||||
//
|
||||
// Note that the VM will print warnings if it detects conflicting signal
|
||||
// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers".
|
||||
//
|
||||
|
||||
#if defined(BSD)
|
||||
#define JVM_HANDLE_XXX_SIGNAL JVM_handle_bsd_signal
|
||||
#elif defined(AIX)
|
||||
#define JVM_HANDLE_XXX_SIGNAL JVM_handle_aix_signal
|
||||
#elif defined(LINUX)
|
||||
#define JVM_HANDLE_XXX_SIGNAL JVM_handle_linux_signal
|
||||
#else
|
||||
#error who are you?
|
||||
#endif
|
||||
|
||||
extern "C" JNIEXPORT
|
||||
int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
|
||||
void* ucVoid, int abort_if_unrecognized)
|
||||
{
|
||||
assert(info != NULL && ucVoid != NULL, "sanity");
|
||||
|
||||
// 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,
|
||||
// this handler 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.
|
||||
|
||||
// Preserve errno value over signal handler.
|
||||
// (note: RAII ok here, even with JFR thread crash protection, see below).
|
||||
ErrnoPreserver ep;
|
||||
|
||||
// Unblock all synchronous error signals (see JDK-8252533)
|
||||
PosixSignals::unblock_error_signals();
|
||||
|
||||
int orig_errno = errno; // Preserve errno value over signal handler.
|
||||
#if defined(BSD)
|
||||
JVM_handle_bsd_signal(sig, info, uc, true);
|
||||
#elif defined(AIX)
|
||||
JVM_handle_aix_signal(sig, info, uc, true);
|
||||
#else
|
||||
JVM_handle_linux_signal(sig, info, uc, true);
|
||||
ucontext_t* const uc = (ucontext_t*) ucVoid;
|
||||
Thread* const t = Thread::current_or_null_safe();
|
||||
|
||||
// Handle JFR thread crash protection.
|
||||
// Note: this may cause us to longjmp away. Do not use any code before this
|
||||
// point which really needs any form of epilogue code running, eg RAII objects.
|
||||
os::ThreadCrashProtection::check_crash_protection(sig, t);
|
||||
|
||||
bool signal_was_handled = false;
|
||||
|
||||
// Handle assertion poison page accesses.
|
||||
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||
signal_was_handled = handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||
}
|
||||
#endif
|
||||
errno = orig_errno;
|
||||
|
||||
// Ignore SIGPIPE and SIGXFSZ (4229104, 6499219).
|
||||
if (sig == SIGPIPE || sig == SIGXFSZ) {
|
||||
PosixSignals::chained_handler(sig, info, ucVoid);
|
||||
signal_was_handled = true; // unconditionally.
|
||||
}
|
||||
|
||||
// Call platform dependent signal handler.
|
||||
if (!signal_was_handled) {
|
||||
JavaThread* const jt = (t != NULL && t->is_Java_thread()) ? (JavaThread*) t : NULL;
|
||||
signal_was_handled = PosixSignals::pd_hotspot_signal_handler(sig, info, uc, jt);
|
||||
}
|
||||
|
||||
// From here on, if the signal had not been handled, it is a fatal error.
|
||||
|
||||
// Give the chained signal handler - should it exist - a shot.
|
||||
if (!signal_was_handled) {
|
||||
signal_was_handled = PosixSignals::chained_handler(sig, info, ucVoid);
|
||||
}
|
||||
|
||||
// Invoke fatal error handling.
|
||||
if (!signal_was_handled && abort_if_unrecognized) {
|
||||
// Extract pc from context for the error handler to display.
|
||||
address pc = NULL;
|
||||
if (uc != NULL) {
|
||||
// prepare fault pc address for error reporting.
|
||||
if (S390_ONLY(sig == SIGILL || sig == SIGFPE) NOT_S390(false)) {
|
||||
pc = (address)info->si_addr;
|
||||
} else {
|
||||
pc = PosixSignals::ucontext_get_pc(uc);
|
||||
}
|
||||
}
|
||||
#if defined(ZERO) && !defined(PRODUCT)
|
||||
char buf[64];
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid,
|
||||
"\n#"
|
||||
"\n# /--------------------\\"
|
||||
"\n# | %-7s |"
|
||||
"\n# \\---\\ /--------------/"
|
||||
"\n# /"
|
||||
"\n# [-] |\\_/| "
|
||||
"\n# (+)=C |o o|__ "
|
||||
"\n# | | =-*-=__\\ "
|
||||
"\n# OOO c_c_(___)",
|
||||
get_signal_name(sig, buf, sizeof(buf)));
|
||||
#else
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
#endif
|
||||
// VMError should not return.
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
return signal_was_handled;
|
||||
}
|
||||
|
||||
// Entry point for the hotspot signal handler.
|
||||
static void javaSignalHandler(int sig, siginfo_t* info, void* ucVoid) {
|
||||
// Do not add any code here!
|
||||
// Only add code to either JVM_HANDLE_XXX_SIGNAL or PosixSignals::pd_hotspot_signal_handler.
|
||||
(void)JVM_HANDLE_XXX_SIGNAL(sig, info, ucVoid, true);
|
||||
}
|
||||
|
||||
static void UserHandler(int sig, void *siginfo, void *context) {
|
||||
@ -766,9 +853,7 @@ void os::run_periodic_checks() {
|
||||
do_signal_check(SIGBUS);
|
||||
do_signal_check(SIGPIPE);
|
||||
do_signal_check(SIGXFSZ);
|
||||
#if defined(PPC64)
|
||||
do_signal_check(SIGTRAP);
|
||||
#endif
|
||||
PPC64_ONLY(do_signal_check(SIGTRAP);)
|
||||
|
||||
// ReduceSignalUsage allows the user to override these handlers
|
||||
// see comments at the very top and jvm_md.h
|
||||
@ -935,7 +1020,6 @@ static bool is_valid_signal(int sig) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returned string is a constant. For unknown signals "UNKNOWN" is returned.
|
||||
static const char* get_signal_name(int sig, char* out, size_t outlen) {
|
||||
|
||||
const char* ret = NULL;
|
||||
@ -1075,7 +1159,7 @@ int os::get_signal_number(const char* signal_name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void set_signal_handler(int sig, bool set_installed) {
|
||||
void set_signal_handler(int sig) {
|
||||
// Check for overwrite.
|
||||
struct sigaction oldAct;
|
||||
sigaction(sig, (struct sigaction*)NULL, &oldAct);
|
||||
@ -1086,7 +1170,7 @@ void set_signal_handler(int sig, bool set_installed) {
|
||||
if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) &&
|
||||
oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) &&
|
||||
oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)javaSignalHandler)) {
|
||||
if (AllowUserSignalHandlers || !set_installed) {
|
||||
if (AllowUserSignalHandlers) {
|
||||
// Do not overwrite; user takes responsibility to forward to us.
|
||||
return;
|
||||
} else if (UseSignalChaining) {
|
||||
@ -1103,13 +1187,8 @@ void set_signal_handler(int sig, bool set_installed) {
|
||||
struct sigaction sigAct;
|
||||
sigfillset(&(sigAct.sa_mask));
|
||||
remove_error_signals_from_set(&(sigAct.sa_mask));
|
||||
sigAct.sa_handler = SIG_DFL;
|
||||
if (!set_installed) {
|
||||
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||
} else {
|
||||
sigAct.sa_sigaction = javaSignalHandler;
|
||||
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||
}
|
||||
sigAct.sa_sigaction = javaSignalHandler;
|
||||
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||
#if defined(__APPLE__)
|
||||
// Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV
|
||||
// (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages"
|
||||
@ -1136,87 +1215,75 @@ void set_signal_handler(int sig, bool set_installed) {
|
||||
assert(oldhand2 == oldhand, "no concurrent signal handler installation");
|
||||
}
|
||||
|
||||
// install signal handlers for signals that HotSpot needs to
|
||||
// handle in order to support Java-level exception handling.
|
||||
|
||||
bool PosixSignals::are_signal_handlers_installed() {
|
||||
return signal_handlers_are_installed;
|
||||
}
|
||||
|
||||
// install signal handlers for signals that HotSpot needs to
|
||||
// handle in order to support Java-level exception handling.
|
||||
void PosixSignals::install_signal_handlers() {
|
||||
if (!signal_handlers_are_installed) {
|
||||
signal_handlers_are_installed = true;
|
||||
|
||||
// signal-chaining
|
||||
typedef void (*signal_setting_t)();
|
||||
signal_setting_t begin_signal_setting = NULL;
|
||||
signal_setting_t end_signal_setting = NULL;
|
||||
begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
|
||||
dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting"));
|
||||
if (begin_signal_setting != NULL) {
|
||||
end_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
|
||||
dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
|
||||
get_signal_action = CAST_TO_FN_PTR(get_signal_t,
|
||||
dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
|
||||
libjsig_is_loaded = true;
|
||||
assert(UseSignalChaining, "should enable signal-chaining");
|
||||
}
|
||||
if (libjsig_is_loaded) {
|
||||
// Tell libjsig jvm is setting signal handlers
|
||||
(*begin_signal_setting)();
|
||||
}
|
||||
// signal-chaining
|
||||
typedef void (*signal_setting_t)();
|
||||
signal_setting_t begin_signal_setting = NULL;
|
||||
signal_setting_t end_signal_setting = NULL;
|
||||
begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
|
||||
dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting"));
|
||||
if (begin_signal_setting != NULL) {
|
||||
end_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
|
||||
dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
|
||||
get_signal_action = CAST_TO_FN_PTR(get_signal_t,
|
||||
dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
|
||||
libjsig_is_loaded = true;
|
||||
assert(UseSignalChaining, "should enable signal-chaining");
|
||||
}
|
||||
if (libjsig_is_loaded) {
|
||||
// Tell libjsig jvm is setting signal handlers
|
||||
(*begin_signal_setting)();
|
||||
}
|
||||
|
||||
set_signal_handler(SIGSEGV, true);
|
||||
set_signal_handler(SIGPIPE, true);
|
||||
set_signal_handler(SIGBUS, true);
|
||||
set_signal_handler(SIGILL, true);
|
||||
set_signal_handler(SIGFPE, true);
|
||||
#if defined(PPC64) || defined(AIX)
|
||||
set_signal_handler(SIGTRAP, true);
|
||||
#endif
|
||||
set_signal_handler(SIGXFSZ, true);
|
||||
set_signal_handler(SIGSEGV);
|
||||
set_signal_handler(SIGPIPE);
|
||||
set_signal_handler(SIGBUS);
|
||||
set_signal_handler(SIGILL);
|
||||
set_signal_handler(SIGFPE);
|
||||
PPC64_ONLY(set_signal_handler(SIGTRAP);)
|
||||
set_signal_handler(SIGXFSZ);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// In Mac OS X 10.4, CrashReporter will write a crash log for all 'fatal' signals, including
|
||||
// signals caught and handled by the JVM. To work around this, we reset the mach task
|
||||
// signal handler that's placed on our process by CrashReporter. This disables
|
||||
// CrashReporter-based reporting.
|
||||
//
|
||||
// This work-around is not necessary for 10.5+, as CrashReporter no longer intercedes
|
||||
// on caught fatal signals.
|
||||
//
|
||||
// Additionally, gdb installs both standard BSD signal handlers, and mach exception
|
||||
// handlers. By replacing the existing task exception handler, we disable gdb's mach
|
||||
// exception handling, while leaving the standard BSD signal handlers functional.
|
||||
kern_return_t kr;
|
||||
kr = task_set_exception_ports(mach_task_self(),
|
||||
EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC,
|
||||
MACH_PORT_NULL,
|
||||
EXCEPTION_STATE_IDENTITY,
|
||||
MACHINE_THREAD_STATE);
|
||||
// In Mac OS X 10.4, CrashReporter will write a crash log for all 'fatal' signals, including
|
||||
// signals caught and handled by the JVM. To work around this, we reset the mach task
|
||||
// signal handler that's placed on our process by CrashReporter. This disables
|
||||
// CrashReporter-based reporting.
|
||||
//
|
||||
// This work-around is not necessary for 10.5+, as CrashReporter no longer intercedes
|
||||
// on caught fatal signals.
|
||||
//
|
||||
// Additionally, gdb installs both standard BSD signal handlers, and mach exception
|
||||
// handlers. By replacing the existing task exception handler, we disable gdb's mach
|
||||
// exception handling, while leaving the standard BSD signal handlers functional.
|
||||
kern_return_t kr;
|
||||
kr = task_set_exception_ports(mach_task_self(),
|
||||
EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC,
|
||||
MACH_PORT_NULL,
|
||||
EXCEPTION_STATE_IDENTITY,
|
||||
MACHINE_THREAD_STATE);
|
||||
|
||||
assert(kr == KERN_SUCCESS, "could not set mach task signal handler");
|
||||
assert(kr == KERN_SUCCESS, "could not set mach task signal handler");
|
||||
#endif
|
||||
|
||||
if (libjsig_is_loaded) {
|
||||
// Tell libjsig jvm finishes setting signal handlers
|
||||
(*end_signal_setting)();
|
||||
}
|
||||
if (libjsig_is_loaded) {
|
||||
// Tell libjsig jvm finishes setting signal handlers
|
||||
(*end_signal_setting)();
|
||||
}
|
||||
|
||||
// We don't activate signal checker if libjsig is in place, we trust ourselves
|
||||
// and if UserSignalHandler is installed all bets are off.
|
||||
// Log that signal checking is off only if -verbose:jni is specified.
|
||||
if (CheckJNICalls) {
|
||||
if (libjsig_is_loaded) {
|
||||
log_debug(jni, resolve)("Info: libjsig is activated, all active signal checking is disabled");
|
||||
check_signals = false;
|
||||
}
|
||||
if (AllowUserSignalHandlers) {
|
||||
log_debug(jni, resolve)("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
|
||||
check_signals = false;
|
||||
}
|
||||
// We don't activate signal checker if libjsig is in place, we trust ourselves
|
||||
// and if UserSignalHandler is installed all bets are off.
|
||||
// Log that signal checking is off only if -verbose:jni is specified.
|
||||
if (CheckJNICalls) {
|
||||
if (libjsig_is_loaded) {
|
||||
log_debug(jni, resolve)("Info: libjsig is activated, all active signal checking is disabled");
|
||||
check_signals = false;
|
||||
}
|
||||
if (AllowUserSignalHandlers) {
|
||||
log_debug(jni, resolve)("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
|
||||
check_signals = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1354,9 +1421,7 @@ void PosixSignals::signal_sets_init() {
|
||||
sigaddset(&unblocked_sigs, SIGSEGV);
|
||||
sigaddset(&unblocked_sigs, SIGBUS);
|
||||
sigaddset(&unblocked_sigs, SIGFPE);
|
||||
#if defined(PPC64) || defined(AIX)
|
||||
sigaddset(&unblocked_sigs, SIGTRAP);
|
||||
#endif
|
||||
PPC64_ONLY(sigaddset(&unblocked_sigs, SIGTRAP);)
|
||||
sigaddset(&unblocked_sigs, SR_signum);
|
||||
|
||||
if (!ReduceSignalUsage) {
|
||||
|
@ -38,7 +38,11 @@ class PosixSignals : public AllStatic {
|
||||
|
||||
public:
|
||||
|
||||
static bool are_signal_handlers_installed();
|
||||
// The platform dependent parts of the central hotspot signal handler.
|
||||
// Returns true if the signal had been recognized and handled, false if not. If true, caller should
|
||||
// return from signal handling.
|
||||
static bool pd_hotspot_signal_handler(int sig, siginfo_t* info, ucontext_t* uc, JavaThread* thread);
|
||||
|
||||
static void install_signal_handlers();
|
||||
|
||||
static bool is_sig_ignored(int sig);
|
||||
|
@ -2144,6 +2144,8 @@ static int check_pending_signals() {
|
||||
}
|
||||
} while (threadIsSuspended);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return 0; // Satisfy compiler
|
||||
}
|
||||
|
||||
int os::signal_wait() {
|
||||
|
@ -168,43 +168,8 @@ frame os::current_frame() {
|
||||
return os::get_sender_for_C_frame(&tmp);
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrecognized) {
|
||||
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// 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_aix_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) {
|
||||
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return 1;
|
||||
} else {
|
||||
// Ignoring SIGPIPE - see bugs 4229104
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL) {
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
}
|
||||
else if(t->is_VM_thread()) {
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
// Decide if this trap can be handled by a stub.
|
||||
address stub = NULL;
|
||||
@ -226,8 +191,8 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
}
|
||||
}
|
||||
|
||||
if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) {
|
||||
goto run_chained_handler;
|
||||
if (info == NULL || uc == NULL) {
|
||||
return false; // Fatal error
|
||||
}
|
||||
|
||||
// If we are a java thread...
|
||||
@ -237,11 +202,11 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
if (sig == SIGSEGV && thread->is_in_full_stack(addr)) {
|
||||
// stack overflow
|
||||
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
|
||||
return 1; // continue
|
||||
return true; // continue
|
||||
} else if (stub != NULL) {
|
||||
goto run_stub;
|
||||
} else {
|
||||
goto report_and_die;
|
||||
return false; // Fatal error
|
||||
}
|
||||
} // end handle SIGSEGV inside stack boundaries
|
||||
|
||||
@ -281,17 +246,6 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
// happens rarely. In heap based and disjoint base compressd oop modes also loads
|
||||
// are used for null checks.
|
||||
|
||||
// A VM-related SIGILL may only occur if we are not in the zero page.
|
||||
// On AIX, we get a SIGILL if we jump to 0x0 or to somewhere else
|
||||
// in the zero page, because it is filled with 0x0. We ignore
|
||||
// explicit SIGILLs in the zero page.
|
||||
if (sig == SIGILL && (pc < (address) 0x200)) {
|
||||
if (TraceTraps) {
|
||||
tty->print_raw_cr("SIGILL happened inside zero page.");
|
||||
}
|
||||
goto report_and_die;
|
||||
}
|
||||
|
||||
int stop_type = -1;
|
||||
// Handle signal from NativeJump::patch_verified_entry().
|
||||
if (sig == SIGILL && nativeInstruction_at(pc)->is_sigill_zombie_not_entrant()) {
|
||||
@ -384,10 +338,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type);
|
||||
}
|
||||
|
||||
va_list detail_args;
|
||||
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
|
||||
pc, info, ucVoid, NULL, 0, 0);
|
||||
va_end(detail_args);
|
||||
return false; // Fatal error
|
||||
}
|
||||
|
||||
else if (sig == SIGBUS) {
|
||||
@ -403,7 +354,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
}
|
||||
next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc);
|
||||
os::Aix::ucontext_set_pc(uc, next_pc);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -428,7 +379,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
}
|
||||
next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc);
|
||||
os::Aix::ucontext_set_pc(uc, next_pc);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -450,32 +401,10 @@ run_stub:
|
||||
// Save all thread context in case we need to restore it.
|
||||
if (thread != NULL) thread->set_saved_exception_pc(pc);
|
||||
os::Aix::ucontext_set_pc(uc, stub);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
run_chained_handler:
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return 1;
|
||||
}
|
||||
if (!abort_if_unrecognized) {
|
||||
// caller wants another chance, so give it to him
|
||||
return 0;
|
||||
}
|
||||
|
||||
report_and_die:
|
||||
|
||||
// Use sigthreadmask instead of sigprocmask on AIX and unmask current signal.
|
||||
sigset_t newset;
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, sig);
|
||||
sigthreadmask(SIG_UNBLOCK, &newset, NULL);
|
||||
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return 0;
|
||||
return false; // Fatal error
|
||||
}
|
||||
|
||||
void os::Aix::init_thread_fpu_state(void) {
|
||||
|
@ -385,56 +385,14 @@ frame os::current_frame() {
|
||||
}
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
|
||||
// From IA32 System Programming Guide
|
||||
enum {
|
||||
trap_page_fault = 0xE
|
||||
};
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_bsd_signal(int sig,
|
||||
siginfo_t* info,
|
||||
void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// If crash protection is installed we may longjmp away and no destructors
|
||||
// for objects in this scope will be run.
|
||||
// So don't use any RAII utilities before crash protection is checked.
|
||||
os::ThreadCrashProtection::check_crash_protection(sig, 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_bsd_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 (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL ){
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
}
|
||||
else if(t->is_VM_thread()){
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
NOTE: does not seem to work on bsd.
|
||||
if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
|
||||
@ -455,7 +413,7 @@ JVM_handle_bsd_signal(int sig,
|
||||
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle ALL stack overflow variations here
|
||||
@ -466,7 +424,7 @@ JVM_handle_bsd_signal(int sig,
|
||||
if (thread->is_in_full_stack(addr)) {
|
||||
// stack overflow
|
||||
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
|
||||
return 1; // continue
|
||||
return true; // continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -678,29 +636,6 @@ JVM_handle_bsd_signal(int sig,
|
||||
return true;
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::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::Bsd::ucontext_get_pc(uc);
|
||||
}
|
||||
|
||||
// unmask current signal
|
||||
sigset_t newset;
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, sig);
|
||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -115,16 +115,10 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
return frame();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_bsd_signal(int sig,
|
||||
siginfo_t* info,
|
||||
void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// handle SafeFetch faults
|
||||
// handle SafeFetch faults the zero way
|
||||
if (sig == SIGSEGV || sig == SIGBUS) {
|
||||
sigjmp_buf* const pjb = get_jmp_buf_for_continuation();
|
||||
if (pjb) {
|
||||
@ -132,37 +126,6 @@ JVM_handle_bsd_signal(int sig,
|
||||
}
|
||||
}
|
||||
|
||||
// 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_bsd_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 (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL ){
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
}
|
||||
else if(t->is_VM_thread()){
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info != NULL && thread != NULL) {
|
||||
// Handle ALL stack overflow variations here
|
||||
if (sig == SIGSEGV || sig == SIGBUS) {
|
||||
@ -202,36 +165,6 @@ JVM_handle_bsd_signal(int sig,
|
||||
}*/
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!abort_if_unrecognized) {
|
||||
// caller wants another chance, so give it to him
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (sig == SIGSEGV) {
|
||||
fatal("\n#"
|
||||
"\n# /--------------------\\"
|
||||
"\n# | segmentation fault |"
|
||||
"\n# \\---\\ /--------------/"
|
||||
"\n# /"
|
||||
"\n# [-] |\\_/| "
|
||||
"\n# (+)=C |o o|__ "
|
||||
"\n# | | =-*-=__\\ "
|
||||
"\n# OOO c_c_(___)");
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
const char *fmt =
|
||||
"caught unhandled signal " INT32_FORMAT " at address " PTR_FORMAT;
|
||||
char buf[128];
|
||||
|
||||
sprintf(buf, fmt, sig, info->si_addr);
|
||||
fatal(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -164,57 +164,9 @@ NOINLINE frame os::current_frame() {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_linux_signal(int sig,
|
||||
siginfo_t* info,
|
||||
void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// If crash protection is installed we may longjmp away and no destructors
|
||||
// for objects in this scope will be run.
|
||||
// So don't use any RAII utilities before crash protection is checked.
|
||||
os::ThreadCrashProtection::check_crash_protection(sig, 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 (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL ){
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
}
|
||||
else if(t->is_VM_thread()){
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
NOTE: does not seem to work on linux.
|
||||
if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
|
||||
@ -235,7 +187,7 @@ JVM_handle_linux_signal(int sig,
|
||||
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
address addr = (address) info->si_addr;
|
||||
@ -250,7 +202,7 @@ JVM_handle_linux_signal(int sig,
|
||||
// check if fault address is within thread stack
|
||||
if (thread->is_in_full_stack(addr)) {
|
||||
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
|
||||
return 1; // continue
|
||||
return true; // continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,10 +245,7 @@ JVM_handle_linux_signal(int sig,
|
||||
tty->print_cr("trap: %s: (SIGILL)", msg);
|
||||
}
|
||||
|
||||
va_list detail_args;
|
||||
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
|
||||
pc, info, ucVoid, NULL, 0, 0);
|
||||
va_end(detail_args);
|
||||
return false; // Fatal error
|
||||
}
|
||||
else
|
||||
|
||||
@ -342,30 +291,8 @@ JVM_handle_linux_signal(int sig,
|
||||
return true;
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
}
|
||||
return false; // Mute compiler
|
||||
|
||||
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(uc);
|
||||
}
|
||||
|
||||
// unmask current signal
|
||||
sigset_t newset;
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, sig);
|
||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return true; // Mute compiler
|
||||
}
|
||||
|
||||
void os::Linux::init_thread_fpu_state(void) {
|
||||
|
@ -241,18 +241,9 @@ address check_vfp3_32_fault_instr = NULL;
|
||||
address check_simd_fault_instr = NULL;
|
||||
address check_mp_ext_fault_instr = NULL;
|
||||
|
||||
// Utility functions
|
||||
|
||||
extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||
void* ucVoid, int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// If crash protection is installed we may longjmp away and no destructors
|
||||
// for objects in this scope will be run.
|
||||
// So don't use any RAII utilities before crash protection is checked.
|
||||
os::ThreadCrashProtection::check_crash_protection(sig, t);
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
if (sig == SIGILL &&
|
||||
((info->si_addr == (caddr_t)check_simd_fault_instr)
|
||||
@ -266,44 +257,6 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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 (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL ){
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
}
|
||||
else if(t->is_VM_thread()){
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
address stub = NULL;
|
||||
address pc = NULL;
|
||||
bool unsafe_access = false;
|
||||
@ -317,7 +270,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
// check if fault address is within thread stack
|
||||
if (thread->is_in_full_stack(addr)) {
|
||||
@ -331,7 +284,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||
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.
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
} else if (overflow_state->in_stack_red_zone(addr)) {
|
||||
// Fatal red zone violation. Disable the guard pages and fall through
|
||||
@ -347,7 +300,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||
thread->osthread()->set_expanding_stack();
|
||||
if (os::Linux::manually_expand_stack(thread, addr)) {
|
||||
thread->osthread()->clear_expanding_stack();
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
thread->osthread()->clear_expanding_stack();
|
||||
} else {
|
||||
@ -440,30 +393,8 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||
return true;
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::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(uc);
|
||||
}
|
||||
|
||||
// unmask current signal
|
||||
sigset_t newset;
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, sig);
|
||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void os::Linux::init_thread_fpu_state(void) {
|
||||
|
@ -188,32 +188,8 @@ frame os::current_frame() {
|
||||
return os::get_sender_for_C_frame(&tmp);
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_linux_signal(int sig,
|
||||
siginfo_t* info,
|
||||
void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// 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) {
|
||||
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
// Ignoring SIGPIPE - see bugs 4229104
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
// Make the signal handler transaction-aware by checking the existence of a
|
||||
// second (transactional) context with MSR TS bits active. If the signal is
|
||||
@ -237,26 +213,6 @@ JVM_handle_linux_signal(int sig,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL) {
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
} else if(t->is_VM_thread()) {
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Moved SafeFetch32 handling outside thread!=NULL conditional block to make
|
||||
// it work if no associated JavaThread object exists.
|
||||
if (uc) {
|
||||
@ -297,7 +253,7 @@ JVM_handle_linux_signal(int sig,
|
||||
if (thread->is_in_full_stack(addr)) {
|
||||
// stack overflow
|
||||
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
|
||||
return 1; // continue
|
||||
return true; // continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,17 +262,6 @@ JVM_handle_linux_signal(int sig,
|
||||
// Java thread running in Java code => find exception handler if any
|
||||
// a fault inside compiled code, the interpreter, or a stub
|
||||
|
||||
// A VM-related SIGILL may only occur if we are not in the zero page.
|
||||
// On AIX, we get a SIGILL if we jump to 0x0 or to somewhere else
|
||||
// in the zero page, because it is filled with 0x0. We ignore
|
||||
// explicit SIGILLs in the zero page.
|
||||
if (sig == SIGILL && (pc < (address) 0x200)) {
|
||||
if (TraceTraps) {
|
||||
tty->print_raw_cr("SIGILL happened inside zero page.");
|
||||
}
|
||||
goto report_and_die;
|
||||
}
|
||||
|
||||
CodeBlob *cb = NULL;
|
||||
int stop_type = -1;
|
||||
// Handle signal from NativeJump::patch_verified_entry().
|
||||
@ -404,10 +349,7 @@ JVM_handle_linux_signal(int sig,
|
||||
tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type);
|
||||
}
|
||||
|
||||
va_list detail_args;
|
||||
VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread,
|
||||
pc, info, ucVoid, NULL, 0, 0);
|
||||
va_end(detail_args);
|
||||
return false; // Fatal error
|
||||
}
|
||||
|
||||
else if (sig == SIGBUS) {
|
||||
@ -465,31 +407,8 @@ JVM_handle_linux_signal(int sig,
|
||||
return true;
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::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(uc);
|
||||
}
|
||||
|
||||
report_and_die:
|
||||
// unmask current signal
|
||||
sigset_t newset;
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, sig);
|
||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void os::Linux::init_thread_fpu_state(void) {
|
||||
|
@ -204,59 +204,8 @@ frame os::current_frame() {
|
||||
}
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_linux_signal(int sig,
|
||||
siginfo_t* info,
|
||||
void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// If crash protection is installed we may longjmp away and no destructors
|
||||
// for objects in this scope will be run.
|
||||
// So don't use any RAII utilities before crash protection is checked.
|
||||
os::ThreadCrashProtection::check_crash_protection(sig, 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) {
|
||||
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
warning("Ignoring SIGPIPE - see bug 4229104");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL) {
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
} else if(t->is_VM_thread()) {
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
// Moved SafeFetch32 handling outside thread!=NULL conditional block to make
|
||||
// it work if no associated JavaThread object exists.
|
||||
@ -294,7 +243,7 @@ JVM_handle_linux_signal(int sig,
|
||||
if (thread->is_in_full_stack(addr)) {
|
||||
// stack overflow
|
||||
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
|
||||
return 1; // continue
|
||||
return true; // continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -418,38 +367,8 @@ JVM_handle_linux_signal(int sig,
|
||||
return true;
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::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(uc);
|
||||
}
|
||||
|
||||
// unmask current signal
|
||||
sigset_t newset;
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, sig);
|
||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||
|
||||
// Hand down correct pc for SIGILL, SIGFPE. pc from context
|
||||
// usually points to the instruction after the failing instruction.
|
||||
// Note: this should be combined with the trap_pc handling above,
|
||||
// because it handles the same issue.
|
||||
if (sig == SIGILL || sig == SIGFPE) {
|
||||
pc = (address)info->si_addr;
|
||||
}
|
||||
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void os::Linux::init_thread_fpu_state(void) {
|
||||
|
@ -200,58 +200,10 @@ enum {
|
||||
trap_page_fault = 0xE
|
||||
};
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_linux_signal(int sig,
|
||||
siginfo_t* info,
|
||||
void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
|
||||
// If crash protection is installed we may longjmp away and no destructors
|
||||
// for objects in this scope will be run.
|
||||
// So don't use any RAII utilities before crash protection is checked.
|
||||
os::ThreadCrashProtection::check_crash_protection(sig, 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 (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||
if (handle_assert_poison_fault(ucVoid, info->si_addr)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL ){
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
}
|
||||
else if(t->is_VM_thread()){
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
/*
|
||||
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
|
||||
@ -271,7 +223,7 @@ JVM_handle_linux_signal(int sig,
|
||||
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef AMD64
|
||||
@ -292,7 +244,7 @@ JVM_handle_linux_signal(int sig,
|
||||
if (thread->is_in_full_stack(addr)) {
|
||||
// stack overflow
|
||||
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
|
||||
return 1; // continue
|
||||
return true; // continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -469,30 +421,7 @@ JVM_handle_linux_signal(int sig,
|
||||
return true;
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::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(uc);
|
||||
}
|
||||
|
||||
// unmask current signal
|
||||
sigset_t newset;
|
||||
sigemptyset(&newset);
|
||||
sigaddset(&newset, sig);
|
||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return true; // Mute compiler
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::Linux::init_thread_fpu_state(void) {
|
||||
|
@ -111,14 +111,8 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
return frame(NULL, NULL); // silence compile warnings
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_linux_signal(int sig,
|
||||
siginfo_t* info,
|
||||
void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
ucontext_t* uc = (ucontext_t*) ucVoid;
|
||||
|
||||
Thread* t = Thread::current_or_null_safe();
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
ucontext_t* uc, JavaThread* thread) {
|
||||
|
||||
// handle SafeFetch faults
|
||||
if (sig == SIGSEGV || sig == SIGBUS) {
|
||||
@ -128,37 +122,6 @@ JVM_handle_linux_signal(int sig,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
} else {
|
||||
// Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
JavaThread* thread = NULL;
|
||||
VMThread* vmthread = NULL;
|
||||
if (PosixSignals::are_signal_handlers_installed()) {
|
||||
if (t != NULL ){
|
||||
if(t->is_Java_thread()) {
|
||||
thread = t->as_Java_thread();
|
||||
}
|
||||
else if(t->is_VM_thread()){
|
||||
vmthread = (VMThread *)t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info != NULL && thread != NULL) {
|
||||
// Handle ALL stack overflow variations here
|
||||
if (sig == SIGSEGV) {
|
||||
@ -216,47 +179,8 @@ JVM_handle_linux_signal(int sig,
|
||||
}*/
|
||||
}
|
||||
|
||||
// signal-chaining
|
||||
if (PosixSignals::chained_handler(sig, info, ucVoid)) {
|
||||
return true;
|
||||
}
|
||||
return false; // Fatal error
|
||||
|
||||
if (!abort_if_unrecognized) {
|
||||
// caller wants another chance, so give it to him
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (sig == SIGSEGV) {
|
||||
fatal("\n#"
|
||||
"\n# /--------------------\\"
|
||||
"\n# | segmentation fault |"
|
||||
"\n# \\---\\ /--------------/"
|
||||
"\n# /"
|
||||
"\n# [-] |\\_/| "
|
||||
"\n# (+)=C |o o|__ "
|
||||
"\n# | | =-*-=__\\ "
|
||||
"\n# OOO c_c_(___)");
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
char buf[128];
|
||||
char exc_buf[32];
|
||||
|
||||
if (os::exception_name(sig, exc_buf, sizeof(exc_buf))) {
|
||||
bool sent_by_kill = (info != NULL && os::signal_sent_by_kill(info));
|
||||
snprintf(buf, sizeof(buf), "caught unhandled signal: %s %s",
|
||||
exc_buf, sent_by_kill ? "(sent by kill)" : "");
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "caught unhandled signal: %d", sig);
|
||||
}
|
||||
|
||||
// Silence -Wformat-security warning for fatal()
|
||||
PRAGMA_DIAG_PUSH
|
||||
PRAGMA_FORMAT_NONLITERAL_IGNORED
|
||||
fatal(buf);
|
||||
PRAGMA_DIAG_POP
|
||||
return true; // silence compiler warnings
|
||||
}
|
||||
|
||||
void os::Linux::init_thread_fpu_state(void) {
|
||||
|
@ -755,7 +755,7 @@ const intx ObjectAlignmentInBytes = 8;
|
||||
"tables") \
|
||||
\
|
||||
product(bool, AllowUserSignalHandlers, false, \
|
||||
"Do not complain if the application installs signal handlers " \
|
||||
"Application will install primary signal handlers for the JVM " \
|
||||
"(Unix only)") \
|
||||
\
|
||||
product(bool, UseSignalChaining, true, \
|
||||
|
@ -116,9 +116,6 @@ class VMError : public AllStatic {
|
||||
// and the offending address points into CDS store.
|
||||
static void check_failing_cds_access(outputStream* st, const void* siginfo);
|
||||
|
||||
static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo,
|
||||
void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7);
|
||||
|
||||
// Timeout handling.
|
||||
// Hook functions for platform dependend functionality:
|
||||
static void reporting_started();
|
||||
@ -146,6 +143,9 @@ public:
|
||||
static void print_vm_info(outputStream* st);
|
||||
|
||||
// main error reporting function
|
||||
static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo,
|
||||
void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7);
|
||||
|
||||
static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args,
|
||||
Thread* thread, address pc, void* siginfo, void* context,
|
||||
const char* filename, int lineno, size_t size) ATTRIBUTE_PRINTF(3, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user