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:
NIRMAL MANOJ C 2020-08-29 10:45:47 +05:30 committed by GitHub
parent ec22b01086
commit 691de14853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 185 additions and 148 deletions

View File

@ -59,6 +59,12 @@ Show 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
----------------------------------------------
**Description:** Create a new instance of the Disassembly widget in order to view one or multiple locations at the same time.

View File

@ -812,13 +812,13 @@ int CutterCore::sizeofDataMeta(RVA addr)
void CutterCore::setComment(RVA addr, const QString &cmt)
{
cmdRawAt(QString("CCu base64:%1").arg(QString(cmt.toLocal8Bit().toBase64())), addr);
emit commentsChanged();
emit commentsChanged(addr);
}
void CutterCore::delComment(RVA addr)
{
cmdRawAt("CC-", addr);
emit commentsChanged();
emit commentsChanged(addr);
}
/**

View File

@ -647,7 +647,7 @@ signals:
void varsChanged();
void functionsChanged();
void flagsChanged();
void commentsChanged();
void commentsChanged(RVA addr);
void registersChanged();
void instructionChanged(RVA offset);
void breakpointsChanged(RVA offset);

View File

@ -143,6 +143,7 @@ void MainWindow::initUI()
disassemblyContextMenuExtensions = 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->actionExtraDisassembly, &QAction::triggered, this, &MainWindow::addExtraDisassembly);
connect(ui->actionExtraHexdump, &QAction::triggered, this, &MainWindow::addExtraHexdump);
@ -347,7 +348,6 @@ void MainWindow::initToolBar()
void MainWindow::initDocks()
{
dockWidgets.reserve(20);
decompilerDock = new DecompilerWidget(this);
consoleDock = new ConsoleWidget(this);
overviewDock = new OverviewWidget(this);
@ -415,7 +415,6 @@ void MainWindow::initDocks()
dashboardDock,
nullptr,
functionsDock,
decompilerDock,
overviewDock,
nullptr,
searchDock,
@ -423,7 +422,7 @@ void MainWindow::initDocks()
typesDock,
nullptr,
};
ui->menuWindows->insertActions(ui->actionExtraDisassembly, makeActionList(windowDocks));
ui->menuWindows->insertActions(ui->actionExtraDecompiler, makeActionList(windowDocks));
QList<CutterDockWidget *> windowDocks2 = {
consoleDock,
commentsDock,
@ -475,6 +474,12 @@ void MainWindow::addExtraDisassembly()
addExtraWidget(extraDock);
}
void MainWindow::addExtraDecompiler()
{
auto *extraDock = new DecompilerWidget(this);
addExtraWidget(extraDock);
}
void MainWindow::addExtraWidget(CutterDockWidget *extraDock)
{
extraDock->setTransient(true);
@ -820,7 +825,6 @@ void MainWindow::restoreDocks()
splitDockWidget(functionsDock, overviewDock, Qt::Vertical);
// main area
tabifyDockWidget(dashboardDock, decompilerDock);
tabifyDockWidget(dashboardDock, entrypointDock);
tabifyDockWidget(dashboardDock, flagsDock);
tabifyDockWidget(dashboardDock, stringsDock);
@ -989,7 +993,7 @@ QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address, AddressTypeHi
createAddNewWidgetAction(tr("New graph"), MemoryWidgetType::Graph);
}
createAddNewWidgetAction(tr("New hexdump"), MemoryWidgetType::Hexdump);
createAddNewWidgetAction(tr("New Decompiler"), MemoryWidgetType::Decompiler);
return menu;
}

View File

@ -168,6 +168,7 @@ private slots:
void addExtraGraph();
void addExtraHexdump();
void addExtraDisassembly();
void addExtraDecompiler();
void on_actionRefresh_Panels_triggered();
@ -236,7 +237,6 @@ private:
QList<CutterDockWidget *> dockWidgets;
QList<CutterDockWidget *> pluginDocks;
DecompilerWidget *decompilerDock = nullptr;
OverviewWidget *overviewDock = nullptr;
QAction *actionOverview = nullptr;
EntrypointWidget *entrypointDock = nullptr;

View File

@ -162,6 +162,7 @@
<string>Debug...</string>
</property>
</widget>
<addaction name="actionExtraDecompiler"/>
<addaction name="actionExtraDisassembly"/>
<addaction name="actionExtraGraph"/>
<addaction name="actionExtraHexdump"/>
@ -756,6 +757,11 @@
<string>Add Hexdump</string>
</property>
</action>
<action name="actionExtraDecompiler">
<property name="text">
<string>Add Decompiler</string>
</property>
</action>
<action name="actionExtraDisassembly">
<property name="text">
<string>Add Disassembly</string>

View File

@ -147,7 +147,7 @@ private:
/**
* @brief Updates targeted "Show in" menu.
*
*
* 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
* type of this item in the targeted "Show in" menu.

View File

@ -8,6 +8,7 @@
#include "common/SelectionHighlight.h"
#include "common/Decompiler.h"
#include "common/CutterSeekable.h"
#include "core/MainWindow.h"
#include <QTextEdit>
#include <QPlainTextEdit>
@ -22,7 +23,8 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
MemoryDockWidget(MemoryWidgetType::Decompiler, main),
mCtxMenu(new DecompilerContextMenu(this, main)),
ui(new Ui::DecompilerWidget),
decompilerWasBusy(false),
decompilerBusy(false),
seekFromCursor(false),
scrollerHorizontal(0),
scrollerVertical(0),
previousFunctionAddr(RVA_INVALID),
@ -31,6 +33,11 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
&r_annotated_code_free)
{
ui->setupUi(this);
setObjectName(main
? main->getUniqueObjectName(tr("Decompiler"))
: tr("Decompiler"));
updateWindowTitle();
syntaxHighlighter = Config()->createSyntaxHighlighter(ui->textEdit->document());
// Event filter to intercept double click and right click in the textbox
ui->textEdit->viewport()->installEventFilter(this);
@ -43,33 +50,21 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
connect(Core(), &CutterCore::registersChanged, this, &DecompilerWidget::highlightPC);
connect(mCtxMenu, &DecompilerContextMenu::copy, this, &DecompilerWidget::copy);
connect(ui->refreshButton, &QAbstractButton::clicked, this, [this]() {
doRefresh();
});
refreshDeferrer = createRefreshDeferrer([this]() {
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 selectedDecompilerId = Config()->getSelectedDecompiler();
QString selectedDecompilerId = Config()->getSelectedDecompiler();
if (selectedDecompilerId.isEmpty()) {
// If no decompiler was previously chosen. set r2ghidra as default decompiler
selectedDecompilerId = "r2ghidra";
}
for (auto dec : decompilers) {
for (Decompiler *dec : decompilers) {
ui->decompilerComboBox->addItem(dec->getName(), dec->getId());
if (dec->getId() == selectedDecompilerId) {
ui->decompilerComboBox->setCurrentIndex(ui->decompilerComboBox->count() - 1);
}
connect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
}
decompilerSelectionEnabled = decompilers.size() > 1;
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
@ -80,26 +75,28 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
connect(ui->decompilerComboBox,
static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&DecompilerWidget::decompilerSelected);
connectCursorPositionChanged(false);
connect(Core(), &CutterCore::seekChanged, this, &DecompilerWidget::seekChanged);
connectCursorPositionChanged(true);
connect(seekable, &CutterSeekable::seekableSeekChanged, this, &DecompilerWidget::seekChanged);
ui->textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->textEdit, &QWidget::customContextMenuRequested,
this, &DecompilerWidget::showDecompilerContextMenu);
connect(Core(), &CutterCore::breakpointsChanged, this, &DecompilerWidget::updateBreakpoints);
mCtxMenu->addSeparator();
mCtxMenu->addAction(&syncAction);
addActions(mCtxMenu->actions());
ui->progressLabel->setVisible(false);
doRefresh(RVA_INVALID);
doRefresh();
connect(Core(), &CutterCore::refreshAll, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::functionRenamed, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::varsChanged, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::functionsChanged, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::flagsChanged, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::refreshAll, this, &DecompilerWidget::doRefresh);
connect(Core(), &CutterCore::functionRenamed, this, &DecompilerWidget::doRefresh);
connect(Core(), &CutterCore::varsChanged, this, &DecompilerWidget::doRefresh);
connect(Core(), &CutterCore::functionsChanged, this, &DecompilerWidget::doRefresh);
connect(Core(), &CutterCore::flagsChanged, this, &DecompilerWidget::doRefresh);
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::refreshIfChanged);
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::refreshIfChanged);
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doRefresh);
// Esc to seek backward
QAction *seekPrevAction = new QAction(this);
@ -116,31 +113,6 @@ Decompiler *DecompilerWidget::getCurrentDecompiler()
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)
{
size_t closestPos = SIZE_MAX;
@ -180,8 +152,11 @@ size_t DecompilerWidget::positionForOffset(ut64 offset)
return closestPos;
}
void DecompilerWidget::updateBreakpoints()
void DecompilerWidget::updateBreakpoints(RVA addr)
{
if (!addressInRange(addr)) {
return;
}
setInfoForBreakpoints();
QTextCursor cursor = ui->textEdit->textCursor();
cursor.select(QTextCursor::Document);
@ -195,8 +170,9 @@ void DecompilerWidget::updateBreakpoints()
void DecompilerWidget::setInfoForBreakpoints()
{
if (mCtxMenu->getIsTogglingBreakpoints())
if (mCtxMenu->getIsTogglingBreakpoints()) {
return;
}
// Get the range of the line
QTextCursor cursorForLine = ui->textEdit->textCursor();
cursorForLine.movePosition(QTextCursor::StartOfLine);
@ -224,7 +200,7 @@ void DecompilerWidget::gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size
mCtxMenu->setFirstOffsetInLine(firstOffset);
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
QVector<RVA> offsetList;
for (auto bpOffset : functionBreakpoints) {
for (RVA bpOffset : functionBreakpoints) {
size_t pos = positionForOffset(bpOffset);
if (startPos <= pos && pos <= endPos) {
offsetList.push_back(bpOffset);
@ -234,8 +210,16 @@ void DecompilerWidget::gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size
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)) {
return;
}
@ -246,26 +230,36 @@ void DecompilerWidget::doRefresh(RVA addr)
if (!dec) {
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()) {
decompilerWasBusy = true;
return;
}
if (addr == RVA_INVALID) {
ui->textEdit->setPlainText(tr("Click Refresh to generate Decompiler from current offset."));
if (!decompilerBusy) {
connect(dec, &Decompiler::finished, this, &DecompilerWidget::doRefresh);
}
return;
}
disconnect(dec, &Decompiler::finished, this, &DecompilerWidget::doRefresh);
// Clear all selections since we just refreshed
ui->textEdit->setExtraSelections({});
previousFunctionAddr = decompiledFunctionAddr;
decompiledFunctionAddr = Core()->getFunctionStart(addr);
mCtxMenu->setDecompiledFunctionAddress(decompiledFunctionAddr);
dec->decompileAt(addr);
if (dec->isRunning()) {
ui->progressLabel->setVisible(true);
ui->decompilerComboBox->setEnabled(false);
updateRefreshButton();
updateWindowTitle();
if (decompiledFunctionAddr == RVA_INVALID) {
// No function was found, so making the progress label invisible and enabling
// the decompiler selection combo box as we are not waiting for any decompilation to finish.
ui->progressLabel->setVisible(false);
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;
}
mCtxMenu->setDecompiledFunctionAddress(decompiledFunctionAddr);
connect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
decompilerBusy = true;
dec->decompileAt(addr);
}
void DecompilerWidget::refreshDecompiler()
@ -296,26 +290,43 @@ void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
ui->progressLabel->setVisible(false);
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
updateRefreshButton();
mCtxMenu->setAnnotationHere(nullptr);
this->code.reset(codeDecompiled);
Decompiler *dec = getCurrentDecompiler();
QObject::disconnect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
decompilerBusy = false;
QString codeString = QString::fromUtf8(this->code->code);
if (codeString.isEmpty()) {
connectCursorPositionChanged(false);
ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)"));
connectCursorPositionChanged(true);
lowestOffsetInCode = RVA_MAX;
highestOffsetInCode = 0;
return;
} else {
connectCursorPositionChanged(true);
ui->textEdit->setPlainText(codeString);
connectCursorPositionChanged(false);
ui->textEdit->setPlainText(codeString);
connectCursorPositionChanged(true);
updateCursorPosition();
highlightPC();
highlightBreakpoints();
}
if (decompilerWasBusy) {
decompilerWasBusy = false;
doAutoRefresh();
lowestOffsetInCode = RVA_MAX;
highestOffsetInCode = 0;
void *iter;
r_vector_foreach(&code->annotations, iter) {
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) {
@ -344,16 +355,14 @@ void DecompilerWidget::setAnnotationsAtCursor(size_t pos)
void DecompilerWidget::decompilerSelected()
{
Config()->setSelectedDecompiler(ui->decompilerComboBox->currentData().toString());
if (autoRefreshEnabled) {
doRefresh();
}
doRefresh();
}
void DecompilerWidget::connectCursorPositionChanged(bool disconnect)
void DecompilerWidget::connectCursorPositionChanged(bool connectPositionChange)
{
if (disconnect) {
QObject::disconnect(ui->textEdit, &QPlainTextEdit::cursorPositionChanged, this,
&DecompilerWidget::cursorPositionChanged);
if (!connectPositionChange) {
disconnect(ui->textEdit, &QPlainTextEdit::cursorPositionChanged, this,
&DecompilerWidget::cursorPositionChanged);
} else {
connect(ui->textEdit, &QPlainTextEdit::cursorPositionChanged, this,
&DecompilerWidget::cursorPositionChanged);
@ -372,9 +381,9 @@ void DecompilerWidget::cursorPositionChanged()
setInfoForBreakpoints();
RVA offset = offsetForPosition(pos);
if (offset != RVA_INVALID && offset != Core()->getOffset()) {
if (offset != RVA_INVALID && offset != seekable->getOffset()) {
seekFromCursor = true;
Core()->seek(offset);
seekable->seek(offset);
mCtxMenu->setOffset(offset);
seekFromCursor = false;
}
@ -386,30 +395,28 @@ void DecompilerWidget::seekChanged()
if (seekFromCursor) {
return;
}
if (autoRefreshEnabled) {
auto fcnAddr = Core()->getFunctionStart(Core()->getOffset());
if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) {
doRefresh();
return;
}
RVA fcnAddr = Core()->getFunctionStart(seekable->getOffset());
if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) {
doRefresh();
return;
}
updateCursorPosition();
}
void DecompilerWidget::updateCursorPosition()
{
RVA offset = Core()->getOffset();
RVA offset = seekable->getOffset();
size_t pos = positionForOffset(offset);
if (pos == SIZE_MAX) {
return;
}
mCtxMenu->setOffset(offset);
connectCursorPositionChanged(true);
connectCursorPositionChanged(false);
QTextCursor cursor = ui->textEdit->textCursor();
cursor.setPosition(pos);
ui->textEdit->setTextCursor(cursor);
updateSelection();
connectCursorPositionChanged(false);
connectCursorPositionChanged(true);
}
void DecompilerWidget::setupFonts()
@ -422,7 +429,7 @@ void DecompilerWidget::updateSelection()
QList<QTextEdit::ExtraSelection> extraSelections;
// Highlight the current line
auto cursor = ui->textEdit->textCursor();
QTextCursor cursor = ui->textEdit->textCursor();
extraSelections.append(createLineHighlightSelection(cursor));
// Highlight all the words in the document same as the current one
@ -438,7 +445,14 @@ void DecompilerWidget::updateSelection()
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()
@ -501,7 +515,7 @@ void DecompilerWidget::highlightBreakpoints()
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
QTextCursor cursor;
for (auto &bp : functionBreakpoints) {
for (RVA &bp : functionBreakpoints) {
if (bp == RVA_INVALID) {
continue;;
}
@ -539,3 +553,11 @@ void DecompilerWidget::copy()
}
}
}
bool DecompilerWidget::addressInRange(RVA addr)
{
if (lowestOffsetInCode <= addr && addr <= highestOffsetInCode) {
return true;
}
return false;
}

View File

@ -47,7 +47,7 @@ private slots:
void cursorPositionChanged();
/**
* @brief When the synced seek is changed, this refreshes the decompiler widget if needed.
*
*
* Decompiler widget is not refreshed in the following two cases
* - Seek changed to an offset contained in the decompiled function.
* - Auto-refresh is disabled.
@ -62,36 +62,45 @@ private:
QSyntaxHighlighter *syntaxHighlighter;
bool decompilerSelectionEnabled;
bool autoRefreshEnabled;
/**
* True if doRefresh() was called, but the decompiler was still running.
* This means, after the decompiler has finished, it should be refreshed immediately.
* True if the selected decompiler is currently running a decompilation for this widget. Once the decompilation
* is over, this should be set to false.
*/
bool decompilerWasBusy;
bool decompilerBusy;
bool seekFromCursor;
int scrollerHorizontal;
int scrollerVertical;
RVA previousFunctionAddr;
RVA decompiledFunctionAddr;
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();
/**
* @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);
/**
* @brief Calls the function doRefresh() if auto-refresh is enabled.
*/
void doAutoRefresh();
void refreshIfChanged(RVA addr);
/**
* @brief Refreshes the decompiler.
*
*
* - This does the following if the specified offset is valid
* - Decompile function that contains the specified offset.
* - Clears all selections stored for highlighting purposes.
@ -102,15 +111,14 @@ private:
*
* @param addr Specified offset/offset in sync.
*/
void doRefresh(RVA addr = Core()->getOffset());
void updateRefreshButton();
void doRefresh();
/**
* @brief Update fonts
*/
void setupFonts();
/**
* @brief Update highlights in the text widget.
*
*
* These include respective highlights for:
* - Line under cursor
* - Word under cursor
@ -120,13 +128,13 @@ private:
/**
* @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.
* 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
* to the position specified by this offset (found using positionForOffset() )
@ -167,7 +175,7 @@ private:
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.
*/
void highlightBreakpoints();
@ -205,7 +213,7 @@ private:
/**
* @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
*/
@ -217,6 +225,13 @@ private:
* @param pos Position of cursor in the decompiled code.
*/
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

