mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 19:36:11 +00:00
Graph highlighting (#624)
* Add saving instruction plaintext * Add graph highlighting * Remove HighlightToken
This commit is contained in:
parent
bb3ff2dc54
commit
336c20a955
@ -11,6 +11,7 @@
|
||||
#include <QFileDialog>
|
||||
#include <QFile>
|
||||
#include <QVBoxLayout>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "Cutter.h"
|
||||
#include "utils/Colors.h"
|
||||
@ -159,6 +160,11 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
disassembly_blocks.clear();
|
||||
blocks.clear();
|
||||
|
||||
if (highlight_token) {
|
||||
delete highlight_token;
|
||||
highlight_token = nullptr;
|
||||
}
|
||||
|
||||
bool emptyGraph = functions.isEmpty();
|
||||
if (emptyGraph) {
|
||||
// If there's no function to print, just move to disassembly and add a message
|
||||
@ -249,6 +255,7 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
|
||||
QTextDocument textDoc;
|
||||
textDoc.setHtml(disas);
|
||||
i.plainText = textDoc.toPlainText();
|
||||
|
||||
RichTextPainter::List richText = RichTextPainter::fromTextDocument(textDoc);
|
||||
//Colors::colorizeAssembly(richText, textDoc.toPlainText(), 0);
|
||||
@ -415,6 +422,29 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
}
|
||||
}
|
||||
|
||||
// highlight selected tokens
|
||||
if (highlight_token != nullptr) {
|
||||
int y = block.y + (2 * charWidth) + (db.header_text.lines.size() * charHeight);
|
||||
|
||||
for (Instr &instr : db.instrs) {
|
||||
int pos = -1;
|
||||
|
||||
while ((pos = instr.plainText.indexOf(highlight_token->content, pos + 1)) != -1) {
|
||||
int tokenEnd = pos + highlight_token->content.length();
|
||||
|
||||
if ((pos > 0 && instr.plainText[pos - 1].isLetterOrNumber())
|
||||
|| (tokenEnd < instr.plainText.length() && instr.plainText[tokenEnd].isLetterOrNumber())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p.fillRect(QRect(block.x + charWidth * 3 + pos * charWidth, y, highlight_token->length * charWidth,
|
||||
charHeight), disassemblySelectionColor.lighter(250));
|
||||
}
|
||||
|
||||
y += int(instr.text.lines.size()) * charHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// highlight program counter
|
||||
if (PCInBlock) {
|
||||
int y = block.y + (2 * charWidth) + (db.header_text.lines.size() * charHeight);
|
||||
@ -691,17 +721,48 @@ void DisassemblerGraphView::seekPrev()
|
||||
}
|
||||
}
|
||||
|
||||
DisassemblerGraphView::Token * DisassemblerGraphView::getToken(Instr * instr, int x)
|
||||
{
|
||||
int clickedCharPos = x / charWidth - 3;
|
||||
|
||||
if (clickedCharPos > instr->plainText.length()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const QRegularExpression tokenRegExp("\\b(?<!\\.)([^\\s]+)\\b(?!\\.)");
|
||||
QRegularExpressionMatchIterator i = tokenRegExp.globalMatch(instr->plainText);
|
||||
|
||||
while (i.hasNext()) {
|
||||
QRegularExpressionMatch match = i.next();
|
||||
|
||||
if (match.capturedStart() <= clickedCharPos && match.capturedEnd() > clickedCharPos) {
|
||||
Token * t = new Token;
|
||||
t->start = match.capturedStart();
|
||||
t->length = match.capturedLength();
|
||||
t->content = match.captured();
|
||||
t->instr = instr;
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::blockClicked(GraphView::GraphBlock &block, QMouseEvent *event,
|
||||
QPoint pos)
|
||||
{
|
||||
RVA instr = getAddrForMouseEvent(block, &pos);
|
||||
if (instr == RVA_INVALID) {
|
||||
Instr *instr = getInstrForMouseEvent(block, &pos);
|
||||
if (!instr) {
|
||||
return;
|
||||
}
|
||||
|
||||
seekLocal(instr);
|
||||
highlight_token = getToken(instr, pos.x());
|
||||
|
||||
mMenu->setOffset(instr);
|
||||
RVA addr = instr->addr;
|
||||
seekLocal(addr);
|
||||
|
||||
mMenu->setOffset(addr);
|
||||
if (event->button() == Qt::RightButton) {
|
||||
mMenu->exec(event->globalPos());
|
||||
}
|
||||
|
@ -17,38 +17,6 @@ class DisassemblerGraphView : public GraphView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
struct Token {
|
||||
int start; //token[0]
|
||||
int length; //token[1]
|
||||
QString type; //token[2]
|
||||
ut64 addr; //token[3]
|
||||
QString name; //token[4]
|
||||
};
|
||||
|
||||
struct HighlightToken {
|
||||
QString type; //highlight_token[0]
|
||||
ut64 addr; //highlight_token[1]
|
||||
QString name; //highlight_token[2]
|
||||
|
||||
bool equalsToken(const Token &token)
|
||||
{
|
||||
return this->type == token.type &&
|
||||
this->addr == token.addr &&
|
||||
this->name == token.name;
|
||||
}
|
||||
|
||||
static HighlightToken *fromToken(const Token &token)
|
||||
{
|
||||
//TODO: memory leaks
|
||||
auto result = new HighlightToken();
|
||||
result->type = token.type;
|
||||
result->addr = token.addr;
|
||||
result->name = token.name;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct Text {
|
||||
std::vector<RichTextPainter::List> lines;
|
||||
|
||||
@ -89,9 +57,18 @@ class DisassemblerGraphView : public GraphView
|
||||
ut64 size = 0;
|
||||
Text text;
|
||||
Text fullText;
|
||||
QString plainText;
|
||||
std::vector<unsigned char> opcode; //instruction bytes
|
||||
};
|
||||
|
||||
struct Token {
|
||||
int start;
|
||||
int length;
|
||||
QString type;
|
||||
Instr * instr;
|
||||
QString name;
|
||||
QString content;
|
||||
};
|
||||
|
||||
struct DisassemblyBlock {
|
||||
Text header_text;
|
||||
@ -176,7 +153,7 @@ private:
|
||||
bool first_draw = true;
|
||||
bool transition_dont_seek = false;
|
||||
|
||||
HighlightToken *highlight_token;
|
||||
Token *highlight_token;
|
||||
// Font data
|
||||
CachedFontMetrics *mFontMetrics;
|
||||
qreal charWidth;
|
||||
@ -190,6 +167,7 @@ private:
|
||||
|
||||
void initFont();
|
||||
void prepareGraphNode(GraphBlock &block);
|
||||
Token *getToken(Instr * instr, int x);
|
||||
RVA getAddrForMouseEvent(GraphBlock &block, QPoint *point);
|
||||
Instr *getInstrForMouseEvent(GraphBlock &block, QPoint *point);
|
||||
DisassemblyBlock *blockForAddress(RVA addr);
|
||||
|
Loading…
Reference in New Issue
Block a user