Debugger: Add "LLDB Dap" preset

lldb has a dap interface since a while now. The "GDB Dap" preset is not
compatible, since gdb uses the same executable and lldb has a "lldb-dap"
(previously "lldb-vscode") executable.

Change-Id: I4105223659de093f0ee44129527c4830d21a3090
Reviewed-by: Artem Sokolovskii <artem.sokolovskii@qt.io>
This commit is contained in:
Cristian Adam
2024-06-13 16:19:45 +02:00
parent 45f262f92c
commit dcaa55200b
8 changed files with 210 additions and 0 deletions

View File

@@ -33,6 +33,7 @@ add_qtc_plugin(Debugger
dap/dapclient.cpp dap/dapclient.h
dap/dapengine.cpp dap/dapengine.h
dap/gdbdapengine.cpp dap/gdbdapengine.h
dap/lldbdapengine.cpp dap/lldbdapengine.h
dap/pydapengine.cpp dap/pydapengine.h
debugger.qrc
debugger_global.h

View File

@@ -6,6 +6,7 @@
#include "cmakedapengine.h"
#include "dapclient.h"
#include "gdbdapengine.h"
#include "lldbdapengine.h"
#include "pydapengine.h"
#include <debugger/breakhandler.h>
@@ -1058,6 +1059,8 @@ DebuggerEngine *createDapEngine(Utils::Id runMode)
return new CMakeDapEngine;
if (runMode == ProjectExplorer::Constants::DAP_GDB_DEBUG_RUN_MODE)
return new GdbDapEngine;
if (runMode == ProjectExplorer::Constants::DAP_LLDB_DEBUG_RUN_MODE)
return new LldbDapEngine;
if (runMode == ProjectExplorer::Constants::DAP_PY_DEBUG_RUN_MODE)
return new PyDapEngine;

View File

@@ -0,0 +1,176 @@
// Copyright (C) 2024 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 "lldbdapengine.h"
#include "dapclient.h"
#include <coreplugin/messagemanager.h>
#include <debugger/debuggermainwindow.h>
#include <utils/mimeconstants.h>
#include <utils/mimeutils.h>
#include <utils/temporarydirectory.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/projecttree.h>
#include <QDebug>
#include <QLocalSocket>
#include <QVersionNumber>
using namespace Core;
using namespace Utils;
namespace Debugger::Internal {
// TODO: Same class as in gdbdapengine.cpp. Refactor into one place.
class ProcessDataProvider : public IDataProvider
{
public:
ProcessDataProvider(const DebuggerRunParameters &rp,
const CommandLine &cmd,
QObject *parent = nullptr)
: IDataProvider(parent)
, 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);
if (m_runParameters.debugger.workingDirectory.isDir())
m_proc.setWorkingDirectory(m_runParameters.debugger.workingDirectory);
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
{
if (m_proc.state() == QProcess::Running)
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 LldbDapClient : public DapClient
{
public:
LldbDapClient(IDataProvider *provider, QObject *parent = nullptr)
: DapClient(provider, parent)
{}
private:
const QLoggingCategory &logCategory() override
{
static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.lldb",
QtWarningMsg);
return logCategory;
}
};
LldbDapEngine::LldbDapEngine()
: DapEngine()
{
setObjectName("LldbDapEngine");
setDebuggerName("LLDB");
setDebuggerType("DAP");
}
void LldbDapEngine::handleDapInitialize()
{
if (!isLocalAttachEngine()) {
DapEngine::handleDapInitialize();
return;
}
QTC_ASSERT(state() == EngineRunRequested, qCDebug(logCategory()) << state());
m_dapClient->postRequest("attach", QJsonObject{{"__restart", ""}});
qCDebug(logCategory()) << "handleDapAttach";
}
bool LldbDapEngine::isLocalAttachEngine() const
{
return runParameters().startMode == AttachToLocalProcess;
}
void LldbDapEngine::handleDapConfigurationDone()
{
if (!isLocalAttachEngine()) {
DapEngine::handleDapConfigurationDone();
return;
}
notifyEngineRunAndInferiorStopOk();
}
void LldbDapEngine::setupEngine()
{
QTC_ASSERT(state() == EngineSetupRequested, qCDebug(logCategory()) << state());
const DebuggerRunParameters &rp = runParameters();
CommandLine cmd{rp.debugger.command.executable()};
if (isLocalAttachEngine())
cmd.addArgs({"--debugger-pid", QString::number(rp.attachPID.pid())});
IDataProvider *dataProvider = new ProcessDataProvider(rp, cmd, this);
m_dapClient = new LldbDapClient(dataProvider, this);
connectDataGeneratorSignals();
m_dapClient->dataProvider()->start();
}
bool LldbDapEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
const auto mimeType = Utils::mimeTypeForFile(bp.fileName);
return mimeType.matchesName(Utils::Constants::C_HEADER_MIMETYPE)
|| mimeType.matchesName(Utils::Constants::C_SOURCE_MIMETYPE)
|| mimeType.matchesName(Utils::Constants::CPP_HEADER_MIMETYPE)
|| mimeType.matchesName(Utils::Constants::CPP_SOURCE_MIMETYPE)
|| bp.type == BreakpointByFunction;
}
const QLoggingCategory &LldbDapEngine::logCategory()
{
static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.lldb",
QtWarningMsg);
return logCategory;
}
} // namespace Debugger::Internal

