mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 19:06:10 +00:00
Synchronized Decompiler and Enabling Multiple Decompiler Widgets (#2402)
* Sync/Unsync decompiler widgets. * Add multiple decompiler widgets with its own decompiler and functions. * updateWindowTitle() in widgets for decompiler, disassembly, and hexdump.
This commit is contained in:
parent
ec22b01086
commit
691de14853
@ -59,6 +59,12 @@ Show Types
|
|||||||
|
|
||||||
**Steps:** Windows -> Types
|
**Steps:** Windows -> Types
|
||||||
|
|
||||||
|
Add a new instance of the Decompiler Widget
|
||||||
|
----------------------------------------------
|
||||||
|
**Description:** Create a new instance of the Decompiler widget in order to view multiple decompiled functions using multiple supported decompilers.
|
||||||
|
|
||||||
|
**Steps:** Windows -> Add Decompiler
|
||||||
|
|
||||||
Add a new instance of the Disassembly Widget
|
Add a new instance of the Disassembly Widget
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
**Description:** Create a new instance of the Disassembly widget in order to view one or multiple locations at the same time.
|
**Description:** Create a new instance of the Disassembly widget in order to view one or multiple locations at the same time.
|
||||||
|
@ -812,13 +812,13 @@ int CutterCore::sizeofDataMeta(RVA addr)
|
|||||||
void CutterCore::setComment(RVA addr, const QString &cmt)
|
void CutterCore::setComment(RVA addr, const QString &cmt)
|
||||||
{
|
{
|
||||||
cmdRawAt(QString("CCu base64:%1").arg(QString(cmt.toLocal8Bit().toBase64())), addr);
|
cmdRawAt(QString("CCu base64:%1").arg(QString(cmt.toLocal8Bit().toBase64())), addr);
|
||||||
emit commentsChanged();
|
emit commentsChanged(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::delComment(RVA addr)
|
void CutterCore::delComment(RVA addr)
|
||||||
{
|
{
|
||||||
cmdRawAt("CC-", addr);
|
cmdRawAt("CC-", addr);
|
||||||
emit commentsChanged();
|
emit commentsChanged(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -647,7 +647,7 @@ signals:
|
|||||||
void varsChanged();
|
void varsChanged();
|
||||||
void functionsChanged();
|
void functionsChanged();
|
||||||
void flagsChanged();
|
void flagsChanged();
|
||||||
void commentsChanged();
|
void commentsChanged(RVA addr);
|
||||||
void registersChanged();
|
void registersChanged();
|
||||||
void instructionChanged(RVA offset);
|
void instructionChanged(RVA offset);
|
||||||
void breakpointsChanged(RVA offset);
|
void breakpointsChanged(RVA offset);
|
||||||
|
@ -143,6 +143,7 @@ void MainWindow::initUI()
|
|||||||
disassemblyContextMenuExtensions = new QMenu(tr("Plugins"), this);
|
disassemblyContextMenuExtensions = new QMenu(tr("Plugins"), this);
|
||||||
addressableContextMenuExtensions = new QMenu(tr("Plugins"), this);
|
addressableContextMenuExtensions = new QMenu(tr("Plugins"), this);
|
||||||
|
|
||||||
|
connect(ui->actionExtraDecompiler, &QAction::triggered, this, &MainWindow::addExtraDecompiler);
|
||||||
connect(ui->actionExtraGraph, &QAction::triggered, this, &MainWindow::addExtraGraph);
|
connect(ui->actionExtraGraph, &QAction::triggered, this, &MainWindow::addExtraGraph);
|
||||||
connect(ui->actionExtraDisassembly, &QAction::triggered, this, &MainWindow::addExtraDisassembly);
|
connect(ui->actionExtraDisassembly, &QAction::triggered, this, &MainWindow::addExtraDisassembly);
|
||||||
connect(ui->actionExtraHexdump, &QAction::triggered, this, &MainWindow::addExtraHexdump);
|
connect(ui->actionExtraHexdump, &QAction::triggered, this, &MainWindow::addExtraHexdump);
|
||||||
@ -347,7 +348,6 @@ void MainWindow::initToolBar()
|
|||||||
void MainWindow::initDocks()
|
void MainWindow::initDocks()
|
||||||
{
|
{
|
||||||
dockWidgets.reserve(20);
|
dockWidgets.reserve(20);
|
||||||
decompilerDock = new DecompilerWidget(this);
|
|
||||||
consoleDock = new ConsoleWidget(this);
|
consoleDock = new ConsoleWidget(this);
|
||||||
|
|
||||||
overviewDock = new OverviewWidget(this);
|
overviewDock = new OverviewWidget(this);
|
||||||
@ -415,7 +415,6 @@ void MainWindow::initDocks()
|
|||||||
dashboardDock,
|
dashboardDock,
|
||||||
nullptr,
|
nullptr,
|
||||||
functionsDock,
|
functionsDock,
|
||||||
decompilerDock,
|
|
||||||
overviewDock,
|
overviewDock,
|
||||||
nullptr,
|
nullptr,
|
||||||
searchDock,
|
searchDock,
|
||||||
@ -423,7 +422,7 @@ void MainWindow::initDocks()
|
|||||||
typesDock,
|
typesDock,
|
||||||
nullptr,
|
nullptr,
|
||||||
};
|
};
|
||||||
ui->menuWindows->insertActions(ui->actionExtraDisassembly, makeActionList(windowDocks));
|
ui->menuWindows->insertActions(ui->actionExtraDecompiler, makeActionList(windowDocks));
|
||||||
QList<CutterDockWidget *> windowDocks2 = {
|
QList<CutterDockWidget *> windowDocks2 = {
|
||||||
consoleDock,
|
consoleDock,
|
||||||
commentsDock,
|
commentsDock,
|
||||||
@ -475,6 +474,12 @@ void MainWindow::addExtraDisassembly()
|
|||||||
addExtraWidget(extraDock);
|
addExtraWidget(extraDock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::addExtraDecompiler()
|
||||||
|
{
|
||||||
|
auto *extraDock = new DecompilerWidget(this);
|
||||||
|
addExtraWidget(extraDock);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::addExtraWidget(CutterDockWidget *extraDock)
|
void MainWindow::addExtraWidget(CutterDockWidget *extraDock)
|
||||||
{
|
{
|
||||||
extraDock->setTransient(true);
|
extraDock->setTransient(true);
|
||||||
@ -820,7 +825,6 @@ void MainWindow::restoreDocks()
|
|||||||
splitDockWidget(functionsDock, overviewDock, Qt::Vertical);
|
splitDockWidget(functionsDock, overviewDock, Qt::Vertical);
|
||||||
|
|
||||||
// main area
|
// main area
|
||||||
tabifyDockWidget(dashboardDock, decompilerDock);
|
|
||||||
tabifyDockWidget(dashboardDock, entrypointDock);
|
tabifyDockWidget(dashboardDock, entrypointDock);
|
||||||
tabifyDockWidget(dashboardDock, flagsDock);
|
tabifyDockWidget(dashboardDock, flagsDock);
|
||||||
tabifyDockWidget(dashboardDock, stringsDock);
|
tabifyDockWidget(dashboardDock, stringsDock);
|
||||||
@ -989,7 +993,7 @@ QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address, AddressTypeHi
|
|||||||
createAddNewWidgetAction(tr("New graph"), MemoryWidgetType::Graph);
|
createAddNewWidgetAction(tr("New graph"), MemoryWidgetType::Graph);
|
||||||
}
|
}
|
||||||
createAddNewWidgetAction(tr("New hexdump"), MemoryWidgetType::Hexdump);
|
createAddNewWidgetAction(tr("New hexdump"), MemoryWidgetType::Hexdump);
|
||||||
|
createAddNewWidgetAction(tr("New Decompiler"), MemoryWidgetType::Decompiler);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +168,7 @@ private slots:
|
|||||||
void addExtraGraph();
|
void addExtraGraph();
|
||||||
void addExtraHexdump();
|
void addExtraHexdump();
|
||||||
void addExtraDisassembly();
|
void addExtraDisassembly();
|
||||||
|
void addExtraDecompiler();
|
||||||
|
|
||||||
void on_actionRefresh_Panels_triggered();
|
void on_actionRefresh_Panels_triggered();
|
||||||
|
|
||||||
@ -236,7 +237,6 @@ private:
|
|||||||
|
|
||||||
QList<CutterDockWidget *> dockWidgets;
|
QList<CutterDockWidget *> dockWidgets;
|
||||||
QList<CutterDockWidget *> pluginDocks;
|
QList<CutterDockWidget *> pluginDocks;
|
||||||
DecompilerWidget *decompilerDock = nullptr;
|
|
||||||
OverviewWidget *overviewDock = nullptr;
|
OverviewWidget *overviewDock = nullptr;
|
||||||
QAction *actionOverview = nullptr;
|
QAction *actionOverview = nullptr;
|
||||||
EntrypointWidget *entrypointDock = nullptr;
|
EntrypointWidget *entrypointDock = nullptr;
|
||||||
|
@ -162,6 +162,7 @@
|
|||||||
<string>Debug...</string>
|
<string>Debug...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
<addaction name="actionExtraDecompiler"/>
|
||||||
<addaction name="actionExtraDisassembly"/>
|
<addaction name="actionExtraDisassembly"/>
|
||||||
<addaction name="actionExtraGraph"/>
|
<addaction name="actionExtraGraph"/>
|
||||||
<addaction name="actionExtraHexdump"/>
|
<addaction name="actionExtraHexdump"/>
|
||||||
@ -756,6 +757,11 @@
|
|||||||
<string>Add Hexdump</string>
|
<string>Add Hexdump</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionExtraDecompiler">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Decompiler</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionExtraDisassembly">
|
<action name="actionExtraDisassembly">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add Disassembly</string>
|
<string>Add Disassembly</string>
|
||||||
|
@ -147,7 +147,7 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates targeted "Show in" menu.
|
* @brief Updates targeted "Show in" menu.
|
||||||
*
|
*
|
||||||
* Removes all actions from the existing targeted "show in" menu. If annotationHere
|
* Removes all actions from the existing targeted "show in" menu. If annotationHere
|
||||||
* represents an item that has an address assigned to it, insert actions compatible with the
|
* represents an item that has an address assigned to it, insert actions compatible with the
|
||||||
* type of this item in the targeted "Show in" menu.
|
* type of this item in the targeted "Show in" menu.
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "common/SelectionHighlight.h"
|
#include "common/SelectionHighlight.h"
|
||||||
#include "common/Decompiler.h"
|
#include "common/Decompiler.h"
|
||||||
#include "common/CutterSeekable.h"
|
#include "common/CutterSeekable.h"
|
||||||
|
#include "core/MainWindow.h"
|
||||||
|
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
@ -22,7 +23,8 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
MemoryDockWidget(MemoryWidgetType::Decompiler, main),
|
MemoryDockWidget(MemoryWidgetType::Decompiler, main),
|
||||||
mCtxMenu(new DecompilerContextMenu(this, main)),
|
mCtxMenu(new DecompilerContextMenu(this, main)),
|
||||||
ui(new Ui::DecompilerWidget),
|
ui(new Ui::DecompilerWidget),
|
||||||
decompilerWasBusy(false),
|
decompilerBusy(false),
|
||||||
|
seekFromCursor(false),
|
||||||
scrollerHorizontal(0),
|
scrollerHorizontal(0),
|
||||||
scrollerVertical(0),
|
scrollerVertical(0),
|
||||||
previousFunctionAddr(RVA_INVALID),
|
previousFunctionAddr(RVA_INVALID),
|
||||||
@ -31,6 +33,11 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
&r_annotated_code_free)
|
&r_annotated_code_free)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
setObjectName(main
|
||||||
|
? main->getUniqueObjectName(tr("Decompiler"))
|
||||||
|
: tr("Decompiler"));
|
||||||
|
updateWindowTitle();
|
||||||
|
|
||||||
syntaxHighlighter = Config()->createSyntaxHighlighter(ui->textEdit->document());
|
syntaxHighlighter = Config()->createSyntaxHighlighter(ui->textEdit->document());
|
||||||
// Event filter to intercept double click and right click in the textbox
|
// Event filter to intercept double click and right click in the textbox
|
||||||
ui->textEdit->viewport()->installEventFilter(this);
|
ui->textEdit->viewport()->installEventFilter(this);
|
||||||
@ -43,33 +50,21 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
connect(Core(), &CutterCore::registersChanged, this, &DecompilerWidget::highlightPC);
|
connect(Core(), &CutterCore::registersChanged, this, &DecompilerWidget::highlightPC);
|
||||||
connect(mCtxMenu, &DecompilerContextMenu::copy, this, &DecompilerWidget::copy);
|
connect(mCtxMenu, &DecompilerContextMenu::copy, this, &DecompilerWidget::copy);
|
||||||
|
|
||||||
connect(ui->refreshButton, &QAbstractButton::clicked, this, [this]() {
|
|
||||||
doRefresh();
|
|
||||||
});
|
|
||||||
refreshDeferrer = createRefreshDeferrer([this]() {
|
refreshDeferrer = createRefreshDeferrer([this]() {
|
||||||
doRefresh();
|
doRefresh();
|
||||||
});
|
});
|
||||||
autoRefreshEnabled = Config()->getDecompilerAutoRefreshEnabled();
|
|
||||||
ui->autoRefreshCheckBox->setChecked(autoRefreshEnabled);
|
|
||||||
setAutoRefresh(autoRefreshEnabled);
|
|
||||||
connect(ui->autoRefreshCheckBox, &QCheckBox::stateChanged, this, [this](int state) {
|
|
||||||
setAutoRefresh(state == Qt::Checked);
|
|
||||||
Config()->setDecompilerAutoRefreshEnabled(autoRefreshEnabled);
|
|
||||||
doAutoRefresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto decompilers = Core()->getDecompilers();
|
auto decompilers = Core()->getDecompilers();
|
||||||
auto selectedDecompilerId = Config()->getSelectedDecompiler();
|
QString selectedDecompilerId = Config()->getSelectedDecompiler();
|
||||||
if (selectedDecompilerId.isEmpty()) {
|
if (selectedDecompilerId.isEmpty()) {
|
||||||
// If no decompiler was previously chosen. set r2ghidra as default decompiler
|
// If no decompiler was previously chosen. set r2ghidra as default decompiler
|
||||||
selectedDecompilerId = "r2ghidra";
|
selectedDecompilerId = "r2ghidra";
|
||||||
}
|
}
|
||||||
for (auto dec : decompilers) {
|
for (Decompiler *dec : decompilers) {
|
||||||
ui->decompilerComboBox->addItem(dec->getName(), dec->getId());
|
ui->decompilerComboBox->addItem(dec->getName(), dec->getId());
|
||||||
if (dec->getId() == selectedDecompilerId) {
|
if (dec->getId() == selectedDecompilerId) {
|
||||||
ui->decompilerComboBox->setCurrentIndex(ui->decompilerComboBox->count() - 1);
|
ui->decompilerComboBox->setCurrentIndex(ui->decompilerComboBox->count() - 1);
|
||||||
}
|
}
|
||||||
connect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
|
|
||||||
}
|
}
|
||||||
decompilerSelectionEnabled = decompilers.size() > 1;
|
decompilerSelectionEnabled = decompilers.size() > 1;
|
||||||
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
|
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
|
||||||
@ -80,26 +75,28 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
connect(ui->decompilerComboBox,
|
connect(ui->decompilerComboBox,
|
||||||
static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||||
&DecompilerWidget::decompilerSelected);
|
&DecompilerWidget::decompilerSelected);
|
||||||
connectCursorPositionChanged(false);
|
connectCursorPositionChanged(true);
|
||||||
connect(Core(), &CutterCore::seekChanged, this, &DecompilerWidget::seekChanged);
|
connect(seekable, &CutterSeekable::seekableSeekChanged, this, &DecompilerWidget::seekChanged);
|
||||||
ui->textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(ui->textEdit, &QWidget::customContextMenuRequested,
|
connect(ui->textEdit, &QWidget::customContextMenuRequested,
|
||||||
this, &DecompilerWidget::showDecompilerContextMenu);
|
this, &DecompilerWidget::showDecompilerContextMenu);
|
||||||
|
|
||||||
connect(Core(), &CutterCore::breakpointsChanged, this, &DecompilerWidget::updateBreakpoints);
|
connect(Core(), &CutterCore::breakpointsChanged, this, &DecompilerWidget::updateBreakpoints);
|
||||||
|
mCtxMenu->addSeparator();
|
||||||
|
mCtxMenu->addAction(&syncAction);
|
||||||
addActions(mCtxMenu->actions());
|
addActions(mCtxMenu->actions());
|
||||||
|
|
||||||
ui->progressLabel->setVisible(false);
|
ui->progressLabel->setVisible(false);
|
||||||
doRefresh(RVA_INVALID);
|
doRefresh();
|
||||||
|
|
||||||
connect(Core(), &CutterCore::refreshAll, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::refreshAll, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::functionRenamed, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::functionRenamed, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::varsChanged, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::varsChanged, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::functionsChanged, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::functionsChanged, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::flagsChanged, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::flagsChanged, this, &DecompilerWidget::doRefresh);
|
||||||
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::refreshIfChanged);
|
||||||
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::refreshIfChanged);
|
||||||
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doAutoRefresh);
|
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doRefresh);
|
||||||
|
|
||||||
// Esc to seek backward
|
// Esc to seek backward
|
||||||
QAction *seekPrevAction = new QAction(this);
|
QAction *seekPrevAction = new QAction(this);
|
||||||
@ -116,31 +113,6 @@ Decompiler *DecompilerWidget::getCurrentDecompiler()
|
|||||||
return Core()->getDecompilerById(ui->decompilerComboBox->currentData().toString());
|
return Core()->getDecompilerById(ui->decompilerComboBox->currentData().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::setAutoRefresh(bool enabled)
|
|
||||||
{
|
|
||||||
autoRefreshEnabled = enabled;
|
|
||||||
updateRefreshButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecompilerWidget::doAutoRefresh()
|
|
||||||
{
|
|
||||||
if (!autoRefreshEnabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
doRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecompilerWidget::updateRefreshButton()
|
|
||||||
{
|
|
||||||
Decompiler *dec = getCurrentDecompiler();
|
|
||||||
ui->refreshButton->setEnabled(!autoRefreshEnabled && dec && !dec->isRunning());
|
|
||||||
if (dec && dec->isRunning() && dec->isCancelable()) {
|
|
||||||
ui->refreshButton->setText(tr("Cancel"));
|
|
||||||
} else {
|
|
||||||
ui->refreshButton->setText(tr("Refresh"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ut64 DecompilerWidget::offsetForPosition(size_t pos)
|
ut64 DecompilerWidget::offsetForPosition(size_t pos)
|
||||||
{
|
{
|
||||||
size_t closestPos = SIZE_MAX;
|
size_t closestPos = SIZE_MAX;
|
||||||
@ -180,8 +152,11 @@ size_t DecompilerWidget::positionForOffset(ut64 offset)
|
|||||||
return closestPos;
|
return closestPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::updateBreakpoints()
|
void DecompilerWidget::updateBreakpoints(RVA addr)
|
||||||
{
|
{
|
||||||
|
if (!addressInRange(addr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setInfoForBreakpoints();
|
setInfoForBreakpoints();
|
||||||
QTextCursor cursor = ui->textEdit->textCursor();
|
QTextCursor cursor = ui->textEdit->textCursor();
|
||||||
cursor.select(QTextCursor::Document);
|
cursor.select(QTextCursor::Document);
|
||||||
@ -195,8 +170,9 @@ void DecompilerWidget::updateBreakpoints()
|
|||||||
|
|
||||||
void DecompilerWidget::setInfoForBreakpoints()
|
void DecompilerWidget::setInfoForBreakpoints()
|
||||||
{
|
{
|
||||||
if (mCtxMenu->getIsTogglingBreakpoints())
|
if (mCtxMenu->getIsTogglingBreakpoints()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// Get the range of the line
|
// Get the range of the line
|
||||||
QTextCursor cursorForLine = ui->textEdit->textCursor();
|
QTextCursor cursorForLine = ui->textEdit->textCursor();
|
||||||
cursorForLine.movePosition(QTextCursor::StartOfLine);
|
cursorForLine.movePosition(QTextCursor::StartOfLine);
|
||||||
@ -224,7 +200,7 @@ void DecompilerWidget::gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size
|
|||||||
mCtxMenu->setFirstOffsetInLine(firstOffset);
|
mCtxMenu->setFirstOffsetInLine(firstOffset);
|
||||||
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
|
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
|
||||||
QVector<RVA> offsetList;
|
QVector<RVA> offsetList;
|
||||||
for (auto bpOffset : functionBreakpoints) {
|
for (RVA bpOffset : functionBreakpoints) {
|
||||||
size_t pos = positionForOffset(bpOffset);
|
size_t pos = positionForOffset(bpOffset);
|
||||||
if (startPos <= pos && pos <= endPos) {
|
if (startPos <= pos && pos <= endPos) {
|
||||||
offsetList.push_back(bpOffset);
|
offsetList.push_back(bpOffset);
|
||||||
@ -234,8 +210,16 @@ void DecompilerWidget::gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size
|
|||||||
mCtxMenu->setAvailableBreakpoints(offsetList);
|
mCtxMenu->setAvailableBreakpoints(offsetList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::doRefresh(RVA addr)
|
void DecompilerWidget::refreshIfChanged(RVA addr)
|
||||||
{
|
{
|
||||||
|
if (addressInRange(addr)) {
|
||||||
|
doRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecompilerWidget::doRefresh()
|
||||||
|
{
|
||||||
|
RVA addr = seekable->getOffset();
|
||||||
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -246,26 +230,36 @@ void DecompilerWidget::doRefresh(RVA addr)
|
|||||||
if (!dec) {
|
if (!dec) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Disabling decompiler selection combo box and making progress label visible ahead of decompilation.
|
||||||
|
ui->progressLabel->setVisible(true);
|
||||||
|
ui->decompilerComboBox->setEnabled(false);
|
||||||
if (dec->isRunning()) {
|
if (dec->isRunning()) {
|
||||||
decompilerWasBusy = true;
|
if (!decompilerBusy) {
|
||||||
return;
|
connect(dec, &Decompiler::finished, this, &DecompilerWidget::doRefresh);
|
||||||
}
|
}
|
||||||
if (addr == RVA_INVALID) {
|
|
||||||
ui->textEdit->setPlainText(tr("Click Refresh to generate Decompiler from current offset."));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
disconnect(dec, &Decompiler::finished, this, &DecompilerWidget::doRefresh);
|
||||||
// Clear all selections since we just refreshed
|
// Clear all selections since we just refreshed
|
||||||
ui->textEdit->setExtraSelections({});
|
ui->textEdit->setExtraSelections({});
|
||||||
previousFunctionAddr = decompiledFunctionAddr;
|
previousFunctionAddr = decompiledFunctionAddr;
|
||||||
decompiledFunctionAddr = Core()->getFunctionStart(addr);
|
decompiledFunctionAddr = Core()->getFunctionStart(addr);
|
||||||
mCtxMenu->setDecompiledFunctionAddress(decompiledFunctionAddr);
|
updateWindowTitle();
|
||||||
dec->decompileAt(addr);
|
if (decompiledFunctionAddr == RVA_INVALID) {
|
||||||
if (dec->isRunning()) {
|
// No function was found, so making the progress label invisible and enabling
|
||||||
ui->progressLabel->setVisible(true);
|
// the decompiler selection combo box as we are not waiting for any decompilation to finish.
|
||||||
ui->decompilerComboBox->setEnabled(false);
|
ui->progressLabel->setVisible(false);
|
||||||
updateRefreshButton();
|
ui->decompilerComboBox->setEnabled(true);
|
||||||
|
connectCursorPositionChanged(false);
|
||||||
|
ui->textEdit->setPlainText(
|
||||||
|
tr("No function found at this offset. Seek to a function or define one in order to decompile it."));
|
||||||
|
connectCursorPositionChanged(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mCtxMenu->setDecompiledFunctionAddress(decompiledFunctionAddr);
|
||||||
|
connect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
|
||||||
|
decompilerBusy = true;
|
||||||
|
dec->decompileAt(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::refreshDecompiler()
|
void DecompilerWidget::refreshDecompiler()
|
||||||
@ -296,26 +290,43 @@ void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
|
|||||||
|
|
||||||
ui->progressLabel->setVisible(false);
|
ui->progressLabel->setVisible(false);
|
||||||
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
|
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
|
||||||
updateRefreshButton();
|
|
||||||
|
|
||||||
mCtxMenu->setAnnotationHere(nullptr);
|
mCtxMenu->setAnnotationHere(nullptr);
|
||||||
this->code.reset(codeDecompiled);
|
this->code.reset(codeDecompiled);
|
||||||
|
|
||||||
|
Decompiler *dec = getCurrentDecompiler();
|
||||||
|
QObject::disconnect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
|
||||||
|
decompilerBusy = false;
|
||||||
|
|
||||||
QString codeString = QString::fromUtf8(this->code->code);
|
QString codeString = QString::fromUtf8(this->code->code);
|
||||||
if (codeString.isEmpty()) {
|
if (codeString.isEmpty()) {
|
||||||
|
connectCursorPositionChanged(false);
|
||||||
ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)"));
|
ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)"));
|
||||||
|
connectCursorPositionChanged(true);
|
||||||
|
lowestOffsetInCode = RVA_MAX;
|
||||||
|
highestOffsetInCode = 0;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
connectCursorPositionChanged(true);
|
|
||||||
ui->textEdit->setPlainText(codeString);
|
|
||||||
connectCursorPositionChanged(false);
|
connectCursorPositionChanged(false);
|
||||||
|
ui->textEdit->setPlainText(codeString);
|
||||||
|
connectCursorPositionChanged(true);
|
||||||
updateCursorPosition();
|
updateCursorPosition();
|
||||||
highlightPC();
|
highlightPC();
|
||||||
highlightBreakpoints();
|
highlightBreakpoints();
|
||||||
}
|
lowestOffsetInCode = RVA_MAX;
|
||||||
|
highestOffsetInCode = 0;
|
||||||
if (decompilerWasBusy) {
|
void *iter;
|
||||||
decompilerWasBusy = false;
|
r_vector_foreach(&code->annotations, iter) {
|
||||||
doAutoRefresh();
|
RCodeAnnotation *annotation = (RCodeAnnotation *)iter;
|
||||||
|
if (annotation->type == R_CODE_ANNOTATION_TYPE_OFFSET) {
|
||||||
|
if (lowestOffsetInCode > annotation->offset.offset) {
|
||||||
|
lowestOffsetInCode = annotation->offset.offset;
|
||||||
|
}
|
||||||
|
if (highestOffsetInCode < annotation->offset.offset) {
|
||||||
|
highestOffsetInCode = annotation->offset.offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDisplayReset) {
|
if (isDisplayReset) {
|
||||||
@ -344,16 +355,14 @@ void DecompilerWidget::setAnnotationsAtCursor(size_t pos)
|
|||||||
void DecompilerWidget::decompilerSelected()
|
void DecompilerWidget::decompilerSelected()
|
||||||
{
|
{
|
||||||
Config()->setSelectedDecompiler(ui->decompilerComboBox->currentData().toString());
|
Config()->setSelectedDecompiler(ui->decompilerComboBox->currentData().toString());
|
||||||
if (autoRefreshEnabled) {
|
doRefresh();
|
||||||
doRefresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::connectCursorPositionChanged(bool disconnect)
|
void DecompilerWidget::connectCursorPositionChanged(bool connectPositionChange)
|
||||||
{
|
{
|
||||||
if (disconnect) {
|
if (!connectPositionChange) {
|
||||||
QObject::disconnect(ui->textEdit, &QPlainTextEdit::cursorPositionChanged, this,
|
disconnect(ui->textEdit, &QPlainTextEdit::cursorPositionChanged, this,
|
||||||
&DecompilerWidget::cursorPositionChanged);
|
&DecompilerWidget::cursorPositionChanged);
|
||||||
} else {
|
} else {
|
||||||
connect(ui->textEdit, &QPlainTextEdit::cursorPositionChanged, this,
|
connect(ui->textEdit, &QPlainTextEdit::cursorPositionChanged, this,
|
||||||
&DecompilerWidget::cursorPositionChanged);
|
&DecompilerWidget::cursorPositionChanged);
|
||||||
@ -372,9 +381,9 @@ void DecompilerWidget::cursorPositionChanged()
|
|||||||
setInfoForBreakpoints();
|
setInfoForBreakpoints();
|
||||||
|
|
||||||
RVA offset = offsetForPosition(pos);
|
RVA offset = offsetForPosition(pos);
|
||||||
if (offset != RVA_INVALID && offset != Core()->getOffset()) {
|
if (offset != RVA_INVALID && offset != seekable->getOffset()) {
|
||||||
seekFromCursor = true;
|
seekFromCursor = true;
|
||||||
Core()->seek(offset);
|
seekable->seek(offset);
|
||||||
mCtxMenu->setOffset(offset);
|
mCtxMenu->setOffset(offset);
|
||||||
seekFromCursor = false;
|
seekFromCursor = false;
|
||||||
}
|
}
|
||||||
@ -386,30 +395,28 @@ void DecompilerWidget::seekChanged()
|
|||||||
if (seekFromCursor) {
|
if (seekFromCursor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (autoRefreshEnabled) {
|
RVA fcnAddr = Core()->getFunctionStart(seekable->getOffset());
|
||||||
auto fcnAddr = Core()->getFunctionStart(Core()->getOffset());
|
if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) {
|
||||||
if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) {
|
doRefresh();
|
||||||
doRefresh();
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
updateCursorPosition();
|
updateCursorPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::updateCursorPosition()
|
void DecompilerWidget::updateCursorPosition()
|
||||||
{
|
{
|
||||||
RVA offset = Core()->getOffset();
|
RVA offset = seekable->getOffset();
|
||||||
size_t pos = positionForOffset(offset);
|
size_t pos = positionForOffset(offset);
|
||||||
if (pos == SIZE_MAX) {
|
if (pos == SIZE_MAX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mCtxMenu->setOffset(offset);
|
mCtxMenu->setOffset(offset);
|
||||||
connectCursorPositionChanged(true);
|
connectCursorPositionChanged(false);
|
||||||
QTextCursor cursor = ui->textEdit->textCursor();
|
QTextCursor cursor = ui->textEdit->textCursor();
|
||||||
cursor.setPosition(pos);
|
cursor.setPosition(pos);
|
||||||
ui->textEdit->setTextCursor(cursor);
|
ui->textEdit->setTextCursor(cursor);
|
||||||
updateSelection();
|
updateSelection();
|
||||||
connectCursorPositionChanged(false);
|
connectCursorPositionChanged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::setupFonts()
|
void DecompilerWidget::setupFonts()
|
||||||
@ -422,7 +429,7 @@ void DecompilerWidget::updateSelection()
|
|||||||
QList<QTextEdit::ExtraSelection> extraSelections;
|
QList<QTextEdit::ExtraSelection> extraSelections;
|
||||||
|
|
||||||
// Highlight the current line
|
// Highlight the current line
|
||||||
auto cursor = ui->textEdit->textCursor();
|
QTextCursor cursor = ui->textEdit->textCursor();
|
||||||
extraSelections.append(createLineHighlightSelection(cursor));
|
extraSelections.append(createLineHighlightSelection(cursor));
|
||||||
|
|
||||||
// Highlight all the words in the document same as the current one
|
// Highlight all the words in the document same as the current one
|
||||||
@ -438,7 +445,14 @@ void DecompilerWidget::updateSelection()
|
|||||||
|
|
||||||
QString DecompilerWidget::getWindowTitle() const
|
QString DecompilerWidget::getWindowTitle() const
|
||||||
{
|
{
|
||||||
return tr("Decompiler");
|
RAnalFunction *fcn = Core()->functionAt(decompiledFunctionAddr);
|
||||||
|
QString windowTitle = tr("Decompiler");
|
||||||
|
if (fcn != NULL) {
|
||||||
|
windowTitle += " (" + QString(fcn->name) + ")";
|
||||||
|
} else {
|
||||||
|
windowTitle += " (Empty)";
|
||||||
|
}
|
||||||
|
return windowTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::fontsUpdatedSlot()
|
void DecompilerWidget::fontsUpdatedSlot()
|
||||||
@ -501,7 +515,7 @@ void DecompilerWidget::highlightBreakpoints()
|
|||||||
|
|
||||||
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
|
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
|
||||||
QTextCursor cursor;
|
QTextCursor cursor;
|
||||||
for (auto &bp : functionBreakpoints) {
|
for (RVA &bp : functionBreakpoints) {
|
||||||
if (bp == RVA_INVALID) {
|
if (bp == RVA_INVALID) {
|
||||||
continue;;
|
continue;;
|
||||||
}
|
}
|
||||||
@ -539,3 +553,11 @@ void DecompilerWidget::copy()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DecompilerWidget::addressInRange(RVA addr)
|
||||||
|
{
|
||||||
|
if (lowestOffsetInCode <= addr && addr <= highestOffsetInCode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -47,7 +47,7 @@ private slots:
|
|||||||
void cursorPositionChanged();
|
void cursorPositionChanged();
|
||||||
/**
|
/**
|
||||||
* @brief When the synced seek is changed, this refreshes the decompiler widget if needed.
|
* @brief When the synced seek is changed, this refreshes the decompiler widget if needed.
|
||||||
*
|
*
|
||||||
* Decompiler widget is not refreshed in the following two cases
|
* Decompiler widget is not refreshed in the following two cases
|
||||||
* - Seek changed to an offset contained in the decompiled function.
|
* - Seek changed to an offset contained in the decompiled function.
|
||||||
* - Auto-refresh is disabled.
|
* - Auto-refresh is disabled.
|
||||||
@ -62,36 +62,45 @@ private:
|
|||||||
|
|
||||||
QSyntaxHighlighter *syntaxHighlighter;
|
QSyntaxHighlighter *syntaxHighlighter;
|
||||||
bool decompilerSelectionEnabled;
|
bool decompilerSelectionEnabled;
|
||||||
bool autoRefreshEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if doRefresh() was called, but the decompiler was still running.
|
* True if the selected decompiler is currently running a decompilation for this widget. Once the decompilation
|
||||||
* This means, after the decompiler has finished, it should be refreshed immediately.
|
* is over, this should be set to false.
|
||||||
*/
|
*/
|
||||||
bool decompilerWasBusy;
|
bool decompilerBusy;
|
||||||
|
|
||||||
|
bool seekFromCursor;
|
||||||
int scrollerHorizontal;
|
int scrollerHorizontal;
|
||||||
int scrollerVertical;
|
int scrollerVertical;
|
||||||
RVA previousFunctionAddr;
|
RVA previousFunctionAddr;
|
||||||
RVA decompiledFunctionAddr;
|
RVA decompiledFunctionAddr;
|
||||||
std::unique_ptr<RAnnotatedCode, void (*)(RAnnotatedCode *)> code;
|
std::unique_ptr<RAnnotatedCode, void (*)(RAnnotatedCode *)> code;
|
||||||
bool seekFromCursor = false;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the lowest offset of instructions among all the instructions in the decompiled function.
|
||||||
|
*/
|
||||||
|
RVA lowestOffsetInCode;
|
||||||
|
/**
|
||||||
|
* Specifies the highest offset of instructions among all the instructions in the decompiled function.
|
||||||
|
*/
|
||||||
|
RVA highestOffsetInCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current decompiler selected by the user.
|
||||||
|
*
|
||||||
|
* @return A pointer to the currently selected decompiler
|
||||||
|
*/
|
||||||
Decompiler *getCurrentDecompiler();
|
Decompiler *getCurrentDecompiler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enable/Disable auto refresh as per the specified boolean value
|
* @brief Calls the function doRefresh() if the address specified is a part of the decompiled function.
|
||||||
*
|
*
|
||||||
* @param enabled
|
* @param addr Address at which a change occurred.
|
||||||
*/
|
*/
|
||||||
void setAutoRefresh(bool enabled);
|
void refreshIfChanged(RVA addr);
|
||||||
/**
|
|
||||||
* @brief Calls the function doRefresh() if auto-refresh is enabled.
|
|
||||||
*/
|
|
||||||
void doAutoRefresh();
|
|
||||||
/**
|
/**
|
||||||
* @brief Refreshes the decompiler.
|
* @brief Refreshes the decompiler.
|
||||||
*
|
*
|
||||||
* - This does the following if the specified offset is valid
|
* - This does the following if the specified offset is valid
|
||||||
* - Decompile function that contains the specified offset.
|
* - Decompile function that contains the specified offset.
|
||||||
* - Clears all selections stored for highlighting purposes.
|
* - Clears all selections stored for highlighting purposes.
|
||||||
@ -102,15 +111,14 @@ private:
|
|||||||
*
|
*
|
||||||
* @param addr Specified offset/offset in sync.
|
* @param addr Specified offset/offset in sync.
|
||||||
*/
|
*/
|
||||||
void doRefresh(RVA addr = Core()->getOffset());
|
void doRefresh();
|
||||||
void updateRefreshButton();
|
|
||||||
/**
|
/**
|
||||||
* @brief Update fonts
|
* @brief Update fonts
|
||||||
*/
|
*/
|
||||||
void setupFonts();
|
void setupFonts();
|
||||||
/**
|
/**
|
||||||
* @brief Update highlights in the text widget.
|
* @brief Update highlights in the text widget.
|
||||||
*
|
*
|
||||||
* These include respective highlights for:
|
* These include respective highlights for:
|
||||||
* - Line under cursor
|
* - Line under cursor
|
||||||
* - Word under cursor
|
* - Word under cursor
|
||||||
@ -120,13 +128,13 @@ private:
|
|||||||
/**
|
/**
|
||||||
* @brief Connect/Disconnect SIGNAL-SLOT connection that deals with changes in cursor position.
|
* @brief Connect/Disconnect SIGNAL-SLOT connection that deals with changes in cursor position.
|
||||||
*
|
*
|
||||||
* If the argument is true, then disconnect the SIGNAL-SLOT connection
|
* If the argument is true, then connect the SIGNAL-SLOT connection
|
||||||
* that changes the view as cursor position gets changed in the text widget.
|
* that changes the view as cursor position gets changed in the text widget.
|
||||||
* Otherwise, connect the corresponding signal with slot.
|
* Otherwise, disconnect the corresponding signal with slot.
|
||||||
*
|
*
|
||||||
* @param disconnect
|
* @param connectPositionChange
|
||||||
*/
|
*/
|
||||||
void connectCursorPositionChanged(bool disconnect);
|
void connectCursorPositionChanged(bool connectPositionChange);
|
||||||
/**
|
/**
|
||||||
* @brief Find the current global offset in sync and update cursor
|
* @brief Find the current global offset in sync and update cursor
|
||||||
* to the position specified by this offset (found using positionForOffset() )
|
* to the position specified by this offset (found using positionForOffset() )
|
||||||
@ -167,7 +175,7 @@ private:
|
|||||||
bool colorLine(QTextEdit::ExtraSelection extraSelection);
|
bool colorLine(QTextEdit::ExtraSelection extraSelection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function responsible to highlight all the breakpoints in the decompiler view.
|
* @brief This function is responsible for highlighting all the breakpoints in the decompiler view.
|
||||||
* It will also run when a breakpoint is added, removed or modified.
|
* It will also run when a breakpoint is added, removed or modified.
|
||||||
*/
|
*/
|
||||||
void highlightBreakpoints();
|
void highlightBreakpoints();
|
||||||
@ -205,7 +213,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* @brief Updates the view when breakpoints are changed
|
* @brief Updates the view when breakpoints are changed
|
||||||
*/
|
*/
|
||||||
void updateBreakpoints();
|
void updateBreakpoints(RVA addr);
|
||||||
/**
|
/**
|
||||||
* @brief Set information about the breakpoints on the line in the context menu
|
* @brief Set information about the breakpoints on the line in the context menu
|
||||||
*/
|
*/
|
||||||
@ -217,6 +225,13 @@ private:
|
|||||||
* @param pos Position of cursor in the decompiled code.
|
* @param pos Position of cursor in the decompiled code.
|
||||||
*/
|
*/
|
||||||
void setAnnotationsAtCursor(size_t pos);
|
void setAnnotationsAtCursor(size_t pos);
|
||||||
|
/**
|
||||||
|
* @brief Checks if the specified address is a part of the decompiled function.
|
||||||
|
*
|
||||||
|
* @param addr An offset in the binary.
|
||||||
|
* @return True if the specified is a part of the decompiled function, False otherwise.
|
||||||
|
*/
|
||||||
|
bool addressInRange(RVA addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DECOMPILERWIDGET_H
|
#endif // DECOMPILERWIDGET_H
|
||||||
|
@ -42,20 +42,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="autoRefreshCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Auto Refresh</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="refreshButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Refresh</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="progressLayout">
|
<layout class="QHBoxLayout" name="progressLayout">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
|
@ -42,7 +42,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
|
|||||||
auto *layout = new QVBoxLayout(this);
|
auto *layout = new QVBoxLayout(this);
|
||||||
// Signals that require a refresh all
|
// Signals that require a refresh all
|
||||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshView()));
|
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshView()));
|
||||||
connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshView()));
|
connect(Core(), &CutterCore::commentsChanged, this, &DisassemblerGraphView::refreshView);
|
||||||
connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView);
|
connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView);
|
||||||
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshView()));
|
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshView()));
|
||||||
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshView()));
|
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshView()));
|
||||||
|
@ -48,14 +48,13 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main)
|
|||||||
setObjectName(main
|
setObjectName(main
|
||||||
? main->getUniqueObjectName(getWidgetType())
|
? main->getUniqueObjectName(getWidgetType())
|
||||||
: getWidgetType());
|
: getWidgetType());
|
||||||
|
updateWindowTitle();
|
||||||
|
|
||||||
topOffset = bottomOffset = RVA_INVALID;
|
topOffset = bottomOffset = RVA_INVALID;
|
||||||
cursorLineOffset = 0;
|
cursorLineOffset = 0;
|
||||||
cursorCharOffset = 0;
|
cursorCharOffset = 0;
|
||||||
seekFromCursor = false;
|
seekFromCursor = false;
|
||||||
|
|
||||||
setWindowTitle(getWindowTitle());
|
|
||||||
|
|
||||||
// Instantiate the window layout
|
// Instantiate the window layout
|
||||||
auto *splitter = new QSplitter;
|
auto *splitter = new QSplitter;
|
||||||
|
|
||||||
@ -145,7 +144,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshDisasm()));
|
connect(Core(), &CutterCore::commentsChanged, this, [this]() {refreshDisasm();});
|
||||||
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshDisasm()));
|
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshDisasm()));
|
||||||
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshDisasm()));
|
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshDisasm()));
|
||||||
connect(Core(), &CutterCore::functionRenamed, this, [this]() {refreshDisasm();});
|
connect(Core(), &CutterCore::functionRenamed, this, [this]() {refreshDisasm();});
|
||||||
|
@ -26,6 +26,7 @@ HexdumpWidget::HexdumpWidget(MainWindow *main) :
|
|||||||
setObjectName(main
|
setObjectName(main
|
||||||
? main->getUniqueObjectName(getWidgetType())
|
? main->getUniqueObjectName(getWidgetType())
|
||||||
: getWidgetType());
|
: getWidgetType());
|
||||||
|
updateWindowTitle();
|
||||||
|
|
||||||
ui->copyMD5->setIcon(QIcon(":/img/icons/copy.svg"));
|
ui->copyMD5->setIcon(QIcon(":/img/icons/copy.svg"));
|
||||||
ui->copySHA1->setIcon(QIcon(":/img/icons/copy.svg"));
|
ui->copySHA1->setIcon(QIcon(":/img/icons/copy.svg"));
|
||||||
@ -76,8 +77,6 @@ HexdumpWidget::HexdumpWidget(MainWindow *main) :
|
|||||||
" border-color : #3daee9"
|
" border-color : #3daee9"
|
||||||
"}");
|
"}");
|
||||||
|
|
||||||
setWindowTitle(getWindowTitle());
|
|
||||||
|
|
||||||
refreshDeferrer = createReplacingRefreshDeferrer<RVA>(false, [this](const RVA *offset) {
|
refreshDeferrer = createReplacingRefreshDeferrer<RVA>(false, [this](const RVA *offset) {
|
||||||
refresh(offset ? *offset : RVA_INVALID);
|
refresh(offset ? *offset : RVA_INVALID);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user