Refactored Decompiler Widget and R2Dec Plugin to use RAnnotatedCode (#2227)

This commit is contained in:
NIRMAL MANOJ C 2020-06-09 02:59:26 +05:30 committed by karliss
parent 498d2076c8
commit 255ffe1208
4 changed files with 76 additions and 102 deletions

View File

@ -5,42 +5,6 @@
#include <QJsonObject>
#include <QJsonArray>
ut64 AnnotatedCode::OffsetForPosition(size_t pos) const
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
for (const auto &annotation : annotations) {
if (annotation.type != CodeAnnotation::Type::Offset || annotation.start > pos || annotation.end <= pos) {
continue;
}
if (closestPos != SIZE_MAX && closestPos >= annotation.start) {
continue;
}
closestPos = annotation.start;
closestOffset = annotation.offset.offset;
}
return closestOffset;
}
size_t AnnotatedCode::PositionForOffset(ut64 offset) const
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
for (const auto &annotation : annotations) {
if (annotation.type != CodeAnnotation::Type::Offset || annotation.offset.offset > offset) {
continue;
}
if (closestOffset != UT64_MAX && closestOffset >= annotation.offset.offset) {
continue;
}
closestPos = annotation.start;
closestOffset = annotation.offset.offset;
}
return closestPos;
}
Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent)
: QObject(parent),
id(id),
@ -48,6 +12,11 @@ Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent)
{
}
RAnnotatedCode *Decompiler::makeWarning(QString warningMessage){
std::string temporary = warningMessage.toStdString();
return r_annotated_code_new(strdup(temporary.c_str()));
}
R2DecDecompiler::R2DecDecompiler(QObject *parent)
: Decompiler("r2dec", "r2dec", parent)
{
@ -64,26 +33,22 @@ void R2DecDecompiler::decompileAt(RVA addr)
if (task) {
return;
}
task = new R2Task("pddj @ " + QString::number(addr));
connect(task, &R2Task::finished, this, [this]() {
AnnotatedCode code = {};
QString s;
QJsonObject json = task->getResultJson().object();
delete task;
task = nullptr;
if (json.isEmpty()) {
code.code = tr("Failed to parse JSON from r2dec");
emit finished(code);
emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from r2dec")));
return;
}
RAnnotatedCode *code = r_annotated_code_new(nullptr);
QString codeString = "";
for (const auto &line : json["log"].toArray()) {
if (!line.isString()) {
continue;
}
code.code.append(line.toString() + "\n");
codeString.append(line.toString() + "\n");
}
auto linesArray = json["lines"].toArray();
@ -92,25 +57,24 @@ void R2DecDecompiler::decompileAt(RVA addr)
if (lineObject.isEmpty()) {
continue;
}
CodeAnnotation annotation = {};
annotation.type = CodeAnnotation::Type::Offset;
annotation.start = code.code.length();
code.code.append(lineObject["str"].toString() + "\n");
annotation.end = code.code.length();
RCodeAnnotation *annotationi = new RCodeAnnotation;
annotationi->start = codeString.length();
codeString.append(lineObject["str"].toString() + "\n");
annotationi->end = codeString.length();
bool ok;
annotation.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok);
if (ok) {
code.annotations.push_back(annotation);
}
annotationi->type = R_CODE_ANNOTATION_TYPE_OFFSET;
annotationi->offset.offset = lineObject["offset"].toVariant().toULongLong(&ok);
r_annotated_code_add_annotation(code, annotationi);
}
for (const auto &line : json["errors"].toArray()) {
if (!line.isString()) {
continue;
}
code.code.append(line.toString() + "\n");
codeString.append(line.toString() + "\n");
}
std::string tmp = codeString.toStdString();
code->code = strdup(tmp.c_str());
emit finished(code);
});
task->startTask();

View File

@ -3,43 +3,11 @@
#include "CutterCommon.h"
#include "R2Task.h"
#include <r_util/r_annotated_code.h>
#include <QString>
#include <QObject>
struct CodeAnnotation
{
size_t start;
size_t end;
enum class Type { Offset };
Type type;
union
{
struct
{
ut64 offset;
} offset;
};
};
/**
* Describes the result of a Decompilation Process with optional metadata
*/
struct AnnotatedCode
{
/**
* The entire decompiled code
*/
QString code;
QList<CodeAnnotation> annotations;
ut64 OffsetForPosition(size_t pos) const;
size_t PositionForOffset(ut64 offset) const;
};
/**
* Implements a decompiler that can be registered using CutterCore::registerDecompiler()
*/
@ -55,6 +23,8 @@ public:
Decompiler(const QString &id, const QString &name, QObject *parent = nullptr);
virtual ~Decompiler() = default;
static RAnnotatedCode *makeWarning(QString warningMessage);
QString getId() const { return id; }
QString getName() const { return name; }
virtual bool isRunning() { return false; }
@ -64,7 +34,7 @@ public:
virtual void cancel() {}
signals:
void finished(AnnotatedCode code);
void finished(RAnnotatedCode *codeDecompiled);
};
class R2DecDecompiler: public Decompiler

