OpenTTD: src/os/unix/crashlog_unix.cpp Source File

OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

crashlog_unix.cpp
Go to the documentation of this file.
1 /* $Id: crashlog_unix.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
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 */
9
12 #include "../../stdafx.h"
13 #include "../../crashlog.h"
14 #include "../../string_func.h"
15 #include "../../gamelog.h"
16 #include "../../saveload/saveload.h"
17
18 #include <errno.h>
19 #include <signal.h>
20 #include <sys/utsname.h>
21
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
29
30 #if defined(__NetBSD__)
31 #include <unistd.h>
32 #endif
33
34 #include "../../safeguards.h"
35
39 class CrashLogUnix : public CrashLog {
41 int signum;
42
43 /* virtual */ char *LogOSVersion(char *buffer, const char *last) const
44 {
45 struct utsname name;
46 if (uname(&name) < 0) {
47 return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", strerror(errno));
48 }
49
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
60 );
61 }
62
63 /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const
64 {
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
72 );
73 }
74
75 #if defined(SUNOS)
76
77 struct StackWalkerParams {
78 char **bufptr;
79 const char *last;
80 int counter;
81 };
82
90 static int SunOSStackWalker(uintptr_t pc, int sig, void *params)
91 {
92 StackWalkerParams *wp = (StackWalkerParams *)params;
93
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);
101 }
102 wp->counter++;
103
104 return 0;
105 }
106 #endif
107
108 /* virtual */ char *LogStacktrace(char *buffer, const char *last) const
109 {
110 buffer += seprintf(buffer, last, "Stacktrace:\n");
111 #if defined(__GLIBC__)
112 void *trace[64];
113 int trace_size = backtrace(trace, lengthof(trace));
114
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]);
118 }
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;
125 }
126
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");
133 }
134 public:
139 CrashLogUnix(int signum) :
140 signum(signum)
141 {
142 }
143 };
144
146 static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL };
147
153 static void CDECL HandleCrash(int signum)
154 {
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);
158 }
159
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();
164 }
165
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();
171 }
172
173 CrashLogUnix log(signum);
174 log.MakeCrashLog();
175
176 CrashLog::AfterCrashLogCleanup();
177 abort();
178 }
179
180 /* static */ void CrashLog::InitialiseCrashLog()
181 {
182 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
183 signal(*i, HandleCrash);
184 }
185 }