diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index f2edeee1..9cb81988 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -915,7 +915,7 @@ QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address) auto createAddNewWidgetAction = [this, menu, address](QString label, MemoryWidgetType type) { QAction *action = new QAction(label, menu); connect(action, &QAction::triggered, this, [this, address, type](){ - addNewMemoryWidget(type, address, true); + addNewMemoryWidget(type, address, false); }); menu->addAction(action); }; diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index bb20c09f..02a842be 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -18,7 +18,7 @@ #include #include -DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow* mainWindow) +DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *mainWindow) : QMenu(parent), offset(0), canCopy(false), @@ -27,7 +27,8 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow* main initAction(&actionCopy, tr("Copy"), SLOT(on_actionCopy_triggered()), getCopySequence()); addAction(&actionCopy); - initAction(&actionCopyAddr, tr("Copy address"), SLOT(on_actionCopyAddr_triggered()), getCopyAddressSequence()); + initAction(&actionCopyAddr, tr("Copy address"), SLOT(on_actionCopyAddr_triggered()), + getCopyAddressSequence()); addAction(&actionCopyAddr); initAction(&showInSubmenu, tr("Show in"), nullptr); @@ -112,9 +113,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow* main DisassemblyContextMenu::~DisassemblyContextMenu() { - for (QAction *action : anonymousActions) { - delete action; - } } void DisassemblyContextMenu::addSetBaseMenu() @@ -249,6 +247,65 @@ void DisassemblyContextMenu::addDebugMenu() debugMenu->addAction(&actionSetPC); } +QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) +{ + QVector result; + const QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array(); + result.reserve(array.size()); + for (const auto &thing : array) { + auto obj = thing.toObject(); + RVA offset = obj["offset"].toVariant().toULongLong(); + QString name = obj["name"].toString(); + QString typeString = obj["type"].toString(); + ThingUsedHere::Type type = ThingUsedHere::Type::Address; + if (typeString == "var") { + type = ThingUsedHere::Type::Var; + } else if (typeString == "flag") { + type = ThingUsedHere::Type::Flag; + } else if (typeString == "function") { + type = ThingUsedHere::Type::Function; + } else if (typeString == "address") { + type = ThingUsedHere::Type::Address; + } + result.push_back(ThingUsedHere{name, offset, type}); + } + return result; +} + +void DisassemblyContextMenu::updateTargetMenuActions(const QVector &targets) +{ + for (auto action : showTargetMenuActions) { + removeAction(action); + auto menu = action->menu(); + if (menu) { + menu->deleteLater(); + } + action->deleteLater(); + } + showTargetMenuActions.clear(); + for (auto &target : targets) { + QString name; + if (target.name.isEmpty()) { + name = tr("%1 (used here)").arg(RAddressString(target.offset)); + } else { + name = tr("%1 (%2)").arg(target.name, RAddressString(target.offset)); + } + auto action = new QAction(name, this); + showTargetMenuActions.append(action); + auto menu = mainWindow->createShowInMenu(this, target.offset); + action->setMenu(menu); + QAction *copyAddress = new QAction(tr("Copy address"), menu); + RVA offset = target.offset; + connect(copyAddress, &QAction::triggered, copyAddress, [offset]() { + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(RAddressString(offset)); + }); + menu->addSeparator(); + menu->addAction(copyAddress); + } + insertActions(copySeparator, showTargetMenuActions); +} + void DisassemblyContextMenu::setOffset(RVA offset) { this->offset = offset; @@ -362,24 +419,22 @@ void DisassemblyContextMenu::aboutToShowSlot() // Only show "rename X used here" if there is something to rename - QJsonArray thingUsedHereArray = Core()->cmdj("anj @ " + QString::number(offset)).array(); - if (!thingUsedHereArray.isEmpty()) { + auto thingsUsedHere = getThingUsedHere(offset); + if (!thingsUsedHere.isEmpty()) { actionRenameUsedHere.setVisible(true); - QJsonObject thingUsedHere = thingUsedHereArray.first().toObject(); - if (thingUsedHere["type"] == "address") { - RVA offset = thingUsedHere["offset"].toVariant().toULongLong(); + auto &thingUsedHere = thingsUsedHere.first(); + if (thingUsedHere.type == ThingUsedHere::Type::Address) { + RVA offset = thingUsedHere.offset; actionRenameUsedHere.setText(tr("Add flag at %1 (used here)").arg(RAddressString(offset))); - } else { - if (thingUsedHere["type"] == "function") { - actionRenameUsedHere.setText(tr("Rename \"%1\"").arg(thingUsedHere["name"].toString())); - } - else { - actionRenameUsedHere.setText(tr("Rename \"%1\" (used here)").arg(thingUsedHere["name"].toString())); - } + } else if (thingUsedHere.type == ThingUsedHere::Type::Function) { + actionRenameUsedHere.setText(tr("Rename \"%1\"").arg(thingUsedHere.name)); + } else { + actionRenameUsedHere.setText(tr("Rename \"%1\" (used here)").arg(thingUsedHere.name)); } } else { actionRenameUsedHere.setVisible(false); } + updateTargetMenuActions(thingsUsedHere); // Decide to show Reverse jmp option showReverseJmpQuery(); @@ -686,38 +741,39 @@ void DisassemblyContextMenu::on_actionRename_triggered() void DisassemblyContextMenu::on_actionRenameUsedHere_triggered() { - QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array(); + auto array = getThingUsedHere(offset); if (array.isEmpty()) { return; } - QJsonObject thingUsedHere = array.first().toObject(); - QString type = thingUsedHere.value("type").toString(); + auto thingUsedHere = array.first(); RenameDialog dialog(this); QString oldName; + auto type = thingUsedHere.type; - if (type == "address") { - RVA offset = thingUsedHere["offset"].toVariant().toULongLong(); + if (type == ThingUsedHere::Type::Address) { + RVA offset = thingUsedHere.offset; dialog.setWindowTitle(tr("Add flag at %1").arg(RAddressString(offset))); dialog.setName("label." + QString::number(offset, 16)); } else { - oldName = thingUsedHere.value("name").toString(); + oldName = thingUsedHere.name; dialog.setWindowTitle(tr("Rename %1").arg(oldName)); dialog.setName(oldName); } + if (dialog.exec()) { QString newName = dialog.getName().trimmed(); if (!newName.isEmpty()) { Core()->cmd("an " + newName + " @ " + QString::number(offset)); - if (type == "address" || type == "flag") { + if (type == ThingUsedHere::Type::Address || type == ThingUsedHere::Type::Address) { Core()->triggerFlagsChanged(); - } else if (type == "var") { + } else if (type == ThingUsedHere::Type::Var) { Core()->triggerVarsChanged(); - } else if (type == "function") { + } else if (type == ThingUsedHere::Type::Function) { Core()->triggerFunctionRenamed(oldName, newName); } } @@ -729,7 +785,8 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered() RAnalFunction *fcn = Core()->functionAt(offset); if (!fcn) { - QMessageBox::critical(this, tr("Re-type function local vars"), tr("You must be in a function to define variable types.")); + QMessageBox::critical(this, tr("Re-type function local vars"), + tr("You must be in a function to define variable types.")); return; } @@ -873,7 +930,7 @@ void DisassemblyContextMenu::setToData(int size, int repeat) QAction *DisassemblyContextMenu::addAnonymousAction(QString name, const char *slot, QKeySequence keySequence) { - auto action = new QAction(); + auto action = new QAction(this); addAction(action); anonymousActions.append(action); initAction(action, name, slot, keySequence); diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index 3225ab7c..9a061824 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -10,7 +10,7 @@ class DisassemblyContextMenu : public QMenu Q_OBJECT public: - DisassemblyContextMenu(QWidget *parent, MainWindow* mainWindow); + DisassemblyContextMenu(QWidget *parent, MainWindow *mainWindow); ~DisassemblyContextMenu(); signals: @@ -101,7 +101,7 @@ private: RVA offset; bool canCopy; QString curHighlightedWord; // The current highlighted word - MainWindow* mainWindow; + MainWindow *mainWindow; QList anonymousActions; @@ -166,6 +166,7 @@ private: QAction actionSetToDataQword; QAction showInSubmenu; + QList showTargetMenuActions; // For creating anonymous entries (that are always visible) QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut); @@ -184,5 +185,20 @@ private: void addSetToDataMenu(); void addEditMenu(); void addDebugMenu(); + + struct ThingUsedHere { + QString name; + RVA offset; + enum class Type { + Var, + Function, + Flag, + Address + }; + Type type; + }; + QVector getThingUsedHere(RVA offset); + + void updateTargetMenuActions(const QVector &targets); }; #endif // DISASSEMBLYCONTEXTMENU_H