GUI: basics of debugging and interaction in the graph
This commit is contained in:
parent
0421420484
commit
3a89da37d8
|
|
@ -2,6 +2,7 @@
|
|||
#include "MenuBuilder.h"
|
||||
#include "CachedFontMetrics.h"
|
||||
#include "QBeaEngine.h"
|
||||
#include "GotoDialog.h"
|
||||
#include <vector>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
|
|
@ -13,7 +14,10 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
|||
: QAbstractScrollArea(parent),
|
||||
mFontMetrics(nullptr),
|
||||
currentGraph(duint(0)),
|
||||
disasm(ConfigUint("Disassembler", "MaxModuleSize"))
|
||||
disasm(ConfigUint("Disassembler", "MaxModuleSize")),
|
||||
mCip(0),
|
||||
mGoto(nullptr),
|
||||
syncOrigin(false)
|
||||
{
|
||||
this->status = "Loading...";
|
||||
|
||||
|
|
@ -57,6 +61,8 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
|||
connect(Bridge::getBridge(), SIGNAL(graphAt(duint)), this, SLOT(graphAtSlot(duint)));
|
||||
connect(Bridge::getBridge(), SIGNAL(updateGraph()), this, SLOT(updateGraphSlot()));
|
||||
connect(Bridge::getBridge(), SIGNAL(selectionGraphGet(SELECTIONDATA*)), this, SLOT(selectionGetSlot(SELECTIONDATA*)));
|
||||
connect(Bridge::getBridge(), SIGNAL(disassembleAt(dsint, dsint)), this, SLOT(disassembleAtSlot(dsint, dsint)));
|
||||
connect(Bridge::getBridge(), SIGNAL(focusGraph()), this, SLOT(setFocus()));
|
||||
|
||||
//Connect to config
|
||||
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
|
||||
|
|
@ -216,11 +222,18 @@ void DisassemblerGraphView::paintNormal(QPainter & p, QRect & viewportRect, int
|
|||
RichTextPainter::paintRichText(&p, x, y, block.width, this->charHeight, 0, line, mFontMetrics);
|
||||
y += this->charHeight;
|
||||
}
|
||||
|
||||
for(Instr & instr : block.block.instrs)
|
||||
{
|
||||
for(auto & line : instr.text.lines)
|
||||
{
|
||||
RichTextPainter::paintRichText(&p, x, y, block.width, this->charHeight, 0, line, mFontMetrics);
|
||||
if(instr.addr == mCip)
|
||||
{
|
||||
p.setPen(mCipColor);
|
||||
p.fillRect(x, y, this->charWidth, this->charHeight, mCipBackgroundColor);
|
||||
p.drawText(x, y, this->charWidth, this->charHeight, 0, QString("\xE2\x80\xA2"));
|
||||
}
|
||||
RichTextPainter::paintRichText(&p, x + this->charWidth, y, block.width - this->charWidth, this->charHeight, 0, line, mFontMetrics);
|
||||
y += this->charHeight;
|
||||
}
|
||||
}
|
||||
|
|
@ -505,7 +518,7 @@ void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
|||
else if(event->button() == Qt::RightButton)
|
||||
{
|
||||
QMenu wMenu(this);
|
||||
wMenu.addAction(mToggleOverviewAction);
|
||||
mMenuBuilder->build(&wMenu);
|
||||
wMenu.exec(event->globalPos()); //execute context menu
|
||||
}
|
||||
}
|
||||
|
|
@ -528,7 +541,7 @@ void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
|||
|
||||
this->viewport()->update();
|
||||
|
||||
if((instr != 0) && (event->button() == Qt::RightButton))
|
||||
if(event->button() == Qt::RightButton)
|
||||
{
|
||||
QMenu wMenu(this);
|
||||
mMenuBuilder->build(&wMenu);
|
||||
|
|
@ -547,12 +560,9 @@ void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
|||
else if(event->button() == Qt::RightButton)
|
||||
{
|
||||
//Right click outside of block
|
||||
if(this->ready && DbgIsDebugging())
|
||||
{
|
||||
QMenu wMenu(this);
|
||||
wMenu.addAction(mToggleOverviewAction);
|
||||
wMenu.exec(event->globalPos()); //execute context menu
|
||||
}
|
||||
QMenu wMenu(this);
|
||||
mMenuBuilder->build(&wMenu);
|
||||
wMenu.exec(event->globalPos()); //execute context menu
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -590,25 +600,7 @@ void DisassemblerGraphView::mouseReleaseEvent(QMouseEvent* event)
|
|||
void DisassemblerGraphView::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
duint instr = this->getInstrForMouseEvent(event);
|
||||
navigate(DbgGetBranchDestination(instr));
|
||||
/*Token token;
|
||||
if(this->getTokenForMouseEvent(event, token))
|
||||
{
|
||||
if(!this->analysis.functions.count(token.addr))
|
||||
{
|
||||
//Not a function or not analyzed, go to address in hex editor
|
||||
//TODO: show in hex editor?
|
||||
}
|
||||
else
|
||||
{
|
||||
this->function = token.addr;
|
||||
this->ready = false;
|
||||
this->desired_pos = nullptr;
|
||||
this->cur_instr = 0;
|
||||
this->highlight_token = nullptr;
|
||||
this->viewport()->update();
|
||||
}
|
||||
}*/
|
||||
DbgCmdExec(QString("graph dis.branchdest(%1), 1").arg(ToPtrString(instr)).toUtf8().constData());
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::prepareGraphNode(DisassemblerBlock & block)
|
||||
|
|
@ -637,7 +629,7 @@ void DisassemblerGraphView::prepareGraphNode(DisassemblerBlock & block)
|
|||
}
|
||||
}
|
||||
int extra = 4 * this->charWidth + 4;
|
||||
block.width = width + extra;
|
||||
block.width = width + extra + this->charWidth;
|
||||
block.height = (height * this->charHeight) + extra;
|
||||
}
|
||||
|
||||
|
|
@ -1457,15 +1449,36 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
return DbgIsDebugging();
|
||||
});
|
||||
|
||||
mMenuBuilder->addAction(makeAction(DIcon(QString("processor%1.png").arg(ArchValue("32", "64"))), tr("Follow in &Disassembler"), SLOT(followDisassemblerSlot())), [this](QMenu*)
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon(QString("processor%1.png").arg(ArchValue("32", "64"))), tr("Follow in &Disassembler"), SLOT(followDisassemblerSlot()), "ActionGraphFollowDisassembler"), [this](QMenu*)
|
||||
{
|
||||
return this->cur_instr != 0;
|
||||
});
|
||||
mMenuBuilder->addSeparator();
|
||||
|
||||
mToggleOverviewAction = makeShortcutAction(DIcon("graph.png"), tr("Toggle &Overview"), SLOT(toggleOverviewSlot()), "ActionGraphToggleOverview");
|
||||
mMenuBuilder->addAction(mToggleOverviewAction);
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("sync.png"), tr("Refresh"), SLOT(loadCurrentGraph()), "ActionGraphRefresh"));
|
||||
mMenuBuilder->addAction(mToggleOverview = makeShortcutAction(DIcon("graph.png"), tr("Toggle &Overview"), SLOT(toggleOverviewSlot()), "ActionGraphToggleOverview"));
|
||||
mMenuBuilder->addAction(mToggleSyncOrigin = makeShortcutAction(DIcon("lock.png"), tr("Toggle &sync with origin"), SLOT(toggleSyncOriginSlot()), "ActionGraphSyncOrigin"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("sync.png"), tr("&Refresh"), SLOT(loadCurrentGraph()), "ActionGraphRefresh"));
|
||||
MenuBuilder* gotoMenu = new MenuBuilder(this);
|
||||
gotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto.png"), tr("Expression"), SLOT(gotoExpressionSlot()), "ActionGotoExpression"));
|
||||
gotoMenu->addAction(makeShortcutAction(DIcon("cbp.png"), tr("Origin"), SLOT(gotoOriginSlot()), "ActionGotoOrigin"));
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("goto.png"), tr("Go to")), gotoMenu);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if(event->modifiers() != 0)
|
||||
return;
|
||||
int key = event->key();
|
||||
if(key == Qt::Key_Up)
|
||||
DbgCmdExec(QString("graph dis.prev(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
|
||||
else if(key == Qt::Key_Down)
|
||||
DbgCmdExec(QString("graph dis.next(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
|
||||
else if(key == Qt::Key_Left)
|
||||
DbgCmdExec(QString("graph dis.brtrue(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
|
||||
else if(key == Qt::Key_Right)
|
||||
DbgCmdExec(QString("graph dis.brfalse(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
|
||||
if(key == Qt::Key_Return || key == Qt::Key_Enter)
|
||||
DbgCmdExec(QString("graph dis.branchdest(%1), 1").arg(ToPtrString(cur_instr)).toUtf8().constData());
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::followDisassemblerSlot()
|
||||
|
|
@ -1486,6 +1499,8 @@ void DisassemblerGraphView::colorsUpdatedSlot()
|
|||
mCommentBackgroundColor = ConfigColor("DisassemblyCommentBackgroundColor");
|
||||
mLabelColor = ConfigColor("DisassemblyLabelColor");
|
||||
mLabelBackgroundColor = ConfigColor("DisassemblyLabelBackgroundColor");
|
||||
mCipBackgroundColor = ConfigColor("DisassemblyCipBackgroundColor");
|
||||
mCipColor = ConfigColor("DisassemblyCipColor");
|
||||
|
||||
jmpColor = ConfigColor("GraphJmpColor");
|
||||
brtrueColor = ConfigColor("GraphBrtrueColor");
|
||||
|
|
@ -1513,6 +1528,8 @@ void DisassemblerGraphView::shortcutsUpdatedSlot()
|
|||
void DisassemblerGraphView::toggleOverviewSlot()
|
||||
{
|
||||
drawOverview = !drawOverview;
|
||||
mToggleOverview->setCheckable(true);
|
||||
mToggleOverview->setChecked(drawOverview);
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
||||
|
|
@ -1521,3 +1538,41 @@ void DisassemblerGraphView::selectionGetSlot(SELECTIONDATA* selection)
|
|||
selection->start = selection->end = cur_instr;
|
||||
Bridge::getBridge()->setResult(1);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::disassembleAtSlot(dsint va, dsint cip)
|
||||
{
|
||||
Q_UNUSED(va);
|
||||
auto cipChanged = mCip != cip;
|
||||
mCip = cip;
|
||||
if(syncOrigin && cipChanged)
|
||||
gotoOriginSlot();
|
||||
else
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::gotoExpressionSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
if(!mGoto)
|
||||
mGoto = new GotoDialog(this);
|
||||
if(mGoto->exec() == QDialog::Accepted)
|
||||
{
|
||||
duint value = DbgValFromString(mGoto->expressionText.toUtf8().constData());
|
||||
DbgCmdExec(QString().sprintf("graph %p, 1", value).toUtf8().constData());
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::gotoOriginSlot()
|
||||
{
|
||||
DbgCmdExec("graph cip, 1");
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::toggleSyncOriginSlot()
|
||||
{
|
||||
syncOrigin = !syncOrigin;
|
||||
mToggleSyncOrigin->setCheckable(true);
|
||||
mToggleSyncOrigin->setChecked(syncOrigin);
|
||||
if(syncOrigin)
|
||||
gotoOriginSlot();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
class MenuBuilder;
|
||||
class CachedFontMetrics;
|
||||
class GotoDialog;
|
||||
|
||||
class DisassemblerGraphView : public QAbstractScrollArea
|
||||
{
|
||||
|
|
@ -236,6 +237,7 @@ public:
|
|||
void adjustGraphLayout(DisassemblerBlock & block, int col, int row);
|
||||
void computeGraphLayout(DisassemblerBlock & block);
|
||||
void setupContextMenu();
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
template<typename T>
|
||||
using Matrix = std::vector<std::vector<T>>;
|
||||
|
|
@ -264,6 +266,10 @@ public slots:
|
|||
void selectionGetSlot(SELECTIONDATA* selection);
|
||||
void tokenizerConfigUpdatedSlot();
|
||||
void loadCurrentGraph();
|
||||
void disassembleAtSlot(dsint va, dsint cip);
|
||||
void gotoExpressionSlot();
|
||||
void gotoOriginSlot();
|
||||
void toggleSyncOriginSlot();
|
||||
|
||||
private:
|
||||
QString status;
|
||||
|
|
@ -294,10 +300,14 @@ private:
|
|||
CachedFontMetrics* mFontMetrics;
|
||||
MenuBuilder* mMenuBuilder;
|
||||
bool drawOverview;
|
||||
QAction* mToggleOverviewAction;
|
||||
bool syncOrigin;
|
||||
int overviewXOfs;
|
||||
int overviewYOfs;
|
||||
qreal overviewScale;
|
||||
duint mCip;
|
||||
|
||||
QAction* mToggleOverview;
|
||||
QAction* mToggleSyncOrigin;
|
||||
|
||||
QColor disassemblyBackgroundColor;
|
||||
QColor disassemblySelectionColor;
|
||||
|
|
@ -314,9 +324,12 @@ private:
|
|||
QColor mCommentBackgroundColor;
|
||||
QColor mLabelColor;
|
||||
QColor mLabelBackgroundColor;
|
||||
QColor mCipColor;
|
||||
QColor mCipBackgroundColor;
|
||||
|
||||
BridgeCFGraph currentGraph;
|
||||
QBeaEngine disasm;
|
||||
GotoDialog* mGoto;
|
||||
protected:
|
||||
#include "ActionHelpers.h"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -473,8 +473,10 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultShortcuts.insert("ActionExecuteCommandScript", Shortcut(tr("Actions -> Execute Script Command"), "X"));
|
||||
defaultShortcuts.insert("ActionRefresh", Shortcut(tr("Actions -> Refresh"), "F5"));
|
||||
defaultShortcuts.insert("ActionGraph", Shortcut(tr("Actions -> Graph"), "G"));
|
||||
defaultShortcuts.insert("ActionGraphFollowDisassembler", Shortcut(tr("Actions -> Graph -> Follow in disassembler"), "Shift+Return"));
|
||||
defaultShortcuts.insert("ActionGraphToggleOverview", Shortcut(tr("Actions -> Graph -> Toggle overview"), "O"));
|
||||
defaultShortcuts.insert("ActionGraphRefresh", Shortcut(tr("Actions -> Graph -> Refresh"), "R"));
|
||||
defaultShortcuts.insert("ActionGraphSyncOrigin", Shortcut(tr("Actions -> Graph -> Toggle sync with origin"), "S"));
|
||||
defaultShortcuts.insert("ActionIncrementx87Stack", Shortcut(tr("Actions -> Increment x87 Stack")));
|
||||
defaultShortcuts.insert("ActionDecrementx87Stack", Shortcut(tr("Actions -> Decrement x87 Stack")));
|
||||
defaultShortcuts.insert("ActionPush", Shortcut(tr("Actions -> Push")));
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -253,5 +253,6 @@
|
|||
<file>images/disable.png</file>
|
||||
<file>images/database-export.png</file>
|
||||
<file>images/database-import.png</file>
|
||||
<file>images/lock.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
Loading…
Reference in New Issue