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
00033 class CrashLogUnix : public CrashLog {
00035 int signum;
00036
00037 char *LogOSVersion(char *buffer, const char *last) const
00038 {
00039 struct utsname name;
00040 if (uname(&name) < 0) {
00041 return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", strerror(errno));
00042 }
00043
00044 return buffer + seprintf(buffer, last,
00045 "Operating system:\n"
00046 " Name: %s\n"
00047 " Release: %s\n"
00048 " Version: %s\n"
00049 " Machine: %s\n",
00050 name.sysname,
00051 name.release,
00052 name.version,
00053 name.machine
00054 );
00055 }
00056
00057 char *LogError(char *buffer, const char *last, const char *message) const
00058 {
00059 return buffer + seprintf(buffer, last,
00060 "Crash reason:\n"
00061 " Signal: %s (%d)\n"
00062 " Message: %s\n\n",
00063 strsignal(this->signum),
00064 this->signum,
00065 message == NULL ? "<none>" : message
00066 );
00067 }
00068
00069 #if defined(SUNOS)
00070
00071 struct StackWalkerParams {
00072 char **bufptr;
00073 const char *last;
00074 int counter;
00075 };
00076
00084 static int SunOSStackWalker(uintptr_t pc, int sig, void *params)
00085 {
00086 StackWalkerParams *wp = (StackWalkerParams *)params;
00087
00088
00089 Dl_info dli;
00090 if (dladdr((void *)pc, &dli) != 0) {
00091 *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] %s(%s+0x%x) [0x%x]\n",
00092 wp->counter, dli.dli_fname, dli.dli_sname, (int)((byte *)pc - (byte *)dli.dli_saddr), (uint)pc);
00093 } else {
00094 *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] [0x%x]\n", wp->counter, (uint)pc);
00095 }
00096 wp->counter++;
00097
00098 return 0;
00099 }
00100 #endif
00101
00102 char *LogStacktrace(char *buffer, const char *last) const
00103 {
00104 buffer += seprintf(buffer, last, "Stacktrace:\n");
00105 #if defined(__GLIBC__)
00106 void *trace[64];
00107 int trace_size = backtrace(trace, lengthof(trace));
00108
00109 char **messages = backtrace_symbols(trace, trace_size);
00110 for (int i = 0; i < trace_size; i++) {
00111 buffer += seprintf(buffer, last, " [%02i] %s\n", i, messages[i]);
00112 }
00113 free(messages);
00114 #elif defined(SUNOS)
00115 ucontext_t uc;
00116 if (getcontext(&uc) != 0) {
00117 buffer += seprintf(buffer, last, " getcontext() failed\n\n");
00118 return buffer;
00119 }
00120
00121 StackWalkerParams wp = { &buffer, last, 0 };
00122 walkcontext(&uc, &CrashLogUnix::SunOSStackWalker, &wp);
00123 #else
00124 buffer += seprintf(buffer, last, " Not supported.\n");
00125 #endif
00126 return buffer + seprintf(buffer, last, "\n");
00127 }
00128 public:
00133 CrashLogUnix(int signum) :
00134 signum(signum)
00135 {
00136 }
00137 };
00138
00140 static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL };
00141
00147 static void CDECL HandleCrash(int signum)
00148 {
00149
00150 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00151 signal(*i, SIG_DFL);
00152 }
00153
00154 if (GamelogTestEmergency()) {
00155 printf("A serious fault condition occured in the game. The game will shut down.\n");
00156 printf("As you loaded an emergency savegame no crash information will be generated.\n");
00157 abort();
00158 }
00159
00160 if (SaveloadCrashWithMissingNewGRFs()) {
00161 printf("A serious fault condition occured in the game. The game will shut down.\n");
00162 printf("As you loaded an savegame for which you do not have the required NewGRFs\n");
00163 printf("no crash information will be generated.\n");
00164 abort();
00165 }
00166
00167 CrashLogUnix log(signum);
00168 log.MakeCrashLog();
00169
00170 CrashLog::AfterCrashLogCleanup();
00171 abort();
00172 }
00173
00174 void CrashLog::InitialiseCrashLog()
00175 {
00176 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00177 signal(*i, HandleCrash);
00178 }
00179 }