Segments implemented (#851)

* Segments implemented

* Not util anymore but common

* Fixed the strings to be shown as the headers better

* Quick Filter functionality is supported on both Section and Segment Widget

* QuickFilter should basically be on but for some widgets, they should be off
This commit is contained in:
Vanellope 2018-10-21 03:20:06 +09:00 committed by Itay Cohen
parent d3572b9eb5
commit ac64bbface
12 changed files with 358 additions and 7 deletions

View File

@ -1652,6 +1652,33 @@ QList<SectionDescription> CutterCore::getAllSections()
return ret;
}
QList<SegmentDescription> CutterCore::getAllSegments()
{
CORE_LOCK();
QList<SegmentDescription> ret;
QJsonArray segments = cmdj("iSSj").array();
for (QJsonValue value : segments) {
QJsonObject segmentObject = value.toObject();
QString name = segmentObject["name"].toString();
if (name.isEmpty())
continue;
SegmentDescription segment;
segment.name = name;
segment.vaddr = segmentObject["vaddr"].toVariant().toULongLong();
segment.paddr = segmentObject["paddr"].toVariant().toULongLong();
segment.size = segmentObject["size"].toVariant().toULongLong();
segment.vsize = segmentObject["vsize"].toVariant().toULongLong();
segment.perm = segmentObject["perm"].toString();
ret << segment;
}
return ret;
}
QList<EntrypointDescription> CutterCore::getAllEntrypoint()
{
CORE_LOCK();

View File

@ -189,6 +189,15 @@ struct SectionDescription {
QString entropy;
};
struct SegmentDescription {
RVA vaddr;
RVA paddr;
RVA size;
RVA vsize;
QString name;
QString perm;
};
struct EntrypointDescription {
RVA vaddr;
RVA paddr;
@ -350,6 +359,7 @@ Q_DECLARE_METATYPE(HeaderDescription)
Q_DECLARE_METATYPE(ZignatureDescription)
Q_DECLARE_METATYPE(SearchDescription)
Q_DECLARE_METATYPE(SectionDescription)
Q_DECLARE_METATYPE(SegmentDescription)
Q_DECLARE_METATYPE(MemoryMapDescription)
Q_DECLARE_METATYPE(BreakpointDescription)
Q_DECLARE_METATYPE(ProcessDescription)
@ -569,6 +579,7 @@ public:
QList<FlagspaceDescription> getAllFlagspaces();
QList<FlagDescription> getAllFlags(QString flagspace = NULL);
QList<SectionDescription> getAllSections();
QList<SegmentDescription> getAllSegments();
QList<EntrypointDescription> getAllEntrypoint();
QList<ClassDescription> getAllClassesFromBin();
QList<ClassDescription> getAllClassesFromFlags();

View File

@ -138,6 +138,7 @@ SOURCES += \
widgets/RelocsWidget.cpp \
widgets/SdbDock.cpp \
widgets/SectionsWidget.cpp \
widgets/SegmentsWidget.cpp \
widgets/Sidebar.cpp \
widgets/StringsWidget.cpp \
widgets/SymbolsWidget.cpp \
@ -233,6 +234,7 @@ HEADERS += \
widgets/RelocsWidget.h \
widgets/SdbDock.h \
widgets/SectionsWidget.h \
widgets/SegmentsWidget.h \
widgets/Sidebar.h \
widgets/StringsWidget.h \
widgets/SymbolsWidget.h \

View File

@ -52,6 +52,7 @@
#include "widgets/GraphWidget.h"
#include "widgets/FunctionsWidget.h"
#include "widgets/SectionsWidget.h"
#include "widgets/SegmentsWidget.h"
#include "widgets/CommentsWidget.h"
#include "widgets/ImportsWidget.h"
#include "widgets/ExportsWidget.h"
@ -201,6 +202,7 @@ void MainWindow::initUI()
graphDock = new GraphWidget(this, ui->actionGraph);
sectionsDock = new SectionsWidget(this, ui->actionSections);
segmentsDock = new SegmentsWidget(this, ui->actionSegments);
entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints);
functionsDock = new FunctionsWidget(this, ui->actionFunctions);
importsDock = new ImportsWidget(this, ui->actionImports);
@ -573,9 +575,11 @@ void MainWindow::restoreDocks()
// Console | Sections
splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal);
splitDockWidget(consoleDock, segmentsDock, Qt::Horizontal);
// Tabs for center (must be applied after splitDockWidget())
tabifyDockWidget(sectionsDock, commentsDock);
tabifyDockWidget(segmentsDock, commentsDock);
tabifyDockWidget(dashboardDock, disassemblyDock);
tabifyDockWidget(dashboardDock, graphDock);
tabifyDockWidget(dashboardDock, hexdumpDock);

