Index: drkonqi/CMakeLists.txt =================================================================== --- drkonqi/CMakeLists.txt +++ drkonqi/CMakeLists.txt @@ -112,5 +112,10 @@ Qt5::X11Extras ) endif() +if (APPLE) + target_link_libraries(drkonqi + KF5::WindowSystem + ) +endif() install(TARGETS drkonqi DESTINATION ${KDE_INSTALL_LIBEXECDIR}) Index: drkonqi/aboutbugreportingdialog.cpp =================================================================== --- drkonqi/aboutbugreportingdialog.cpp +++ drkonqi/aboutbugreportingdialog.cpp @@ -36,7 +36,7 @@ { setAttribute(Qt::WA_DeleteOnClose, true); - setWindowIcon(QIcon::fromTheme(QStringLiteral("help-hint"))); + setWindowIcon(QIcon::fromTheme(QStringLiteral("help-hint"), windowIcon())); setWindowTitle(i18nc("@title title of the dialog", "About Bug Reporting - Help")); QVBoxLayout* layout = new QVBoxLayout(this); Index: drkonqi/backtracegenerator.h =================================================================== --- drkonqi/backtracegenerator.h +++ drkonqi/backtracegenerator.h @@ -84,6 +84,7 @@ State m_state; BacktraceParser * m_parser; QString m_parsedBacktrace; + bool m_lldbDetached; #ifdef BACKTRACE_PARSER_DEBUG BacktraceParser * m_debugParser; Index: drkonqi/backtracegenerator.cpp =================================================================== --- drkonqi/backtracegenerator.cpp +++ drkonqi/backtracegenerator.cpp @@ -37,7 +37,8 @@ BacktraceGenerator::BacktraceGenerator(const Debugger & debugger, QObject *parent) : QObject(parent), m_debugger(debugger), m_proc(NULL), - m_temp(NULL), m_state(NotLoaded) + m_temp(NULL), m_state(NotLoaded), + m_lldbDetached(false) { m_parser = BacktraceParser::newParser(m_debugger.codeName(), this); m_parser->connectToGenerator(this); @@ -56,9 +57,12 @@ m_proc->terminate(); if (!m_proc->waitForFinished(10000)) { m_proc->kill(); - m_proc->waitForFinished(); + // lldb can become "stuck" on OS X; just mark m_proc as to be deleted later rather + // than waiting a potentially very long time for it to heed the kill() request. + m_proc->deleteLater(); + } else { + delete m_proc; } - delete m_proc; delete m_temp; } } @@ -95,9 +99,17 @@ *m_proc << KShell::splitArgs(str); m_proc->setOutputChannelMode(KProcess::OnlyStdoutChannel); m_proc->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Text); + // check if the debugger should take its input from a file we'll generate, + // and take the appropriate steps if so + QString stdinFile = m_debugger.backendValueOfParameter(QStringLiteral("ExecInputFile")); + Debugger::expandString(stdinFile, Debugger::ExpansionUsageShell, m_temp->fileName()); + if (!stdinFile.isEmpty() && QFile::exists(stdinFile)) { + m_proc->setStandardInputFile(stdinFile); + } connect(m_proc, &KProcess::readyReadStandardOutput, this, &BacktraceGenerator::slotReadInput); connect(m_proc, static_cast(&KProcess::finished), this, &BacktraceGenerator::slotProcessExited); + m_lldbDetached = false; m_proc->start(); if (!m_proc->waitForStarted()) { //we mustn't keep these around... @@ -116,15 +128,31 @@ void BacktraceGenerator::slotReadInput() { + if (m_lldbDetached) { + return; + } + // we do not know if the output array ends in the middle of an utf-8 sequence m_output += m_proc->readAllStandardOutput(); int pos; - while ((pos = m_output.indexOf('\n')) != -1) { + while ((pos = m_output.indexOf('\n')) != -1 && m_proc->state() == QProcess::Running) { QString line = QString::fromLocal8Bit(m_output, pos + 1); m_output.remove(0, pos + 1); emit newLine(line); + line = line.simplified(); + if (line.startsWith(QLatin1String("Process ")) && line.endsWith(QLatin1String(" detached"))) { + // Anything following this line doesn't interest us, and lldb has been known + // to turn into a zombie instead of exitting, thereby blocking us. + m_lldbDetached = true; + m_proc->terminate(); + if (!m_proc->waitForFinished(500)) { + m_proc->kill(); + } + slotProcessExited(0, QProcess::NormalExit); + return; + } } } Index: drkonqi/backtracewidget.cpp =================================================================== --- drkonqi/backtracewidget.cpp +++ drkonqi/backtracewidget.cpp @@ -205,6 +205,9 @@ // scroll to crash QTextCursor crashCursor = ui.m_backtraceEdit->document()->find(QStringLiteral("[KCrash Handler]")); + if (crashCursor.isNull()) { + crashCursor = ui.m_backtraceEdit->document()->find(QStringLiteral("KCrash::defaultCrashHandler")); + } if (!crashCursor.isNull()) { crashCursor.movePosition(QTextCursor::Up, QTextCursor::MoveAnchor); ui.m_backtraceEdit->verticalScrollBar()->setValue(ui.m_backtraceEdit->cursorRect(crashCursor).top()); Index: drkonqi/bugzillaintegration/reportassistantdialog.cpp =================================================================== --- drkonqi/bugzillaintegration/reportassistantdialog.cpp +++ drkonqi/bugzillaintegration/reportassistantdialog.cpp @@ -50,7 +50,7 @@ //Set window properties setWindowTitle(i18nc("@title:window","Crash Reporting Assistant")); - setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"))); + setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"), windowIcon())); connect(this, &ReportAssistantDialog::currentPageChanged, this, &ReportAssistantDialog::currentPageChanged_slot); connect(button(QDialogButtonBox::Help), &QPushButton::clicked, this, &ReportAssistantDialog::showHelp); Index: drkonqi/data/AppleTerminal =================================================================== --- /dev/null +++ drkonqi/data/AppleTerminal @@ -0,0 +1,24 @@ +#!/bin/sh + +SCRIPT="${TMPDIR}/RunInTerminal.$$.sh" + +CleanUp() { + rm -f "${SCRIPT}" +} + +trap CleanUp 0 +trap CleanUp 1 +trap CleanUp 2 +trap CleanUp 15 + +if [ $# != 0 ] ;then + echo "$@" > "${SCRIPT}" +else + cat - > "${SCRIPT}" +fi +chmod 700 "${SCRIPT}" + +echo "Running the requested command(s) in a new Terminal instance" +echo "Remember to quit the Terminal application!" + +open -W -n -F -a Terminal.app "${SCRIPT}" Index: drkonqi/data/CMakeLists.txt =================================================================== --- drkonqi/data/CMakeLists.txt +++ drkonqi/data/CMakeLists.txt @@ -1,2 +1,5 @@ install(FILES mappings DESTINATION ${KDE_INSTALL_DATADIR}/drkonqi) install(DIRECTORY debuggers DESTINATION ${KDE_INSTALL_DATADIR}/drkonqi PATTERN ".svn" EXCLUDE) +if(APPLE) + install(PROGRAMS AppleTerminal DESTINATION ${KDE_INSTALL_BINDIR}) +endif Index: drkonqi/data/debuggers/external/lldbrc =================================================================== --- /dev/null +++ drkonqi/data/debuggers/external/lldbrc @@ -0,0 +1,8 @@ +[General] +Name=lldb +TryExec=lldb +Backends=KCrash + +[KCrash] +Exec=AppleTerminal lldb -p %pid +Terminal=true Index: drkonqi/data/debuggers/internal/lldbrc =================================================================== --- /dev/null +++ drkonqi/data/debuggers/internal/lldbrc @@ -0,0 +1,9 @@ +[General] +Name=lldb +TryExec=lldb +Backends=KCrash + +[KCrash] +Exec=lldb -p %pid +ExecInputFile=%tempfile +BatchCommands=set set term-width 200\nthread info\nbt all\ndetach Index: drkonqi/debugger.h =================================================================== --- drkonqi/debugger.h +++ drkonqi/debugger.h @@ -70,6 +70,8 @@ /** If this is an external debugger, it returns whether it should be run in a terminal or not */ bool runInTerminal() const; + /** Returns the value of the arbitrary configuration parameter @param key, or an empty QString if @param key isn't defined */ + QString backendValueOfParameter(const QString &key) const; enum ExpandStringUsage { ExpansionUsagePlainText, Index: drkonqi/debugger.cpp =================================================================== --- drkonqi/debugger.cpp +++ drkonqi/debugger.cpp @@ -104,6 +104,15 @@ } } +QString Debugger::backendValueOfParameter(const QString &key) const +{ + if (!isValid() || !m_config->hasGroup(m_backend)) { + return QString(); + } else { + return m_config->group(m_backend).readEntry(key, QString()); + } +} + //static void Debugger::expandString(QString & str, ExpandStringUsage usage, const QString & tempFile) { Index: drkonqi/drkonqibackends.cpp =================================================================== --- drkonqi/drkonqibackends.cpp +++ drkonqi/drkonqibackends.cpp @@ -36,6 +36,10 @@ #include "backtracegenerator.h" #include "drkonqi.h" +#ifdef Q_OS_MACOS +#include +#endif + AbstractDrKonqiBackend::~AbstractDrKonqiBackend() { } @@ -158,7 +162,9 @@ { QList internalDebuggers = Debugger::availableInternalDebuggers(QStringLiteral("KCrash")); KConfigGroup config(KSharedConfig::openConfig(), "DrKonqi"); -#ifndef Q_OS_WIN +#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED > 1070 + QString defaultDebuggerName = config.readEntry("Debugger", QString("lldb")); +#elif !defined(Q_OS_WIN) QString defaultDebuggerName = config.readEntry("Debugger", QStringLiteral("gdb")); #else QString defaultDebuggerName = config.readEntry("Debugger", QString("kdbgwin")); Index: drkonqi/drkonqidialog.cpp =================================================================== --- drkonqi/drkonqidialog.cpp +++ drkonqi/drkonqidialog.cpp @@ -54,7 +54,7 @@ //Setting dialog title and icon setWindowTitle(DrKonqi::crashedApplication()->name()); - setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"))); + setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"), windowIcon())); QVBoxLayout* l = new QVBoxLayout(this); m_tabWidget = new QTabWidget(this); Index: drkonqi/main.cpp =================================================================== --- drkonqi/main.cpp +++ drkonqi/main.cpp @@ -36,6 +36,9 @@ #if HAVE_X11 #include #endif +#ifdef Q_OS_MACOS +#include +#endif #include "drkonqi.h" #include "drkonqidialog.h" @@ -79,7 +82,7 @@ QStringLiteral("gkiagia@users.sourceforge.net")); aboutData.addAuthor(i18nc("@info:credit","A. L. Spehr"), QString(), QStringLiteral("spehr@kde.org")); - qa.setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"))); + qa.setWindowIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug"), qa.windowIcon())); QCommandLineParser parser; parser.setApplicationDescription(description); @@ -149,6 +152,9 @@ DrKonqiDialog *w = new DrKonqiDialog(); QObject::connect(w, &DrKonqiDialog::rejected, &qa, &QApplication::quit); w->show(); +#ifdef Q_OS_MACOS + KWindowSystem::forceActiveWindow(w->winId()); +#endif }; bool restarted = parser.isSet(restartedOption); Index: drkonqi/parser/CMakeLists.txt =================================================================== --- drkonqi/parser/CMakeLists.txt +++ drkonqi/parser/CMakeLists.txt @@ -3,6 +3,7 @@ backtraceparsergdb.cpp backtraceparserkdbgwin.cpp backtraceparsernull.cpp + backtraceparserlldb.cpp ) add_library(drkonqi_backtrace_parser STATIC ${BACKTRACEPARSER_SRCS}) Index: drkonqi/parser/backtraceparser.cpp =================================================================== --- drkonqi/parser/backtraceparser.cpp +++ drkonqi/parser/backtraceparser.cpp @@ -18,6 +18,7 @@ #include "backtraceparser_p.h" #include "backtraceparsergdb.h" #include "backtraceparserkdbgwin.h" +#include "backtraceparserlldb.h" #include "backtraceparsernull.h" #include #include @@ -30,6 +31,8 @@ return new BacktraceParserGdb(parent); } else if (debuggerName == QLatin1String("kdbgwin")) { return new BacktraceParserKdbgwin(parent); + } else if (debuggerName == QLatin1String("lldb")) { + return new BacktraceParserLldb(parent); } else { return new BacktraceParserNull(parent); } @@ -198,6 +201,10 @@ || line.functionName().startsWith(QLatin1String("*__GI_")) //glibc2.9 uses *__GI_ as prefix || line.libraryName().contains(QStringLiteral("libpthread.so")) || line.libraryName().contains(QStringLiteral("libglib-2.0.so")) +#ifdef Q_OS_MACOS + || (line.libraryName().startsWith(QStringLiteral("libsystem_")) && line.libraryName().endsWith(QStringLiteral(".dylib"))) + || line.libraryName().contains(QStringLiteral("Foundation`")) +#endif || line.libraryName().contains(QStringLiteral("ntdll.dll")) || line.libraryName().contains(QStringLiteral("kernel32.dll")) || line.functionName().contains(QStringLiteral("_tmain")) Index: drkonqi/parser/backtraceparserlldb.h =================================================================== --- /dev/null +++ drkonqi/parser/backtraceparserlldb.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2014-2016 René J.V. Bertin + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BACKTRACEPARSERLLDB_H +#define BACKTRACEPARSERLLDB_H + +#include "backtraceparser.h" + +class BacktraceParserLldb : public BacktraceParser +{ + Q_OBJECT + Q_DECLARE_PRIVATE(BacktraceParser) +public: + explicit BacktraceParserLldb(QObject *parent = 0); + +protected Q_SLOTS: + virtual void newLine(const QString & lineStr); + +protected: + virtual BacktraceParserPrivate *constructPrivate() const; +}; + +#endif // BACKTRACEPARSERLLDB_H Index: drkonqi/parser/backtraceparserlldb.cpp =================================================================== --- /dev/null +++ drkonqi/parser/backtraceparserlldb.cpp @@ -0,0 +1,57 @@ +/* + Copyright (C) 2014 René J.V. Bertin + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "backtraceparserlldb.h" +#include "backtraceparser_p.h" + +//BEGIN BacktraceParserLldb + +class BacktraceLineLldb : public BacktraceLine +{ +public: + BacktraceLineLldb(const QString & line); +}; + +BacktraceLineLldb::BacktraceLineLldb(const QString & line) + : BacktraceLine() +{ + d->m_line = line; + // For now we'll have faith that lldb provides useful information, and that it would + // be unwarranted to give it a rating of "MissingEverything". + d->m_rating = Good; +} + +//END BacktraceLineLldb + +//BEGIN BacktraceParserLldb + +BacktraceParserLldb::BacktraceParserLldb(QObject *parent) : BacktraceParser(parent) {} + +BacktraceParserPrivate *BacktraceParserLldb::constructPrivate() const +{ + BacktraceParserPrivate *d = BacktraceParser::constructPrivate(); + d->m_usefulness = MayBeUseful; + return d; +} + +void BacktraceParserLldb::newLine(const QString & lineStr) +{ + d_ptr->m_linesList.append(BacktraceLineLldb(lineStr)); +} + + +//END BacktraceParserLldb