diff options
Diffstat (limited to 'runtime/fault_handler.cc')
-rw-r--r-- | runtime/fault_handler.cc | 184 |
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 |