diff --git a/src/plugins/debugger/CMakeLists.txt b/src/plugins/debugger/CMakeLists.txt index 4280af0235c..08998caf3e2 100644 --- a/src/plugins/debugger/CMakeLists.txt +++ b/src/plugins/debugger/CMakeLists.txt @@ -27,7 +27,9 @@ add_qtc_plugin(Debugger console/consoleitemmodel.cpp console/consoleitemmodel.h console/consoleproxymodel.cpp console/consoleproxymodel.h console/consoleview.cpp console/consoleview.h + dap/cmakedapengine.cpp dap/cmakedapengine.h dap/dapengine.cpp dap/dapengine.h + dap/gdbdapengine.cpp dap/gdbdapengine.h debugger.qrc debugger_global.h debuggeractions.cpp debuggeractions.h diff --git a/src/plugins/debugger/dap/cmakedapengine.cpp b/src/plugins/debugger/dap/cmakedapengine.cpp new file mode 100644 index 00000000000..d43646f408a --- /dev/null +++ b/src/plugins/debugger/dap/cmakedapengine.cpp @@ -0,0 +1,118 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "cmakedapengine.h" + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +using namespace Core; +using namespace Utils; +static Q_LOGGING_CATEGORY(dapEngineLog, "qtc.dbg.dapengine", QtWarningMsg) + +namespace Debugger::Internal { + +class LocalSocketDataProvider : public IDataProvider +{ +public: + LocalSocketDataProvider(const QString &socketName) + : m_socketName(socketName) + { + connect(&m_socket, &QLocalSocket::connected, this, &IDataProvider::started); + connect(&m_socket, &QLocalSocket::disconnected, this, &IDataProvider::done); + connect(&m_socket, &QLocalSocket::readyRead, this, &IDataProvider::readyReadStandardOutput); + connect(&m_socket, + &QLocalSocket::errorOccurred, + this, + &IDataProvider::readyReadStandardError); + } + + ~LocalSocketDataProvider() { m_socket.disconnectFromServer(); } + + void start() override { m_socket.connectToServer(m_socketName, QIODevice::ReadWrite); } + + bool isRunning() const override { return m_socket.isOpen(); } + void writeRaw(const QByteArray &data) override { m_socket.write(data); } + void kill() override + { + if (m_socket.isOpen()) + m_socket.disconnectFromServer(); + else { + m_socket.abort(); + emit done(); + } + } + QByteArray readAllStandardOutput() override { return m_socket.readAll(); } + QString readAllStandardError() override { return QString(); } + int exitCode() const override { return 0; } + QString executable() const override { return m_socket.serverName(); } + + QProcess::ExitStatus exitStatus() const override { return QProcess::NormalExit; } + QProcess::ProcessError error() const override { return QProcess::UnknownError; } + Utils::ProcessResult result() const override { return ProcessResult::FinishedWithSuccess; } + QString exitMessage() const override { return QString(); }; + +private: + QLocalSocket m_socket; + const QString m_socketName; +}; + +CMakeDapEngine::CMakeDapEngine() + : DapEngine() +{ + setObjectName("CmakeDapEngine"); + setDebuggerName("CmakeDAP"); +} + +void CMakeDapEngine::handleDapStarted() +{ + QTC_ASSERT(state() == EngineRunRequested, qCDebug(dapEngineLog) << state()); + + postDirectCommand({ + {"command", "initialize"}, + {"type", "request"}, + {"arguments", QJsonObject { + {"clientID", "QtCreator"}, // The ID of the client using this adapter. + {"clientName", "QtCreator"}, // The human-readable name of the client using this adapter. + {"adapterID", "cmake"}, + {"pathFormat", "path"} + }} + }); + + qCDebug(dapEngineLog) << "handleDapStarted"; +} + +void CMakeDapEngine::setupEngine() +{ + QTC_ASSERT(state() == EngineSetupRequested, qCDebug(dapEngineLog) << state()); + + qCDebug(dapEngineLog) << "build system name" + << ProjectExplorer::ProjectTree::currentBuildSystem()->name(); + + if (TemporaryDirectory::masterDirectoryFilePath().osType() == Utils::OsType::OsTypeWindows) { + m_dataGenerator = std::make_unique("\\\\.\\pipe\\cmake-dap"); + } else { + m_dataGenerator = std::make_unique( + TemporaryDirectory::masterDirectoryPath() + "/cmake-dap.sock"); + } + connectDataGeneratorSignals(); + + connect(ProjectExplorer::ProjectTree::currentBuildSystem(), + &ProjectExplorer::BuildSystem::debuggingStarted, + this, + [this] { m_dataGenerator->start(); }); + + ProjectExplorer::ProjectTree::currentBuildSystem()->requestDebugging(); + notifyEngineSetupOk(); +} + +} // namespace Debugger::Internal diff --git a/src/plugins/debugger/dap/cmakedapengine.h b/src/plugins/debugger/dap/cmakedapengine.h new file mode 100644 index 00000000000..59a536fee0c --- /dev/null +++ b/src/plugins/debugger/dap/cmakedapengine.h @@ -0,0 +1,20 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "dapengine.h" + +namespace Debugger::Internal { + +class CMakeDapEngine : public DapEngine +{ +public: + CMakeDapEngine(); + +private: + void handleDapStarted() override; + void setupEngine() override; +}; + +} // Debugger::Internal diff --git a/src/plugins/debugger/dap/dapengine.cpp b/src/plugins/debugger/dap/dapengine.cpp index 2535e8daf7b..db4ef9da69e 100644 --- a/src/plugins/debugger/dap/dapengine.cpp +++ b/src/plugins/debugger/dap/dapengine.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "dapengine.h" +#include "cmakedapengine.h" +#include "gdbdapengine.h" #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #include #include @@ -59,106 +62,8 @@ static Q_LOGGING_CATEGORY(dapEngineLog, "qtc.dbg.dapengine", QtWarningMsg) namespace Debugger::Internal { -class ProcessDataProvider : public IDataProvider -{ -public: - ProcessDataProvider(const DebuggerRunParameters &rp, const CommandLine &cmd) - : m_runParameters(rp) - , m_cmd(cmd) - { - connect(&m_proc, &Process::started, this, &IDataProvider::started); - connect(&m_proc, &Process::done, this, &IDataProvider::done); - connect(&m_proc, - &Process::readyReadStandardOutput, - this, - &IDataProvider::readyReadStandardOutput); - connect(&m_proc, - &Process::readyReadStandardError, - this, - &IDataProvider::readyReadStandardError); - } - - ~ProcessDataProvider() - { - m_proc.kill(); - m_proc.waitForFinished(); - } - - void start() override - { - m_proc.setProcessMode(ProcessMode::Writer); - m_proc.setEnvironment(m_runParameters.debugger.environment); - m_proc.setCommand(m_cmd); - m_proc.start(); - } - - bool isRunning() const override { return m_proc.isRunning(); } - void writeRaw(const QByteArray &data) override { m_proc.writeRaw(data); } - void kill() override { m_proc.kill(); } - QByteArray readAllStandardOutput() override { return m_proc.readAllStandardOutput().toUtf8(); } - QString readAllStandardError() override { return m_proc.readAllStandardError(); } - int exitCode() const override { return m_proc.exitCode(); } - QString executable() const override { return m_proc.commandLine().executable().toUserOutput(); } - - QProcess::ExitStatus exitStatus() const override { return m_proc.exitStatus(); } - QProcess::ProcessError error() const override { return m_proc.error(); } - Utils::ProcessResult result() const override { return m_proc.result(); } - QString exitMessage() const override { return m_proc.exitMessage(); }; - -private: - Utils::Process m_proc; - const DebuggerRunParameters m_runParameters; - const CommandLine m_cmd; -}; - -class LocalSocketDataProvider : public IDataProvider -{ -public: - LocalSocketDataProvider(const QString &socketName) - : m_socketName(socketName) - { - connect(&m_socket, &QLocalSocket::connected, this, &IDataProvider::started); - connect(&m_socket, &QLocalSocket::disconnected, this, &IDataProvider::done); - connect(&m_socket, &QLocalSocket::readyRead, this, &IDataProvider::readyReadStandardOutput); - connect(&m_socket, - &QLocalSocket::errorOccurred, - this, - &IDataProvider::readyReadStandardError); - } - - ~LocalSocketDataProvider() { m_socket.disconnectFromServer(); } - - void start() override { m_socket.connectToServer(m_socketName, QIODevice::ReadWrite); } - - bool isRunning() const override { return m_socket.isOpen(); } - void writeRaw(const QByteArray &data) override { m_socket.write(data); } - void kill() override { - if (m_socket.isOpen()) - m_socket.disconnectFromServer(); - else { - m_socket.abort(); - emit done(); - } - } - QByteArray readAllStandardOutput() override { return m_socket.readAll(); } - QString readAllStandardError() override { return QString(); } - int exitCode() const override { return 0; } - QString executable() const override { return m_socket.serverName(); } - - QProcess::ExitStatus exitStatus() const override { return QProcess::NormalExit; } - QProcess::ProcessError error() const override { return QProcess::UnknownError; } - Utils::ProcessResult result() const override { return ProcessResult::FinishedWithSuccess; } - QString exitMessage() const override { return QString(); }; - -private: - QLocalSocket m_socket; - const QString m_socketName; -}; - DapEngine::DapEngine() { - setObjectName("DapEngine"); - setDebuggerName("DAP"); m_rootWatchItem = new WatchItem(); m_currentWatchItem = m_rootWatchItem; } @@ -236,58 +141,6 @@ void DapEngine::shutdownEngine() m_dataGenerator->kill(); } -void DapEngine::setupEngine() -{ - QTC_ASSERT(state() == EngineSetupRequested, qCDebug(dapEngineLog) << state()); - - const auto connectDataGeneratorSignals = [this] { - if (!m_dataGenerator) - return; - - connect(m_dataGenerator.get(), &IDataProvider::started, this, &DapEngine::handleDapStarted); - connect(m_dataGenerator.get(), &IDataProvider::done, this, &DapEngine::handleDapDone); - connect(m_dataGenerator.get(), - &IDataProvider::readyReadStandardOutput, - this, - &DapEngine::readDapStandardOutput); - connect(m_dataGenerator.get(), - &IDataProvider::readyReadStandardError, - this, - &DapEngine::readDapStandardError); - }; - - Perspective *currentPerspective = DebuggerMainWindow::instance()->currentPerspective(); - if (currentPerspective->parentPerspectiveId() == Constants::CMAKE_PERSPECTIVE_ID) { - qCDebug(dapEngineLog) << "build system name" << ProjectExplorer::ProjectTree::currentBuildSystem()->name(); - - if (TemporaryDirectory::masterDirectoryFilePath().osType() == Utils::OsType::OsTypeWindows) { - m_dataGenerator = std::make_unique("\\\\.\\pipe\\cmake-dap"); - } else { - m_dataGenerator = std::make_unique( - TemporaryDirectory::masterDirectoryPath() + "/cmake-dap.sock"); - } - connectDataGeneratorSignals(); - - connect(ProjectExplorer::ProjectTree::currentBuildSystem(), - &ProjectExplorer::BuildSystem::debuggingStarted, - this, - [this] { - m_dataGenerator->start(); - }); - - ProjectExplorer::ProjectTree::currentBuildSystem()->requestDebugging(); - } else { - const DebuggerRunParameters &rp = runParameters(); - const CommandLine cmd{rp.debugger.command.executable(), {"-i", "dap"}}; - - m_dataGenerator = std::make_unique(rp, cmd); - connectDataGeneratorSignals(); - m_dataGenerator->start(); - - } - notifyEngineSetupOk(); -} - // From the docs: // The sequence of events/requests is as follows: // * adapters sends initialized event (after the initialize request has returned) @@ -310,9 +163,7 @@ void DapEngine::handleDapStarted() {"type", "request"}, {"arguments", QJsonObject { {"clientID", "QtCreator"}, // The ID of the client using this adapter. - {"clientName", "QtCreator"}, // The human-readable name of the client using this adapter. - {"adapterID", "cmake"}, - {"pathFormat", "path"} + {"clientName", "QtCreator"} // The human-readable name of the client using this adapter. }} }); @@ -1083,9 +934,29 @@ void DapEngine::claimInitialBreakpoints() qCDebug(dapEngineLog) << "claimInitialBreakpoints"; } -DebuggerEngine *createDapEngine() +void DapEngine::connectDataGeneratorSignals() { - return new DapEngine; + if (!m_dataGenerator) + return; + + connect(m_dataGenerator.get(), &IDataProvider::started, this, &DapEngine::handleDapStarted); + connect(m_dataGenerator.get(), &IDataProvider::done, this, &DapEngine::handleDapDone); + connect(m_dataGenerator.get(), + &IDataProvider::readyReadStandardOutput, + this, + &DapEngine::readDapStandardOutput); + connect(m_dataGenerator.get(), + &IDataProvider::readyReadStandardError, + this, + &DapEngine::readDapStandardError); +} + +DebuggerEngine *createDapEngine(Utils::Id runMode) +{ + if (runMode == ProjectExplorer::Constants::CMAKE_DEBUG_RUN_MODE) + return new CMakeDapEngine; + + return new GdbDapEngine; } } // Debugger::Internal diff --git a/src/plugins/debugger/dap/dapengine.h b/src/plugins/debugger/dap/dapengine.h index 5a0c34492f9..1950713f15d 100644 --- a/src/plugins/debugger/dap/dapengine.h +++ b/src/plugins/debugger/dap/dapengine.h @@ -50,12 +50,11 @@ class DapEngine : public DebuggerEngine public: DapEngine(); -private: +protected: void executeStepIn(bool) override; void executeStepOut() override; void executeStepOver(bool) override; - void setupEngine() override; void shutdownInferior() override; void shutdownEngine() override; @@ -106,7 +105,7 @@ private: void claimInitialBreakpoints(); - void handleDapStarted(); + virtual void handleDapStarted(); void handleDapLaunch(); void handleDapConfigurationDone(); @@ -122,6 +121,7 @@ private: void handleResponse(const QString &ba); void updateAll() override; void updateLocals() override; + void connectDataGeneratorSignals(); QByteArray m_inbuffer; std::unique_ptr m_dataGenerator = nullptr; diff --git a/src/plugins/debugger/dap/gdbdapengine.cpp b/src/plugins/debugger/dap/gdbdapengine.cpp new file mode 100644 index 00000000000..316a0c7d547 --- /dev/null +++ b/src/plugins/debugger/dap/gdbdapengine.cpp @@ -0,0 +1,97 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "gdbdapengine.h" + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +using namespace Core; +using namespace Utils; +static Q_LOGGING_CATEGORY(dapEngineLog, "qtc.dbg.dapengine", QtWarningMsg) + +namespace Debugger::Internal { + +class ProcessDataProvider : public IDataProvider +{ +public: + ProcessDataProvider(const DebuggerRunParameters &rp, const CommandLine &cmd) + : m_runParameters(rp) + , m_cmd(cmd) + { + connect(&m_proc, &Process::started, this, &IDataProvider::started); + connect(&m_proc, &Process::done, this, &IDataProvider::done); + connect(&m_proc, + &Process::readyReadStandardOutput, + this, + &IDataProvider::readyReadStandardOutput); + connect(&m_proc, + &Process::readyReadStandardError, + this, + &IDataProvider::readyReadStandardError); + } + + ~ProcessDataProvider() + { + m_proc.kill(); + m_proc.waitForFinished(); + } + + void start() override + { + m_proc.setProcessMode(ProcessMode::Writer); + m_proc.setEnvironment(m_runParameters.debugger.environment); + m_proc.setCommand(m_cmd); + m_proc.start(); + } + + bool isRunning() const override { return m_proc.isRunning(); } + void writeRaw(const QByteArray &data) override { m_proc.writeRaw(data); } + void kill() override { m_proc.kill(); } + QByteArray readAllStandardOutput() override { return m_proc.readAllStandardOutput().toUtf8(); } + QString readAllStandardError() override { return m_proc.readAllStandardError(); } + int exitCode() const override { return m_proc.exitCode(); } + QString executable() const override { return m_proc.commandLine().executable().toUserOutput(); } + + QProcess::ExitStatus exitStatus() const override { return m_proc.exitStatus(); } + QProcess::ProcessError error() const override { return m_proc.error(); } + Utils::ProcessResult result() const override { return m_proc.result(); } + QString exitMessage() const override { return m_proc.exitMessage(); }; + +private: + Utils::Process m_proc; + const DebuggerRunParameters m_runParameters; + const CommandLine m_cmd; +}; + +GdbDapEngine::GdbDapEngine() + : DapEngine() +{ + setObjectName("GdbDapEngine"); + setDebuggerName("GdbDAP"); +} + +void GdbDapEngine::setupEngine() +{ + QTC_ASSERT(state() == EngineSetupRequested, qCDebug(dapEngineLog) << state()); + + const DebuggerRunParameters &rp = runParameters(); + const CommandLine cmd{rp.debugger.command.executable(), {"-i", "dap"}}; + + m_dataGenerator = std::make_unique(rp, cmd); + connectDataGeneratorSignals(); + m_dataGenerator->start(); + + notifyEngineSetupOk(); +} + +} // namespace Debugger::Internal diff --git a/src/plugins/debugger/dap/gdbdapengine.h b/src/plugins/debugger/dap/gdbdapengine.h new file mode 100644 index 00000000000..a968ab4a5ac --- /dev/null +++ b/src/plugins/debugger/dap/gdbdapengine.h @@ -0,0 +1,19 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "dapengine.h" + +namespace Debugger::Internal { + +class GdbDapEngine : public DapEngine +{ +public: + GdbDapEngine(); + +private: + void setupEngine() override; +}; + +} // Debugger::Internal diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 0a04eb61bcc..84c8837757f 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -70,7 +70,7 @@ DebuggerEngine *createPdbEngine(); DebuggerEngine *createQmlEngine(); DebuggerEngine *createLldbEngine(); DebuggerEngine *createUvscEngine(); -DebuggerEngine *createDapEngine(); +DebuggerEngine *createDapEngine(Utils::Id runMode = ProjectExplorer::Constants::NO_RUN_MODE); static QString noEngineMessage() { @@ -483,7 +483,7 @@ void DebuggerRunTool::start() if (!m_engine) { if (runControl()->runMode() == ProjectExplorer::Constants::CMAKE_DEBUG_RUN_MODE) - m_engine = createDapEngine(); + m_engine = createDapEngine(runControl()->runMode()); else if (m_runParameters.isCppDebugging()) { switch (m_runParameters.cppEngineType) { case GdbEngineType: