mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-07 15:32:13 +00:00
Add context menu entries for target address (#1712)
* Refactor "used here" logic. * Add menu for showing instruction target.
This commit is contained in:
parent
468100c52d
commit
f50fecc57b
@ -915,7 +915,7 @@ QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address)
|
|||||||
auto createAddNewWidgetAction = [this, menu, address](QString label, MemoryWidgetType type) {
|
auto createAddNewWidgetAction = [this, menu, address](QString label, MemoryWidgetType type) {
|
||||||
QAction *action = new QAction(label, menu);
|
QAction *action = new QAction(label, menu);
|
||||||
connect(action, &QAction::triggered, this, [this, address, type](){
|
connect(action, &QAction::triggered, this, [this, address, type](){
|
||||||
addNewMemoryWidget(type, address, true);
|
addNewMemoryWidget(type, address, false);
|
||||||
});
|
});
|
||||||
menu->addAction(action);
|
menu->addAction(action);
|
||||||
};
|
};
|
||||||
|
@ -27,7 +27,8 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow* main
|
|||||||
initAction(&actionCopy, tr("Copy"), SLOT(on_actionCopy_triggered()), getCopySequence());
|
initAction(&actionCopy, tr("Copy"), SLOT(on_actionCopy_triggered()), getCopySequence());
|
||||||
addAction(&actionCopy);
|
addAction(&actionCopy);
|
||||||
|
|
||||||
initAction(&actionCopyAddr, tr("Copy address"), SLOT(on_actionCopyAddr_triggered()), getCopyAddressSequence());
|
initAction(&actionCopyAddr, tr("Copy address"), SLOT(on_actionCopyAddr_triggered()),
|
||||||
|
getCopyAddressSequence());
|
||||||
addAction(&actionCopyAddr);
|
addAction(&actionCopyAddr);
|
||||||
|
|
||||||
initAction(&showInSubmenu, tr("Show in"), nullptr);
|
initAction(&showInSubmenu, tr("Show in"), nullptr);
|
||||||
@ -112,9 +113,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow* main
|
|||||||
|
|
||||||
DisassemblyContextMenu::~DisassemblyContextMenu()
|
DisassemblyContextMenu::~DisassemblyContextMenu()
|
||||||
{
|
{
|
||||||
for (QAction *action : anonymousActions) {
|
|
||||||
delete action;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::addSetBaseMenu()
|
void DisassemblyContextMenu::addSetBaseMenu()
|
||||||
@ -249,6 +247,65 @@ void DisassemblyContextMenu::addDebugMenu()
|
|||||||
debugMenu->addAction(&actionSetPC);
|
debugMenu->addAction(&actionSetPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<DisassemblyContextMenu::ThingUsedHere> DisassemblyContextMenu::getThingUsedHere(RVA offset)
|
||||||
|
{
|
||||||
|
QVector<ThingUsedHere> 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<ThingUsedHere> &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)
|
void DisassemblyContextMenu::setOffset(RVA offset)
|
||||||
{
|
{
|
||||||
this->offset = offset;
|
this->offset = offset;
|
||||||
@ -362,24 +419,22 @@ void DisassemblyContextMenu::aboutToShowSlot()
|
|||||||
|
|
||||||
|
|
||||||
// Only show "rename X used here" if there is something to rename
|
// Only show "rename X used here" if there is something to rename
|
||||||
QJsonArray thingUsedHereArray = Core()->cmdj("anj @ " + QString::number(offset)).array();
|
auto thingsUsedHere = getThingUsedHere(offset);
|
||||||
if (!thingUsedHereArray.isEmpty()) {
|
if (!thingsUsedHere.isEmpty()) {
|
||||||
actionRenameUsedHere.setVisible(true);
|
actionRenameUsedHere.setVisible(true);
|
||||||
QJsonObject thingUsedHere = thingUsedHereArray.first().toObject();
|
auto &thingUsedHere = thingsUsedHere.first();
|
||||||
if (thingUsedHere["type"] == "address") {
|
if (thingUsedHere.type == ThingUsedHere::Type::Address) {
|
||||||
RVA offset = thingUsedHere["offset"].toVariant().toULongLong();
|
RVA offset = thingUsedHere.offset;
|
||||||
actionRenameUsedHere.setText(tr("Add flag at %1 (used here)").arg(RAddressString(offset)));
|
actionRenameUsedHere.setText(tr("Add flag at %1 (used here)").arg(RAddressString(offset)));
|
||||||
|
} else if (thingUsedHere.type == ThingUsedHere::Type::Function) {
|
||||||
|
actionRenameUsedHere.setText(tr("Rename \"%1\"").arg(thingUsedHere.name));
|
||||||
} else {
|
} else {
|
||||||
if (thingUsedHere["type"] == "function") {
|
actionRenameUsedHere.setText(tr("Rename \"%1\" (used here)").arg(thingUsedHere.name));
|
||||||
actionRenameUsedHere.setText(tr("Rename \"%1\"").arg(thingUsedHere["name"].toString()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
actionRenameUsedHere.setText(tr("Rename \"%1\" (used here)").arg(thingUsedHere["name"].toString()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actionRenameUsedHere.setVisible(false);
|
actionRenameUsedHere.setVisible(false);
|
||||||
}
|
}
|
||||||
|
updateTargetMenuActions(thingsUsedHere);
|
||||||
|
|
||||||
// Decide to show Reverse jmp option
|
// Decide to show Reverse jmp option
|
||||||
showReverseJmpQuery();
|
showReverseJmpQuery();
|
||||||
@ -686,38 +741,39 @@ void DisassemblyContextMenu::on_actionRename_triggered()
|
|||||||
|
|
||||||
void DisassemblyContextMenu::on_actionRenameUsedHere_triggered()
|
void DisassemblyContextMenu::on_actionRenameUsedHere_triggered()
|
||||||
{
|
{
|
||||||
QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array();
|
auto array = getThingUsedHere(offset);
|
||||||
if (array.isEmpty()) {
|
if (array.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject thingUsedHere = array.first().toObject();
|
auto thingUsedHere = array.first();
|
||||||
QString type = thingUsedHere.value("type").toString();
|
|
||||||
|
|
||||||
RenameDialog dialog(this);
|
RenameDialog dialog(this);
|
||||||
|
|
||||||
QString oldName;
|
QString oldName;
|
||||||
|
auto type = thingUsedHere.type;
|
||||||
|
|
||||||
if (type == "address") {
|
if (type == ThingUsedHere::Type::Address) {
|
||||||
RVA offset = thingUsedHere["offset"].toVariant().toULongLong();
|
RVA offset = thingUsedHere.offset;
|
||||||
dialog.setWindowTitle(tr("Add flag at %1").arg(RAddressString(offset)));
|
dialog.setWindowTitle(tr("Add flag at %1").arg(RAddressString(offset)));
|
||||||
dialog.setName("label." + QString::number(offset, 16));
|
dialog.setName("label." + QString::number(offset, 16));
|
||||||
} else {
|
} else {
|
||||||
oldName = thingUsedHere.value("name").toString();
|
oldName = thingUsedHere.name;
|
||||||
dialog.setWindowTitle(tr("Rename %1").arg(oldName));
|
dialog.setWindowTitle(tr("Rename %1").arg(oldName));
|
||||||
dialog.setName(oldName);
|
dialog.setName(oldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (dialog.exec()) {
|
if (dialog.exec()) {
|
||||||
QString newName = dialog.getName().trimmed();
|
QString newName = dialog.getName().trimmed();
|
||||||
if (!newName.isEmpty()) {
|
if (!newName.isEmpty()) {
|
||||||
Core()->cmd("an " + newName + " @ " + QString::number(offset));
|
Core()->cmd("an " + newName + " @ " + QString::number(offset));
|
||||||
|
|
||||||
if (type == "address" || type == "flag") {
|
if (type == ThingUsedHere::Type::Address || type == ThingUsedHere::Type::Address) {
|
||||||
Core()->triggerFlagsChanged();
|
Core()->triggerFlagsChanged();
|
||||||
} else if (type == "var") {
|
} else if (type == ThingUsedHere::Type::Var) {
|
||||||
Core()->triggerVarsChanged();
|
Core()->triggerVarsChanged();
|
||||||
} else if (type == "function") {
|
} else if (type == ThingUsedHere::Type::Function) {
|
||||||
Core()->triggerFunctionRenamed(oldName, newName);
|
Core()->triggerFunctionRenamed(oldName, newName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -729,7 +785,8 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
|
|||||||
RAnalFunction *fcn = Core()->functionAt(offset);
|
RAnalFunction *fcn = Core()->functionAt(offset);
|
||||||
|
|
||||||
if (!fcn) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,7 +930,7 @@ void DisassemblyContextMenu::setToData(int size, int repeat)
|
|||||||
QAction *DisassemblyContextMenu::addAnonymousAction(QString name, const char *slot,
|
QAction *DisassemblyContextMenu::addAnonymousAction(QString name, const char *slot,
|
||||||
QKeySequence keySequence)
|
QKeySequence keySequence)
|
||||||
{
|
{
|
||||||
auto action = new QAction();
|
auto action = new QAction(this);
|
||||||
addAction(action);
|
addAction(action);
|
||||||
anonymousActions.append(action);
|
anonymousActions.append(action);
|
||||||
initAction(action, name, slot, keySequence);
|
initAction(action, name, slot, keySequence);
|
||||||
|
@ -166,6 +166,7 @@ private:
|
|||||||
QAction actionSetToDataQword;
|
QAction actionSetToDataQword;
|
||||||
|
|
||||||
QAction showInSubmenu;
|
QAction showInSubmenu;
|
||||||
|
QList<QAction*> showTargetMenuActions;
|
||||||
|
|
||||||
// For creating anonymous entries (that are always visible)
|
// For creating anonymous entries (that are always visible)
|
||||||
QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut);
|
QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut);
|
||||||
@ -184,5 +185,20 @@ private:
|
|||||||
void addSetToDataMenu();
|
void addSetToDataMenu();
|
||||||
void addEditMenu();
|
void addEditMenu();
|
||||||
void addDebugMenu();
|
void addDebugMenu();
|
||||||
|
|
||||||
|
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);
|
||||||
};
|
};
|
||||||
#endif // DISASSEMBLYCONTEXTMENU_H
|
#endif // DISASSEMBLYCONTEXTMENU_H
|
||||||
|
Loading…
Reference in New Issue
Block a user