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;