From 9f7b96281d834f30b34aa3c96e8b49cb394141b3 Mon Sep 17 00:00:00 2001 From: fcasal Date: Tue, 17 Jul 2018 08:26:20 +0100 Subject: [PATCH] Debugging shortcuts (#578) * Added debug shortcuts and debug menu * Added "Add breakpoint" shortcut * Added debug shortcuts to readme * Fix double memorymap ui * Add bp F2 shortcut and fix toggling bp with shortcuts --- .gitignore | 3 + README.md | 59 +++++++++++-------- src/Cutter.cpp | 8 +-- src/Cutter.h | 4 +- src/Cutter.pro | 1 - src/CutterApplication.cpp | 1 + src/MainWindow.cpp | 13 ++++- src/MainWindow.ui | 6 ++ src/menus/DisassemblyContextMenu.cpp | 30 ++++++++-- src/menus/DisassemblyContextMenu.h | 2 + src/widgets/BreakpointWidget.cpp | 2 +- src/widgets/DebugToolbar.cpp | 82 ++++++++++++++------------- src/widgets/DebugToolbar.h | 11 +++- src/widgets/DisassemblerGraphView.cpp | 2 +- 14 files changed, 145 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index eefdbf8d..293c312d 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ __pycache__ # Other compile_commands.json + +# vscode +**/.vscode \ No newline at end of file diff --git a/README.md b/README.md index 9a0fde4b..37839eb6 100644 --- a/README.md +++ b/README.md @@ -72,31 +72,44 @@ Check this [page](https://github.com/radareorg/cutter/blob/master/docs/Common-er To deploy *cutter* using a pre-built `Dockerfile`, it's possible to use the [provided configuration](docker). The corresponding `README.md` file also contains instructions on how to get started using the docker image with minimal effort. -## Keyboard shortcuts +### Global shortcuts +| Shortcut | Function | +| ---------- | ------------------- | +| . | Focus console input | +| G/S | Focus search bar | +| Ctrl/Cmd+R | Refresh contents | -| Shortcut | Function | -| --- | --- | -| Global shortcuts: || -| . | Focus console input | -| G & S | Focus search bar | -| F5 | Refresh contents | -| Disassembly view: || -| Esc | Seek to previous position | -| Space | Switch to disassembly graph view | -| Ctrl/Cmd+C | Copy | -| ; | Add comment | -| N | Rename current function/flag | -| Shift+N | Rename flag/function used here | -| X | Show Xrefs | -| Disassembly graph view: || -| Esc | Seek to previous position | -| Space | Switch to disassembly view | -| + | Zoom in | -| - | Zoom out | -| = | Reset zoom | -| J | Next instruction | -| K | Previous instruction | +### Disassembly view shortcuts +| Shortcut | Function | +| ---------- | -------------------------------- | +| Esc | Seek to previous position | +| Space | Switch to disassembly graph view | +| Ctrl/Cmd+C | Copy | +| ; | Add comment | +| N | Rename current function/flag | +| Shift+N | Rename flag/function used here | +| X | Show Xrefs | +### Graph view shortcuts +| Shortcut | Function | +| ------------------- | -------------------------- | +| Esc | Seek to previous position | +| Space | Switch to disassembly view | +| Ctrl/Cmd+MouseWheel | Zoom | +| + | Zoom in | +| - | Zoom out | +| = | Reset zoom | +| J | Next instruction | +| K | Previous instruction | + +### Debug shortcuts +| Shortcut | Function | +| --------------- | -------------- | +| F9 | Start debug | +| F7 | Step into | +| F8 | Step over | +| F5 | Continue | +| F2/(Ctrl/Cmd)+B | Add breakpoint | ## Help diff --git a/src/Cutter.cpp b/src/Cutter.cpp index 322e0740..5a2d8ef2 100644 --- a/src/Cutter.cpp +++ b/src/Cutter.cpp @@ -933,16 +933,16 @@ void CutterCore::setDebugPlugin(QString plugin) setConfig("dbg.backend", plugin); } -void CutterCore::addBreakpoint(RVA addr) +void CutterCore::toggleBreakpoint(RVA addr) { - cmd("db " + RAddressString(addr)); + cmd("dbs " + RAddressString(addr)); emit instructionChanged(addr); emit breakpointsChanged(); } -void CutterCore::addBreakpoint(QString addr) +void CutterCore::toggleBreakpoint(QString addr) { - cmd("db " + addr); + cmd("dbs " + addr); emit instructionChanged(addr.toULongLong()); emit breakpointsChanged(); } diff --git a/src/Cutter.h b/src/Cutter.h index 616cf7ef..9fa63346 100644 --- a/src/Cutter.h +++ b/src/Cutter.h @@ -497,8 +497,8 @@ public: void continueUntilDebug(QString offset); void stepDebug(); void stepOverDebug(); - void addBreakpoint(RVA addr); - void addBreakpoint(QString addr); + void toggleBreakpoint(RVA addr); + void toggleBreakpoint(QString addr); void delBreakpoint(RVA addr); void delAllBreakpoints(); void enableBreakpoint(RVA addr); diff --git a/src/Cutter.pro b/src/Cutter.pro index c5dc7242..80733297 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -324,7 +324,6 @@ FORMS += \ widgets/BacktraceWidget.ui \ dialogs/OpenFileDialog.ui \ widgets/MemoryMapWidget.ui \ - widgets/MemoryMapWidget.ui \ dialogs/preferences/DebugOptionsWidget.ui \ widgets/BreakpointWidget.ui \ dialogs/BreakpointsDialog.ui \ diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 483e999d..53f15bfe 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -22,6 +22,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc setApplicationName("Cutter"); setApplicationVersion(APP_VERSION); setWindowIcon(QIcon(":/img/cutter.svg")); + setAttribute(Qt::AA_DontShowIconsInMenus); // Set QString codec to UTF-8 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 597812cd..27fde709 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -130,8 +130,19 @@ void MainWindow::initUI() spacer3->setMaximumWidth(100); ui->mainToolBar->addWidget(spacer3); - QToolBar *debugToolbar = new DebugToolbar(this); + DebugToolbar *debugToolbar = new DebugToolbar(this); ui->mainToolBar->addWidget(debugToolbar); + // Debug menu + ui->menuDebug->addAction(debugToolbar->actionStart); + ui->menuDebug->addAction(debugToolbar->actionStartEmul); + ui->menuDebug->addAction(debugToolbar->actionAttach); + ui->menuDebug->addSeparator(); + ui->menuDebug->addAction(debugToolbar->actionStep); + ui->menuDebug->addAction(debugToolbar->actionStepOver); + ui->menuDebug->addSeparator(); + ui->menuDebug->addAction(debugToolbar->actionContinue); + ui->menuDebug->addAction(debugToolbar->actionContinueUntilCall); + ui->menuDebug->addAction(debugToolbar->actionContinueUntilSyscall); // Sepparator between undo/redo and goto lineEdit QWidget *spacer4 = new QWidget(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index e9c0f7f7..78650105 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -277,10 +277,16 @@ border-top: 0px; + + + Debug + + + diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 9d65ab73..8e6a6be1 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -113,8 +113,8 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent) addSeparator(); debugMenu = new QMenu(tr("Debug"), this); debugMenuAction = addMenu(debugMenu); - actionAddBreakpoint.setText(tr("Add breakpoint")); - debugMenu->addAction(&actionAddBreakpoint); + createAction(debugMenu, &actionAddBreakpoint, tr("Add/remove breakpoint"), getAddBPSequence(), + SLOT(on_actionAddBreakpoint_triggered())); actionContinueUntil.setText(tr("Continue until line")); debugMenu->addAction(&actionContinueUntil); QString progCounterName = Core()->getRegisterName("PC"); @@ -148,8 +148,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent) connect(&actionSetBits32, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBits32_triggered())); connect(&actionSetBits64, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBits64_triggered())); - connect(&actionAddBreakpoint, &QAction::triggered, - this, &DisassemblyContextMenu::on_actionAddBreakpoint_triggered); connect(&actionContinueUntil, &QAction::triggered, this, &DisassemblyContextMenu::on_actionContinueUntil_triggered); connect(&actionSetPC, &QAction::triggered, @@ -280,6 +278,11 @@ QKeySequence DisassemblyContextMenu::getDisplayOptionsSequence() const return {}; //TODO insert correct sequence } +QList DisassemblyContextMenu::getAddBPSequence() const +{ + return {Qt::Key_F2, Qt::CTRL + Qt::Key_B}; +} + void DisassemblyContextMenu::on_actionEditInstruction_triggered() { EditInstructionDialog *e = new EditInstructionDialog(this); @@ -354,7 +357,7 @@ void DisassemblyContextMenu::on_actionCopyAddr_triggered() void DisassemblyContextMenu::on_actionAddBreakpoint_triggered() { - Core()->addBreakpoint(offset); + Core()->toggleBreakpoint(offset); } void DisassemblyContextMenu::on_actionContinueUntil_triggered() @@ -582,3 +585,20 @@ void DisassemblyContextMenu::createAction(QAction *action, QString name, QKeySeq shortcut->setContext(Qt::WidgetWithChildrenShortcut); connect(shortcut, SIGNAL(activated()), this, slot); } + +void DisassemblyContextMenu::createAction(QMenu *menu, QAction *action, QString name, QList keySequence, + const char *slot) +{ + action->setText(name); + menu->addAction(action); + action->setShortcuts(keySequence); + + connect(action, SIGNAL(triggered(bool)), this, slot); + + auto pWidget = parentWidget(); + for (auto stct : keySequence) { + QShortcut *shortcut = new QShortcut(stct, pWidget); + shortcut->setContext(Qt::WidgetWithChildrenShortcut); + connect(shortcut, SIGNAL(activated()), this, slot); + } +} \ No newline at end of file diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index 8436513e..a4a8a693 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -67,6 +67,7 @@ private: QKeySequence getRenameUsedHereSequence() const; QKeySequence getXRefSequence() const; QKeySequence getDisplayOptionsSequence() const; + QList getAddBPSequence() const; RVA offset; bool canCopy; @@ -123,5 +124,6 @@ private: // For creating anonymous entries (that are always visible) void createAction(QString name, QKeySequence keySequence, const char *slot); void createAction(QAction *action, QString name, QKeySequence keySequence, const char *slot); + void createAction(QMenu *menu, QAction *action, QString name, QList keySequence, const char *slot); }; #endif // DISASSEMBLYCONTEXTMENU_H diff --git a/src/widgets/BreakpointWidget.cpp b/src/widgets/BreakpointWidget.cpp index ca8ebc8b..ade66ba4 100644 --- a/src/widgets/BreakpointWidget.cpp +++ b/src/widgets/BreakpointWidget.cpp @@ -191,7 +191,7 @@ void BreakpointWidget::addBreakpointDialog() if (!bps.isEmpty()) { QStringList bpList = bps.split(" ", QString::SkipEmptyParts); for ( QString bp : bpList) { - Core()->addBreakpoint(bp); + Core()->toggleBreakpoint(bp); } } } diff --git a/src/widgets/DebugToolbar.cpp b/src/widgets/DebugToolbar.cpp index 6aa3b9e9..60e274e7 100644 --- a/src/widgets/DebugToolbar.cpp +++ b/src/widgets/DebugToolbar.cpp @@ -24,15 +24,19 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) : QIcon stepOverIcon = QIcon(":/img/icons/step_over_light.svg"); actionStart = new QAction(startDebugIcon, tr("Start debug"), parent); + actionStart->setShortcut(QKeySequence(Qt::Key_F9)); actionStartEmul = new QAction(startEmulIcon, tr("Start emulation"), parent); - QAction *actionAttach = new QAction(startAttachIcon, tr("Attach to process"), parent); + actionAttach = new QAction(startAttachIcon, tr("Attach to process"), parent); QAction *actionStop = new QAction(stopIcon, tr("Stop debug"), parent); - QAction *actionContinue = new QAction(continueIcon, tr("Continue"), parent); - QAction *actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent); - QAction *actionContinueUntilCall = new QAction(continueUntilCallIcon, tr("Continue until call"), parent); - QAction *actionContinueUntilSyscall = new QAction(continueUntilSyscallIcon, tr("Continue until syscall"), parent); - QAction *actionStep = new QAction(stepIcon, tr("Step"), parent); - QAction *actionStepOver = new QAction(stepOverIcon, tr("Step over"), parent); + actionContinue = new QAction(continueIcon, tr("Continue"), parent); + actionContinue->setShortcut(QKeySequence(Qt::Key_F5)); + actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent); + actionContinueUntilCall = new QAction(continueUntilCallIcon, tr("Continue until call"), parent); + actionContinueUntilSyscall = new QAction(continueUntilSyscallIcon, tr("Continue until syscall"), parent); + actionStep = new QAction(stepIcon, tr("Step"), parent); + actionStep->setShortcut(QKeySequence(Qt::Key_F7)); + actionStepOver = new QAction(stepOverIcon, tr("Step over"), parent); + actionStepOver->setShortcut(QKeySequence(Qt::Key_F8)); QToolButton *startButton = new QToolButton; startButton->setPopupMode(QToolButton::MenuButtonPopup); @@ -61,39 +65,39 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) : addAction(actionStep); addAction(actionStepOver); - connect(actionStop, &QAction::triggered, Core(), &CutterCore::stopDebug); - connect(actionStop, &QAction::triggered, [=](){ - actionContinue->setVisible(true); - actionStart->setVisible(true); - actionStartEmul->setVisible(true); - actionAttach->setVisible(true); - actionContinueUntilMain->setVisible(true); - actionContinueUntilCall->setVisible(true); - this->colorToolbar(false); - }); - connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug); - connect(actionStart, &QAction::triggered, Core(), &CutterCore::startDebug); - connect(actionStart, &QAction::triggered, [=](){ - this->colorToolbar(true); - actionAttach->setVisible(false); - actionStartEmul->setVisible(false); - }); - connect(actionAttach, &QAction::triggered, this, &DebugToolbar::attachProcessDialog); - connect(actionStartEmul, &QAction::triggered, Core(), &CutterCore::startEmulation); - connect(actionStartEmul, &QAction::triggered, [=](){ - actionContinue->setVisible(false); - actionStart->setVisible(false); - actionAttach->setVisible(false); - actionContinueUntilMain->setVisible(false); - actionContinueUntilCall->setVisible(false); - continueUntilButton->setDefaultAction(actionContinueUntilSyscall); - this->colorToolbar(true); - }); - connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug); - connect(actionContinue, &QAction::triggered, Core(), &CutterCore::continueDebug); - connect(actionContinueUntilMain, &QAction::triggered, this, &DebugToolbar::continueUntilMain); + connect(actionStop, &QAction::triggered, Core(), &CutterCore::stopDebug); + connect(actionStop, &QAction::triggered, [=]() { + actionContinue->setVisible(true); + actionStart->setVisible(true); + actionStartEmul->setVisible(true); + actionAttach->setVisible(true); + actionContinueUntilMain->setVisible(true); + actionContinueUntilCall->setVisible(true); + this->colorToolbar(false); + }); + connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug); + connect(actionStart, &QAction::triggered, Core(), &CutterCore::startDebug); + connect(actionStart, &QAction::triggered, [=]() { + this->colorToolbar(true); + actionAttach->setVisible(false); + actionStartEmul->setVisible(false); + }); + connect(actionAttach, &QAction::triggered, this, &DebugToolbar::attachProcessDialog); + connect(actionStartEmul, &QAction::triggered, Core(), &CutterCore::startEmulation); + connect(actionStartEmul, &QAction::triggered, [=]() { + actionContinue->setVisible(false); + actionStart->setVisible(false); + actionAttach->setVisible(false); + actionContinueUntilMain->setVisible(false); + actionContinueUntilCall->setVisible(false); + continueUntilButton->setDefaultAction(actionContinueUntilSyscall); + this->colorToolbar(true); + }); + connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug); + connect(actionContinue, &QAction::triggered, Core(), &CutterCore::continueDebug); + connect(actionContinueUntilMain, &QAction::triggered, this, &DebugToolbar::continueUntilMain); connect(actionContinueUntilCall, &QAction::triggered, Core(), &CutterCore::continueUntilCall); - connect(actionContinueUntilSyscall, &QAction::triggered, Core(),&CutterCore::continueUntilSyscall); + connect(actionContinueUntilSyscall, &QAction::triggered, Core(), &CutterCore::continueUntilSyscall); } void DebugToolbar::continueUntilMain() diff --git a/src/widgets/DebugToolbar.h b/src/widgets/DebugToolbar.h index 01a0356a..09974b8f 100644 --- a/src/widgets/DebugToolbar.h +++ b/src/widgets/DebugToolbar.h @@ -11,11 +11,18 @@ class DebugToolbar : public QToolBar public: explicit DebugToolbar(MainWindow *main, QWidget *parent = nullptr); + QAction *actionStart; + QAction *actionStartEmul; + QAction *actionAttach; + QAction *actionContinue; + QAction *actionContinueUntilMain; + QAction *actionContinueUntilCall; + QAction *actionContinueUntilSyscall; + QAction *actionStep; + QAction *actionStepOver; private: MainWindow *main; - QAction *actionStart; - QAction *actionStartEmul; private slots: void continueUntilMain(); diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 22c45aeb..3644ae9e 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -693,8 +693,8 @@ void DisassemblerGraphView::blockClicked(GraphView::GraphBlock &block, QMouseEve seekLocal(instr); + mMenu->setOffset(instr); if (event->button() == Qt::RightButton) { - mMenu->setOffset(instr); mMenu->exec(event->globalPos()); } }