Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a hotkey for toggling immediate base (#2420) #2429

Draft
wants to merge 8 commits into
base: dev
Choose a base branch
from
2 changes: 2 additions & 0 deletions docs/source/user-docs/shortcuts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ Disassembly View Shortcuts
+-------------+----------------------------------+
| Ctrl/Cmd+= | Reset zoom |
+-------------+----------------------------------+
| H | Toggle immediate base |
+-------------+----------------------------------+

Graph View Shortcuts
--------------------
Expand Down
24 changes: 20 additions & 4 deletions src/core/Cutter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,14 +699,19 @@ void CutterCore::delFlag(const QString &name)
emit flagsChanged();
}

QJsonObject CutterCore::getInstructionObject(RVA addr)
{
return Core()->cmdj("aoj @ " + QString::number(addr)).array().first().toObject();
}

QString CutterCore::getInstructionBytes(RVA addr)
{
return cmdj("aoj @ " + RAddressString(addr)).array().first().toObject()[RJsonKey::bytes].toString();
return getInstructionObject(addr)[RJsonKey::bytes].toString();
}

QString CutterCore::getInstructionOpcode(RVA addr)
{
return cmdj("aoj @ " + RAddressString(addr)).array().first().toObject()[RJsonKey::opcode].toString();
return getInstructionObject(addr)[RJsonKey::opcode].toString();
}

void CutterCore::editInstruction(RVA addr, const QString &inst)
Expand Down Expand Up @@ -842,6 +847,18 @@ void CutterCore::setImmediateBase(const QString &r2BaseName, RVA offset)
emit instructionChanged(offset);
}

int CutterCore::getImmediateBase(RVA offset)
{
QJsonArray result = this->cmdj(QString("ahj %1").arg(offset)).array();
for (const auto& n: result) {
QJsonValue immbase = n.toObject()["immbase"];
if (immbase.isDouble()) {
return immbase.toInt();
}
}
return 0;
}

void CutterCore::setCurrentBits(int bits, RVA offset)
{
if (offset == RVA_INVALID) {
Expand Down Expand Up @@ -1229,8 +1246,7 @@ QJsonDocument CutterCore::getRegistersInfo()
RVA CutterCore::getOffsetJump(RVA addr)
{
bool ok;
RVA value = cmdj("aoj @" + QString::number(
addr)).array().first().toObject().value(RJsonKey::jump).toVariant().toULongLong(&ok);
RVA value = getInstructionObject(addr).value(RJsonKey::jump).toVariant().toULongLong(&ok);

if (!ok) {
return RVA_INVALID;
Expand Down
9 changes: 9 additions & 0 deletions src/core/Cutter.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,17 @@ class CUTTER_EXPORT CutterCore: public QObject
QString nearestFlag(RVA offset, RVA *flagOffsetOut);
void triggerFlagsChanged();

/**
* @brief Returns json data of an instruction
* @param addr Address of the instruction
* @returns Instruction data
*/
QJsonObject getInstructionObject(RVA addr);

/* Edition functions */
QString getInstructionBytes(RVA addr);
QString getInstructionOpcode(RVA addr);

void editInstruction(RVA addr, const QString &inst);
void nopInstruction(RVA addr);
void jmpReverse(RVA addr);
Expand Down Expand Up @@ -232,6 +240,7 @@ class CUTTER_EXPORT CutterCore: public QObject
void delComment(RVA addr);
QString getCommentAt(RVA addr);
void setImmediateBase(const QString &r2BaseName, RVA offset = RVA_INVALID);
int getImmediateBase(RVA offset = RVA_INVALID);
void setCurrentBits(int bits, RVA offset = RVA_INVALID);

/**
Expand Down
36 changes: 30 additions & 6 deletions src/menus/DisassemblyContextMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main

addSetBaseMenu();

initAction(&actionToggleBase, tr("Toggle Immediate Base (Hex/Dec)"),
SLOT(on_actionToggleBase_triggered()), getToggleBaseSequence());
addAction(&actionToggleBase);

addSetBitsMenu();

structureOffsetMenu = addMenu(tr("Structure offset"));
Expand Down Expand Up @@ -400,6 +404,7 @@ void DisassemblyContextMenu::setOffset(RVA offset)
this->offset = offset;

this->actionSetFunctionVarTypes.setVisible(true);
actionToggleBase.setVisible(checkImmediateBaseMenu(Core()->getInstructionObject(offset)));
}

void DisassemblyContextMenu::setCanCopy(bool enabled)
Expand All @@ -412,14 +417,17 @@ void DisassemblyContextMenu::setCurHighlightedWord(const QString &text)
this->curHighlightedWord = text;
}

// Check if it makes sense to show the immediate base menu
bool DisassemblyContextMenu::checkImmediateBaseMenu(const QJsonObject& instObject) {
auto keys = instObject.keys();
return keys.contains("val") || keys.contains("ptr");
}

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");
setBaseMenu->menuAction()->setVisible(immBase);
QJsonObject instObject = Core()->getInstructionObject(offset);

setBaseMenu->menuAction()->setVisible(checkImmediateBaseMenu(instObject));
setBitsMenu->menuAction()->setVisible(true);

// Create structure offset menu if it makes sense
Expand Down Expand Up @@ -674,6 +682,11 @@ QKeySequence DisassemblyContextMenu::getUndefineFunctionSequence() const
return {Qt::Key_U};
}

QKeySequence DisassemblyContextMenu::getToggleBaseSequence() const
{
return {Qt::Key_H};
}


void DisassemblyContextMenu::on_actionEditInstruction_triggered()
{
Expand Down Expand Up @@ -803,6 +816,17 @@ void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered()
}
}

// TODO: requires the user to trigger the action twice if the number is in decimals
void DisassemblyContextMenu::on_actionToggleBase_triggered()
{
int base = Core()->getImmediateBase(offset);
if (base == 10) {
setBase("h");
} else {
setBase("d");
}
}

void DisassemblyContextMenu::on_actionAddFlag_triggered()
{
FlagDialog dialog(offset, this->parentWidget());
Expand Down
12 changes: 12 additions & 0 deletions src/menus/DisassemblyContextMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ private slots:
void on_actionSetToData_triggered();
void on_actionSetToDataEx_triggered();

void on_actionToggleBase_triggered();

/**
* @brief Executed on selecting an offset from the structureOffsetMenu
* Uses the applyStructureOffset() function of CutterCore to apply the
Expand Down Expand Up @@ -101,6 +103,7 @@ private slots:
QKeySequence getDefineNewFunctionSequence() const;
QKeySequence getUndefineFunctionSequence() const;
QKeySequence getEditFunctionSequence() const;
QKeySequence getToggleBaseSequence() const;
QList<QKeySequence> getAddBPSequence() const;

/**
Expand Down Expand Up @@ -156,6 +159,7 @@ private slots:
QAction actionSetBaseIPAddr;
QAction actionSetBaseSyscall;
QAction actionSetBaseString;
QAction actionToggleBase;

QMenu *setBitsMenu;
QAction actionSetBits16;
Expand Down Expand Up @@ -229,6 +233,14 @@ private slots:
};
QVector<ThingUsedHere> getThingUsedHere(RVA offset);

/**
* @brief Checks if it makes sense to display the immediate base menu
* @param instObject Object with instruction data
* @returns Return true if the it makes sense to display the set immediate base menu
* return false otherwise.
*/
bool checkImmediateBaseMenu(const QJsonObject& instObject);

void updateTargetMenuActions(const QVector<ThingUsedHere> &targets);
};
#endif // DISASSEMBLYCONTEXTMENU_H