File indexing completed on 2024-04-28 04:38:34
0001 /* 0002 SPDX-FileCopyrightText: 2006 Vladimir Prus <ghost@cs.msu.su> 0003 SPDX-FileCopyrightText: 2007 Hamish Rodda <rodda@kde.org> 0004 SPDX-FileCopyrightText: 2009 Andreas Pakulat <apaku@gmx.de> 0005 SPDX-FileCopyrightText: 2016 Aetf <aetf@unlimitedcodeworks.xyz> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "midebugjobs.h" 0011 0012 #include "debuglog.h" 0013 #include "dialogs/selectcoredialog.h" 0014 #include "midebugsession.h" 0015 #include "midebuggerplugin.h" 0016 0017 #include <execute/iexecuteplugin.h> 0018 #include <interfaces/icore.h> 0019 #include <interfaces/iproject.h> 0020 #include <interfaces/ilaunchconfiguration.h> 0021 #include <interfaces/iuicontroller.h> 0022 #include <outputview/outputmodel.h> 0023 #include <util/scopeddialog.h> 0024 0025 #include <KConfigGroup> 0026 #include <KLocalizedString> 0027 #include <KParts/MainWindow> 0028 0029 #include <QFileInfo> 0030 0031 using namespace KDevMI; 0032 using namespace KDevelop; 0033 0034 template<class JobBase> 0035 MIDebugJobBase<JobBase>::MIDebugJobBase(MIDebuggerPlugin* plugin, QObject* parent) 0036 : JobBase(parent) 0037 { 0038 Q_ASSERT(plugin); 0039 0040 JobBase::setCapabilities(KJob::Killable); 0041 0042 m_session = plugin->createSession(); 0043 QObject::connect(m_session, &MIDebugSession::finished, this, &MIDebugJobBase::done); 0044 0045 qCDebug(DEBUGGERCOMMON) << "created debug job" << this << "with" << m_session; 0046 } 0047 0048 template<class JobBase> 0049 MIDebugJobBase<JobBase>::~MIDebugJobBase() 0050 { 0051 // Don't print m_session unconditionally, because it can be already destroyed. 0052 qCDebug(DEBUGGERCOMMON) << "destroying debug job" << this; 0053 // If this job is destroyed before it starts, m_session can be already destroyed even if this job is not finished. 0054 // For example, this occurs when the user starts debugging and immediately exits KDevelop. 0055 if (m_session && !JobBase::isFinished()) { 0056 qCDebug(DEBUGGERCOMMON) << "debug job destroyed before it finished, stopping debugger of" << m_session; 0057 m_session->stopDebugger(); 0058 } 0059 } 0060 0061 template<typename JobBase> 0062 void MIDebugJobBase<JobBase>::done() 0063 { 0064 qCDebug(DEBUGGERCOMMON) << "finishing debug job" << this << "with" << m_session; 0065 JobBase::emitResult(); 0066 } 0067 0068 template<typename JobBase> 0069 bool MIDebugJobBase<JobBase>::doKill() 0070 { 0071 qCDebug(DEBUGGERCOMMON) << "killing debug job" << this << "and stopping debugger of" << m_session; 0072 m_session->stopDebugger(); 0073 return true; 0074 } 0075 0076 MIDebugJob::MIDebugJob(MIDebuggerPlugin* p, ILaunchConfiguration* launchcfg, 0077 IExecutePlugin* execute, QObject* parent) 0078 : MIDebugJobBase(p, parent) 0079 , m_launchcfg(launchcfg) 0080 , m_execute(execute) 0081 { 0082 connect(m_session, &MIDebugSession::inferiorStdoutLines, this, &MIDebugJob::stdoutReceived); 0083 connect(m_session, &MIDebugSession::inferiorStderrLines, this, &MIDebugJob::stderrReceived); 0084 0085 if (launchcfg->project()) { 0086 setObjectName(i18nc("ProjectName: run configuration name", "%1: %2", 0087 launchcfg->project()->name(), launchcfg->name())); 0088 } else { 0089 setObjectName(launchcfg->name()); 0090 } 0091 } 0092 0093 void MIDebugJob::start() 0094 { 0095 Q_ASSERT(m_execute); 0096 0097 QString err; 0098 0099 // check if the config is valid 0100 QString executable = m_execute->executable(m_launchcfg, err).toLocalFile(); 0101 if (!err.isEmpty()) { 0102 finishWithError(InvalidExecutable, err); 0103 return; 0104 } 0105 0106 if (!QFileInfo(executable).isExecutable()) { 0107 finishWithError(ExecutableIsNotExecutable, i18n("'%1' is not an executable", executable)); 0108 return; 0109 } 0110 0111 QStringList arguments = m_execute->arguments(m_launchcfg, err); 0112 if (!err.isEmpty()) { 0113 finishWithError(InvalidArguments, err); 0114 return; 0115 } 0116 0117 setStandardToolView(IOutputView::DebugView); 0118 setBehaviours(IOutputView::Behaviours(IOutputView::AllowUserClose) | KDevelop::IOutputView::AutoScroll); 0119 0120 auto model = new KDevelop::OutputModel; 0121 model->setFilteringStrategy(OutputModel::NativeAppErrorFilter); 0122 setModel(model); 0123 setTitle(m_launchcfg->name()); 0124 0125 KConfigGroup grp = m_launchcfg->config(); 0126 QString startWith = grp.readEntry(Config::StartWithEntry, QStringLiteral("ApplicationOutput")); 0127 if (startWith == QLatin1String("ApplicationOutput")) { 0128 setVerbosity(Verbose); 0129 } else { 0130 setVerbosity(Silent); 0131 } 0132 0133 startOutput(); 0134 0135 if (!m_session->startDebugging(m_launchcfg, m_execute)) { 0136 done(); 0137 } 0138 } 0139 0140 void MIDebugJob::stderrReceived(const QStringList& l) 0141 { 0142 if (OutputModel* m = model()) { 0143 m->appendLines(l); 0144 } 0145 } 0146 0147 void MIDebugJob::stdoutReceived(const QStringList& l) 0148 { 0149 if (OutputModel* m = model()) { 0150 m->appendLines(l); 0151 } 0152 } 0153 0154 void MIDebugJob::finishWithError(int errorCode, const QString& errorText) 0155 { 0156 qCDebug(DEBUGGERCOMMON) << "failing" << this << "and stopping debugger of" << m_session; 0157 m_session->stopDebugger(); 0158 setError(errorCode); 0159 setErrorText(errorText); 0160 emitResult(); 0161 } 0162 0163 OutputModel* MIDebugJob::model() 0164 { 0165 return qobject_cast<OutputModel*>(OutputJob::model()); 0166 } 0167 0168 MIExamineCoreJob::MIExamineCoreJob(MIDebuggerPlugin *plugin, QObject *parent) 0169 : MIDebugJobBase(plugin, parent) 0170 { 0171 setObjectName(i18n("Debug core file")); 0172 } 0173 0174 void MIExamineCoreJob::start() 0175 { 0176 ScopedDialog<SelectCoreDialog> dlg(ICore::self()->uiController()->activeMainWindow()); 0177 if (dlg->exec() == QDialog::Rejected) { 0178 qCDebug(DEBUGGERCOMMON) << "Select Core File dialog rejected, finishing" << this << "and stopping debugger of" 0179 << m_session; 0180 m_session->stopDebugger(); 0181 done(); 0182 return; 0183 } 0184 0185 if (!m_session->examineCoreFile(dlg->executableFile(), dlg->core())) { 0186 done(); 0187 } 0188 } 0189 0190 MIAttachProcessJob::MIAttachProcessJob(MIDebuggerPlugin *plugin, int pid, QObject *parent) 0191 : MIDebugJobBase(plugin, parent) 0192 , m_pid(pid) 0193 { 0194 setObjectName(i18n("Debug process %1", pid)); 0195 } 0196 0197 void MIAttachProcessJob::start() 0198 { 0199 if (!m_session->attachToProcess(m_pid)) { 0200 done(); 0201 } 0202 } 0203 0204 #include "moc_midebugjobs.cpp"