mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-12 07:36:16 +00:00
Edit/Rename Variables Actions for function variables (#2357)
* Edit Function Variables Action * Rename Function Variables Action * CutterCore::renameFunctionVariable
This commit is contained in:
parent
6ed32d5d1d
commit
1c86f54c95
@ -676,6 +676,17 @@ void CutterCore::renameFlag(QString old_name, QString new_name)
|
||||
emit flagsChanged();
|
||||
}
|
||||
|
||||
void CutterCore::renameFunctionVariable(QString newName, QString oldName, RVA functionAddress)
|
||||
{
|
||||
CORE_LOCK();
|
||||
RAnalFunction *function = r_anal_get_function_at(core->anal, functionAddress);
|
||||
RAnalVar *variable = r_anal_function_get_var_byname(function, oldName.toUtf8().constData());
|
||||
if (variable) {
|
||||
r_anal_var_rename(variable, newName.toUtf8().constData(), true);
|
||||
}
|
||||
emit refreshCodeViews();
|
||||
}
|
||||
|
||||
void CutterCore::delFlag(RVA addr)
|
||||
{
|
||||
cmdRawAt("f-", addr);
|
||||
|
@ -146,6 +146,15 @@ public:
|
||||
void renameFunction(const RVA offset, const QString &newName);
|
||||
void delFunction(RVA addr);
|
||||
void renameFlag(QString old_name, QString new_name);
|
||||
/**
|
||||
* @brief Renames the specified local variable in the function specified by the
|
||||
* address given.
|
||||
* @param newName Specifies the name to which the current name of the variable
|
||||
* should be renamed.
|
||||
* @param oldName Specifies the current name of the function variable.
|
||||
* @param functionAddress Specifies the exact address of the function.
|
||||
*/
|
||||
void renameFunctionVariable(QString newName, QString oldName, RVA functionAddress);
|
||||
|
||||
/**
|
||||
* @param addr
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
EditVariablesDialog::EditVariablesDialog(RVA offset, QString initialVar, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::EditVariablesDialog)
|
||||
ui(new Ui::EditVariablesDialog),
|
||||
functionAddress(RVA_INVALID)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &EditVariablesDialog::applyFields);
|
||||
@ -17,7 +18,8 @@ EditVariablesDialog::EditVariablesDialog(RVA offset, QString initialVar, QWidget
|
||||
this, &EditVariablesDialog::updateFields);
|
||||
|
||||
QString fcnName = Core()->cmdRawAt("afn.", offset).trimmed();
|
||||
setWindowTitle(tr("Set Variable Types for Function: %1").arg(fcnName));
|
||||
functionAddress = offset;
|
||||
setWindowTitle(tr("Edit Variables in Function: %1").arg(fcnName));
|
||||
|
||||
variables = Core()->getVariables(offset);
|
||||
int currentItemIndex = -1;
|
||||
@ -63,7 +65,7 @@ void EditVariablesDialog::applyFields()
|
||||
.replace(QLatin1Char('\\'), QLatin1Char('_'))
|
||||
.replace(QLatin1Char('/'), QLatin1Char('_'));
|
||||
if (newName != desc.name) {
|
||||
Core()->cmdRaw(QString("afvn %1 %2").arg(newName).arg(desc.name));
|
||||
Core()->renameFunctionVariable(newName, desc.name, functionAddress);
|
||||
}
|
||||
|
||||
// Refresh the views to reflect the changes to vars
|
||||
|
@ -23,6 +23,7 @@ private slots:
|
||||
|
||||
private:
|
||||
Ui::EditVariablesDialog *ui;
|
||||
RVA functionAddress;
|
||||
QList<VariableDescription> variables;
|
||||
|
||||
void populateTypesComboBox();
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "MainWindow.h"
|
||||
#include "dialogs/BreakpointsDialog.h"
|
||||
#include "dialogs/CommentsDialog.h"
|
||||
#include "dialogs/EditVariablesDialog.h"
|
||||
#include "dialogs/XrefsDialog.h"
|
||||
#include "common/Configuration.h"
|
||||
|
||||
@ -18,6 +19,7 @@ DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWi
|
||||
: QMenu(parent),
|
||||
curHighlightedWord(QString()),
|
||||
offset(0),
|
||||
decompiledFunctionAddress(RVA_INVALID),
|
||||
isTogglingBreakpoints(false),
|
||||
mainWindow(mainWindow),
|
||||
annotationHere(nullptr),
|
||||
@ -29,6 +31,7 @@ DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWi
|
||||
actionDeleteComment(tr("Delete comment"), this),
|
||||
actionRenameThingHere(tr("Rename function at cursor"), this),
|
||||
actionDeleteName(tr("Delete <name>"), this),
|
||||
actionEditFunctionVariables(tr("Edit variable <name of variable>"), this),
|
||||
actionXRefs(tr("Show X-Refs"), this),
|
||||
actionToggleBreakpoint(tr("Add/remove breakpoint"), this),
|
||||
actionAdvancedBreakpoint(tr("Advanced breakpoint"), this),
|
||||
@ -50,6 +53,8 @@ DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWi
|
||||
setActionRenameThingHere();
|
||||
setActionDeleteName();
|
||||
|
||||
setActionEditFunctionVariables();
|
||||
|
||||
addSeparator();
|
||||
addBreakpointMenu();
|
||||
addDebugMenu();
|
||||
@ -83,6 +88,11 @@ void DecompilerContextMenu::setOffset(RVA offset)
|
||||
// this->actionSetFunctionVarTypes.setVisible(true);
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::setDecompiledFunctionAddress(RVA functionAddr)
|
||||
{
|
||||
this->decompiledFunctionAddress = functionAddr;
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::setFirstOffsetInLine(RVA firstOffset)
|
||||
{
|
||||
this->firstOffsetInLine = firstOffset;
|
||||
@ -132,8 +142,12 @@ void DecompilerContextMenu::aboutToHideSlot()
|
||||
{
|
||||
actionAddComment.setVisible(true);
|
||||
actionRenameThingHere.setVisible(true);
|
||||
actionRenameThingHere.setEnabled(true);
|
||||
actionDeleteName.setVisible(false);
|
||||
actionEditFunctionVariables.setVisible(true);
|
||||
actionEditFunctionVariables.setEnabled(true);
|
||||
actionXRefs.setVisible(true);
|
||||
setToolTipsVisible(false);
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::aboutToShowSlot()
|
||||
@ -190,11 +204,9 @@ void DecompilerContextMenu::aboutToShowSlot()
|
||||
} else {
|
||||
copySeparator->setVisible(true);
|
||||
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME) {
|
||||
actionRenameThingHere.setVisible(true);
|
||||
actionRenameThingHere.setText(tr("Rename function %1").arg(QString(
|
||||
annotationHere->reference.name)));
|
||||
}
|
||||
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) {
|
||||
} else if (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) {
|
||||
RFlagItem *flagDetails = r_flag_get_i(Core()->core()->flags, annotationHere->reference.offset);
|
||||
if (flagDetails) {
|
||||
actionRenameThingHere.setText(tr("Rename %1").arg(QString(flagDetails->name)));
|
||||
@ -229,6 +241,19 @@ void DecompilerContextMenu::aboutToShowSlot()
|
||||
}
|
||||
actionShowInSubmenu.setMenu(mainWindow->createShowInMenu(this, offset));
|
||||
updateTargetMenuActions();
|
||||
|
||||
if (!isFunctionVariable()) {
|
||||
actionEditFunctionVariables.setVisible(false);
|
||||
} else {
|
||||
actionEditFunctionVariables.setText(tr("Edit variable %1").arg(QString(
|
||||
annotationHere->variable.name)));
|
||||
actionRenameThingHere.setText(tr("Rename variable %1").arg(QString(annotationHere->variable.name)));
|
||||
if (!variablePresentInR2()) {
|
||||
actionEditFunctionVariables.setDisabled(true);
|
||||
actionRenameThingHere.setDisabled(true);
|
||||
setToolTipsVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up actions
|
||||
@ -283,6 +308,8 @@ void DecompilerContextMenu::setActionRenameThingHere()
|
||||
connect(&actionRenameThingHere, &QAction::triggered, this,
|
||||
&DecompilerContextMenu::actionRenameThingHereTriggered);
|
||||
addAction(&actionRenameThingHere);
|
||||
actionRenameThingHere.setToolTip(tr("Can't rename this variable.<br>"
|
||||
"Only local variables defined in disassembly can be renamed."));
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::setActionDeleteName()
|
||||
@ -293,6 +320,16 @@ void DecompilerContextMenu::setActionDeleteName()
|
||||
actionDeleteName.setVisible(false);
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::setActionEditFunctionVariables()
|
||||
{
|
||||
connect(&actionEditFunctionVariables, &QAction::triggered, this,
|
||||
&DecompilerContextMenu::actionEditFunctionVariablesTriggered);
|
||||
addAction(&actionEditFunctionVariables);
|
||||
actionEditFunctionVariables.setShortcut(Qt::Key_Y);
|
||||
actionEditFunctionVariables.setToolTip(tr("Can't edit this variable.<br>"
|
||||
"Only local variables defined in disassembly can be edited."));
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::setActionToggleBreakpoint()
|
||||
{
|
||||
connect(&actionToggleBreakpoint, &QAction::triggered, this,
|
||||
@ -390,7 +427,21 @@ void DecompilerContextMenu::actionRenameThingHereTriggered()
|
||||
Core()->addFlag(var_addr, newName, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (isFunctionVariable()) {
|
||||
if (!variablePresentInR2()) {
|
||||
// Show can't rename this variable dialog
|
||||
QMessageBox::critical(this, tr("Rename local variable %1").arg(QString(
|
||||
annotationHere->variable.name)),
|
||||
tr("Can't rename this variable. "
|
||||
"Only local variables defined in disassembly can be renamed."));
|
||||
return;
|
||||
}
|
||||
QString oldName(annotationHere->variable.name);
|
||||
QString newName = QInputDialog::getText(this, tr("Rename %2").arg(oldName),
|
||||
tr("Enter name"), QLineEdit::Normal, oldName, &ok);
|
||||
if (ok && !newName.isEmpty()) {
|
||||
Core()->renameFunctionVariable(newName, oldName, decompiledFunctionAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,6 +450,21 @@ void DecompilerContextMenu::actionDeleteNameTriggered()
|
||||
Core()->delFlag(annotationHere->reference.offset);
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::actionEditFunctionVariablesTriggered()
|
||||
{
|
||||
if (!isFunctionVariable()) {
|
||||
return;
|
||||
} else if (!variablePresentInR2()) {
|
||||
QMessageBox::critical(this, tr("Edit local variable %1").arg(QString(
|
||||
annotationHere->variable.name)),
|
||||
tr("Can't edit this variable. "
|
||||
"Only local variables defined in disassembly can be edited."));
|
||||
return;
|
||||
}
|
||||
EditVariablesDialog dialog(decompiledFunctionAddress, QString(annotationHere->variable.name), this);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::actionXRefsTriggered()
|
||||
{
|
||||
if (!annotationHere || !r_annotation_is_reference(annotationHere)) {
|
||||
@ -513,3 +579,20 @@ void DecompilerContextMenu::updateTargetMenuActions()
|
||||
insertActions(copySeparator, showTargetMenuActions);
|
||||
}
|
||||
}
|
||||
|
||||
bool DecompilerContextMenu::isFunctionVariable()
|
||||
{
|
||||
return (annotationHere && r_annotation_is_variable(annotationHere));
|
||||
}
|
||||
|
||||
bool DecompilerContextMenu::variablePresentInR2()
|
||||
{
|
||||
QString variableName(annotationHere->variable.name);
|
||||
QList<VariableDescription> variables = Core()->getVariables(offset);
|
||||
for (const VariableDescription &var : variables) {
|
||||
if (var.name == variableName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ signals:
|
||||
public slots:
|
||||
void setCurHighlightedWord(QString word);
|
||||
void setOffset(RVA offset);
|
||||
void setDecompiledFunctionAddress(RVA functionAddr);
|
||||
void setFirstOffsetInLine(RVA firstOffset);
|
||||
void setAvailableBreakpoints(QVector<RVA> offsetList);
|
||||
|
||||
@ -42,6 +43,8 @@ private slots:
|
||||
void actionRenameThingHereTriggered();
|
||||
void actionDeleteNameTriggered();
|
||||
|
||||
void actionEditFunctionVariablesTriggered();
|
||||
|
||||
void actionXRefsTriggered();
|
||||
|
||||
void actionToggleBreakpointTriggered();
|
||||
@ -54,6 +57,7 @@ private:
|
||||
// Private variables
|
||||
QString curHighlightedWord;
|
||||
RVA offset;
|
||||
RVA decompiledFunctionAddress;
|
||||
RVA firstOffsetInLine;
|
||||
bool isTogglingBreakpoints;
|
||||
QVector<RVA> availableBreakpoints;
|
||||
@ -75,6 +79,8 @@ private:
|
||||
QAction actionRenameThingHere;
|
||||
QAction actionDeleteName;
|
||||
|
||||
QAction actionEditFunctionVariables;
|
||||
|
||||
QAction actionXRefs;
|
||||
|
||||
QMenu *breakpointMenu;
|
||||
@ -105,6 +111,8 @@ private:
|
||||
void setActionRenameThingHere();
|
||||
void setActionDeleteName();
|
||||
|
||||
void setActionEditFunctionVariables();
|
||||
|
||||
void setActionToggleBreakpoint();
|
||||
void setActionAdvancedBreakpoint();
|
||||
|
||||
@ -114,25 +122,11 @@ private:
|
||||
// Add Menus
|
||||
void addBreakpointMenu();
|
||||
void addDebugMenu();
|
||||
// I left out the following part from RAnnotatedCode. Probably, we will be returning/passing annotations
|
||||
// from/to the function getThingUsedHere() and updateTargetMenuActions(). This block of comment will get removed in
|
||||
// future PRs.
|
||||
//
|
||||
// struct ThingUsedHere {
|
||||
// QString name;
|
||||
// RVA offset;
|
||||
// enum class Type {
|
||||
// Var,
|
||||
// Function,
|
||||
// Flag,
|
||||
// Address
|
||||
// };
|
||||
// Type type;
|
||||
// };
|
||||
// QVector<ThingUsedHere> getThingUsedHere(RVA offset);
|
||||
|
||||
// void updateTargetMenuActions(const QVector<ThingUsedHere> &targets);
|
||||
void updateTargetMenuActions();
|
||||
|
||||
bool isFunctionVariable();
|
||||
bool variablePresentInR2();
|
||||
};
|
||||
|
||||
#endif // DECOMPILERCONTEXTMENU_H
|
@ -883,7 +883,7 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
|
||||
return;
|
||||
}
|
||||
|
||||
EditVariablesDialog dialog(Core()->getOffset(), curHighlightedWord, this);
|
||||
EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this);
|
||||
if (dialog.empty()) { // don't show the dialog if there are no variables
|
||||
return;
|
||||
}
|
||||
|
@ -269,6 +269,7 @@ void DecompilerWidget::doRefresh(RVA addr)
|
||||
ui->textEdit->setExtraSelections({});
|
||||
previousFunctionAddr = decompiledFunctionAddr;
|
||||
decompiledFunctionAddr = Core()->getFunctionStart(addr);
|
||||
mCtxMenu->setDecompiledFunctionAddress(decompiledFunctionAddr);
|
||||
dec->decompileAt(addr);
|
||||
if (dec->isRunning()) {
|
||||
ui->progressLabel->setVisible(true);
|
||||
|
Loading…
Reference in New Issue
Block a user