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