Action to rename functions in the decompiler context menu (#2286)

This commit is contained in:
NIRMAL MANOJ C 2020-07-16 14:26:38 +05:30
parent 88f837465f
commit eef9baa300
11 changed files with 104 additions and 22 deletions

View File

@ -658,10 +658,10 @@ bool CutterCore::mapFile(QString path, RVA mapaddr)
return true; return true;
} }
void CutterCore::renameFunction(const QString &oldName, const QString &newName) void CutterCore::renameFunction(const RVA offset, const QString &newName)
{ {
cmdRaw("afn " + newName + " " + oldName); cmdRaw("afn " + newName + " " + RAddressString(offset));
emit functionRenamed(oldName, newName); emit functionRenamed(offset, newName);
} }
void CutterCore::delFunction(RVA addr) void CutterCore::delFunction(RVA addr)
@ -3640,9 +3640,9 @@ void CutterCore::triggerVarsChanged()
emit varsChanged(); emit varsChanged();
} }
void CutterCore::triggerFunctionRenamed(const QString &prevName, const QString &newName) void CutterCore::triggerFunctionRenamed(const RVA offset, const QString &newName)
{ {
emit functionRenamed(prevName, newName); emit functionRenamed(offset, newName);
} }
void CutterCore::loadPDB(const QString &file) void CutterCore::loadPDB(const QString &file)

View File

@ -143,7 +143,7 @@ public:
QStringList autocomplete(const QString &cmd, RLinePromptType promptType, size_t limit = 4096); QStringList autocomplete(const QString &cmd, RLinePromptType promptType, size_t limit = 4096);
/* Functions methods */ /* Functions methods */
void renameFunction(const QString &oldName, const QString &newName); void renameFunction(const RVA offset, const QString &newName);
void delFunction(RVA addr); void delFunction(RVA addr);
void renameFlag(QString old_name, QString new_name); void renameFlag(QString old_name, QString new_name);
@ -587,7 +587,7 @@ public:
/* Signals related */ /* Signals related */
void triggerVarsChanged(); void triggerVarsChanged();
void triggerFunctionRenamed(const QString &prevName, const QString &newName); void triggerFunctionRenamed(const RVA offset, const QString &newName);
void triggerRefreshAll(); void triggerRefreshAll();
void triggerAsmOptionsChanged(); void triggerAsmOptionsChanged();
void triggerGraphOptionsChanged(); void triggerGraphOptionsChanged();
@ -636,7 +636,7 @@ public:
signals: signals:
void refreshAll(); void refreshAll();
void functionRenamed(const QString &prev_name, const QString &new_name); void functionRenamed(const RVA offset, const QString &new_name);
void varsChanged(); void varsChanged();
void functionsChanged(); void functionsChanged();
void flagsChanged(); void flagsChanged();

View File

