diff --git a/rizin b/rizin
index 74ca7ff0..380372dc 160000
--- a/rizin
+++ b/rizin
@@ -1 +1 @@
-Subproject commit 74ca7ff0d1a95d3604b1900311e18741af097ec4
+Subproject commit 380372dce7cc7bf6244f135d10c73a426a098167
diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp
index b1018047..24946fad 100644
--- a/src/core/Cutter.cpp
+++ b/src/core/Cutter.cpp
@@ -1865,10 +1865,11 @@ void CutterCore::stopDebug()
}
currentlyDebugging = false;
+ currentlyTracing = false;
emit debugTaskStateChanged();
if (currentlyEmulating) {
- cmdEsil("aeim-; aei-; wcr; .ar-");
+ cmdEsil("aeim-; aei-; wcr; .ar-; aets-");
currentlyEmulating = false;
} else if (currentlyAttachedToPID != -1) {
// Use cmd because cmdRaw would not work with command concatenation
@@ -1926,7 +1927,33 @@ void CutterCore::continueDebug()
connect(debugTask.data(), &RizinTask::finished, this, [this]() {
debugTask.clear();
syncAndSeekProgramCounter();
- emit registersChanged();
+ emit refreshCodeViews();
+ emit debugTaskStateChanged();
+ });
+
+ debugTask->startTask();
+}
+
+void CutterCore::continueBackDebug()
+{
+ if (!currentlyDebugging) {
+ return;
+ }
+
+ if (currentlyEmulating) {
+ if (!asyncCmdEsil("aecb", debugTask)) {
+ return;
+ }
+ } else {
+ if (!asyncCmd("dcb", debugTask)) {
+ return;
+ }
+ }
+ emit debugTaskStateChanged();
+
+ connect(debugTask.data(), &RizinTask::finished, this, [this]() {
+ debugTask.clear();
+ syncAndSeekProgramCounter();
emit refreshCodeViews();
emit debugTaskStateChanged();
});
@@ -1954,8 +1981,6 @@ void CutterCore::continueUntilDebug(QString offset)
connect(debugTask.data(), &RizinTask::finished, this, [this]() {
debugTask.clear();
syncAndSeekProgramCounter();
- emit registersChanged();
- emit stackChanged();
emit refreshCodeViews();
emit debugTaskStateChanged();
});
@@ -1983,6 +2008,7 @@ void CutterCore::continueUntilCall()
connect(debugTask.data(), &RizinTask::finished, this, [this]() {
debugTask.clear();
syncAndSeekProgramCounter();
+ emit refreshCodeViews();
emit debugTaskStateChanged();
});
@@ -2009,6 +2035,7 @@ void CutterCore::continueUntilSyscall()
connect(debugTask.data(), &RizinTask::finished, this, [this]() {
debugTask.clear();
syncAndSeekProgramCounter();
+ emit refreshCodeViews();
emit debugTaskStateChanged();
});
@@ -2035,6 +2062,7 @@ void CutterCore::stepDebug()
connect(debugTask.data(), &RizinTask::finished, this, [this]() {
debugTask.clear();
syncAndSeekProgramCounter();
+ emit refreshCodeViews();
emit debugTaskStateChanged();
});
@@ -2061,6 +2089,7 @@ void CutterCore::stepOverDebug()
connect(debugTask.data(), &RizinTask::finished, this, [this]() {
debugTask.clear();
syncAndSeekProgramCounter();
+ emit refreshCodeViews();
emit debugTaskStateChanged();
});
@@ -2081,6 +2110,34 @@ void CutterCore::stepOutDebug()
connect(debugTask.data(), &RizinTask::finished, this, [this]() {
debugTask.clear();
syncAndSeekProgramCounter();
+ emit refreshCodeViews();
+ emit debugTaskStateChanged();
+ });
+
+ debugTask->startTask();
+}
+
+void CutterCore::stepBackDebug()
+{
+ if (!currentlyDebugging) {
+ return;
+ }
+
+ if (currentlyEmulating) {
+ if (!asyncCmdEsil("aesb", debugTask)) {
+ return;
+ }
+ } else {
+ if (!asyncCmd("dsb", debugTask)) {
+ return;
+ }
+ }
+ emit debugTaskStateChanged();
+
+ connect(debugTask.data(), &RizinTask::finished, this, [this]() {
+ debugTask.clear();
+ syncAndSeekProgramCounter();
+ emit refreshCodeViews();
emit debugTaskStateChanged();
});
@@ -2112,6 +2169,78 @@ void CutterCore::setDebugPlugin(QString plugin)
setConfig("dbg.backend", plugin);
}
+void CutterCore::startTraceSession()
+{
+ if (!currentlyDebugging || currentlyTracing) {
+ return;
+ }
+
+ if (currentlyEmulating) {
+ if (!asyncCmdEsil("aets+", debugTask)) {
+ return;
+ }
+ } else {
+ if (!asyncCmd("dts+", debugTask)) {
+ return;
+ }
+ }
+ emit debugTaskStateChanged();
+
+ connect(debugTask.data(), &RizinTask::finished, this, [this]() {
+ if (debugTaskDialog) {
+ delete debugTaskDialog;
+ }
+ debugTask.clear();
+
+ currentlyTracing = true;
+ emit debugTaskStateChanged();
+ });
+
+ debugTaskDialog = new RizinTaskDialog(debugTask);
+ debugTaskDialog->setBreakOnClose(true);
+ debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
+ debugTaskDialog->setDesc(tr("Creating debug tracepoint..."));
+ debugTaskDialog->show();
+
+ debugTask->startTask();
+}
+
+void CutterCore::stopTraceSession()
+{
+ if (!currentlyDebugging || !currentlyTracing) {
+ return;
+ }
+
+ if (currentlyEmulating) {
+ if (!asyncCmdEsil("aets-", debugTask)) {
+ return;
+ }
+ } else {
+ if (!asyncCmd("dts-", debugTask)) {
+ return;
+ }
+ }
+ emit debugTaskStateChanged();
+
+ connect(debugTask.data(), &RizinTask::finished, this, [this]() {
+ if (debugTaskDialog) {
+ delete debugTaskDialog;
+ }
+ debugTask.clear();
+
+ currentlyTracing = false;
+ emit debugTaskStateChanged();
+ });
+
+ debugTaskDialog = new RizinTaskDialog(debugTask);
+ debugTaskDialog->setBreakOnClose(true);
+ debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
+ debugTaskDialog->setDesc(tr("Stopping debug session..."));
+ debugTaskDialog->show();
+
+ debugTask->startTask();
+}
+
void CutterCore::toggleBreakpoint(RVA addr)
{
cmdRaw(QString("dbs %1").arg(addr));
diff --git a/src/core/Cutter.h b/src/core/Cutter.h
index 2a0ba6dd..a577ee9a 100644
--- a/src/core/Cutter.h
+++ b/src/core/Cutter.h
@@ -409,12 +409,17 @@ public:
void suspendDebug();
void syncAndSeekProgramCounter();
void continueDebug();
+ void continueBackDebug();
void continueUntilCall();
void continueUntilSyscall();
void continueUntilDebug(QString offset);
void stepDebug();
void stepOverDebug();
void stepOutDebug();
+ void stepBackDebug();
+
+ void startTraceSession();
+ void stopTraceSession();
void addBreakpoint(const BreakpointDescription &config);
void updateBreakpoint(int index, const BreakpointDescription &config);
@@ -449,6 +454,7 @@ public:
bool isRedirectableDebugee();
bool currentlyDebugging = false;
bool currentlyEmulating = false;
+ bool currentlyTracing = false;
int currentlyAttachedToPID = -1;
QString currentlyOpenFile;
diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp
index 76735810..0b422623 100644
--- a/src/core/MainWindow.cpp
+++ b/src/core/MainWindow.cpp
@@ -296,10 +296,14 @@ void MainWindow::initToolBar()
ui->menuDebug->addAction(debugActions->actionStep);
ui->menuDebug->addAction(debugActions->actionStepOver);
ui->menuDebug->addAction(debugActions->actionStepOut);
+ ui->menuDebug->addAction(debugActions->actionStepBack);
ui->menuDebug->addSeparator();
ui->menuDebug->addAction(debugActions->actionContinue);
ui->menuDebug->addAction(debugActions->actionContinueUntilCall);
ui->menuDebug->addAction(debugActions->actionContinueUntilSyscall);
+ ui->menuDebug->addAction(debugActions->actionContinueBack);
+ ui->menuDebug->addSeparator();
+ ui->menuDebug->addAction(debugActions->actionTrace);
// Sepparator between undo/redo and goto lineEdit
QWidget *spacer4 = new QWidget();
diff --git a/src/img/icons/reverse_continue.svg b/src/img/icons/reverse_continue.svg
new file mode 100644
index 00000000..43d98f61
--- /dev/null
+++ b/src/img/icons/reverse_continue.svg
@@ -0,0 +1,8 @@
+
diff --git a/src/img/icons/reverse_step.svg b/src/img/icons/reverse_step.svg
new file mode 100644
index 00000000..a9f4ed2d
--- /dev/null
+++ b/src/img/icons/reverse_step.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/img/icons/start_trace.svg b/src/img/icons/start_trace.svg
new file mode 100644
index 00000000..96d55d77
--- /dev/null
+++ b/src/img/icons/start_trace.svg
@@ -0,0 +1,62 @@
+
+
diff --git a/src/img/icons/stop_trace.svg b/src/img/icons/stop_trace.svg
new file mode 100644
index 00000000..65805f35
--- /dev/null
+++ b/src/img/icons/stop_trace.svg
@@ -0,0 +1,59 @@
+
+
diff --git a/src/resources.qrc b/src/resources.qrc
index 19989a98..f7cc7b12 100644
--- a/src/resources.qrc
+++ b/src/resources.qrc
@@ -33,6 +33,7 @@
img/icons/light/continue_until_call.svg
img/icons/continue_until_syscall.svg
img/icons/light/continue_until_syscall.svg
+ img/icons/reverse_continue.svg
img/icons/detach_debugger.svg
img/icons/light/step_into.svg
img/icons/step_into.svg
@@ -40,6 +41,9 @@
img/icons/step_over.svg
img/icons/step_out.svg
img/icons/light/step_out.svg
+ img/icons/reverse_step.svg
+ img/icons/start_trace.svg
+ img/icons/stop_trace.svg
img/icons/cloud.svg
img/icons/down.svg
img/icons/down_white.svg
diff --git a/src/widgets/DebugActions.cpp b/src/widgets/DebugActions.cpp
index 2de927f6..b0f34d9c 100644
--- a/src/widgets/DebugActions.cpp
+++ b/src/widgets/DebugActions.cpp
@@ -22,6 +22,10 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
QIcon startEmulIcon = QIcon(":/img/icons/play_light_emul.svg");
QIcon startAttachIcon = QIcon(":/img/icons/play_light_attach.svg");
QIcon startRemoteIcon = QIcon(":/img/icons/play_light_remote.svg");
+ QIcon continueBackIcon = QIcon(":/img/icons/reverse_continue.svg");
+ QIcon stepBackIcon = QIcon(":/img/icons/reverse_step.svg");
+ startTraceIcon = QIcon(":/img/icons/start_trace.svg");
+ stopTraceIcon = QIcon(":/img/icons/stop_trace.svg");
stopIcon = QIcon(":/img/icons/media-stop_light.svg");
restartIcon = QIcon(":/img/icons/spin_light.svg");
detachIcon = QIcon(":/img/icons/detach_debugger.svg");
@@ -39,9 +43,13 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
QString continueUMLabel = tr("Continue until main");
QString continueUCLabel = tr("Continue until call");
QString continueUSLabel = tr("Continue until syscall");
+ QString continueBackLabel = tr("Continue backwards");
QString stepLabel = tr("Step");
QString stepOverLabel = tr("Step over");
QString stepOutLabel = tr("Step out");
+ QString stepBackLabel = tr("Step backwards");
+ startTraceLabel = tr("Start trace session");
+ stopTraceLabel = tr("Stop trace session");
suspendLabel = tr("Suspend the process");
continueLabel = tr("Continue");
restartDebugLabel = tr("Restart program");
@@ -59,19 +67,23 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
actionContinueUntilMain = new QAction(continueUMLabel, this);
actionContinueUntilCall = new QAction(continueUCLabel, this);
actionContinueUntilSyscall = new QAction(continueUSLabel, this);
+ actionContinueBack = new QAction(continueBackIcon, continueBackLabel, this);
+ actionContinueBack->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F5));
actionStep = new QAction(stepLabel, this);
actionStep->setShortcut(QKeySequence(Qt::Key_F7));
actionStepOver = new QAction(stepOverLabel, this);
actionStepOver->setShortcut(QKeySequence(Qt::Key_F8));
actionStepOut = new QAction(stepOutLabel, this);
actionStepOut->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F8));
+ actionStepBack = new QAction(stepBackIcon, stepBackLabel, this);
+ actionStepBack->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F7));
+ actionTrace = new QAction(startTraceIcon, startTraceLabel, this);
QToolButton *startButton = new QToolButton;
startButton->setPopupMode(QToolButton::MenuButtonPopup);
connect(startButton, &QToolButton::triggered, startButton, &QToolButton::setDefaultAction);
QMenu *startMenu = new QMenu(startButton);
- // only emulation is currently allowed
startMenu->addAction(actionStart);
startMenu->addAction(actionStartEmul);
startMenu->addAction(actionAttach);
@@ -98,6 +110,9 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
toolBar->addAction(actionStepOver);
toolBar->addAction(actionStep);
toolBar->addAction(actionStepOut);
+ toolBar->addAction(actionStepBack);
+ toolBar->addAction(actionContinueBack);
+ toolBar->addAction(actionTrace);
allActions = { actionStop,
actionAllContinues,
@@ -107,16 +122,25 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
actionContinueUntilSyscall,
actionStep,
actionStepOut,
- actionStepOver };
- // hide allactions
+ actionStepOver,
+ actionContinueBack,
+ actionStepBack,
+ actionTrace };
+
+ // Hide all actions
setAllActionsVisible(false);
- // Toggle all buttons except restart, suspend(=continue) and stop since those are
- // necessary to avoid staying stuck
- toggleActions = { actionStepOver, actionStep,
- actionStepOut, actionContinueUntilMain,
- actionContinueUntilCall, actionContinueUntilSyscall };
+ // Toggle all buttons except reverse step/continue which are handled separately and
+ // restart, suspend(=continue) and stop since those are necessary to avoid freezing
+ toggleActions = { actionStepOver,
+ actionStep,
+ actionStepOut,
+ actionContinueUntilMain,
+ actionContinueUntilCall,
+ actionContinueUntilSyscall,
+ actionTrace };
toggleConnectionActions = { actionAttach, actionStartRemote };
+ reverseActions = { actionStepBack, actionContinueBack };
connect(Core(), &CutterCore::debugProcessFinished, this, [=](int pid) {
QMessageBox msgBox;
@@ -138,6 +162,10 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
actionContinue->setText(continueLabel);
actionContinue->setIcon(continueIcon);
}
+ for (QAction *a : reverseActions) {
+ a->setVisible(Core()->currentlyTracing);
+ a->setDisabled(disableToolbar);
+ }
} else {
for (QAction *a : toggleConnectionActions) {
a->setDisabled(disableToolbar);
@@ -160,7 +188,10 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
continueUntilButton->setDefaultAction(actionContinueUntilMain);
setAllActionsVisible(false);
});
+
connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug);
+ connect(actionStepBack, &QAction::triggered, Core(), &CutterCore::stepBackDebug);
+
connect(actionStart, &QAction::triggered, this, &DebugActions::startDebug);
connect(actionAttach, &QAction::triggered, this, &DebugActions::attachProcessDialog);
@@ -178,6 +209,10 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
actionStartEmul->setText(restartEmulLabel);
actionStartEmul->setIcon(restartIcon);
actionStop->setText(stopEmulLabel);
+ // Reverse debug actions aren't visible until we start tracing
+ for (QAction *a : reverseActions) {
+ a->setVisible(false);
+ }
});
connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug);
connect(actionStepOut, &QAction::triggered, Core(), &CutterCore::stepOutDebug);
@@ -185,6 +220,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
connect(actionContinueUntilCall, &QAction::triggered, Core(), &CutterCore::continueUntilCall);
connect(actionContinueUntilSyscall, &QAction::triggered, Core(),
&CutterCore::continueUntilSyscall);
+ connect(actionContinueBack, &QAction::triggered, Core(), &CutterCore::continueBackDebug);
connect(actionContinue, &QAction::triggered, Core(), [=]() {
// Switch between continue and suspend depending on the debugger's state
if (Core()->isDebugTaskInProgress()) {
@@ -194,6 +230,19 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
}
});
+ connect(actionTrace, &QAction::triggered, Core(), [=]() {
+ // Check if a debug session was created to switch between start and stop
+ if (!Core()->currentlyTracing) {
+ Core()->startTraceSession();
+ actionTrace->setText(stopTraceLabel);
+ actionTrace->setIcon(stopTraceIcon);
+ } else {
+ Core()->stopTraceSession();
+ actionTrace->setText(startTraceLabel);
+ actionTrace->setIcon(startTraceIcon);
+ }
+ });
+
connect(Config(), &Configuration::interfaceThemeChanged, this, &DebugActions::chooseThemeIcons);
chooseThemeIcons();
}
@@ -352,6 +401,13 @@ void DebugActions::startDebug()
actionStart->setIcon(restartIcon);
setButtonVisibleIfMainExists();
+ // Reverse debug actions aren't visible until we start tracing
+ for (QAction *a : reverseActions) {
+ a->setVisible(false);
+ }
+ actionTrace->setText(startTraceLabel);
+ actionTrace->setIcon(startTraceIcon);
+
Core()->startDebug();
}
diff --git a/src/widgets/DebugActions.h b/src/widgets/DebugActions.h
index 4ba280e6..ac5bc92b 100644
--- a/src/widgets/DebugActions.h
+++ b/src/widgets/DebugActions.h
@@ -26,21 +26,28 @@ public:
QAction *actionContinueUntilMain;
QAction *actionContinueUntilCall;
QAction *actionContinueUntilSyscall;
+ QAction *actionContinueBack;
QAction *actionStep;
QAction *actionStepOver;
QAction *actionStepOut;
+ QAction *actionStepBack;
QAction *actionStop;
QAction *actionAllContinues;
+ QAction *actionTrace;
// Continue/suspend and start/restart interchange during runtime
QIcon continueIcon;
QIcon suspendIcon;
QIcon restartIcon;
QIcon startDebugIcon;
- QString suspendLabel;
+ QIcon startTraceIcon;
+ QIcon stopTraceIcon;
QString continueLabel;
+ QString suspendLabel;
QString restartDebugLabel;
QString startDebugLabel;
+ QString startTraceLabel;
+ QString stopTraceLabel;
// Stop and Detach interchange during runtime
QIcon detachIcon;
@@ -52,6 +59,7 @@ private:
*/
QList toggleActions;
QList toggleConnectionActions;
+ QList reverseActions;
QList allActions;
QToolButton *continueUntilButton;
RemoteDebugDialog *remoteDialog = nullptr;