Skip to content

Commit

Permalink
feat: [reversedebug] add new feature of reverse debugger
Browse files Browse the repository at this point in the history
Log: new feature
  • Loading branch information
LiHua000 authored and deepin-mozart committed Sep 26, 2024
1 parent a498471 commit f10ec50
Show file tree
Hide file tree
Showing 30 changed files with 774 additions and 50 deletions.
3 changes: 3 additions & 0 deletions src/base/abstractdebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,17 @@ class AbstractDebugger : public QObject

virtual void interruptDebug() = 0;
virtual void continueDebug() = 0;
virtual void reverseContinue() = 0;
virtual void abortDebug() = 0;
virtual void restartDebug() = 0;

virtual void stepOver() = 0;
virtual void stepIn() = 0;
virtual void stepOut() = 0;
virtual void stepBack() = 0;

virtual RunState getRunState() const = 0;
virtual bool supportStepBack() = 0;
virtual bool runCoredump(const QString &target, const QString &core, const QString &kit) = 0;

signals:
Expand Down
1 change: 1 addition & 0 deletions src/common/actionmanager/action_define.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ constexpr char M_BUILD[] = "IDE.Menu.Build";
constexpr char M_DEBUG[] = "IDE.Menu.Debug";
constexpr char M_TOOLS[] = "IDE.Menu.Tools";
constexpr char M_TOOLS_BINARY[] = "IDE.Menu.Tools.Binary";
constexpr char M_TOOLS_EVENTRECORDER[] = "IDE.Menu.Tools.EventRecorder";
constexpr char M_TOOLS_REVERSEDEBUG[] = "IDE.Menu.Tools.ReverseDebug";
constexpr char M_HELP[] = "IDE.Menu.Help";

Expand Down
138 changes: 105 additions & 33 deletions src/plugins/debugger/dap/dapdebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class DebuggerPrivate
bool isRemote = false;
RemoteInfo remoteInfo;

bool startAttaching = false;
DAPDebugger::debugState debugState = DAPDebugger::Normal;
};

DebuggerPrivate::~DebuggerPrivate()
Expand Down Expand Up @@ -215,6 +215,35 @@ void DAPDebugger::startDebug()
}
}

void DAPDebugger::startRerverseDebug(const QString &target)
{
d->isRemote = false;
d->debugState = Reverse;
if (d->currentSession == d->remoteSession)
d->currentSession = d->localSession;

updateRunState(kPreparing);

QMap<QString, QVariant> param;
param.insert("program", "rr");

d->requestDAPPortPpid = QString(getpid());
QDBusMessage msg = QDBusMessage::createSignal("/path",
"com.deepin.unioncode.interface",
"getDebugPort");

msg << d->requestDAPPortPpid
<< "cmake" //rr only support c/c++
<< ""
<< QStringList{target};

bool ret = QDBusConnection::sessionBus().send(msg);
if (!ret) {
qWarning() << "requeset debug port failed";
updateRunState(kNoRun);
}
}

void DAPDebugger::startDebugRemote(const RemoteInfo &info)
{
d->remoteInfo = info;
Expand Down Expand Up @@ -255,7 +284,7 @@ void DAPDebugger::attachDebug(const QString &processId)
}

d->isRemote = false;
d->startAttaching = true;
d->debugState = Attaching;
d->currentSession = d->localSession;

// only support gdb for now
Expand Down Expand Up @@ -304,6 +333,14 @@ void DAPDebugger::continueDebug()
}
}

void DAPDebugger::reverseContinue()
{
if (d->runState == kStopped) {
d->currentSession->reverseContinue(d->threadId);
editor.removeDebugLine();
}
}

void DAPDebugger::abortDebug()
{
if (d->runState == kRunning || d->runState == kStopped || d->runState == kCustomRunning) {
Expand All @@ -321,8 +358,6 @@ void DAPDebugger::abortDebug()
}

d->currentSession->terminate();
if (d->startAttaching)
d->startAttaching = false;
printOutput(tr("\nThe debugee has Terminated.\n"), OutputPane::OutputFormat::NormalMessage);
}

Expand Down Expand Up @@ -366,6 +401,18 @@ void DAPDebugger::stepOut()
}
}

void DAPDebugger::stepBack()
{
if (d->runState == kStopped && d->processingVariablesCount == 0) {
d->currentSession->stepBack(d->threadId, undefined);
}
}

bool DAPDebugger::supportStepBack()
{
return d->debugState == Reverse;
}

