mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-19 10:58:51 +00:00
Added register references widget
This commit is contained in:
parent
dde5d00b98
commit
13c3ff4cf8
@ -746,6 +746,26 @@ QJsonDocument CutterCore::getRegisterValues()
|
||||
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)
|
||||
{
|
||||
return cmd("drn " + registerRole).trimmed();
|
||||
|
@ -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<BreakpointDescription> getBreakpoints();
|
||||
QList<ProcessDescription> getAllProcesses();
|
||||
QList<RegisterRefDescription> getRegisterRefs();
|
||||
|
||||
QList<XrefDescription> getXRefs(RVA addr, bool to, bool whole_function,
|
||||
const QString &filterType = QString::null);
|
||||
|
@ -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 \
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include "widgets/DebugToolbar.h"
|
||||
#include "widgets/MemoryMapWidget.h"
|
||||
#include "widgets/BreakpointWidget.h"
|
||||
#include "widgets/RegisterRefsWidget.h"
|
||||
|
||||
// Graphics
|
||||
#include <QGraphicsEllipseItem>
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -232,6 +232,7 @@ border-top: 0px;
|
||||
<addaction name="actionBacktrace"/>
|
||||
<addaction name="actionMemoryMap"/>
|
||||
<addaction name="actionBreakpoint"/>
|
||||
<addaction name="actionRegisterRefs"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="addInfoWidgets">
|
||||
<property name="title">
|
||||
@ -1061,6 +1062,14 @@ border-top: 0px;
|
||||
<string>Breakpoints</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRegisterRefs">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Register References</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClasses">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
160
src/widgets/RegisterRefsWidget.cpp
Normal file
160
src/widgets/RegisterRefsWidget.cpp
Normal 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 ®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<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(®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<RegisterRefDescription>();
|
||||
Core()->seek(item.value);
|
||||
}
|
81
src/widgets/RegisterRefsWidget.h
Normal file
81
src/widgets/RegisterRefsWidget.h
Normal 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();
|
||||
};
|
69
src/widgets/RegisterRefsWidget.ui
Normal file
69
src/widgets/RegisterRefsWidget.ui
Normal 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>
|
Loading…
Reference in New Issue
Block a user