@ -10,15 +10,18 @@
#include <QClipboard> #include <QClipboard>
#include <QApplication> #include <QApplication>
#include <QPushButton> #include <QPushButton>
#include <QInputDialog>
DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow) DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow)
: QMenu(parent), : QMenu(parent),
offset(0), offset(0),
isTogglingBreakpoints(false), isTogglingBreakpoints(false),
mainWindow(mainWindow), mainWindow(mainWindow),
annotationHere(nullptr),
actionCopy(tr("Copy"), this), actionCopy(tr("Copy"), this),
actionAddComment(tr("Add Comment"), this), actionAddComment(tr("Add Comment"), this),
actionDeleteComment(tr("Delete comment"), this), actionDeleteComment(tr("Delete comment"), this),
actionRenameThingHere(tr("Rename function at cursor"), this),
actionToggleBreakpoint(tr("Add/remove breakpoint"), this), actionToggleBreakpoint(tr("Add/remove breakpoint"), this),
actionAdvancedBreakpoint(tr("Advanced breakpoint"), this), actionAdvancedBreakpoint(tr("Advanced breakpoint"), this),
breakpointsInLineMenu(new QMenu(this)), breakpointsInLineMenu(new QMenu(this)),
@ -31,6 +34,8 @@ DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWi
setActionAddComment(); setActionAddComment();
setActionDeleteComment(); setActionDeleteComment();
setActionRenameThingHere();
addSeparator(); addSeparator();
addBreakpointMenu(); addBreakpointMenu();
addDebugMenu(); addDebugMenu();
@ -47,6 +52,11 @@ DecompilerContextMenu::~DecompilerContextMenu()
{ {
} }
void DecompilerContextMenu::setAnnotationHere(RCodeAnnotation *annotation)
{
this->annotationHere = annotation;
}
void DecompilerContextMenu::setOffset(RVA offset) void DecompilerContextMenu::setOffset(RVA offset)
{ {
this->offset = offset; this->offset = offset;
@ -152,6 +162,14 @@ void DecompilerContextMenu::aboutToShowSlot()
QString progCounterName = Core()->getRegisterName("PC").toUpper(); QString progCounterName = Core()->getRegisterName("PC").toUpper();
actionSetPC.setText(tr("Set %1 here").arg(progCounterName)); actionSetPC.setText(tr("Set %1 here").arg(progCounterName));
if (!annotationHere) { // To be considered as invalid
actionRenameThingHere.setVisible(false);
} else {
actionRenameThingHere.setVisible(true);
actionRenameThingHere.setText(tr("Rename function %1").arg(QString(
annotationHere->function_name.name)));
}
} }
// Set up actions // Set up actions
@ -178,6 +196,14 @@ void DecompilerContextMenu::setActionDeleteComment()
addAction(&actionDeleteComment); addAction(&actionDeleteComment);
} }
void DecompilerContextMenu::setActionRenameThingHere()
{
actionRenameThingHere.setShortcut({Qt::SHIFT + Qt::Key_N});
connect(&actionRenameThingHere, &QAction::triggered, this,
&DecompilerContextMenu::actionRenameThingHereTriggered);
addAction(&actionRenameThingHere);
}
void DecompilerContextMenu::setActionToggleBreakpoint() void DecompilerContextMenu::setActionToggleBreakpoint()
{ {
connect(&actionToggleBreakpoint, &QAction::triggered, this, connect(&actionToggleBreakpoint, &QAction::triggered, this,
@ -220,6 +246,34 @@ void DecompilerContextMenu::actionDeleteCommentTriggered()
Core()->delComment(this->firstOffsetInLine); Core()->delComment(this->firstOffsetInLine);
} }
void DecompilerContextMenu::actionRenameThingHereTriggered()
{
if (!annotationHere) {
return;
}
bool ok;
auto type = annotationHere->type;
if (type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME) {
QString currentName(annotationHere->function_name.name);
RVA func_addr = annotationHere->function_name.offset;
RAnalFunction *func = Core()->functionAt(func_addr);
if (func == NULL) {
QString function_name = QInputDialog::getText(this, tr("Define this function at %2").arg(RAddressString(func_addr)),
tr("Function name:"), QLineEdit::Normal, currentName, &ok);
if (ok && !function_name.isEmpty()) {
Core()->createFunctionAt(func_addr, function_name);
}
} else {
QString newName = QInputDialog::getText(this, tr("Rename function %2").arg(currentName),
tr("Function name:"), QLineEdit::Normal, currentName, &ok);
if (ok && !newName.isEmpty()) {
Core()->renameFunction(func_addr, newName);
}
}
}
}
void DecompilerContextMenu::actionToggleBreakpointTriggered() void DecompilerContextMenu::actionToggleBreakpointTriggered()
{ {
if (!this->availableBreakpoints.isEmpty()) { if (!this->availableBreakpoints.isEmpty()) {

View File

@ -5,6 +5,8 @@
#include <QMenu> #include <QMenu>
#include <QKeySequence> #include <QKeySequence>
#include <r_util/r_annotated_code.h>
class DecompilerContextMenu : public QMenu class DecompilerContextMenu : public QMenu
{ {
Q_OBJECT Q_OBJECT
@ -14,6 +16,7 @@ public:
~DecompilerContextMenu(); ~DecompilerContextMenu();
bool getIsTogglingBreakpoints(); bool getIsTogglingBreakpoints();
void setAnnotationHere(RCodeAnnotation *annotation);
signals: signals:
void copy(); void copy();
@ -34,6 +37,8 @@ private slots:
void actionAddCommentTriggered(); void actionAddCommentTriggered();
void actionDeleteCommentTriggered(); void actionDeleteCommentTriggered();
void actionRenameThingHereTriggered();
void actionToggleBreakpointTriggered(); void actionToggleBreakpointTriggered();
void actionAdvancedBreakpointTriggered(); void actionAdvancedBreakpointTriggered();
@ -48,12 +53,16 @@ private:
QVector<RVA> availableBreakpoints; QVector<RVA> availableBreakpoints;
MainWindow *mainWindow; MainWindow *mainWindow;
RCodeAnnotation *annotationHere;
QAction actionCopy; QAction actionCopy;
QAction *copySeparator; QAction *copySeparator;
QAction actionAddComment; QAction actionAddComment;
QAction actionDeleteComment; QAction actionDeleteComment;
QAction actionRenameThingHere;
QMenu *breakpointMenu; QMenu *breakpointMenu;
QAction actionToggleBreakpoint; QAction actionToggleBreakpoint;
QAction actionAdvancedBreakpoint; QAction actionAdvancedBreakpoint;
@ -75,6 +84,8 @@ private:
void setActionAddComment(); void setActionAddComment();
void setActionDeleteComment(); void setActionDeleteComment();
void setActionRenameThingHere();
void setActionToggleBreakpoint(); void setActionToggleBreakpoint();
void setActionAdvancedBreakpoint(); void setActionAdvancedBreakpoint();

View File

@ -818,7 +818,7 @@ void DisassemblyContextMenu::on_actionRename_triggered()
QString newName = QInputDialog::getText(this, tr("Rename function %2").arg(fcn->name), QString newName = QInputDialog::getText(this, tr("Rename function %2").arg(fcn->name),
tr("Function name:"), QLineEdit::Normal, fcn->name, &ok); tr("Function name:"), QLineEdit::Normal, fcn->name, &ok);
if (ok && !newName.isEmpty()) { if (ok && !newName.isEmpty()) {
Core()->renameFunction(fcn->name, newName); Core()->renameFunction(fcn->addr, newName);
} }
} else if (f) { } else if (f) {
// Renaming flag // Renaming flag
@ -863,13 +863,12 @@ void DisassemblyContextMenu::on_actionRenameUsedHere_triggered()
// If user accepted // If user accepted
if (ok && !newName.isEmpty()) { if (ok && !newName.isEmpty()) {
Core()->cmdRawAt(QString("an %1").arg(newName), offset); Core()->cmdRawAt(QString("an %1").arg(newName), offset);
if (type == ThingUsedHere::Type::Address || type == ThingUsedHere::Type::Flag) { if (type == ThingUsedHere::Type::Address || type == ThingUsedHere::Type::Flag) {
Core()->triggerFlagsChanged(); Core()->triggerFlagsChanged();
} else if (type == ThingUsedHere::Type::Var) { } else if (type == ThingUsedHere::Type::Var) {
Core()->triggerVarsChanged(); Core()->triggerVarsChanged();
} else if (type == ThingUsedHere::Type::Function) { } else if (type == ThingUsedHere::Type::Function) {
Core()->triggerFunctionRenamed(oldName, newName); Core()->triggerFunctionRenamed(thingUsedHere.offset, newName);
} }
} }
} }
@ -1041,7 +1040,7 @@ void DisassemblyContextMenu::on_actionEditFunction_triggered()
if (dialog.exec()) { if (dialog.exec()) {
QString new_name = dialog.getNameText(); QString new_name = dialog.getNameText();
Core()->renameFunction(fcn->name, new_name); Core()->renameFunction(fcn->addr, new_name);
QString new_start_addr = dialog.getStartAddrText(); QString new_start_addr = dialog.getStartAddrText();
fcn->addr = Core()->math(new_start_addr); fcn->addr = Core()->math(new_start_addr);
QString new_stack_size = dialog.getStackSizeText(); QString new_stack_size = dialog.getStackSizeText();

View File

@ -284,7 +284,8 @@ void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
ui->progressLabel->setVisible(false); ui->progressLabel->setVisible(false);
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled); ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
updateRefreshButton(); updateRefreshButton();
mCtxMenu->setAnnotationHere(nullptr);
this->code.reset(codeDecompiled); this->code.reset(codeDecompiled);
QString codeString = QString::fromUtf8(this->code->code); QString codeString = QString::fromUtf8(this->code->code);
if (codeString.isEmpty()) { if (codeString.isEmpty()) {
@ -305,6 +306,23 @@ void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
} }
} }
void DecompilerWidget::setAnnotationsAtCursor(size_t pos)
{
RCodeAnnotation *annotationAtPos = nullptr;
void *annotationi;
r_vector_foreach(&this->code->annotations, annotationi) {
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
if (annotation->type == R_CODE_ANNOTATION_TYPE_OFFSET ||
annotation->type == R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT ||
annotation->start > pos || annotation->end <= pos) {
continue;
}
annotationAtPos = annotation;
break;
}
mCtxMenu->setAnnotationHere(annotationAtPos);
}
void DecompilerWidget::decompilerSelected() void DecompilerWidget::decompilerSelected()
{ {
Config()->setSelectedDecompiler(ui->decompilerComboBox->currentData().toString()); Config()->setSelectedDecompiler(ui->decompilerComboBox->currentData().toString());
@ -333,7 +351,7 @@ void DecompilerWidget::cursorPositionChanged()
} }
size_t pos = ui->textEdit->textCursor().position(); size_t pos = ui->textEdit->textCursor().position();
setAnnotationsAtCursor(pos);
setInfoForBreakpoints(); setInfoForBreakpoints();

View File

@ -113,6 +113,8 @@ private:
void gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size_t startPos, size_t endPos); void gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size_t startPos, size_t endPos);
void setInfoForBreakpoints(); void setInfoForBreakpoints();
void setAnnotationsAtCursor(size_t pos);
}; };
#endif // DECOMPILERWIDGET_H #endif // DECOMPILERWIDGET_H

View File

@ -43,8 +43,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
// 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(), SIGNAL(commentsChanged()), this, SLOT(refreshView()));
connect(Core(), SIGNAL(functionRenamed(const QString &, const QString &)), this, connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView);
SLOT(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()));
connect(Core(), SIGNAL(instructionChanged(RVA)), this, SLOT(refreshView())); connect(Core(), SIGNAL(instructionChanged(RVA)), this, SLOT(refreshView()));

