00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../../stdafx.h"
00013 #include "../../crashlog.h"
00014 #include "../../string_func.h"
00015 #include "../../gamelog.h"
00016 #include "../../saveload/saveload.h"
00017
00018 #include <errno.h>
00019 #include <signal.h>
00020 #include <sys/utsname.h>
00021
00022 #if defined(__GLIBC__)
00023
00024 # include <execinfo.h>
00025 #elif defined(SUNOS)
00026 # include <ucontext.h>
00027 # include <dlfcn.h>
00028 #endif
00029
00030 #if defined(__NetBSD__)
00031 #include <unistd.h>
00032 #endif
00033
00037 class CrashLogUnix : public CrashLog {
00039 int signum;
00040
00041 char *LogOSVersion(char *buffer, const char *last) const
00042 {
00043 struct utsname name;
00044 if (uname(&name) < 0) {
00045 return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", strerror(errno));
00046 }
00047
00048 return buffer + seprintf(buffer, last,
00049 "Operating system:\n"
00050 " Name: %s\n"
00051 " Release: %s\n"
00052 " Version: %s\n"
00053 " Machine: %s\n",
00054 name.sysname,
00055 name.release,
00056 name.version,
00057 name.machine
00058 );
00059 }
00060
00061 char *LogError(char *buffer, const char *last, const char *message) const
00062 {
00063 return buffer + seprintf(buffer, last,
00064 "Crash reason:\n"
00065 " Signal: %s (%d)\n"
00066 " Message: %s\n\n",
00067 strsignal(this->signum),
00068 this->signum,
00069 message == NULL ? "<none>" : message
00070 );
00071 }
00072
00073 #if defined(SUNOS)
00074
00075 struct StackWalkerParams {
00076 char **bufptr;
00077 const char *last;
00078 int counter;
00079 };
00080
00088 static int SunOSStackWalker(uintptr_t pc, int sig, void *params)
00089 {
00090 StackWalkerParams *wp = (StackWalkerParams *)params;
00091
00092
00093 Dl_info dli;
00094 if (dladdr((void *)pc, &dli) != 0) {
00095 *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] %s(%s+0x%x) [0x%x]\n",
00096 wp->counter, dli.dli_fname, dli.dli_sname, (int)((byte *)pc - (byte *)dli.dli_saddr), (uint)pc);
00097 } else {
00098 *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] [0x%x]\n", wp->counter, (uint)pc);
00099 }
00100 wp->counter++;
00101
00102 return 0;
00103 }
00104 #endif
00105
00106 char *LogStacktrace(char *buffer, const char *last) const
00107 {
00108 buffer += seprintf(buffer, last, "Stacktrace:\n");
00109 #if defined(__GLIBC__)
00110 void *trace[64];
00111 int trace_size = backtrace(trace, lengthof(trace));
00112
00113 char **messages = backtrace_symbols(trace, trace_size);
00114 for (int i = 0; i < trace_size; i++) {
00115 buffer += seprintf(buffer, last, " [%02i] %s\n", i, messages[i]);
00116 }
00117 free(messages);
00118 #elif defined(SUNOS)
00119 ucontext_t uc;
00120 if (getcontext(&uc) != 0) {
00121 buffer += seprintf(buffer, last, " getcontext() failed\n\n");
00122 return buffer;
00123 }
00124
00125 StackWalkerParams wp = { &buffer, last, 0 };
00126 walkcontext(&uc, &CrashLogUnix::SunOSStackWalker, &wp);
00127 #else
00128 buffer += seprintf(buffer, last, " Not supported.\n");
00129 #endif
00130 return buffer + seprintf(buffer, last, "\n");
00131 }
00132 public:
00137 CrashLogUnix(int signum) :
00138 signum(signum)
00139 {
00140 }
00141 };
00142
00144 static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL };
00145
00151 static void CDECL HandleCrash(int signum)
00152 {
00153
00154 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00155 signal(*i, SIG_DFL);
00156 }
00157
00158 if (GamelogTestEmergency()) {
00159 printf("A serious fault condition occurred in the game. The game will shut down.\n");
00160 printf("As you loaded an emergency savegame no crash information will be generated.\n");
00161 abort();
00162 }
00163
00164 if (SaveloadCrashWithMissingNewGRFs()) {
00165 printf("A serious fault condition occurred in the game. The game will shut down.\n");
00166 printf("As you loaded an savegame for which you do not have the required NewGRFs\n");
00167 printf("no crash information will be generated.\n");
00168 abort();
00169 }
00170
00171 CrashLogUnix log(signum);
00172 log.MakeCrashLog();
00173
00174 CrashLog::AfterCrashLogCleanup();
00175 abort();
00176 }
00177
00178 void CrashLog::InitialiseCrashLog()
00179 {
00180 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00181 signal(*i, HandleCrash);
00182 }
00183 }