void CrashHandlerImpl::processCrash(const std::string & sharedMemoryName) { try { m_SharedMemoryName = sharedMemoryName; // Create a shared memory object. m_SharedMemory = bip::shared_memory_object(bip::open_only, m_SharedMemoryName.c_str(), bip::read_write); // Map the whole shared memory in this process m_MemoryMappedRegion = bip::mapped_region(m_SharedMemory, bip::read_write); // Our SharedCrashInfo will be stored in this shared memory. m_pCrashInfo = reinterpret_cast<CrashInfo *>(m_MemoryMappedRegion.get_address()); if(m_pCrashInfo) { m_textLength = std::find(m_pCrashInfo->description, m_pCrashInfo->description + boost::size(m_pCrashInfo->description), '\0') - m_pCrashInfo->description; } } catch(...) { // Unexpected error m_pCrashInfo = NULL; } processCrash(); std::exit(0); }
void CrashHandlerWindows::handleCrash(int crashType, void * crashExtraInfo, int fpeCode) { Autolock autoLock(&m_Lock); // Run the callbacks for(std::vector<CrashHandler::CrashCallback>::iterator it = m_crashCallbacks.begin(); it != m_crashCallbacks.end(); ++it) { (*it)(); } m_pCrashInfo->signal = crashType; m_pCrashInfo->code = fpeCode; PEXCEPTION_POINTERS pointers = reinterpret_cast<PEXCEPTION_POINTERS>(crashExtraInfo); // Copy CONTEXT to crash info structure PCONTEXT context = reinterpret_cast<PCONTEXT>(m_pCrashInfo->contextRecord); ARX_STATIC_ASSERT(sizeof(m_pCrashInfo->contextRecord) >= sizeof(*context), "buffer too small"); memset(context, 0, sizeof(*context)); EXCEPTION_POINTERS fakePointers; EXCEPTION_RECORD exception; if(pointers) { u32 code = m_pCrashInfo->exceptionCode = pointers->ExceptionRecord->ExceptionCode; m_pCrashInfo->address = u64(pointers->ExceptionRecord->ExceptionAddress); m_pCrashInfo->hasAddress = true; if(code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_IN_PAGE_ERROR) { m_pCrashInfo->memory = pointers->ExceptionRecord->ExceptionInformation[1]; m_pCrashInfo->hasMemory = true; } #if ARX_ARCH == ARX_ARCH_X86 m_pCrashInfo->stack = pointers->ContextRecord->Esp; m_pCrashInfo->hasStack = true; m_pCrashInfo->frame = pointers->ContextRecord->Ebp; m_pCrashInfo->hasFrame = true; #elif ARX_ARCH == ARX_ARCH_X86_64 m_pCrashInfo->stack = pointers->ContextRecord->Rsp; m_pCrashInfo->hasStack = true; #endif std::memcpy(context, pointers->ContextRecord, sizeof(*context)); } else { RtlCaptureContext(context); std::memset(&exception, 0, sizeof(exception)); fakePointers.ContextRecord = context; fakePointers.ExceptionRecord = &exception; pointers = &fakePointers; } // Get current thread id m_pCrashInfo->threadId = u32(GetCurrentThreadId()); writeCrashDump(pointers); // Try to spawn a sub-process to process the crash info STARTUPINFO si; memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); BOOL created = CreateProcessW(m_exe, m_args.data(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if(created) { while(true) { if(m_pCrashInfo->exitLock.try_wait()) { break; } if(WaitForSingleObject(pi.hProcess, 100) != WAIT_TIMEOUT) { break; } } TerminateProcess(GetCurrentProcess(), 1); unregisterCrashHandlers(); std::abort(); } // Fallback: process the crash info in-process unregisterCrashHandlers(); processCrash(); std::abort(); }
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(); }