From 8bc7213b8c571b5684a3e2f741129d160ec00dc0 Mon Sep 17 00:00:00 2001 From: "Thomas (nezza-_-) Roth" Date: Thu, 7 Dec 2017 00:19:14 +0100 Subject: [PATCH] Add basic Pseudocode tab (Fixes #142) (#184) * Add basic Pseudocode tab (Fixes #142) * Add missing include to fix Windows build * PseudocodeWidget: Move refreshPseudocode to slots to silence warning --- src/MainWindow.cpp | 6 ++ src/MainWindow.h | 2 + src/cutter.cpp | 5 ++ src/cutter.h | 5 +- src/cutter.pro | 9 ++- src/widgets/PseudocodeWidget.cpp | 103 +++++++++++++++++++++++++++++++ src/widgets/PseudocodeWidget.h | 40 ++++++++++++ src/widgets/PseudocodeWidget.ui | 23 +++++++ 8 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 src/widgets/PseudocodeWidget.cpp create mode 100644 src/widgets/PseudocodeWidget.h create mode 100644 src/widgets/PseudocodeWidget.ui diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index bdc1f34c..6dce720a 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -99,6 +99,7 @@ MainWindow::MainWindow(QWidget *parent) : relocsDock(nullptr), commentsDock(nullptr), stringsDock(nullptr), + pseudocodeDock(nullptr), flagsDock(nullptr), dashboardDock(nullptr), gotoEntry(nullptr), @@ -191,6 +192,9 @@ void MainWindow::initUI() hexdumpDock = new HexdumpWidget(tr("Hexdump"), this); dockWidgets.push_back(hexdumpDock); + pseudocodeDock = new PseudocodeWidget(tr("Pseudocode"), this); + dockWidgets.push_back(pseudocodeDock); + // Add graph view as dockable graphDock = new QDockWidget(tr("Graph"), this); graphDock->setObjectName("Graph"); @@ -659,6 +663,7 @@ void MainWindow::restoreDocks() tabifyDockWidget(dashboardDock, disassemblyDock); tabifyDockWidget(dashboardDock, graphDock); tabifyDockWidget(dashboardDock, hexdumpDock); + tabifyDockWidget(dashboardDock, pseudocodeDock); tabifyDockWidget(dashboardDock, entrypointDock); tabifyDockWidget(dashboardDock, flagsDock); tabifyDockWidget(dashboardDock, stringsDock); @@ -695,6 +700,7 @@ void MainWindow::showDefaultDocks() disassemblyDock, sidebarDock, hexdumpDock, + pseudocodeDock, dashboardDock }; diff --git a/src/MainWindow.h b/src/MainWindow.h index 8d916227..87878433 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -8,6 +8,7 @@ #include "widgets/DisassemblerGraphView.h" #include "widgets/SidebarWidget.h" #include "widgets/HexdumpWidget.h" +#include "widgets/PseudocodeWidget.h" #include "utils/Configuration.h" #include @@ -169,6 +170,7 @@ private: DisassemblyWidget *disassemblyDock; SidebarWidget *sidebarDock; HexdumpWidget *hexdumpDock; + PseudocodeWidget *pseudocodeDock; QDockWidget *graphDock; DisassemblerGraphView *graphView; QDockWidget *asmDock; diff --git a/src/cutter.cpp b/src/cutter.cpp index 09ccabc1..b9568b51 100644 --- a/src/cutter.cpp +++ b/src/cutter.cpp @@ -721,6 +721,11 @@ RVA CutterCore::getOffsetJump(RVA addr) return value; } +QString CutterCore::getDecompiledCode(RVA addr) +{ + return cmd("pdc @ " + QString::number(addr)); +} + QString CutterCore::getDecompiledCode(QString addr) { return cmd("pdc @ " + addr); diff --git a/src/cutter.h b/src/cutter.h index b72e8a5f..4f479936 100644 --- a/src/cutter.h +++ b/src/cutter.h @@ -225,8 +225,8 @@ public: RVA prevOpAddr(RVA startAddr, int count); RVA nextOpAddr(RVA startAddr, int count); - // Disassembly/Graph/Hexdump view priority - enum class MemoryWidgetType { Disassembly, Graph, Hexdump }; + // Disassembly/Graph/Hexdump/Pseudocode view priority + enum class MemoryWidgetType { Disassembly, Graph, Hexdump, Pseudocode }; MemoryWidgetType getMemoryWidgetPriority() const { return memoryWidgetPriority; } void setMemoryWidgetPriority(MemoryWidgetType type) { memoryWidgetPriority = type; } void triggerRaisePrioritizedMemoryWidget() { emit raisePrioritizedMemoryWidget(memoryWidgetPriority); } @@ -262,6 +262,7 @@ public: QList> get_exec_sections(); QString getOffsetInfo(QString addr); RVA getOffsetJump(RVA addr); + QString getDecompiledCode(RVA addr); QString getDecompiledCode(QString addr); QString getFileInfo(); QStringList getStats(); diff --git a/src/cutter.pro b/src/cutter.pro index b5c6b125..2b0139a0 100644 --- a/src/cutter.pro +++ b/src/cutter.pro @@ -79,7 +79,8 @@ SOURCES += \ utils/Colors.cpp \ dialogs/SaveProjectDialog.cpp \ utils/TempConfig.cpp \ - utils/SvgIconEngine.cpp + utils/SvgIconEngine.cpp \ + widgets/PseudocodeWidget.cpp HEADERS += \ cutter.h \ @@ -129,7 +130,8 @@ HEADERS += \ utils/Colors.h \ dialogs/SaveProjectDialog.h \ utils/TempConfig.h \ - utils/SvgIconEngine.h + utils/SvgIconEngine.h \ + widgets/PseudocodeWidget.h FORMS += \ dialogs/AboutDialog.ui \ @@ -159,7 +161,8 @@ FORMS += \ widgets/SymbolsWidget.ui \ widgets/SidebarWidget.ui \ widgets/HexdumpWidget.ui \ - dialogs/SaveProjectDialog.ui + dialogs/SaveProjectDialog.ui \ + widgets/PseudocodeWidget.ui RESOURCES += \ resources.qrc diff --git a/src/widgets/PseudocodeWidget.cpp b/src/widgets/PseudocodeWidget.cpp new file mode 100644 index 00000000..7dda87a8 --- /dev/null +++ b/src/widgets/PseudocodeWidget.cpp @@ -0,0 +1,103 @@ +#include "PseudocodeWidget.h" +#include "ui_PseudocodeWidget.h" + +#include "utils/Configuration.h" +#include "utils/Helpers.h" +#include "utils/TempConfig.h" + +PseudocodeWidget::PseudocodeWidget(QWidget *parent, Qt::WindowFlags flags) : + QDockWidget(parent, flags), + ui(new Ui::PseudocodeWidget) +{ + ui->setupUi(this); + + setupFonts(); + colorsUpdatedSlot(); + + connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated())); + connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot())); + + connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshPseudocode())); + connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshPseudocode())); + connect(Core(), SIGNAL(functionRenamed(QString, QString)), this, SLOT(refreshPseudocode())); + connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshPseudocode())); + connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshPseudocode())); + connect(Core(), &CutterCore::instructionChanged, this, [this](RVA offset) { + refreshPseudocode(); + }); + + + + + connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA))); + connect(Core(), SIGNAL(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)), this, SLOT(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType))); + connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) { + if (visibility) + { + Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Pseudocode); + } + }); + + // Get alerted when there's a refresh + connect(Core(), &CutterCore::refreshAll, this, [this]() { + refresh(Core()->getOffset()); + }); + + refresh(Core()->getOffset()); +} + +PseudocodeWidget::PseudocodeWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags) + : PseudocodeWidget(parent, flags) +{ + setWindowTitle(title); +} + +PseudocodeWidget::~PseudocodeWidget() {} + + +void PseudocodeWidget::on_seekChanged(RVA addr) +{ + refresh(addr); +} + +void PseudocodeWidget::refresh(RVA addr) +{ + QString decompiledCode = Core()->getDecompiledCode(addr); + if (decompiledCode.length() == 0) + { + decompiledCode = tr("Cannot decompile at") + " " + RAddressString(addr) + " " + tr("(Not a function?)"); + } + ui->pseudocodeTextBrowser->setText(decompiledCode); +} + +void PseudocodeWidget::refreshPseudocode() +{ + refresh(Core()->getOffset()); +} + +void PseudocodeWidget::raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type) +{ + if (type == CutterCore::MemoryWidgetType::Pseudocode) + { + raise(); + } +} + +void PseudocodeWidget::setupFonts() +{ + QFont font = Config()->getFont(); + ui->pseudocodeTextBrowser->setFont(font); +} + +void PseudocodeWidget::fontsUpdated() +{ + setupFonts(); +} + +void PseudocodeWidget::colorsUpdatedSlot() +{ + QString styleSheet = QString("QTextBrowser { background-color: %1; color: %2; }") + .arg(ConfigColor("gui.background").name()) + .arg(ConfigColor("btext").name()); + ui->pseudocodeTextBrowser->setStyleSheet(styleSheet); +} diff --git a/src/widgets/PseudocodeWidget.h b/src/widgets/PseudocodeWidget.h new file mode 100644 index 00000000..8b7434b0 --- /dev/null +++ b/src/widgets/PseudocodeWidget.h @@ -0,0 +1,40 @@ +#ifndef PSEUDOCODEWIDGET_H +#define PSEUDOCODEWIDGET_H + +#include +#include + +#include "ui_PseudocodeWidget.h" +#include "cutter.h" + +namespace Ui +{ + class PseudocodeWidget; +} + +class PseudocodeWidget : public QDockWidget +{ +Q_OBJECT + +public: + explicit PseudocodeWidget(const QString &title, QWidget *parent = nullptr, Qt::WindowFlags flags = 0); + explicit PseudocodeWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = 0); + ~PseudocodeWidget(); + +private: + std::unique_ptr ui; + void refresh(RVA addr); + void setupFonts(); + +signals: + +public slots: +private slots: + void on_seekChanged(RVA addr); + void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type); + void fontsUpdated(); + void colorsUpdatedSlot(); + void refreshPseudocode(); +}; + +#endif // PSEUDOCODEWIDGET_H diff --git a/src/widgets/PseudocodeWidget.ui b/src/widgets/PseudocodeWidget.ui new file mode 100644 index 00000000..be117bfc --- /dev/null +++ b/src/widgets/PseudocodeWidget.ui @@ -0,0 +1,23 @@ + + + PseudocodeWidget + + + + 0 + 0 + 686 + 646 + + + + 0 + + + Form + + + + + +