/* * Copyright (C) 2009 Aleksey Palazhchenko * Copyright (C) 2014 Sergey Shambir * Copyright (C) 2016 Alexander Makarov * * This file is a part of Breakpad-qt library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * */ #include #include #include #include #include "QBreakpadHandler.h" #include "QBreakpadHttpUploader.h" #define QBREAKPAD_VERSION 0x000400 #if defined(Q_OS_MAC) #include "client/mac/handler/exception_handler.h" #elif defined(Q_OS_LINUX) #include "client/linux/handler/exception_handler.h" #elif defined(Q_OS_WIN32) #include "client/windows/handler/exception_handler.h" #endif #if defined(Q_OS_WIN32) bool DumpCallback(const wchar_t* dump_dir, const wchar_t* minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool succeeded) #elif defined(Q_OS_MAC) bool DumpCallback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded) #else bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) #endif { #ifdef Q_OS_LINUX Q_UNUSED(descriptor); #endif Q_UNUSED(context); #if defined(Q_OS_WIN32) Q_UNUSED(assertion); Q_UNUSED(exinfo); #endif /* NO STACK USE, NO HEAP USE THERE !!! Creating QString's, using qDebug, etc. - everything is crash-unfriendly. */ #if defined(Q_OS_WIN32) QString path = QString::fromWCharArray(dump_dir) + QLatin1String("/") + QString::fromWCharArray(minidump_id); qDebug("%s, dump path: %s\n", succeeded ? "Succeed to write minidump" : "Failed to write minidump", qPrintable(path)); #elif defined(Q_OS_MAC) QString path = QString::fromUtf8(dump_dir) + QLatin1String("/") + QString::fromUtf8(minidump_id); qDebug("%s, dump path: %s\n", succeeded ? "Succeed to write minidump" : "Failed to write minidump", qPrintable(path)); #else qDebug("%s, dump path: %s\n", succeeded ? "Succeed to write minidump" : "Failed to write minidump", descriptor.path()); #endif return succeeded; } class QBreakpadHandlerPrivate { public: google_breakpad::ExceptionHandler* pExptHandler; QString dumpPath; QUrl uploadUrl; }; //------------------------------------------------------------------------------ QString QBreakpadHandler::version() { return QString("%1.%2.%3").arg( QString::number((QBREAKPAD_VERSION >> 16) & 0xff), QString::number((QBREAKPAD_VERSION >> 8) & 0xff), QString::number(QBREAKPAD_VERSION & 0xff)); } QBreakpadHandler::QBreakpadHandler() : d(new QBreakpadHandlerPrivate()) { } QBreakpadHandler::~QBreakpadHandler() { delete d; } void QBreakpadHandler::setDumpPath(const QString& path) { QString absPath = path; if(!QDir::isAbsolutePath(absPath)) { absPath = QDir::cleanPath(qApp->applicationDirPath() + "/" + path); } Q_ASSERT(QDir::isAbsolutePath(absPath)); QDir().mkpath(absPath); if (!QDir().exists(absPath)) { qDebug("Failed to set dump path which not exists: %s", qPrintable(absPath)); return; } d->dumpPath = absPath; // NOTE: ExceptionHandler initialization #if defined(Q_OS_WIN32) d->pExptHandler = new google_breakpad::ExceptionHandler(absPath.toStdWString(), /*FilterCallback*/ 0, DumpCallback, /*context*/ 0, google_breakpad::ExceptionHandler::HANDLER_ALL); #elif defined(Q_OS_MAC) d->pExptHandler = new google_breakpad::ExceptionHandler(absPath.toStdString(), /*FilterCallback*/ 0, DumpCallback, /*context*/ 0, true, NULL); #else d->pExptHandler = new google_breakpad::ExceptionHandler(google_breakpad::MinidumpDescriptor(absPath.toStdString()), /*FilterCallback*/ 0, DumpCallback, /*context*/ 0, true, -1); #endif } QString QBreakpadHandler::uploadUrl() const { return d->uploadUrl.toString(); } QStringList QBreakpadHandler::dumpFileList() const { if(!d->dumpPath.isNull() && !d->dumpPath.isEmpty()) { QDir dumpDir(d->dumpPath); dumpDir.setNameFilters(QStringList()<<"*.dmp"); return dumpDir.entryList(); } return QStringList(); } void QBreakpadHandler::setUploadUrl(const QUrl &url) { if(!url.isValid() || url.isEmpty()) return; d->uploadUrl = url; } void QBreakpadHandler::sendDumps() { if(!d->dumpPath.isNull() && !d->dumpPath.isEmpty()) { QDir dumpDir(d->dumpPath); dumpDir.setNameFilters(QStringList()<<"*.dmp"); QStringList dumpFiles = dumpDir.entryList(); foreach(QString itDmpFileName, dumpFiles) { qDebug() << "Sending " << QString(itDmpFileName); QBreakpadHttpUploader *sender = new QBreakpadHttpUploader(d->uploadUrl); sender->uploadDump(d->dumpPath + "/" + itDmpFileName); } } }