Fetch disassembly with pdJ (Fixes #177) (#210)

* Use pdJ for DisassemblyWidget
* Attach DisassemblyLine to QTextBlock in DisassemblyWidget
This commit is contained in:
Florian Märkl 2017-12-13 15:30:00 +01:00 committed by xarkes
parent fb796d0758
commit 4213852419
4 changed files with 64 additions and 46 deletions

View File

@ -1,5 +1,6 @@
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
#include <utils/TempConfig.h>
#include "utils/Configuration.h" #include "utils/Configuration.h"
#include "cutter.h" #include "cutter.h"
#include "sdb.h" #include "sdb.h"
@ -1331,3 +1332,22 @@ void CutterCore::setNotes(const QString &notes)
this->notes = notes; this->notes = notes;
emit notesChanged(this->notes); emit notesChanged(this->notes);
} }
QList<DisassemblyLine> CutterCore::disassembleLines(RVA offset, int lines)
{
QJsonArray array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") + QString::number(offset)).array();
QList<DisassemblyLine> r;
for (QJsonValue value : array)
{
QJsonObject object = value.toObject();
DisassemblyLine line;
line.offset = object["offset"].toVariant().toULongLong();
line.text = object["text"].toString();
r << line;
}
return r;
}

View File

@ -168,6 +168,12 @@ struct RBinPluginDescription
QString type; QString type;
}; };
struct DisassemblyLine
{
RVA offset;
QString text;
};
Q_DECLARE_METATYPE(FunctionDescription) Q_DECLARE_METATYPE(FunctionDescription)
Q_DECLARE_METATYPE(ImportDescription) Q_DECLARE_METATYPE(ImportDescription)
Q_DECLARE_METATYPE(ExportDescription) Q_DECLARE_METATYPE(ExportDescription)
@ -202,6 +208,9 @@ public:
QString cmd(const QString &str); QString cmd(const QString &str);
QJsonDocument cmdj(const QString &str); QJsonDocument cmdj(const QString &str);
QStringList cmdList(const QString &str) { auto l = cmd(str).split("\n"); l.removeAll(""); return l; } QStringList cmdList(const QString &str) { auto l = cmd(str).split("\n"); l.removeAll(""); return l; }
QList<DisassemblyLine> disassembleLines(RVA offset, int lines);
void renameFunction(QString prev_name, QString new_name); void renameFunction(QString prev_name, QString new_name);
void delFunction(RVA addr); void delFunction(RVA addr);
void renameFlag(QString old_name, QString new_name); void renameFlag(QString old_name, QString new_name);

View File

@ -11,6 +11,19 @@
#include <QJsonObject> #include <QJsonObject>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QRegularExpression> #include <QRegularExpression>
#include <QTextBlockUserData>
class DisassemblyTextBlockUserData: public QTextBlockUserData
{
public:
DisassemblyLine line;
explicit DisassemblyTextBlockUserData(const DisassemblyLine &line)
{
this->line = line;
}
};
DisassemblyWidget::DisassemblyWidget(QWidget *parent) DisassemblyWidget::DisassemblyWidget(QWidget *parent)
@ -126,25 +139,6 @@ QWidget* DisassemblyWidget::getTextWidget()
return mDisasTextEdit; return mDisasTextEdit;
} }
QString DisassemblyWidget::readDisasm(const QString &cmd, bool stripLastNewline)
{
TempConfig tempConfig;
tempConfig.set("scr.html", true)
.set("scr.color", true);
QString disas = Core()->cmd(cmd);
if (stripLastNewline)
{
// ugly hack to remove trailing newline
static const auto trimBrRegExp = QRegularExpression("<br />$");
disas = disas.remove(trimBrRegExp);
}
return disas.trimmed();
}
void DisassemblyWidget::refreshDisasm(RVA offset) void DisassemblyWidget::refreshDisasm(RVA offset)
{ {
if (offset != RVA_INVALID) if (offset != RVA_INVALID)
@ -168,11 +162,25 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value(); int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value();
mDisasTextEdit->setLockScroll(true); // avoid flicker mDisasTextEdit->setLockScroll(true); // avoid flicker
QString disas = readDisasm("pd " + QString::number(maxLines) + "@" + QString::number(topOffset), true); QList<DisassemblyLine> disassemblyLines;
{
TempConfig tempConfig;
tempConfig.set("scr.html", true)
.set("scr.color", true);
disassemblyLines = Core()->disassembleLines(topOffset, maxLines);
}
connectCursorPositionChanged(true); connectCursorPositionChanged(true);
mDisasTextEdit->document()->setHtml(disas); mDisasTextEdit->document()->clear();
QTextCursor cursor(mDisasTextEdit->document());
for (DisassemblyLine line : disassemblyLines)
{
cursor.insertHtml(line.text);
auto a = new DisassemblyTextBlockUserData(line);
cursor.block().setUserData(a);
cursor.insertBlock();
}
// get bottomOffset from last visible line. // get bottomOffset from last visible line.
// because pd N may return more than N lines, move maxLines lines down from the top // because pd N may return more than N lines, move maxLines lines down from the top
@ -307,32 +315,14 @@ RVA DisassemblyWidget::readCurrentDisassemblyOffset()
RVA DisassemblyWidget::readDisassemblyOffset(QTextCursor tc) RVA DisassemblyWidget::readDisassemblyOffset(QTextCursor tc)
{ {
// TODO: do this in a different way without parsing the disassembly text QTextBlockUserData *userData = tc.block().userData();
if (!userData)
static const QRegularExpression offsetRegExp("^0x[0-9A-Fa-f]*");
while (true)
{ {
tc.select(QTextCursor::LineUnderCursor);
QString line = tc.selectedText();
auto match = offsetRegExp.match(line);
if (match.hasMatch())
{
return match.captured(0).toULongLong(nullptr, 16);
}
tc.movePosition(QTextCursor::StartOfLine);
if (tc.atStart())
{
break;
}
tc.movePosition(QTextCursor::Up);
}
return RVA_INVALID; return RVA_INVALID;
}
auto *dsUserData = static_cast<DisassemblyTextBlockUserData *>(userData);
return dsUserData->line.offset;
} }
void DisassemblyWidget::updateCursorPosition() void DisassemblyWidget::updateCursorPosition()

View File

@ -46,7 +46,6 @@ private:
RVA bottomOffset; RVA bottomOffset;
int maxLines; int maxLines;
QString readDisasm(const QString &cmd, bool stripLastNewline);
RVA readCurrentDisassemblyOffset(); RVA readCurrentDisassemblyOffset();
RVA readDisassemblyOffset(QTextCursor tc); RVA readDisassemblyOffset(QTextCursor tc);
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);