From 13c3ff4cf866ac0527b52d2cab80dd4c9663e07d Mon Sep 17 00:00:00 2001 From: mandlebro Date: Thu, 19 Jul 2018 15:35:46 +0100 Subject: [PATCH] Added register references widget --- src/Cutter.cpp | 20 ++++ src/Cutter.h | 8 ++ src/Cutter.pro | 9 +- src/MainWindow.cpp | 5 +- src/MainWindow.h | 1 + src/MainWindow.ui | 9 ++ src/widgets/RegisterRefsWidget.cpp | 160 +++++++++++++++++++++++++++++ src/widgets/RegisterRefsWidget.h | 81 +++++++++++++++ src/widgets/RegisterRefsWidget.ui | 69 +++++++++++++ 9 files changed, 358 insertions(+), 4 deletions(-) create mode 100644 src/widgets/RegisterRefsWidget.cpp create mode 100644 src/widgets/RegisterRefsWidget.h create mode 100644 src/widgets/RegisterRefsWidget.ui diff --git a/src/Cutter.cpp b/src/Cutter.cpp index 72b617ce..7fdcffdd 100644 --- a/src/Cutter.cpp +++ b/src/Cutter.cpp @@ -746,6 +746,26 @@ QJsonDocument CutterCore::getRegisterValues() return cmdj("drj"); } +QList CutterCore::getRegisterRefs() +{ + QList ret; + QJsonArray registerRefArray = cmdj("drrj").array(); + + for (QJsonValue value : registerRefArray) { + QJsonObject regRefObject = value.toObject(); + + RegisterRefDescription regRef; + + regRef.reg = regRefObject["reg"].toString(); + regRef.value = regRefObject["value"].toString(); + regRef.ref = regRefObject["ref"].toString(); + + ret << regRef; + } + + return ret; +} + QString CutterCore::getRegisterName(QString registerRole) { return cmd("drn " + registerRole).trimmed(); diff --git a/src/Cutter.h b/src/Cutter.h index 9fa63346..b510ea9f 100644 --- a/src/Cutter.h +++ b/src/Cutter.h @@ -319,6 +319,12 @@ struct ProcessDescription { QString path; }; +struct RegisterRefDescription { + QString reg; + QString value; + QString ref; +}; + Q_DECLARE_METATYPE(FunctionDescription) Q_DECLARE_METATYPE(ImportDescription) Q_DECLARE_METATYPE(ExportDescription) @@ -350,6 +356,7 @@ Q_DECLARE_METATYPE(SectionDescription) Q_DECLARE_METATYPE(MemoryMapDescription) Q_DECLARE_METATYPE(BreakpointDescription) Q_DECLARE_METATYPE(ProcessDescription) +Q_DECLARE_METATYPE(RegisterRefDescription) class CutterCore: public QObject { @@ -566,6 +573,7 @@ public: BlockStatistics getBlockStatistics(unsigned int blocksCount); QList getBreakpoints(); QList getAllProcesses(); + QList getRegisterRefs(); QList getXRefs(RVA addr, bool to, bool whole_function, const QString &filterType = QString::null); diff --git a/src/Cutter.pro b/src/Cutter.pro index 80733297..20428c41 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -181,7 +181,8 @@ SOURCES += \ dialogs/preferences/DebugOptionsWidget.cpp \ widgets/BreakpointWidget.cpp \ dialogs/BreakpointsDialog.cpp \ - dialogs/AttachProcDialog.cpp + dialogs/AttachProcDialog.cpp \ + widgets/RegisterRefsWidget.cpp HEADERS += \ Cutter.h \ @@ -274,7 +275,8 @@ HEADERS += \ dialogs/preferences/DebugOptionsWidget.h \ widgets/BreakpointWidget.h \ dialogs/BreakpointsDialog.h \ - dialogs/AttachProcDialog.h + dialogs/AttachProcDialog.h \ + widgets/RegisterRefsWidget.h FORMS += \ dialogs/AboutDialog.ui \ @@ -327,7 +329,8 @@ FORMS += \ dialogs/preferences/DebugOptionsWidget.ui \ widgets/BreakpointWidget.ui \ dialogs/BreakpointsDialog.ui \ - dialogs/AttachProcDialog.ui + dialogs/AttachProcDialog.ui \ + widgets/RegisterRefsWidget.ui RESOURCES += \ resources.qrc \ diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index cffa83c0..10c323e1 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -76,6 +76,7 @@ #include "widgets/DebugToolbar.h" #include "widgets/MemoryMapWidget.h" #include "widgets/BreakpointWidget.h" +#include "widgets/RegisterRefsWidget.h" // Graphics #include @@ -219,6 +220,7 @@ void MainWindow::initUI() registersDock = new RegistersWidget(this, ui->actionRegisters); memoryMapDock = new MemoryMapWidget(this, ui->actionMemoryMap); breakpointDock = new BreakpointWidget(this, ui->actionBreakpoint); + registerRefsDock = new RegisterRefsWidget(this, ui->actionRegisterRefs); #ifdef CUTTER_ENABLE_JUPYTER jupyterDock = new JupyterWidget(this, ui->actionJupyter); #else @@ -562,9 +564,10 @@ void MainWindow::restoreDocks() splitDockWidget(sidebarDock, stackDock, Qt::Horizontal); splitDockWidget(stackDock, registersDock, Qt::Vertical); tabifyDockWidget(stackDock, backtraceDock); - // MemoryMap/Breakpoint widget goes in the center tabs + // MemoryMap/Breakpoint/RegRefs widget goes in the center tabs tabifyDockWidget(dashboardDock, memoryMapDock); tabifyDockWidget(dashboardDock, breakpointDock); + tabifyDockWidget(dashboardDock, registerRefsDock); #ifdef CUTTER_ENABLE_JUPYTER tabifyDockWidget(dashboardDock, jupyterDock); #endif diff --git a/src/MainWindow.h b/src/MainWindow.h index 2a4bb38f..873aaa6e 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -227,6 +227,7 @@ private: QDockWidget *memoryMapDock = nullptr; NewFileDialog *newFileDialog = nullptr; QDockWidget *breakpointDock = nullptr; + QDockWidget *registerRefsDock = nullptr; #ifdef CUTTER_ENABLE_JUPYTER JupyterWidget *jupyterDock = nullptr; #endif diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 78650105..7983e740 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -232,6 +232,7 @@ border-top: 0px; + @@ -1061,6 +1062,14 @@ border-top: 0px; Breakpoints + + + true + + + Register References + + true diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp new file mode 100644 index 00000000..11440e31 --- /dev/null +++ b/src/widgets/RegisterRefsWidget.cpp @@ -0,0 +1,160 @@ +#include "RegisterRefsWidget.h" +#include "ui_RegisterRefsWidget.h" +#include "MainWindow.h" +#include "utils/Helpers.h" +#include + +RegisterRefModel::RegisterRefModel(QList *registerRefs, QObject *parent) + : QAbstractListModel(parent), + registerRefs(registerRefs) +{ +} + +int RegisterRefModel::rowCount(const QModelIndex &) const +{ + return registerRefs->count(); +} + +int RegisterRefModel::columnCount(const QModelIndex &) const +{ + return RegisterRefModel::ColumnCount; +} + +QVariant RegisterRefModel::data(const QModelIndex &index, int role) const +{ + if (index.row() >= registerRefs->count()) + return QVariant(); + + const RegisterRefDescription ®isterRef = registerRefs->at(index.row()); + + switch (role) { + case Qt::DisplayRole: + switch (index.column()) { + case RegColumn: + return registerRef.reg; + case ValueColumn: + return registerRef.value; + case RefColumn: + return registerRef.ref; + default: + return QVariant(); + } + case RegisterRefDescriptionRole: + return QVariant::fromValue(registerRef); + default: + return QVariant(); + } +} + +QVariant RegisterRefModel::headerData(int section, Qt::Orientation, int role) const +{ + switch (role) { + case Qt::DisplayRole: + switch (section) { + case RegColumn: + return tr("Register"); + case ValueColumn: + return tr("Value"); + case RefColumn: + return tr("Reference"); + default: + return QVariant(); + } + default: + return QVariant(); + } +} + +void RegisterRefModel::beginReloadRegisterRef() +{ + beginResetModel(); +} + +void RegisterRefModel::endReloadRegisterRef() +{ + endResetModel(); +} + +RegisterRefProxyModel::RegisterRefProxyModel(RegisterRefModel *sourceModel, QObject *parent) + : QSortFilterProxyModel(parent) +{ + setSourceModel(sourceModel); +} + +bool RegisterRefProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + QModelIndex index = sourceModel()->index(row, 0, parent); + RegisterRefDescription item = index.data( + RegisterRefModel::RegisterRefDescriptionRole).value(); + return item.reg.contains(filterRegExp()); +} + +bool RegisterRefProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + RegisterRefDescription leftRegRef = left.data( + RegisterRefModel::RegisterRefDescriptionRole).value(); + RegisterRefDescription rightRegRef = right.data( + RegisterRefModel::RegisterRefDescriptionRole).value(); + + switch (left.column()) { + case RegisterRefModel::RegColumn: + return leftRegRef.reg < rightRegRef.reg; + case RegisterRefModel::RefColumn: + return leftRegRef.ref < rightRegRef.ref; + case RegisterRefModel::ValueColumn: + return leftRegRef.value < rightRegRef.value; + default: + break; + } + + return leftRegRef.reg < rightRegRef.reg; +} + +RegisterRefsWidget::RegisterRefsWidget(MainWindow *main, QAction *action) : + CutterDockWidget(main, action), + ui(new Ui::RegisterRefsWidget) +{ + ui->setupUi(this); + + registerRefModel = new RegisterRefModel(®isterRefs, this); + registerRefProxyModel = new RegisterRefProxyModel(registerRefModel, this); + ui->registerRefTreeView->setModel(registerRefProxyModel); + ui->registerRefTreeView->sortByColumn(RegisterRefModel::RegColumn, Qt::AscendingOrder); + + // Ctrl-F to show/hide the filter entry + QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this); + connect(search_shortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter); + search_shortcut->setContext(Qt::WidgetWithChildrenShortcut); + + connect(ui->quickFilterView, SIGNAL(filterTextChanged(const QString &)), registerRefProxyModel, + SLOT(setFilterWildcard(const QString &))); + connect(ui->quickFilterView, SIGNAL(filterClosed()), ui->registerRefTreeView, SLOT(setFocus())); + setScrollMode(); + connect(Core(), &CutterCore::refreshAll, this, &RegisterRefsWidget::refreshRegisterRef); + connect(Core(), &CutterCore::registersChanged, this, &RegisterRefsWidget::refreshRegisterRef); +} + +RegisterRefsWidget::~RegisterRefsWidget() {} + +void RegisterRefsWidget::refreshRegisterRef() +{ + registerRefModel->beginReloadRegisterRef(); + registerRefs = Core()->getRegisterRefs(); + registerRefModel->endReloadRegisterRef(); + + ui->registerRefTreeView->resizeColumnToContents(0); + ui->registerRefTreeView->resizeColumnToContents(1); + ui->registerRefTreeView->resizeColumnToContents(2); +} + +void RegisterRefsWidget::setScrollMode() +{ + qhelpers::setVerticalScrollMode(ui->registerRefTreeView); +} + +void RegisterRefsWidget::on_registerRefTreeView_doubleClicked(const QModelIndex &index) +{ + RegisterRefDescription item = index.data( + RegisterRefModel::RegisterRefDescriptionRole).value(); + Core()->seek(item.value); +} diff --git a/src/widgets/RegisterRefsWidget.h b/src/widgets/RegisterRefsWidget.h new file mode 100644 index 00000000..09fd3d7a --- /dev/null +++ b/src/widgets/RegisterRefsWidget.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include "Cutter.h" +#include "CutterDockWidget.h" + +#include +#include + +class MainWindow; +class QTreeWidget; + +namespace Ui { +class RegisterRefsWidget; +} + + +class MainWindow; +class QTreeWidgetItem; + + +class RegisterRefModel: public QAbstractListModel +{ + Q_OBJECT + +private: + QList *registerRefs; + +public: + enum Column { RegColumn = 0, ValueColumn, RefColumn, ColumnCount }; + enum Role { RegisterRefDescriptionRole = Qt::UserRole }; + + RegisterRefModel(QList *registerRefs, QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + void beginReloadRegisterRef(); + void endReloadRegisterRef(); +}; + + + +class RegisterRefProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + RegisterRefProxyModel(RegisterRefModel *sourceModel, QObject *parent = nullptr); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +}; + + +class RegisterRefsWidget : public CutterDockWidget +{ + Q_OBJECT + +public: + explicit RegisterRefsWidget(MainWindow *main, QAction *action = nullptr); + ~RegisterRefsWidget(); + +private slots: + void on_registerRefTreeView_doubleClicked(const QModelIndex &index); + void refreshRegisterRef(); + +private: + std::unique_ptr ui; + + RegisterRefModel *registerRefModel; + RegisterRefProxyModel *registerRefProxyModel; + QList registerRefs; + + void setScrollMode(); +}; diff --git a/src/widgets/RegisterRefsWidget.ui b/src/widgets/RegisterRefsWidget.ui new file mode 100644 index 00000000..9d29ea77 --- /dev/null +++ b/src/widgets/RegisterRefsWidget.ui @@ -0,0 +1,69 @@ + + + RegisterRefsWidget + + + + 0 + 0 + 400 + 300 + + + + Register References + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTreeView::item +{ + padding-top: 1px; + padding-bottom: 1px; +} + + + QFrame::NoFrame + + + 0 + + + 8 + + + true + + + + + + + + + + + + QuickFilterView + QWidget +
widgets/QuickFilterView.h
+ 1 +
+
+ + +