File indexing completed on 2024-04-21 16:12:21

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::preparedForDebugger, d->btGenerator, &BacktraceGenerator::setBackendPrepared);
0034 
0035     for (const Debugger &debugger : std::as_const(externalDebuggers)) {
0036         if (debugger.isInstalled()) {
0037             // TODO: use TerminalDebuggerLauncher instead
0038             addDebugger(new DefaultDebuggerLauncher(debugger, this));
0039         }
0040     }
0041 
0042     // DBus API to inject additional external debuggers at runtime. Used by KDevelop to add itself.
0043     if (qobject_cast<KCrashBackend *>(backendParent)) {
0044         // Runtime debugger injection is only allowed with KCrash because the API sports no interfaces for the debugger
0045         // to describe its compatibility and it was introduced when only KCrash was around. To not have apps break
0046         // randomly on different backends we require that our backend be KCrash.
0047         d->dbusInterfaceAdaptor = new DBusInterfaceAdaptor(this);
0048     }
0049 }
0050 
0051 DebuggerManager::~DebuggerManager()
0052 {
0053     if (d->btGenerator->state() == BacktraceGenerator::Loading) {
0054         // if the debugger is running, kill it and continue the process.
0055         delete d->btGenerator;
0056         onDebuggerFinished();
0057     }
0058 
0059     delete d;
0060 }
0061 
0062 bool DebuggerManager::debuggerIsRunning() const
0063 {
0064     return d->debuggerRunning;
0065 }
0066 
0067 bool DebuggerManager::showExternalDebuggers() const
0068 {
0069     KConfigGroup config(KSharedConfig::openConfig(), "DrKonqi");
0070     return config.readEntry("ShowDebugButton", false);
0071 }
0072 
0073 QList<AbstractDebuggerLauncher *> DebuggerManager::availableExternalDebuggers() const
0074 {
0075     return d->externalDebuggers;
0076 }
0077 
0078 BacktraceGenerator *DebuggerManager::backtraceGenerator() const
0079 {
0080     return d->btGenerator;
0081 }
0082 
0083 void DebuggerManager::addDebugger(AbstractDebuggerLauncher *launcher, bool emitsignal)
0084 {
0085     d->externalDebuggers.append(launcher);
0086     connect(launcher, &AbstractDebuggerLauncher::starting, this, &DebuggerManager::onDebuggerStarting);
0087     connect(launcher, &AbstractDebuggerLauncher::finished, this, &DebuggerManager::onDebuggerFinished);
0088     connect(launcher, &AbstractDebuggerLauncher::invalidated, this, &DebuggerManager::onDebuggerInvalidated);
0089     if (emitsignal) {
0090         Q_EMIT externalDebuggerAdded(launcher);
0091     }
0092 }
0093 
0094 void DebuggerManager::onDebuggerStarting()
0095 {
0096     d->debuggerRunning = true;
0097     Q_EMIT debuggerStarting();
0098     Q_EMIT debuggerRunning(true);
0099 }
0100 
0101 void DebuggerManager::onDebuggerFinished()
0102 {
0103     d->debuggerRunning = false;
0104     Q_EMIT debuggerFinished();
0105     Q_EMIT debuggerRunning(false);
0106 }
0107 
0108 void DebuggerManager::onDebuggerInvalidated()
0109 {
0110     auto *launcher = qobject_cast<AbstractDebuggerLauncher *>(sender());
0111     Q_ASSERT(launcher);
0112     int index = d->externalDebuggers.indexOf(launcher);
0113     Q_ASSERT(index >= 0);
0114     d->externalDebuggers.removeAt(index);
0115     Q_EMIT externalDebuggerRemoved(launcher);
0116 }