summaryrefslogtreecommitdiffstats
path: root/runtime/fault_handler.cc
diff options
context:
space:
mode:
authorDave Allison <dallison@google.com>2014-08-29 12:06:16 -0700
committerDave Allison <dallison@google.com>2014-09-04 10:27:48 -0700
commit0c2894b5db7ad9ccc44f2ac37034cdc2bb05cda7 (patch)
treef0b95af077b55ee06bc9b3b1f4a4d04c743a5f13 /runtime/fault_handler.cc
parent5355835411cafcc2772e061cb7aef3b8ca1e6ea1 (diff)
downloadart-0c2894b5db7ad9ccc44f2ac37034cdc2bb05cda7.zip
art-0c2894b5db7ad9ccc44f2ac37034cdc2bb05cda7.tar.gz
art-0c2894b5db7ad9ccc44f2ac37034cdc2bb05cda7.tar.bz2
Make nested signal more generic
This moves the nested signal catching code up to a slightly higher level in the fault manager. Originally it was down in the DumpJavaStack function but it needs to be up in the caller of that to allow for other handlers like the stack dumper. Change-Id: I31029f555dd9b501f4b5c0ed5c95777004873126
Diffstat (limited to 'runtime/fault_handler.cc')
-rw-r--r--runtime/fault_handler.cc152
1 files changed, 78 insertions, 74 deletions
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 25f87c5..cc1038c 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -151,17 +151,78 @@ void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
// We hit a signal we didn't handle. This might be something for which
// we can give more information about so call all registered handlers to see
// if it is.
- for (const auto& handler : other_handlers_) {
- if (handler->Action(sig, info, context)) {
- return;
+
+ Thread* self = Thread::Current();
+
+ // Now set up the nested signal handler.
+
+ // Shutdown the fault manager so that it will remove the signal chain for
+ // SIGSEGV and we call the real sigaction.
+ fault_manager.Shutdown();
+
+ // The action for SIGSEGV should be the default handler now.
+
+ // Unblock the signals we allow so that they can be delivered in the signal handler.
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGSEGV);
+ sigaddset(&sigset, SIGABRT);
+ pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
+
+ // If we get a signal in this code we want to invoke our nested signal
+ // handler.
+ struct sigaction action, oldsegvaction, oldabortaction;
+ action.sa_sigaction = art_nested_signal_handler;
+
+ // Explicitly mask out SIGSEGV and SIGABRT from the nested signal handler. This
+ // should be the default but we definitely don't want these happening in our
+ // nested signal handler.
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGSEGV);
+ sigaddset(&action.sa_mask, SIGABRT);
+
+ action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+#if !defined(__APPLE__) && !defined(__mips__)
+ action.sa_restorer = nullptr;
+#endif
+
+ bool signal_handled = false;
+
+ // Catch SIGSEGV and SIGABRT to invoke our nested handler
+ int e1 = sigaction(SIGSEGV, &action, &oldsegvaction);
+ int e2 = sigaction(SIGABRT, &action, &oldabortaction);
+ if (e1 != 0 || e2 != 0) {
+ LOG(ERROR) << "Unable to set up nested signal handler";
+ } else {
+ // Save the current state and call the handlers. If anything causes a signal
+ // our nested signal handler will be invoked and this will longjmp to the saved
+ // state.
+ if (setjmp(*self->GetNestedSignalState()) == 0) {
+ for (const auto& handler : other_handlers_) {
+ if (handler->Action(sig, info, context)) {
+ signal_handled = true;
+ break;
+ }
+ }
+ } else {
+ LOG(ERROR) << "Nested signal detected - original signal being reported";
}
+
+ // Restore the signal handlers.
+ sigaction(SIGSEGV, &oldsegvaction, nullptr);
+ sigaction(SIGABRT, &oldabortaction, nullptr);
}
- // Set a breakpoint in this function to catch unhandled signals.
- art_sigsegv_fault();
+ // Now put the fault manager back in place.
+ fault_manager.Init();
+
+ if (!signal_handled) {
+ // Set a breakpoint in this function to catch unhandled signals.
+ art_sigsegv_fault();
- // Pass this on to the next handler in the chain, or the default if none.
- InvokeUserSignalHandler(sig, info, context);
+ // Pass this on to the next handler in the chain, or the default if none.
+ InvokeUserSignalHandler(sig, info, context);
+ }
}
void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) {
@@ -311,75 +372,18 @@ bool JavaStackTraceHandler::Action(int sig, siginfo_t* siginfo, void* context) {
uintptr_t sp = 0;
Thread* self = Thread::Current();
- // Shutdown the fault manager so that it will remove the signal chain for
- // SIGSEGV and we call the real sigaction.
- fault_manager.Shutdown();
-
- // The action for SIGSEGV should be the default handler now.
-
- // Unblock the signals we allow so that they can be delivered in the signal handler.
- sigset_t sigset;
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGSEGV);
- sigaddset(&sigset, SIGABRT);
- pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
-
- // If we get a signal in this code we want to invoke our nested signal
- // handler.
- struct sigaction action, oldsegvaction, oldabortaction;
- action.sa_sigaction = art_nested_signal_handler;
-
- // Explictly mask out SIGSEGV and SIGABRT from the nested signal handler. This
- // should be the default but we definitely don't want these happening in our
- // nested signal handler.
- sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGSEGV);
- sigaddset(&action.sa_mask, SIGABRT);
-
- action.sa_flags = SA_SIGINFO | SA_ONSTACK;
-#if !defined(__APPLE__) && !defined(__mips__)
- action.sa_restorer = nullptr;
-#endif
-
- // Catch SIGSEGV and SIGABRT to invoke our nested handler
- int e1 = sigaction(SIGSEGV, &action, &oldsegvaction);
- int e2 = sigaction(SIGABRT, &action, &oldabortaction);
- if (e1 != 0 || e2 != 0) {
- LOG(ERROR) << "Unable to register nested signal handler - no stack trace possible";
- // If sigaction failed we have a serious problem. We cannot catch
- // any failures in the stack tracer and it's likely to occur since
- // the program state is bad. Therefore we don't even try to give
- // a stack trace.
- } else {
- // Save the current state and try to dump the stack. If this causes a signal
- // our nested signal handler will be invoked and this will longjmp to the saved
- // state.
- if (setjmp(*self->GetNestedSignalState()) == 0) {
- manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp);
- // Inside of generated code, sp[0] is the method, so sp is the frame.
- StackReference<mirror::ArtMethod>* frame =
- reinterpret_cast<StackReference<mirror::ArtMethod>*>(sp);
- self->SetTopOfStack(frame, 0); // Since we don't necessarily have a dex pc, pass in 0.
+ manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp);
+ // Inside of generated code, sp[0] is the method, so sp is the frame.
+ StackReference<mirror::ArtMethod>* frame =
+ reinterpret_cast<StackReference<mirror::ArtMethod>*>(sp);
+ self->SetTopOfStack(frame, 0); // Since we don't necessarily have a dex pc, pass in 0.
#ifdef TEST_NESTED_SIGNAL
- // To test the nested signal handler we raise a signal here. This will cause the
- // nested signal handler to be called and perform a longjmp back to the setjmp
- // above.
- abort();
+ // To test the nested signal handler we raise a signal here. This will cause the
+ // nested signal handler to be called and perform a longjmp back to the setjmp
+ // above.
+ abort();
#endif
- self->DumpJavaStack(LOG(ERROR));
- } else {
- LOG(ERROR) << "Stack trace aborted due to nested signal - original signal being reported";
- }
-
- // Restore the signal handlers.
- sigaction(SIGSEGV, &oldsegvaction, nullptr);
- sigaction(SIGABRT, &oldabortaction, nullptr);
- }
-
- // Now put the fault manager back in place.
- fault_manager.Init();
-
- // And we're done.
+ self->DumpJavaStack(LOG(ERROR));
}
return false; // Return false since we want to propagate the fault to the main signal handler.