summaryrefslogtreecommitdiff
path: root/runtime/fault_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/fault_handler.cc')
-rw-r--r--runtime/fault_handler.cc184
1 files changed, 120 insertions, 64 deletions
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index dd28f3658b..a3c1f3bdf5 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -16,17 +16,19 @@
#include "fault_handler.h"
-#include <atomic>
#include <string.h>
#include <sys/mman.h>
#include <sys/ucontext.h>
+#include <atomic>
+
#include "art_method-inl.h"
#include "base/logging.h" // For VLOG
#include "base/membarrier.h"
#include "base/safe_copy.h"
#include "base/stl_util.h"
#include "dex/dex_file_types.h"
+#include "gc/heap.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "mirror/class.h"
@@ -49,64 +51,128 @@ extern "C" NO_INLINE __attribute__((visibility("default"))) void art_sigsegv_fau
}
// Signal handler called on SIGSEGV.
-static bool art_fault_handler(int sig, siginfo_t* info, void* context) {
- return fault_manager.HandleFault(sig, info, context);
+static bool art_sigsegv_handler(int sig, siginfo_t* info, void* context) {
+ return fault_manager.HandleSigsegvFault(sig, info, context);
+}
+
+// Signal handler called on SIGBUS.
+static bool art_sigbus_handler(int sig, siginfo_t* info, void* context) {
+ return fault_manager.HandleSigbusFault(sig, info, context);
}
FaultManager::FaultManager()
: generated_code_ranges_lock_("FaultHandler generated code ranges lock",
LockLevel::kGenericBottomLock),
- initialized_(false) {
- sigaction(SIGSEGV, nullptr, &oldaction_);
-}
+ initialized_(false) {}
FaultManager::~FaultManager() {
}
-void FaultManager::Init() {
- CHECK(!initialized_);
- sigset_t mask;
- sigfillset(&mask);
- sigdelset(&mask, SIGABRT);
- sigdelset(&mask, SIGBUS);
- sigdelset(&mask, SIGFPE);
- sigdelset(&mask, SIGILL);
- sigdelset(&mask, SIGSEGV);
-
- SigchainAction sa = {
- .sc_sigaction = art_fault_handler,
- .sc_mask = mask,
- .sc_flags = 0UL,
- };
-
- AddSpecialSignalHandlerFn(SIGSEGV, &sa);
-
- // Notify the kernel that we intend to use a specific `membarrier()` command.
- int result = art::membarrier(MembarrierCommand::kRegisterPrivateExpedited);
- if (result != 0) {
- LOG(WARNING) << "FaultHandler: MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED failed: "
- << errno << " " << strerror(errno);
+static const char* SignalCodeName(int sig, int code) {
+ if (sig == SIGSEGV) {
+ switch (code) {
+ case SEGV_MAPERR: return "SEGV_MAPERR";
+ case SEGV_ACCERR: return "SEGV_ACCERR";
+ case 8: return "SEGV_MTEAERR";
+ case 9: return "SEGV_MTESERR";
+ default: return "SEGV_UNKNOWN";
+ }
+ } else if (sig == SIGBUS) {
+ switch (code) {
+ case BUS_ADRALN: return "BUS_ADRALN";
+ case BUS_ADRERR: return "BUS_ADRERR";
+ case BUS_OBJERR: return "BUS_OBJERR";
+ default: return "BUS_UNKNOWN";
+ }
+ } else {
+ return "UNKNOWN";
}
+}
- {
- MutexLock lock(Thread::Current(), generated_code_ranges_lock_);
- for (size_t i = 0; i != kNumLocalGeneratedCodeRanges; ++i) {
- GeneratedCodeRange* next = (i + 1u != kNumLocalGeneratedCodeRanges)
- ? &generated_code_ranges_storage_[i + 1u]
- : nullptr;
- generated_code_ranges_storage_[i].next.store(next, std::memory_order_relaxed);
- generated_code_ranges_storage_[i].start = nullptr;
- generated_code_ranges_storage_[i].size = 0u;
- }
- free_generated_code_ranges_ = generated_code_ranges_storage_;
+static std::ostream& PrintSignalInfo(std::ostream& os, siginfo_t* info) {
+ os << " si_signo: " << info->si_signo << " (" << strsignal(info->si_signo) << ")\n"
+ << " si_code: " << info->si_code
+ << " (" << SignalCodeName(info->si_signo, info->si_code) << ")";
+ if (info->si_signo == SIGSEGV || info->si_signo == SIGBUS) {
+ os << "\n" << " si_addr: " << info->si_addr;
}
+ return os;
+}
- initialized_ = true;
+static bool InstallSigbusHandler() {
+ return gUseUserfaultfd &&
+ Runtime::Current()->GetHeap()->MarkCompactCollector()->IsUsingSigbusFeature();
+}
+
+void FaultManager::Init(bool use_sig_chain) {
+ CHECK(!initialized_);
+ if (use_sig_chain) {
+ sigset_t mask;
+ sigfillset(&mask);
+ sigdelset(&mask, SIGABRT);
+ sigdelset(&mask, SIGBUS);
+ sigdelset(&mask, SIGFPE);
+ sigdelset(&mask, SIGILL);
+ sigdelset(&mask, SIGSEGV);
+
+ SigchainAction sa = {
+ .sc_sigaction = art_sigsegv_handler,
+ .sc_mask = mask,
+ .sc_flags = 0UL,
+ };
+
+ AddSpecialSignalHandlerFn(SIGSEGV, &sa);
+ if (InstallSigbusHandler()) {
+ sa.sc_sigaction = art_sigbus_handler;
+ AddSpecialSignalHandlerFn(SIGBUS, &sa);
+ }
+
+ // Notify the kernel that we intend to use a specific `membarrier()` command.
+ int result = art::membarrier(MembarrierCommand::kRegisterPrivateExpedited);
+ if (result != 0) {
+ LOG(WARNING) << "FaultHandler: MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED failed: "
+ << errno << " " << strerror(errno);
+ }
+
+ {
+ MutexLock lock(Thread::Current(), generated_code_ranges_lock_);
+ for (size_t i = 0; i != kNumLocalGeneratedCodeRanges; ++i) {
+ GeneratedCodeRange* next = (i + 1u != kNumLocalGeneratedCodeRanges)
+ ? &generated_code_ranges_storage_[i + 1u]
+ : nullptr;
+ generated_code_ranges_storage_[i].next.store(next, std::memory_order_relaxed);
+ generated_code_ranges_storage_[i].start = nullptr;
+ generated_code_ranges_storage_[i].size = 0u;
+ }
+ free_generated_code_ranges_ = generated_code_ranges_storage_;
+ }
+
+ initialized_ = true;
+ } else if (InstallSigbusHandler()) {
+ struct sigaction act;
+ std::memset(&act, '\0', sizeof(act));
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.sa_sigaction = [](int sig, siginfo_t* info, void* context) {
+ if (!art_sigbus_handler(sig, info, context)) {
+ std::ostringstream oss;
+ PrintSignalInfo(oss, info);
+ LOG(FATAL) << "Couldn't handle SIGBUS fault:"
+ << "\n"
+ << oss.str();
+ }
+ };
+ if (sigaction(SIGBUS, &act, nullptr)) {
+ LOG(FATAL) << "Fault handler for SIGBUS couldn't be setup: " << strerror(errno);
+ }
+ }
}
void FaultManager::Release() {
if (initialized_) {
- RemoveSpecialSignalHandlerFn(SIGSEGV, art_fault_handler);
+ RemoveSpecialSignalHandlerFn(SIGSEGV, art_sigsegv_handler);
+ if (InstallSigbusHandler()) {
+ RemoveSpecialSignalHandlerFn(SIGBUS, art_sigbus_handler);
+ }
initialized_ = false;
}
}
@@ -157,32 +223,22 @@ bool FaultManager::HandleFaultByOtherHandlers(int sig, siginfo_t* info, void* co
return false;
}
-static const char* SignalCodeName(int sig, int code) {
- if (sig != SIGSEGV) {
- return "UNKNOWN";
- } else {
- switch (code) {
- case SEGV_MAPERR: return "SEGV_MAPERR";
- case SEGV_ACCERR: return "SEGV_ACCERR";
- case 8: return "SEGV_MTEAERR";
- case 9: return "SEGV_MTESERR";
- default: return "UNKNOWN";
- }
- }
-}
-static std::ostream& PrintSignalInfo(std::ostream& os, siginfo_t* info) {
- os << " si_signo: " << info->si_signo << " (" << strsignal(info->si_signo) << ")\n"
- << " si_code: " << info->si_code
- << " (" << SignalCodeName(info->si_signo, info->si_code) << ")";
- if (info->si_signo == SIGSEGV) {
- os << "\n" << " si_addr: " << info->si_addr;
+bool FaultManager::HandleSigbusFault(int sig, siginfo_t* info, void* context ATTRIBUTE_UNUSED) {
+ DCHECK_EQ(sig, SIGBUS);
+ if (VLOG_IS_ON(signals)) {
+ PrintSignalInfo(VLOG_STREAM(signals) << "Handling SIGBUS fault:\n", info);
}
- return os;
+
+#ifdef TEST_NESTED_SIGNAL
+ // Simulate a crash in a handler.
+ raise(SIGBUS);
+#endif
+ return Runtime::Current()->GetHeap()->MarkCompactCollector()->SigbusHandler(info);
}
-bool FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
+bool FaultManager::HandleSigsegvFault(int sig, siginfo_t* info, void* context) {
if (VLOG_IS_ON(signals)) {
- PrintSignalInfo(VLOG_STREAM(signals) << "Handling fault:" << "\n", info);
+ PrintSignalInfo(VLOG_STREAM(signals) << "Handling SIGSEGV fault:\n", info);
}
#ifdef TEST_NESTED_SIGNAL