From be4144babea20206d2372ec37baccdea3c683971 Mon Sep 17 00:00:00 2001 From: jamieb122 <5406474+jamieb122@users.noreply.github.com> Date: Wed, 3 Oct 2018 13:10:53 -0700 Subject: [PATCH] afvn/afvt support via context menu (#708) * Added ability to re-type local vars in Dissassembly Widget. Can re-type to any loaded structs, types or enums * afvn support via context menu --- src/Cutter.pro | 9 +- src/dialogs/SetFunctionVarTypes.cpp | 118 ++++++++++++++++++++ src/dialogs/SetFunctionVarTypes.h | 36 +++++++ src/dialogs/SetFunctionVarTypes.ui | 156 +++++++++++++++++++++++++++ src/menus/DisassemblyContextMenu.cpp | 40 +++++++ src/menus/DisassemblyContextMenu.h | 3 + 6 files changed, 359 insertions(+), 3 deletions(-) create mode 100644 src/dialogs/SetFunctionVarTypes.cpp create mode 100644 src/dialogs/SetFunctionVarTypes.h create mode 100644 src/dialogs/SetFunctionVarTypes.ui diff --git a/src/Cutter.pro b/src/Cutter.pro index 400e8eaa..75a9c80f 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -194,7 +194,8 @@ SOURCES += \ dialogs/BreakpointsDialog.cpp \ dialogs/AttachProcDialog.cpp \ widgets/RegisterRefsWidget.cpp \ - dialogs/SetToDataDialog.cpp + dialogs/SetToDataDialog.cpp \ + dialogs/SetFunctionVarTypes.cpp HEADERS += \ Cutter.h \ @@ -289,7 +290,8 @@ HEADERS += \ dialogs/AttachProcDialog.h \ widgets/RegisterRefsWidget.h \ dialogs/SetToDataDialog.h \ - utils/InitialOptions.h + utils/InitialOptions.h \ + dialogs/SetFunctionVarTypes.h FORMS += \ dialogs/AboutDialog.ui \ @@ -343,7 +345,8 @@ FORMS += \ dialogs/BreakpointsDialog.ui \ dialogs/AttachProcDialog.ui \ widgets/RegisterRefsWidget.ui \ - dialogs/SetToDataDialog.ui + dialogs/SetToDataDialog.ui \ + dialogs/SetFunctionVarTypes.ui RESOURCES += \ resources.qrc \ diff --git a/src/dialogs/SetFunctionVarTypes.cpp b/src/dialogs/SetFunctionVarTypes.cpp new file mode 100644 index 00000000..bf4cd7d0 --- /dev/null +++ b/src/dialogs/SetFunctionVarTypes.cpp @@ -0,0 +1,118 @@ +#include "SetFunctionVarTypes.h" +#include "ui_SetFunctionVarTypes.h" + +#include +#include + +SetFunctionVarTypes::SetFunctionVarTypes(QWidget *parent) : + QDialog(parent), + ui(new Ui::SetFunctionVarTypes) +{ + ui->setupUi(this); + connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(on_OkPressed())); + connect(ui->dropdownLocalVars, SIGNAL(currentIndexChanged(QString)), + SLOT(on_ComboBoxChanged(QString))); + + populateTypesComboBox(); + +} + +SetFunctionVarTypes::~SetFunctionVarTypes() +{ + delete ui; +} + +void SetFunctionVarTypes::setUserMessage(const QString userMessage) +{ + ui->userMessage->setText(userMessage); +} + +void SetFunctionVarTypes::setFcn(RAnalFunction *fcn) +{ + RListIter *iter; + RAnalVar *var; + + if (fcn == nullptr) { + ui->userMessage->setText(tr("You must be in a function to define variable types.")); + ui->labelSetTypeTo->setVisible(false); + ui->selectedTypeForVar->setVisible(false); + ui->dropdownLocalVars->setVisible(false); + + this->validFcn = false; + return; + } + ui->userMessage->setVisible(true); + ui->labelSetTypeTo->setVisible(true); + ui->selectedTypeForVar->setVisible(true); + ui->dropdownLocalVars->setVisible(true); + + this->validFcn = true; + this->fcn = fcn; + this->fcnVars = r_anal_var_all_list(Core()->core()->anal, this->fcn); + + for (iter = this->fcnVars->head; iter + && (var = static_cast(iter->data)); iter = iter->n) { + ui->dropdownLocalVars->addItem(var->name, + QVariant::fromValue(static_cast(var))); + } +} + +void SetFunctionVarTypes::on_OkPressed() +{ + + RAnalVar *selectedVar; + QVariant selectedVarVariant; + + if (!this->validFcn) { + return; + } + + selectedVarVariant = ui->dropdownLocalVars->currentData(); + selectedVar = static_cast(selectedVarVariant.value()); + + Core()->cmd(QString("afvt %1 %2") + .arg(selectedVar->name) + .arg(ui->selectedTypeForVar->currentText())); + + Core()->cmd(QString("afvn %1 %2") + .arg(ui->newVarName->text().replace(" ", "_")) + .arg(ui->dropdownLocalVars->currentText())); +} + +void SetFunctionVarTypes::on_ComboBoxChanged(QString varName) +{ + ui->newVarName->setText(varName); +} + + +void SetFunctionVarTypes::populateTypesComboBox() +{ + //gets all loaded types, structures and enums and puts them in a list + + QString res; + QStringList userStructures; + QStringList userEnumerations; + QList primitiveTypesTypeList; + + res = Core()->cmd(QString("ts")); + userStructures = res.split("\n"); + userStructures.removeAll(QString("")); + ui->selectedTypeForVar->addItems(userStructures); + ui->selectedTypeForVar->insertSeparator(ui->selectedTypeForVar->count()); + + primitiveTypesTypeList = Core()->getAllTypes(); + + for (TypeDescription thisType : primitiveTypesTypeList) { + ui->selectedTypeForVar->addItem(thisType.type); + } + + ui->selectedTypeForVar->insertSeparator(ui->selectedTypeForVar->count()); + + res = Core()->cmd(QString("te")); + userStructures = res.split("\n"); + userStructures.removeAll(QString("")); + ui->selectedTypeForVar->addItems(userStructures); + + return; + +} diff --git a/src/dialogs/SetFunctionVarTypes.h b/src/dialogs/SetFunctionVarTypes.h new file mode 100644 index 00000000..6f702a14 --- /dev/null +++ b/src/dialogs/SetFunctionVarTypes.h @@ -0,0 +1,36 @@ +#ifndef SETFUNCTIONVARTYPES_H +#define SETFUNCTIONVARTYPES_H + +#include "Cutter.h" +#include + +namespace Ui { +class SetFunctionVarTypes; +} + +class SetFunctionVarTypes : public QDialog +{ + Q_OBJECT + +public: + explicit SetFunctionVarTypes(QWidget *parent = nullptr); + ~SetFunctionVarTypes(); + + void setUserMessage(const QString userMessage); + void setFcn(RAnalFunction *fcn); + +public slots: + void on_OkPressed(); + void on_ComboBoxChanged(QString varName); + + +private: + RList *fcnVars; + RAnalFunction *fcn; + Ui::SetFunctionVarTypes *ui; + bool validFcn; + void populateTypesComboBox(); + +}; + +#endif // SETFUNCTIONVARTYPES_H diff --git a/src/dialogs/SetFunctionVarTypes.ui b/src/dialogs/SetFunctionVarTypes.ui new file mode 100644 index 00000000..07511ad1 --- /dev/null +++ b/src/dialogs/SetFunctionVarTypes.ui @@ -0,0 +1,156 @@ + + + SetFunctionVarTypes + + + + 0 + 0 + 636 + 327 + + + + Dialog + + + + + 10 + 290 + 621 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 20 + 10 + 601 + 17 + + + + + + + + + + 20 + 60 + 271 + 31 + + + + + + + 30 + 180 + 91 + 17 + + + + Set Type To: + + + + + + 30 + 210 + 261 + 31 + + + + true + + + 15 + + + + + + 30 + 110 + 241 + 17 + + + + Set Name To: + + + + + + 20 + 30 + 67 + 17 + + + + Modify: + + + + + + 30 + 140 + 261 + 31 + + + + + + + + buttonBox + accepted() + SetFunctionVarTypes + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SetFunctionVarTypes + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 8a72786d..bef6bc45 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -5,6 +5,7 @@ #include "dialogs/FlagDialog.h" #include "dialogs/RenameDialog.h" #include "dialogs/XrefsDialog.h" +#include "dialogs/SetFunctionVarTypes.h" #include "dialogs/SetToDataDialog.h" #include #include @@ -41,6 +42,10 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent) SLOT(on_actionRenameUsedHere_triggered()), getRenameUsedHereSequence()); addAction(&actionRenameUsedHere); + initAction(&actionSetFunctionVarTypes, tr("Re-type function local vars"), + SLOT(on_actionSetFunctionVarTypes_triggered()), getRetypeSequence()); + addAction(&actionSetFunctionVarTypes); + initAction(&actionDeleteComment, tr("Delete comment"), SLOT(on_actionDeleteComment_triggered())); addAction(&actionDeleteComment); @@ -246,6 +251,7 @@ void DisassemblyContextMenu::aboutToShowSlot() RCore *core = Core()->core(); RAnalFunction *fcn = r_anal_get_fcn_at (core->anal, offset, R_ANAL_FCN_TYPE_NULL); + RAnalFunction *in_fcn = Core()->functionAt(offset); RFlagItem *f = r_flag_get_i (core->flags, offset); actionDeleteFlag.setVisible(f ? true : false); @@ -262,6 +268,16 @@ void DisassemblyContextMenu::aboutToShowSlot() actionRename.setVisible(false); } + //only show retype for local vars if in a function + if(in_fcn) + { + actionSetFunctionVarTypes.setVisible(true); + } + else + { + actionSetFunctionVarTypes.setVisible(false); + } + // only show "rename X used here" if there is something to rename QJsonArray thingUsedHereArray = Core()->cmdj("anj @ " + QString::number(offset)).array(); @@ -331,6 +347,11 @@ QKeySequence DisassemblyContextMenu::getRenameUsedHereSequence() const return {Qt::SHIFT + Qt::Key_N}; } +QKeySequence DisassemblyContextMenu::getRetypeSequence() const +{ + return {Qt::Key_Y}; +} + QKeySequence DisassemblyContextMenu::getXRefSequence() const { return {Qt::Key_X}; @@ -587,6 +608,25 @@ void DisassemblyContextMenu::on_actionRenameUsedHere_triggered() } } +void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered() +{ + SetFunctionVarTypes *dialog; + + + RAnalFunction *fcn = Core()->functionAt(offset); + + dialog = new SetFunctionVarTypes(this); + + if(fcn) + { + dialog->setWindowTitle(tr("Set Variable Types for Function: %1").arg(fcn->name)); + } + dialog->setFcn(fcn); + + dialog->exec(); + +} + void DisassemblyContextMenu::on_actionXRefs_triggered() { XrefsDialog *dialog = new XrefsDialog(this); diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index 41b51d3a..f927b749 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -37,6 +37,7 @@ private slots: void on_actionAddFlag_triggered(); void on_actionRename_triggered(); void on_actionRenameUsedHere_triggered(); + void on_actionSetFunctionVarTypes_triggered(); void on_actionXRefs_triggered(); void on_actionDisplayOptions_triggered(); @@ -61,6 +62,7 @@ private: QKeySequence getAddFlagSequence() const; QKeySequence getRenameSequence() const; QKeySequence getRenameUsedHereSequence() const; + QKeySequence getRetypeSequence() const; QKeySequence getXRefSequence() const; QKeySequence getDisplayOptionsSequence() const; QList getAddBPSequence() const; @@ -86,6 +88,7 @@ private: QAction actionAnalyzeFunction; QAction actionRename; QAction actionRenameUsedHere; + QAction actionSetFunctionVarTypes; QAction actionXRefs; QAction actionDisplayOptions;