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;
}
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)

View File

@ -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();

View File

@ -10,15 +10,18 @@
#include <QClipboard>
#include <QApplication>
#include <QPushButton>
#include <QInputDialog>
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()) {

View File

@ -5,6 +5,8 @@
#include <QMenu>
#include <QKeySequence>
#include <r_util/r_annotated_code.h>
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<RVA> 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();

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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()));

View File

@ -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) {

View File

@ -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);

View File

@ -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);
};