View File

@ -38,6 +38,7 @@ class QLineEdit;
class SdbDock;
class QAction;
class SectionsWidget;
class SegmentsWidget;
class ConsoleWidget;
class EntrypointWidget;
class DisassemblerGraphView;
@ -215,6 +216,7 @@ private:
QLineEdit *gotoEntry = nullptr;
SdbDock *sdbDock = nullptr;
SectionsWidget *sectionsDock = nullptr;
SegmentsWidget *segmentsDock = nullptr;
ZignaturesWidget *zignaturesDock = nullptr;
ConsoleWidget *consoleDock = nullptr;
ClassesWidget *classesDock = nullptr;

View File

@ -173,6 +173,7 @@ QToolTip {
<addaction name="actionTypes"/>
<addaction name="actionFlags"/>
<addaction name="actionSections"/>
<addaction name="actionSegments"/>
<addaction name="actionHeaders"/>
<addaction name="actionZignatures"/>
<addaction name="actionRelocs"/>
@ -452,6 +453,17 @@ QToolTip {
<string>Show/Hide Sections panel</string>
</property>
</action>
<action name="actionSegments">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Segments</string>
</property>
<property name="toolTip">
<string>Show/Hide Segments panel</string>
</property>
</action>
<action name="actionFunctions">
<property name="checkable">
<bool>true</bool>

View File

@ -2,7 +2,7 @@
#include "QuickFilterView.h"
#include "ui_QuickFilterView.h"
QuickFilterView::QuickFilterView(QWidget *parent) :
QuickFilterView::QuickFilterView(QWidget *parent, bool defaultOn) :
QWidget(parent),
ui(new Ui::QuickFilterView())
{
@ -13,6 +13,10 @@ QuickFilterView::QuickFilterView(QWidget *parent) :
connect(ui->filterLineEdit, &QLineEdit::textChanged, this, [this](const QString & text) {
emit filterTextChanged(text);
});
if (!defaultOn) {
closeFilter();
}
}
QuickFilterView::~QuickFilterView() {}

View File

@ -15,7 +15,7 @@ class QuickFilterView : public QWidget
Q_OBJECT
public:
explicit QuickFilterView(QWidget *parent = nullptr);
explicit QuickFilterView(QWidget *parent = nullptr, bool defaultOn = true);
~QuickFilterView();
public slots:

View File

@ -3,6 +3,7 @@
#include "SectionsWidget.h"
#include "MainWindow.h"
#include "QuickFilterView.h"
#include "common/Helpers.h"
SectionsModel::SectionsModel(QList<SectionDescription> *sections, QObject *parent)
@ -81,7 +82,7 @@ QVariant SectionsModel::headerData(int section, Qt::Orientation, int role) const
case SectionsModel::AddressColumn:
return tr("Address");
case SectionsModel::EndAddressColumn:
return tr("EndAddress");
return tr("End Address");
case SectionsModel::EntropyColumn:
return tr("Entropy");
default:
@ -135,19 +136,41 @@ SectionsWidget::SectionsWidget(MainWindow *main, QAction *action) :
auto proxyModel = new SectionsProxyModel(sectionsModel, this);
sectionsTable->setModel(proxyModel);
sectionsTable->setIndentation(10);
sectionsTable->setSortingEnabled(true);
sectionsTable->sortByColumn(SectionsModel::NameColumn, Qt::AscendingOrder);
connect(sectionsTable, SIGNAL(doubleClicked(const QModelIndex &)),
this, SLOT(onSectionsDoubleClicked(const QModelIndex &)));
setWidget(sectionsTable);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshSections()));
quickFilterView = new QuickFilterView(this, false);
quickFilterView->setObjectName(QStringLiteral("quickFilterView"));
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Maximum);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(quickFilterView->sizePolicy().hasHeightForWidth());
quickFilterView->setSizePolicy(sizePolicy1);
QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this);
connect(search_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::showFilter);
search_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
connect(clear_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::clearFilter);
clear_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
connect(quickFilterView, SIGNAL(filterTextChanged(const QString &)), proxyModel,
SLOT(setFilterWildcard(const QString &)));
connect(quickFilterView, SIGNAL(filterClosed()), sectionsTable, SLOT(setFocus()));
dockWidgetContents = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(sectionsTable);
layout->addWidget(quickFilterView);
layout->setMargin(0);
dockWidgetContents->setLayout(layout);
setWidget(dockWidgetContents);
}
SectionsWidget::~SectionsWidget() {}