View File

@ -148,8 +148,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main)
connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(commentsChanged()), this, SLOT(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(), SIGNAL(functionRenamed(const QString &, const QString &)), this, connect(Core(), &CutterCore::functionRenamed, this, [this]() {refreshDisasm();});
SLOT(refreshDisasm()));
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm()));
connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshDisasm()));
connect(Core(), &CutterCore::instructionChanged, this, [this](RVA offset) { connect(Core(), &CutterCore::instructionChanged, this, [this](RVA offset) {

View File

@ -334,11 +334,11 @@ bool FunctionModel::updateCurrentIndex()
return changed; return changed;
} }
void FunctionModel::functionRenamed(const QString &prev_name, const QString &new_name) void FunctionModel::functionRenamed(const RVA offset, const QString &new_name)
{ {
for (int i = 0; i < functions->count(); i++) { for (int i = 0; i < functions->count(); i++) {
FunctionDescription &function = (*functions)[i]; FunctionDescription &function = (*functions)[i];
if (function.name == prev_name) { if (function.offset == offset) {
function.name = new_name; function.name = new_name;
emit dataChanged(index(i, 0), index(i, columnCount() - 1)); emit dataChanged(index(i, 0), index(i, columnCount() - 1));
} }
@ -533,7 +533,7 @@ void FunctionsWidget::onActionFunctionsRenameTriggered()
// If user accepted // If user accepted
if (ok && !newName.isEmpty()) { if (ok && !newName.isEmpty()) {
// Rename function in r2 core // Rename function in r2 core
Core()->renameFunction(function.name, newName); Core()->renameFunction(function.offset, newName);
// Seek to new renamed function // Seek to new renamed function
Core()->seekAndShow(function.offset); Core()->seekAndShow(function.offset);

View File

@ -69,7 +69,7 @@ public:
QString name(const QModelIndex &index) const override; QString name(const QModelIndex &index) const override;
private slots: private slots:
void seekChanged(RVA addr); void seekChanged(RVA addr);
void functionRenamed(const QString &prev_name, const QString &new_name); void functionRenamed(const RVA offset, const QString &new_name);
}; };