mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 19:06:10 +00:00
Refactored Decompiler Widget and R2Dec Plugin to use RAnnotatedCode (#2227)
This commit is contained in:
parent
498d2076c8
commit
255ffe1208
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user