OpenTTD
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 
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 
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 }
bool GamelogTestEmergency()
Finds out if current game is a loaded emergency savegame.
Definition: gamelog.cpp:392
Helper class for creating crash logs.
Definition: crashlog.h:18
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:398
char * LogStacktrace(char *buffer, const char *last) const
Writes the stack trace to the buffer, if there is information about it available. ...
static void CDECL HandleCrash(int signum)
Entry point for the crash handler.
static void InitialiseCrashLog()
Initialiser for crash logs; do the appropriate things so crashes are handled by our crash handler ins...
static const int _signals_to_handle[]
The signals we want our crash handler to handle.
char * LogError(char *buffer, const char *last, const char *message) const
Writes actually encountered error to the buffer.
CrashLogUnix(int signum)
A crash log is always generated by signal.
static const char * message
Pointer to the error message.
Definition: crashlog.h:21
Unix implementation for the crash logger.
static void AfterCrashLogCleanup()
Try to close the sound/video stuff so it doesn&#39;t keep lingering around incorrect video states or so...
Definition: crashlog.cpp:489
bool MakeCrashLog() const
Makes the crash log, writes it to a file and then subsequently tries to make a crash dump and crash s...
Definition: crashlog.cpp:421
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
#define endof(x)
Get the end element of an fixed size array.
Definition: stdafx.h:427
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:114
bool SaveloadCrashWithMissingNewGRFs()
Did loading the savegame cause a crash? If so, were NewGRFs missing?
Definition: afterload.cpp:359
int signum
Signal that has been thrown.
char * LogOSVersion(char *buffer, const char *last) const
Writes OS&#39; version to the buffer.