diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index d2c819c37..e8c5d59fb 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -137,6 +137,11 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #include #endif +#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) +#include +#include +#endif + // Locations for searching the srb2.pk3 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2" @@ -238,6 +243,71 @@ SDL_bool framebuffer = SDL_FALSE; UINT8 keyboard_started = false; +#define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string) +#define CRASHLOG_WRITE(string) if (fd != -1) write(fd, string, strlen(string)) +#define CRASHLOG_STDERR_WRITE(string) \ + if (fd != -1)\ + write(fd, string, strlen(string));\ + I_OutputMsg("%s", string) + +static void write_backtrace(INT32 signal) +{ +#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) + int fd = -1; + size_t size; + time_t rawtime; + struct tm timeinfo; + + enum { BT_SIZE = 1024, STR_SIZE = 32 }; + void *array[BT_SIZE]; + char timestr[STR_SIZE]; + + const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n"; + const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr. + + fd = open(va("%s" PATHSEP "%s", srb2home, "crash-log.txt"), O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR); + + if (fd == -1) + I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n"); + + // Get the current time as a string. + time(&rawtime); + localtime_r(&rawtime, &timeinfo); + strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo); + + CRASHLOG_WRITE("------------------------\n"); // Nice looking seperator + + CRASHLOG_STDERR_WRITE("\n"); // Newline to look nice for both outputs. + CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message + STDERR_WRITE(error2); // Tell the user where the crash log is. + + // Tell the log when we crashed. + CRASHLOG_WRITE("Time of crash: "); + CRASHLOG_WRITE(timestr); + CRASHLOG_WRITE("\n"); + + // Give the crash log the cause and a nice 'Backtrace:' thing + // The signal is given to the user when the parent process sees we crashed. + CRASHLOG_WRITE("Cause: "); + CRASHLOG_WRITE(strsignal(signal)); + CRASHLOG_WRITE("\n"); // Newline for the signal name + + CRASHLOG_STDERR_WRITE("\nBacktrace:\n"); + + // Flood the output and log with the backtrace + size = backtrace(array, BT_SIZE); + backtrace_symbols_fd(array, size, fd); + backtrace_symbols_fd(array, size, STDERR_FILENO); + + CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :) + + close(fd); +#endif +} +#undef STDERR_WRITE +#undef CRASHLOG_WRITE +#undef CRASHLOG_STDERR_WRITE + static void I_ReportSignal(int num, int coredumped) { //static char msg[] = "oh no! back to reality!\r\n"; @@ -297,6 +367,7 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) { D_QuitNetGame(); // Fix server freezes CL_AbortDownloadResume(); + write_backtrace(num); I_ReportSignal(num, 0); I_ShutdownSystem(); signal(num, SIG_DFL); //default signal action @@ -687,6 +758,26 @@ static void I_RegisterSignals (void) #endif } +#ifdef NEWSIGNALHANDLER +static void signal_handler_child(INT32 num) +{ + write_backtrace(num); + + signal(num, SIG_DFL); //default signal action + raise(num); +} + +static void I_RegisterChildSignals(void) +{ + // If these defines don't exist, + // then compilation would have failed above us... + signal(SIGILL , signal_handler_child); + signal(SIGSEGV , signal_handler_child); + signal(SIGABRT , signal_handler_child); + signal(SIGFPE , signal_handler_child); +} +#endif + // //I_OutputMsg // @@ -2123,6 +2214,7 @@ static void I_Fork(void) newsignalhandler_Warn("fork()"); break; case 0: + I_RegisterChildSignals(); break; default: if (logstream)