Skip to content

Commit

Permalink
Global variable actions and Show in action and refactoring (#2295)
Browse files Browse the repository at this point in the history
* Show in action for global variables and functions
* Copy address of global variable or function referenced by the cursor selection
* Rename global variable
  • Loading branch information
NirmalManoj committed Aug 14, 2020
1 parent b9ee1cc commit 90c979c
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 32 deletions.
13 changes: 11 additions & 2 deletions src/core/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -926,12 +926,19 @@ void MainWindow::showMemoryWidget(MemoryWidgetType type)
memoryDockWidget->raiseMemoryWidget();
}

QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address)
QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address, AddressTypeHint addressType)
{
QMenu *menu = new QMenu(parent);
// Memory dock widgets
for (auto &dock : dockWidgets) {
if (auto memoryWidget = qobject_cast<MemoryDockWidget *>(dock)) {
if (memoryWidget->getType() == MemoryWidgetType::Graph
|| memoryWidget->getType() == MemoryWidgetType::Decompiler)
{
if (addressType == AddressTypeHint::Data) {
continue;
}
}
QAction *action = new QAction(memoryWidget->windowTitle(), menu);
connect(action, &QAction::triggered, this, [memoryWidget, address]() {
memoryWidget->getSeekable()->seek(address);
Expand Down Expand Up @@ -964,7 +971,9 @@ QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address)
menu->addAction(action);
};
createAddNewWidgetAction(tr("New disassembly"), MemoryWidgetType::Disassembly);
createAddNewWidgetAction(tr("New graph"), MemoryWidgetType::Graph);
if (addressType != AddressTypeHint::Data) {
createAddNewWidgetAction(tr("New graph"), MemoryWidgetType::Graph);
}
createAddNewWidgetAction(tr("New hexdump"), MemoryWidgetType::Hexdump);

return menu;
Expand Down
4 changes: 2 additions & 2 deletions src/core/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ class MainWindow : public QMainWindow
QString getUniqueObjectName(const QString &widgetType) const;
void showMemoryWidget();
void showMemoryWidget(MemoryWidgetType type);

QMenu *createShowInMenu(QWidget *parent, RVA address);
enum class AddressTypeHint { Function, Data, Unknown };
QMenu *createShowInMenu(QWidget *parent, RVA address, AddressTypeHint addressType = AddressTypeHint::Unknown);
void setCurrentMemoryWidget(MemoryDockWidget* memoryWidget);
MemoryDockWidget* getLastMemoryWidget();

Expand Down
198 changes: 178 additions & 20 deletions src/menus/DecompilerContextMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "MainWindow.h"
#include "dialogs/BreakpointsDialog.h"
#include "dialogs/CommentsDialog.h"
#include "common/Configuration.h"

#include <QtCore>
#include <QShortcut>
Expand All @@ -14,27 +15,36 @@

DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWindow)
: QMenu(parent),
curHighlightedWord(QString()),
offset(0),
isTogglingBreakpoints(false),
mainWindow(mainWindow),
annotationHere(nullptr),
actionCopy(tr("Copy"), this),
actionCopyInstructionAddress(tr("Copy instruction address (<address>)"), this),
actionCopyReferenceAddress(tr("Copy address of [flag] (<address>)"), this),
actionShowInSubmenu(tr("Show in"), this),
actionAddComment(tr("Add Comment"), this),
actionDeleteComment(tr("Delete comment"), this),
actionRenameThingHere(tr("Rename function at cursor"), this),
actionDeleteName(tr("Delete <name>"), this),
actionToggleBreakpoint(tr("Add/remove breakpoint"), this),
actionAdvancedBreakpoint(tr("Advanced breakpoint"), this),
breakpointsInLineMenu(new QMenu(this)),
actionContinueUntil(tr("Continue until line"), this),
actionSetPC(tr("Set PC"), this)
{
setActionCopy();
setActionCopy(); // Sets all three copy actions
addSeparator();

setActionShowInSubmenu();
copySeparator = addSeparator();

setActionAddComment();
setActionDeleteComment();

setActionRenameThingHere();
setActionDeleteName();

addSeparator();
addBreakpointMenu();
Expand All @@ -57,6 +67,11 @@ void DecompilerContextMenu::setAnnotationHere(RCodeAnnotation *annotation)
this->annotationHere = annotation;
}

void DecompilerContextMenu::setCurHighlightedWord(QString word)
{
this->curHighlightedWord = word;
}

void DecompilerContextMenu::setOffset(RVA offset)
{
this->offset = offset;
Expand Down Expand Up @@ -86,11 +101,6 @@ void DecompilerContextMenu::setupBreakpointsInLineMenu()
}
}

void DecompilerContextMenu::setCanCopy(bool enabled)
{
actionCopy.setVisible(enabled);
}

void DecompilerContextMenu::setShortcutContextInActions(QMenu *menu)
{
for (QAction *action : menu->actions()) {
Expand All @@ -117,11 +127,14 @@ bool DecompilerContextMenu::getIsTogglingBreakpoints()
void DecompilerContextMenu::aboutToHideSlot()
{
actionAddComment.setVisible(true);
actionRenameThingHere.setVisible(true);
actionDeleteName.setVisible(false);
}

void DecompilerContextMenu::aboutToShowSlot()
{
if (this->firstOffsetInLine != RVA_MAX) {
actionShowInSubmenu.setVisible(true);
QString comment = Core()->cmdRawAt("CC.", this->firstOffsetInLine);
actionAddComment.setVisible(true);
if (comment.isEmpty()) {
Expand All @@ -132,6 +145,7 @@ void DecompilerContextMenu::aboutToShowSlot()
actionAddComment.setText(tr("Edit Comment"));
}
} else {
actionShowInSubmenu.setVisible(false);
actionAddComment.setVisible(false);
actionDeleteComment.setVisible(false);
}
Expand Down Expand Up @@ -163,22 +177,82 @@ void DecompilerContextMenu::aboutToShowSlot()
QString progCounterName = Core()->getRegisterName("PC").toUpper();
actionSetPC.setText(tr("Set %1 here").arg(progCounterName));

if (!annotationHere) { // To be considered as invalid
if (!annotationHere
|| annotationHere->type ==
R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) { // To be considered as invalid
actionRenameThingHere.setVisible(false);
copySeparator->setVisible(false);
} else {
copySeparator->setVisible(true);
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME) {
actionRenameThingHere.setVisible(true);
actionRenameThingHere.setText(tr("Rename function %1").arg(QString(
annotationHere->reference.name)));
}
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) {
RFlagItem *flagDetails = r_flag_get_i(Core()->core()->flags, annotationHere->reference.offset);
if (flagDetails) {
actionRenameThingHere.setText(tr("Rename %1").arg(QString(flagDetails->name)));
actionDeleteName.setText(tr("Remove %1").arg(QString(flagDetails->name)));
actionDeleteName.setVisible(true);
} else {
actionRenameThingHere.setText(tr("Add name to %1").arg(curHighlightedWord));
}
}
}
actionCopyInstructionAddress.setText(tr("Copy instruction address (%1)").arg(RAddressString(
offset)));
bool isReference = false;
if (annotationHere) {
isReference = (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE
|| annotationHere->type == R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE
|| annotationHere->type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME);
}
if (isReference) {
actionCopyReferenceAddress.setVisible(true);
RVA referenceAddr = annotationHere->reference.offset;
RFlagItem *flagDetails = r_flag_get_i(Core()->core()->flags, referenceAddr);
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME) {
actionCopyReferenceAddress.setText(tr("Copy address of %1 (%2)").arg
(QString(annotationHere->reference.name), RAddressString(referenceAddr)));
} else if (flagDetails) {
actionCopyReferenceAddress.setText(tr("Copy address of %1 (%2)").arg
(flagDetails->name, RAddressString(referenceAddr)));
} else {
actionCopyReferenceAddress.setText(tr("Copy address (%1)").arg(RAddressString(referenceAddr)));
}
} else {
actionRenameThingHere.setVisible(true);
actionRenameThingHere.setText(tr("Rename function %1").arg(QString(
annotationHere->function_name.name)));
actionCopyReferenceAddress.setVisible(false);
}
if (actionShowInSubmenu.menu() != nullptr) {
actionShowInSubmenu.menu()->deleteLater();
}
actionShowInSubmenu.setMenu(mainWindow->createShowInMenu(this, offset));
updateTargetMenuActions();
}

// Set up actions

void DecompilerContextMenu::setActionCopy()

void DecompilerContextMenu::setActionCopy() // Set all three copy actions
{
connect(&actionCopy, &QAction::triggered, this, &DecompilerContextMenu::actionCopyTriggered);
addAction(&actionCopy);
actionCopy.setShortcut(QKeySequence::Copy);

connect(&actionCopyInstructionAddress, &QAction::triggered, this,
&DecompilerContextMenu::actionCopyInstructionAddressTriggered);
addAction(&actionCopyInstructionAddress);

connect(&actionCopyReferenceAddress, &QAction::triggered, this,
&DecompilerContextMenu::actionCopyReferenceAddressTriggered);
addAction(&actionCopyReferenceAddress);
actionCopyReferenceAddress.setShortcut({Qt::CTRL + Qt::SHIFT + Qt::Key_C});
}

void DecompilerContextMenu::setActionShowInSubmenu()
{
addAction(&actionShowInSubmenu);
}

void DecompilerContextMenu::setActionAddComment()
Expand All @@ -198,12 +272,20 @@ void DecompilerContextMenu::setActionDeleteComment()

void DecompilerContextMenu::setActionRenameThingHere()
{
actionRenameThingHere.setShortcut({Qt::SHIFT + Qt::Key_N});
actionRenameThingHere.setShortcut({Qt::Key_N});
connect(&actionRenameThingHere, &QAction::triggered, this,
&DecompilerContextMenu::actionRenameThingHereTriggered);
addAction(&actionRenameThingHere);
}

void DecompilerContextMenu::setActionDeleteName()
{
connect(&actionDeleteName, &QAction::triggered, this,
&DecompilerContextMenu::actionDeleteNameTriggered);
addAction(&actionDeleteName);
actionDeleteName.setVisible(false);
}

void DecompilerContextMenu::setActionToggleBreakpoint()
{
connect(&actionToggleBreakpoint, &QAction::triggered, this,
Expand Down Expand Up @@ -236,6 +318,18 @@ void DecompilerContextMenu::actionCopyTriggered()
emit copy();
}

void DecompilerContextMenu::actionCopyInstructionAddressTriggered()
{
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(RAddressString(offset));
}

void DecompilerContextMenu::actionCopyReferenceAddressTriggered()
{
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(RAddressString(annotationHere->reference.offset));
}

void DecompilerContextMenu::actionAddCommentTriggered()
{
CommentsDialog::addOrEditComment(this->firstOffsetInLine, this);
Expand All @@ -251,29 +345,53 @@ void DecompilerContextMenu::actionRenameThingHereTriggered()
if (!annotationHere) {
return;
}
RCoreLocked core = Core()->core();
bool ok;
auto type = annotationHere->type;
if (type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME) {
QString currentName(annotationHere->function_name.name);
RVA func_addr = annotationHere->function_name.offset;
QString currentName(annotationHere->reference.name);
RVA func_addr = annotationHere->reference.offset;
RAnalFunction *func = Core()->functionAt(func_addr);
if (func == NULL) {
QString function_name = QInputDialog::getText(this, tr("Define this function at %2").arg(RAddressString(func_addr)),
tr("Function name:"), QLineEdit::Normal, currentName, &ok);
QString function_name = QInputDialog::getText(this,
tr("Define this function at %2").arg(RAddressString(func_addr)),
tr("Function name:"), QLineEdit::Normal, currentName, &ok);
if (ok && !function_name.isEmpty()) {
Core()->createFunctionAt(func_addr, function_name);
}
} else {
QString newName = QInputDialog::getText(this, tr("Rename function %2").arg(currentName),
tr("Function name:"), QLineEdit::Normal, currentName, &ok);
tr("Function name:"), QLineEdit::Normal, currentName, &ok);
if (ok && !newName.isEmpty()) {
Core()->renameFunction(func_addr, newName);
}
Core()->renameFunction(func_addr, newName);
}
}

} else if (type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) {
RVA var_addr = annotationHere->reference.offset;
RFlagItem *flagDetails = r_flag_get_i(core->flags, var_addr);
if (flagDetails) {
QString newName = QInputDialog::getText(this, tr("Rename %2").arg(flagDetails->name),
tr("Enter name"), QLineEdit::Normal, flagDetails->name, &ok);
if (ok && !newName.isEmpty()) {
Core()->renameFlag(flagDetails->name, newName);
}
} else {
QString newName = QInputDialog::getText(this, tr("Add name to %2").arg(curHighlightedWord),
tr("Enter name"), QLineEdit::Normal, curHighlightedWord, &ok);
if (ok && !newName.isEmpty()) {
Core()->addFlag(var_addr, newName, 1);
}
}

}
}

