diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index a80e3e0c..c35b8cf7 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -51,6 +51,7 @@ Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent) R2DecDecompiler::R2DecDecompiler(QObject *parent) : Decompiler("r2dec", "r2dec", parent) { + task = nullptr; } bool R2DecDecompiler::isAvailable() @@ -58,47 +59,59 @@ bool R2DecDecompiler::isAvailable() return Core()->cmdList("e cmd.pdc=?").contains(QStringLiteral("pdd")); } -AnnotatedCode R2DecDecompiler::decompileAt(RVA addr) +void R2DecDecompiler::decompileAt(RVA addr) { - AnnotatedCode code = {}; - QString s; - - QJsonObject json = Core()->cmdj("pddj @ " + QString::number(addr)).object(); - if (json.isEmpty()) { - return code; + if (task) { + return; } - for (const auto &line : json["log"].toArray()) { - if (!line.isString()) { - continue; - } - code.code.append(line.toString() + "\n"); - } + task = new R2Task("pddj @ " + QString::number(addr)); + connect(task, &R2Task::finished, this, [this]() { + AnnotatedCode code = {}; + QString s; - auto linesArray = json["lines"].toArray(); - for (const auto &line : linesArray) { - QJsonObject lineObject = line.toObject(); - if (lineObject.isEmpty()) { - continue; + QJsonObject json = task->getResultJson().object(); + delete task; + task = nullptr; + if (json.isEmpty()) { + code.code = tr("Failed to parse JSON from r2dec"); + emit finished(code); + return; } - CodeAnnotation annotation = {}; - annotation.type = CodeAnnotation::Type::Offset; - annotation.start = code.code.length(); - code.code.append(lineObject["str"].toString() + "\n"); - annotation.end = code.code.length(); - bool ok; - annotation.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok); - if (ok) { - code.annotations.push_back(annotation); - } - } - for (const auto &line : json["errors"].toArray()) { - if (!line.isString()) { - continue; + for (const auto &line : json["log"].toArray()) { + if (!line.isString()) { + continue; + } + code.code.append(line.toString() + "\n"); } - code.code.append(line.toString() + "\n"); - } - return code; -} \ No newline at end of file + auto linesArray = json["lines"].toArray(); + for (const auto &line : linesArray) { + QJsonObject lineObject = line.toObject(); + 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(); + bool ok; + annotation.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok); + if (ok) { + code.annotations.push_back(annotation); + } + } + + for (const auto &line : json["errors"].toArray()) { + if (!line.isString()) { + continue; + } + code.code.append(line.toString() + "\n"); + } + + emit finished(code); + }); + task->startTask(); +} diff --git a/src/common/Decompiler.h b/src/common/Decompiler.h index 87c564f3..cd88d4ec 100644 --- a/src/common/Decompiler.h +++ b/src/common/Decompiler.h @@ -2,6 +2,7 @@ #define DECOMPILER_H #include "CutterCommon.h" +#include "R2Task.h" #include #include @@ -54,19 +55,30 @@ public: Decompiler(const QString &id, const QString &name, QObject *parent = nullptr); virtual ~Decompiler() = default; - QString getId() const { return id; } - QString getName() const { return name; } + QString getId() const { return id; } + QString getName() const { return name; } + virtual bool isRunning() { return false; } + virtual bool isCancelable() { return false; } - virtual AnnotatedCode decompileAt(RVA addr) =0; + virtual void decompileAt(RVA addr) =0; + virtual void cancel() {} + +signals: + void finished(AnnotatedCode code); }; class R2DecDecompiler: public Decompiler { Q_OBJECT +private: + R2Task *task; + public: explicit R2DecDecompiler(QObject *parent = nullptr); - AnnotatedCode decompileAt(RVA addr) override; + void decompileAt(RVA addr) override; + + bool isRunning() override { return task != nullptr; } static bool isAvailable(); }; diff --git a/src/common/R2Task.cpp b/src/common/R2Task.cpp index f3e539e4..82c2e253 100644 --- a/src/common/R2Task.cpp +++ b/src/common/R2Task.cpp @@ -47,6 +47,11 @@ QString R2Task::getResult() return QString::fromUtf8(task->res); } +QJsonDocument R2Task::getResultJson() +{ + return Core()->parseJson(task->res, task->cmd); +} + const char *R2Task::getResultRaw() { return task->res; diff --git a/src/common/R2Task.h b/src/common/R2Task.h index 5dc8d8a9..d4efcace 100644 --- a/src/common/R2Task.h +++ b/src/common/R2Task.h @@ -23,6 +23,7 @@ public: void joinTask(); QString getResult(); + QJsonDocument getResultJson(); const char *getResultRaw(); signals: diff --git a/src/widgets/PseudocodeWidget.cpp b/src/widgets/PseudocodeWidget.cpp index a5fba078..24ac23ac 100644 --- a/src/widgets/PseudocodeWidget.cpp +++ b/src/widgets/PseudocodeWidget.cpp @@ -41,13 +41,14 @@ PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) : if (dec->getId() == selectedDecompilerId) { ui->decompilerComboBox->setCurrentIndex(ui->decompilerComboBox->count() - 1); } + connect(dec, &Decompiler::finished, this, &PseudocodeWidget::decompilationFinished); } - if(decompilers.size() <= 1) { - ui->decompilerComboBox->setEnabled(false); - if (decompilers.isEmpty()) { - ui->textEdit->setPlainText(tr("No Decompiler available.")); - } + decompilerSelectionEnabled = decompilers.size() > 1; + ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled); + + if (decompilers.isEmpty()) { + ui->textEdit->setPlainText(tr("No Decompiler available.")); } connect(ui->decompilerComboBox, static_cast(&QComboBox::currentIndexChanged), this, &PseudocodeWidget::decompilerSelected); @@ -61,6 +62,7 @@ PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) : connect(mCtxMenu, &QMenu::triggered, this, &PseudocodeWidget::refreshPseudocode); addActions(mCtxMenu->actions()); + ui->progressLabel->setVisible(false); doRefresh(RVA_INVALID); } @@ -74,7 +76,7 @@ void PseudocodeWidget::doRefresh(RVA addr) } Decompiler *dec = Core()->getDecompilerById(ui->decompilerComboBox->currentData().toString()); - if (!dec) { + if (!dec || dec->isRunning()) { return; } @@ -83,10 +85,34 @@ void PseudocodeWidget::doRefresh(RVA addr) return; } - code = dec->decompileAt(addr); + dec->decompileAt(addr); + if (dec->isRunning()) { + ui->progressLabel->setVisible(true); + ui->decompilerComboBox->setEnabled(false); + if (dec->isCancelable()) { + ui->refreshButton->setText(tr("Cancel")); + } else { + ui->refreshButton->setEnabled(false); + } + return; + } +} + +void PseudocodeWidget::refreshPseudocode() +{ + doRefresh(Core()->getOffset()); +} + +void PseudocodeWidget::decompilationFinished(AnnotatedCode code) +{ + ui->progressLabel->setVisible(false); + ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled); + ui->refreshButton->setText(tr("Refresh")); + ui->refreshButton->setEnabled(true); + + this->code = code; if (code.code.isEmpty()) { - ui->textEdit->setPlainText(tr("Cannot decompile at") + " " + RAddressString( - addr) + " " + tr("(Not a function?)")); + ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)")); return; } else { connectCursorPositionChanged(true); @@ -96,11 +122,6 @@ void PseudocodeWidget::doRefresh(RVA addr) } } -void PseudocodeWidget::refreshPseudocode() -{ - doRefresh(Core()->getOffset()); -} - void PseudocodeWidget::decompilerSelected() { Config()->setSelectedDecompiler(ui->decompilerComboBox->currentData().toString()); diff --git a/src/widgets/PseudocodeWidget.h b/src/widgets/PseudocodeWidget.h index 11f200c4..b701a14f 100644 --- a/src/widgets/PseudocodeWidget.h +++ b/src/widgets/PseudocodeWidget.h @@ -36,11 +36,13 @@ private slots: void decompilerSelected(); void cursorPositionChanged(); void seekChanged(); + void decompilationFinished(AnnotatedCode code); private: std::unique_ptr ui; QSyntaxHighlighter *syntaxHighlighter; + bool decompilerSelectionEnabled; AnnotatedCode code; diff --git a/src/widgets/PseudocodeWidget.ui b/src/widgets/PseudocodeWidget.ui index 733d2f7f..00fe5f0f 100644 --- a/src/widgets/PseudocodeWidget.ui +++ b/src/widgets/PseudocodeWidget.ui @@ -49,6 +49,20 @@ + + + + 8 + + + + + Decompiling... + + + + + @@ -70,7 +84,7 @@ - +