View File

@ -42,20 +42,6 @@
</item>
<item>
<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>
<layout class="QHBoxLayout" name="progressLayout">
<property name="leftMargin">

View File

@ -42,7 +42,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
auto *layout = new QVBoxLayout(this);
// Signals that require a refresh all
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(), SIGNAL(flagsChanged()), this, SLOT(refreshView()));
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshView()));

View File

@ -48,14 +48,13 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main)
setObjectName(main
? main->getUniqueObjectName(getWidgetType())
: getWidgetType());
updateWindowTitle();
topOffset = bottomOffset = RVA_INVALID;
cursorLineOffset = 0;
cursorCharOffset = 0;
seekFromCursor = false;
setWindowTitle(getWindowTitle());
// Instantiate the window layout
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(functionsChanged()), this, SLOT(refreshDisasm()));
connect(Core(), &CutterCore::functionRenamed, this, [this]() {refreshDisasm();});

View File

@ -26,6 +26,7 @@ HexdumpWidget::HexdumpWidget(MainWindow *main) :
setObjectName(main
? main->getUniqueObjectName(getWidgetType())
: getWidgetType());
updateWindowTitle();
ui->copyMD5->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"
"}");
setWindowTitle(getWindowTitle());
refreshDeferrer = createReplacingRefreshDeferrer<RVA>(false, [this](const RVA *offset) {
refresh(offset ? *offset : RVA_INVALID);
});