summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@digia.com>2012-07-04 14:16:26 +0200
committerNikolai Kosjar <nikolai.kosjar@digia.com>2012-09-21 15:57:41 +0200
commit903281b3520693e1e116523c6690d07f420feca5 (patch)
tree47c56cd6596e8ac137b8ea7940b1d15eed63a2e4 /src
parent6d06d47a6e96e531af7ad622076e1aff39c14efc (diff)
downloadqt-creator-903281b3520693e1e116523c6690d07f420feca5.tar.gz
Linux: Add a crash handler providing a backtrace for debug builds.
Use case: You're working with a debug version of Qt Creator and you're interested in getting a backtrace displayed as soon as Qt Creator crashes without searching for the core file, starting your debugger, ... Once a 'serious signal' (currently SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGPIPE) is delivered, a popup displays the following debug information: - Qt Creator version (same as in the about dialog) - Kernel version (uname -a) - GNU/Linux Distribution (/etc/lsb-release) - Backtrace (by gdb) Please note that this crash handler is built and used only in debug mode on GNU/Linux. It's solely meant as a convenience tool for the developer. In contrast to the breakpad integration, this crash handler operates 'offline'. There is no network i/o involved. Change-Id: Idcfb1bf1ad68942615ecfe0dffc0d03154455049 Reviewed-by: Christian Kandeler <christian.kandeler@digia.com> Reviewed-by: hjk <qthjk@ovi.com>
Diffstat (limited to 'src')
-rw-r--r--src/app/app.pro7
-rw-r--r--src/app/main.cpp7
-rw-r--r--src/tools/qtcreatorcrashhandler/backtracecollector.cpp119
-rw-r--r--src/tools/qtcreatorcrashhandler/backtracecollector.h63
-rw-r--r--src/tools/qtcreatorcrashhandler/crashhandler.cpp250
-rw-r--r--src/tools/qtcreatorcrashhandler/crashhandler.h66
-rw-r--r--src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp132
-rw-r--r--src/tools/qtcreatorcrashhandler/crashhandlerdialog.h67
-rw-r--r--src/tools/qtcreatorcrashhandler/crashhandlerdialog.ui122
-rw-r--r--src/tools/qtcreatorcrashhandler/crashhandlersetup.cpp133
-rw-r--r--src/tools/qtcreatorcrashhandler/crashhandlersetup.h37
-rw-r--r--src/tools/qtcreatorcrashhandler/main.cpp68
-rw-r--r--src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.pro26
-rw-r--r--src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.qbs28
-rw-r--r--src/tools/qtcreatorcrashhandler/utils.cpp44
-rw-r--r--src/tools/qtcreatorcrashhandler/utils.h42
-rw-r--r--src/tools/tools.pro8
17 files changed, 1217 insertions, 2 deletions
diff --git a/src/app/app.pro b/src/app/app.pro
index 896b2cc884..85831adb6f 100644
--- a/src/app/app.pro
+++ b/src/app/app.pro
@@ -6,6 +6,13 @@ TARGET = $$IDE_APP_TARGET
DESTDIR = $$IDE_APP_PATH
SOURCES += main.cpp
+linux-* {
+ # Build only in debug mode.
+ debug_and_release|CONFIG(debug, debug|release) {
+ HEADERS += ../tools/qtcreatorcrashhandler/crashhandlersetup.h
+ SOURCES += ../tools/qtcreatorcrashhandler/crashhandlersetup.cpp
+ }
+}
include(../rpath.pri)
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 526ca15477..e96692b04f 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -29,6 +29,7 @@
**************************************************************************/
#include "qtsingleapplication.h"
+#include "../tools/qtcreatorcrashhandler/crashhandlersetup.h"
#include <app/app_version.h>
#include <extensionsystem/iplugin.h>
@@ -228,6 +229,8 @@ int main(int argc, char **argv)
const int threadCount = QThreadPool::globalInstance()->maxThreadCount();
QThreadPool::globalInstance()->setMaxThreadCount(qMax(4, 2 * threadCount));
+ setupCrashHandler(); // Display a backtrace once a serious signal is delivered.
+
#ifdef ENABLE_QT_BREAKPAD
QtSystemExceptionHandler systemExceptionHandler;
#endif
@@ -432,5 +435,7 @@ int main(int argc, char **argv)
QTimer::singleShot(100, &pluginManager, SLOT(startTests()));
#endif
- return app.exec();
+ const int r = app.exec();
+ cleanupCrashHandler();
+ return r;
}
diff --git a/src/tools/qtcreatorcrashhandler/backtracecollector.cpp b/src/tools/qtcreatorcrashhandler/backtracecollector.cpp
new file mode 100644
index 0000000000..df8500000f
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/backtracecollector.cpp
@@ -0,0 +1,119 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#include "backtracecollector.h"
+
+#include <QDebug>
+#include <QScopedPointer>
+#include <QTemporaryFile>
+
+const char GdbBatchCommands[] =
+ "set height 0\n"
+ "set width 0\n"
+ "thread\n"
+ "thread apply all backtrace full\n";
+
+class BacktraceCollectorPrivate
+{
+public:
+ BacktraceCollectorPrivate() : errorOccurred(false) {}
+
+ bool errorOccurred;
+ QScopedPointer<QTemporaryFile> commandFile;
+ QProcess debugger;
+ QString output;
+};
+
+BacktraceCollector::BacktraceCollector(QObject *parent) :
+ QObject(parent), d(new BacktraceCollectorPrivate)
+{
+ connect(&d->debugger, SIGNAL(finished(int,QProcess::ExitStatus)),
+ SLOT(onDebuggerFinished(int,QProcess::ExitStatus)));
+ connect(&d->debugger, SIGNAL(error(QProcess::ProcessError)),
+ SLOT(onDebuggerError(QProcess::ProcessError)));
+ connect(&d->debugger, SIGNAL(readyRead()), SLOT(onDebuggerOutputAvailable()));
+ d->debugger.setProcessChannelMode(QProcess::MergedChannels);
+}
+
+BacktraceCollector::~BacktraceCollector()
+{
+ delete d;
+}
+
+void BacktraceCollector::run(Q_PID pid)
+{
+ d->debugger.start(QLatin1String("gdb"), QStringList()
+ << QLatin1String("--nw") // Do not use a window interface.
+ << QLatin1String("--nx") // Do not read .gdbinit file.
+ << QLatin1String("--batch") // Exit after processing options.
+ << QLatin1String("--command") << createTemporaryCommandFile()
+ << QLatin1String("--pid") << QString::number(pid)
+ );
+}
+
+void BacktraceCollector::onDebuggerFinished(int exitCode, QProcess::ExitStatus /*exitStatus*/)
+{
+ if (d->errorOccurred) {
+ emit error(QLatin1String("QProcess: ") + d->debugger.errorString());
+ return;
+ }
+ if (exitCode != 0) {
+ emit error(QString::fromLatin1("Debugger exited with code %1.").arg(exitCode));
+ return;
+ }
+ emit backtrace(d->output);
+}
+
+void BacktraceCollector::onDebuggerError(QProcess::ProcessError /*error*/)
+{
+ d->errorOccurred = true;
+}
+
+QString BacktraceCollector::createTemporaryCommandFile()
+{
+ d->commandFile.reset(new QTemporaryFile);
+ if (!d->commandFile->open()) {
+ emit error(QLatin1String("Error: Could not create temporary command file."));
+ return QString();
+ }
+ if (d->commandFile->write(GdbBatchCommands) == -1) {
+ emit error(QLatin1String("Error: Could not write temporary command file."));
+ return QString();
+ }
+ d->commandFile->close();
+ return d->commandFile->fileName();
+}
+
+void BacktraceCollector::onDebuggerOutputAvailable()
+{
+ const QString newChunk = d->debugger.readAll();
+ d->output.append(newChunk);
+ emit backtraceChunk(newChunk);
+}
diff --git a/src/tools/qtcreatorcrashhandler/backtracecollector.h b/src/tools/qtcreatorcrashhandler/backtracecollector.h
new file mode 100644
index 0000000000..151d7c09d1
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/backtracecollector.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#ifndef BACKTRACECOLLECTOR_H
+#define BACKTRACECOLLECTOR_H
+
+#include <QProcess>
+
+class BacktraceCollectorPrivate;
+
+class BacktraceCollector : public QObject
+{
+ Q_OBJECT
+public:
+ explicit BacktraceCollector(QObject *parent = 0);
+ ~BacktraceCollector();
+
+ void run(Q_PID pid);
+
+signals:
+ void error(const QString &errorMessage);
+ void backtrace(const QString &backtrace);
+ void backtraceChunk(const QString &chunk);
+
+private slots:
+ void onDebuggerOutputAvailable();
+ void onDebuggerFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ void onDebuggerError(QProcess::ProcessError err);
+
+private:
+ QString createTemporaryCommandFile();
+
+ BacktraceCollectorPrivate *d;
+};
+
+#endif // BACKTRACECOLLECTOR_H
diff --git a/src/tools/qtcreatorcrashhandler/crashhandler.cpp b/src/tools/qtcreatorcrashhandler/crashhandler.cpp
new file mode 100644
index 0000000000..dfc5e5012f
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/crashhandler.cpp
@@ -0,0 +1,250 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#include "crashhandler.h"
+#include "crashhandlerdialog.h"
+#include "backtracecollector.h"
+#include "utils.h"
+
+#include <QApplication>
+#include <QDebug>
+#include <QDesktopServices>
+#include <QFile>
+#include <QRegExp>
+#include <QTextStream>
+#include <QUrl>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+static const char FileDistroInformation[] = "/etc/lsb-release";
+static const char FileKernelVersion[] = "/proc/version";
+
+static QString collectLinuxDistributionInfo()
+{
+ return QString::fromLatin1(fileContents(QLatin1String(FileDistroInformation)));
+}
+
+static QString collectKernelVersionInfo()
+{
+ return QString::fromLatin1(fileContents(QLatin1String(FileKernelVersion)));
+}
+
+class CrashHandlerPrivate
+{
+public:
+ CrashHandlerPrivate(pid_t pid, CrashHandler *crashHandler)
+ : pid(pid), dialog(crashHandler), argv(0), envp(0) {}
+
+ ~CrashHandlerPrivate()
+ {
+ if (argv) {
+ for (int i = 0; argv[i]; ++i)
+ delete[] argv[i];
+ }
+ if (envp) {
+ for (int i = 0; envp[i]; ++i)
+ delete[] envp[i];
+ }
+ free(argv);
+ free(envp);
+ }
+
+ pid_t pid;
+ BacktraceCollector backtraceCollector;
+ CrashHandlerDialog dialog;
+
+ // For restarting the process.
+ char **argv;
+ char **envp;
+};
+
+CrashHandler::CrashHandler(pid_t pid, QObject *parent)
+ : QObject(parent), d(new CrashHandlerPrivate(pid, this))
+{
+ connect(&d->backtraceCollector, SIGNAL(error(QString)), SLOT(onError(QString)));
+ connect(&d->backtraceCollector, SIGNAL(backtraceChunk(QString)), SLOT(onBacktraceChunk(QString)));
+ connect(&d->backtraceCollector, SIGNAL(backtrace(QString)), SLOT(onBacktraceFinished(QString)));
+
+ d->dialog.appendDebugInfo(collectKernelVersionInfo());
+ d->dialog.appendDebugInfo(collectLinuxDistributionInfo());
+ d->dialog.show();
+
+ if (!collectRestartAppData()) // If we can't restart the app properly, ...
+ d->dialog.disableRestartAppButton();
+}
+
+CrashHandler::~CrashHandler()
+{
+ delete d;
+}
+
+void CrashHandler::run()
+{
+ d->backtraceCollector.run(d->pid);
+}
+
+void CrashHandler::onError(const QString &errorMessage)
+{
+ d->dialog.setToFinalState();
+
+ QTextStream(stderr) << errorMessage;
+ const QString text = QLatin1String("There occured a problem providing the backtrace. "
+ "Please make sure to have the debugger \"gdb\" installed.\n");
+ d->dialog.appendDebugInfo(text);
+ d->dialog.appendDebugInfo(errorMessage);
+}
+
+void CrashHandler::onBacktraceChunk(const QString &chunk)
+{
+ d->dialog.appendDebugInfo(chunk);
+ QTextStream out(stdout);
+ out << chunk;
+}
+
+void CrashHandler::onBacktraceFinished(const QString &backtrace)
+{
+ d->dialog.setToFinalState();
+
+ // Select first line of relevant thread.
+
+ // Example debugger output:
+ // ...
+ // [Current thread is 1 (Thread 0x7f1c33c79780 (LWP 975))]
+ // ...
+ // Thread 1 (Thread 0x7f1c33c79780 (LWP 975)):
+ // ...
+ QRegExp rx("\\[Current thread is (\\d+)");
+ const int pos = rx.indexIn(backtrace);
+ if (pos == -1)
+ return;
+ const QString threadNumber = rx.cap(1);
+ const QString textToSelect = QString::fromLatin1("Thread %1").arg(threadNumber);
+ d->dialog.selectLineWithContents(textToSelect);
+}
+
+void CrashHandler::openBugTracker()
+{
+ QDesktopServices::openUrl(QUrl(URL_BUGTRACKER));
+}
+
+bool CrashHandler::collectRestartAppData()
+{
+ const QString procDir = QString::fromLatin1("/proc/%1").arg(d->pid);
+
+ // Construct d->argv.
+ // man 5 proc: /proc/[pid]/cmdline
+ // The command-line arguments appear in this file as a set of strings separated by
+ // null bytes ('\0'), with a further null byte after the last string.
+ const QString procCmdFileName = procDir + QLatin1String("/cmdline");
+ QList<QByteArray> cmdEntries = fileContents(procCmdFileName).split('\0');
+ if (cmdEntries.size() < 2) {
+ qWarning("%s: Unexpected format in file '%s'.\n", Q_FUNC_INFO, qPrintable(procCmdFileName));
+ return false;
+ }
+ cmdEntries.removeLast();
+ char * const executable = qstrdup(qPrintable(cmdEntries.takeFirst()));
+ d->argv = (char **) malloc(sizeof(char*) * (cmdEntries.size() + 2));
+ if (d->argv == 0)
+ qFatal("%s: malloc() failed.\n", Q_FUNC_INFO);
+ d->argv[0] = executable;
+ int i;
+ for (i = 1; i <= cmdEntries.size(); ++i)
+ d->argv[i] = qstrdup(cmdEntries.at(i-1));
+ d->argv[i] = 0;
+
+ // Construct d->envp.
+ // man 5 proc: /proc/[pid]/environ
+ // The entries are separated by null bytes ('\0'), and there may be a null byte at the end.
+ const QString procEnvFileName = procDir + QLatin1String("/environ");
+ QList<QByteArray> envEntries = fileContents(procEnvFileName).split('\0');
+ if (envEntries.isEmpty()) {
+ qWarning("%s: Unexpected format in file '%s'.\n", Q_FUNC_INFO, qPrintable(procEnvFileName));
+ return false;
+ }
+ if (envEntries.last().isEmpty())
+ envEntries.removeLast();
+ d->envp = (char **) malloc(sizeof(char*) * (envEntries.size() + 1));
+ if (d->envp == 0)
+ qFatal("%s: malloc() failed.\n", Q_FUNC_INFO);
+ for (i = 0; i < envEntries.size(); ++i)
+ d->envp[i] = qstrdup(envEntries.at(i));
+ d->envp[i] = 0;
+
+ return true;
+}
+
+void CrashHandler::restartApplication()
+{
+ // TODO: If QTBUG-2284 is resolved, use QProcess::startDetached() here.
+ // Close the crash handler and start the process again with same environment and
+ // command line arguments.
+ //
+ // We can't use QProcess::startDetached because of bug
+ //
+ // QTBUG-2284
+ // QProcess::startDetached does not support setting an environment for the new process
+ //
+ // therefore, we use fork-exec.
+
+ pid_t pid = fork();
+ switch (pid) {
+ case -1: // error
+ qFatal("%s: fork() failed.", Q_FUNC_INFO);
+ break;
+ case 0: // child
+ qDebug("Restarting Qt Creator with\n");
+ for (int i = 0; d->argv[i]; ++i)
+ qDebug(" %s", d->argv[i]);
+ qDebug("\nand environment\n");
+ for (int i = 0; d->envp[i]; ++i)
+ qDebug(" %s", d->envp[i]);
+
+ // The standards pipes must be open, otherwise the restarted Qt Creator will
+ // receive a SIGPIPE as soon as these are used.
+ if (freopen("/dev/null", "r", stdin) == 0)
+ qFatal("%s: freopen() failed for stdin: %s.\n", Q_FUNC_INFO, strerror(errno));
+ if (freopen("/dev/null", "w", stdout) == 0)
+ qFatal("%s: freopen() failed for stdout: %s.\n", Q_FUNC_INFO, strerror(errno));
+ if (freopen("/dev/null", "w", stderr) == 0)
+ qFatal("%s: freopen() failed for stderr: %s.\n.", Q_FUNC_INFO, strerror(errno));
+
+ execve(d->argv[0], d->argv, d->envp);
+ _exit(EXIT_FAILURE);
+ default: // parent
+ qApp->quit();
+ break;
+ }
+}
diff --git a/src/tools/qtcreatorcrashhandler/crashhandler.h b/src/tools/qtcreatorcrashhandler/crashhandler.h
new file mode 100644
index 0000000000..f834befb75
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/crashhandler.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#ifndef CRASHHANDLER_H
+#define CRASHHANDLER_H
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QString;
+QT_END_NAMESPACE
+
+class ApplicationInfo;
+class CrashHandlerPrivate;
+
+class CrashHandler : public QObject
+{
+ Q_OBJECT
+public:
+ explicit CrashHandler(pid_t pid, QObject *parent = 0);
+ ~CrashHandler();
+
+ void run();
+
+public slots:
+ void onError(const QString &errorMessage);
+ void onBacktraceChunk(const QString &chunk);
+ void onBacktraceFinished(const QString &backtrace);
+
+ void openBugTracker();
+ void restartApplication();
+
+private:
+ bool collectRestartAppData();
+
+ CrashHandlerPrivate *d;
+};
+
+#endif // CRASHHANDLER_H
diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp
new file mode 100644
index 0000000000..d1ff87d270
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp
@@ -0,0 +1,132 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#include "crashhandler.h"
+#include "crashhandlerdialog.h"
+#include "ui_crashhandlerdialog.h"
+#include "utils.h"
+
+#include <app/app_version.h>
+
+#include <QClipboard>
+#include <QIcon>
+
+CrashHandlerDialog::CrashHandlerDialog(CrashHandler *handler, QWidget *parent) :
+ QDialog(parent),
+ m_crashHandler(handler),
+ m_ui(new Ui::CrashHandlerDialog)
+{
+ m_ui->setupUi(this);
+ m_ui->introLabel->setTextFormat(Qt::RichText);
+ m_ui->introLabel->setOpenExternalLinks(true);
+ m_ui->debugInfoEdit->setReadOnly(true);
+ m_ui->progressBar->setMinimum(0);
+ m_ui->progressBar->setMaximum(0);
+
+ const QStyle * const style = QApplication::style();
+ m_ui->closeButton->setIcon(style->standardIcon(QStyle::SP_DialogCloseButton));
+
+ const int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, 0);
+ QIcon icon = style->standardIcon(QStyle::SP_MessageBoxCritical);
+ m_ui->iconLabel->setPixmap(icon.pixmap(iconSize, iconSize));
+
+ connect(m_ui->copyToClipBoardButton, SIGNAL(clicked()), this, SLOT(copyToClipboardClicked()));
+ connect(m_ui->reportBugButton, SIGNAL(clicked()), m_crashHandler, SLOT(openBugTracker()));
+ connect(m_ui->restartAppButton, SIGNAL(clicked()), m_crashHandler, SLOT(restartApplication()));
+ connect(m_ui->closeButton, SIGNAL(clicked()), qApp, SLOT(quit()));
+
+ setApplicationInfo();
+}
+
+CrashHandlerDialog::~CrashHandlerDialog()
+{
+ delete m_ui;
+}
+
+void CrashHandlerDialog::setToFinalState()
+{
+ m_ui->progressBar->hide();
+ m_ui->copyToClipBoardButton->setEnabled(true);
+ m_ui->reportBugButton->setEnabled(true);
+}
+
+void CrashHandlerDialog::disableRestartAppButton()
+{
+ m_ui->restartAppButton->setDisabled(true);
+}
+
+void CrashHandlerDialog::setApplicationInfo()
+{
+ const QString ideName = QLatin1String("Qt Creator");
+ const QString contents = tr(
+ "<p><b>%1 has closed unexpectedly.</b></p>"
+ "<p>Please file a <a href='%2'>bug report</a> with the debug information provided below.</p>")
+ .arg(ideName, QLatin1String(URL_BUGTRACKER));
+ m_ui->introLabel->setText(contents);
+
+ QString revision;
+#ifdef IDE_REVISION
+ revision = tr(" from revision %1").arg(QString::fromLatin1(Core::Constants::IDE_REVISION_STR).left(10));
+#endif
+ const QString versionInformation = tr(
+ "%1 %2%3, built on %4 at %5, based on Qt %6 (%7 bit)\n")
+ .arg(ideName, QLatin1String(Core::Constants::IDE_VERSION_LONG), revision,
+ QLatin1String(__DATE__), QLatin1String(__TIME__), QLatin1String(QT_VERSION_STR),
+ QString::number(QSysInfo::WordSize));
+ m_ui->debugInfoEdit->append(versionInformation);
+}
+
+void CrashHandlerDialog::appendDebugInfo(const QString &chunk)
+{
+ m_ui->debugInfoEdit->append(chunk);
+}
+
+void CrashHandlerDialog::selectLineWithContents(const QString &text)
+{
+ // The selected line will be the first line visible.
+
+ // Go to end.
+ QTextCursor cursor = m_ui->debugInfoEdit->textCursor();
+ cursor.movePosition(QTextCursor::End);
+ m_ui->debugInfoEdit->setTextCursor(cursor);
+
+ // Find text by searching backwards.
+ m_ui->debugInfoEdit->find(text, QTextDocument::FindCaseSensitively | QTextDocument::FindBackward);
+
+ // Highlight whole line.
+ cursor = m_ui->debugInfoEdit->textCursor();
+ cursor.select(QTextCursor::LineUnderCursor);
+ m_ui->debugInfoEdit->setTextCursor(cursor);
+}
+
+void CrashHandlerDialog::copyToClipboardClicked()
+{
+ QApplication::clipboard()->setText(m_ui->debugInfoEdit->toPlainText());
+}
diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.h b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.h
new file mode 100644
index 0000000000..ecee4cffa9
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#ifndef CRASHHANDLERDIALOG_H
+#define CRASHHANDLERDIALOG_H
+
+#include <QDialog>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class CrashHandlerDialog;
+}
+QT_END_NAMESPACE
+
+class CrashHandler;
+
+class CrashHandlerDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CrashHandlerDialog(CrashHandler *handler, QWidget *parent = 0);
+ ~CrashHandlerDialog();
+
+public:
+ void disableRestartAppButton();
+ void setApplicationInfo();
+ void setToFinalState();
+ void appendDebugInfo(const QString &chunk);
+ void selectLineWithContents(const QString &text);
+
+private slots:
+ void copyToClipboardClicked();
+
+private:
+ CrashHandler *m_crashHandler;
+ Ui::CrashHandlerDialog *m_ui;
+};
+
+#endif // CRASHHANDLERDIALOG_H
diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.ui b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.ui
new file mode 100644
index 0000000000..101efd2e48
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.ui
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CrashHandlerDialog</class>
+ <widget class="QDialog" name="CrashHandlerDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>800</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>400</width>
+ <height>300</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="iconLabel">
+ <property name="text">
+ <string>Icon</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="introLabel">
+ <property name="text">
+ <string>Some useful information here...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="progressBar">
+ <property name="value">
+ <number>24</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="debugInfoEdit"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="copyToClipBoardButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>C&amp;opy to clipboard</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="reportBugButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Report this &amp;bug</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="restartAppButton">
+ <property name="text">
+ <string>&amp;Restart Qt Creator</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/tools/qtcreatorcrashhandler/crashhandlersetup.cpp b/src/tools/qtcreatorcrashhandler/crashhandlersetup.cpp
new file mode 100644
index 0000000000..658429aabb
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/crashhandlersetup.cpp
@@ -0,0 +1,133 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#include "crashhandlersetup.h"
+
+#include <QtGlobal>
+
+#if !defined(QT_NO_DEBUG) && defined(Q_OS_LINUX)
+#define BUILD_CRASH_HANDLER
+#endif
+
+#ifdef BUILD_CRASH_HANDLER
+
+#include <QApplication>
+#include <QDebug>
+#include <QString>
+
+#include <stdlib.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifdef Q_WS_X11
+#include <qx11info_x11.h>
+#include <X11/Xlib.h>
+#endif
+
+static const char *crashHandlerPathC;
+static void *signalHandlerStack;
+
+extern "C" void signalHandler(int /*signal*/)
+{
+#ifdef Q_WS_X11
+ // Kill window since it's frozen anyway.
+ if (QX11Info::display())
+ close(ConnectionNumber(QX11Info::display()));
+#endif
+ pid_t pid = fork();
+ switch (pid) {
+ case -1: // error
+ break;
+ case 0: // child
+ execl(crashHandlerPathC, crashHandlerPathC, (char *) 0);
+ _exit(EXIT_FAILURE);
+ default: // parent
+ waitpid(pid, 0, 0);
+ _exit(EXIT_FAILURE);
+ break;
+ }
+}
+#endif // BUILD_CRASH_HANDLER
+
+void setupCrashHandler()
+{
+#ifdef BUILD_CRASH_HANDLER
+ const QString crashHandlerPath = qApp->applicationDirPath()
+ + QLatin1String("/qtcreator_crash_handler");
+ crashHandlerPathC = qstrdup(qPrintable(crashHandlerPath));
+
+ // Setup an alternative stack for the signal handler. This way we are able to handle SIGSEGV
+ // even if the normal process stack is exhausted.
+ stack_t ss;
+ ss.ss_sp = signalHandlerStack = malloc(SIGSTKSZ); // Usual requirements for alternative signal stack.
+ if (ss.ss_sp == 0) {
+ qWarning("Warning: Could not allocate space for alternative signal stack (%s).", Q_FUNC_INFO);
+ return;
+ }
+ ss.ss_size = SIGSTKSZ;
+ ss.ss_flags = 0;
+ if (sigaltstack(&ss, 0) == -1) {
+ qWarning("Warning: Failed to set alternative signal stack (%s).", Q_FUNC_INFO);
+ return;
+ }
+
+ // Install signal handler for calling the crash handler.
+ struct sigaction sa;
+ if (sigemptyset(&sa.sa_mask) == -1) {
+ qWarning("Warning: Failed to empty signal set (%s).", Q_FUNC_INFO);
+ return;
+ }
+ sa.sa_handler = &signalHandler;
+ // SA_RESETHAND - Restore signal action to default after signal handler has been called.
+ // SA_NODEFER - Don't block the signal after it was triggered (otherwise blocked signals get
+ // inherited via fork() and execve()). Without this the signal will not be delivered to the
+ // restarted Qt Creator.
+ // SA_ONSTACK - Use alternative stack.
+ sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_ONSTACK;
+ const int signalsToHandle[] = { SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGPIPE, 0 };
+ for (int i = 0; signalsToHandle[i]; ++i) {
+ if (sigaction(signalsToHandle[i], &sa, 0) == -1 )
+ qWarning("Warning: Failed to install signal handler for SIGILL (%s).", Q_FUNC_INFO);
+ }
+#endif // BUILD_CRASH_HANDLER
+}
+
+void cleanupCrashHandler()
+{
+#ifdef BUILD_CRASH_HANDLER
+ delete[] crashHandlerPathC;
+ free(signalHandlerStack);
+#endif
+}
diff --git a/src/tools/qtcreatorcrashhandler/crashhandlersetup.h b/src/tools/qtcreatorcrashhandler/crashhandlersetup.h
new file mode 100644
index 0000000000..698cd5f9a6
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/crashhandlersetup.h
@@ -0,0 +1,37 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#ifndef CRASHHANDLERSETUP_H
+#define CRASHHANDLERSETUP_H
+
+void setupCrashHandler();
+void cleanupCrashHandler();
+
+#endif // CRASHHANDLERSETUP_H
diff --git a/src/tools/qtcreatorcrashhandler/main.cpp b/src/tools/qtcreatorcrashhandler/main.cpp
new file mode 100644
index 0000000000..94c21db2db
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/main.cpp
@@ -0,0 +1,68 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#include "crashhandler.h"
+#include "utils.h"
+
+#include <QApplication>
+#include <QFile>
+#include <QProcess>
+#include <QString>
+#include <QStyle>
+#include <QTextStream>
+
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ app.setApplicationName(QLatin1String(APPLICATION_NAME));
+ app.setWindowIcon(QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical));
+
+ // Check usage.
+ Q_PID parentPid = getppid();
+ QString parentExecutable = QFile::symLinkTarget(QString::fromLatin1("/proc/%1/exe")
+ .arg(QString::number(parentPid)));
+ if (argc > 1 || !parentExecutable.contains("qtcreator")) {
+ QTextStream err(stderr);
+ err << QString::fromLatin1("This crash handler will be called by Qt Creator itself. "
+ "Don't call this manually.\n");
+ return EXIT_FAILURE;
+ }
+
+ // Run.
+ CrashHandler *crashHandler = new CrashHandler(parentPid);
+ crashHandler->run();
+
+ return app.exec();
+}
diff --git a/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.pro b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.pro
new file mode 100644
index 0000000000..551de3008d
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.pro
@@ -0,0 +1,26 @@
+include(../../../qtcreator.pri)
+
+TARGET = qtcreator_crash_handler
+DESTDIR = $$IDE_BIN_PATH
+
+CONFIG -= app_bundle
+TEMPLATE = app
+
+SOURCES += \
+ main.cpp \
+ backtracecollector.cpp \
+ crashhandlerdialog.cpp \
+ crashhandler.cpp \
+ utils.cpp
+
+HEADERS += \
+ backtracecollector.h \
+ crashhandlerdialog.h \
+ crashhandler.h \
+ utils.h
+
+FORMS += \
+ crashhandlerdialog.ui
+
+target.path = /bin
+INSTALLS += target
diff --git a/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.qbs b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.qbs
new file mode 100644
index 0000000000..820f26d68c
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/qtcreatorcrashhandler.qbs
@@ -0,0 +1,28 @@
+import qbs.base 1.0
+import "../QtcTool.qbs" as QtcTool
+
+QtcTool {
+ name: "qtcreator_crash_handler"
+ condition: qbs.targetOS == "linux" && qbs.buildVariant == "debug"
+
+ cpp.includePaths: [
+ buildDirectory
+ ]
+
+ Depends { name: "cpp" }
+ Depends { name: "Qt.widgets" }
+ Depends { name: "app_version_header" }
+
+ files: [
+ "main.cpp",
+ "backtracecollector.cpp",
+ "backtracecollector.h",
+ "crashhandlerdialog.cpp",
+ "crashhandlerdialog.h",
+ "crashhandler.cpp",
+ "crashhandler.h",
+ "utils.cpp",
+ "utils.h",
+ "crashhandlerdialog.ui"
+ ]
+}
diff --git a/src/tools/qtcreatorcrashhandler/utils.cpp b/src/tools/qtcreatorcrashhandler/utils.cpp
new file mode 100644
index 0000000000..aca361bab7
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/utils.cpp
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#include "utils.h"
+
+#include <QDebug>
+#include <QFile>
+
+QByteArray fileContents(const QString &filePath)
+{
+ QFile file(filePath);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning("Warning: Could not open '%s'.", qPrintable(filePath));
+ return QByteArray();
+ }
+ return file.readAll();
+}
diff --git a/src/tools/qtcreatorcrashhandler/utils.h b/src/tools/qtcreatorcrashhandler/utils.h
new file mode 100644
index 0000000000..0979d248de
--- /dev/null
+++ b/src/tools/qtcreatorcrashhandler/utils.h
@@ -0,0 +1,42 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: http://www.qt-project.org/
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**************************************************************************/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <QByteArray>
+#include <QString>
+
+const char APPLICATION_NAME[] = "Qt Creator Crash Handler";
+const char URL_BUGTRACKER[] = "https://bugreports.qt-project.org/";
+
+QByteArray fileContents(const QString &filePath);
+
+#endif // UTILS_H
diff --git a/src/tools/tools.pro b/src/tools/tools.pro
index dcbb5bb6de..879144711b 100644
--- a/src/tools/tools.pro
+++ b/src/tools/tools.pro
@@ -21,5 +21,11 @@ win32 {
QT_BREAKPAD_ROOT_PATH = $$(QT_BREAKPAD_ROOT_PATH)
!isEmpty(QT_BREAKPAD_ROOT_PATH) {
SUBDIRS += qtcrashhandler
+} else {
+ linux-* {
+ # Build only in debug mode.
+ debug_and_release|CONFIG(debug, debug|release) {
+ SUBDIRS += qtcreatorcrashhandler
+ }
+ }
}
-