Otclient  14/8/2020
unixcrashhandler.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2016 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #if !defined(WIN32) && defined(CRASH_HANDLER)
24 
25 #include "crashhandler.h"
26 #include <framework/global.h>
28 
29 #ifndef __USE_GNU
30 #define __USE_GNU
31 #endif
32 
33 #include <csignal>
34 #include <execinfo.h>
35 #include <ucontext.h>
36 
37 #define MAX_BACKTRACE_DEPTH 128
38 #define DEMANGLE_BACKTRACE_SYMBOLS
39 
40 void crashHandler(int signum, siginfo_t* info, void* secret)
41 {
42  g_logger.error("Application crashed");
43 
44  std::stringstream ss;
45  ss << stdext::format("app name: %s\n", g_app.getName());
46  ss << stdext::format("app version: %s\n", g_app.getVersion());
47  ss << stdext::format("build compiler: %s\n", BUILD_COMPILER);
48  ss << stdext::format("build date: %s\n", __DATE__);
49  ss << stdext::format("build type: %s\n", BUILD_TYPE);
50  ss << stdext::format("build revision: %s (%s)\n", BUILD_REVISION, BUILD_COMMIT);
51  ss << stdext::format("crash date: %s\n", stdext::date_time_string());
52  ss.flags(std::ios::hex | std::ios::showbase);
53 
54  ucontext_t context = *(ucontext_t*)secret;
55 #if __WORDSIZE == 64
56  ss << " at rip = " << context.uc_mcontext.gregs[REG_RIP] << std::endl;
57  ss << " rax = " << context.uc_mcontext.gregs[REG_RAX] << std::endl;
58  ss << " rbx = " << context.uc_mcontext.gregs[REG_RBX] << std::endl;
59  ss << " rcx = " << context.uc_mcontext.gregs[REG_RCX] << std::endl;
60  ss << " rdx = " << context.uc_mcontext.gregs[REG_RDX] << std::endl;
61  ss << " rsi = " << context.uc_mcontext.gregs[REG_RSI] << std::endl;
62  ss << " rdi = " << context.uc_mcontext.gregs[REG_RDI] << std::endl;
63  ss << " rbp = " << context.uc_mcontext.gregs[REG_RBP] << std::endl;
64  ss << " rsp = " << context.uc_mcontext.gregs[REG_RSP] << std::endl;
65  ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl;
66  ss << std::endl;
67 #elif defined(REG_EIP)
68  ss << " at eip = " << context.uc_mcontext.gregs[REG_EIP] << std::endl;
69  ss << " eax = " << context.uc_mcontext.gregs[REG_EAX] << std::endl;
70  ss << " ebx = " << context.uc_mcontext.gregs[REG_EBX] << std::endl;
71  ss << " ecx = " << context.uc_mcontext.gregs[REG_ECX] << std::endl;
72  ss << " edx = " << context.uc_mcontext.gregs[REG_EDX] << std::endl;
73  ss << " esi = " << context.uc_mcontext.gregs[REG_ESI] << std::endl;
74  ss << " edi = " << context.uc_mcontext.gregs[REG_EDI] << std::endl;
75  ss << " ebp = " << context.uc_mcontext.gregs[REG_EBP] << std::endl;
76  ss << " esp = " << context.uc_mcontext.gregs[REG_ESP] << std::endl;
77  ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl;
78  ss << std::endl;
79 #endif
80 
81  ss.flags(std::ios::dec);
82  ss << " backtrace:" << std::endl;
83 
84  void* buffer[MAX_BACKTRACE_DEPTH];
85  int numLevels = backtrace(buffer, MAX_BACKTRACE_DEPTH);
86  char **tracebackBuffer = backtrace_symbols(buffer, numLevels);
87  if(tracebackBuffer) {
88  for(int i = 2; i < numLevels; i++) {
89  std::string line = tracebackBuffer[i];
90  if(line.find("__libc_start_main") != std::string::npos)
91  break;
92 #ifdef DEMANGLE_BACKTRACE_SYMBOLS
93  std::size_t demanglePos = line.find("(_Z");
94  if(demanglePos != std::string::npos) {
95  demanglePos++;
96  int len = std::min(line.find_first_of("+", demanglePos), line.find_first_of(")", demanglePos)) - demanglePos;
97  std::string funcName = line.substr(demanglePos, len);
98  line.replace(demanglePos, len, stdext::demangle_name(funcName.c_str()));
99  }
100 #endif
101  ss << " " << i-1 << ": " << line << std::endl;
102  }
103  free(tracebackBuffer);
104  }
105 
106  g_logger.info(ss.str());
107 
108  std::string fileName = "crash_report.log";
109  std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::app);
110  if(fout.is_open() && fout.good()) {
111  fout << "== application crashed\n";
112  fout << ss.str();
113  fout << "\n";
114  fout.close();
115  g_logger.info(stdext::format("Crash report saved to file %s", fileName));
116  } else
117  g_logger.error("Failed to save crash report!");
118 
119  signal(SIGILL, SIG_DFL);
120  signal(SIGSEGV, SIG_DFL);
121  signal(SIGFPE, SIG_DFL);
122  signal(SIGABRT, SIG_DFL);
123 }
124 
125 void installCrashHandler()
126 {
127  struct sigaction sa;
128  sa.sa_sigaction = &crashHandler;
129  sigemptyset (&sa.sa_mask);
130  sa.sa_flags = SA_RESTART | SA_SIGINFO;
131 
132  sigaction(SIGILL, &sa, nullptr); // illegal instruction
133  sigaction(SIGSEGV, &sa, nullptr); // segmentation fault
134  sigaction(SIGFPE, &sa, nullptr); // floating-point exception
135  sigaction(SIGABRT, &sa, nullptr); // process aborted (asserts)
136 }
137 
138 #endif
crashhandler.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
stdext::format
std::string format()
Definition: format.h:82
stdext::demangle_name
const char * demangle_name(const char *name)
Demangle names for GNU g++ compiler.
Definition: demangle.cpp:45
Application::getName
const std::string & getName()
Definition: application.h:51
g_logger
Logger g_logger
Definition: logger.cpp:35
BUILD_TYPE
#define BUILD_TYPE
Definition: const.h:40
BUILD_REVISION
#define BUILD_REVISION
Definition: const.h:36
g_app
ConsoleApplication g_app
Definition: consoleapplication.cpp:32
stdext::date_time_string
std::string date_time_string()
Get current date and time in a std::string.
Definition: string.cpp:48
BUILD_COMMIT
#define BUILD_COMMIT
Definition: const.h:32
global.h
Logger::info
void info(const std::string &what)
Definition: logger.h:52
application.h
Application::getVersion
const std::string & getVersion()
Definition: application.h:53