Merge branch 'print-backtrace' into 'next'

Print a backtrace when SRB2 crashes in a Unix-like environment.

See merge request STJr/SRB2!1288
This commit is contained in:
LJ Sonic 2021-03-07 08:26:44 -05:00
commit 0765004188

View file

@ -137,6 +137,11 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
#include <errno.h>
#endif
#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
#include <execinfo.h>
#include <time.h>
#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)