View File

@ -13,6 +13,7 @@ class QTreeView;
class QAbstractItemView;
class MainWindow;
class SectionsWidget;
class QuickFilterView;
class SectionsModel : public QAbstractListModel
{
@ -64,6 +65,8 @@ private:
SectionsModel *sectionsModel;
QTreeView *sectionsTable;
MainWindow *main;
QWidget *dockWidgetContents;
QuickFilterView *quickFilterView;
};
#endif // SECTIONSWIDGET_H

View File

@ -0,0 +1,191 @@
#include <QTreeView>
#include "SegmentsWidget.h"
#include "MainWindow.h"
#include "QuickFilterView.h"
#include "common/Helpers.h"
SegmentsModel::SegmentsModel(QList<SegmentDescription> *segments, QObject *parent)
: QAbstractListModel(parent),
segments(segments)
{
}
int SegmentsModel::rowCount(const QModelIndex &) const
{
return segments->count();
}
int SegmentsModel::columnCount(const QModelIndex &) const
{
return SegmentsModel::ColumnCount;
}
QVariant SegmentsModel::data(const QModelIndex &index, int role) const
{
// TODO: create unique colors, e. g. use HSV color space and rotate in H for 360/size
static const QList<QColor> colors = { QColor("#1ABC9C"), //TURQUOISE
QColor("#2ECC71"), //EMERALD
QColor("#3498DB"), //PETER RIVER
QColor("#9B59B6"), //AMETHYST
QColor("#34495E"), //WET ASPHALT
QColor("#F1C40F"), //SUN FLOWER
QColor("#E67E22"), //CARROT
QColor("#E74C3C"), //ALIZARIN
QColor("#ECF0F1"), //CLOUDS
QColor("#BDC3C7"), //SILVER
QColor("#95A5A6") //COBCRETE
};
if (index.row() >= segments->count())
return QVariant();
const SegmentDescription &segment = segments->at(index.row());
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case SegmentsModel::NameColumn:
return segment.name;
case SegmentsModel::SizeColumn:
return segment.size;
case SegmentsModel::AddressColumn:
return RAddressString(segment.vaddr);
case SegmentsModel::EndAddressColumn:
return RAddressString(segment.vaddr + segment.size);
case SegmentsModel::PermColumn:
return segment.perm;
default:
return QVariant();
}
case Qt::DecorationRole:
if (index.column() == 0)
return colors[index.row() % colors.size()];
return QVariant();
case SegmentsModel::SegmentDescriptionRole:
return QVariant::fromValue(segment);
default:
return QVariant();
}
}
QVariant SegmentsModel::headerData(int segment, Qt::Orientation, int role) const
{
switch (role) {
case Qt::DisplayRole:
switch (segment) {
case SegmentsModel::NameColumn:
return tr("Name");
case SegmentsModel::SizeColumn:
return tr("Size");
case SegmentsModel::AddressColumn:
return tr("Address");
case SegmentsModel::EndAddressColumn:
return tr("End Address");
case SegmentsModel::PermColumn:
return tr("Permissions");
default:
return QVariant();
}
default:
return QVariant();
}
}
SegmentsProxyModel::SegmentsProxyModel(SegmentsModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{
setSourceModel(sourceModel);
setFilterCaseSensitivity(Qt::CaseInsensitive);
setSortCaseSensitivity(Qt::CaseInsensitive);
}
bool SegmentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
auto leftSegment = left.data(SegmentsModel::SegmentDescriptionRole).value<SegmentDescription>();
auto rightSegment = right.data(SegmentsModel::SegmentDescriptionRole).value<SegmentDescription>();
switch (left.column()) {
case SegmentsModel::NameColumn:
return leftSegment.name < rightSegment.name;
case SegmentsModel::SizeColumn:
return leftSegment.size < rightSegment.size;
case SegmentsModel::AddressColumn:
case SegmentsModel::EndAddressColumn:
return leftSegment.vaddr < rightSegment.vaddr;
default:
break;
}
return false;
}
SegmentsWidget::SegmentsWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action),
main(main)
{
setObjectName("SegmentsWidget");
setWindowTitle(QStringLiteral("Segments"));
segmentsTable = new QTreeView;
segmentsModel = new SegmentsModel(&segments, this);
auto proxyModel = new SegmentsProxyModel(segmentsModel, this);
segmentsTable->setModel(proxyModel);
segmentsTable->setIndentation(10);
segmentsTable->setSortingEnabled(true);
segmentsTable->sortByColumn(SegmentsModel::NameColumn, Qt::AscendingOrder);
connect(segmentsTable, SIGNAL(doubleClicked(const QModelIndex &)),
this, SLOT(onSegmentsDoubleClicked(const QModelIndex &)));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshSegments()));
quickFilterView = new QuickFilterView(this, false);
quickFilterView->setObjectName(QStringLiteral("quickFilterView"));
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Maximum);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(quickFilterView->sizePolicy().hasHeightForWidth());
quickFilterView->setSizePolicy(sizePolicy1);
QShortcut *search_shortcut = new QShortcut(QKeySequence::Find, this);
connect(search_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::showFilter);
search_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
QShortcut *clear_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
connect(clear_shortcut, &QShortcut::activated, quickFilterView, &QuickFilterView::clearFilter);
clear_shortcut->setContext(Qt::WidgetWithChildrenShortcut);
connect(quickFilterView, SIGNAL(filterTextChanged(const QString &)), proxyModel,
SLOT(setFilterWildcard(const QString &)));
connect(quickFilterView, SIGNAL(filterClosed()), segmentsTable, SLOT(setFocus()));
dockWidgetContents = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(segmentsTable);
layout->addWidget(quickFilterView);
layout->setMargin(0);
dockWidgetContents->setLayout(layout);
setWidget(dockWidgetContents);
}
SegmentsWidget::~SegmentsWidget() {}
void SegmentsWidget::refreshSegments()
{
segmentsModel->beginResetModel();
segments = Core()->getAllSegments();
segmentsModel->endResetModel();
qhelpers::adjustColumns(segmentsTable, SegmentsModel::ColumnCount, 0);
}
void SegmentsWidget::onSegmentsDoubleClicked(const QModelIndex &index)
{
if (!index.isValid())
return;
auto segment = index.data(SegmentsModel::SegmentDescriptionRole).value<SegmentDescription>();
Core()->seek(segment.vaddr);
}

