diff --git a/debuggers/common/CMakeLists.txt b/debuggers/common/CMakeLists.txt --- a/debuggers/common/CMakeLists.txt +++ b/debuggers/common/CMakeLists.txt @@ -4,25 +4,49 @@ mi/miparser.cpp mi/micommand.cpp mi/micommandqueue.cpp + dialogs/selectcoredialog.cpp debuglog.cpp + # debug session & debugger midebugger.cpp midebugsession.cpp + midebuggerplugin.cpp + midebugjobs.cpp + # controllers mibreakpointcontroller.cpp miframestackmodel.cpp mivariablecontroller.cpp mivariable.cpp stringhelpers.cpp stty.cpp ) -#ki18n_wrap_ui(debuggercommon_SRCS something.ui) + +find_package(KF5SysGuard) +if(KF5SysGuard_FOUND) + add_definitions(-DKDEV_ENABLE_DBG_ATTACH_DIALOG) + set(debuggercommon_SRCS + ${debuggercommon_SRCS} + dialogs/processselection.cpp + ) +endif() + +ki18n_wrap_ui(debuggercommon_SRCS + dialogs/selectcoredialog.ui +) add_library(kdevdebuggercommon STATIC ${debuggercommon_SRCS}) target_link_libraries(kdevdebuggercommon PUBLIC KDev::Debugger PRIVATE Qt5::Core + Qt5::Gui KDev::Util ) +if(KF5SysGuard_FOUND) + target_link_libraries(kdevdebuggercommon + PUBLIC + KF5::ProcessUi + ) +endif() kde_target_enable_exceptions(kdevdebuggercommon PUBLIC) diff --git a/debuggers/gdb/processselection.h b/debuggers/common/dialogs/processselection.h rename from debuggers/gdb/processselection.h rename to debuggers/common/dialogs/processselection.h --- a/debuggers/gdb/processselection.h +++ b/debuggers/common/dialogs/processselection.h @@ -26,10 +26,8 @@ class KSysGuardProcessList; class QPushButton; -namespace KDevMI -{ -namespace GDB -{ +namespace KDevMI { + class ProcessSelectionDialog : public QDialog { Q_OBJECT @@ -47,7 +45,6 @@ QPushButton* m_okButton; }; -} // end of namespace GDB } // end of namespace KDevMI #endif diff --git a/debuggers/gdb/processselection.cpp b/debuggers/common/dialogs/processselection.cpp rename from debuggers/gdb/processselection.cpp rename to debuggers/common/dialogs/processselection.cpp --- a/debuggers/gdb/processselection.cpp +++ b/debuggers/common/dialogs/processselection.cpp @@ -36,7 +36,7 @@ #include -using namespace KDevMI::GDB; +using namespace KDevMI; ProcessSelectionDialog::ProcessSelectionDialog(QWidget *parent) : QDialog(parent) diff --git a/debuggers/gdb/selectcoredialog.h b/debuggers/common/dialogs/selectcoredialog.h rename from debuggers/gdb/selectcoredialog.h rename to debuggers/common/dialogs/selectcoredialog.h --- a/debuggers/gdb/selectcoredialog.h +++ b/debuggers/common/dialogs/selectcoredialog.h @@ -28,7 +28,6 @@ #include "ui_selectcoredialog.h" namespace KDevMI { -namespace GDB { class SelectCoreDialog : public QDialog { @@ -41,7 +40,6 @@ Ui::SelectCoreDialog m_ui; }; -} // end of namespace GDB } // end of namespace KDevMI #endif diff --git a/debuggers/gdb/selectcoredialog.cpp b/debuggers/common/dialogs/selectcoredialog.cpp rename from debuggers/gdb/selectcoredialog.cpp rename to debuggers/common/dialogs/selectcoredialog.cpp --- a/debuggers/gdb/selectcoredialog.cpp +++ b/debuggers/common/dialogs/selectcoredialog.cpp @@ -20,9 +20,10 @@ */ #include "selectcoredialog.h" + #include -using namespace KDevMI::GDB; +using namespace KDevMI; SelectCoreDialog::SelectCoreDialog(QWidget* parent) : QDialog(parent) diff --git a/debuggers/gdb/selectcoredialog.ui b/debuggers/common/dialogs/selectcoredialog.ui rename from debuggers/gdb/selectcoredialog.ui rename to debuggers/common/dialogs/selectcoredialog.ui diff --git a/debuggers/common/mi/micommand.h b/debuggers/common/mi/micommand.h --- a/debuggers/common/mi/micommand.h +++ b/debuggers/common/mi/micommand.h @@ -101,6 +101,7 @@ protected: MICommand(CommandType type, const QString& arguments = QString(), CommandFlags flags = 0); friend class KDevMI::MIDebugSession; + public: virtual ~MICommand(); @@ -194,16 +195,15 @@ bool stateReloading() const; -private: +protected: CommandType type_; CommandFlags flags_; uint32_t token_ = 0; QString command_; MICommandHandler *commandHandler_; QStringList lines; bool stateReloading_; -private: int m_thread; int m_frame; }; diff --git a/debuggers/common/midebugger.h b/debuggers/common/midebugger.h --- a/debuggers/common/midebugger.h +++ b/debuggers/common/midebugger.h @@ -50,7 +50,7 @@ /** Starts the debugger. This should be done after connecting to all signals the client is interested in. */ - virtual void start(KConfigGroup& config, const QStringList& extraArguments = {}) = 0; + virtual bool start(KConfigGroup& config, const QStringList& extraArguments = {}) = 0; /** Executes a command. This method may be called at most once each time 'ready' is emitted. When the diff --git a/debuggers/common/midebuggerplugin.h b/debuggers/common/midebuggerplugin.h new file mode 100644 --- /dev/null +++ b/debuggers/common/midebuggerplugin.h @@ -0,0 +1,155 @@ +/* + * Common code for MI debugger support + * + * Copyright 1999-2001 John Birch + * Copyright 2001 by Bernd Gehrmann + * Copyright 2007 Hamish Rodda + * Copyright 2016 Aetf + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see . + * + */ + +#ifndef MIDEBUGGERPLUGIN_H +#define MIDEBUGGERPLUGIN_H + +#include +#include +#include +#include + +#include + +class QDBusInterface; +class QSignalMapper; +class QUrl; + +namespace KDevelop { +class Context; +} + +namespace KDevMI { +class MIDebugSession; +class MIDebuggerPlugin : public KDevelop::IPlugin, public KDevelop::IStatus +{ + Q_OBJECT + Q_INTERFACES(KDevelop::IStatus) + +public: + MIDebuggerPlugin(const QString& componentName, QObject *parent); + ~MIDebuggerPlugin() override; + + void unload() override; + KDevelop::ContextMenuExtension contextMenuExtension( KDevelop::Context* ) override; + + virtual MIDebugSession *createSession() const = 0; + +//BEGIN IStatus +public: + QString statusName() const override; + +Q_SIGNALS: + void clearMessage(KDevelop::IStatus*) override; + void showMessage(KDevelop::IStatus*, const QString & message, int timeout = 0) override; + void hideProgress(KDevelop::IStatus*) override; + void showProgress(KDevelop::IStatus*, int minimum, int maximum, int value) override; + void showErrorMessage(const QString&, int) override; +//END IStatus + +Q_SIGNALS: + void reset(); + void stopDebugger(); + void attachTo(int pid); + void coreFile(const QString& core); + void runUntil(const QUrl &url, int line); + void jumpTo(const QUrl &url, int line); + void addWatchVariable(const QString& var); + void evaluateExpression(const QString& expr); + void raiseDebuggerConsoleViews(); + +protected Q_SLOTS: + + void slotDebugExternalProcess(QObject* interface); + void slotExamineCore(); + #ifdef KDEV_ENABLE_DBG_ATTACH_DIALOG + void slotAttachProcess(); + #endif + + void slotDBusServiceRegistered(const QString& service); + void slotDBusServiceUnregistered(const QString& service); + void slotCloseDrKonqi(); + +protected: + void setupToolviews(); + void setupActions(); + void setupDBus(); + + void attachProcess(int pid); + void showStatusMessage(const QString& msg, int timeout); + +private: + QHash m_drkonqis; + QSignalMapper* m_drkonqiMap; + QString m_drkonqi; +}; + +template +class DebuggerToolFactory : public KDevelop::IToolViewFactory +{ +public: + DebuggerToolFactory(Plugin * plugin, const QString &id, Qt::DockWidgetArea defaultArea) + : m_plugin(plugin), m_id(id), m_defaultArea(defaultArea) + {} + + QWidget* create(QWidget *parent = 0) override + { + return new T(m_plugin, parent); + } + + QString id() const override + { + return m_id; + } + + Qt::DockWidgetArea defaultPosition() override + { + return m_defaultArea; + } + + void viewCreated(Sublime::View* view) override + { + if (view->widget()->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("requestRaise()")) != -1) + QObject::connect(view->widget(), SIGNAL(requestRaise()), view, SLOT(requestRaise())); + } + + /* At present, some debugger widgets (e.g. breakpoint) contain actions so that shortcuts + work, but they don't need any toolbar. So, suppress toolbar action. */ + QList toolBarActions(QWidget* viewWidget) const override + { + Q_UNUSED(viewWidget); + return QList(); + } + +private: + Plugin * m_plugin; + QString m_id; + Qt::DockWidgetArea m_defaultArea; +}; + +} // end of namespace KDevMI + +#endif // MIDEBUGGERPLUGIN_H diff --git a/debuggers/common/midebuggerplugin.cpp b/debuggers/common/midebuggerplugin.cpp new file mode 100644 --- /dev/null +++ b/debuggers/common/midebuggerplugin.cpp @@ -0,0 +1,310 @@ +/* + * Common code for MI debugger support + * + * Copyright 1999-2001 John Birch + * Copyright 2001 by Bernd Gehrmann + * Copyright 2006 Vladimir Prus + * Copyright 2007 Hamish Rodda + * Copyright 2016 Aetf + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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, see . + * + */ + +#include "midebuggerplugin.h" + +#include "midebugjobs.h" +#include "dialogs/processselection.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace KDevelop; +using namespace KDevMI; + +MIDebuggerPlugin::MIDebuggerPlugin(const QString &componentName, QObject *parent) + : KDevelop::IPlugin(componentName, parent) +{ + KDEV_USE_EXTENSION_INTERFACE(KDevelop::IStatus) + + core()->debugController()->initializeUi(); + + setupToolviews(); + setupActions(); + setupDBus(); +} + +void MIDebuggerPlugin::setupToolviews() +{ + // TODO: port tool views + /* + disassemblefactory = new DebuggerToolFactory( + this, "org.kdevelop.debugger.DisassemblerView", Qt::BottomDockWidgetArea); + + lldbfactory = new DebuggerToolFactory( + this, "org.kdevelop.debugger.ConsoleView",Qt::BottomDockWidgetArea); + + core()->uiController()->addToolView( + i18n("Disassemble/Registers"), + disassemblefactory); + + core()->uiController()->addToolView( + i18n("LLDB"), + lldbfactory); + +#ifndef WITH_OKTETA + memoryviewerfactory = nullptr; +#else + memoryviewerfactory = new DebuggerToolFactory( + this, "org.kdevelop.debugger.MemoryView", Qt::BottomDockWidgetArea); + core()->uiController()->addToolView( + i18n("Memory"), + memoryviewerfactory); +#endif +*/ +} + +void MIDebuggerPlugin::setupActions() +{ + KActionCollection* ac = actionCollection(); + + QAction * action = new QAction(this); + action->setIcon(QIcon::fromTheme("core")); + action->setText(i18n("Examine Core File...")); + action->setToolTip(i18n("Examine core file")); + action->setWhatsThis(i18n("Examine core file" + "