View File

@ -18,7 +18,8 @@
DecompilerWidget::DecompilerWidget(MainWindow *main) :
MemoryDockWidget(MemoryWidgetType::Decompiler, main),
mCtxMenu(new DisassemblyContextMenu(this, main)),
ui(new Ui::DecompilerWidget)
ui(new Ui::DecompilerWidget),
code(Decompiler::makeWarning(tr("Choose an offset and refresh to get decompiled code")), &r_annotated_code_free)
{
ui->setupUi(this);
@ -139,6 +140,45 @@ void DecompilerWidget::updateRefreshButton()
}
}
static ut64 offsetForPosition(RAnnotatedCode &codeDecompiled, size_t pos)
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
void *annotationi;
r_vector_foreach(&codeDecompiled.annotations, annotationi) {
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->start > pos
|| annotation->end <= pos) {
continue;
}
if (closestPos != SIZE_MAX && closestPos >= annotation->start) {
continue;
}
closestPos = annotation->start;
closestOffset = annotation->offset.offset;
}
return closestOffset;
}
static size_t positionForOffset(RAnnotatedCode &codeDecompiled, ut64 offset)
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
void *annotationi;
r_vector_foreach(&codeDecompiled.annotations, annotationi) {
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->offset.offset > offset) {
continue;
}
if (closestOffset != UT64_MAX && closestOffset >= annotation->offset.offset) {
continue;
}
closestPos = annotation->start;
closestOffset = annotation->offset.offset;
}
return closestPos;
}
void DecompilerWidget::doRefresh(RVA addr)
{
if (!refreshDeferrer->attemptRefresh(nullptr)) {
@ -183,7 +223,7 @@ void DecompilerWidget::refreshDecompiler()
QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
{
size_t pos = code.PositionForOffset(addr);
size_t pos = positionForOffset(*code, addr);
if (pos == SIZE_MAX || pos == 0) {
return QTextCursor();
}
@ -193,19 +233,20 @@ QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
return cursor;
}
void DecompilerWidget::decompilationFinished(AnnotatedCode code)
void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
{
ui->progressLabel->setVisible(false);
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
updateRefreshButton();
this->code = code;
if (code.code.isEmpty()) {
this->code.reset(codeDecompiled);
QString codeString = QString::fromUtf8(this->code->code);
if (codeString.isEmpty()) {
ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)"));
return;
} else {
connectCursorPositionChanged(true);
ui->textEdit->setPlainText(code.code);
ui->textEdit->setPlainText(codeString);
connectCursorPositionChanged(false);
updateCursorPosition();
highlightPC();
@ -244,7 +285,7 @@ void DecompilerWidget::cursorPositionChanged()
}
size_t pos = ui->textEdit->textCursor().position();
RVA offset = code.OffsetForPosition(pos);
RVA offset = offsetForPosition(*code, pos);
if (offset != RVA_INVALID && offset != Core()->getOffset()) {
seekFromCursor = true;
Core()->seek(offset);
@ -274,7 +315,7 @@ void DecompilerWidget::seekChanged()
void DecompilerWidget::updateCursorPosition()
{
RVA offset = Core()->getOffset();
size_t pos = code.PositionForOffset(offset);
size_t pos = positionForOffset(*code, offset);
if (pos == SIZE_MAX) {
return;
}
@ -334,7 +375,7 @@ void DecompilerWidget::showDisasContextMenu(const QPoint &pt)
void DecompilerWidget::seekToReference()
{
size_t pos = ui->textEdit->textCursor().position();
RVA offset = code.OffsetForPosition(pos);
RVA offset = offsetForPosition(*code, pos);
seekable->seekToReference(offset);
}
@ -352,7 +393,6 @@ bool DecompilerWidget::eventFilter(QObject *obj, QEvent *event)
return MemoryDockWidget::eventFilter(obj, event);
}
void DecompilerWidget::highlightPC()
{
RVA PCAddress = Core()->getProgramCounterValue();

View File

@ -38,7 +38,7 @@ private slots:
void decompilerSelected();
void cursorPositionChanged();
void seekChanged();
void decompilationFinished(AnnotatedCode code);
void decompilationFinished(RAnnotatedCode *code);
private:
std::unique_ptr<Ui::DecompilerWidget> ui;
@ -56,8 +56,7 @@ private:
bool decompilerWasBusy;
RVA decompiledFunctionAddr;
AnnotatedCode code;
std::unique_ptr<RAnnotatedCode, void (*)(RAnnotatedCode*)> code;
bool seekFromCursor = false;
Decompiler *getCurrentDecompiler();
@ -99,6 +98,7 @@ private:
* It will also run when a breakpoint is added, removed or modified.
*/
void highlightBreakpoints();
};
#endif // DECOMPILERWIDGET_H