mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-24 05:45:27 +00:00
Decompiler Documentation + Clean up (#2374)
This commit is contained in:
parent
1c86f54c95
commit
b7d1059a1b
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow)
|
DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow)
|
||||||
: QMenu(parent),
|
: QMenu(parent),
|
||||||
|
mainWindow(mainWindow),
|
||||||
curHighlightedWord(QString()),
|
curHighlightedWord(QString()),
|
||||||
offset(0),
|
offset(0),
|
||||||
decompiledFunctionAddress(RVA_INVALID),
|
decompiledFunctionAddress(RVA_INVALID),
|
||||||
isTogglingBreakpoints(false),
|
isTogglingBreakpoints(false),
|
||||||
mainWindow(mainWindow),
|
|
||||||
annotationHere(nullptr),
|
annotationHere(nullptr),
|
||||||
actionCopy(tr("Copy"), this),
|
actionCopy(tr("Copy"), this),
|
||||||
actionCopyInstructionAddress(tr("Copy instruction address (<address>)"), this),
|
actionCopyInstructionAddress(tr("Copy instruction address (<address>)"), this),
|
||||||
@ -48,11 +48,11 @@ DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWi
|
|||||||
setActionAddComment();
|
setActionAddComment();
|
||||||
setActionDeleteComment();
|
setActionDeleteComment();
|
||||||
|
|
||||||
setActionXRefs();
|
|
||||||
|
|
||||||
setActionRenameThingHere();
|
setActionRenameThingHere();
|
||||||
setActionDeleteName();
|
setActionDeleteName();
|
||||||
|
|
||||||
|
setActionXRefs();
|
||||||
|
|
||||||
setActionEditFunctionVariables();
|
setActionEditFunctionVariables();
|
||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
@ -73,34 +73,37 @@ DecompilerContextMenu::~DecompilerContextMenu()
|
|||||||
|
|
||||||
void DecompilerContextMenu::setAnnotationHere(RCodeAnnotation *annotation)
|
void DecompilerContextMenu::setAnnotationHere(RCodeAnnotation *annotation)
|
||||||
{
|
{
|
||||||
this->annotationHere = annotation;
|
annotationHere = annotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerContextMenu::setCurHighlightedWord(QString word)
|
void DecompilerContextMenu::setCurHighlightedWord(QString word)
|
||||||
{
|
{
|
||||||
this->curHighlightedWord = word;
|
curHighlightedWord = word;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerContextMenu::setOffset(RVA offset)
|
void DecompilerContextMenu::setOffset(RVA newOffset)
|
||||||
{
|
{
|
||||||
this->offset = offset;
|
offset = newOffset;
|
||||||
|
|
||||||
// this->actionSetFunctionVarTypes.setVisible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerContextMenu::setDecompiledFunctionAddress(RVA functionAddr)
|
void DecompilerContextMenu::setDecompiledFunctionAddress(RVA functionAddr)
|
||||||
{
|
{
|
||||||
this->decompiledFunctionAddress = functionAddr;
|
decompiledFunctionAddress = functionAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerContextMenu::setFirstOffsetInLine(RVA firstOffset)
|
void DecompilerContextMenu::setFirstOffsetInLine(RVA firstOffset)
|
||||||
{
|
{
|
||||||
this->firstOffsetInLine = firstOffset;
|
firstOffsetInLine = firstOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
RVA DecompilerContextMenu::getFirstOffsetInLine()
|
||||||
|
{
|
||||||
|
return firstOffsetInLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerContextMenu::setAvailableBreakpoints(QVector<RVA> offsetList)
|
void DecompilerContextMenu::setAvailableBreakpoints(QVector<RVA> offsetList)
|
||||||
{
|
{
|
||||||
this->availableBreakpoints = offsetList;
|
availableBreakpoints = offsetList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerContextMenu::setupBreakpointsInLineMenu()
|
void DecompilerContextMenu::setupBreakpointsInLineMenu()
|
||||||
@ -130,12 +133,12 @@ void DecompilerContextMenu::setShortcutContextInActions(QMenu *menu)
|
|||||||
|
|
||||||
void DecompilerContextMenu::setIsTogglingBreakpoints(bool isToggling)
|
void DecompilerContextMenu::setIsTogglingBreakpoints(bool isToggling)
|
||||||
{
|
{
|
||||||
this->isTogglingBreakpoints = isToggling;
|
isTogglingBreakpoints = isToggling;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecompilerContextMenu::getIsTogglingBreakpoints()
|
bool DecompilerContextMenu::getIsTogglingBreakpoints()
|
||||||
{
|
{
|
||||||
return this->isTogglingBreakpoints;
|
return isTogglingBreakpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerContextMenu::aboutToHideSlot()
|
void DecompilerContextMenu::aboutToHideSlot()
|
||||||
@ -169,7 +172,6 @@ void DecompilerContextMenu::aboutToShowSlot()
|
|||||||
actionDeleteComment.setVisible(false);
|
actionDeleteComment.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setupBreakpointsInLineMenu();
|
setupBreakpointsInLineMenu();
|
||||||
|
|
||||||
// Only show debug options if we are currently debugging
|
// Only show debug options if we are currently debugging
|
||||||
@ -184,7 +186,6 @@ void DecompilerContextMenu::aboutToShowSlot()
|
|||||||
} else {
|
} else {
|
||||||
actionToggleBreakpoint.setText(tr("Remove all breakpoints in line"));
|
actionToggleBreakpoint.setText(tr("Remove all breakpoints in line"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numberOfBreakpoints > 1) {
|
if (numberOfBreakpoints > 1) {
|
||||||
actionAdvancedBreakpoint.setMenu(breakpointsInLineMenu);
|
actionAdvancedBreakpoint.setMenu(breakpointsInLineMenu);
|
||||||
} else {
|
} else {
|
||||||
@ -198,7 +199,7 @@ void DecompilerContextMenu::aboutToShowSlot()
|
|||||||
|
|
||||||
if (!annotationHere
|
if (!annotationHere
|
||||||
|| annotationHere->type ==
|
|| annotationHere->type ==
|
||||||
R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) { // To be considered as invalid
|
R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) { // If constant, don't show rename and targeted show-in
|
||||||
actionRenameThingHere.setVisible(false);
|
actionRenameThingHere.setVisible(false);
|
||||||
copySeparator->setVisible(false);
|
copySeparator->setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
@ -219,7 +220,7 @@ void DecompilerContextMenu::aboutToShowSlot()
|
|||||||
}
|
}
|
||||||
actionCopyInstructionAddress.setText(tr("Copy instruction address (%1)").arg(RAddressString(
|
actionCopyInstructionAddress.setText(tr("Copy instruction address (%1)").arg(RAddressString(
|
||||||
offset)));
|
offset)));
|
||||||
if (annotationHere && r_annotation_is_reference(annotationHere)) {
|
if (isReference()) {
|
||||||
actionCopyReferenceAddress.setVisible(true);
|
actionCopyReferenceAddress.setVisible(true);
|
||||||
RVA referenceAddr = annotationHere->reference.offset;
|
RVA referenceAddr = annotationHere->reference.offset;
|
||||||
RFlagItem *flagDetails = r_flag_get_i(Core()->core()->flags, referenceAddr);
|
RFlagItem *flagDetails = r_flag_get_i(Core()->core()->flags, referenceAddr);
|
||||||
@ -258,7 +259,6 @@ void DecompilerContextMenu::aboutToShowSlot()
|
|||||||
|
|
||||||
// Set up actions
|
// Set up actions
|
||||||
|
|
||||||
|
|
||||||
void DecompilerContextMenu::setActionCopy() // Set all three copy actions
|
void DecompilerContextMenu::setActionCopy() // Set all three copy actions
|
||||||
{
|
{
|
||||||
connect(&actionCopy, &QAction::triggered, this, &DecompilerContextMenu::actionCopyTriggered);
|
connect(&actionCopy, &QAction::triggered, this, &DecompilerContextMenu::actionCopyTriggered);
|
||||||
@ -386,7 +386,7 @@ void DecompilerContextMenu::actionDeleteCommentTriggered()
|
|||||||
|
|
||||||
void DecompilerContextMenu::actionRenameThingHereTriggered()
|
void DecompilerContextMenu::actionRenameThingHereTriggered()
|
||||||
{
|
{
|
||||||
if (!annotationHere) {
|
if (!annotationHere || annotationHere->type == R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RCoreLocked core = Core()->core();
|
RCoreLocked core = Core()->core();
|
||||||
@ -410,7 +410,6 @@ void DecompilerContextMenu::actionRenameThingHereTriggered()
|
|||||||
Core()->renameFunction(func_addr, newName);
|
Core()->renameFunction(func_addr, newName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) {
|
} else if (type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) {
|
||||||
RVA var_addr = annotationHere->reference.offset;
|
RVA var_addr = annotationHere->reference.offset;
|
||||||
RFlagItem *flagDetails = r_flag_get_i(core->flags, var_addr);
|
RFlagItem *flagDetails = r_flag_get_i(core->flags, var_addr);
|
||||||
@ -467,7 +466,7 @@ void DecompilerContextMenu::actionEditFunctionVariablesTriggered()
|
|||||||
|
|
||||||
void DecompilerContextMenu::actionXRefsTriggered()
|
void DecompilerContextMenu::actionXRefsTriggered()
|
||||||
{
|
{
|
||||||
if (!annotationHere || !r_annotation_is_reference(annotationHere)) {
|
if (!isReference()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
XrefsDialog dialog(mainWindow, nullptr);
|
XrefsDialog dialog(mainWindow, nullptr);
|
||||||
@ -551,9 +550,7 @@ void DecompilerContextMenu::updateTargetMenuActions()
|
|||||||
}
|
}
|
||||||
showTargetMenuActions.clear();
|
showTargetMenuActions.clear();
|
||||||
RCoreLocked core = Core()->core();
|
RCoreLocked core = Core()->core();
|
||||||
if (annotationHere && (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE
|
if (isReference()) {
|
||||||
|| annotationHere->type == R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE
|
|
||||||
|| annotationHere->type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME)) {
|
|
||||||
QString name;
|
QString name;
|
||||||
QMenu *menu;
|
QMenu *menu;
|
||||||
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE
|
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE
|
||||||
@ -580,6 +577,11 @@ void DecompilerContextMenu::updateTargetMenuActions()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DecompilerContextMenu::isReference()
|
||||||
|
{
|
||||||
|
return (annotationHere && r_annotation_is_reference(annotationHere));
|
||||||
|
}
|
||||||
|
|
||||||
bool DecompilerContextMenu::isFunctionVariable()
|
bool DecompilerContextMenu::isFunctionVariable()
|
||||||
{
|
{
|
||||||
return (annotationHere && r_annotation_is_variable(annotationHere));
|
return (annotationHere && r_annotation_is_variable(annotationHere));
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <r_util/r_annotated_code.h>
|
#include <r_util/r_annotated_code.h>
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
|
||||||
class DecompilerContextMenu : public QMenu
|
class DecompilerContextMenu : public QMenu
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -17,18 +19,18 @@ public:
|
|||||||
|
|
||||||
bool getIsTogglingBreakpoints();
|
bool getIsTogglingBreakpoints();
|
||||||
void setAnnotationHere(RCodeAnnotation *annotation);
|
void setAnnotationHere(RCodeAnnotation *annotation);
|
||||||
|
RVA getFirstOffsetInLine();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void copy();
|
void copy();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setCurHighlightedWord(QString word);
|
void setCurHighlightedWord(QString word);
|
||||||
void setOffset(RVA offset);
|
void setOffset(RVA newOffset);
|
||||||
void setDecompiledFunctionAddress(RVA functionAddr);
|
void setDecompiledFunctionAddress(RVA functionAddr);
|
||||||
void setFirstOffsetInLine(RVA firstOffset);
|
void setFirstOffsetInLine(RVA firstOffset);
|
||||||
void setAvailableBreakpoints(QVector<RVA> offsetList);
|
void setAvailableBreakpoints(QVector<RVA> offsetList);
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void aboutToShowSlot();
|
void aboutToShowSlot();
|
||||||
void aboutToHideSlot();
|
void aboutToHideSlot();
|
||||||
@ -55,16 +57,30 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Private variables
|
// Private variables
|
||||||
|
MainWindow *mainWindow;
|
||||||
QString curHighlightedWord;
|
QString curHighlightedWord;
|
||||||
RVA offset;
|
RVA offset;
|
||||||
RVA decompiledFunctionAddress;
|
RVA decompiledFunctionAddress;
|
||||||
|
/**
|
||||||
|
* Lowest offset among all offsets present in the line under cursor in the decompiler widget.
|
||||||
|
*/
|
||||||
RVA firstOffsetInLine;
|
RVA firstOffsetInLine;
|
||||||
|
/**
|
||||||
|
* When the actionToggleBreakpoint has been triggered, and it hasn't finished executing,
|
||||||
|
* the value of this variable will be true, otherwise false
|
||||||
|
*/
|
||||||
bool isTogglingBreakpoints;
|
bool isTogglingBreakpoints;
|
||||||
|
/**
|
||||||
|
* List of the offsets of all the breakpoints (enabled and disabled) that are present in the line under cursor.
|
||||||
|
*/
|
||||||
QVector<RVA> availableBreakpoints;
|
QVector<RVA> availableBreakpoints;
|
||||||
MainWindow *mainWindow;
|
/**
|
||||||
|
* Context-related annotation for the data under cursor in the decompiler widget.
|
||||||
|
* If such an annotation doesn't exist, its value is nullptr.
|
||||||
|
*/
|
||||||
RCodeAnnotation *annotationHere;
|
RCodeAnnotation *annotationHere;
|
||||||
|
|
||||||
|
// Actions and menus in the context menu
|
||||||
QAction actionCopy;
|
QAction actionCopy;
|
||||||
QAction actionCopyInstructionAddress;
|
QAction actionCopyInstructionAddress;
|
||||||
QAction actionCopyReferenceAddress;
|
QAction actionCopyReferenceAddress;
|
||||||
@ -94,6 +110,12 @@ private:
|
|||||||
QAction actionSetPC;
|
QAction actionSetPC;
|
||||||
|
|
||||||
// Private Functions
|
// Private Functions
|
||||||
|
/**
|
||||||
|
* @brief Sets the shortcut context in all the actions contained
|
||||||
|
* in the specified QMenu to Qt::WidgetWithChildrenShortcut.
|
||||||
|
*
|
||||||
|
* @param menu - QMenu specified
|
||||||
|
*/
|
||||||
void setShortcutContextInActions(QMenu *menu);
|
void setShortcutContextInActions(QMenu *menu);
|
||||||
void setupBreakpointsInLineMenu();
|
void setupBreakpointsInLineMenu();
|
||||||
void setIsTogglingBreakpoints(bool isToggling);
|
void setIsTogglingBreakpoints(bool isToggling);
|
||||||
@ -123,9 +145,35 @@ private:
|
|||||||
void addBreakpointMenu();
|
void addBreakpointMenu();
|
||||||
void addDebugMenu();
|
void addDebugMenu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
void updateTargetMenuActions();
|
void updateTargetMenuActions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if annotationHere is a reference (function name,
|
||||||
|
* global variable, constant variable with an address).
|
||||||
|
*
|
||||||
|
* @return True if annotationHere is a reference, otherwise false.
|
||||||
|
*/
|
||||||
|
bool isReference();
|
||||||
|
/**
|
||||||
|
* @brief Check if annotationHere is a function variable
|
||||||
|
* (local variable or function parameter).
|
||||||
|
*
|
||||||
|
* @return True if annotationHere is a function variable, otherwise false.
|
||||||
|
*/
|
||||||
bool isFunctionVariable();
|
bool isFunctionVariable();
|
||||||
|
/**
|
||||||
|
* @brief Check if the function variable annotated by annotationHere is
|
||||||
|
* present in radare2.
|
||||||
|
*
|
||||||
|
* @return True if the variable is present, otherwise false
|
||||||
|
*/
|
||||||
bool variablePresentInR2();
|
bool variablePresentInR2();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,10 +31,8 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
&r_annotated_code_free)
|
&r_annotated_code_free)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
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 clicks in the textbox
|
|
||||||
ui->textEdit->viewport()->installEventFilter(this);
|
ui->textEdit->viewport()->installEventFilter(this);
|
||||||
|
|
||||||
setupFonts();
|
setupFonts();
|
||||||
@ -48,11 +46,9 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
connect(ui->refreshButton, &QAbstractButton::clicked, this, [this]() {
|
connect(ui->refreshButton, &QAbstractButton::clicked, this, [this]() {
|
||||||
doRefresh();
|
doRefresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
refreshDeferrer = createRefreshDeferrer([this]() {
|
refreshDeferrer = createRefreshDeferrer([this]() {
|
||||||
doRefresh();
|
doRefresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
autoRefreshEnabled = Config()->getDecompilerAutoRefreshEnabled();
|
autoRefreshEnabled = Config()->getDecompilerAutoRefreshEnabled();
|
||||||
ui->autoRefreshCheckBox->setChecked(autoRefreshEnabled);
|
ui->autoRefreshCheckBox->setChecked(autoRefreshEnabled);
|
||||||
setAutoRefresh(autoRefreshEnabled);
|
setAutoRefresh(autoRefreshEnabled);
|
||||||
@ -75,10 +71,8 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
}
|
}
|
||||||
connect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
|
connect(dec, &Decompiler::finished, this, &DecompilerWidget::decompilationFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
decompilerSelectionEnabled = decompilers.size() > 1;
|
decompilerSelectionEnabled = decompilers.size() > 1;
|
||||||
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
|
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
|
||||||
|
|
||||||
if (decompilers.isEmpty()) {
|
if (decompilers.isEmpty()) {
|
||||||
ui->textEdit->setPlainText(tr("No Decompiler available."));
|
ui->textEdit->setPlainText(tr("No Decompiler available."));
|
||||||
}
|
}
|
||||||
@ -90,7 +84,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) :
|
|||||||
connect(Core(), &CutterCore::seekChanged, this, &DecompilerWidget::seekChanged);
|
connect(Core(), &CutterCore::seekChanged, 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::showDisasContextMenu);
|
this, &DecompilerWidget::showDecompilerContextMenu);
|
||||||
|
|
||||||
connect(Core(), &CutterCore::breakpointsChanged, this, &DecompilerWidget::updateBreakpoints);
|
connect(Core(), &CutterCore::breakpointsChanged, this, &DecompilerWidget::updateBreakpoints);
|
||||||
addActions(mCtxMenu->actions());
|
addActions(mCtxMenu->actions());
|
||||||
@ -147,13 +141,13 @@ void DecompilerWidget::updateRefreshButton()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ut64 offsetForPosition(RAnnotatedCode &codeDecompiled, size_t pos)
|
ut64 DecompilerWidget::offsetForPosition(size_t pos)
|
||||||
{
|
{
|
||||||
size_t closestPos = SIZE_MAX;
|
size_t closestPos = SIZE_MAX;
|
||||||
ut64 closestOffset = UT64_MAX;
|
ut64 closestOffset = mCtxMenu->getFirstOffsetInLine();
|
||||||
void *annotationi;
|
void *iter;
|
||||||
r_vector_foreach(&codeDecompiled.annotations, annotationi) {
|
r_vector_foreach(&code->annotations, iter) {
|
||||||
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
|
RCodeAnnotation *annotation = (RCodeAnnotation *)iter;
|
||||||
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->start > pos
|
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->start > pos
|
||||||
|| annotation->end <= pos) {
|
|| annotation->end <= pos) {
|
||||||
continue;
|
continue;
|
||||||
@ -167,13 +161,13 @@ static ut64 offsetForPosition(RAnnotatedCode &codeDecompiled, size_t pos)
|
|||||||
return closestOffset;
|
return closestOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t positionForOffset(RAnnotatedCode &codeDecompiled, ut64 offset)
|
size_t DecompilerWidget::positionForOffset(ut64 offset)
|
||||||
{
|
{
|
||||||
size_t closestPos = SIZE_MAX;
|
size_t closestPos = SIZE_MAX;
|
||||||
ut64 closestOffset = UT64_MAX;
|
ut64 closestOffset = UT64_MAX;
|
||||||
void *annotationi;
|
void *iter;
|
||||||
r_vector_foreach(&codeDecompiled.annotations, annotationi) {
|
r_vector_foreach(&code->annotations, iter) {
|
||||||
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
|
RCodeAnnotation *annotation = (RCodeAnnotation *)iter;
|
||||||
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->offset.offset > offset) {
|
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->offset.offset > offset) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -216,13 +210,13 @@ void DecompilerWidget::gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size
|
|||||||
size_t endPos)
|
size_t endPos)
|
||||||
{
|
{
|
||||||
RVA firstOffset = RVA_MAX;
|
RVA firstOffset = RVA_MAX;
|
||||||
void *annotationi;
|
void *iter;
|
||||||
r_vector_foreach(&codeDecompiled.annotations, annotationi) {
|
r_vector_foreach(&codeDecompiled.annotations, iter) {
|
||||||
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
|
RCodeAnnotation *annotation = (RCodeAnnotation *)iter;
|
||||||
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET) {
|
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((startPos <= annotation->start && annotation->start < endPos) || (startPos <= annotation->end
|
if ((startPos <= annotation->start && annotation->start < endPos) || (startPos < annotation->end
|
||||||
&& annotation->end < endPos)) {
|
&& annotation->end < endPos)) {
|
||||||
firstOffset = (annotation->offset.offset < firstOffset) ? annotation->offset.offset : firstOffset;
|
firstOffset = (annotation->offset.offset < firstOffset) ? annotation->offset.offset : firstOffset;
|
||||||
}
|
}
|
||||||
@ -231,7 +225,7 @@ void DecompilerWidget::gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size
|
|||||||
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
|
QList<RVA> functionBreakpoints = Core()->getBreakpointsInFunction(decompiledFunctionAddr);
|
||||||
QVector<RVA> offsetList;
|
QVector<RVA> offsetList;
|
||||||
for (auto bpOffset : functionBreakpoints) {
|
for (auto bpOffset : functionBreakpoints) {
|
||||||
size_t pos = positionForOffset(*code, bpOffset);
|
size_t pos = positionForOffset(bpOffset);
|
||||||
if (startPos <= pos && pos <= endPos) {
|
if (startPos <= pos && pos <= endPos) {
|
||||||
offsetList.push_back(bpOffset);
|
offsetList.push_back(bpOffset);
|
||||||
}
|
}
|
||||||
@ -245,26 +239,21 @@ void DecompilerWidget::doRefresh(RVA addr)
|
|||||||
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui->decompilerComboBox->currentIndex() < 0) {
|
if (ui->decompilerComboBox->currentIndex() < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Decompiler *dec = getCurrentDecompiler();
|
Decompiler *dec = getCurrentDecompiler();
|
||||||
if (!dec) {
|
if (!dec) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dec->isRunning()) {
|
if (dec->isRunning()) {
|
||||||
decompilerWasBusy = true;
|
decompilerWasBusy = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr == RVA_INVALID) {
|
if (addr == RVA_INVALID) {
|
||||||
ui->textEdit->setPlainText(tr("Click Refresh to generate Decompiler from current offset."));
|
ui->textEdit->setPlainText(tr("Click Refresh to generate Decompiler from current offset."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all selections since we just refreshed
|
// Clear all selections since we just refreshed
|
||||||
ui->textEdit->setExtraSelections({});
|
ui->textEdit->setExtraSelections({});
|
||||||
previousFunctionAddr = decompiledFunctionAddr;
|
previousFunctionAddr = decompiledFunctionAddr;
|
||||||
@ -287,11 +276,10 @@ void DecompilerWidget::refreshDecompiler()
|
|||||||
|
|
||||||
QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
|
QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
|
||||||
{
|
{
|
||||||
size_t pos = positionForOffset(*code, addr);
|
size_t pos = positionForOffset(addr);
|
||||||
if (pos == SIZE_MAX || pos == 0) {
|
if (pos == SIZE_MAX || pos == 0) {
|
||||||
return QTextCursor();
|
return QTextCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextCursor cursor = ui->textEdit->textCursor();
|
QTextCursor cursor = ui->textEdit->textCursor();
|
||||||
cursor.setPosition(pos);
|
cursor.setPosition(pos);
|
||||||
return cursor;
|
return cursor;
|
||||||
@ -339,9 +327,9 @@ void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
|
|||||||
void DecompilerWidget::setAnnotationsAtCursor(size_t pos)
|
void DecompilerWidget::setAnnotationsAtCursor(size_t pos)
|
||||||
{
|
{
|
||||||
RCodeAnnotation *annotationAtPos = nullptr;
|
RCodeAnnotation *annotationAtPos = nullptr;
|
||||||
void *annotationi;
|
void *iter;
|
||||||
r_vector_foreach(&this->code->annotations, annotationi) {
|
r_vector_foreach(&this->code->annotations, iter) {
|
||||||
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
|
RCodeAnnotation *annotation = (RCodeAnnotation *)iter;
|
||||||
if (annotation->type == R_CODE_ANNOTATION_TYPE_OFFSET ||
|
if (annotation->type == R_CODE_ANNOTATION_TYPE_OFFSET ||
|
||||||
annotation->type == R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT ||
|
annotation->type == R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT ||
|
||||||
annotation->start > pos || annotation->end <= pos) {
|
annotation->start > pos || annotation->end <= pos) {
|
||||||
@ -381,10 +369,9 @@ void DecompilerWidget::cursorPositionChanged()
|
|||||||
|
|
||||||
size_t pos = ui->textEdit->textCursor().position();
|
size_t pos = ui->textEdit->textCursor().position();
|
||||||
setAnnotationsAtCursor(pos);
|
setAnnotationsAtCursor(pos);
|
||||||
|
|
||||||
setInfoForBreakpoints();
|
setInfoForBreakpoints();
|
||||||
|
|
||||||
RVA offset = offsetForPosition(*code, pos);
|
RVA offset = offsetForPosition(pos);
|
||||||
if (offset != RVA_INVALID && offset != Core()->getOffset()) {
|
if (offset != RVA_INVALID && offset != Core()->getOffset()) {
|
||||||
seekFromCursor = true;
|
seekFromCursor = true;
|
||||||
Core()->seek(offset);
|
Core()->seek(offset);
|
||||||
@ -399,7 +386,6 @@ void DecompilerWidget::seekChanged()
|
|||||||
if (seekFromCursor) {
|
if (seekFromCursor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoRefreshEnabled) {
|
if (autoRefreshEnabled) {
|
||||||
auto fcnAddr = Core()->getFunctionStart(Core()->getOffset());
|
auto fcnAddr = Core()->getFunctionStart(Core()->getOffset());
|
||||||
if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) {
|
if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) {
|
||||||
@ -407,14 +393,13 @@ void DecompilerWidget::seekChanged()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCursorPosition();
|
updateCursorPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::updateCursorPosition()
|
void DecompilerWidget::updateCursorPosition()
|
||||||
{
|
{
|
||||||
RVA offset = Core()->getOffset();
|
RVA offset = Core()->getOffset();
|
||||||
size_t pos = positionForOffset(*code, offset);
|
size_t pos = positionForOffset(offset);
|
||||||
if (pos == SIZE_MAX) {
|
if (pos == SIZE_MAX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -465,7 +450,7 @@ void DecompilerWidget::colorsUpdatedSlot()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecompilerWidget::showDisasContextMenu(const QPoint &pt)
|
void DecompilerWidget::showDecompilerContextMenu(const QPoint &pt)
|
||||||
{
|
{
|
||||||
mCtxMenu->exec(ui->textEdit->mapToGlobal(pt));
|
mCtxMenu->exec(ui->textEdit->mapToGlobal(pt));
|
||||||
}
|
}
|
||||||
@ -473,7 +458,7 @@ void DecompilerWidget::showDisasContextMenu(const QPoint &pt)
|
|||||||
void DecompilerWidget::seekToReference()
|
void DecompilerWidget::seekToReference()
|
||||||
{
|
{
|
||||||
size_t pos = ui->textEdit->textCursor().position();
|
size_t pos = ui->textEdit->textCursor().position();
|
||||||
RVA offset = offsetForPosition(*code, pos);
|
RVA offset = offsetForPosition(pos);
|
||||||
seekable->seekToReference(offset);
|
seekable->seekToReference(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,7 +505,6 @@ void DecompilerWidget::highlightBreakpoints()
|
|||||||
if (bp == RVA_INVALID) {
|
if (bp == RVA_INVALID) {
|
||||||
continue;;
|
continue;;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = getCursorForAddress(bp);
|
cursor = getCursorForAddress(bp);
|
||||||
if (!cursor.isNull()) {
|
if (!cursor.isNull()) {
|
||||||
// Use a Block formatting since these lines are not updated frequently as selections and PC
|
// Use a Block formatting since these lines are not updated frequently as selections and PC
|
||||||
|
@ -28,16 +28,30 @@ public:
|
|||||||
explicit DecompilerWidget(MainWindow *main);
|
explicit DecompilerWidget(MainWindow *main);
|
||||||
~DecompilerWidget();
|
~DecompilerWidget();
|
||||||
public slots:
|
public slots:
|
||||||
void showDisasContextMenu(const QPoint &pt);
|
void showDecompilerContextMenu(const QPoint &pt);
|
||||||
|
|
||||||
void highlightPC();
|
void highlightPC();
|
||||||
private slots:
|
private slots:
|
||||||
|
/**
|
||||||
|
* @brief Copy to clipboard what's needed depending on the state of text widget.
|
||||||
|
*
|
||||||
|
* @note If something is selected in the text widget, copy selection.
|
||||||
|
* If something is highlighted, copy highlighted word.
|
||||||
|
* Otherwise, copy the line under cursor.
|
||||||
|
*/
|
||||||
void copy();
|
void copy();
|
||||||
void fontsUpdatedSlot();
|
void fontsUpdatedSlot();
|
||||||
void colorsUpdatedSlot();
|
void colorsUpdatedSlot();
|
||||||
void refreshDecompiler();
|
void refreshDecompiler();
|
||||||
void decompilerSelected();
|
void decompilerSelected();
|
||||||
void cursorPositionChanged();
|
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.
|
||||||
|
*/
|
||||||
void seekChanged();
|
void seekChanged();
|
||||||
void decompilationFinished(RAnnotatedCode *code);
|
void decompilationFinished(RAnnotatedCode *code);
|
||||||
|
|
||||||
@ -51,7 +65,7 @@ private:
|
|||||||
bool autoRefreshEnabled;
|
bool autoRefreshEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if doRefresh() was called, but the decompiler was still running
|
* True if doRefresh() was called, but the decompiler was still running.
|
||||||
* This means, after the decompiler has finished, it should be refreshed immediately.
|
* This means, after the decompiler has finished, it should be refreshed immediately.
|
||||||
*/
|
*/
|
||||||
bool decompilerWasBusy;
|
bool decompilerWasBusy;
|
||||||
@ -65,16 +79,71 @@ private:
|
|||||||
|
|
||||||
Decompiler *getCurrentDecompiler();
|
Decompiler *getCurrentDecompiler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable/Disable auto refresh as per the specified boolean value
|
||||||
|
*
|
||||||
|
* @param enabled
|
||||||
|
*/
|
||||||
void setAutoRefresh(bool enabled);
|
void setAutoRefresh(bool enabled);
|
||||||
|
/**
|
||||||
|
* @brief Calls the function doRefresh() if auto-refresh is enabled.
|
||||||
|
*/
|
||||||
void doAutoRefresh();
|
void doAutoRefresh();
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
* - Reset previousFunctionAddr with the current function's address
|
||||||
|
* and decompiledFunctionAddr with the address of the function that
|
||||||
|
* was decompiled.
|
||||||
|
* - If the offset is invalid, error message is shown in the text widget.
|
||||||
|
*
|
||||||
|
* @param addr Specified offset/offset in sync.
|
||||||
|
*/
|
||||||
void doRefresh(RVA addr = Core()->getOffset());
|
void doRefresh(RVA addr = Core()->getOffset());
|
||||||
void updateRefreshButton();
|
void updateRefreshButton();
|
||||||
|
/**
|
||||||
|
* @brief Update fonts
|
||||||
|
*/
|
||||||
void setupFonts();
|
void setupFonts();
|
||||||
|
/**
|
||||||
|
* @brief Update highlights in the text widget.
|
||||||
|
*
|
||||||
|
* These include respective highlights for:
|
||||||
|
* - Line under cursor
|
||||||
|
* - Word under cursor
|
||||||
|
* - Program Counter(PC) while debugging
|
||||||
|
*/
|
||||||
void updateSelection();
|
void updateSelection();
|
||||||
|
/**
|
||||||
|
* @brief Connect/Disconnect SIGNAL-SLOT connection that deals with changes in cursor position.
|
||||||
|
*
|
||||||
|
* If the argument is true, then disconnect the SIGNAL-SLOT connection
|
||||||
|
* that changes the view as cursor position gets changed in the text widget.
|
||||||
|
* Otherwise, connect the corresponding signal with slot.
|
||||||
|
*
|
||||||
|
* @param disconnect
|
||||||
|
*/
|
||||||
void connectCursorPositionChanged(bool disconnect);
|
void connectCursorPositionChanged(bool disconnect);
|
||||||
|
/**
|
||||||
|
* @brief Find the current global offset in sync and update cursor
|
||||||
|
* to the position specified by this offset (found using positionForOffset() )
|
||||||
|
*/
|
||||||
void updateCursorPosition();
|
void updateCursorPosition();
|
||||||
|
|
||||||
QString getWindowTitle() const override;
|
QString getWindowTitle() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Event filter that intercept the following events:
|
||||||
|
* 1. Double click
|
||||||
|
* 2. Right click
|
||||||
|
*
|
||||||
|
* @param obj
|
||||||
|
* @param event
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,21 +173,49 @@ private:
|
|||||||
void highlightBreakpoints();
|
void highlightBreakpoints();
|
||||||
/**
|
/**
|
||||||
* @brief Finds the earliest offset and breakpoints within the specified range [startPos, endPos]
|
* @brief Finds the earliest offset and breakpoints within the specified range [startPos, endPos]
|
||||||
* in the specified RAnnotatedCode
|
* in the specified RAnnotatedCode.
|
||||||
*
|
*
|
||||||
* This function is supposed to be used for finding the earliest offset and breakpoints within the specified range
|
* This function is supposed to be used for finding the earliest offset and breakpoints within the specified range
|
||||||
* [startPos, endPos]. This will set the value of the variables 'RVA firstOffsetInLine' and 'QVector<RVA> availableBreakpoints' in
|
* [startPos, endPos]. This will set the value of the variables 'RVA firstOffsetInLine' and 'QVector<RVA> availableBreakpoints' in
|
||||||
* this->mCtxMenu.
|
* the context menu.
|
||||||
*
|
*
|
||||||
* @param codeDecompiled - A reference to the RAnnotatedCode for the function that is decompiled.
|
* @param codeDecompiled - A reference to the RAnnotatedCode for the function that is decompiled.
|
||||||
* @param startPos - Position of the start of the range(inclusive).
|
* @param startPos - Position of the start of the range(inclusive).
|
||||||
* @param endPos - Position of the end of the range(inclusive).
|
* @param endPos - Position of the end of the range(inclusive).
|
||||||
*/
|
*/
|
||||||
void gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size_t startPos, size_t endPos);
|
void gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size_t startPos, size_t endPos);
|
||||||
|
/**
|
||||||
|
* @brief Finds the offset that's closest to the specified position in the decompiled code.
|
||||||
|
*
|
||||||
|
* @note If no annotations that covers the specified position is found, the first offset in the line
|
||||||
|
* containing specified position will be returned
|
||||||
|
*
|
||||||
|
* @param pos - Position of the decompiled code.
|
||||||
|
* @return Offset for the specified position/first offset in line.
|
||||||
|
*/
|
||||||
|
ut64 offsetForPosition(size_t pos);
|
||||||
|
/**
|
||||||
|
* @brief Find the start position of the annotation with the offset that's closest to
|
||||||
|
* the specified offset
|
||||||
|
*
|
||||||
|
* @param offset
|
||||||
|
* @return Position found or SIZE_MAX
|
||||||
|
*/
|
||||||
|
size_t positionForOffset(ut64 offset);
|
||||||
|
/**
|
||||||
|
* @brief Updates the view when breakpoints are changed
|
||||||
|
*/
|
||||||
void updateBreakpoints();
|
void updateBreakpoints();
|
||||||
|
/**
|
||||||
|
* @brief Set information about the breakpoints on the line in the context menu
|
||||||
|
*/
|
||||||
void setInfoForBreakpoints();
|
void setInfoForBreakpoints();
|
||||||
|
/**
|
||||||
|
* @brief Find the context-related annotation covering the specified position.
|
||||||
|
* If found, set the variable annotationHere in the decompiler context menu.
|
||||||
|
*
|
||||||
|
* @param pos Position of cursor in the decompiled code.
|
||||||
|
*/
|
||||||
void setAnnotationsAtCursor(size_t pos);
|
void setAnnotationsAtCursor(size_t pos);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user