Rework the trip history window layout.
[openttd-joker.git] / src / os / unix / crashlog_unix.cpp
blob670e73847527b0023c08bb152aafb1ae62f056d5
1 /* $Id: crashlog_unix.cpp 20266 2010-07-31 21:02:56Z alberth $ */
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
10 /** @file crashlog_unix.cpp Unix crash log handler */
12 #include "../../stdafx.h"
13 #include "../../crashlog.h"
14 #include "../../string_func.h"
15 #include "../../gamelog.h"
16 #include "../../saveload/saveload.h"
18 #include <errno.h>
19 #include <signal.h>
20 #include <sys/utsname.h>
22 #if defined(__GLIBC__)
23 /* Execinfo (and thus making stacktraces) is a GNU extension */
24 # include <execinfo.h>
25 #elif defined(SUNOS)
26 # include <ucontext.h>
27 # include <dlfcn.h>
28 #endif
30 #if defined(__NetBSD__)
31 #include <unistd.h>
32 #endif
34 #include "../../safeguards.h"
36 /**
37 * Unix implementation for the crash logger.
39 class CrashLogUnix : public CrashLog {
40 /** Signal that has been thrown. */
41 int signum;
43 /* virtual */ char *LogOSVersion(char *buffer, const char *last) const
45 struct utsname name;
46 if (uname(&name) < 0) {
47 return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", strerror(errno));
50 return buffer + seprintf(buffer, last,
51 "Operating system:\n"
52 " Name: %s\n"
53 " Release: %s\n"
54 " Version: %s\n"
55 " Machine: %s\n",
56 name.sysname,
57 name.release,
58 name.version,
59 name.machine
63 /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const
65 return buffer + seprintf(buffer, last,
66 "Crash reason:\n"
67 " Signal: %s (%d)\n"
68 " Message: %s\n\n",
69 strsignal(this->signum),
70 this->signum,
71 message == NULL ? "<none>" : message
75 #if defined(SUNOS)
76 /** Data needed while walking up the stack */
77 struct StackWalkerParams {
78 char **bufptr; ///< Buffer
79 const char *last; ///< End of buffer
80 int counter; ///< We are at counter-th stack level
83 /**
84 * Callback used while walking up the stack.
85 * @param pc program counter
86 * @param sig 'active' signal (unused)
87 * @param params parameters
88 * @return always 0, continue walking up the stack
90 static int SunOSStackWalker(uintptr_t pc, int sig, void *params)
92 StackWalkerParams *wp = (StackWalkerParams *)params;
94 /* Resolve program counter to file and nearest symbol (if possible) */
95 Dl_info dli;
96 if (dladdr((void *)pc, &dli) != 0) {
97 *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] %s(%s+0x%x) [0x%x]\n",
98 wp->counter, dli.dli_fname, dli.dli_sname, (int)((byte *)pc - (byte *)dli.dli_saddr), (uint)pc);
99 } else {
100 *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] [0x%x]\n", wp->counter, (uint)pc);
102 wp->counter++;
104 return 0;
106 #endif
108 /* virtual */ char *LogStacktrace(char *buffer, const char *last) const
110 buffer += seprintf(buffer, last, "Stacktrace:\n");
111 #if defined(__GLIBC__)
112 void *trace[64];
113 int trace_size = backtrace(trace, lengthof(trace));
115 char **messages = backtrace_symbols(trace, trace_size);
116 for (int i = 0; i < trace_size; i++) {
117 buffer += seprintf(buffer, last, " [%02i] %s\n", i, messages[i]);
119 free(messages);
120 #elif defined(SUNOS)
121 ucontext_t uc;
122 if (getcontext(&uc) != 0) {
123 buffer += seprintf(buffer, last, " getcontext() failed\n\n");
124 return buffer;
127 StackWalkerParams wp = { &buffer, last, 0 };
128 walkcontext(&uc, &CrashLogUnix::SunOSStackWalker, &wp);
129 #else
130 buffer += seprintf(buffer, last, " Not supported.\n");
131 #endif
132 return buffer + seprintf(buffer, last, "\n");
134 public:
136 * A crash log is always generated by signal.
137 * @param signum the signal that was caused by the crash.
139 CrashLogUnix(int signum) :
140 signum(signum)
145 /** The signals we want our crash handler to handle. */
146 static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL };
149 * Entry point for the crash handler.
150 * @note Not static so it shows up in the backtrace.
151 * @param signum the signal that caused us to crash.
153 static void CDECL HandleCrash(int signum)
155 /* Disable all handling of signals by us, so we don't go into infinite loops. */
156 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
157 signal(*i, SIG_DFL);
160 if (GamelogTestEmergency()) {
161 printf("A serious fault condition occurred in the game. The game will shut down.\n");
162 printf("As you loaded an emergency savegame no crash information will be generated.\n");
163 abort();
166 if (SaveloadCrashWithMissingNewGRFs()) {
167 printf("A serious fault condition occurred in the game. The game will shut down.\n");
168 printf("As you loaded an savegame for which you do not have the required NewGRFs\n");
169 printf("no crash information will be generated.\n");
170 abort();
173 CrashLogUnix log(signum);
174 log.MakeCrashLog();
176 CrashLog::AfterCrashLogCleanup();
177 abort();
180 /* static */ void CrashLog::InitialiseCrashLog()
182 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
183 signal(*i, HandleCrash);