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 "macos.h"
00017
00018 #include <errno.h>
00019 #include <signal.h>
00020 #include <mach-o/arch.h>
00021 #include <dlfcn.h>
00022 #include <cxxabi.h>
00023
00024
00025
00026 #if defined(__i386__)
00027 #define IS_ALIGNED(addr) (((uintptr_t)(addr) & 0xf) == 8)
00028 #else
00029 #define IS_ALIGNED(addr) (((uintptr_t)(addr) & 0xf) == 0)
00030 #endif
00031
00032
00033 #if __LP64__
00034 #define PRINTF_PTR "0x%016lx"
00035 #else
00036 #define PRINTF_PTR "0x%08lx"
00037 #endif
00038
00039 #define MAX_STACK_FRAMES 64
00040
00044 class CrashLogOSX : public CrashLog {
00046 int signum;
00047
00048 char filename_log[MAX_PATH];
00049 char filename_save[MAX_PATH];
00050 char filename_screenshot[MAX_PATH];
00051
00052 char *LogOSVersion(char *buffer, const char *last) const
00053 {
00054 int ver_maj, ver_min, ver_bug;
00055 GetMacOSVersion(&ver_maj, &ver_min, &ver_bug);
00056
00057 const NXArchInfo *arch = NXGetLocalArchInfo();
00058
00059 return buffer + seprintf(buffer, last,
00060 "Operating system:\n"
00061 " Name: Mac OS X\n"
00062 " Release: %d.%d.%d\n"
00063 " Machine: %s\n"
00064 " Min Ver: %d\n\n",
00065 ver_maj, ver_min, ver_bug,
00066 arch != NULL ? arch->description : "unknown",
00067 MAC_OS_X_VERSION_MIN_REQUIRED
00068 );
00069 }
00070
00071 char *LogError(char *buffer, const char *last, const char *message) const
00072 {
00073 return buffer + seprintf(buffer, last,
00074 "Crash reason:\n"
00075 " Signal: %s (%d)\n"
00076 " Message: %s\n\n",
00077 strsignal(this->signum),
00078 this->signum,
00079 message == NULL ? "<none>" : message
00080 );
00081 }
00082
00083 char *LogStacktrace(char *buffer, const char *last) const
00084 {
00085
00086
00087
00088
00089 buffer += seprintf(buffer, last, "\nStacktrace:\n");
00090
00091 void **frame;
00092 #if defined(__ppc__) || defined(__ppc64__)
00093
00094 __asm__ volatile("mr %0, r1" : "=r" (frame));
00095 #else
00096 frame = (void **)__builtin_frame_address(0);
00097 #endif
00098
00099 for (int i = 0; frame != NULL && i < MAX_STACK_FRAMES; i++) {
00100
00101 #if defined(__ppc__) || defined(__ppc64__)
00102 void *ip = frame[2];
00103 #else
00104 void *ip = frame[1];
00105 #endif
00106 if (ip == NULL) break;
00107
00108
00109 buffer += seprintf(buffer, last, " [%02d]", i);
00110
00111 Dl_info dli;
00112 bool dl_valid = dladdr(ip, &dli) != 0;
00113
00114 const char *fname = "???";
00115 if (dl_valid && dli.dli_fname) {
00116
00117 const char *s = strrchr(dli.dli_fname, '/');
00118 if (s != NULL) {
00119 fname = s + 1;
00120 } else {
00121 fname = dli.dli_fname;
00122 }
00123 }
00124
00125 buffer += seprintf(buffer, last, " %-20s " PRINTF_PTR, fname, (uintptr_t)ip);
00126
00127
00128 if (dl_valid && dli.dli_sname != NULL && dli.dli_saddr != NULL) {
00129
00130 int status = -1;
00131 char *func_name = abi::__cxa_demangle(dli.dli_sname, NULL, 0, &status);
00132
00133 long int offset = (intptr_t)ip - (intptr_t)dli.dli_saddr;
00134 buffer += seprintf(buffer, last, " (%s + %ld)", func_name != NULL ? func_name : dli.dli_sname, offset);
00135
00136 free(func_name);
00137 }
00138 buffer += seprintf(buffer, last, "\n");
00139
00140
00141 void **next = (void **)frame[0];
00142
00143 if (next <= frame || !IS_ALIGNED(next)) break;
00144 frame = next;
00145 }
00146
00147 return buffer + seprintf(buffer, last, "\n");
00148 }
00149
00150 public:
00155 CrashLogOSX(int signum) : signum(signum)
00156 {
00157 filename_log[0] = '\0';
00158 filename_save[0] = '\0';
00159 filename_screenshot[0] = '\0';
00160 }
00161
00163 bool MakeCrashLog()
00164 {
00165 char buffer[65536];
00166 bool ret = true;
00167
00168 printf("Crash encountered, generating crash log...\n");
00169 this->FillCrashLog(buffer, lastof(buffer));
00170 printf("%s\n", buffer);
00171 printf("Crash log generated.\n\n");
00172
00173 printf("Writing crash log to disk...\n");
00174 if (!this->WriteCrashLog(buffer, filename_log, lastof(filename_log))) {
00175 filename_log[0] = '\0';
00176 ret = false;
00177 }
00178
00179 printf("Writing crash savegame...\n");
00180 if (!this->WriteSavegame(filename_save, lastof(filename_save))) {
00181 filename_save[0] = '\0';
00182 ret = false;
00183 }
00184
00185 printf("Writing crash savegame...\n");
00186 if (!this->WriteScreenshot(filename_screenshot, lastof(filename_screenshot))) {
00187 filename_screenshot[0] = '\0';
00188 ret = false;
00189 }
00190
00191 return ret;
00192 }
00193
00195 void DisplayCrashDialog() const
00196 {
00197 static const char crash_title[] =
00198 "A serious fault condition occured in the game. The game will shut down.";
00199
00200 char message[1024];
00201 seprintf(message, lastof(message),
00202 "Please send the generated crash information and the last (auto)save to the developers. "
00203 "This will greatly help debugging. The correct place to do this is http://bugs.openttd.org.\n\n"
00204 "Generated file(s):\n%s\n%s\n%s",
00205 this->filename_log, this->filename_save, this->filename_screenshot);
00206
00207 ShowMacDialog(crash_title, message, "Quit");
00208 }
00209 };
00210
00212 static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL, SIGSYS };
00213
00219 void CDECL HandleCrash(int signum)
00220 {
00221
00222 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00223 signal(*i, SIG_DFL);
00224 }
00225
00226 if (GamelogTestEmergency()) {
00227 ShowMacDialog("A serious fault condition occured in the game. The game will shut down.",
00228 "As you loaded an emergency savegame no crash information will be generated.\n",
00229 "Quit");
00230 abort();
00231 }
00232
00233 CrashLogOSX log(signum);
00234 log.MakeCrashLog();
00235 log.DisplayCrashDialog();
00236
00237 CrashLog::AfterCrashLogCleanup();
00238 abort();
00239 }
00240
00241 void CrashLog::InitialiseCrashLog()
00242 {
00243 for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
00244 signal(*i, HandleCrash);
00245 }
00246 }