mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 19:06:10 +00:00
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
This commit is contained in:
parent
41cfb78d13
commit
9f7b96281d
3
.gitignore
vendored
3
.gitignore
vendored
@ -66,3 +66,6 @@ __pycache__
|
|||||||
|
|
||||||
# Other
|
# Other
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
|
||||||
|
# vscode
|
||||||
|
**/.vscode
|
29
README.md
29
README.md
@ -72,15 +72,16 @@ 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.
|
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 |
|
| Shortcut | Function |
|
||||||
| --- | --- |
|
| ---------- | ------------------- |
|
||||||
| Global shortcuts: ||
|
|
||||||
| . | Focus console input |
|
| . | Focus console input |
|
||||||
| G & S | Focus search bar |
|
| G/S | Focus search bar |
|
||||||
| F5 | Refresh contents |
|
| Ctrl/Cmd+R | Refresh contents |
|
||||||
| Disassembly view: ||
|
|
||||||
|
### Disassembly view shortcuts
|
||||||
|
| Shortcut | Function |
|
||||||
|
| ---------- | -------------------------------- |
|
||||||
| Esc | Seek to previous position |
|
| Esc | Seek to previous position |
|
||||||
| Space | Switch to disassembly graph view |
|
| Space | Switch to disassembly graph view |
|
||||||
| Ctrl/Cmd+C | Copy |
|
| Ctrl/Cmd+C | Copy |
|
||||||
@ -88,15 +89,27 @@ To deploy *cutter* using a pre-built `Dockerfile`, it's possible to use the [pro
|
|||||||
| N | Rename current function/flag |
|
| N | Rename current function/flag |
|
||||||
| Shift+N | Rename flag/function used here |
|
| Shift+N | Rename flag/function used here |
|
||||||
| X | Show Xrefs |
|
| X | Show Xrefs |
|
||||||
| Disassembly graph view: ||
|
|
||||||
|
### Graph view shortcuts
|
||||||
|
| Shortcut | Function |
|
||||||
|
| ------------------- | -------------------------- |
|
||||||
| Esc | Seek to previous position |
|
| Esc | Seek to previous position |
|
||||||
| Space | Switch to disassembly view |
|
| Space | Switch to disassembly view |
|
||||||
|
| Ctrl/Cmd+MouseWheel | Zoom |
|
||||||
| + | Zoom in |
|
| + | Zoom in |
|
||||||
| - | Zoom out |
|
| - | Zoom out |
|
||||||
| = | Reset zoom |
|
| = | Reset zoom |
|
||||||
| J | Next instruction |
|
| J | Next instruction |
|
||||||
| K | Previous 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
|
## Help
|
||||||
|
|
||||||
|
@ -933,16 +933,16 @@ void CutterCore::setDebugPlugin(QString plugin)
|
|||||||
setConfig("dbg.backend", 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 instructionChanged(addr);
|
||||||
emit breakpointsChanged();
|
emit breakpointsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::addBreakpoint(QString addr)
|
void CutterCore::toggleBreakpoint(QString addr)
|
||||||
{
|
{
|
||||||
cmd("db " + addr);
|
cmd("dbs " + addr);
|
||||||
emit instructionChanged(addr.toULongLong());
|
emit instructionChanged(addr.toULongLong());
|
||||||
emit breakpointsChanged();
|
emit breakpointsChanged();
|
||||||
}
|
}
|
||||||
|
@ -497,8 +497,8 @@ public:
|
|||||||
void continueUntilDebug(QString offset);
|
void continueUntilDebug(QString offset);
|
||||||
void stepDebug();
|
void stepDebug();
|
||||||
void stepOverDebug();
|
void stepOverDebug();
|
||||||
void addBreakpoint(RVA addr);
|
void toggleBreakpoint(RVA addr);
|
||||||
void addBreakpoint(QString addr);
|
void toggleBreakpoint(QString addr);
|
||||||
void delBreakpoint(RVA addr);
|
void delBreakpoint(RVA addr);
|
||||||
void delAllBreakpoints();
|
void delAllBreakpoints();
|
||||||
void enableBreakpoint(RVA addr);
|
void enableBreakpoint(RVA addr);
|
||||||
|
@ -324,7 +324,6 @@ FORMS += \
|
|||||||
widgets/BacktraceWidget.ui \
|
widgets/BacktraceWidget.ui \
|
||||||
dialogs/OpenFileDialog.ui \
|
dialogs/OpenFileDialog.ui \
|
||||||
widgets/MemoryMapWidget.ui \
|
widgets/MemoryMapWidget.ui \
|
||||||
widgets/MemoryMapWidget.ui \
|
|
||||||
dialogs/preferences/DebugOptionsWidget.ui \
|
dialogs/preferences/DebugOptionsWidget.ui \
|
||||||
widgets/BreakpointWidget.ui \
|
widgets/BreakpointWidget.ui \
|
||||||
dialogs/BreakpointsDialog.ui \
|
dialogs/BreakpointsDialog.ui \
|
||||||
|
@ -22,6 +22,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
|||||||
setApplicationName("Cutter");
|
setApplicationName("Cutter");
|
||||||
setApplicationVersion(APP_VERSION);
|
setApplicationVersion(APP_VERSION);
|
||||||
setWindowIcon(QIcon(":/img/cutter.svg"));
|
setWindowIcon(QIcon(":/img/cutter.svg"));
|
||||||
|
setAttribute(Qt::AA_DontShowIconsInMenus);
|
||||||
|
|
||||||
// Set QString codec to UTF-8
|
// Set QString codec to UTF-8
|
||||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||||
|
@ -130,8 +130,19 @@ void MainWindow::initUI()
|
|||||||
spacer3->setMaximumWidth(100);
|
spacer3->setMaximumWidth(100);
|
||||||
ui->mainToolBar->addWidget(spacer3);
|
ui->mainToolBar->addWidget(spacer3);
|
||||||
|
|
||||||
QToolBar *debugToolbar = new DebugToolbar(this);
|
DebugToolbar *debugToolbar = new DebugToolbar(this);
|
||||||
ui->mainToolBar->addWidget(debugToolbar);
|
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
|
// Sepparator between undo/redo and goto lineEdit
|
||||||
QWidget *spacer4 = new QWidget();
|
QWidget *spacer4 = new QWidget();
|
||||||
|
@ -277,10 +277,16 @@ border-top: 0px;
|
|||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="addExtraWidgets"/>
|
<addaction name="addExtraWidgets"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuDebug">
|
||||||
|
<property name="title">
|
||||||
|
<string>Debug</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menuEdit"/>
|
<addaction name="menuEdit"/>
|
||||||
<addaction name="menuView"/>
|
<addaction name="menuView"/>
|
||||||
<addaction name="menuWindows"/>
|
<addaction name="menuWindows"/>
|
||||||
|
<addaction name="menuDebug"/>
|
||||||
<addaction name="menuHelp"/>
|
<addaction name="menuHelp"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QToolBar" name="mainToolBar">
|
<widget class="QToolBar" name="mainToolBar">
|
||||||
|
@ -113,8 +113,8 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent)
|
|||||||
addSeparator();
|
addSeparator();
|
||||||
debugMenu = new QMenu(tr("Debug"), this);
|
debugMenu = new QMenu(tr("Debug"), this);
|
||||||
debugMenuAction = addMenu(debugMenu);
|
debugMenuAction = addMenu(debugMenu);
|
||||||
actionAddBreakpoint.setText(tr("Add breakpoint"));
|
createAction(debugMenu, &actionAddBreakpoint, tr("Add/remove breakpoint"), getAddBPSequence(),
|
||||||
debugMenu->addAction(&actionAddBreakpoint);
|
SLOT(on_actionAddBreakpoint_triggered()));
|
||||||
actionContinueUntil.setText(tr("Continue until line"));
|
actionContinueUntil.setText(tr("Continue until line"));
|
||||||
debugMenu->addAction(&actionContinueUntil);
|
debugMenu->addAction(&actionContinueUntil);
|
||||||
QString progCounterName = Core()->getRegisterName("PC");
|
QString progCounterName = Core()->getRegisterName("PC");
|
||||||
@ -148,8 +148,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent)
|
|||||||
connect(&actionSetBits32, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBits32_triggered()));
|
connect(&actionSetBits32, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBits32_triggered()));
|
||||||
connect(&actionSetBits64, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBits64_triggered()));
|
connect(&actionSetBits64, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBits64_triggered()));
|
||||||
|
|
||||||
connect(&actionAddBreakpoint, &QAction::triggered,
|
|
||||||
this, &DisassemblyContextMenu::on_actionAddBreakpoint_triggered);
|
|
||||||
connect(&actionContinueUntil, &QAction::triggered,
|
connect(&actionContinueUntil, &QAction::triggered,
|
||||||
this, &DisassemblyContextMenu::on_actionContinueUntil_triggered);
|
this, &DisassemblyContextMenu::on_actionContinueUntil_triggered);
|
||||||
connect(&actionSetPC, &QAction::triggered,
|
connect(&actionSetPC, &QAction::triggered,
|
||||||
@ -280,6 +278,11 @@ QKeySequence DisassemblyContextMenu::getDisplayOptionsSequence() const
|
|||||||
return {}; //TODO insert correct sequence
|
return {}; //TODO insert correct sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QKeySequence> DisassemblyContextMenu::getAddBPSequence() const
|
||||||
|
{
|
||||||
|
return {Qt::Key_F2, Qt::CTRL + Qt::Key_B};
|
||||||
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::on_actionEditInstruction_triggered()
|
void DisassemblyContextMenu::on_actionEditInstruction_triggered()
|
||||||
{
|
{
|
||||||
EditInstructionDialog *e = new EditInstructionDialog(this);
|
EditInstructionDialog *e = new EditInstructionDialog(this);
|
||||||
@ -354,7 +357,7 @@ void DisassemblyContextMenu::on_actionCopyAddr_triggered()
|
|||||||
|
|
||||||
void DisassemblyContextMenu::on_actionAddBreakpoint_triggered()
|
void DisassemblyContextMenu::on_actionAddBreakpoint_triggered()
|
||||||
{
|
{
|
||||||
Core()->addBreakpoint(offset);
|
Core()->toggleBreakpoint(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::on_actionContinueUntil_triggered()
|
void DisassemblyContextMenu::on_actionContinueUntil_triggered()
|
||||||
@ -582,3 +585,20 @@ void DisassemblyContextMenu::createAction(QAction *action, QString name, QKeySeq
|
|||||||
shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
shortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
connect(shortcut, SIGNAL(activated()), this, slot);
|
connect(shortcut, SIGNAL(activated()), this, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisassemblyContextMenu::createAction(QMenu *menu, QAction *action, QString name, QList<QKeySequence> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -67,6 +67,7 @@ private:
|
|||||||
QKeySequence getRenameUsedHereSequence() const;
|
QKeySequence getRenameUsedHereSequence() const;
|
||||||
QKeySequence getXRefSequence() const;
|
QKeySequence getXRefSequence() const;
|
||||||
QKeySequence getDisplayOptionsSequence() const;
|
QKeySequence getDisplayOptionsSequence() const;
|
||||||
|
QList<QKeySequence> getAddBPSequence() const;
|
||||||
|
|
||||||
RVA offset;
|
RVA offset;
|
||||||
bool canCopy;
|
bool canCopy;
|
||||||
@ -123,5 +124,6 @@ private:
|
|||||||
// For creating anonymous entries (that are always visible)
|
// For creating anonymous entries (that are always visible)
|
||||||
void createAction(QString name, QKeySequence keySequence, const char *slot);
|
void createAction(QString name, QKeySequence keySequence, const char *slot);
|
||||||
void createAction(QAction *action, 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<QKeySequence> keySequence, const char *slot);
|
||||||
};
|
};
|
||||||
#endif // DISASSEMBLYCONTEXTMENU_H
|
#endif // DISASSEMBLYCONTEXTMENU_H
|
||||||
|
@ -191,7 +191,7 @@ void BreakpointWidget::addBreakpointDialog()
|
|||||||
if (!bps.isEmpty()) {
|
if (!bps.isEmpty()) {
|
||||||
QStringList bpList = bps.split(" ", QString::SkipEmptyParts);
|
QStringList bpList = bps.split(" ", QString::SkipEmptyParts);
|
||||||
for ( QString bp : bpList) {
|
for ( QString bp : bpList) {
|
||||||
Core()->addBreakpoint(bp);
|
Core()->toggleBreakpoint(bp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,15 +24,19 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
|||||||
QIcon stepOverIcon = QIcon(":/img/icons/step_over_light.svg");
|
QIcon stepOverIcon = QIcon(":/img/icons/step_over_light.svg");
|
||||||
|
|
||||||
actionStart = new QAction(startDebugIcon, tr("Start debug"), parent);
|
actionStart = new QAction(startDebugIcon, tr("Start debug"), parent);
|
||||||
|
actionStart->setShortcut(QKeySequence(Qt::Key_F9));
|
||||||
actionStartEmul = new QAction(startEmulIcon, tr("Start emulation"), parent);
|
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 *actionStop = new QAction(stopIcon, tr("Stop debug"), parent);
|
||||||
QAction *actionContinue = new QAction(continueIcon, tr("Continue"), parent);
|
actionContinue = new QAction(continueIcon, tr("Continue"), parent);
|
||||||
QAction *actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent);
|
actionContinue->setShortcut(QKeySequence(Qt::Key_F5));
|
||||||
QAction *actionContinueUntilCall = new QAction(continueUntilCallIcon, tr("Continue until call"), parent);
|
actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent);
|
||||||
QAction *actionContinueUntilSyscall = new QAction(continueUntilSyscallIcon, tr("Continue until syscall"), parent);
|
actionContinueUntilCall = new QAction(continueUntilCallIcon, tr("Continue until call"), parent);
|
||||||
QAction *actionStep = new QAction(stepIcon, tr("Step"), parent);
|
actionContinueUntilSyscall = new QAction(continueUntilSyscallIcon, tr("Continue until syscall"), parent);
|
||||||
QAction *actionStepOver = new QAction(stepOverIcon, tr("Step over"), 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;
|
QToolButton *startButton = new QToolButton;
|
||||||
startButton->setPopupMode(QToolButton::MenuButtonPopup);
|
startButton->setPopupMode(QToolButton::MenuButtonPopup);
|
||||||
|
@ -11,11 +11,18 @@ class DebugToolbar : public QToolBar
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DebugToolbar(MainWindow *main, QWidget *parent = nullptr);
|
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:
|
private:
|
||||||
MainWindow *main;
|
MainWindow *main;
|
||||||
QAction *actionStart;
|
|
||||||
QAction *actionStartEmul;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void continueUntilMain();
|
void continueUntilMain();
|
||||||
|
@ -693,8 +693,8 @@ void DisassemblerGraphView::blockClicked(GraphView::GraphBlock &block, QMouseEve
|
|||||||
|
|
||||||
seekLocal(instr);
|
seekLocal(instr);
|
||||||
|
|
||||||
if (event->button() == Qt::RightButton) {
|
|
||||||
mMenu->setOffset(instr);
|
mMenu->setOffset(instr);
|
||||||
|
if (event->button() == Qt::RightButton) {
|
||||||
mMenu->exec(event->globalPos());
|
mMenu->exec(event->globalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user