View File

@ -0,0 +1,72 @@
#ifndef SEGMENTSWIDGET_H
#define SEGMENTSWIDGET_H
#include <memory>
#include <QAbstractListModel>
#include <QSortFilterProxyModel>
#include "Cutter.h"
#include "CutterDockWidget.h"
class QTreeView;
class QAbstractItemView;
class MainWindow;
class SegmentsWidget;
class QuickFilterView;
class SegmentsModel : public QAbstractListModel
{
Q_OBJECT
friend SegmentsWidget;
private:
QList<SegmentDescription> *segments;
public:
enum Column { NameColumn = 0, SizeColumn, AddressColumn, EndAddressColumn, PermColumn, ColumnCount };
enum Role { SegmentDescriptionRole = Qt::UserRole };
SegmentsModel(QList<SegmentDescription> *segments, QObject *parent = nullptr);
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 segment, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
};
class SegmentsProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
SegmentsProxyModel(SegmentsModel *sourceModel, QObject *parent = nullptr);
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};
class SegmentsWidget : public CutterDockWidget
{
Q_OBJECT
public:
explicit SegmentsWidget(MainWindow *main, QAction *action = nullptr);
~SegmentsWidget();
private slots:
void refreshSegments();
void onSegmentsDoubleClicked(const QModelIndex &index);
private:
QList<SegmentDescription> segments;
SegmentsModel *segmentsModel;
QTreeView *segmentsTable;
MainWindow *main;
QWidget *dockWidgetContents;
QuickFilterView *quickFilterView;
};
#endif // SEGMENTSWIDGET_H