File indexing completed on 2024-04-28 09:21:07

0001 /*
0002     SPDX-FileCopyrightText: 2009 George Kiagiadakis <gkiagia@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 #include "debuggermanager.h"
0008 
0009 #include <KConfigGroup>
0010 
0011 #include "backtracegenerator.h"
0012 #include "debugger.h"
0013 #include "debuggerlaunchers.h"
0014 #include "drkonqibackends.h"
0015 
0016 struct DebuggerManager::Private {
0017     BacktraceGenerator *btGenerator = nullptr;
0018     bool debuggerRunning = false;
0019     QList<AbstractDebuggerLauncher *> externalDebuggers;
0020     DBusInterfaceAdaptor *dbusInterfaceAdaptor = nullptr;
0021 };
0022 
0023 DebuggerManager::DebuggerManager(const Debugger &internalDebugger, const QList<Debugger> &externalDebuggers, AbstractDrKonqiBackend *backendParent)
0024     : QObject(backendParent)
0025     , d(new Private)
0026 {
0027     d->btGenerator = new BacktraceGenerator(internalDebugger, this);
0028     connect(d->btGenerator, &BacktraceGenerator::starting, this, &DebuggerManager::onDebuggerStarting);
0029     connect(d->btGenerator, &BacktraceGenerator::done, this, &DebuggerManager::onDebuggerFinished);
0030     connect(d->btGenerator, &BacktraceGenerator::someError, this, &DebuggerManager::onDebuggerFinished);
0031     connect(d->btGenerator, &BacktraceGenerator::failedToStart, this, &DebuggerManager::onDebuggerFinished);
0032     connect(d->btGenerator, &BacktraceGenerator::preparing, backendParent, &AbstractDrKonqiBackend::prepareForDebugger);
0033     connect(backendParent, &AbstractDrKonqiBackend::failedToPrepare, d->btGenerator, &BacktraceGenerator::setBackendFailed);
0034     connect(backendParent, &AbstractDrKonqiBackend::preparedForDebugger, d->btGenerator, &BacktraceGenerator::setBackendPrepared);
0035 
0036     for (const Debugger &debugger : std::as_const(externalDebuggers)) {
0037         if (debugger.isInstalled()) {
0038             // TODO: use TerminalDebuggerLauncher instead
0039             addDebugger(new DefaultDebuggerLauncher(debugger, this));
0040         }
0041     }
0042 
0043     // DBus API to inject additional external debuggers at runtime. Used by KDevelop to add itself.
0044     if (qobject_cast<KCrashBackend *>(backendParent)) {
0045         // Runtime debugger injection is only allowed with KCrash because the API sports no interfaces for the debugger
0046         // to describe its compatibility and it was introduced when only KCrash was around. To not have apps break
0047         // randomly on different backends we require that our backend be KCrash.
0048         d->dbusInterfaceAdaptor = new DBusInterfaceAdaptor(this);
0049     }
0050 }
0051 
0052 DebuggerManager::~DebuggerManager()
0053 {
0054     if (d->btGenerator->state() == BacktraceGenerator::Loading) {
0055         // if the debugger is running, kill it and continue the process.
0056         delete d->btGenerator;
0057         onDebuggerFinished();
0058     }
0059 
0060     delete d;
0061 }
0062 
0063 bool DebuggerManager::debuggerIsRunning() const
0064 {
0065     return d->debuggerRunning;
0066 }
0067 
0068 bool DebuggerManager::showExternalDebuggers() const
0069 {
0070     KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("DrKonqi"));
0071     return config.readEntry("ShowDebugButton", false);
0072 }
0073 
0074 QList<AbstractDebuggerLauncher *> DebuggerManager::availableExternalDebuggers() const
0075 {
0076     return d->externalDebuggers;
0077 }
0078 
0079 BacktraceGenerator *DebuggerManager::backtraceGenerator() const
0080 {
0081     return d->btGenerator;
0082 }
0083 
0084 void DebuggerManager::addDebugger(AbstractDebuggerLauncher *launcher, bool emitsignal)
0085 {
0086     d->externalDebuggers.append(launcher);
0087     connect(launcher, &AbstractDebuggerLauncher::starting, this, &DebuggerManager::onDebuggerStarting);
0088     connect(launcher, &AbstractDebuggerLauncher::finished, this, &DebuggerManager::onDebuggerFinished);
0089     connect(launcher, &AbstractDebuggerLauncher::invalidated, this, &DebuggerManager::onDebuggerInvalidated);
0090     if (emitsignal) {
0091         Q_EMIT externalDebuggerAdded(launcher);
0092     }
0093 }
0094 
0095 void DebuggerManager::onDebuggerStarting()
0096 {
0097     d->debuggerRunning = true;
0098     Q_EMIT debuggerStarting();
0099     Q_EMIT debuggerRunning(true);
0100 }
0101 
0102 void DebuggerManager::onDebuggerFinished()
0103 {
0104     d->debuggerRunning = false;
0105     Q_EMIT debuggerFinished();
0106     Q_EMIT debuggerRunning(false);
0107 }
0108 
0109 void DebuggerManager::onDebuggerInvalidated()
0110 {
0111     auto *launcher = qobject_cast<AbstractDebuggerLauncher *>(sender());
0112     Q_ASSERT(launcher);
0113     int index = d->externalDebuggers.indexOf(launcher);
0114     Q_ASSERT(index >= 0);
0115     d->externalDebuggers.removeAt(index);
0116     Q_EMIT externalDebuggerRemoved(launcher);
0117 }
0118 
0119 #include "moc_debuggermanager.cpp"