cutter/src/menus/DisassemblyContextMenu.cpp

406 lines
13 KiB
C++
Raw Normal View History

#include "DisassemblyContextMenu.h"
#include "dialogs/AsmOptionsDialog.h"
#include "dialogs/CommentsDialog.h"
#include "dialogs/FlagDialog.h"
#include "dialogs/RenameDialog.h"
#include "dialogs/XrefsDialog.h"
#include <QtCore>
#include <QShortcut>
2017-11-19 17:49:29 +00:00
DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent)
: QMenu(parent),
offset(0),
2017-12-02 15:43:21 +00:00
canCopy(false),
actionCopy(this),
2017-11-19 17:49:29 +00:00
actionAddComment(this),
actionAddFlag(this),
actionRename(this),
2017-11-30 14:16:39 +00:00
actionRenameUsedHere(this),
2017-11-19 17:49:29 +00:00
actionXRefs(this),
actionDisplayOptions(this),
actionSetBaseBinary(this),
actionSetBaseOctal(this),
actionSetBaseDecimal(this),
actionSetBaseHexadecimal(this),
actionSetBasePort(this),
actionSetBaseIPAddr(this),
actionSetBaseSyscall(this),
actionSetBaseString(this)
{
2017-12-02 15:43:21 +00:00
actionCopy.setText(tr("Copy"));
this->addAction(&actionCopy);
actionCopy.setShortcut(getCopySequence());
copySeparator = addSeparator();
actionAddComment.setText(tr("Add Comment"));
this->addAction(&actionAddComment);
actionAddComment.setShortcut(getCommentSequence());
actionAddFlag.setText(tr("Add Flag"));
this->addAction(&actionAddFlag);
2017-11-30 14:16:39 +00:00
actionAddFlag.setShortcut(getAddFlagSequence());
actionRename.setText(tr("Rename"));
this->addAction(&actionRename);
2017-11-30 14:16:39 +00:00
actionRename.setShortcut(getRenameSequence());
actionRenameUsedHere.setText(("Rename Flag/Fcn/Var Used Here"));
this->addAction(&actionRenameUsedHere);
actionRenameUsedHere.setShortcut(getRenameUsedHereSequence());
2017-11-28 13:50:41 +00:00
setBaseMenu = new QMenu(tr("Set Immediate Base to..."), this);
setBaseMenuAction = addMenu(setBaseMenu);
actionSetBaseBinary.setText(tr("Binary"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBaseBinary);
actionSetBaseOctal.setText(tr("Octal"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBaseOctal);
actionSetBaseDecimal.setText(tr("Decimal"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBaseDecimal);
actionSetBaseHexadecimal.setText(tr("Hexadecimal"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBaseHexadecimal);
actionSetBasePort.setText(tr("Network Port"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBasePort);
actionSetBaseIPAddr.setText(tr("IP Address"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBaseIPAddr);
actionSetBaseSyscall.setText(tr("Syscall"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBaseSyscall);
actionSetBaseString.setText(tr("String"));
2017-11-28 13:50:41 +00:00
setBaseMenu->addAction(&actionSetBaseString);
this->addSeparator();
actionXRefs.setText(tr("Show X-Refs"));
this->addAction(&actionXRefs);
2017-11-30 14:16:39 +00:00
actionXRefs.setShortcut(getXRefSequence());
this->addSeparator();
actionDisplayOptions.setText(tr("Show Options"));
2017-11-30 14:16:39 +00:00
actionDisplayOptions.setShortcut(getDisplayOptionsSequence());
this->addAction(&actionDisplayOptions);
auto pWidget = parentWidget();
2017-11-30 14:16:39 +00:00
#define ADD_SHORTCUT(sequence, slot) { \
QShortcut *shortcut = new QShortcut((sequence), pWidget); \
shortcut->setContext(Qt::WidgetWithChildrenShortcut); \
connect(shortcut, &QShortcut::activated, this, (slot)); \
}
ADD_SHORTCUT(getCopySequence(), &DisassemblyContextMenu::on_actionCopy_triggered);
ADD_SHORTCUT(getDisplayOptionsSequence(), &DisassemblyContextMenu::on_actionDisplayOptions_triggered);
ADD_SHORTCUT(getXRefSequence(), &DisassemblyContextMenu::on_actionXRefs_triggered);
ADD_SHORTCUT(getCommentSequence(), &DisassemblyContextMenu::on_actionAddComment_triggered);
ADD_SHORTCUT(getAddFlagSequence(), &DisassemblyContextMenu::on_actionAddFlag_triggered);
ADD_SHORTCUT(getRenameSequence(), &DisassemblyContextMenu::on_actionRename_triggered);
ADD_SHORTCUT(getRenameUsedHereSequence(), &DisassemblyContextMenu::on_actionRenameUsedHere_triggered);
#undef ADD_SHORTCUT
2017-12-02 15:43:21 +00:00
connect(&actionCopy, SIGNAL(triggered(bool)), this, SLOT(on_actionCopy_triggered()));
connect(&actionAddComment, SIGNAL(triggered(bool)), this, SLOT(on_actionAddComment_triggered()));
connect(&actionAddFlag, SIGNAL(triggered(bool)), this, SLOT(on_actionAddFlag_triggered()));
connect(&actionRename, SIGNAL(triggered(bool)), this, SLOT(on_actionRename_triggered()));
2017-11-30 14:16:39 +00:00
connect(&actionRenameUsedHere, SIGNAL(triggered(bool)), this, SLOT(on_actionRenameUsedHere_triggered()));
connect(&actionXRefs, SIGNAL(triggered(bool)), this, SLOT(on_actionXRefs_triggered()));
connect(&actionDisplayOptions, SIGNAL(triggered()), this, SLOT(on_actionDisplayOptions_triggered()));
connect(&actionSetBaseBinary, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseBinary_triggered()));
connect(&actionSetBaseOctal, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseOctal_triggered()));
connect(&actionSetBaseDecimal, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseDecimal_triggered()));
connect(&actionSetBaseHexadecimal, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseHexadecimal_triggered()));
connect(&actionSetBasePort, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBasePort_triggered()));
connect(&actionSetBaseIPAddr, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseIPAddr_triggered()));
connect(&actionSetBaseSyscall, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseSyscall_triggered()));
connect(&actionSetBaseString, SIGNAL(triggered(bool)), this, SLOT(on_actionSetBaseString_triggered()));
2017-11-28 13:50:41 +00:00
connect(this, SIGNAL(aboutToShow()), this, SLOT(aboutToShowSlot()));
}
void DisassemblyContextMenu::setOffset(RVA offset)
{
this->offset = offset;
}
2017-12-02 15:43:21 +00:00
void DisassemblyContextMenu::setCanCopy(bool enabled)
{
this->canCopy = enabled;
}
2017-11-28 13:50:41 +00:00
void DisassemblyContextMenu::aboutToShowSlot()
{
// check if set immediate base menu makes sense
QJsonObject instObject = Core()->cmdj("aoj @ " + QString::number(offset)).array().first().toObject();
auto keys = instObject.keys();
bool immBase = keys.contains("val") || keys.contains("ptr");
setBaseMenuAction->setVisible(immBase);
QString comment = Core()->cmd("CC." + RAddressString(offset));
if (comment.isNull() || comment.isEmpty())
{
actionAddComment.setText(tr("Add Comment"));
}
else
{
actionAddComment.setText(tr("Edit Comment"));
}
2017-12-02 15:43:21 +00:00
actionCopy.setVisible(canCopy);
copySeparator->setVisible(canCopy);
RCore *core = Core()->core();
RAnalFunction *fcn = r_anal_get_fcn_at (core->anal, offset, R_ANAL_FCN_TYPE_NULL);
RFlagItem *f = r_flag_get_i (core->flags, offset);
if (fcn)
{
actionRename.setVisible(true);
actionRename.setText(tr("Rename function \"%1\"").arg(fcn->name));
}
else if (f)
{
actionRename.setVisible(true);
actionRename.setText(tr("Rename flag \"%1\"").arg(f->name));
}
else
{
actionRename.setVisible(false);
}
2017-11-30 14:16:39 +00:00
// only show "rename X used here" if there is something to rename
2017-11-30 21:18:09 +00:00
QJsonArray thingUsedHereArray = Core()->cmdj("anj @ " + QString::number(offset)).array();
if (!thingUsedHereArray.isEmpty())
2017-11-30 14:16:39 +00:00
{
actionRenameUsedHere.setVisible(true);
2017-11-30 21:18:09 +00:00
QJsonObject thingUsedHere = thingUsedHereArray.first().toObject();
if (thingUsedHere["type"] == "address")
{
RVA offset = thingUsedHere["offset"].toVariant().toULongLong();
actionRenameUsedHere.setText(tr("Add flag at %1 (used here)").arg(RAddressString(offset)));
}
else
{
actionRenameUsedHere.setText(tr("Rename \"%1\" (used here)").arg(thingUsedHere["name"].toString()));
}
2017-11-30 14:16:39 +00:00
}
else
{
actionRenameUsedHere.setVisible(false);
}
2017-12-02 15:43:21 +00:00
}
QKeySequence DisassemblyContextMenu::getCopySequence() const
{
return QKeySequence::Copy;
2017-11-28 13:50:41 +00:00
}
QKeySequence DisassemblyContextMenu::getCommentSequence() const
{
return {";"};
}
QKeySequence DisassemblyContextMenu::getAddFlagSequence() const
{
return {}; //TODO insert correct sequence
}
QKeySequence DisassemblyContextMenu::getRenameSequence() const
{
return {Qt::Key_N};
}
2017-11-30 14:16:39 +00:00
QKeySequence DisassemblyContextMenu::getRenameUsedHereSequence() const
{
return {Qt::SHIFT + Qt::Key_N};
}
2017-11-28 13:50:41 +00:00
QKeySequence DisassemblyContextMenu::getXRefSequence() const
{
return {Qt::Key_X};
}
QKeySequence DisassemblyContextMenu::getDisplayOptionsSequence() const
{
return {}; //TODO insert correct sequence
}
2017-12-02 15:43:21 +00:00
void DisassemblyContextMenu::on_actionCopy_triggered()
{
emit copy();
}
void DisassemblyContextMenu::on_actionAddComment_triggered()
{
QString oldComment = Core()->cmd("CC." + RAddressString(offset));
// Remove newline at the end added by cmd
oldComment.remove(oldComment.length()-1, 1);
CommentsDialog *c = new CommentsDialog(this);
if (oldComment.isNull() || oldComment.isEmpty())
{
c->setWindowTitle(tr("Add Comment at %1").arg(RAddressString(offset)));
}
else
{
c->setWindowTitle(tr("Edit Comment at %1").arg(RAddressString(offset)));
}
c->setComment(oldComment);
if (c->exec())
{
QString comment = c->getComment();
if (comment.isEmpty())
{
Core()->delComment(offset);
}
else
{
Core()->setComment(offset, comment);
}
}
}
void DisassemblyContextMenu::on_actionAddFlag_triggered()
{
FlagDialog *dialog = new FlagDialog(offset, this->parentWidget());
dialog->exec();
}
void DisassemblyContextMenu::on_actionRename_triggered()
{
2017-11-26 16:53:05 +00:00
RCore *core = Core()->core();
RenameDialog *dialog = new RenameDialog(this);
2017-11-26 16:53:05 +00:00
RAnalFunction *fcn = r_anal_get_fcn_at (core->anal, offset, R_ANAL_FCN_TYPE_NULL);
RFlagItem *f = r_flag_get_i (core->flags, offset);
if (fcn)
{
/* Rename function */
dialog->setWindowTitle(tr("Rename function %1").arg(fcn->name));
dialog->setName(fcn->name);
if (dialog->exec())
{
QString new_name = dialog->getName();
Core()->renameFunction(fcn->name, new_name);
2017-11-26 16:53:05 +00:00
}
}
else if (f)
{
/* Rename current flag */
dialog->setWindowTitle(tr("Rename flag %1").arg(f->name));
dialog->setName(f->name);
if (dialog->exec())
{
QString new_name = dialog->getName();
Core()->renameFlag(f->name, new_name);
2017-11-26 16:53:05 +00:00
}
}
else
{
return;
}
}
2017-11-30 14:16:39 +00:00
void DisassemblyContextMenu::on_actionRenameUsedHere_triggered()
{
2017-11-30 21:18:09 +00:00
QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array();
if (array.isEmpty())
2017-11-30 14:16:39 +00:00
{
return;
}
2017-11-30 21:18:09 +00:00
QJsonObject thingUsedHere = array.first().toObject();
QString type = thingUsedHere.value("type").toString();
2017-11-30 14:16:39 +00:00
RenameDialog *dialog = new RenameDialog(this);
2017-11-30 21:18:09 +00:00
QString oldName;
2017-11-30 21:18:09 +00:00
if (type == "address")
{
RVA offset = thingUsedHere["offset"].toVariant().toULongLong();
dialog->setWindowTitle(tr("Add flag at %1").arg(RAddressString(offset)));
dialog->setName("label." + QString::number(offset, 16));
}
else
{
oldName = thingUsedHere.value("name").toString();
2017-11-30 21:18:09 +00:00
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")
{
Core()->triggerFlagsChanged();
}
else if (type == "var")
{
Core()->triggerVarsChanged();
}
else if (type == "function")
{
Core()->triggerFunctionRenamed(oldName, newName);
}
2017-11-30 21:18:09 +00:00
}
2017-11-30 14:16:39 +00:00
}
}
void DisassemblyContextMenu::on_actionXRefs_triggered()
{
XrefsDialog *dialog = new XrefsDialog(this);
dialog->fillRefsForAddress(offset, RAddressString(offset), false);
dialog->exec();
}
void DisassemblyContextMenu::on_actionDisplayOptions_triggered()
{
AsmOptionsDialog *dialog = new AsmOptionsDialog(this->parentWidget());
dialog->show();
}
void DisassemblyContextMenu::on_actionSetBaseBinary_triggered()
{
Core()->setImmediateBase("b", offset);
}
void DisassemblyContextMenu::on_actionSetBaseOctal_triggered()
{
Core()->setImmediateBase("o", offset);
}
void DisassemblyContextMenu::on_actionSetBaseDecimal_triggered()
{
Core()->setImmediateBase("d", offset);
}
void DisassemblyContextMenu::on_actionSetBaseHexadecimal_triggered()
{
Core()->setImmediateBase("h", offset);
}
void DisassemblyContextMenu::on_actionSetBasePort_triggered()
{
Core()->setImmediateBase("p", offset);
}
void DisassemblyContextMenu::on_actionSetBaseIPAddr_triggered()
{
Core()->setImmediateBase("i", offset);
}
void DisassemblyContextMenu::on_actionSetBaseSyscall_triggered()
{
Core()->setImmediateBase("S", offset);
}
void DisassemblyContextMenu::on_actionSetBaseString_triggered()
{
Core()->setImmediateBase("s", offset);
}