DAP Protocol implementations.
More work for seperating debugger interface and the gdb mi client
This commit is contained in:
parent
9a66022b8a
commit
d302fcc10f
|
@ -130,6 +130,7 @@ SOURCES += \
|
|||
debugger/gdbmidebugger.cpp \
|
||||
debugger/gdbmiresultparser.cpp \
|
||||
debugger/dapprotocol.cpp \
|
||||
debugger/dapdebugger.cpp \
|
||||
cpprefacter.cpp \
|
||||
parser/cppparser.cpp \
|
||||
parser/cpppreprocessor.cpp \
|
||||
|
@ -261,6 +262,7 @@ HEADERS += \
|
|||
debugger/gdbmidebugger.h \
|
||||
debugger/gdbmiresultparser.h \
|
||||
debugger/dapprotocol.h \
|
||||
debugger/dapdebugger.h \
|
||||
cpprefacter.h \
|
||||
customfileiconprovider.h \
|
||||
parser/cppparser.h \
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
#include "dapdebugger.h"
|
||||
#include "../utils.h"
|
||||
#include "dapprotocol.h"
|
||||
#include "../systemconsts.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
DAPDebuggerClient::DAPDebuggerClient(Debugger *debugger, QObject *parent):
|
||||
DebuggerClient{debugger, parent}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DAPDebuggerClient::run()
|
||||
{
|
||||
mStop = false;
|
||||
bool errorOccured = false;
|
||||
mInferiorRunning = false;
|
||||
mProcessExited = false;
|
||||
QString cmd = debuggerPath();
|
||||
// QString arguments = "--annotate=2";
|
||||
QStringList arguments{"--interpret=mi", "--silent"};
|
||||
QString workingDir = QFileInfo(debuggerPath()).path();
|
||||
|
||||
mProcess = std::make_shared<QProcess>();
|
||||
auto action = finally([&]{
|
||||
mProcess.reset();
|
||||
});
|
||||
mProcess->setProgram(cmd);
|
||||
mProcess->setArguments(arguments);
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QString path = env.value("PATH");
|
||||
QStringList pathAdded = binDirs();
|
||||
if (!path.isEmpty()) {
|
||||
path = pathAdded.join(PATH_SEPARATOR) + PATH_SEPARATOR + path;
|
||||
} else {
|
||||
path = pathAdded.join(PATH_SEPARATOR);
|
||||
}
|
||||
QString cmdDir = extractFileDir(cmd);
|
||||
if (!cmdDir.isEmpty()) {
|
||||
path = cmdDir + PATH_SEPARATOR + path;
|
||||
}
|
||||
env.insert("PATH",path);
|
||||
mProcess->setProcessEnvironment(env);
|
||||
|
||||
mProcess->setWorkingDirectory(workingDir);
|
||||
|
||||
connect(mProcess.get(), &QProcess::errorOccurred,
|
||||
[&](){
|
||||
errorOccured= true;
|
||||
});
|
||||
QByteArray buffer;
|
||||
QByteArray readed;
|
||||
|
||||
mProcess->start();
|
||||
mProcess->waitForStarted(5000);
|
||||
mStartSemaphore.release(1);
|
||||
while (true) {
|
||||
mProcess->waitForFinished(1);
|
||||
if (mProcess->state()!=QProcess::Running) {
|
||||
break;
|
||||
}
|
||||
if (mStop) {
|
||||
mProcess->terminate();
|
||||
mProcess->kill();
|
||||
break;
|
||||
}
|
||||
if (errorOccured)
|
||||
break;
|
||||
readed = mProcess->readAll();
|
||||
buffer += readed;
|
||||
|
||||
if (readed.endsWith("\n")&& outputTerminated(buffer)) {
|
||||
processDebugOutput(buffer);
|
||||
buffer.clear();
|
||||
mCmdRunning = false;
|
||||
runNextCmd();
|
||||
} else if (!mCmdRunning && readed.isEmpty()){
|
||||
runNextCmd();
|
||||
} else if (readed.isEmpty()){
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
if (errorOccured) {
|
||||
emit processFailed(mProcess->error());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
|
||||
*
|
||||
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef DAP_DEBUGGER_H
|
||||
#define DAP_DEBUGGER_H
|
||||
|
||||
#include "debugger.h"
|
||||
|
||||
class DAPDebuggerClient : public DebuggerClient {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DAPDebuggerClient(Debugger* debugger, QObject *parent = nullptr);
|
||||
|
||||
|
||||
// QThread interface
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
// DebuggerClient interface
|
||||
public:
|
||||
void postCommand(const QString &Command, const QString &Params, DebugCommandSource Source) override;
|
||||
void registerInferiorStoppedCommand(const QString &Command, const QString &Params) override;
|
||||
void stopDebug() override;
|
||||
|
||||
protected:
|
||||
void runNextCmd() override;
|
||||
private:
|
||||
void initializeRequest();
|
||||
private:
|
||||
std::shared_ptr<QProcess> mProcess;
|
||||
bool mStop;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -57,6 +57,9 @@ QString createDAPResponseMessage(
|
|||
qint64 seq, qint64 request_seq, bool success,
|
||||
const QString& command, const QString& message, const QJsonObject& body);
|
||||
|
||||
QString createDAPEventMessage(
|
||||
qint64 seq, const QString& event, const QJsonObject& body);
|
||||
|
||||
std::shared_ptr<DAPProtocolMessage> parseDAPMessage(const QByteArray& contentPart);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -270,12 +270,14 @@ void Debugger::updateRegisterValues(const QHash<int, QString> &values)
|
|||
void Debugger::refreshAll()
|
||||
{
|
||||
refreshWatchVars();
|
||||
sendCommand("-stack-list-variables", "--all-values");
|
||||
if (memoryModel()->startAddress()>0)
|
||||
sendCommand("-data-read-memory",QString("%1 x 1 %2 %3 ")
|
||||
.arg(memoryModel()->startAddress())
|
||||
.arg(pSettings->debugger().memoryViewRows())
|
||||
.arg(pSettings->debugger().memoryViewColumns())
|
||||
if (mExecuting && mClient)
|
||||
mClient->refreshStackVariables();
|
||||
if (memoryModel()->startAddress()>0
|
||||
&& mExecuting && mClient)
|
||||
mClient->readMemory(
|
||||
memoryModel()->startAddress(),
|
||||
pSettings->debugger().memoryViewRows(),
|
||||
pSettings->debugger().memoryViewColumns()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -314,7 +316,9 @@ bool Debugger::inferiorRunning()
|
|||
|
||||
void Debugger::interrupt()
|
||||
{
|
||||
sendCommand("-exec-interrupt", "");
|
||||
if (mExecuting && mClient) {
|
||||
mClient->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
bool Debugger::isForProject() const
|
||||
|
@ -437,13 +441,8 @@ PBreakpoint Debugger::breakpointAt(int line, const Editor *editor, int *index)
|
|||
void Debugger::setBreakPointCondition(int index, const QString &condition, bool forProject)
|
||||
{
|
||||
PBreakpoint breakpoint=mBreakpointModel->setBreakPointCondition(index,condition, forProject);
|
||||
if (condition.isEmpty()) {
|
||||
sendCommand("-break-condition",
|
||||
QString("%1").arg(breakpoint->number));
|
||||
} else {
|
||||
sendCommand("-break-condition",
|
||||
QString("%1 %2").arg(breakpoint->number).arg(condition));
|
||||
}
|
||||
if (mExecuting && mClient)
|
||||
mClient->setBreakpointCondition(breakpoint);
|
||||
}
|
||||
|
||||
void Debugger::sendAllBreakpointsToDebugger()
|
||||
|
@ -495,8 +494,8 @@ void Debugger::loadForProject(const QString &filename, const QString &projectFol
|
|||
void Debugger::addWatchpoint(const QString &expression)
|
||||
{
|
||||
QString s=expression.trimmed();
|
||||
if (!s.isEmpty()) {
|
||||
sendCommand("-break-watch",s,DebugCommandSource::Other);
|
||||
if (mExecuting && mClient) {
|
||||
mClient->addWatchpoint(expression);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -545,12 +544,12 @@ void Debugger::modifyWatchVarExpression(const QString &oldExpr, const QString &n
|
|||
|
||||
void Debugger::refreshWatchVars()
|
||||
{
|
||||
if (mExecuting) {
|
||||
if (mExecuting && mClient) {
|
||||
sendAllWatchVarsToDebugger();
|
||||
if (mDebuggerType==DebuggerType::LLDB_MI) {
|
||||
for (PWatchVar var:mWatchModel->watchVars()) {
|
||||
if (!var->name.isEmpty())
|
||||
sendCommand("-var-update",QString(" --all-values %1").arg(var->name));
|
||||
mClient->refreshWatchVar(var);
|
||||
}
|
||||
} else {
|
||||
sendCommand("-var-update"," --all-values *");
|
||||
|
@ -1003,23 +1002,6 @@ DebuggerClient::DebuggerClient(Debugger* debugger, QObject *parent) : QThread(pa
|
|||
mCmdRunning = false;
|
||||
}
|
||||
|
||||
void DebuggerClient::clearCmdQueue()
|
||||
{
|
||||
QMutexLocker locker(&mCmdQueueMutex);
|
||||
mCmdQueue.clear();
|
||||
}
|
||||
|
||||
void DebuggerClient::runInferiorStoppedHook()
|
||||
{
|
||||
QMutexLocker locker(&mCmdQueueMutex);
|
||||
foreach (const PDebugCommand& cmd, mInferiorStoppedHookCommands) {
|
||||
mCmdQueue.push_front(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const QStringList &DebuggerClient::binDirs() const
|
||||
{
|
||||
return mBinDirs;
|
||||
|
@ -1065,11 +1047,6 @@ bool DebuggerClient::updateCPUInfo() const
|
|||
return mUpdateCPUInfo;
|
||||
}
|
||||
|
||||
const PDebugCommand &DebuggerClient::currentCmd() const
|
||||
{
|
||||
return mCurrentCmd;
|
||||
}
|
||||
|
||||
const QStringList &DebuggerClient::consoleOutput() const
|
||||
{
|
||||
return mConsoleOutput;
|
||||
|
|
|
@ -45,13 +45,6 @@ enum class DebuggerType {
|
|||
DAP
|
||||
};
|
||||
|
||||
struct DebugCommand{
|
||||
QString command;
|
||||
QString params;
|
||||
DebugCommandSource source;
|
||||
};
|
||||
|
||||
using PDebugCommand = std::shared_ptr<DebugCommand>;
|
||||
struct WatchVar;
|
||||
using PWatchVar = std::shared_ptr<WatchVar>;
|
||||
struct WatchVar {
|
||||
|
@ -482,8 +475,6 @@ public:
|
|||
|
||||
const QStringList &consoleOutput() const;
|
||||
|
||||
const PDebugCommand ¤tCmd() const;
|
||||
|
||||
bool updateCPUInfo() const;
|
||||
|
||||
bool receivedSFWarning() const;
|
||||
|
@ -501,6 +492,15 @@ public:
|
|||
void addBinDir(const QString &binDir);
|
||||
|
||||
Debugger* debugger() { return mDebugger; }
|
||||
|
||||
//requests
|
||||
virtual void interrupt() = 0;
|
||||
virtual void refreshStackVariables() = 0;
|
||||
virtual void readMemory(qulonglong startAddress, int rows, int cols) = 0;
|
||||
virtual void setBreakpointCondition(PBreakpoint breakpoint) = 0;
|
||||
virtual void addWatchpoint(const QString& watchExp) = 0;
|
||||
virtual void refreshWatchVar(PWatchVar var) = 0;
|
||||
|
||||
signals:
|
||||
void parseStarted();
|
||||
void invalidateAllVars();
|
||||
|
@ -540,21 +540,18 @@ signals:
|
|||
void varsValueUpdated();
|
||||
protected:
|
||||
virtual void runNextCmd() = 0;
|
||||
void clearCmdQueue();
|
||||
void runInferiorStoppedHook();
|
||||
protected:
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
QRecursiveMutex mCmdQueueMutex;
|
||||
#else
|
||||
QMutex mCmdQueueMutex;
|
||||
#endif
|
||||
QQueue<PDebugCommand> mCmdQueue;
|
||||
|
||||
bool mCmdRunning;
|
||||
|
||||
QList<PDebugCommand> mInferiorStoppedHookCommands;
|
||||
bool mInferiorRunning;
|
||||
bool mProcessExited;
|
||||
PDebugCommand mCurrentCmd;
|
||||
|
||||
QStringList mConsoleOutput;
|
||||
QStringList mFullOutput;
|
||||
QSemaphore mStartSemaphore;
|
||||
|
|
|
@ -860,4 +860,65 @@ void GDBMIDebuggerClient::asyncUpdate()
|
|||
mAsyncUpdated = false;
|
||||
}
|
||||
|
||||
const PDebugCommand &GDBMIDebuggerClient::currentCmd() const
|
||||
{
|
||||
return mCurrentCmd;
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::interrupt()
|
||||
{
|
||||
postCommand("-exec-interrupt", "", DebugCommandSource::Other);
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::refreshStackVariables()
|
||||
{
|
||||
postCommand("-stack-list-variables", "--all-values", DebugCommandSource::Other);
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::readMemory(qulonglong startAddress, int rows, int cols)
|
||||
{
|
||||
postCommand("-data-read-memory",QString("%1 x 1 %2 %3 ")
|
||||
.arg(startAddress)
|
||||
.arg(rows)
|
||||
.arg(cols),
|
||||
DebugCommandSource::Other
|
||||
);
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::setBreakpointCondition(PBreakpoint breakpoint)
|
||||
{
|
||||
Q_ASSERT(breakpoint!=nullptr);
|
||||
QString condition = breakpoint->condition;
|
||||
if (condition.isEmpty()) {
|
||||
postCommand("-break-condition",
|
||||
QString("%1").arg(breakpoint->number), DebugCommandSource::Other);
|
||||
} else {
|
||||
postCommand("-break-condition",
|
||||
QString("%1 %2").arg(breakpoint->number).arg(condition), DebugCommandSource::Other);
|
||||
}
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::addWatchpoint(const QString &watchExp)
|
||||
{
|
||||
if (!watchExp.isEmpty())
|
||||
postCommand("-break-watch", watchExp, DebugCommandSource::Other);
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::refreshWatchVar(PWatchVar var)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::runInferiorStoppedHook()
|
||||
{
|
||||
QMutexLocker locker(&mCmdQueueMutex);
|
||||
foreach (const PDebugCommand& cmd, mInferiorStoppedHookCommands) {
|
||||
mCmdQueue.push_front(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void GDBMIDebuggerClient::clearCmdQueue()
|
||||
{
|
||||
QMutexLocker locker(&mCmdQueueMutex);
|
||||
mCmdQueue.clear();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,14 @@
|
|||
#include <memory>
|
||||
#include <QRegularExpression>
|
||||
|
||||
struct DebugCommand{
|
||||
QString command;
|
||||
QString params;
|
||||
DebugCommandSource source;
|
||||
};
|
||||
|
||||
using PDebugCommand = std::shared_ptr<DebugCommand>;
|
||||
|
||||
class GDBMIDebuggerClient: public DebuggerClient {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -37,6 +45,14 @@ public:
|
|||
void postCommand(const QString &Command, const QString &Params, DebugCommandSource Source) override;
|
||||
void registerInferiorStoppedCommand(const QString &Command, const QString &Params) override;
|
||||
void stopDebug() override;
|
||||
const PDebugCommand ¤tCmd() const;
|
||||
|
||||
void interrupt() override;
|
||||
void refreshStackVariables() override;
|
||||
void readMemory(qulonglong startAddress, int rows, int cols) override;
|
||||
void setBreakpointCondition(PBreakpoint breakpoint) override;
|
||||
void addWatchpoint(const QString& watchExp) override;
|
||||
void refreshWatchVar(PWatchVar var) override;
|
||||
// QThread interface
|
||||
protected:
|
||||
void run() override;
|
||||
|
@ -63,6 +79,8 @@ private:
|
|||
void processResultRecord(const QByteArray& line);
|
||||
void processDebugOutput(const QByteArray& debugOutput);
|
||||
QByteArray removeToken(const QByteArray& line) const;
|
||||
void runInferiorStoppedHook();
|
||||
void clearCmdQueue();
|
||||
private slots:
|
||||
void asyncUpdate();
|
||||
private:
|
||||
|
@ -77,6 +95,11 @@ private:
|
|||
bool mAsyncUpdated;
|
||||
|
||||
static const QRegularExpression REGdbSourceLine;
|
||||
|
||||
QQueue<PDebugCommand> mCmdQueue;
|
||||
PDebugCommand mCurrentCmd;
|
||||
QList<PDebugCommand> mInferiorStoppedHookCommands;
|
||||
|
||||
};
|
||||
|
||||
#endif // GDBMI_DEBUGGER_H
|
||||
|
|
Loading…
Reference in New Issue