UI Improvemetnts + graph.offset implementation (#612)

* Add getBreakpointsAddresses to list breakpoints offsets

* Add breakpoint highligthing and improve of disassembly UIs

* Improve dialogs and positions

* Add graph,offset option to preference

* Tiny text fix

* Updated radare2 sumodule
This commit is contained in:
Itay Cohen 2018-08-12 19:20:16 +03:00 committed by xarkes
parent 4e3d857239
commit bf07f2a002
15 changed files with 117 additions and 38 deletions

@ -1 +1 @@
Subproject commit c9ec8b54b9ba32ba6712f319825f8d032e573e68 Subproject commit 404e4a1b74df7941c3ff7511f5396e1e1736ce37

View File

@ -1078,6 +1078,25 @@ QList<BreakpointDescription> CutterCore::getBreakpoints()
return ret; return ret;
} }
QList<RVA> CutterCore::getBreakpointsAddresses()
{
QList<BreakpointDescription> bps = getBreakpoints();
BreakpointDescription bp;
QList<RVA> bpAddresses;
foreach (bp, bps)
{
bpAddresses << bp.addr;
}
return bpAddresses;
}
bool CutterCore::isBreakpoint(QList<RVA> breakpoints, RVA addr)
{
return breakpoints.contains(addr);
}
QJsonDocument CutterCore::getBacktrace() QJsonDocument CutterCore::getBacktrace()
{ {
return cmdj("dbtj"); return cmdj("dbtj");

View File

@ -518,6 +518,8 @@ public:
void delAllBreakpoints(); void delAllBreakpoints();
void enableBreakpoint(RVA addr); void enableBreakpoint(RVA addr);
void disableBreakpoint(RVA addr); void disableBreakpoint(RVA addr);
bool isBreakpoint(QList<RVA> breakpoints, RVA addr);
QList<RVA> getBreakpointsAddresses();
QString getActiveDebugPlugin(); QString getActiveDebugPlugin();
QStringList getDebugPlugins(); QStringList getDebugPlugins();
void setDebugPlugin(QString plugin); void setDebugPlugin(QString plugin);

View File

@ -206,8 +206,6 @@ border-top: 0px;
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionLock"/> <addaction name="actionLock"/>
<addaction name="actionTabs_on_Top"/> <addaction name="actionTabs_on_Top"/>
<addaction name="separator"/>
<addaction name="actionPreferences"/>
</widget> </widget>
<widget class="QMenu" name="menuHelp"> <widget class="QMenu" name="menuHelp">
<property name="title"> <property name="title">
@ -222,6 +220,8 @@ border-top: 0px;
<addaction name="actionSearch"/> <addaction name="actionSearch"/>
<addaction name="actionUndoSeek"/> <addaction name="actionUndoSeek"/>
<addaction name="actionRedoSeek"/> <addaction name="actionRedoSeek"/>
<addaction name="separator"/>
<addaction name="actionPreferences"/>
</widget> </widget>
<widget class="QMenu" name="addDebugWidgets"> <widget class="QMenu" name="addDebugWidgets">
<property name="title"> <property name="title">

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>296</width> <width>506</width>
<height>310</height> <height>310</height>
</rect> </rect>
</property> </property>

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>545</width> <width>545</width>
<height>450</height> <height>526</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -17,7 +17,7 @@
<item> <item>
<widget class="QTabWidget" name="asmOptionsTab"> <widget class="QTabWidget" name="asmOptionsTab">
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="asmStyleTab"> <widget class="QWidget" name="asmStyleTab">
<attribute name="title"> <attribute name="title">

View File

@ -25,6 +25,7 @@ GraphOptionsWidget::~GraphOptionsWidget() {}
void GraphOptionsWidget::updateOptionsFromVars() void GraphOptionsWidget::updateOptionsFromVars()
{ {
qhelpers::setCheckedWithoutSignals(ui->graphOffsetCheckBox, Config()->getConfigBool("graph.offset"));
ui->maxColsSpinBox->blockSignals(true); ui->maxColsSpinBox->blockSignals(true);
ui->maxColsSpinBox->setValue(Config()->getGraphBlockMaxChars()); ui->maxColsSpinBox->setValue(Config()->getGraphBlockMaxChars());
ui->maxColsSpinBox->blockSignals(false); ui->maxColsSpinBox->blockSignals(false);
@ -44,3 +45,8 @@ void GraphOptionsWidget::on_maxColsSpinBox_valueChanged(int value)
triggerOptionsChanged(); triggerOptionsChanged();
} }
void GraphOptionsWidget::on_graphOffsetCheckBox_toggled(bool checked)
{
Config()->setConfig("graph.offset", checked);
triggerOptionsChanged();
}

View File

@ -31,6 +31,7 @@ private slots:
void updateOptionsFromVars(); void updateOptionsFromVars();
void on_maxColsSpinBox_valueChanged(int value); void on_maxColsSpinBox_valueChanged(int value);
void on_graphOffsetCheckBox_toggled(bool checked);
}; };

View File