This loads a core file, which is typically created " + "after the application has crashed, e.g. with a " + "segmentation fault. The core file contains an " + "image of the program memory at the time it crashed, " + "allowing you to do a post-mortem analysis.

")); + connect(action, &QAction::triggered, this, &MIDebuggerPlugin::slotExamineCore); + ac->addAction("debug_core", action); + + #ifdef KDEV_ENABLE_DBG_ATTACH_DIALOG + action = new QAction(this); + action->setIcon(QIcon::fromTheme("connect_creating")); + action->setText(i18n("Attach to Process...")); + action->setToolTip(i18n("Attach to process")); + action->setWhatsThis(i18n("Attach to process" + "

Attaches the debugger to a running process.

")); + connect(action, &QAction::triggered, this, &MIDebuggerPlugin::slotAttachProcess); + ac->addAction("debug_attach", action); + #endif +} + +void MIDebuggerPlugin::setupDBus() +{ + m_drkonqiMap = new QSignalMapper(this); + connect(m_drkonqiMap, static_cast(&QSignalMapper::mapped), + this, &MIDebuggerPlugin::slotDebugExternalProcess); + + QDBusConnectionInterface* dbusInterface = QDBusConnection::sessionBus().interface(); + for (const auto &service : dbusInterface->registeredServiceNames().value()) { + slotDBusServiceRegistered(service); + } + + QDBusServiceWatcher* watcher = new QDBusServiceWatcher(this); + connect(watcher, &QDBusServiceWatcher::serviceRegistered, + this, &MIDebuggerPlugin::slotDBusServiceRegistered); + connect(watcher, &QDBusServiceWatcher::serviceUnregistered, + this, &MIDebuggerPlugin::slotDBusServiceUnregistered); +} + +void MIDebuggerPlugin::unload() +{ + // TODO: port tool views + /* + core()->uiController()->removeToolView(disassemblefactory); + core()->uiController()->removeToolView(lldbfactory); + core()->uiController()->removeToolView(memoryviewerfactory); + */ +} + +MIDebuggerPlugin::~MIDebuggerPlugin() +{ +} + +void MIDebuggerPlugin::slotDBusServiceRegistered(const QString& service) +{ + if (service.startsWith("org.kde.drkonqi")) { + // New registration + QDBusInterface* drkonqiInterface = new QDBusInterface(service, "/krashinfo", + QString(), QDBusConnection::sessionBus(), + this); + m_drkonqis.insert(service, drkonqiInterface); + + connect(drkonqiInterface, SIGNAL(acceptDebuggingApplication()), m_drkonqiMap, SLOT(map())); + m_drkonqiMap->setMapping(drkonqiInterface, drkonqiInterface); + + drkonqiInterface->call("registerDebuggingApplication", i18n("KDevelop")); + } +} + +void MIDebuggerPlugin::slotDBusServiceUnregistered(const QString& service) +{ + if (service.startsWith("org.kde.drkonqi")) { + // Deregistration + if (m_drkonqis.contains(service)) + delete m_drkonqis.take(service); + } +} + +void MIDebuggerPlugin::slotDebugExternalProcess(QObject* interface) +{ + auto dbusInterface = static_cast(interface); + + QDBusReply reply = dbusInterface->call("pid"); + if (reply.isValid()) { + attachProcess(reply.value()); + QTimer::singleShot(500, this, &MIDebuggerPlugin::slotCloseDrKonqi); + + m_drkonqi = m_drkonqis.key(dbusInterface); + } + + core()->uiController()->activeMainWindow()->raise(); +} + +void MIDebuggerPlugin::slotCloseDrKonqi() +{ + if (!m_drkonqi.isEmpty()) { + QDBusInterface drkonqiInterface(m_drkonqi, "/MainApplication", "org.kde.KApplication"); + drkonqiInterface.call("quit"); + m_drkonqi.clear(); + } +} + +ContextMenuExtension MIDebuggerPlugin::contextMenuExtension(Context* context) +{ + ContextMenuExtension menuExt = IPlugin::contextMenuExtension(context); + + if (context->type() != KDevelop::Context::EditorContext) + return menuExt; + + EditorContext *econtext = dynamic_cast(context); + if (!econtext) + return menuExt; + + QString contextIdent = econtext->currentWord(); + + if (!contextIdent.isEmpty()) + { + QString squeezed = KStringHandler::csqueeze(contextIdent, 30); + + QAction* action = new QAction(this); + action->setText(i18n("Evaluate: %1", squeezed)); + action->setWhatsThis(i18n("Evaluate expression" + "

