implemented simple crash handler
This commit is contained in:
+39
-1
@@ -108,7 +108,8 @@ target_include_directories(
|
||||
${OIIO_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(${OLIVE_TARGET}
|
||||
target_link_libraries(
|
||||
${OLIVE_TARGET}
|
||||
PRIVATE
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
@@ -127,6 +128,14 @@ target_link_libraries(${OLIVE_TARGET}
|
||||
${OIIO_LIBRARIES}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(
|
||||
${OLIVE_TARGET}
|
||||
PRIVATE
|
||||
DbgHelp
|
||||
)
|
||||
endif()
|
||||
|
||||
set(OLIVE_TS_FILES
|
||||
# FIXME: Empty variable
|
||||
)
|
||||
@@ -151,3 +160,32 @@ if(DOXYGEN_FOUND)
|
||||
set(DOXYGEN_EXTRACT_PRIVATE "YES")
|
||||
doxygen_add_docs(docs ALL ${OLIVE_SOURCES})
|
||||
endif()
|
||||
|
||||
set(OLIVE_CRASH_TARGET "crashhandler")
|
||||
|
||||
set(OLIVE_CRASH_SOURCES
|
||||
dialog/crashhandler/crashhandler.h
|
||||
dialog/crashhandler/crashhandler.cpp
|
||||
dialog/crashhandler/crashhandlermain.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
add_executable(
|
||||
${OLIVE_CRASH_TARGET}
|
||||
WIN32
|
||||
${OLIVE_CRASH_SOURCES}
|
||||
)
|
||||
else()
|
||||
add_executable(
|
||||
${OLIVE_CRASH_TARGET}
|
||||
${OLIVE_CRASH_SOURCES}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
${OLIVE_CRASH_TARGET}
|
||||
PRIVATE
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
)
|
||||
|
||||
@@ -22,6 +22,8 @@ set(OLIVE_SOURCES
|
||||
common/channellayout.h
|
||||
common/clamp.h
|
||||
common/constructors.h
|
||||
common/crashhandler.h
|
||||
common/crashhandler.cpp
|
||||
common/debug.h
|
||||
common/debug.cpp
|
||||
common/define.h
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "crashhandler.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#include <QStandardPaths>
|
||||
#include <QTextStream>
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
void crash_handler(int sig) {
|
||||
QString log_path = QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).filePath("olive_crash");
|
||||
QFile output(log_path);
|
||||
|
||||
output.open(QFile::WriteOnly);
|
||||
QTextStream ostream(&output);
|
||||
|
||||
ostream << "Signal: " << sig << "\n\n";
|
||||
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
// Use Windows stackwalk API
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(CONTEXT));
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
|
||||
DWORD image;
|
||||
STACKFRAME64 stackframe;
|
||||
ZeroMemory(&stackframe, sizeof(STACKFRAME64));
|
||||
|
||||
#ifdef _M_IX86
|
||||
image = IMAGE_FILE_MACHINE_I386;
|
||||
stackframe.AddrPC.Offset = context.Eip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Ebp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Esp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_X64
|
||||
image = IMAGE_FILE_MACHINE_AMD64;
|
||||
stackframe.AddrPC.Offset = context.Rip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Rsp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Rsp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_IA64
|
||||
image = IMAGE_FILE_MACHINE_IA64;
|
||||
stackframe.AddrPC.Offset = context.StIIP;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.IntSp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrBStore.Offset = context.RsBSP;
|
||||
stackframe.AddrBStore.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.IntSp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
|
||||
BOOL result = StackWalk64(
|
||||
image, process, thread,
|
||||
&stackframe, &context, NULL,
|
||||
SymFunctionTableAccess64, SymGetModuleBase64, NULL);
|
||||
|
||||
if (!result) { break; }
|
||||
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
DWORD64 displacement = 0;
|
||||
|
||||
ostream << "[" << i << "] ";
|
||||
|
||||
if (SymFromAddr(process, stackframe.AddrPC.Offset, &displacement, symbol)) {
|
||||
ostream << symbol->Name;
|
||||
//printf("[%i] %s\n", i, symbol->Name);
|
||||
} else {
|
||||
ostream << "???";
|
||||
//printf("[%i] ???\n", i);
|
||||
}
|
||||
|
||||
ostream << "\n";
|
||||
}
|
||||
|
||||
SymCleanup(process);
|
||||
#elif defined(Q_OS_LINUX)
|
||||
void *array[10];
|
||||
size_t size;
|
||||
|
||||
// get void*'s for all entries on the stack
|
||||
size = backtrace(array, 10);
|
||||
|
||||
// print out all the frames to stderr
|
||||
fprintf(stderr, "Error: signal %d:\n", sig);
|
||||
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
||||
#endif
|
||||
|
||||
output.close();
|
||||
|
||||
QProcess::startDetached(QStringLiteral("crashhandler"), {log_path});
|
||||
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CRASHHANDLER_H
|
||||
#define CRASHHANDLER_H
|
||||
|
||||
void crash_handler(int sig);
|
||||
|
||||
#endif // CRASHHANDLER_H
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "crashhandler.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QLabel>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
CrashHandlerDialog::CrashHandlerDialog(const char *log_file)
|
||||
{
|
||||
setWindowTitle(tr("Olive"));
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(new QLabel(tr("We're sorry, Olive has crashed. Please send the following log to the developers to "
|
||||
"help resolve this.")));
|
||||
|
||||
QTextEdit* edit = new QTextEdit();
|
||||
layout->addWidget(edit);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox();
|
||||
|
||||
// FIXME: Implement auto-reporting
|
||||
//buttons->addButton(tr("Send Error Report"), QDialogButtonBox::AcceptRole);
|
||||
//buttons->addButton(tr("Don't Send"), QDialogButtonBox::RejectRole);
|
||||
buttons->addButton(QDialogButtonBox::Ok);
|
||||
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
QFile log(log_file);
|
||||
if (log.open(QFile::ReadOnly | QFile::Text)) {
|
||||
edit->setText(log.readAll());
|
||||
log.close();
|
||||
}
|
||||
}
|
||||
|
||||
void CrashHandlerDialog::accept()
|
||||
{
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void CrashHandlerDialog::reject()
|
||||
{
|
||||
QDialog::reject();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef CRASHHANDLERDIALOG_H
|
||||
#define CRASHHANDLERDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class CrashHandlerDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CrashHandlerDialog(const char* log_file);
|
||||
|
||||
public slots:
|
||||
virtual void accept() override;
|
||||
|
||||
virtual void reject() override;
|
||||
|
||||
};
|
||||
|
||||
#endif // CRASHHANDLERDIALOG_H
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "crashhandler.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
CrashHandlerDialog chd(argv[1]);
|
||||
chd.open();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
@@ -35,11 +35,15 @@ extern "C" {
|
||||
#include <QSurfaceFormat>
|
||||
|
||||
#include "core.h"
|
||||
#include "common/crashhandler.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
av_log_set_level(AV_LOG_QUIET);
|
||||
|
||||
signal(SIGSEGV, crash_handler);
|
||||
signal(SIGABRT, crash_handler);
|
||||
|
||||
// Set OpenGL display profile (3.2 Core)
|
||||
QSurfaceFormat format;
|
||||
format.setVersion(3, 2);
|
||||
|
||||
Reference in New Issue
Block a user