@ -13,28 +13,51 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Graph</string> <string>Graph</string>
</property> </property>
<layout class="QFormLayout" name="formLayout"> <widget class="QLabel" name="maxColsLabel">
<item row="0" column="0"> <property name="geometry">
<widget class="QLabel" name="maxColsLabel"> <rect>
<property name="text"> <x>30</x>
<string>Maximum Line Length:</string> <y>10</y>
</property> <width>141</width>
</widget> <height>18</height>
</item> </rect>
<item row="0" column="1"> </property>
<widget class="QSpinBox" name="maxColsSpinBox"> <property name="text">
<property name="minimum"> <string>Maximum Line Length:</string>
<number>10</number> </property>
</property> </widget>
<property name="maximum"> <widget class="QSpinBox" name="maxColsSpinBox">
<number>999999999</number> <property name="geometry">
</property> <rect>
<property name="singleStep"> <x>190</x>
<number>5</number> <y>10</y>
</property> <width>104</width>
</widget> <height>23</height>
</item> </rect>
</layout> </property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
</widget>
<widget class="QCheckBox" name="graphOffsetCheckBox">
<property name="geometry">
<rect>
<x>30</x>
<y>44</y>
<width>162</width>
<height>22</height>
</rect>
</property>
<property name="text">
<string>Show offsets (graph.offset) </string>
</property>
</widget>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -22,7 +22,7 @@ static const QHash<QString, QVariant> asmOptions = {
{ "asm.flags.offset", false }, { "asm.flags.offset", false },
{ "asm.emu", false }, { "asm.emu", false },
{ "asm.cmt.right", true }, { "asm.cmt.right", true },
{ "asm.cmt.col", 70 }, { "asm.cmt.col", 35 },
{ "asm.var.summary", false }, { "asm.var.summary", false },
{ "asm.bytes", false }, { "asm.bytes", false },
{ "asm.size", false }, { "asm.size", false },
@ -37,7 +37,9 @@ static const QHash<QString, QVariant> asmOptions = {
{ "asm.var.subonly", true }, { "asm.var.subonly", true },
{ "asm.tabs", 5 }, { "asm.tabs", 5 },
{ "asm.tabs.off", 5 }, { "asm.tabs.off", 5 },
{ "esil.breakoninvalid", true } { "asm.marks", false },
{ "esil.breakoninvalid", true },
{ "graph.offset", false}
}; };
@ -118,7 +120,7 @@ void Configuration::loadDefaultTheme()
setColor("gui.cflow", QColor(0, 0, 0)); setColor("gui.cflow", QColor(0, 0, 0));
setColor("gui.dataoffset", QColor(0, 0, 0)); setColor("gui.dataoffset", QColor(0, 0, 0));
setColor("gui.border", QColor(0, 0, 0)); setColor("gui.border", QColor(0, 0, 0));
setColor("highlight", QColor(210, 210, 255)); setColor("highlight", QColor(210, 210, 255, 150));
setColor("highlightWord", QColor(210, 210, 255)); setColor("highlightWord", QColor(210, 210, 255));
// RIP line selection in debug // RIP line selection in debug
setColor("highlightPC", QColor(214, 255, 210)); setColor("highlightPC", QColor(214, 255, 210));
@ -135,6 +137,7 @@ void Configuration::loadDefaultTheme()
setColor("gui.navbar.str", QColor(69, 104, 229)); setColor("gui.navbar.str", QColor(69, 104, 229));
setColor("gui.navbar.sym", QColor(229, 150, 69)); setColor("gui.navbar.sym", QColor(229, 150, 69));
setColor("gui.navbar.empty", QColor(100, 100, 100)); setColor("gui.navbar.empty", QColor(100, 100, 100));
setColor("gui.breakpoint_background", QColor(233, 143, 143));
} }
void Configuration::loadBaseDark() void Configuration::loadBaseDark()
@ -176,6 +179,7 @@ void Configuration::loadBaseDark()
setColor("gui.navbar.empty", QColor(100, 100, 100)); setColor("gui.navbar.empty", QColor(100, 100, 100));
// RIP line selection in debug // RIP line selection in debug
setColor("highlightPC", QColor(87, 26, 7)); setColor("highlightPC", QColor(87, 26, 7));
setColor("gui.breakpoint_background", QColor(140, 76, 76));
} }
void Configuration::loadDarkTheme() void Configuration::loadDarkTheme()
@ -187,15 +191,16 @@ void Configuration::loadDarkTheme()
// Disassembly nodes background // Disassembly nodes background
setColor("gui.alt_background", QColor(28, 31, 36)); setColor("gui.alt_background", QColor(28, 31, 36));
// Disassembly nodes background when selected // Disassembly nodes background when selected
setColor("gui.disass_selected", QColor(44, 53, 54)); setColor("gui.disass_selected", QColor(31, 34, 40));
// Disassembly line selected // Disassembly line selected
setColor("highlight", QColor(21, 29, 29)); setColor("highlight", QColor(21, 29, 29, 150));
setColor("highlightWord", QColor(100, 100, 100)); setColor("highlightWord", QColor(100, 100, 100));
} }
const QFont Configuration::getFont() const const QFont Configuration::getFont() const
{ {
QFont font = s.value("font", QFont("Inconsolata", 12)).value<QFont>(); QFont font = s.value("font", QFont("Inconsolata", 11)).value<QFont>();
return font; return font;
} }

