diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 30c1d2a1..bf799b78 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -658,10 +658,10 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) return true; } -void CutterCore::renameFunction(const QString &oldName, const QString &newName) +void CutterCore::renameFunction(const RVA offset, const QString &newName) { - cmdRaw("afn " + newName + " " + oldName); - emit functionRenamed(oldName, newName); + cmdRaw("afn " + newName + " " + RAddressString(offset)); + emit functionRenamed(offset, newName); } void CutterCore::delFunction(RVA addr) @@ -3640,9 +3640,9 @@ void CutterCore::triggerVarsChanged() 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) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 040624fc..40ca53ec 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -143,7 +143,7 @@ public: QStringList autocomplete(const QString &cmd, RLinePromptType promptType, size_t limit = 4096); /* Functions methods */ - void renameFunction(const QString &oldName, const QString &newName); + void renameFunction(const RVA offset, const QString &newName); void delFunction(RVA addr); void renameFlag(QString old_name, QString new_name); @@ -587,7 +587,7 @@ public: /* Signals related */ void triggerVarsChanged(); - void triggerFunctionRenamed(const QString &prevName, const QString &newName); + void triggerFunctionRenamed(const RVA offset, const QString &newName); void triggerRefreshAll(); void triggerAsmOptionsChanged(); void triggerGraphOptionsChanged(); @@ -636,7 +636,7 @@ public: signals: void refreshAll(); - void functionRenamed(const QString &prev_name, const QString &new_name); + void functionRenamed(const RVA offset, const QString &new_name); void varsChanged(); void functionsChanged(); void flagsChanged(); diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index 5ce34f79..6afb74e1 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -10,15 +10,18 @@ #include #include #include +#include DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow) : QMenu(parent), offset(0), isTogglingBreakpoints(false), mainWindow(mainWindow), + annotationHere(nullptr), actionCopy(tr("Copy"), this), actionAddComment(tr("Add Comment"), this), actionDeleteComment(tr("Delete comment"), this), + actionRenameThingHere(tr("Rename function at cursor"), this), actionToggleBreakpoint(tr("Add/remove breakpoint"), this), actionAdvancedBreakpoint(tr("Advanced breakpoint"), this), breakpointsInLineMenu(new QMenu(this)), @@ -31,6 +34,8 @@ DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWi setActionAddComment(); setActionDeleteComment(); + setActionRenameThingHere(); + addSeparator(); addBreakpointMenu(); addDebugMenu(); @@ -47,6 +52,11 @@ DecompilerContextMenu::~DecompilerContextMenu() { } +void DecompilerContextMenu::setAnnotationHere(RCodeAnnotation *annotation) +{ + this->annotationHere = annotation; +} + void DecompilerContextMenu::setOffset(RVA offset) { this->offset = offset; @@ -152,6 +162,14 @@ void DecompilerContextMenu::aboutToShowSlot() QString progCounterName = Core()->getRegisterName("PC").toUpper(); 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 @@ -178,6 +196,14 @@ void DecompilerContextMenu::setActionDeleteComment() addAction(&actionDeleteComment); } +void DecompilerContextMenu::setActionRenameThingHere() +{ + actionRenameThingHere.setShortcut({Qt::SHIFT + Qt::Key_N}); + connect(&actionRenameThingHere, &QAction::triggered, this, + &DecompilerContextMenu::actionRenameThingHereTriggered); + addAction(&actionRenameThingHere); +} + void DecompilerContextMenu::setActionToggleBreakpoint() { connect(&actionToggleBreakpoint, &QAction::triggered, this, @@ -220,6 +246,34 @@ void DecompilerContextMenu::actionDeleteCommentTriggered() 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() { if (!this->availableBreakpoints.isEmpty()) { diff --git a/src/menus/DecompilerContextMenu.h b/src/menus/DecompilerContextMenu.h index bb2cb0b2..26553ccd 100644 --- a/src/menus/DecompilerContextMenu.h +++ b/src/menus/DecompilerContextMenu.h @@ -5,6 +5,8 @@ #include #include +#include + class DecompilerContextMenu : public QMenu { Q_OBJECT @@ -14,6 +16,7 @@ public: ~DecompilerContextMenu(); bool getIsTogglingBreakpoints(); + void setAnnotationHere(RCodeAnnotation *annotation); signals: void copy(); @@ -34,6 +37,8 @@ private slots: void actionAddCommentTriggered(); void actionDeleteCommentTriggered(); + void actionRenameThingHereTriggered(); + void actionToggleBreakpointTriggered(); void actionAdvancedBreakpointTriggered(); @@ -48,12 +53,16 @@ private: QVector availableBreakpoints; MainWindow *mainWindow; + RCodeAnnotation *annotationHere; + QAction actionCopy; QAction *copySeparator; QAction actionAddComment; QAction actionDeleteComment; + QAction actionRenameThingHere; + QMenu *breakpointMenu; QAction actionToggleBreakpoint; QAction actionAdvancedBreakpoint; @@ -75,6 +84,8 @@ private: void setActionAddComment(); void setActionDeleteComment(); + void setActionRenameThingHere(); + void setActionToggleBreakpoint(); void setActionAdvancedBreakpoint(); diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index c83bf6d0..4987c1a1 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -818,7 +818,7 @@ void DisassemblyContextMenu::on_actionRename_triggered() QString newName = QInputDialog::getText(this, tr("Rename function %2").arg(fcn->name), tr("Function name:"), QLineEdit::Normal, fcn->name, &ok); if (ok && !newName.isEmpty()) { - Core()->renameFunction(fcn->name, newName); + Core()->renameFunction(fcn->addr, newName); } } else if (f) { // Renaming flag @@ -863,13 +863,12 @@ void DisassemblyContextMenu::on_actionRenameUsedHere_triggered() // If user accepted if (ok && !newName.isEmpty()) { Core()->cmdRawAt(QString("an %1").arg(newName), offset); - if (type == ThingUsedHere::Type::Address || type == ThingUsedHere::Type::Flag) { Core()->triggerFlagsChanged(); } else if (type == ThingUsedHere::Type::Var) { Core()->triggerVarsChanged(); } 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()) { QString new_name = dialog.getNameText(); - Core()->renameFunction(fcn->name, new_name); + Core()->renameFunction(fcn->addr, new_name); QString new_start_addr = dialog.getStartAddrText(); fcn->addr = Core()->math(new_start_addr); QString new_stack_size = dialog.getStackSizeText(); diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index e34c3f92..bba012ea 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -284,7 +284,8 @@ void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled) ui->progressLabel->setVisible(false); ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled); updateRefreshButton(); - + + mCtxMenu->setAnnotationHere(nullptr); this->code.reset(codeDecompiled); QString codeString = QString::fromUtf8(this->code->code); 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() { Config()->setSelectedDecompiler(ui->decompilerComboBox->currentData().toString()); @@ -333,7 +351,7 @@ void DecompilerWidget::cursorPositionChanged() } size_t pos = ui->textEdit->textCursor().position(); - + setAnnotationsAtCursor(pos); setInfoForBreakpoints(); diff --git a/src/widgets/DecompilerWidget.h b/src/widgets/DecompilerWidget.h index e5876a57..eedd2df7 100644 --- a/src/widgets/DecompilerWidget.h +++ b/src/widgets/DecompilerWidget.h @@ -113,6 +113,8 @@ private: void gatherBreakpointInfo(RAnnotatedCode &codeDecompiled, size_t startPos, size_t endPos); void setInfoForBreakpoints(); + + void setAnnotationsAtCursor(size_t pos); }; #endif // DECOMPILERWIDGET_H diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index de36f38f..dd8c7780 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -43,8 +43,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se // Signals that require a refresh all connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshView())); connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshView())); - connect(Core(), SIGNAL(functionRenamed(const QString &, const QString &)), this, - SLOT(refreshView())); + connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView); connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshView())); connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshView())); connect(Core(), SIGNAL(instructionChanged(RVA)), this, SLOT(refreshView())); diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 043efdad..bce516a7 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -148,8 +148,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main) connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshDisasm())); - connect(Core(), SIGNAL(functionRenamed(const QString &, const QString &)), this, - SLOT(refreshDisasm())); + connect(Core(), &CutterCore::functionRenamed, this, [this]() {refreshDisasm();}); connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshDisasm())); connect(Core(), &CutterCore::instructionChanged, this, [this](RVA offset) { diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 97825d7d..a20bbe3c 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -334,11 +334,11 @@ bool FunctionModel::updateCurrentIndex() 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++) { FunctionDescription &function = (*functions)[i]; - if (function.name == prev_name) { + if (function.offset == offset) { function.name = new_name; emit dataChanged(index(i, 0), index(i, columnCount() - 1)); } @@ -533,7 +533,7 @@ void FunctionsWidget::onActionFunctionsRenameTriggered() // If user accepted if (ok && !newName.isEmpty()) { // Rename function in r2 core - Core()->renameFunction(function.name, newName); + Core()->renameFunction(function.offset, newName); // Seek to new renamed function Core()->seekAndShow(function.offset); diff --git a/src/widgets/FunctionsWidget.h b/src/widgets/FunctionsWidget.h index 93ff3955..d4fa4d94 100644 --- a/src/widgets/FunctionsWidget.h +++ b/src/widgets/FunctionsWidget.h @@ -69,7 +69,7 @@ public: QString name(const QModelIndex &index) const override; private slots: void seekChanged(RVA addr); - void functionRenamed(const QString &prev_name, const QString &new_name); + void functionRenamed(const RVA offset, const QString &new_name); };