OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
crashlog.cpp
Go to the documentation of this file.
1#include "crashlog.h"
2#include "commandline.h"
3
4#include <Tempest/Except>
5#include <Tempest/Platform>
6
7#include <iostream>
8#include <cstring>
9#include <csignal>
10#include <fstream>
11#include <cstring>
12
13#if defined(__cpp_lib_stacktrace)
14#include <stacktrace>
15#endif
16
17#if defined(__LINUX__) || defined(__APPLE__)
18#include <execinfo.h> // backtrace
19#include <dlfcn.h> // dladdr
20#include <cxxabi.h> // __cxa_demangle
21#endif
22
23#include <dbg/frames.hpp>
24#include <dbg/symbols.hpp>
25
26static char gpuName[64]="?";
27
28#ifdef __WINDOWS__
29#include <windows.h>
30
31static LONG WINAPI exceptionHandler(PEXCEPTION_POINTERS) {
32 SetUnhandledExceptionFilter(nullptr);
33 CrashLog::dumpStack("ExceptionFilter", nullptr);
34 return EXCEPTION_EXECUTE_HANDLER;
35 }
36#endif
37
38static void signalHandler(int sig) {
39 std::signal(sig, SIG_DFL);
40 const char* sname = nullptr;
41 char buf[16]={};
42 if(sig==SIGSEGV)
43 sname = "SIGSEGV";
44 else if(sig==SIGABRT)
45 sname = "SIGABRT";
46 else if(sig==SIGFPE)
47 sname = "SIGFPE";
48 else if(sig==SIGABRT)
49 sname = "SIGABRT";
50 else {
51 std::snprintf(buf,16,"%d",sig);
52 sname = buf;
53 }
54
55 CrashLog::dumpStack(sname, nullptr);
56 std::raise(sig);
57 }
58
59[[noreturn]]
60static void terminateHandler() {
61 char msg[128] = "std::terminate";
62 std::exception_ptr p = std::current_exception();
63 std::string extGpuLog;
64 if(p) {
65 try {
66 std::rethrow_exception(p);
67 }
68 catch (GothicNotFoundException& ) {
69 std::signal(SIGABRT, SIG_DFL); // avoid recursion
70 std::abort();
71 }
72 catch (Tempest::DeviceLostException& e) {
73 std::snprintf(msg,sizeof(msg),"DeviceLostException(%s)",e.what());
74 extGpuLog = e.log();
75 }
76 catch (Tempest::BadTextureCastException& e) {
77 std::snprintf(msg,sizeof(msg),"BadTextureCastException(%s)",e.what());
78 }
79 catch (std::system_error& e) {
80 std::snprintf(msg,sizeof(msg),"std::system_error(%s)",e.what());
81 }
82 catch (std::runtime_error& e) {
83 std::snprintf(msg,sizeof(msg),"std::runtime_error(%s)",e.what());
84 }
85 catch (std::logic_error& e) {
86 std::snprintf(msg,sizeof(msg),"std::logic_error(%s)",e.what());
87 }
88 catch (std::bad_alloc& e) {
89 std::snprintf(msg,sizeof(msg),"std::bad_alloc(%s)",e.what());
90 }
91 catch (std::exception& e) {
92 std::snprintf(msg,sizeof(msg),"std::exception(%s)",e.what());
93 }
94 catch (...) {
95 }
96 }
97 CrashLog::dumpStack(msg, extGpuLog.c_str());
98 std::signal(SIGABRT, SIG_DFL); // avoid recursion
99 std::abort();
100 }
101
103#ifdef __WINDOWS__
104 SetUnhandledExceptionFilter(exceptionHandler);
105#endif
106
107 std::signal(SIGSEGV, &signalHandler);
108 std::signal(SIGABRT, &signalHandler);
109 std::signal(SIGFPE, &signalHandler);
110 std::signal(SIGABRT, &signalHandler);
111 std::set_terminate(terminateHandler);
112 }
113
114void CrashLog::setGpu(std::string_view name) {
115 if(name.empty())
116 return;
117 std::strncpy(gpuName,name.data(),sizeof(gpuName)-1);
118 }
119
120void CrashLog::dumpStack(const char *sig, const char *extGpuLog) {
121#if !defined(__cpp_lib_stacktrace) && defined(__WINDOWS__)
122 dbg::symdb db;
123 dbg::call_stack<64> traceback;
124#endif
125 if(sig==nullptr)
126 sig = "SIGSEGV";
127
128 std::cout.setf(std::ios::unitbuf);
129 std::cout << std::endl << "---crashlog(" << sig << ")---" << std::endl;
130 writeSysInfo(std::cout);
131 tracebackGpu(std::cout, extGpuLog);
132#if defined(__cpp_lib_stacktrace)
133 tracebackStd(std::cout);
134#elif defined(__WINDOWS__)
135 traceback.collect(0);
136 traceback.log(db, std::cout);
137#elif defined(__LINUX__) || defined(__APPLE__)
138 tracebackLinux(std::cout);
139#endif
140 std::cout << std::endl;
141
142 std::ofstream fout("crash.log");
143 fout.setf(std::ios::unitbuf);
144 fout << "---crashlog(" << sig << ")---" << std::endl;
145 writeSysInfo(fout);
146 tracebackGpu(std::cout, extGpuLog);
147#if defined(__cpp_lib_stacktrace)
148 tracebackStd(fout);
149#elif defined(__WINDOWS__)
150 traceback.log(db, fout);
151#elif defined(__LINUX__) || defined(__APPLE__)
152 tracebackLinux(fout);
153#endif
154 fout.flush();
155 }
156
157void CrashLog::tracebackStd(std::ostream &out) {
158#if defined(__cpp_lib_stacktrace)
159 auto trace = std::stacktrace::current();
160
161 uint32_t frameId = 0;
162 for (auto& i : trace) {
163 out << " #" << frameId << "\t" << i.description() << ":" << i.source_line() << " in " << i.source_file() << std::endl;
164 ++frameId;
165 }
166#endif
167 }
168
169void CrashLog::tracebackLinux(std::ostream &out) {
170#if defined(__LINUX__) || defined(__APPLE__)
171 // inspired by https://gist.github.com/fmela/591333/36faca4c2f68f7483cd0d3a357e8a8dd5f807edf (BSD)
172 void *callstack[64] = {};
173 char **symbols = nullptr;
174 int framesNum = 0;
175 framesNum = backtrace(callstack, 64);
176 symbols = backtrace_symbols(callstack, framesNum);
177 if(symbols != nullptr) {
178 int skip = 4; // skip the signal handler frames
179 bool loop = true;
180 Dl_info info;
181 const char* frame = "";
182 for(int i = skip; i < framesNum && loop; i++) {
183 if(dladdr(callstack[i], &info) && info.dli_sname) {
184 int status = -1;
185 if(info.dli_sname[0] == '_')
186 frame = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
187 frame = status == 0 ? frame : info.dli_sname == 0 ? symbols[i] : info.dli_sname;
188 }
189 if(!strcmp("main", frame)) {
190 // looping beyond the main() causes crashes
191 loop = false;
192 }
193 if(strcmp(frame, symbols[i]))
194 out << "#" << i-skip+1 << ": " << frame << " - " << symbols[i] << std::endl;
195 else
196 out << "#" << i-skip+1 << ": " << frame << std::endl;
197 }
198 free(symbols);
199 }
200#endif
201 }
202
203void CrashLog::tracebackGpu(std::ostream& out, const char* extGpuLog) {
204 if(extGpuLog==nullptr || extGpuLog[0]=='\0')
205 return;
206 out << std::endl;
207 out << "---gpulog begin---" << std::endl;
208 out << extGpuLog << std::endl;
209 out << "---gpulog end ---" << std::endl;
210 out << std::endl;
211 }
212
213void CrashLog::writeSysInfo(std::ostream &fout) {
214 fout << "GPU: " << gpuName << std::endl;
215 }
static void setGpu(std::string_view name)
Definition crashlog.cpp:114
static void setup()
Definition crashlog.cpp:102
static void dumpStack(const char *sig, const char *extGpuLog)
Definition crashlog.cpp:120
static void terminateHandler()
Definition crashlog.cpp:60
static char gpuName[64]
Definition crashlog.cpp:26
static void signalHandler(int sig)
Definition crashlog.cpp:38