Implement crash report system on Windows.
This commit is contained in:
parent
489cb4dbf5
commit
9e80ddb040
@ -81,14 +81,6 @@ set(CRASH_HANDLER_IMPL "")
|
|||||||
message(STATUS "Crash dumps are ${MultiMC_HANDLE_SEGV}")
|
message(STATUS "Crash dumps are ${MultiMC_HANDLE_SEGV}")
|
||||||
if (MultiMC_HANDLE_SEGV)
|
if (MultiMC_HANDLE_SEGV)
|
||||||
add_definitions(-DHANDLE_SEGV)
|
add_definitions(-DHANDLE_SEGV)
|
||||||
if (UNIX)
|
|
||||||
set(CRASH_HANDLER_IMPL "UnixCrash.cpp")
|
|
||||||
elseif (WIN32)
|
|
||||||
message(WARNING "The crash dump system is not currently implemented on Windows")
|
|
||||||
#set(CRASH_HANDLER_IMPL "WinCrash.cpp")
|
|
||||||
else ()
|
|
||||||
message(WARNING "The crash dump system is not supported on this platform.")
|
|
||||||
endif ()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
option(MultiMC_TEST_SEGV "Intentionally segfault on startup to test crash handling." OFF)
|
option(MultiMC_TEST_SEGV "Intentionally segfault on startup to test crash handling." OFF)
|
||||||
@ -275,7 +267,7 @@ SET(MULTIMC_SOURCES
|
|||||||
|
|
||||||
# Crash handling
|
# Crash handling
|
||||||
HandleCrash.h
|
HandleCrash.h
|
||||||
${CRASH_HANDLER_IMPL}
|
HandleCrash.cpp
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
logger/QsDebugOutput.cpp
|
logger/QsDebugOutput.cpp
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// This is the Unix implementation of MultiMC's crash handling system.
|
// This is the Unix implementation of MultiMC's crash handling system.
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <execinfo.h>
|
#include <iostream>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -8,7 +8,11 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
#include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <MultiMC.h>
|
#include <MultiMC.h>
|
||||||
|
|
||||||
@ -20,7 +24,7 @@
|
|||||||
#define BT_SIZE 20
|
#define BT_SIZE 20
|
||||||
|
|
||||||
|
|
||||||
#define DUMPF_NAME_FMT "mmc-crash-%X.bm\0" // Black magic? Bowel movement? Dump?
|
#define DUMPF_NAME_FMT "mmc-crash-%X.bm" // Black magic? Bowel movement? Dump?
|
||||||
// 1234567890 1234
|
// 1234567890 1234
|
||||||
// The maximum number of digits in a unix timestamp when encoded in hexadecimal is about 17.
|
// The maximum number of digits in a unix timestamp when encoded in hexadecimal is about 17.
|
||||||
// Our format string is ~14 characters long.
|
// Our format string is ~14 characters long.
|
||||||
@ -29,43 +33,108 @@
|
|||||||
|
|
||||||
// {{{ Handling
|
// {{{ Handling
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
// #ThanksMicrosoft
|
||||||
|
// Blame Microsoft for this atrocity.
|
||||||
|
void dprintf(int fd, const char* fmt...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
char buffer[10240];
|
||||||
|
// Just sprintf to a really long string and hope it works...
|
||||||
|
// This is a hack, but I can't think of a better way to do it easily.
|
||||||
|
int len = vsprintf(buffer, fmt, args);
|
||||||
|
printf(buffer, fmt, args);
|
||||||
|
write(fd, buffer, len);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void getVsnType(char* out);
|
void getVsnType(char* out);
|
||||||
void readFromTo(int from, int to);
|
void readFromTo(int from, int to);
|
||||||
|
|
||||||
// The signal handler. If this function is called, it means shit has probably collided with some sort of device one might use to keep oneself cool.
|
void dumpMiscInfo(int dumpFile)
|
||||||
void handler(int sig)
|
|
||||||
{
|
{
|
||||||
// Variables for storing crash info.
|
|
||||||
void* trace[BT_SIZE]; // Backtrace frames
|
|
||||||
size_t size; // The backtrace size
|
|
||||||
|
|
||||||
bool gotSysInfo = false; // True if system info check succeeded
|
|
||||||
utsname sysinfo; // System information
|
|
||||||
|
|
||||||
time_t unixTime = 0; // Unix timestamp. Used to give our crash dumps "unique" names.
|
|
||||||
|
|
||||||
char dumpFileName[DUMPF_NAME_LEN]; // The name of the file we're dumping to.
|
|
||||||
int dumpFile; // File descriptor for our dump file.
|
|
||||||
|
|
||||||
char vsnType[42]; // The version type. If it's more than 42 chars, the universe might implode...
|
char vsnType[42]; // The version type. If it's more than 42 chars, the universe might implode...
|
||||||
|
|
||||||
int otherFile; // File descriptor for other things.
|
// Get MMC info.
|
||||||
|
getVsnType(vsnType);
|
||||||
|
|
||||||
fprintf(stderr, "Fatal error! Received signal %d\n", sig);
|
|
||||||
|
|
||||||
|
|
||||||
// Get the backtrace.
|
|
||||||
size = backtrace(trace, BT_SIZE);
|
|
||||||
|
|
||||||
|
|
||||||
// Get system info.
|
|
||||||
gotSysInfo = uname(&sysinfo) >= 0;
|
|
||||||
|
|
||||||
|
|
||||||
// Get MMC info.
|
// Get MMC info.
|
||||||
getVsnType(vsnType);
|
getVsnType(vsnType);
|
||||||
|
|
||||||
|
dprintf(dumpFile, "MultiMC Version: %s\n", BuildConfig.VERSION_CSTR);
|
||||||
|
dprintf(dumpFile, "MultiMC Version Type: %s\n", vsnType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpBacktrace(int dumpFile)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
// Variables for storing crash info.
|
||||||
|
void* trace[BT_SIZE]; // Backtrace frames
|
||||||
|
size_t size; // The backtrace size
|
||||||
|
|
||||||
|
// Get the backtrace.
|
||||||
|
size = backtrace(trace, BT_SIZE);
|
||||||
|
|
||||||
|
// Dump the backtrace
|
||||||
|
dprintf(dumpFile, "---- BEGIN BACKTRACE ----\n");
|
||||||
|
backtrace_symbols_fd(trace, size, dumpFile);
|
||||||
|
dprintf(dumpFile, "---- END BACKTRACE ----\n");
|
||||||
|
#elif defined Q_OS_WIN32
|
||||||
|
dprintf(dumpFile, "---- BEGIN BACKTRACE ----\n");
|
||||||
|
dprintf(dumpFile, "Not yet implemented on this platform.\n");
|
||||||
|
dprintf(dumpFile, "---- END BACKTRACE ----\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpSysInfo(int dumpFile)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
bool gotSysInfo = false; // True if system info check succeeded
|
||||||
|
utsname sysinfo; // System information
|
||||||
|
|
||||||
|
// Dump system info
|
||||||
|
if (uname(&sysinfo) >= 0)
|
||||||
|
{
|
||||||
|
dprintf(dumpFile, "OS System: %s\n", sysinfo.sysname);
|
||||||
|
dprintf(dumpFile, "OS Machine: %s\n", sysinfo.machine);
|
||||||
|
dprintf(dumpFile, "OS Release: %s\n", sysinfo.release);
|
||||||
|
dprintf(dumpFile, "OS Version: %s\n", sysinfo.version);
|
||||||
|
} else {
|
||||||
|
dprintf(dumpFile, "OS System: Unknown Unix");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// TODO: Get more information here.
|
||||||
|
dprintf(dumpFile, "OS System: Windows");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpLogs(int dumpFile)
|
||||||
|
{
|
||||||
|
int otherFile;
|
||||||
|
|
||||||
|
// Attempt to attach the log file if the logger was initialized.
|
||||||
|
dprintf(dumpFile, "---- BEGIN LOGS ----\n");
|
||||||
|
if (loggerInitialized)
|
||||||
|
{
|
||||||
|
otherFile = open("MultiMC-0.log", O_RDONLY);
|
||||||
|
readFromTo(otherFile, dumpFile);
|
||||||
|
} else {
|
||||||
|
dprintf(dumpFile, "Logger not initialized.\n");
|
||||||
|
}
|
||||||
|
dprintf(dumpFile, "---- END LOGS ----\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The signal handler. If this function is called, it means shit has probably collided with some sort of device one might use to keep oneself cool.
|
||||||
|
void handler(int sig)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Fatal error! Received signal %d\n", sig);
|
||||||
|
|
||||||
|
time_t unixTime = 0; // Unix timestamp. Used to give our crash dumps "unique" names.
|
||||||
|
|
||||||
|
char dumpFileName[DUMPF_NAME_LEN]; // The name of the file we're dumping to.
|
||||||
|
int dumpFile; // File descriptor for our dump file.
|
||||||
|
|
||||||
// Determine what our dump file should be called.
|
// Determine what our dump file should be called.
|
||||||
// We'll just call it "mmc-crash-<unixtime>.dump"
|
// We'll just call it "mmc-crash-<unixtime>.dump"
|
||||||
@ -83,7 +152,8 @@ void handler(int sig)
|
|||||||
// Now, we need to open the file.
|
// Now, we need to open the file.
|
||||||
// Fail if it already exists. This should never happen.
|
// Fail if it already exists. This should never happen.
|
||||||
dumpFile = open(dumpFileName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
dumpFile = open(dumpFileName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
|
||||||
|
|
||||||
if (dumpFile >= 0)
|
if (dumpFile >= 0)
|
||||||
{
|
{
|
||||||
// If we opened the dump file successfully.
|
// If we opened the dump file successfully.
|
||||||
@ -92,53 +162,30 @@ void handler(int sig)
|
|||||||
|
|
||||||
// Dump misc info
|
// Dump misc info
|
||||||
dprintf(dumpFile, "Unix Time: %d\n", unixTime);
|
dprintf(dumpFile, "Unix Time: %d\n", unixTime);
|
||||||
dprintf(dumpFile, "MultiMC Version: %s\n", BuildConfig.VERSION_CSTR);
|
|
||||||
dprintf(dumpFile, "MultiMC Version Type: %s\n", vsnType);
|
|
||||||
dprintf(dumpFile, "Signal: %d\n", sig);
|
dprintf(dumpFile, "Signal: %d\n", sig);
|
||||||
|
dumpMiscInfo(dumpFile);
|
||||||
// Dump system info
|
|
||||||
if (gotSysInfo)
|
dprintf(dumpFile, "\n");
|
||||||
{
|
|
||||||
dprintf(dumpFile, "OS System: %s\n", sysinfo.sysname);
|
dumpSysInfo(dumpFile);
|
||||||
dprintf(dumpFile, "OS Machine: %s\n", sysinfo.machine);
|
|
||||||
dprintf(dumpFile, "OS Release: %s\n", sysinfo.release);
|
|
||||||
dprintf(dumpFile, "OS Version: %s\n", sysinfo.version);
|
|
||||||
} else {
|
|
||||||
dprintf(dumpFile, "OS System: Unknown Unix");
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf(dumpFile, "\n");
|
dprintf(dumpFile, "\n");
|
||||||
|
|
||||||
// Dump the backtrace
|
dumpBacktrace(dumpFile);
|
||||||
dprintf(dumpFile, "---- BEGIN BACKTRACE ----\n");
|
|
||||||
backtrace_symbols_fd(trace, size, dumpFile);
|
|
||||||
dprintf(dumpFile, "---- END BACKTRACE ----\n");
|
|
||||||
|
|
||||||
dprintf(dumpFile, "\n");
|
dprintf(dumpFile, "\n");
|
||||||
|
|
||||||
// Attempt to attach the log file if the logger was initialized.
|
|
||||||
dprintf(dumpFile, "---- BEGIN LOGS ----\n");
|
|
||||||
if (loggerInitialized)
|
|
||||||
{
|
|
||||||
otherFile = open("MultiMC-0.log", O_RDONLY);
|
|
||||||
readFromTo(otherFile, dumpFile);
|
|
||||||
} else {
|
|
||||||
dprintf(dumpFile, "Logger not initialized.\n");
|
|
||||||
}
|
|
||||||
dprintf(dumpFile, "---- END LOGS ----\n");
|
|
||||||
|
|
||||||
// DIE DIE DIE!
|
// DIE DIE DIE!
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to open dump file %s to write crash info (%d). Here's a backtrace on stderr instead.\n", dumpFileName, errno);
|
fprintf(stderr, "Failed to open dump file %s to write crash info (ERRNO: %d)\n", dumpFileName, errno);
|
||||||
// If we can't dump to the file, dump a backtrace to stderr and give up.
|
|
||||||
backtrace_symbols_fd(trace, size, STDERR_FILENO);
|
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Reads data from the file descriptor on the first argument into the second argument.
|
// Reads data from the file descriptor on the first argument into the second argument.
|
||||||
void readFromTo(int from, int to)
|
void readFromTo(int from, int to)
|
||||||
{
|
{
|
Loading…
Reference in New Issue
Block a user