crashlog_unix.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
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 /* Execinfo (and thus making stacktraces) is a GNU extension */
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   /* virtual */ 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   /* virtual */ 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     /* Resolve program counter to file and nearest symbol (if possible) */
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   /* virtual */ 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   /* Disable all handling of signals by us, so we don't go into infinite loops. */
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 /* static */ void CrashLog::InitialiseCrashLog()
00167 {
00168   for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00169     signal(*i, HandleCrash);
00170   }
00171 }

Generated on Sat Dec 26 20:06:03 2009 for OpenTTD by  doxygen 1.5.6