View File

@ -332,6 +332,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
p.setBrush(Qt::gray); p.setBrush(Qt::gray);
p.drawRect(block.x, block.y, block.width, block.height); p.drawRect(block.x, block.y, block.width, block.height);
breakpoints = Core()->getBreakpointsAddresses();
// Render node // Render node
DisassemblyBlock &db = disassembly_blocks[block.entry]; DisassemblyBlock &db = disassembly_blocks[block.entry];
@ -350,6 +351,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
if ((instr.addr <= PCAddr) && (PCAddr <= instr.addr + instr.size)) { if ((instr.addr <= PCAddr) && (PCAddr <= instr.addr + instr.size)) {
PCInBlock = true; PCInBlock = true;
} }
// TODO: L219 // TODO: L219
} }
@ -359,12 +361,13 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
} else if (db.indirectcall) { } else if (db.indirectcall) {
p.setBrush(indirectcallShadowColor); p.setBrush(indirectcallShadowColor);
} else { } else {
p.setBrush(QColor(0, 0, 0, 128)); p.setBrush(QColor(0, 0, 0, 100));
} }
p.drawRect(block.x + 4, block.y + 4, // Node's shadow effect
block.width + 4, block.height + 4); p.drawRect(block.x + 2, block.y + 2,
p.setPen(graphNodeColor); block.width, block.height);
p.setPen(QPen(graphNodeColor, 1));
if (block_selected) { if (block_selected) {
p.setBrush(disassemblySelectedBackgroundColor); p.setBrush(disassemblySelectedBackgroundColor);
@ -436,6 +439,14 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
y += charHeight; y += charHeight;
} }
for (Instr &instr : db.instrs) { for (Instr &instr : db.instrs) {
if (Core()->isBreakpoint(breakpoints, instr.addr)) {
p.fillRect(QRect(block.x + charWidth, y, block.width - (10 + 2 * charWidth),
int(instr.text.lines.size()) * charHeight), ConfigColor("gui.breakpoint_background"));
if (instr.addr == selected_instruction) {
p.fillRect(QRect(block.x + charWidth, y, block.width - (10 + 2 * charWidth),
int(instr.text.lines.size()) * charHeight), disassemblySelectionColor);
}
}
for (auto &line : instr.text.lines) { for (auto &line : instr.text.lines) {
int rectSize = qRound(charWidth); int rectSize = qRound(charWidth);
if (rectSize % 2) { if (rectSize % 2) {

View File

@ -197,6 +197,7 @@ private:
void seekInstruction(bool previous_instr); void seekInstruction(bool previous_instr);
CutterSeekableWidget *seekable = nullptr; CutterSeekableWidget *seekable = nullptr;
QList<QShortcut *> shortcuts; QList<QShortcut *> shortcuts;
QList<RVA> breakpoints;
QColor disassemblyBackgroundColor; QColor disassemblyBackgroundColor;
QColor disassemblySelectedBackgroundColor; QColor disassemblySelectedBackgroundColor;

View File

@ -209,6 +209,7 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
return; return;
} }
breakpoints = Core()->getBreakpointsAddresses();
int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value(); int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value();
mDisasTextEdit->setLockScroll(true); // avoid flicker mDisasTextEdit->setLockScroll(true); // avoid flicker
@ -224,14 +225,21 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
mDisasTextEdit->document()->clear(); mDisasTextEdit->document()->clear();
QTextCursor cursor(mDisasTextEdit->document()); QTextCursor cursor(mDisasTextEdit->document());
QTextBlockFormat regular = cursor.blockFormat();
for (DisassemblyLine line : disassemblyLines) { for (DisassemblyLine line : disassemblyLines) {
if (line.offset < topOffset) { // overflow if (line.offset < topOffset) { // overflow
break; break;
} }
cursor.insertHtml(line.text); cursor.insertHtml(line.text);
if(Core()->isBreakpoint(breakpoints,line.offset)) {
QTextBlockFormat f;
f.setBackground(ConfigColor("gui.breakpoint_background"));
cursor.setBlockFormat(f);
}
auto a = new DisassemblyTextBlockUserData(line); auto a = new DisassemblyTextBlockUserData(line);
cursor.block().setUserData(a); cursor.block().setUserData(a);
cursor.insertBlock(); cursor.insertBlock();
cursor.setBlockFormat(regular);
} }
if (!disassemblyLines.isEmpty()) { if (!disassemblyLines.isEmpty()) {

View File

@ -61,6 +61,8 @@ private:
RVA readDisassemblyOffset(QTextCursor tc); RVA readDisassemblyOffset(QTextCursor tc);
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
QList<RVA> breakpoints;
void setupFonts(); void setupFonts();
void setupColors(); void setupColors();

View File

@ -35,6 +35,7 @@ void QuickFilterView::clearFilter()
void QuickFilterView::closeFilter() void QuickFilterView::closeFilter()
{ {
ui->filterLineEdit->setText("");
hide(); hide();
emit filterClosed(); emit filterClosed();
} }