crashlog_unix.cpp

Go to the documentation of this file.
00001 /* $Id: crashlog_unix.cpp 18855 2010-01-18 10:11:27Z smatz $ */
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 #include "../../saveload/saveload.h"
00017 
00018 #include <errno.h>
00019 #include <signal.h>
00020 #include <sys/utsname.h>
00021 
00022 #if defined(__GLIBC__)
00023 /* Execinfo (and thus making stacktraces) is a GNU extension */
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   /* virtual */ 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   /* virtual */ 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     /* Resolve program counter to file and nearest symbol (if possible) */
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   /* virtual */ 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   /* Disable all handling of signals by us, so we don't go into infinite loops. */
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 /* static */ void CrashLog::InitialiseCrashLog()
00175 {
00176   for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00177     signal(*i, HandleCrash);
00178   }
00179 }

Generated on Wed Apr 21 20:31:51 2010 for OpenTTD by  doxygen 1.6.1