mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-21 14:16:08 +00:00
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:
parent
4e3d857239
commit
bf07f2a002
2
radare2
2
radare2
@ -1 +1 @@
|
||||
Subproject commit c9ec8b54b9ba32ba6712f319825f8d032e573e68
|
||||
Subproject commit 404e4a1b74df7941c3ff7511f5396e1e1736ce37
|
@ -1078,6 +1078,25 @@ QList<BreakpointDescription> CutterCore::getBreakpoints()
|
||||
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()
|
||||
{
|
||||
return cmdj("dbtj");
|
||||
|
@ -518,6 +518,8 @@ public:
|
||||
void delAllBreakpoints();
|
||||
void enableBreakpoint(RVA addr);
|
||||
void disableBreakpoint(RVA addr);
|
||||
bool isBreakpoint(QList<RVA> breakpoints, RVA addr);
|
||||
QList<RVA> getBreakpointsAddresses();
|
||||
QString getActiveDebugPlugin();
|
||||
QStringList getDebugPlugins();
|
||||
void setDebugPlugin(QString plugin);
|
||||
|
@ -206,8 +206,6 @@ border-top: 0px;
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLock"/>
|
||||
<addaction name="actionTabs_on_Top"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPreferences"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
@ -222,6 +220,8 @@ border-top: 0px;
|
||||
<addaction name="actionSearch"/>
|
||||
<addaction name="actionUndoSeek"/>
|
||||
<addaction name="actionRedoSeek"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPreferences"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="addDebugWidgets">
|
||||
<property name="title">
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>296</width>
|
||||
<width>506</width>
|
||||
<height>310</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>545</width>
|
||||
<height>450</height>
|
||||
<height>526</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -17,7 +17,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="asmOptionsTab">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="asmStyleTab">
|
||||
<attribute name="title">
|
||||
|
@ -25,6 +25,7 @@ GraphOptionsWidget::~GraphOptionsWidget() {}
|
||||
|
||||
void GraphOptionsWidget::updateOptionsFromVars()
|
||||
{
|
||||
qhelpers::setCheckedWithoutSignals(ui->graphOffsetCheckBox, Config()->getConfigBool("graph.offset"));
|
||||
ui->maxColsSpinBox->blockSignals(true);
|
||||
ui->maxColsSpinBox->setValue(Config()->getGraphBlockMaxChars());
|
||||
ui->maxColsSpinBox->blockSignals(false);
|
||||
@ -44,3 +45,8 @@ void GraphOptionsWidget::on_maxColsSpinBox_valueChanged(int value)
|
||||
triggerOptionsChanged();
|
||||
}
|
||||
|
||||
void GraphOptionsWidget::on_graphOffsetCheckBox_toggled(bool checked)
|
||||
{
|
||||
Config()->setConfig("graph.offset", checked);
|
||||
triggerOptionsChanged();
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ private slots:
|
||||
void updateOptionsFromVars();
|
||||
|
||||
void on_maxColsSpinBox_valueChanged(int value);
|
||||
void on_graphOffsetCheckBox_toggled(bool checked);
|
||||
};
|
||||
|
||||
|
||||
|
@ -13,16 +13,28 @@
|
||||
<property name="windowTitle">
|
||||
<string>Graph</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="maxColsLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>10</y>
|
||||
<width>141</width>
|
||||
<height>18</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Maximum Line Length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="maxColsSpinBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>190</x>
|
||||
<y>10</y>
|
||||
<width>104</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
@ -33,8 +45,19 @@
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<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>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
@ -22,7 +22,7 @@ static const QHash<QString, QVariant> asmOptions = {
|
||||
{ "asm.flags.offset", false },
|
||||
{ "asm.emu", false },
|
||||
{ "asm.cmt.right", true },
|
||||
{ "asm.cmt.col", 70 },
|
||||
{ "asm.cmt.col", 35 },
|
||||
{ "asm.var.summary", false },
|
||||
{ "asm.bytes", false },
|
||||
{ "asm.size", false },
|
||||
@ -37,7 +37,9 @@ static const QHash<QString, QVariant> asmOptions = {
|
||||
{ "asm.var.subonly", true },
|
||||
{ "asm.tabs", 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.dataoffset", 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));
|
||||
// RIP line selection in debug
|
||||
setColor("highlightPC", QColor(214, 255, 210));
|
||||
@ -135,6 +137,7 @@ void Configuration::loadDefaultTheme()
|
||||
setColor("gui.navbar.str", QColor(69, 104, 229));
|
||||
setColor("gui.navbar.sym", QColor(229, 150, 69));
|
||||
setColor("gui.navbar.empty", QColor(100, 100, 100));
|
||||
setColor("gui.breakpoint_background", QColor(233, 143, 143));
|
||||
}
|
||||
|
||||
void Configuration::loadBaseDark()
|
||||
@ -176,6 +179,7 @@ void Configuration::loadBaseDark()
|
||||
setColor("gui.navbar.empty", QColor(100, 100, 100));
|
||||
// RIP line selection in debug
|
||||
setColor("highlightPC", QColor(87, 26, 7));
|
||||
setColor("gui.breakpoint_background", QColor(140, 76, 76));
|
||||
}
|
||||
|
||||
void Configuration::loadDarkTheme()
|
||||
@ -187,15 +191,16 @@ void Configuration::loadDarkTheme()
|
||||
// Disassembly nodes background
|
||||
setColor("gui.alt_background", QColor(28, 31, 36));
|
||||
// Disassembly nodes background when selected
|
||||
setColor("gui.disass_selected", QColor(44, 53, 54));
|
||||
setColor("gui.disass_selected", QColor(31, 34, 40));
|
||||
// Disassembly line selected
|
||||
setColor("highlight", QColor(21, 29, 29));
|
||||
setColor("highlight", QColor(21, 29, 29, 150));
|
||||
setColor("highlightWord", QColor(100, 100, 100));
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -332,6 +332,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
p.setBrush(Qt::gray);
|
||||
p.drawRect(block.x, block.y, block.width, block.height);
|
||||
|
||||
breakpoints = Core()->getBreakpointsAddresses();
|
||||
|
||||
// Render node
|
||||
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)) {
|
||||
PCInBlock = true;
|
||||
}
|
||||
|
||||
// TODO: L219
|
||||
}
|
||||
|
||||
@ -359,12 +361,13 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
} else if (db.indirectcall) {
|
||||
p.setBrush(indirectcallShadowColor);
|
||||
} else {
|
||||
p.setBrush(QColor(0, 0, 0, 128));
|
||||
p.setBrush(QColor(0, 0, 0, 100));
|
||||
}
|
||||
|
||||
p.drawRect(block.x + 4, block.y + 4,
|
||||
block.width + 4, block.height + 4);
|
||||
p.setPen(graphNodeColor);
|
||||
// Node's shadow effect
|
||||
p.drawRect(block.x + 2, block.y + 2,
|
||||
block.width, block.height);
|
||||
p.setPen(QPen(graphNodeColor, 1));
|
||||
|
||||
if (block_selected) {
|
||||
p.setBrush(disassemblySelectedBackgroundColor);
|
||||
@ -436,6 +439,14 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
y += charHeight;
|
||||
}
|
||||
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) {
|
||||
int rectSize = qRound(charWidth);
|
||||
if (rectSize % 2) {
|
||||
|
@ -197,6 +197,7 @@ private:
|
||||
void seekInstruction(bool previous_instr);
|
||||
CutterSeekableWidget *seekable = nullptr;
|
||||
QList<QShortcut *> shortcuts;
|
||||
QList<RVA> breakpoints;
|
||||
|
||||
QColor disassemblyBackgroundColor;
|
||||
QColor disassemblySelectedBackgroundColor;
|
||||
|
@ -209,6 +209,7 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
|
||||
return;
|
||||
}
|
||||
|
||||
breakpoints = Core()->getBreakpointsAddresses();
|
||||
int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value();
|
||||
mDisasTextEdit->setLockScroll(true); // avoid flicker
|
||||
|
||||
@ -224,14 +225,21 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
|
||||
|
||||
mDisasTextEdit->document()->clear();
|
||||
QTextCursor cursor(mDisasTextEdit->document());
|
||||
QTextBlockFormat regular = cursor.blockFormat();
|
||||
for (DisassemblyLine line : disassemblyLines) {
|
||||
if (line.offset < topOffset) { // overflow
|
||||
break;
|
||||
}
|
||||
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);
|
||||
cursor.block().setUserData(a);
|
||||
cursor.insertBlock();
|
||||
cursor.setBlockFormat(regular);
|
||||
}
|
||||
|
||||
if (!disassemblyLines.isEmpty()) {
|
||||
|
@ -61,6 +61,8 @@ private:
|
||||
RVA readDisassemblyOffset(QTextCursor tc);
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
QList<RVA> breakpoints;
|
||||
|
||||
void setupFonts();
|
||||
void setupColors();
|
||||
|
||||
|
@ -35,6 +35,7 @@ void QuickFilterView::clearFilter()
|
||||
|
||||
void QuickFilterView::closeFilter()
|
||||
{
|
||||
ui->filterLineEdit->setText("");
|
||||
hide();
|
||||
emit filterClosed();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user