View File

@@ -0,0 +1,26 @@
// Copyright (C) 2024 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 LldbDapEngine : public DapEngine
{
public:
LldbDapEngine();
private:
void setupEngine() override;
void handleDapInitialize() override;
void handleDapConfigurationDone() override;
bool isLocalAttachEngine() const;
bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
const QLoggingCategory &logCategory() override;
};
} // Debugger::Internal

View File

@@ -123,6 +123,7 @@ QtcPlugin {
"dapclient.cpp", "dapclient.h",
"dapengine.cpp", "dapengine.h",
"gdbdapengine.cpp", "gdbdapengine.h",
"lldbdapengine.cpp", "lldbdapengine.h",
"pydapengine.cpp", "pydapengine.h",
]
}

View File

@@ -1224,6 +1224,7 @@ void DebuggerPluginPrivate::createDapDebuggerPerspective(QWidget *globalLogWindo
ProjectExplorer::Constants::DAP_CMAKE_DEBUG_RUN_MODE,
/*forceSkipDeploy=*/true},
DapPerspective{Tr::tr("GDB Preset"), ProjectExplorer::Constants::DAP_GDB_DEBUG_RUN_MODE},
DapPerspective{Tr::tr("LLDB Preset"), ProjectExplorer::Constants::DAP_LLDB_DEBUG_RUN_MODE},
DapPerspective{Tr::tr("Python Preset"), ProjectExplorer::Constants::DAP_PY_DEBUG_RUN_MODE},
};

View File

@@ -1096,6 +1096,7 @@ DebuggerRunWorkerFactory::DebuggerRunWorkerFactory()
addSupportedRunMode(ProjectExplorer::Constants::DEBUG_RUN_MODE);
addSupportedRunMode(ProjectExplorer::Constants::DAP_CMAKE_DEBUG_RUN_MODE);
addSupportedRunMode(ProjectExplorer::Constants::DAP_GDB_DEBUG_RUN_MODE);
addSupportedRunMode(ProjectExplorer::Constants::DAP_LLDB_DEBUG_RUN_MODE);
addSupportedDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
addSupportedDeviceType("DockerDeviceType");

View File

@@ -171,6 +171,7 @@ const char NORMAL_RUN_MODE[]="RunConfiguration.NormalRunMode";
const char DEBUG_RUN_MODE[]="RunConfiguration.DebugRunMode";
const char DAP_CMAKE_DEBUG_RUN_MODE[]="RunConfiguration.CmakeDebugRunMode";
const char DAP_GDB_DEBUG_RUN_MODE[]="RunConfiguration.DapGdbDebugRunMode";
const char DAP_LLDB_DEBUG_RUN_MODE[]="RunConfiguration.DapLldbDebugRunMode";
const char DAP_PY_DEBUG_RUN_MODE[]="RunConfiguration.DapPyDebugRunMode";
const char QML_PROFILER_RUN_MODE[]="RunConfiguration.QmlProfilerRunMode";
const char QML_PROFILER_RUNNER[]="RunConfiguration.QmlProfilerRunner";