void DecompilerContextMenu::actionDeleteNameTriggered()
{
Core()->delFlag(annotationHere->reference.offset);
}

void DecompilerContextMenu::actionToggleBreakpointTriggered()
{
if (!this->availableBreakpoints.isEmpty()) {
Expand Down Expand Up @@ -335,3 +453,43 @@ void DecompilerContextMenu::addDebugMenu()
setActionSetPC();
debugMenu->addAction(&actionSetPC);
}

void DecompilerContextMenu::updateTargetMenuActions()
{
for (auto action : showTargetMenuActions) {
removeAction(action);
auto menu = action->menu();
if (menu) {
menu->deleteLater();
}
action->deleteLater();
}
showTargetMenuActions.clear();
RCoreLocked core = Core()->core();
if (annotationHere && (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE
|| annotationHere->type == R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE
|| annotationHere->type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME)) {
QString name;
QMenu *menu;
if (annotationHere->type == R_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE
|| annotationHere->type == R_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) {
menu = mainWindow->createShowInMenu(this, annotationHere->reference.offset, MainWindow::AddressTypeHint::Data);
RVA var_addr = annotationHere->reference.offset;
RFlagItem *flagDetails = r_flag_get_i(core->flags, var_addr);
if (flagDetails) {
name = tr("Show %1 in").arg(flagDetails->name);
} else {
name = tr("Show %1 in").arg(RAddressString(annotationHere->reference.offset));
}
} else if (annotationHere->type == R_CODE_ANNOTATION_TYPE_FUNCTION_NAME) {
menu = mainWindow->createShowInMenu(this, annotationHere->reference.offset,
MainWindow::AddressTypeHint::Function);
name = tr("%1 (%2)").arg(QString(annotationHere->reference.name),
RAddressString(annotationHere->reference.offset));
}
auto action = new QAction(name, this);
showTargetMenuActions.append(action);
action->setMenu(menu);
insertActions(copySeparator, showTargetMenuActions);
}
}
Loading

0 comments on commit 90c979c

Please sign in to comment.