2019-04-09 07:44:44 +00:00
|
|
|
#include "CrashHandler.h"
|
|
|
|
#include "BugReporting.h"
|
|
|
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QFileDialog>
|
2019-04-09 19:33:13 +00:00
|
|
|
#include <QStandardPaths>
|
2019-04-09 07:44:44 +00:00
|
|
|
#include <QTime>
|
2019-04-09 19:33:13 +00:00
|
|
|
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QString>
|
2019-04-09 07:44:44 +00:00
|
|
|
#include <QFile>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QMap>
|
2019-04-09 19:33:13 +00:00
|
|
|
#include <QProcess>
|
2019-04-09 07:44:44 +00:00
|
|
|
|
|
|
|
#if defined (Q_OS_LINUX)
|
|
|
|
#include "client/linux/handler/exception_handler.h"
|
|
|
|
#elif defined (Q_OS_WIN32)
|
|
|
|
#include "client/windows/handler/exception_handler.h"
|
|
|
|
#elif defined (Q_OS_MACOS)
|
|
|
|
#include "client/mac/handler/exception_handler.h"
|
|
|
|
#endif // Q_OS
|
|
|
|
|
2019-04-09 19:33:13 +00:00
|
|
|
static google_breakpad::ExceptionHandler *exceptionHandler = nullptr;
|
2019-04-09 07:44:44 +00:00
|
|
|
|
2019-04-09 19:33:13 +00:00
|
|
|
static void finishCrashHandler()
|
|
|
|
{
|
|
|
|
delete exceptionHandler;
|
|
|
|
}
|
2019-04-09 07:44:44 +00:00
|
|
|
|
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
// Called if crash dump was successfully created
|
|
|
|
// Saves path to file
|
|
|
|
bool callback(const wchar_t *_dump_dir,
|
|
|
|
const wchar_t *_minidump_id,
|
|
|
|
void *context, EXCEPTION_POINTERS *exinfo,
|
|
|
|
MDRawAssertionInfo *assertion,
|
|
|
|
bool success)
|
|
|
|
{
|
2019-04-09 19:33:13 +00:00
|
|
|
const QDir dir = QString::fromWCharArray(_dump_dir);
|
|
|
|
const QString id = QString::fromWCharArray(_minidump_id);
|
2019-04-10 19:10:30 +00:00
|
|
|
QProcess::startDetached(QCoreApplication::applicationFilePath(),
|
|
|
|
{ "--start-crash-handler", dir.filePath(id + ".dmp") });
|
2019-04-10 11:26:30 +00:00
|
|
|
_exit(1);
|
2019-04-09 07:44:44 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#elif defined (Q_OS_LINUX)
|
|
|
|
// Called if crash dump was successfully created
|
|
|
|
// Saves path to file
|
|
|
|
bool callback(const google_breakpad::MinidumpDescriptor &md, void *context, bool b)
|
|
|
|
{
|
2019-04-10 19:10:30 +00:00
|
|
|
QProcess::startDetached(QCoreApplication::applicationFilePath(),
|
|
|
|
{ "--start-crash-handler", md.path() });
|
2019-04-10 11:26:30 +00:00
|
|
|
_exit(1);
|
2019-04-09 07:44:44 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#elif defined (Q_OS_MACOS)
|
|
|
|
// Called if crash dump was successfully created
|
|
|
|
// Saves path to file
|
|
|
|
bool callback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded)
|
|
|
|
{
|
2019-04-09 19:33:13 +00:00
|
|
|
const QDir dir = QString::fromUtf8(dump_dir);
|
|
|
|
const QString id = QString::fromUtf8(minidump_id);
|
2019-04-10 19:10:30 +00:00
|
|
|
QProcess::startDetached(QCoreApplication::applicationFilePath(),
|
|
|
|
{ "--start-crash-handler", dir.filePath(id + ".dmp") });
|
2019-04-10 11:26:30 +00:00
|
|
|
_exit(1);
|
2019-04-09 07:44:44 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif // Q_OS
|
|
|
|
|
2019-04-09 19:33:13 +00:00
|
|
|
void initCrashHandler()
|
2019-04-09 07:44:44 +00:00
|
|
|
{
|
2019-04-09 19:33:13 +00:00
|
|
|
if (exceptionHandler) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Here will be placed crash dump at the first place
|
|
|
|
// and then moved if needed
|
|
|
|
|
|
|
|
#if defined (Q_OS_LINUX)
|
|
|
|
static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString();
|
|
|
|
exceptionHandler = new google_breakpad::ExceptionHandler(google_breakpad::MinidumpDescriptor(tmpLocation),
|
|
|
|
nullptr,
|
|
|
|
callback,
|
|
|
|
nullptr,
|
|
|
|
true,
|
|
|
|
-1);
|
|
|
|
#elif defined (Q_OS_MACOS)
|
|
|
|
static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString();
|
|
|
|
exceptionHandler = new google_breakpad::ExceptionHandler(tmpLocation,
|
|
|
|
nullptr,
|
|
|
|
callback,
|
|
|
|
nullptr,
|
|
|
|
true,
|
|
|
|
nullptr);
|
|
|
|
#else
|
|
|
|
static std::wstring tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdWString();
|
|
|
|
exceptionHandler = new google_breakpad::ExceptionHandler(tmpLocation,
|
|
|
|
nullptr,
|
|
|
|
callback,
|
|
|
|
nullptr,
|
|
|
|
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
|
|
|
#endif
|
|
|
|
atexit(finishCrashHandler);
|
2019-04-09 07:44:44 +00:00
|
|
|
}
|
|
|
|
|
2019-04-09 19:33:13 +00:00
|
|
|
void showCrashDialog(const QString &dumpFile)
|
|
|
|
{
|
2019-04-09 07:44:44 +00:00
|
|
|
QMessageBox mb;
|
2019-04-10 11:32:21 +00:00
|
|
|
mb.setWindowTitle(QObject::tr("Crash"));
|
2019-04-09 19:33:13 +00:00
|
|
|
mb.setText(QObject::tr("Cutter received a signal it can't handle and will close.<br/>"
|
2019-04-10 11:32:21 +00:00
|
|
|
"Would you like to create a crash dump for a bug report?"));
|
2019-04-09 07:44:44 +00:00
|
|
|
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
2019-04-10 11:32:21 +00:00
|
|
|
mb.button(QMessageBox::Yes)->setText(QObject::tr("Create a Crash Dump"));
|
|
|
|
mb.button(QMessageBox::No)->setText(QObject::tr("Quit"));
|
2019-04-09 07:44:44 +00:00
|
|
|
mb.setDefaultButton(QMessageBox::Yes);
|
|
|
|
|
2019-04-09 19:33:13 +00:00
|
|
|
bool ok = false;
|
2019-04-09 07:44:44 +00:00
|
|
|
int ret = mb.exec();
|
|
|
|
if (ret == QMessageBox::Yes) {
|
|
|
|
QString dumpSaveFileName;
|
|
|
|
int placementFailCounter = 0;
|
|
|
|
do {
|
|
|
|
placementFailCounter++;
|
|
|
|
if (placementFailCounter == 4) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dumpSaveFileName = QFileDialog::getSaveFileName(nullptr,
|
|
|
|
QObject::tr("Choose a directory to save the crash dump in"),
|
|
|
|
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) +
|
|
|
|
QDir::separator() +
|
|
|
|
"Cutter_crash_dump_"
|
2019-04-10 11:32:21 +00:00
|
|
|
+ QDate::currentDate().toString("dd.MM.yy") + "_"
|
|
|
|
+ QTime::currentTime().toString("HH.mm.ss") + ".dmp",
|
|
|
|
QObject::tr("Minidump (*.dmp)"));
|
2019-04-09 07:44:44 +00:00
|
|
|
|
|
|
|
if (dumpSaveFileName.isEmpty()) {
|
2019-04-09 19:33:13 +00:00
|
|
|
return;
|
2019-04-09 07:44:44 +00:00
|
|
|
}
|
2019-04-09 19:33:13 +00:00
|
|
|
if (QFile::rename(dumpFile, dumpSaveFileName)) {
|
|
|
|
ok = true;
|
2019-04-09 07:44:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
QMessageBox::critical(nullptr,
|
2019-04-10 11:32:21 +00:00
|
|
|
QObject::tr("Save Crash Dump"),
|
|
|
|
QObject::tr("Failed to write to %1.<br/>"
|
|
|
|
"Please make sure you have access to that directory "
|
2019-04-09 07:44:44 +00:00
|
|
|
"and try again.").arg(QFileInfo(dumpSaveFileName).dir().path()));
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
QMessageBox info;
|
|
|
|
info.setWindowTitle(QObject::tr("Success"));
|
|
|
|
info.setText(QObject::tr("<a href=\"%1\">Crash dump</a> was successfully created.")
|
|
|
|
.arg(QFileInfo(dumpSaveFileName).dir().path()));
|
|
|
|
info.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
|
|
|
2019-04-10 11:32:21 +00:00
|
|
|
info.button(QMessageBox::Yes)->setText(QObject::tr("Open an Issue"));
|
|
|
|
info.button(QMessageBox::No)->setText(QObject::tr("Quit"));
|
2019-04-09 07:44:44 +00:00
|
|
|
info.setDefaultButton(QMessageBox::Yes);
|
|
|
|
|
|
|
|
int ret = info.exec();
|
|
|
|
if (ret == QMessageBox::Yes) {
|
|
|
|
openIssue();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
QMessageBox::critical(nullptr,
|
2019-04-10 11:32:21 +00:00
|
|
|
QObject::tr("Error"),
|
|
|
|
QObject::tr("Error occurred during crash dump creation."));
|
2019-04-09 07:44:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-09 19:33:13 +00:00
|
|
|
QFile f(dumpFile);
|
2019-04-09 07:44:44 +00:00
|
|
|
f.remove();
|
|
|
|
}
|
|
|
|
}
|