void CrashHandlerPOSIX::handleCrash(int signal, int code) { // Remove crash handlers so we don't end in an infinite crash loop removeCrashHandlers(m_pPreviousCrashHandlers); // Run the callbacks for(std::vector<CrashHandler::CrashCallback>::iterator it = m_crashCallbacks.begin(); it != m_crashCallbacks.end(); ++it) { (*it)(); } m_pCrashInfo->signal = signal; m_pCrashInfo->code = code; // Store the backtrace in the shared crash info #ifdef HAVE_BACKTRACE backtrace(m_pCrashInfo->backtrace, ARRAY_SIZE(m_pCrashInfo->backtrace)); #endif m_pCrashInfo->crashBrokerLock.post(); while(true) { // Busy wait so we don't enter any additional stack frames and keep the backtrace clean. } }
void CrashHandlerPOSIX::unregisterCrashHandlers() { unregisterThreadCrashHandlers(); removeCrashHandlers(m_pPreviousCrashHandlers); delete m_pPreviousCrashHandlers; m_pPreviousCrashHandlers = 0; }
void CrashHandlerPOSIX::handleCrash(int signal, void * info, void * context) { // Remove crash handlers so we don't end in an infinite crash loop removeCrashHandlers(m_pPreviousCrashHandlers); // Run the callbacks for(std::vector<CrashHandler::CrashCallback>::iterator it = m_crashCallbacks.begin(); it != m_crashCallbacks.end(); ++it) { (*it)(); } m_pCrashInfo->signal = signal; #if ARX_HAVE_SIGACTION if(info) { siginfo_t * siginfo = reinterpret_cast<siginfo_t *>(info); m_pCrashInfo->code = siginfo->si_code; #if defined(SIGILL) || defined(SIGFPE) if(signal == SIGILL || signal == SIGFPE) { m_pCrashInfo->address = u64(siginfo->si_addr); m_pCrashInfo->hasAddress = true; } #endif #if defined(SIGSEGV) && defined(SIGBUS) if(signal == SIGSEGV || signal == SIGBUS) { m_pCrashInfo->memory = u64(siginfo->si_addr); m_pCrashInfo->hasMemory = true; } #endif } #endif #if ARX_HAVE_SIGACTION && ARX_PLATFORM == ARX_PLATFORM_LINUX if(context) { ucontext_t * ctx = reinterpret_cast<ucontext_t *>(context); #if ARX_ARCH == ARX_ARCH_X86 && defined(REG_EIP) m_pCrashInfo->address = ctx->uc_mcontext.gregs[REG_EIP]; m_pCrashInfo->hasAddress = true; m_pCrashInfo->stack = ctx->uc_mcontext.gregs[REG_ESP]; m_pCrashInfo->hasStack = true; m_pCrashInfo->frame = ctx->uc_mcontext.gregs[REG_EBP]; m_pCrashInfo->hasFrame = true; #elif ARX_ARCH == ARX_ARCH_X86_64 && defined(REG_RIP) m_pCrashInfo->address = ctx->uc_mcontext.gregs[REG_RIP]; m_pCrashInfo->hasAddress = true; m_pCrashInfo->stack = ctx->uc_mcontext.gregs[REG_RSP]; m_pCrashInfo->hasStack = true; #elif ARX_ARCH == ARX_ARCH_ARM m_pCrashInfo->address = ctx->uc_mcontext.arm_pc; m_pCrashInfo->hasAddress = true; m_pCrashInfo->stack = ctx->uc_mcontext.arm_sp; m_pCrashInfo->hasStack = true; m_pCrashInfo->frame = ctx->uc_mcontext.arm_fp; m_pCrashInfo->hasFrame = true; #else ARX_UNUSED(ctx); #endif } #else ARX_UNUSED(context); #endif // Store the backtrace in the shared crash info #if ARX_HAVE_BACKTRACE backtrace(m_pCrashInfo->backtrace, boost::size(m_pCrashInfo->backtrace)); #endif // Change directory core dumps are written to if(m_pCrashInfo->crashReportFolder[0] != '\0') { #if ARX_HAVE_CHDIR if(chdir(m_pCrashInfo->crashReportFolder) == 0) { // Shut up GCC, we don't care } #endif } // Try to spawn a sub-process to process the crash info // Using fork() in a signal handler is bad, but we are already crashing anyway pid_t processor = fork(); if(processor > 0) { while(true) { if(m_pCrashInfo->exitLock.try_wait()) { break; } #if ARX_HAVE_WAITPID if(waitpid(processor, NULL, WNOHANG) != 0) { break; } #endif #if ARX_HAVE_NANOSLEEP timespec t; t.tv_sec = 0; t.tv_nsec = 100 * 1000; nanosleep(&t, NULL); #endif } // Exit if the crash reporter failed kill(getpid(), SIGKILL); std::abort(); } #ifdef ARX_HAVE_EXECVP char argument[256]; strcpy(argument, "--crashinfo="); strcat(argument, m_SharedMemoryName.c_str()); const char * args[] = { m_executable.string().c_str(), argument, NULL }; execvp(m_executable.string().c_str(), const_cast<char **>(args)); #endif // Fallback: process the crash info in-process processCrash(); std::abort(); }