/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This file is part of SableVM. * * See the file "LICENSE" for Copyright information and the * * terms and conditions for copying, distribution and * * modification of SableVM. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* ---------------------------------------------------------------------- _svmf_initialization_unrecoverable_exception ---------------------------------------------------------------------- */ static void _svmf_initialization_unrecoverable_exception (_svmt_JNIEnv *env) { siglongjmp (env->vm->initialization->unrecoverable_exception_handler, 1); } #ifdef _SABLEVM_SIGNALS_FOR_EXCEPTIONS /* we remember previously established signal handlers, so that we can delegate back to them when we don't handle a signal. */ static struct sigaction _svmv_old_sigsegv; static struct sigaction _svmv_old_sigfpe; /* ---------------------------------------------------------------------- _svmf_signal_throw ---------------------------------------------------------------------- */ static void _svmf_signal_throw (_svmt_JNIEnv *env, jint signal_code) { assert (env->signal_code == SVM_SIGNAL_NONE); if (env->signal_handler == NULL) { _svmt_JavaVM *vm = env->vm; if (vm->initialization == NULL) { return; /* delegate the signal */ } _svmf_initialization_unrecoverable_exception (env); } env->signal_code = signal_code; siglongjmp (*(env->signal_handler), 1); } /* ---------------------------------------------------------------------- _svmf_internal_sigaction ---------------------------------------------------------------------- */ static void _svmf_internal_sigaction (int signo, siginfo_t * info, void *ignored) { _svmt_JNIEnv *env; /* find the current thread */ env = _svmf_get_current_env (); if (env == NULL) { /* This thread is not attached to VM, so let's delegate to previous handler, if there was one */ goto delegate; } switch (signo) { case SIGSEGV: { #ifndef NDEBUG if (!(env->sigsegv_expected)) { _svmm_fatal_error ("unexpected segmentation fault"); } else { /* reset flag */ env->sigsegv_expected = JNI_FALSE; } #endif /* not NDEBUG */ _svmf_signal_throw (env, SVM_SIGNAL_NULL_POINTER_EXCEPTION); goto delegate; } break; case SIGFPE: { switch (info->si_code) { case FPE_INTDIV: { #ifndef NDEBUG if (!(env->sigfpe_expected)) { _svmm_fatal_error ("unexpected floating point signal"); } else { env->sigfpe_expected = JNI_FALSE; } #endif /* not NDEBUG */ _svmf_signal_throw (env, SVM_SIGNAL_ARITHMETIC_EXCEPTION); goto delegate; } break; case FPE_INTOVF: case FPE_FLTDIV: case FPE_FLTOVF: case FPE_FLTUND: case FPE_FLTRES: case FPE_FLTINV: case FPE_FLTSUB: default: { _svmm_fatal_error ("unexpected floating point signal"); } break; } } break; default: { /* this signal handler shouldn't be registered to catch these! */ _svmm_fatal_error ("impossible control flow"); } } return; delegate: /* find out if there was another signal handler before we set our own. If yes call it. If not, abort (as the process would have core dumped, anyway). Of course, we don't support ignoring (SIG_IGN) these signals, as it would leave us in an ugly infinite loop. */ switch (signo) { case SIGSEGV: { if ((_svmv_old_sigsegv.sa_flags & SA_SIGINFO) != 0) { _svmv_old_sigsegv.sa_sigaction (signo, info, ignored); } else if ((_svmv_old_sigsegv.sa_handler != SIG_DFL) && (_svmv_old_sigsegv.sa_handler != SIG_IGN)) { _svmv_old_sigsegv.sa_handler (signo); } else { _svmm_fatal_error ("unhandled segmentation fault"); } } break; case SIGFPE: { if ((_svmv_old_sigfpe.sa_flags & SA_SIGINFO) != 0) { _svmv_old_sigfpe.sa_sigaction (signo, info, ignored); } else if ((_svmv_old_sigfpe.sa_handler != SIG_DFL) && (_svmv_old_sigfpe.sa_handler != SIG_IGN)) { _svmv_old_sigfpe.sa_handler (signo); } else { _svmm_fatal_error ("unhandled floating point signal"); } } break; default: { /* this signal handler shouldn't be registered to catch these! */ _svmm_fatal_error ("impossible control flow"); } break; } } #endif /* _SABLEVM_SIGNALS_FOR_EXCEPTIONS */ /* ---------------------------------------------------------------------- _svmf_error_init ---------------------------------------------------------------------- */ static jint _svmf_error_init (void) { #ifdef _SABLEVM_SIGNALS_FOR_EXCEPTIONS struct sigaction sa; memset (&sa, 0, sizeof (sa)); /* mask all signals handled by the signal handler */ if (sigemptyset (&sa.sa_mask) != 0) { goto error; } if (sigaddset (&sa.sa_mask, SIGSEGV) != 0) { goto error; } if (sigaddset (&sa.sa_mask, SIGFPE) != 0) { goto error; } /* use extended info version */ sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = _svmf_internal_sigaction; if (sigaction (SIGSEGV, &sa, &_svmv_old_sigsegv) != 0) { goto error; } if (sigaction (SIGFPE, &sa, &_svmv_old_sigfpe) != 0) { goto error; } return JNI_OK; error: return JNI_ERR; #else return JNI_OK; #endif /* _SABLEVM_SIGNALS_FOR_EXCEPTIONS */ }