crashpad: updated crash handler

This commit is contained in:
itsmattkc
2020-09-22 18:42:51 +10:00
parent 871bc08c12
commit cd47676043
11 changed files with 298 additions and 285 deletions
+2 -3
View File
@@ -23,10 +23,9 @@ set(OLIVE_SOURCES
common/clamp.h
common/commandlineparser.h
common/commandlineparser.cpp
common/crashhandler.h
common/crashhandler.cpp
common/crashpadinterface.cpp
common/crashpadinterface.h
common/crashpadinterface.cpp
common/crashpadutils.h
common/debug.h
common/debug.cpp
common/define.h
-150
View File
@@ -1,150 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "crashhandler.h"
#include <QApplication>
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QStandardPaths>
#include <QTextStream>
#include <QtGlobal>
#if defined(Q_OS_WINDOWS)
#include <Windows.h>
#include <DbgHelp.h>
#include <stdio.h>
#include <stdlib.h>
#elif defined(Q_OS_MAC) || defined(Q_OS_LINUX)
#include <execinfo.h>
#endif
#include "common/filefunctions.h"
OLIVE_NAMESPACE_ENTER
void crash_handler(int sig)
{
QString log_path = QDir(FileFunctions::GetTempFilePath()).filePath(QStringLiteral("olive_crash"));
QFile output(log_path);
output.open(QFile::WriteOnly);
QTextStream ostream(&output);
#ifdef GITHASH
ostream << "Version: " << GITHASH << "\n";
#endif
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_MAC) || 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
backtrace_symbols_fd(array, size, output.handle());
#endif
output.close();
QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("olive-crashhandler"));
QProcess::startDetached(crash_handler_exe, {log_path});
exit(1);
}
OLIVE_NAMESPACE_EXIT
+38 -43
View File
@@ -23,75 +23,67 @@
#ifdef USE_CRASHPAD
#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QMessageBox>
#include <QProcess>
#include "crashpadutils.h"
#include "filefunctions.h"
#ifdef Q_OS_WINDOWS
#ifdef OS_WIN
#include <Windows.h>
#endif
// Copied from base::FilePath to match its macro
#if defined(OS_POSIX)
// On most platforms, native pathnames are char arrays, and the encoding
// may or may not be specified. On Mac OS X, native pathnames are encoded
// in UTF-8.
#define TO_BASE_STRING_TYPE(x) x.toStdString()
#elif defined(OS_WIN)
// On Windows, for Unicode-aware applications, native pathnames are wchar_t
// arrays encoded in UTF-16.
#define TO_BASE_STRING_TYPE(x) x.toStdWString()
#endif // OS_WIN
crashpad::CrashpadClient *client;
bool ShowCrashConfirmation()
QString GenerateReportPath()
{
QString msg = QCoreApplication::translate("CrashReport",
"We're sorry, Olive has crashed. "
"Would you like to send an error report to "
"help developers fix this issue?\n\n"
"Crash reports are anonymous and only send "
"non-specific details about your computer and"
"how the crash occurred.");
return (QMessageBox::critical(nullptr,
QString(),
msg,
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes);
return QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("reports"));
}
#ifdef Q_OS_WINDOWS
base::FilePath GenerateReportPathForCrashpad()
{
return base::FilePath(QSTRING_TO_BASE_STRING(GenerateReportPath()));
}
#if defined(OS_WIN)
LONG WINAPI Win32ExceptionHandler(_EXCEPTION_POINTERS *ExceptionInfo)
{
if (ShowCrashConfirmation()) {
client->DumpAndCrash(ExceptionInfo);
}
QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("olive-crashhandler"));
QProcess::startDetached(crash_handler_exe, {GenerateReportPath(), QString::number(QDateTime::currentSecsSinceEpoch())});
client->DumpAndCrash(ExceptionInfo);
return EXCEPTION_CONTINUE_SEARCH;
}
#elif defined(OS_LINUX)
bool LinuxExceptionHandler(int, siginfo_t*, ucontext_t*)
{
QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("olive-crashhandler"));
QProcess::startDetached(crash_handler_exe, {GenerateReportPath(), QString::number(QDateTime::currentSecsSinceEpoch())});
// Returning false signals to Crashpad to proceed with its own exception handling
return false;
}
#endif
bool InitializeCrashpad()
{
QString exe_dir = QCoreApplication::applicationDirPath();
#ifdef OS_WIN
base::FilePath handler(QSTRING_TO_BASE_STRING(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler.exe"))));
#else
// FIXME: On Linux, probably should put this in a subdir so that it doesn't conflict with
// anything else in /usr/bin
#ifdef Q_OS_WINDOWS
base::FilePath handler(TO_BASE_STRING_TYPE(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler.exe"))));
#else
base::FilePath handler(TO_BASE_STRING_TYPE(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler"))));
base::FilePath handler(QSTRING_TO_BASE_STRING(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler"))));
#endif
base::FilePath reports_dir(TO_BASE_STRING_TYPE(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath("reports")));
base::FilePath reports_dir = GenerateReportPathForCrashpad();
base::FilePath metrics_dir(TO_BASE_STRING_TYPE(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath("metrics")));
std::string url = "https://olivevideoeditor.org/crashpad/report.php";
base::FilePath metrics_dir(QSTRING_TO_BASE_STRING(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("metrics"))));
// Metadata that will be posted to the server with the crash report map
std::map<std::string, std::string> annotations;
@@ -105,19 +97,22 @@ bool InitializeCrashpad()
std::unique_ptr<crashpad::CrashReportDatabase> database = crashpad::CrashReportDatabase::Initialize(reports_dir);
if (database == NULL) return false;
// Enable automated crash uploads
// Disable automated crash uploads
crashpad::Settings *settings = database->GetSettings();
if (settings == NULL) return false;
settings->SetUploadsEnabled(true);
settings->SetUploadsEnabled(false);
// Start crash handler
client = new crashpad::CrashpadClient();
bool status = client->StartHandler(handler, reports_dir, metrics_dir,
url, annotations, arguments, true, true);
"https://olivevideoeditor.org/crashpad/report.php",
annotations, arguments, true, true);
// Override Crashpad exception filter with our own
#ifdef Q_OS_WINDOWS
#if defined(OS_WIN)
SetUnhandledExceptionFilter(Win32ExceptionHandler);
#elif defined(OS_LINUX)
crashpad::CrashpadClient::SetFirstChanceExceptionHandler(LinuxExceptionHandler);
#endif
return status;
-1
View File
@@ -23,7 +23,6 @@
#ifdef USE_CRASHPAD
#include <client/crashpad_client.h>
#include <client/crash_report_database.h>
#include <client/settings.h>
@@ -18,15 +18,23 @@
***/
#ifndef CRASHHANDLER_H
#define CRASHHANDLER_H
#ifndef CRASHPADUTILS_H
#define CRASHPADUTILS_H
#include "common/define.h"
#include <client/crashpad_client.h>
OLIVE_NAMESPACE_ENTER
// Copied from base::FilePath to match its macro
#if defined(OS_POSIX)
// On most platforms, native pathnames are char arrays, and the encoding
// may or may not be specified. On Mac OS X, native pathnames are encoded
// in UTF-8.
#define QSTRING_TO_BASE_STRING(x) x.toStdString()
#define BASE_STRING_TO_QSTRING(x) QString::fromStdString(x)
#elif defined(OS_WIN)
// On Windows, for Unicode-aware applications, native pathnames are wchar_t
// arrays encoded in UTF-16.
#define QSTRING_TO_BASE_STRING(x) x.toStdWString()
#define BASE_STRING_TO_QSTRING(x) QString::fromStdWString(x)
#endif // OS_WIN
void crash_handler(int sig);
OLIVE_NAMESPACE_EXIT
#endif // CRASHHANDLER_H
#endif // CRASHPADUTILS_H