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;
+
+
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());
}
}