diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp
index 0860404c..d207a5be 100644
--- a/src/core/Cutter.cpp
+++ b/src/core/Cutter.cpp
@@ -1902,6 +1902,35 @@ void CutterCore::continueDebug()
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(), &R2Task::finished, this, [this] () {
+ debugTask.clear();
+ syncAndSeekProgramCounter();
+ emit registersChanged();
+ emit stackChanged();
+ emit refreshCodeViews();
+ emit debugTaskStateChanged();
+ });
+
+ debugTask->startTask();
+}
+
void CutterCore::continueUntilDebug(QString offset)
{
if (!currentlyDebugging) {
@@ -2055,6 +2084,32 @@ void CutterCore::stepOutDebug()
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(), &R2Task::finished, this, [this] () {
+ debugTask.clear();
+ syncAndSeekProgramCounter();
+ emit debugTaskStateChanged();
+ });
+
+ debugTask->startTask();
+}
+
QStringList CutterCore::getDebugPlugins()
{
QStringList plugins;
@@ -2080,6 +2135,41 @@ void CutterCore::setDebugPlugin(QString plugin)
setConfig("dbg.backend", plugin);
}
+void CutterCore::addTraceSession()
+{
+ if (!currentlyDebugging) {
+ return;
+ }
+
+ if (currentlyEmulating) {
+ if (!asyncCmdEsil("aets+", debugTask)) {
+ return;
+ }
+ } else {
+ if (!asyncCmd("dts+", debugTask)) {
+ return;
+ }
+ }
+ emit debugTaskStateChanged();
+
+ connect(debugTask.data(), &R2Task::finished, this, [this] () {
+ if (debugTaskDialog) {
+ delete debugTaskDialog;
+ }
+ debugTask.clear();
+
+ emit debugTaskStateChanged();
+ });
+
+ debugTaskDialog = new R2TaskDialog(debugTask);
+ debugTaskDialog->setBreakOnClose(true);
+ debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
+ debugTaskDialog->setDesc(tr("Creating debug tracepoint..."));
+ 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 5adcad96..4c54fbd6 100644
--- a/src/core/Cutter.h
+++ b/src/core/Cutter.h
@@ -394,12 +394,15 @@ 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 addTraceSession();
void addBreakpoint(const BreakpointDescription &config);
void updateBreakpoint(int index, const BreakpointDescription &config);
diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp
index 0174a8ce..385a3cd0 100644
--- a/src/core/MainWindow.cpp
+++ b/src/core/MainWindow.cpp
@@ -294,10 +294,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->actionAddTraceSession);
// Sepparator between undo/redo and goto lineEdit
QWidget *spacer4 = new QWidget();
diff --git a/src/resources.qrc b/src/resources.qrc
index 19989a98..9f1b5306 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,8 @@
img/icons/step_over.svg
img/icons/step_out.svg
img/icons/light/step_out.svg
+ img/icons/reverse_step.svg
+ img/icons/record_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 6f09220f..b8f3380e 100644
--- a/src/widgets/DebugActions.cpp
+++ b/src/widgets/DebugActions.cpp
@@ -24,6 +24,9 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *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");
+ QIcon addTraceSessionIcon = QIcon(":/img/icons/record_trace.svg");
stopIcon = QIcon(":/img/icons/media-stop_light.svg");
restartIcon = QIcon(":/img/icons/spin_light.svg");
detachIcon = QIcon(":/img/icons/detach_debugger.svg");
@@ -41,9 +44,12 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *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");
+ QString addTraceSessionLabel = tr("Add trace session");
suspendLabel = tr("Suspend the process");
continueLabel = tr("Continue");
restartDebugLabel = tr("Restart program");
@@ -61,12 +67,17 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *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));
+ actionAddTraceSession = new QAction(addTraceSessionIcon, addTraceSessionLabel, this);
QToolButton *startButton = new QToolButton;
startButton->setPopupMode(QToolButton::MenuButtonPopup);
@@ -100,16 +111,22 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) :
toolBar->addAction(actionStepOver);
toolBar->addAction(actionStep);
toolBar->addAction(actionStepOut);
+ toolBar->addAction(actionStepBack);
+ toolBar->addAction(actionContinueBack);
+ toolBar->addAction(actionAddTraceSession);
- allActions = {actionStop, actionAllContinues, actionContinue, actionContinueUntilCall, actionContinueUntilMain, actionContinueUntilSyscall, actionStep, actionStepOut, actionStepOver};
- // hide allactions
+ allActions = {actionStop, actionAllContinues, actionContinue, actionContinueUntilCall,
+ actionContinueUntilMain, actionContinueUntilSyscall, actionStep, actionStepOut,
+ actionStepOver, actionContinueBack, actionStepBack, actionAddTraceSession};
+
+ // 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
- };
+ actionContinueUntilCall, actionContinueUntilSyscall, actionStepBack,
+ actionContinueBack, actionAddTraceSession};
toggleConnectionActions = {actionAttach, actionStartRemote};
connect(Core(), &CutterCore::debugProcessFinished, this, [ = ](int pid) {
diff --git a/src/widgets/DebugActions.h b/src/widgets/DebugActions.h
index c786b073..75e7069d 100644
--- a/src/widgets/DebugActions.h
+++ b/src/widgets/DebugActions.h
@@ -26,11 +26,14 @@ public:
QAction *actionContinueUntilMain;
QAction *actionContinueUntilCall;
QAction *actionContinueUntilSyscall;
+ QAction *actionContinueBack;
QAction *actionStep;
QAction *actionStepOver;
QAction *actionStepOut;
+ QAction *actionStepBack;
QAction *actionStop;
QAction *actionAllContinues;
+ QAction *actionAddTraceSession;
// Continue/suspend and start/restart interchange during runtime
QIcon continueIcon;