/* * Copyright (c) 2010-2012 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #define __USE_GNU #include "crashhandler.h" #include #include #include #include #define MAX_BACKTRACE_DEPTH 128 #define DEMANGLE_BACKTRACE_SYMBOLS void crashHandler(int signum, siginfo_t* info, void* secret) { logError("Application crashed"); ucontext_t context = *(ucontext_t*)secret; time_t tnow; char fileName[128]; time(&tnow); tm *ts = localtime(&tnow); strftime(fileName, 128, (g_app->getName() + "-crash_-%d-%m-%Y_%H:%M:%S.txt").c_str(), ts); std::stringstream ss; ss.flags(std::ios::hex | std::ios::showbase); #if __WORDSIZE == 64 ss << " at rip = " << context.uc_mcontext.gregs[REG_RIP] << std::endl; ss << " rax = " << context.uc_mcontext.gregs[REG_RAX] << std::endl; ss << " rbx = " << context.uc_mcontext.gregs[REG_RBX] << std::endl; ss << " rcx = " << context.uc_mcontext.gregs[REG_RCX] << std::endl; ss << " rdx = " << context.uc_mcontext.gregs[REG_RDX] << std::endl; ss << " rsi = " << context.uc_mcontext.gregs[REG_RSI] << std::endl; ss << " rdi = " << context.uc_mcontext.gregs[REG_RDI] << std::endl; ss << " rbp = " << context.uc_mcontext.gregs[REG_RBP] << std::endl; ss << " rsp = " << context.uc_mcontext.gregs[REG_RSP] << std::endl; ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl; ss << std::endl; #else ss << " at eip = " << context.uc_mcontext.gregs[REG_EIP] << std::endl; ss << " eax = " << context.uc_mcontext.gregs[REG_EAX] << std::endl; ss << " ebx = " << context.uc_mcontext.gregs[REG_EBX] << std::endl; ss << " ecx = " << context.uc_mcontext.gregs[REG_ECX] << std::endl; ss << " edx = " << context.uc_mcontext.gregs[REG_EDX] << std::endl; ss << " esi = " << context.uc_mcontext.gregs[REG_ESI] << std::endl; ss << " edi = " << context.uc_mcontext.gregs[REG_EDI] << std::endl; ss << " ebp = " << context.uc_mcontext.gregs[REG_EBP] << std::endl; ss << " esp = " << context.uc_mcontext.gregs[REG_ESP] << std::endl; ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl; ss << std::endl; #endif ss.flags(std::ios::dec); ss << " backtrace:" << std::endl; void* buffer[MAX_BACKTRACE_DEPTH]; int numLevels = backtrace(buffer, MAX_BACKTRACE_DEPTH); char **tracebackBuffer = backtrace_symbols(buffer, numLevels); if(tracebackBuffer) { for(int i = 2; i < numLevels; i++) { std::string line = tracebackBuffer[i]; if(line.find("__libc_start_main") != std::string::npos) break; #ifdef DEMANGLE_BACKTRACE_SYMBOLS std::size_t demanglePos = line.find("(_Z"); if(demanglePos != std::string::npos) { demanglePos++; int len = std::min(line.find_first_of("+", demanglePos), line.find_first_of(")", demanglePos)) - demanglePos; std::string funcName = line.substr(demanglePos, len); line.replace(demanglePos, len, Fw::demangleName(funcName.c_str())); } #endif ss << " " << i-1 << ": " << line << std::endl; } free(tracebackBuffer); } logInfo(ss.str()); std::ofstream out(fileName); out << ss.str(); out.close(); logInfo("Crash report saved to file ", fileName); signal(SIGILL, SIG_DFL); signal(SIGSEGV, SIG_DFL); signal(SIGFPE, SIG_DFL); } void installCrashHandler() { struct sigaction sa; sa.sa_sigaction = &crashHandler; sigemptyset (&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_SIGINFO; sigaction(SIGILL, &sa, NULL); // illegal instruction sigaction(SIGSEGV, &sa, NULL); // segmentation fault sigaction(SIGFPE, &sa, NULL); // floating-point exception }