Added register references widget

This commit is contained in:
mandlebro 2018-07-19 15:35:46 +01:00 committed by xarkes
parent dde5d00b98
commit 13c3ff4cf8
9 changed files with 358 additions and 4 deletions

View File

@ -746,6 +746,26 @@ QJsonDocument CutterCore::getRegisterValues()
return cmdj("drj"); return cmdj("drj");
} }
QList<RegisterRefDescription> CutterCore::getRegisterRefs()
{
QList<RegisterRefDescription> 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) QString CutterCore::getRegisterName(QString registerRole)
{ {
return cmd("drn " + registerRole).trimmed(); return cmd("drn " + registerRole).trimmed();

View File

@ -319,6 +319,12 @@ struct ProcessDescription {
QString path; QString path;
}; };
struct RegisterRefDescription {
QString reg;
QString value;
QString ref;
};
Q_DECLARE_METATYPE(FunctionDescription) Q_DECLARE_METATYPE(FunctionDescription)
Q_DECLARE_METATYPE(ImportDescription) Q_DECLARE_METATYPE(ImportDescription)
Q_DECLARE_METATYPE(ExportDescription) Q_DECLARE_METATYPE(ExportDescription)
@ -350,6 +356,7 @@ Q_DECLARE_METATYPE(SectionDescription)
Q_DECLARE_METATYPE(MemoryMapDescription) Q_DECLARE_METATYPE(MemoryMapDescription)
Q_DECLARE_METATYPE(BreakpointDescription) Q_DECLARE_METATYPE(BreakpointDescription)
Q_DECLARE_METATYPE(ProcessDescription) Q_DECLARE_METATYPE(ProcessDescription)
Q_DECLARE_METATYPE(RegisterRefDescription)
class CutterCore: public QObject class CutterCore: public QObject
{ {
@ -566,6 +573,7 @@ public:
BlockStatistics getBlockStatistics(unsigned int blocksCount); BlockStatistics getBlockStatistics(unsigned int blocksCount);
QList<BreakpointDescription> getBreakpoints(); QList<BreakpointDescription> getBreakpoints();
QList<ProcessDescription> getAllProcesses(); QList<ProcessDescription> getAllProcesses();
QList<RegisterRefDescription> getRegisterRefs();
QList<XrefDescription> getXRefs(RVA addr, bool to, bool whole_function, QList<XrefDescription> getXRefs(RVA addr, bool to, bool whole_function,
const QString &filterType = QString::null); const QString &filterType = QString::null);

View File

@ -181,7 +181,8 @@ SOURCES += \
dialogs/preferences/DebugOptionsWidget.cpp \ dialogs/preferences/DebugOptionsWidget.cpp \
widgets/BreakpointWidget.cpp \ widgets/BreakpointWidget.cpp \
dialogs/BreakpointsDialog.cpp \ dialogs/BreakpointsDialog.cpp \
dialogs/AttachProcDialog.cpp dialogs/AttachProcDialog.cpp \
widgets/RegisterRefsWidget.cpp
HEADERS += \ HEADERS += \
Cutter.h \ Cutter.h \
@ -274,7 +275,8 @@ HEADERS += \
dialogs/preferences/DebugOptionsWidget.h \ dialogs/preferences/DebugOptionsWidget.h \
widgets/BreakpointWidget.h \ widgets/BreakpointWidget.h \
dialogs/BreakpointsDialog.h \ dialogs/BreakpointsDialog.h \
dialogs/AttachProcDialog.h dialogs/AttachProcDialog.h \
widgets/RegisterRefsWidget.h
FORMS += \ FORMS += \
dialogs/AboutDialog.ui \ dialogs/AboutDialog.ui \
@ -327,7 +329,8 @@ FORMS += \
dialogs/preferences/DebugOptionsWidget.ui \ dialogs/preferences/DebugOptionsWidget.ui \
widgets/BreakpointWidget.ui \ widgets/BreakpointWidget.ui \
dialogs/BreakpointsDialog.ui \ dialogs/BreakpointsDialog.ui \
dialogs/AttachProcDialog.ui dialogs/AttachProcDialog.ui \
widgets/RegisterRefsWidget.ui
RESOURCES += \ RESOURCES += \
resources.qrc \ resources.qrc \

View File

@ -76,6 +76,7 @@
#include "widgets/DebugToolbar.h" #include "widgets/DebugToolbar.h"
#include "widgets/MemoryMapWidget.h" #include "widgets/MemoryMapWidget.h"
#include "widgets/BreakpointWidget.h" #include "widgets/BreakpointWidget.h"
#include "widgets/RegisterRefsWidget.h"
// Graphics // Graphics
#include <QGraphicsEllipseItem> #include <QGraphicsEllipseItem>
@ -219,6 +220,7 @@ void MainWindow::initUI()
registersDock = new RegistersWidget(this, ui->actionRegisters); registersDock = new RegistersWidget(this, ui->actionRegisters);
memoryMapDock = new MemoryMapWidget(this, ui->actionMemoryMap); memoryMapDock = new MemoryMapWidget(this, ui->actionMemoryMap);
breakpointDock = new BreakpointWidget(this, ui->actionBreakpoint); breakpointDock = new BreakpointWidget(this, ui->actionBreakpoint);
registerRefsDock = new RegisterRefsWidget(this, ui->actionRegisterRefs);
#ifdef CUTTER_ENABLE_JUPYTER #ifdef CUTTER_ENABLE_JUPYTER
jupyterDock = new JupyterWidget(this, ui->actionJupyter); jupyterDock = new JupyterWidget(this, ui->actionJupyter);
#else #else
@ -562,9 +564,10 @@ void MainWindow::restoreDocks()
splitDockWidget(sidebarDock, stackDock, Qt::Horizontal); splitDockWidget(sidebarDock, stackDock, Qt::Horizontal);
splitDockWidget(stackDock, registersDock, Qt::Vertical); splitDockWidget(stackDock, registersDock, Qt::Vertical);
tabifyDockWidget(stackDock, backtraceDock); 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, memoryMapDock);
tabifyDockWidget(dashboardDock, breakpointDock); tabifyDockWidget(dashboardDock, breakpointDock);
tabifyDockWidget(dashboardDock, registerRefsDock);
#ifdef CUTTER_ENABLE_JUPYTER #ifdef CUTTER_ENABLE_JUPYTER
tabifyDockWidget(dashboardDock, jupyterDock); tabifyDockWidget(dashboardDock, jupyterDock);
#endif #endif

View File

@ -227,6 +227,7 @@ private:
QDockWidget *memoryMapDock = nullptr; QDockWidget *memoryMapDock = nullptr;
NewFileDialog *newFileDialog = nullptr; NewFileDialog *newFileDialog = nullptr;
QDockWidget *breakpointDock = nullptr; QDockWidget *breakpointDock = nullptr;
QDockWidget *registerRefsDock = nullptr;
#ifdef CUTTER_ENABLE_JUPYTER #ifdef CUTTER_ENABLE_JUPYTER
JupyterWidget *jupyterDock = nullptr; JupyterWidget *jupyterDock = nullptr;
#endif #endif

View File

@ -232,6 +232,7 @@ border-top: 0px;
<addaction name="actionBacktrace"/> <addaction name="actionBacktrace"/>
<addaction name="actionMemoryMap"/> <addaction name="actionMemoryMap"/>
<addaction name="actionBreakpoint"/> <addaction name="actionBreakpoint"/>
<addaction name="actionRegisterRefs"/>
</widget> </widget>
<widget class="QMenu" name="addInfoWidgets"> <widget class="QMenu" name="addInfoWidgets">
<property name="title"> <property name="title">
@ -1061,6 +1062,14 @@ border-top: 0px;
<string>Breakpoints</string> <string>Breakpoints</string>
</property> </property>
</action> </action>
<action name="actionRegisterRefs">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Register References</string>
</property>
</action>
<action name="actionClasses"> <action name="actionClasses">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>

View File

@ -0,0 +1,160 @@
#include "RegisterRefsWidget.h"
#include "ui_RegisterRefsWidget.h"
#include "MainWindow.h"
#include "utils/Helpers.h"
#include <QMenu>
RegisterRefModel::RegisterRefModel(QList<RegisterRefDescription> *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 &registerRef = 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<RegisterRefDescription>();
return item.reg.contains(filterRegExp());
}
bool RegisterRefProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
RegisterRefDescription leftRegRef = left.data(
RegisterRefModel::RegisterRefDescriptionRole).value<RegisterRefDescription>();
RegisterRefDescription rightRegRef = right.data(
RegisterRefModel::RegisterRefDescriptionRole).value<RegisterRefDescription>();
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(&registerRefs, 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<RegisterRefDescription>();
Core()->seek(item.value);
}

View File

@ -0,0 +1,81 @@
#pragma once
#include <memory>
#include "Cutter.h"
#include "CutterDockWidget.h"
#include <QAbstractListModel>
#include <QSortFilterProxyModel>
class MainWindow;
class QTreeWidget;
namespace Ui {
class RegisterRefsWidget;
}
class MainWindow;
class QTreeWidgetItem;
class RegisterRefModel: public QAbstractListModel
{
Q_OBJECT
private:
QList<RegisterRefDescription> *registerRefs;
public:
enum Column { RegColumn = 0, ValueColumn, RefColumn, ColumnCount };
enum Role { RegisterRefDescriptionRole = Qt::UserRole };
RegisterRefModel(QList<RegisterRefDescription> *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::RegisterRefsWidget> ui;
RegisterRefModel *registerRefModel;
RegisterRefProxyModel *registerRefProxyModel;
QList<RegisterRefDescription> registerRefs;
void setScrollMode();
};

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RegisterRefsWidget</class>
<widget class="QDockWidget" name="RegisterRefsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Register References</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTreeView" name="registerRefTreeView">
<property name="styleSheet">
<string notr="true">QTreeView::item
{
padding-top: 1px;
padding-bottom: 1px;
}</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="indentation">
<number>8</number>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QuickFilterView" name="quickFilterView" native="true"/>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QuickFilterView</class>
<extends>QWidget</extends>
<header>widgets/QuickFilterView.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>