Shows the value of the expression under the cursor.

")); + connect(action, &QAction::triggered, this, [this, contextIdent](){ + emit addWatchVariable(contextIdent); + }); + menuExt.addAction(ContextMenuExtension::DebugGroup, action); + + action = new QAction(this); + action->setText(i18n("Watch: %1", squeezed)); + action->setWhatsThis(i18n("Watch expression" + "

Adds the expression under the cursor to the Variables/Watch list.

")); + connect(action, &QAction::triggered, this, [this, contextIdent](){ + emit evaluateExpression(contextIdent); + }); + menuExt.addAction(ContextMenuExtension::DebugGroup, action); + } + + return menuExt; +} + +void MIDebuggerPlugin::slotExamineCore() +{ + showStatusMessage(i18n("Choose a core file to examine..."), 1000); + + if (core()->debugController()->currentSession() != nullptr) { + KMessageBox::ButtonCode answer = KMessageBox::warningYesNo( + core()->uiController()->activeMainWindow(), + i18n("A program is already being debugged. Do you want to abort the " + "currently running debug session and continue?")); + if (answer == KMessageBox::No) + return; + } + MIExamineCoreJob *job = new MIExamineCoreJob(this, core()->runController()); + core()->runController()->registerJob(job); + // job->start() is called in registerJob +} + +#ifdef KDEV_ENABLE_DBG_ATTACH_DIALOG +void MIDebuggerPlugin::slotAttachProcess() +{ + showStatusMessage(i18n("Choose a process to attach to..."), 1000); + + if (core()->debugController()->currentSession() != nullptr) { + KMessageBox::ButtonCode answer = KMessageBox::warningYesNo( + core()->uiController()->activeMainWindow(), + i18n("A program is already being debugged. Do you want to abort the " + "currently running debug session and continue?")); + if (answer == KMessageBox::No) + return; + } + + ProcessSelectionDialog dlg(core()->uiController()->activeMainWindow()); + if (!dlg.exec() || !dlg.pidSelected()) + return; + + // TODO: move check into process selection dialog + int pid = dlg.pidSelected(); + if (QApplication::applicationPid() == pid) + KMessageBox::error(core()->uiController()->activeMainWindow(), + i18n("Not attaching to process %1: cannot attach the debugger to itself.", pid)); + else + attachProcess(pid); +} +#endif + +void MIDebuggerPlugin::attachProcess(int pid) +{ + MIAttachProcessJob *job = new MIAttachProcessJob(this, pid, core()->runController()); + core()->runController()->registerJob(job); + // job->start() is called in registerJob +} + +QString MIDebuggerPlugin::statusName() const +{ + return i18n("Debugger"); +} + +void MIDebuggerPlugin::showStatusMessage(const QString& msg, int timeout) +{ + emit showMessage(this, msg, timeout); +} diff --git a/debuggers/gdb/debugjob.h b/debuggers/common/midebugjobs.h rename from debuggers/gdb/debugjob.h rename to debuggers/common/midebugjobs.h --- a/debuggers/gdb/debugjob.h +++ b/debuggers/common/midebugjobs.h @@ -1,9 +1,10 @@ /* -* GDB Debugger Support +* Common Code for Debugger Support * * Copyright 2006 Vladimir Prus * Copyright 2007 Hamish Rodda * Copyright 2009 Andreas Pakulat +* Copyright 2016 Aetf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as @@ -20,8 +21,8 @@ * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef GDBDEBUGJOB -#define GDBDEBUGJOB +#ifndef MIDEBUGJOBS_H +#define MIDEBUGJOBS_H #include @@ -33,48 +34,71 @@ } namespace KDevMI { -namespace GDB -{ -class CppDebuggerPlugin; -class DebugSession; +class MIDebuggerPlugin; +class MIDebugSession; -class DebugJob : public KDevelop::OutputJob +class MIDebugJob : public KDevelop::OutputJob { -Q_OBJECT + Q_OBJECT public: - DebugJob( CppDebuggerPlugin* p, KDevelop::ILaunchConfiguration* launchcfg, - IExecutePlugin* plugin, QObject* parent = 0 ); + MIDebugJob(MIDebuggerPlugin* p, KDevelop::ILaunchConfiguration* launchcfg, IExecutePlugin* plugin, + QObject* parent = 0); void start() override; + protected: bool doKill() override; -private slots: + +private Q_SLOTS: void stdoutReceived(const QStringList&); void stderrReceived(const QStringList&); void done(); + private: KDevelop::OutputModel* model(); - DebugSession* m_session; + + MIDebugSession* m_session; KDevelop::ILaunchConfiguration* m_launchcfg; IExecutePlugin* m_execute; }; -//this job is just here to be able to kill the debug session -class KillSessionJob : public KJob +class MIExamineCoreJob : public KJob { -Q_OBJECT + Q_OBJECT public: - KillSessionJob(DebugSession *session, QObject *parent = 0); + MIExamineCoreJob(MIDebuggerPlugin *plugin, QObject *parent = nullptr); + void start() override; + protected: bool doKill() override; + +private Q_SLOTS: + void done(); + +private: + MIDebugSession *m_session; +}; + +class MIAttachProcessJob : public KJob +{ + Q_OBJECT +public: + MIAttachProcessJob(MIDebuggerPlugin *plugin, int pid, QObject *parent = nullptr); + + void start() override; + +protected: + bool doKill() override; + +private Q_SLOTS: + void done(); + private: - DebugSession* m_session; -private slots: - void sessionFinished(); + int m_pid; + MIDebugSession *m_session; }; -} // end of namespace GDB } // end of namespace KDevMI -#endif +#endif // MIDEBUGJOBS_H diff --git a/debuggers/common/midebugjobs.cpp b/debuggers/common/midebugjobs.cpp new file mode 100644 --- /dev/null +++ b/debuggers/common/midebugjobs.cpp @@ -0,0 +1,219 @@ +/* +* Common Code for Debugger Support +* +* Copyright 2006 Vladimir Prus +* Copyright 2007 Hamish Rodda +* Copyright 2009 Andreas Pakulat +* Copyright 2016 Aetf +* +* 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 "midebugjobs.h" + +#include "debuglog.h" +#include "dialogs/selectcoredialog.h" +#include "midebugsession.h" +#include "midebuggerplugin.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace KDevMI; +using namespace KDevelop; + +MIDebugJob::MIDebugJob(MIDebuggerPlugin* p, ILaunchConfiguration* launchcfg, + IExecutePlugin* execute, QObject* parent) + : KDevelop::OutputJob(parent) + , m_launchcfg(launchcfg) + , m_execute(execute) +{ + setCapabilities(Killable); + + m_session = p->createSession(); + connect(m_session, &MIDebugSession::inferiorStdoutLines, this, &MIDebugJob::stderrReceived); + connect(m_session, &MIDebugSession::inferiorStderrLines, this, &MIDebugJob::stdoutReceived); + connect(m_session, &MIDebugSession::finished, this, &MIDebugJob::done); + + if (launchcfg->project()) { + setObjectName(i18nc("ProjectName: run configuration name", "%1: %2", + launchcfg->project()->name(), launchcfg->name())); + } else { + setObjectName(launchcfg->name()); + } +} + +void MIDebugJob::start() +{ + Q_ASSERT(m_execute); + + QString err; + + // check if the config is valid + QString executable = m_execute->executable(m_launchcfg, err).toLocalFile(); + if (!err.isEmpty()) { + setError(-1); + setErrorText(err); + emitResult(); + return; + } + + if (!QFileInfo(executable).isExecutable()) { + setError(-1); + setErrorText(i18n("'%1' is not an executable", executable)); + emitResult(); + return; + } + + QStringList arguments = m_execute->arguments(m_launchcfg, err); + if (!err.isEmpty()) { + setError(-1); + setErrorText(err); + emitResult(); + return; + } + + setStandardToolView(IOutputView::DebugView); + setBehaviours(IOutputView::Behaviours(IOutputView::AllowUserClose) | KDevelop::IOutputView::AutoScroll); + + auto model = new KDevelop::OutputModel; + model->setFilteringStrategy(OutputModel::NativeAppErrorFilter); + setModel(model); + setTitle(m_launchcfg->name()); + + KConfigGroup grp = m_launchcfg->config(); + QString startWith = grp.readEntry(startWithEntry, QString("ApplicationOutput")); + if (startWith == "GdbConsole") { + setVerbosity(Silent); + } else if (startWith == "FrameStack") { + setVerbosity(Silent); + } else { + setVerbosity(Verbose); + } + + startOutput(); + + if (!m_session->startDebugging(m_launchcfg, m_execute)) { + done(); + } +} + +bool MIDebugJob::doKill() +{ + m_session->stopDebugger(); + return true; +} + +void MIDebugJob::stderrReceived(const QStringList& l) +{ + if (OutputModel* m = model()) { + m->appendLines(l); + } +} + +void MIDebugJob::stdoutReceived(const QStringList& l) +{ + if (OutputModel* m = model()) { + m->appendLines(l); + } +} + +OutputModel* MIDebugJob::model() +{ + return qobject_cast(OutputJob::model()); +} + +void MIDebugJob::done() +{ + emitResult(); +} + +MIExamineCoreJob::MIExamineCoreJob(MIDebuggerPlugin *plugin, QObject *parent) + : KJob(parent) +{ + setCapabilities(Killable); + + m_session = plugin->createSession(); + connect(m_session, &MIDebugSession::finished, this, &MIExamineCoreJob::done); + + setObjectName(i18n("Debug core file")); +} + +void MIExamineCoreJob::start() +{ + SelectCoreDialog dlg(ICore::self()->uiController()->activeMainWindow()); + if (dlg.exec() == QDialog::Rejected) { + done(); + return; + } + + if (!m_session->examineCoreFile(dlg.binary(), dlg.core())) { + done(); + } +} + +bool MIExamineCoreJob::doKill() +{ + m_session->stopDebugger(); + return true; +} + +void MIExamineCoreJob::done() +{ + emitResult(); +} + +MIAttachProcessJob::MIAttachProcessJob(MIDebuggerPlugin *plugin, int pid, QObject *parent) + : KJob(parent) + , m_pid(pid) +{ + setCapabilities(Killable); + + m_session = plugin->createSession(); + connect(m_session, &MIDebugSession::finished, this, &MIAttachProcessJob::done); + + setObjectName(i18n("Debug process %1", pid)); +} + +void MIAttachProcessJob::start() +{ + if (!m_session->attachToProcess(m_pid)) { + done(); + } +} + +bool MIAttachProcessJob::doKill() +{ + m_session->stopDebugger(); + return true; +} + +void MIAttachProcessJob::done() +{ + emitResult(); +} diff --git a/debuggers/common/midebugsession.cpp b/debuggers/common/midebugsession.cpp --- a/debuggers/common/midebugsession.cpp +++ b/debuggers/common/midebugsession.cpp @@ -165,7 +165,9 @@ // Change to use a global launch configuration when calling : KConfigGroup(KSharedConfig::openConfig(), "GDB Config"); - m_debugger->start(config, extraArguments); + if (!m_debugger->start(config, extraArguments)) { + return false; + } // FIXME: here, we should wait until the debugger is up and waiting for input. // Then, clear s_dbgNotStarted @@ -273,6 +275,8 @@ { qCDebug(DEBUGGERCOMMON) << "Attach to process" << pid; + emit showMessage(i18n("Attaching to process %1", pid), 1000); + if (debuggerStateIsOn(s_dbgNotStarted)) { // FIXME: use global launch configuration rather than nullptr if (!startDebugger(nullptr)) { @@ -321,6 +325,8 @@ bool MIDebugSession::examineCoreFile(const QUrl &debugee, const QUrl &coreFile) { + emit showMessage(i18n("Examining core file %1", coreFile.toLocalFile()), 1000); + if (debuggerStateIsOn(s_dbgNotStarted)) { // FIXME: use global launch configuration rather than nullptr if (!startDebugger(nullptr)) { diff --git a/debuggers/common/stty.cpp b/debuggers/common/stty.cpp --- a/debuggers/common/stty.cpp +++ b/debuggers/common/stty.cpp @@ -69,7 +69,6 @@ #include #include -#include #include "stty.h" #include "debuglog.h" diff --git a/debuggers/gdb/CMakeLists.txt b/debuggers/gdb/CMakeLists.txt --- a/debuggers/gdb/CMakeLists.txt +++ b/debuggers/gdb/CMakeLists.txt @@ -13,13 +13,6 @@ set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS_DEBUG} ${_flags}") endfunction() -find_package(KF5SysGuard) -if(KF5SysGuard_FOUND) - add_definitions( - -DKDEV_ENABLE_GDB_ATTACH_DIALOG - ) -endif() - if (CMAKE_VERSION VERSION_GREATER "2.9" OR NOT CMAKE_GENERATOR MATCHES "Ninja") set(HAVE_PATH_WITH_SPACES_TEST TRUE) else() @@ -44,8 +37,6 @@ debugsession.cpp gdbbreakpointcontroller.cpp gdbconfigpage.cpp - debugjob.cpp - selectcoredialog.cpp variablecontroller.cpp gdbframestackmodel.cpp gdbvariable.cpp @@ -64,18 +55,9 @@ memviewdlg.cpp) endif() - -if(KF5SysGuard_FOUND) - set(kdevgdb_SRCS - ${kdevgdb_SRCS} - processselection.cpp - ) -endif() - set(kdevgdb_UI debuggertracingdialog.ui gdbconfigpage.ui - selectcoredialog.ui selectaddressdialog.ui registers/registersview.ui ) @@ -95,9 +77,6 @@ KF5::TextEditor kdevdebuggercommon ) -if(KF5SysGuard_FOUND) - target_link_libraries(kdevgdb KF5::ProcessUi) -endif() set(test_gdb_SRCS unittests/test_gdb.cpp ${kdevgdb_SRCS}) ecm_add_test(${test_gdb_SRCS} @@ -115,9 +94,6 @@ KF5::Parts kdevdebuggercommon ) -if(KF5SysGuard_FOUND) - target_link_libraries(test_gdb KF5::ProcessUi) -endif() if (HAVE_PATH_WITH_SPACES_TEST) set_target_properties(test_gdb PROPERTIES COMPILE_FLAGS "-DHAVE_PATH_WITH_SPACES_TEST") diff --git a/debuggers/gdb/debuggerplugin.h b/debuggers/gdb/debuggerplugin.h --- a/debuggers/gdb/debuggerplugin.h +++ b/debuggers/gdb/debuggerplugin.h @@ -1,24 +1,23 @@ /* * GDB Debugger Support + * Copyright 2016 Aetf * - * Copyright 1999-2001 John Birch - * Copyright 2001 by Bernd Gehrmann - * Copyright 2007 Hamish Rodda - * - * 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 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. * * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * */ #ifndef _DEBUGGERPART_H_ @@ -35,6 +34,9 @@ #include #include +#include "midebuggerplugin.h" +#include "debugsession.h" + class QLabel; class QMenu; class QDBusInterface; @@ -53,97 +55,29 @@ namespace GDB { class DisassembleWidget; -class Breakpoint; class GDBOutputWidget; class MemoryViewerWidget; -class DebugSession; -template class DebuggerToolFactory; -class CppDebuggerPlugin : public KDevelop::IPlugin, public KDevelop::IStatus +class CppDebuggerPlugin : public MIDebuggerPlugin { Q_OBJECT - Q_INTERFACES(KDevelop::IStatus) public: friend class DebugSession; - CppDebuggerPlugin( QObject *parent, const QVariantList & = QVariantList() ); + CppDebuggerPlugin(QObject *parent, const QVariantList & = QVariantList()); ~CppDebuggerPlugin() override; + DebugSession *createSession() const override; void unload() override; - - KDevelop::ContextMenuExtension contextMenuExtension( KDevelop::Context* ) override; - - DebugSession *createSession(); - -public: - //BEGIN IStatus - QString statusName() const override; - -Q_SIGNALS: - void clearMessage(KDevelop::IStatus*) override; - void showMessage(KDevelop::IStatus*, const QString & message, int timeout = 0) override; - void hideProgress(KDevelop::IStatus*) override; - void showProgress(KDevelop::IStatus*, int minimum, int maximum, int value) override; - void showErrorMessage(const QString&, int) override; - //END IStatus - - void addWatchVariable(const QString& variable); - void evaluateExpression(const QString& variable); - - void raiseGdbConsoleViews(); - - void reset(); - -private Q_SLOTS: - void setupDBus(); - void slotDebugExternalProcess(QObject* interface); - void contextEvaluate(); - void contextWatch(); - - void slotExamineCore(); - #ifdef KDEV_ENABLE_GDB_ATTACH_DIALOG - void slotAttachProcess(); - #endif - - void slotDBusServiceRegistered(const QString& service); - void slotDBusServiceUnregistered(const QString& service); - - void slotCloseDrKonqi(); - - void slotFinished(); - - void controllerMessage(const QString&, int); - -Q_SIGNALS: - //TODO: port to launch framework - //void startDebugger(const KDevelop::IRun & run, KJob* job); - void stopDebugger(); - void attachTo(int pid); - void coreFile(const QString& core); - void runUntil(const QUrl &url, int line); - void jumpTo(const QUrl &url, int line); - -protected: - void initializeGuiState() override; private: - KConfigGroup config() const; + void setupToolviews(); - void attachProcess(int pid); - void setupActions(); - - QHash m_drkonqis; - QSignalMapper* m_drkonqiMap; - QString m_drkonqi; - - QString m_contextIdent; - - KConfigGroup m_config; - - DebuggerToolFactory< DisassembleWidget >* disassemblefactory; - DebuggerToolFactory< GDBOutputWidget >* gdbfactory; - DebuggerToolFactory< MemoryViewerWidget >* memoryviewerfactory; +private: + DebuggerToolFactory* disassemblefactory; + DebuggerToolFactory* gdbfactory; + DebuggerToolFactory* memoryviewerfactory; }; } // end of namespace GDB diff --git a/debuggers/gdb/debuggerplugin.cpp b/debuggers/gdb/debuggerplugin.cpp --- a/debuggers/gdb/debuggerplugin.cpp +++ b/debuggers/gdb/debuggerplugin.cpp @@ -24,127 +24,37 @@ #include "debuggerplugin.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "disassemblewidget.h" -#ifdef KDEV_ENABLE_GDB_ATTACH_DIALOG -#include "processselection.h" -#endif #include "memviewdlg.h" #include "gdboutputwidget.h" -#include "dbgglobal.h" -#include "debugsession.h" -#include "selectcoredialog.h" -#include #include "gdbconfigpage.h" -#include "debugjob.h" - - -namespace KDevMI { namespace GDB { - -template -class DebuggerToolFactory : public KDevelop::IToolViewFactory -{ -public: - DebuggerToolFactory(CppDebuggerPlugin* plugin, const QString &id, Qt::DockWidgetArea defaultArea) - : m_plugin(plugin), m_id(id), m_defaultArea(defaultArea) - {} - - QWidget* create(QWidget *parent = 0) override - { - return new T(m_plugin, parent); - } - - QString id() const override - { - return m_id; - } - - Qt::DockWidgetArea defaultPosition() override - { - return m_defaultArea; - } - - void viewCreated(Sublime::View* view) override - { - if (view->widget()->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("requestRaise()")) != -1) - QObject::connect(view->widget(), SIGNAL(requestRaise()), view, SLOT(requestRaise())); - } - - /* At present, some debugger widgets (e.g. breakpoint) contain actions so that shortcuts - work, but they don't need any toolbar. So, suppress toolbar action. */ - QList toolBarActions( QWidget* viewWidget ) const override - { - Q_UNUSED(viewWidget); - return QList(); - } +#include "debugsession.h" -private: - CppDebuggerPlugin* m_plugin; - QString m_id; - Qt::DockWidgetArea m_defaultArea; -}; +#include +#include +#include +#include +#include +#include -} // end of namespace GDB -} // end of namespace KDevMI +#include using namespace KDevMI::GDB; + K_PLUGIN_FACTORY_WITH_JSON(CppDebuggerFactory, "kdevgdb.json", registerPlugin(); ) -CppDebuggerPlugin::CppDebuggerPlugin( QObject *parent, const QVariantList & ) : - KDevelop::IPlugin( "kdevgdb", parent ), - m_config(KSharedConfig::openConfig(), "GDB Debugger") +CppDebuggerPlugin::CppDebuggerPlugin(QObject *parent, const QVariantList &) + : MIDebuggerPlugin("kdevgdb", parent) { - KDEV_USE_EXTENSION_INTERFACE( KDevelop::IStatus ) - - core()->debugController()->initializeUi(); - setXMLFile("kdevgdbui.rc"); - disassemblefactory = new DebuggerToolFactory( + disassemblefactory = new DebuggerToolFactory( this, "org.kdevelop.debugger.DisassemblerView", Qt::BottomDockWidgetArea); - gdbfactory = new DebuggerToolFactory( + gdbfactory = new DebuggerToolFactory( this, "org.kdevelop.debugger.ConsoleView",Qt::BottomDockWidgetArea); core()->uiController()->addToolView( @@ -158,17 +68,13 @@ #ifndef WITH_OKTETA memoryviewerfactory = nullptr; #else - memoryviewerfactory = new DebuggerToolFactory( + memoryviewerfactory = new DebuggerToolFactory( this, "org.kdevelop.debugger.MemoryView", Qt::BottomDockWidgetArea); core()->uiController()->addToolView( i18n("Memory"), memoryviewerfactory); #endif - setupActions(); - - setupDBus(); - QList plugins = KDevelop::ICore::self()->pluginController()->allPluginsForExtension("org.kdevelop.IExecutePlugin"); foreach(IPlugin* plugin, plugins) { IExecutePlugin* iface = plugin->extension(); @@ -186,230 +92,19 @@ core()->uiController()->removeToolView(memoryviewerfactory); } -void CppDebuggerPlugin::setupActions() -{ - KActionCollection* ac = actionCollection(); - - QAction * action = new QAction(QIcon::fromTheme("core"), i18n("Examine Core File..."), this); - action->setToolTip( i18n("Examine core file") ); - action->setWhatsThis( i18n("Examine core file

" - "This loads a core file, which is typically created " - "after the application has crashed, e.g. with a " - "segmentation fault. The core file contains an " - "image of the program memory at the time it crashed, " - "allowing you to do a post-mortem analysis.

") ); - connect(action, &QAction::triggered, this, &CppDebuggerPlugin::slotExamineCore); - ac->addAction("debug_core", action); - - #ifdef KDEV_ENABLE_GDB_ATTACH_DIALOG - action = new QAction(QIcon::fromTheme("connect_creating"), i18n("Attach to Process"), this); - action->setToolTip( i18n("Attach to process...") ); - action->setWhatsThis(i18n("Attach to process

Attaches the debugger to a running process.

")); - connect(action, SIGNAL(triggered(bool)), this, SLOT(slotAttachProcess())); - ac->addAction("debug_attach", action); - #endif -} - -void CppDebuggerPlugin::setupDBus() -{ - m_drkonqiMap = new QSignalMapper(this); - connect(m_drkonqiMap, static_cast(&QSignalMapper::mapped), this, &CppDebuggerPlugin::slotDebugExternalProcess); - - QDBusConnectionInterface* dbusInterface = QDBusConnection::sessionBus().interface(); - foreach (const QString& service, dbusInterface->registeredServiceNames().value()) - slotDBusServiceRegistered(service); - - QDBusServiceWatcher* watcher = new QDBusServiceWatcher(this); - connect(watcher, &QDBusServiceWatcher::serviceRegistered, - this, &CppDebuggerPlugin::slotDBusServiceRegistered); - connect(watcher, &QDBusServiceWatcher::serviceUnregistered, - this, &CppDebuggerPlugin::slotDBusServiceUnregistered); -} - -void CppDebuggerPlugin::slotDBusServiceRegistered( const QString& service ) -{ - if (service.startsWith("org.kde.drkonqi")) { - // New registration - QDBusInterface* drkonqiInterface = new QDBusInterface(service, "/krashinfo", QString(), QDBusConnection::sessionBus(), this); - m_drkonqis.insert(service, drkonqiInterface); - - connect(drkonqiInterface, SIGNAL(acceptDebuggingApplication()), m_drkonqiMap, SLOT(map())); - m_drkonqiMap->setMapping(drkonqiInterface, drkonqiInterface); - - drkonqiInterface->call("registerDebuggingApplication", i18n("KDevelop")); - } -} - -void CppDebuggerPlugin::slotDBusServiceUnregistered( const QString& service ) -{ - if (service.startsWith("org.kde.drkonqi")) { - // Deregistration - if (m_drkonqis.contains(service)) - delete m_drkonqis.take(service); - } -} - -void CppDebuggerPlugin::slotDebugExternalProcess(QObject* interface) -{ - QDBusReply reply = static_cast(interface)->call("pid"); - - if (reply.isValid()) { - attachProcess(reply.value()); - QTimer::singleShot(500, this, SLOT(slotCloseDrKonqi())); - - m_drkonqi = m_drkonqis.key(static_cast(interface)); - } - - KDevelop::ICore::self()->uiController()->activeMainWindow()->raise(); -} - -void CppDebuggerPlugin::slotCloseDrKonqi() -{ - if (!m_drkonqi.isEmpty()) { - QDBusInterface drkonqiInterface(m_drkonqi, "/MainApplication", "org.kde.KApplication"); - drkonqiInterface.call("quit"); - m_drkonqi.clear(); - } -} - CppDebuggerPlugin::~CppDebuggerPlugin() { } - -void CppDebuggerPlugin::initializeGuiState() -{ -} - -KDevelop::ContextMenuExtension CppDebuggerPlugin::contextMenuExtension( KDevelop::Context* context ) -{ - KDevelop::ContextMenuExtension menuExt = KDevelop::IPlugin::contextMenuExtension( context ); - - if( context->type() != KDevelop::Context::EditorContext ) - return menuExt; - - KDevelop::EditorContext *econtext = dynamic_cast(context); - if (!econtext) - return menuExt; - - m_contextIdent = econtext->currentWord(); - - if (!m_contextIdent.isEmpty()) - { - // PORTING TODO - //QString squeezed = KStringHandler::csqueeze(m_contextIdent, 30); - QAction* action = new QAction( i18n("Evaluate: %1", m_contextIdent), this); - connect(action, &QAction::triggered, this, &CppDebuggerPlugin::contextEvaluate); - action->setWhatsThis(i18n("Evaluate expression

Shows the value of the expression under the cursor.

")); - menuExt.addAction( KDevelop::ContextMenuExtension::DebugGroup, action); - - action = new QAction( i18n("Watch: %1", m_contextIdent), this); - connect(action, &QAction::triggered, this, &CppDebuggerPlugin::contextWatch); - action->setWhatsThis(i18n("Watch expression

Adds an expression under the cursor to the Variables/Watch list.

")); - menuExt.addAction( KDevelop::ContextMenuExtension::DebugGroup, action); - } - - return menuExt; -} - -void CppDebuggerPlugin::contextWatch() -{ - emit addWatchVariable(m_contextIdent); -} - -void CppDebuggerPlugin::contextEvaluate() -{ - emit evaluateExpression(m_contextIdent); -} - -DebugSession* CppDebuggerPlugin::createSession() +DebugSession* CppDebuggerPlugin::createSession() const { DebugSession *session = new DebugSession(); KDevelop::ICore::self()->debugController()->addSession(session); - connect(session, &DebugSession::showMessage, this, &CppDebuggerPlugin::controllerMessage); + connect(session, &DebugSession::showMessage, this, &CppDebuggerPlugin::showStatusMessage); connect(session, &DebugSession::reset, this, &CppDebuggerPlugin::reset); - connect(session, &DebugSession::finished, this, &CppDebuggerPlugin::slotFinished); connect(session, &DebugSession::raiseDebuggerConsoleViews, - this, &CppDebuggerPlugin::raiseGdbConsoleViews); + this, &CppDebuggerPlugin::raiseDebuggerConsoleViews); return session; } -void CppDebuggerPlugin::slotExamineCore() -{ - emit showMessage(this, i18n("Choose a core file to examine..."), 1000); - - SelectCoreDialog dlg(KDevelop::ICore::self()->uiController()->activeMainWindow()); - if (dlg.exec() == QDialog::Rejected) { - return; - } - - emit showMessage(this, i18n("Examining core file %1", dlg.core().toLocalFile()), 1000); - - DebugSession* session = createSession(); - session->examineCoreFile(dlg.binary(), dlg.core()); - - KillSessionJob *job = new KillSessionJob(session); - job->setObjectName(i18n("Debug core file")); - core()->runController()->registerJob(job); - job->start(); -} - -#ifdef KDEV_ENABLE_GDB_ATTACH_DIALOG -void CppDebuggerPlugin::slotAttachProcess() -{ - emit showMessage(this, i18n("Choose a process to attach to..."), 1000); - - ProcessSelectionDialog dlg; - if (!dlg.exec() || !dlg.pidSelected()) - return; - - int pid = dlg.pidSelected(); - if(QApplication::applicationPid()==pid) - KMessageBox::error(KDevelop::ICore::self()->uiController()->activeMainWindow(), - i18n("Not attaching to process %1: cannot attach the debugger to itself.", pid)); - else - attachProcess(pid); -} -#endif - -void CppDebuggerPlugin::attachProcess(int pid) -{ - emit showMessage(this, i18n("Attaching to process %1", pid), 1000); - - DebugSession* session = createSession(); - session->attachToProcess(pid); - - KillSessionJob *job = new KillSessionJob(session); - job->setObjectName(i18n("Debug process %1", pid)); - core()->runController()->registerJob(job); - job->start(); -} - -// Used to disable breakpoint actions when non-text document selected - -// save/restore partial project session - -KConfigGroup CppDebuggerPlugin::config() const -{ - return m_config; -} - -QString CppDebuggerPlugin::statusName() const -{ - return i18n("Debugger"); -} - -void CppDebuggerPlugin::slotFinished() -{ - /* TODO: is this required? - Q_ASSERT(dynamic_cast(sender())); - DebugSession* session = static_cast(sender()); - */ -} - -void CppDebuggerPlugin::controllerMessage( const QString& msg, int timeout ) -{ - emit showMessage(this, msg, timeout); -} - #include "debuggerplugin.moc" diff --git a/debuggers/gdb/debugjob.cpp b/debuggers/gdb/debugjob.cpp deleted file mode 100644 --- a/debuggers/gdb/debugjob.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* -* GDB Debugger Support -* -* Copyright 2006 Vladimir Prus -* Copyright 2007 Hamish Rodda -* Copyright 2009 Andreas Pakulat -* -* 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 "debugjob.h" -#include "debuggerplugin.h" -#include "debuglog.h" -#include "debugsession.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -using namespace KDevMI::GDB; -using namespace KDevelop; - -DebugJob::DebugJob(CppDebuggerPlugin* p, KDevelop::ILaunchConfiguration* launchcfg, IExecutePlugin* execute, QObject* parent) - : KDevelop::OutputJob(parent) - , m_launchcfg( launchcfg ) - , m_execute( execute ) -{ - setCapabilities(Killable); - - m_session = p->createSession(); - connect(m_session, &DebugSession::inferiorStdoutLines, this, &DebugJob::stderrReceived); - connect(m_session, &DebugSession::inferiorStderrLines, this, &DebugJob::stdoutReceived); - connect(m_session, &DebugSession::finished, this, &DebugJob::done ); - - if (launchcfg->project()) { - setObjectName(i18nc("ProjectName: run configuration name", "%1: %2", launchcfg->project()->name(), launchcfg->name())); - } else { - setObjectName(launchcfg->name()); - } -} - -void DebugJob::start() -{ - KConfigGroup grp = m_launchcfg->config(); - KDevelop::EnvironmentGroupList l(KSharedConfig::openConfig()); - Q_ASSERT(m_execute); - QString err; - QString executable = m_execute->executable( m_launchcfg, err ).toLocalFile(); - - if( !err.isEmpty() ) - { - setError( -1 ); - setErrorText( err ); - emitResult(); - return; - } - - if(!QFileInfo(executable).isExecutable()){ - setError( -1 ); - setErrorText(QString("'%1' is not an executable").arg(executable)); - emitResult(); - return; - } - - QStringList arguments = m_execute->arguments( m_launchcfg, err ); - if( !err.isEmpty() ) - { - setError( -1 ); - setErrorText( err ); - } - if( error() != 0 ) - { - emitResult(); - return; - } - - setStandardToolView(KDevelop::IOutputView::DebugView); - setBehaviours(KDevelop::IOutputView::Behaviours(KDevelop::IOutputView::AllowUserClose) | KDevelop::IOutputView::AutoScroll); - auto model = new KDevelop::OutputModel; - model->setFilteringStrategy(OutputModel::NativeAppErrorFilter); - setModel(model); - setTitle(m_launchcfg->name()); - - QString startWith = grp.readEntry(startWithEntry, QString("ApplicationOutput")); - if (startWith == "GdbConsole") { - setVerbosity(Silent); - } else if (startWith == "FrameStack") { - setVerbosity(Silent); - } else { - setVerbosity(Verbose); - } - - startOutput(); - - if (!m_session->startDebugging(m_launchcfg, m_execute)) { - done(); - } -} - -bool DebugJob::doKill() -{ - qCDebug(DEBUGGERGDB); - m_session->stopDebugger(); - return true; -} - -void DebugJob::stderrReceived(const QStringList& l ) -{ - if (KDevelop::OutputModel* m = model()) { - m->appendLines( l ); - } -} - -void DebugJob::stdoutReceived(const QStringList& l ) -{ - if (KDevelop::OutputModel* m = model()) { - m->appendLines( l ); - } -} - -KDevelop::OutputModel* DebugJob::model() -{ - return dynamic_cast( KDevelop::OutputJob::model() ); -} - - -void DebugJob::done() -{ - emitResult(); -} - - -KillSessionJob::KillSessionJob(DebugSession *session, QObject* parent): KJob(parent), m_session(session) -{ - connect(m_session, &DebugSession::finished, this, &KillSessionJob::sessionFinished); - setCapabilities(Killable); -} - -void KillSessionJob::start() -{ - //NOOP -} - -bool KillSessionJob::doKill() -{ - m_session->stopDebugger(); - return true; -} - -void KillSessionJob::sessionFinished() -{ - emitResult(); -} diff --git a/debuggers/gdb/gdb.h b/debuggers/gdb/gdb.h --- a/debuggers/gdb/gdb.h +++ b/debuggers/gdb/gdb.h @@ -34,7 +34,7 @@ explicit GdbDebugger(QObject* parent = 0); ~GdbDebugger() override; - void start(KConfigGroup& config, const QStringList& extraArguments = {}) override; + bool start(KConfigGroup& config, const QStringList& extraArguments = {}) override; }; diff --git a/debuggers/gdb/gdb.cpp b/debuggers/gdb/gdb.cpp --- a/debuggers/gdb/gdb.cpp +++ b/debuggers/gdb/gdb.cpp @@ -48,7 +48,7 @@ { } -void GdbDebugger::start(KConfigGroup& config, const QStringList& extraArguments) +bool GdbDebugger::start(KConfigGroup& config, const QStringList& extraArguments) { // FIXME: verify that default value leads to something sensible QUrl gdbUrl = config.readEntry(gdbPathEntry, QUrl()); @@ -78,8 +78,7 @@ qApp->activeWindow(), i18n("Could not locate the debugging shell '%1'.", shell_without_args ), i18n("Debugging Shell Not Found") ); - // FIXME: throw, or set some error message. - return; + return false; } arguments.insert(0, debuggerBinary_); @@ -96,4 +95,5 @@ qCDebug(DEBUGGERGDB) << "GDB process pid:" << process_->pid(); emit userCommandOutput(shell.toLocalFile() + ' ' + debuggerBinary_ + ' ' + arguments.join(' ') + '\n'); + return true; } diff --git a/debuggers/gdb/gdbconfigpage.cpp b/debuggers/gdb/gdbconfigpage.cpp --- a/debuggers/gdb/gdbconfigpage.cpp +++ b/debuggers/gdb/gdbconfigpage.cpp @@ -46,11 +46,11 @@ #include "debugsession.h" #include "debuggerplugin.h" +#include "midebugjobs.h" #include "ui_gdbconfigpage.h" #include #include -#include "debugjob.h" using namespace KDevelop; @@ -165,7 +165,7 @@ { l << depjob; } - l << new KDevMI::GDB::DebugJob( m_plugin, cfg, m_execute ); + l << new KDevMI::MIDebugJob( m_plugin, cfg, m_execute ); return new KDevelop::ExecuteCompositeJob( KDevelop::ICore::self()->runController(), l ); } qWarning() << "Unknown launch mode" << launchMode << "for config:" << cfg->name(); diff --git a/debuggers/gdb/gdboutputwidget.cpp b/debuggers/gdb/gdboutputwidget.cpp --- a/debuggers/gdb/gdboutputwidget.cpp +++ b/debuggers/gdb/gdboutputwidget.cpp @@ -105,7 +105,7 @@ this, &GDBOutputWidget::currentSessionChanged); connect(plugin, &CppDebuggerPlugin::reset, this, &GDBOutputWidget::clear); - connect(plugin, &CppDebuggerPlugin::raiseGdbConsoleViews, this, &GDBOutputWidget::requestRaise); + connect(plugin, &CppDebuggerPlugin::raiseDebuggerConsoleViews, this, &GDBOutputWidget::requestRaise); currentSessionChanged(KDevelop::ICore::self()->debugController()->currentSession());