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