Skip to content

Commit

Permalink
Common behaviour for lists with items that have address (radareorg#1700)
Browse files Browse the repository at this point in the history
  • Loading branch information
karliss authored and xarkes committed Aug 19, 2019
1 parent cd2dbc4 commit 0aa91c3
Show file tree
Hide file tree
Showing 37 changed files with 906 additions and 1,290 deletions.
20 changes: 10 additions & 10 deletions src/Cutter.pro
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,10 @@ SOURCES += \
widgets/GraphGridLayout.cpp \
widgets/HexWidget.cpp \
common/SelectionHighlight.cpp \
common/Decompiler.cpp
common/Decompiler.cpp \
menus/AddressableItemContextMenu.cpp \
common/AddressableItemModel.cpp \
widgets/ListDockWidget.cpp

GRAPHVIZ_SOURCES = \
widgets/GraphvizLayout.cpp
Expand Down Expand Up @@ -490,7 +493,10 @@ HEADERS += \
widgets/GraphLayout.h \
widgets/HexWidget.h \
common/SelectionHighlight.h \
common/Decompiler.h
common/Decompiler.h \
menus/AddressableItemContextMenu.h \
common/AddressableItemModel.h \
widgets/ListDockWidget.h

GRAPHVIZ_HEADERS = widgets/GraphGridLayout.h

Expand All @@ -506,17 +512,11 @@ FORMS += \
dialogs/InitialOptionsDialog.ui \
dialogs/EditFunctionDialog.ui \
core/MainWindow.ui \
widgets/CommentsWidget.ui \
widgets/ConsoleWidget.ui \
widgets/Dashboard.ui \
widgets/EntrypointWidget.ui \
widgets/FlagsWidget.ui \
widgets/ExportsWidget.ui \
widgets/FunctionsWidget.ui \
widgets/ImportsWidget.ui \
widgets/RelocsWidget.ui \
widgets/StringsWidget.ui \
widgets/SymbolsWidget.ui \
widgets/HexdumpWidget.ui \
dialogs/SaveProjectDialog.ui \
dialogs/preferences/PreferencesDialog.ui \
Expand All @@ -527,7 +527,6 @@ FORMS += \
widgets/ClassesWidget.ui \
widgets/VTablesWidget.ui \
widgets/TypesWidget.ui \
widgets/HeadersWidget.ui \
widgets/SearchWidget.ui \
dialogs/R2PluginsDialog.ui \
dialogs/VersionInfoDialog.ui \
Expand All @@ -554,7 +553,8 @@ FORMS += \
widgets/SdbWidget.ui \
dialogs/LinkTypeDialog.ui \
widgets/ColorPicker.ui \
dialogs/preferences/ColorThemeEditDialog.ui
dialogs/preferences/ColorThemeEditDialog.ui \
widgets/ListDockWidget.ui

RESOURCES += \
resources.qrc \
Expand Down
30 changes: 30 additions & 0 deletions src/common/AddressableItemModel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "AddressableItemModel.h"

AddressableFilterProxyModel::AddressableFilterProxyModel(AddressableItemModelI *sourceModel,
QObject *parent) :
AddressableItemModel<QSortFilterProxyModel>(parent)
{
setSourceModel(sourceModel);
addressableSourceModel = sourceModel;
}

RVA AddressableFilterProxyModel::address(const QModelIndex &index) const
{
return addressableSourceModel->address(this->mapToSource(index));
}

QString AddressableFilterProxyModel::name(const QModelIndex &index) const
{
return addressableSourceModel->name(this->mapToSource(index));
}

void AddressableFilterProxyModel::setSourceModel(QAbstractItemModel *)
{
throw new std::runtime_error("Not supported");
}

void AddressableFilterProxyModel::setSourceModel(AddressableItemModelI *sourceModel)
{
ParentClass::setSourceModel(sourceModel->asItemModel());
addressableSourceModel = sourceModel;
}
49 changes: 49 additions & 0 deletions src/common/AddressableItemModel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

#ifndef ADDRESSABLEITEMMODEL_H
#define ADDRESSABLEITEMMODEL_H

#include <QAbstractItemModel>
#include <QSortFilterProxyModel>
#include <QAbstractItemModel>

#include <core/CutterCommon.h>

class AddressableItemModelI
{
public:
virtual RVA address(const QModelIndex &index) const = 0;
/**
* @brief Get name for item, optional.
* @param index item intex
* @return Item name or empty QString if item doesn't have short descriptive name.
*/
virtual QString name(const QModelIndex &index) const { Q_UNUSED(index) return QString(); }
virtual QAbstractItemModel *asItemModel() = 0;
};

template <class ParentModel = QAbstractItemModel>
class AddressableItemModel : public ParentModel, public AddressableItemModelI
{
static_assert (std::is_base_of<QAbstractItemModel, ParentModel>::value,
"ParentModel needs to inherit from QAbstractItemModel");
public:
explicit AddressableItemModel(QObject *parent = nullptr) : ParentModel(parent) {}
virtual ~AddressableItemModel() {}
QAbstractItemModel *asItemModel() { return this; }
};

class AddressableFilterProxyModel : public AddressableItemModel<QSortFilterProxyModel>
{
using ParentClass = AddressableItemModel<QSortFilterProxyModel>;
public:
AddressableFilterProxyModel(AddressableItemModelI *sourceModel, QObject *parent);

RVA address(const QModelIndex &index) const override;
QString name(const QModelIndex &) const override;
void setSourceModel(AddressableItemModelI *sourceModel);
private:
void setSourceModel(QAbstractItemModel *sourceModel) override; // Don't use this directly
AddressableItemModelI *addressableSourceModel;
};

#endif // ADDRESSABLEITEMMODEL_H
11 changes: 11 additions & 0 deletions src/core/Cutter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2597,6 +2597,17 @@ void CutterCore::addFlag(RVA offset, QString name, RVA size)
emit flagsChanged();
}

QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut)
{
auto r = cmdj(QString("fdj @") + QString::number(offset)).object();
QString name = r.value("name").toString();
if (flagOffsetOut) {
int queryOffset = r.value("offset").toInt(0);
*flagOffsetOut = offset + static_cast<RVA>(-queryOffset);
}
return name;
}

void CutterCore::handleREvent(int type, void *data)
{
switch (type) {
Expand Down
7 changes: 7 additions & 0 deletions src/core/Cutter.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ class CutterCore: public QObject
void delFlag(RVA addr);
void delFlag(const QString &name);
void addFlag(RVA offset, QString name, RVA size);
/**
* @brief Get nearest flag at or before offset.
* @param offset search position
* @param flagOffsetOut adress of returned flag
* @return flag name
*/
QString nearestFlag(RVA offset, RVA *flagOffsetOut);
void triggerFlagsChanged();

/* Edition functions */
Expand Down
103 changes: 103 additions & 0 deletions src/menus/AddressableItemContextMenu.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#include "AddressableItemContextMenu.h"
#include "dialogs/XrefsDialog.h"
#include "MainWindow.h"
#include "dialogs/CommentsDialog.h"

#include <QtCore>
#include <QShortcut>
#include <QJsonArray>
#include <QClipboard>
#include <QApplication>
#include <QPushButton>

AddressableItemContextMenu::AddressableItemContextMenu(QWidget *parent, MainWindow *mainWindow)
: QMenu(parent)
, mainWindow(mainWindow)
, actionShowInMenu(tr("Show in"), this)
, actionCopyAddress(tr("Copy address"), this)
, actionShowXrefs(tr("Show X-Refs"), this)
, actionAddcomment(tr("Add comment"), this)
{
connect(&actionCopyAddress, &QAction::triggered, this,
&AddressableItemContextMenu::onActionCopyAddress);
actionCopyAddress.setShortcuts({Qt::CTRL + Qt::SHIFT + Qt::Key_C});
actionCopyAddress.setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut);

connect(&actionShowXrefs, &QAction::triggered, this,
&AddressableItemContextMenu::onActionShowXrefs);
actionShowXrefs.setShortcut({Qt::Key_X});
actionShowXrefs.setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut);

connect(&actionAddcomment, &QAction::triggered, this,
&AddressableItemContextMenu::onActionAddComment);


addAction(&actionShowInMenu);
addAction(&actionCopyAddress);
addAction(&actionShowXrefs);
addSeparator();
addAction(&actionAddcomment);

connect(this, &QMenu::aboutToShow, this, &AddressableItemContextMenu::aboutToShowSlot);
}

AddressableItemContextMenu::~AddressableItemContextMenu()
{
}

void AddressableItemContextMenu::setWholeFunction(bool wholeFunciton)
{
this->wholeFunction = wholeFunciton;
}

void AddressableItemContextMenu::setOffset(RVA offset)
{
setTarget(offset);
}

void AddressableItemContextMenu::setTarget(RVA offset, QString name)
{
this->offset = offset;
this->name = name;
}

void AddressableItemContextMenu::onActionCopyAddress()
{
auto clipboard = QApplication::clipboard();
clipboard->setText(RAddressString(offset));
}

void AddressableItemContextMenu::onActionShowXrefs()
{
XrefsDialog dialog(nullptr);
QString tmpName = name;
if (name.isEmpty()) {
name = RAddressString(offset);
}
dialog.fillRefsForAddress(offset, name, wholeFunction);
dialog.exec();
}

void AddressableItemContextMenu::onActionAddComment()
{
// Create dialog
CommentsDialog c(this);

if (c.exec()) {
// Get new function name
QString comment = c.getComment();
// Rename function in r2 core
Core()->setComment(offset, comment);
// Seek to new renamed function
Core()->seekAndShow(offset);
}
}

void AddressableItemContextMenu::aboutToShowSlot()
{
if (actionShowInMenu.menu()) {
actionShowInMenu.menu()->deleteLater();
}
actionShowInMenu.setMenu(mainWindow->createShowInMenu(this, offset));
}

43 changes: 43 additions & 0 deletions src/menus/AddressableItemContextMenu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef ADDRESSABLEITEMCONTEXTMENU_H
#define ADDRESSABLEITEMCONTEXTMENU_H

#include "core/Cutter.h"
#include <QMenu>
#include <QKeySequence>

class AddressableItemContextMenu : public QMenu
{
Q_OBJECT

public:
AddressableItemContextMenu(QWidget *parent, MainWindow *mainWindow);
~AddressableItemContextMenu();

/**
* @brief Configure if addressable item refers to whole function or specific address
* @param wholeFunciton
*/
void setWholeFunction(bool wholeFunciton);
public slots:
void setOffset(RVA offset);
void setTarget(RVA offset, QString name = QString());
private:
void onActionCopyAddress();
void onActionShowXrefs();
void onActionAddComment();

virtual void aboutToShowSlot();

MainWindow *mainWindow;

RVA offset;
protected:
QAction actionShowInMenu;
QAction actionCopyAddress;
QAction actionShowXrefs;
QAction actionAddcomment;

QString name;
bool wholeFunction = false;
};
#endif // ADDRESSABLEITEMCONTEXTMENU_H

0 comments on commit 0aa91c3

Please sign in to comment.