DAPDebugger::RunState DAPDebugger::getRunState() const
{
return d->runState;
Expand Down Expand Up @@ -568,17 +615,18 @@ void DAPDebugger::registerDapHandlers()

bool signalStopped = false;
if (event.reason == "signal-received" && event.description.has_value()) {
signalStopped = true;
auto signalName = QString::fromStdString(event.description.value().c_str());
if (signalName == "SIGSEGV") { // Segmentation fault
signalStopped = true;
auto signalMeaning = event.text.has_value() ? event.text.value().c_str() : "";
QMetaObject::invokeMethod(this, "showStoppedBySignalMessageBox",
Q_ARG(QString, QString::fromStdString(signalMeaning)), Q_ARG(QString, signalName));
}
if (signalName == "SIGINT" && d->pausing) // stopped by user
signalStopped = true;
if (signalName == "SIGINT" && !d->pausing) // stopped by user
signalStopped = false;
}

bool attaching = d->debugState == Attaching;
// ui focus on the active frame.
if (event.reason == "function breakpoint"
|| event.reason == "breakpoint"
Expand All @@ -588,14 +636,12 @@ void DAPDebugger::registerDapHandlers()
|| event.reason == "end-stepping-range"
|| event.reason == "goto"
|| signalStopped
|| (event.reason == "unknown" && d->startAttaching)) {
|| (event.reason == "unknown" && attaching)) {
//when attaching to running program . it won`t receive initialized event and event`s reason is "unknwon"
//so initial breakpoints in here
if (d->startAttaching) {
if (attaching) {
d->currentSession->getRawSession()->setReadyForBreakpoints(true);
debugService->sendAllBreakpoints(d->currentSession);

d->startAttaching = false;
}
if (event.threadId) {
d->threadId = event.threadId.value(0);
Expand Down Expand Up @@ -1265,6 +1311,7 @@ void DAPDebugger::updateRunState(DAPDebugger::RunState state)
case kNoRun:
exitDebug();
AppOutputPane::instance()->setProcessFinished("debugPane");
d->debugState = Normal;
break;
case kRunning:
case kCustomRunning:
Expand Down Expand Up @@ -1333,7 +1380,7 @@ void DAPDebugger::prepareDebug()
QMap<QString, QVariant> param;
if (!d->isRemote)
param = generator->getDebugArguments(getActiveProjectInfo(), d->currentOpenedFileName);

bool ret = generator->prepareDebug(param, retMsg);
if (!ret) {
printOutput(retMsg, OutputPane::ErrorMessage);
Expand Down Expand Up @@ -1448,31 +1495,56 @@ void DAPDebugger::launchSession(int port, const QMap<QString, QVariant> &param,
}

// Launch debuggee.
if (d->startAttaching) {
dap::object obj;
obj["processId"] = param.value("targetPath").toString().toStdString();
dap::AttachRequest request;
request.name = kitName.toStdString(); //kitName: gdb
request.connect = obj;
bSuccess &= d->currentSession->attach(request);
} else {
auto &ctx = dpfInstance.serviceContext();
LanguageService *service = ctx.service<LanguageService>(LanguageService::name());
if (service) {
auto generator = service->create<LanguageGenerator>(kitName);
if (generator) {
if (generator->isLaunchNotAttach()) {
dap::LaunchRequest request = generator->launchDAP(param);
bSuccess &= d->currentSession->launch(request);
} else {
dap::AttachRequest request = generator->attachDAP(port, param);
bSuccess &= d->currentSession->attach(request);
switch (d->debugState) {
case Normal: {
auto &ctx = dpfInstance.serviceContext();
LanguageService *service = ctx.service<LanguageService>(LanguageService::name());
if (service) {
auto generator = service->create<LanguageGenerator>(kitName);
if (generator) {
if (generator->isLaunchNotAttach()) {
dap::LaunchRequest request = generator->launchDAP(param);
bSuccess &= d->currentSession->launch(request);
} else {
dap::AttachRequest request = generator->attachDAP(port, param);
bSuccess &= d->currentSession->attach(request);
}
}
} else {
bSuccess &= false;
}
} else {
bSuccess &= false;
break;
}
case Attaching: {
dap::object obj;
obj["processId"] = param.value("targetPath").toString().toStdString();
dap::AttachRequest request;
request.name = kitName.toStdString(); //kitName: gdb
request.connect = obj;
bSuccess &= d->currentSession->attach(request);
break;
}
case Reverse: {
dap::LaunchRequest request;
request.name = "rr";
request.type = "cppdbg";
request.request = "launch";
request.program = ""; // targetPath.toStdString();
request.stopAtEntry = false;
dap::array<dap::string> arrayArg;
foreach (QString arg, param["arguments"].toStringList()) {
arrayArg.push_back(arg.toStdString());
}
request.args = arrayArg;
request.externalConsole = false;
request.MIMode = "gdb";
request.__sessionId = QUuid::createUuid().toString().toStdString();
bSuccess &= d->currentSession->launch(request);
}
default:
break;
}

if (!bSuccess) {
qCritical() << "startDebug failed!";
} else {
Expand Down
10 changes: 10 additions & 0 deletions src/plugins/debugger/dap/dapdebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ class DAPDebugger : public AbstractDebugger
explicit DAPDebugger(QObject *parent = nullptr);
~DAPDebugger() override;

enum debugState {
Normal,
Attaching,
Reverse
};

DWidget *getOutputPane() const override;
DWidget *getStackPane() const override;
DWidget *getLocalsPane() const override;
Expand All @@ -53,18 +59,22 @@ class DAPDebugger : public AbstractDebugger

void startDebug() override;
void startDebugRemote(const RemoteInfo &info) override;
void startRerverseDebug(const QString &target);
void attachDebug(const QString &processId) override;
void detachDebug() override;

void interruptDebug() override;
void continueDebug() override;
void reverseContinue() override;
void abortDebug() override;
void restartDebug() override;

void stepOver() override;
void stepIn() override;
void stepOut() override;
void stepBack() override;

bool supportStepBack() override;
RunState getRunState() const override;
bool runCoredump(const QString &target, const QString &core, const QString &kit) override;

Expand Down
28 changes: 27 additions & 1 deletion src/plugins/debugger/debugmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "debuggerglobals.h"
#include "interface/menumanager.h"
#include "interface/attachinfodialog.h"
#include "reversedebug/reversedebugger.h"

#include "services/debugger/debuggerservice.h"
#include "services/window/windowservice.h"
Expand All @@ -34,6 +35,9 @@ bool DebugManager::initialize(dpfservice::WindowService *windowService,
menuManager.reset(new MenuManager());
menuManager->initialize(windowService);

auto reverseDbg = new ReverseDebugger(this);
connect(reverseDbg, &ReverseDebugger::startReplay, this, &DebugManager::rrReplay);

connect(currentDebugger, &AbstractDebugger::runStateChanged, this, &DebugManager::handleRunStateChanged);

// bind debug services
Expand Down Expand Up @@ -170,6 +174,11 @@ void DebugManager::continueDebug()
AsynInvoke(currentDebugger->continueDebug());
}

void DebugManager::reverseContinue()
{
AsynInvoke(currentDebugger->reverseContinue());
}

void DebugManager::abortDebug()
{
AsynInvoke(currentDebugger->abortDebug());
Expand Down Expand Up @@ -198,11 +207,21 @@ void DebugManager::stepOut()
AsynInvoke(currentDebugger->stepOut());
}

void DebugManager::stepBack()
{
AsynInvoke(currentDebugger->stepBack());
}

bool DebugManager::supportStepBack()
{
return currentDebugger->supportStepBack();
}

void DebugManager::handleRunStateChanged(AbstractDebugger::RunState state)
{
menuManager->handleRunStateChanged(state);

if(state == AbstractDebugger::kStart || state == AbstractDebugger::kRunning) {
if(state == AbstractDebugger::kStart || state == AbstractDebugger::kRunning || state == AbstractDebugger::kCustomRunning) {
emit debugStarted();
} else if (state == AbstractDebugger::kNoRun) {
emit debugStopped();
Expand Down Expand Up @@ -236,3 +255,10 @@ bool DebugManager::runCoredump(const QString &target, const QString &core, const
{
return QtConcurrent::run(currentDebugger, &AbstractDebugger::runCoredump, target, core, kit);
}

void DebugManager::rrReplay(const QString &target)
{
auto dapdbgger = qobject_cast<DAPDebugger *>(debuggers["dap"]);
dapdbgger->startRerverseDebug(target);
}

4 changes: 4 additions & 0 deletions src/plugins/debugger/debugmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,22 @@ public slots:

void interruptDebug();
void continueDebug();
void reverseContinue();
void abortDebug();
void restartDebug();

void stepOver();
void stepIn();
void stepOut();
void stepBack();
bool supportStepBack();

void handleRunStateChanged(AbstractDebugger::RunState state);
void handleEvents(const dpf::Event &event);

private:
bool runCoredump(const QString &target, const QString &core, const QString &kit);
void rrReplay(const QString &target);

QMap<QString, AbstractDebugger *> debuggers;
AbstractDebugger *currentDebugger = nullptr;
Expand Down
Loading

0 comments on commit f10ec50

Please sign in to comment.