1
0
Fork 0

GUI: basics of debugging and interaction in the graph

This commit is contained in:
mrexodia 2016-10-13 11:48:47 +02:00
parent 0421420484
commit 3a89da37d8
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
5 changed files with 106 additions and 35 deletions

View File

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

View File

@ -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"
};

View File

@ -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")));

BIN
src/gui/images/lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -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>