diff options
| author | Alexander Taylor <alex@vector35.com> | 2025-04-09 12:47:00 -0400 |
|---|---|---|
| committer | Alexander Taylor <alex@vector35.com> | 2025-04-09 17:16:23 -0400 |
| commit | e3772366504d6d05b4809013cb4f4149ca64c4d4 (patch) | |
| tree | e3fcb0818bfede1a5f8fff0b1edd59422b517b67 /view/kernelcache | |
| parent | f78345462ebc25e0241d838f04104e5c6bfae863 (diff) | |
Shared cache and kernel cache UI cleanup.
One day, these will share more code, but today is not quite that day.
Diffstat (limited to 'view/kernelcache')
| -rw-r--r-- | view/kernelcache/ui/kctriage.cpp | 548 | ||||
| -rw-r--r-- | view/kernelcache/ui/kctriage.h | 79 |
2 files changed, 255 insertions, 372 deletions
diff --git a/view/kernelcache/ui/kctriage.cpp b/view/kernelcache/ui/kctriage.cpp index 3fa70065..7b3cf9f0 100644 --- a/view/kernelcache/ui/kctriage.cpp +++ b/view/kernelcache/ui/kctriage.cpp @@ -1,59 +1,65 @@ -// -// Created by kat on 8/15/24. -// - +#include "globalarea.h" #include "kctriage.h" +#include "progresstask.h" #include "ui/fontsettings.h" +#include <QMessageBox> #include <QPainter> -#include <QTextBrowser> -#include "tabwidget.h" -#include "globalarea.h" -#include "progresstask.h" - #include <cmath> -#include <QMessageBox> - -#define QSETTINGS_KEY_SELECTED_TAB "KCTriage-SelectedTab" -#define QSETTINGS_KEY_TAB_LAYOUT "KCTriage-TabLayout" -#define QSETTINGS_KEY_IMAGELOAD_TAB_LAYOUT "KCTriage-ImageLoadTabLayout" -#define QSETTINGS_KEY_ALPHA_POPUP_SEEN "KCTriage-AlphaPopupSeenV2" +using namespace BinaryNinja; +using namespace KernelCacheAPI; SymbolTableModel::SymbolTableModel(SymbolTableView* parent) : QAbstractTableModel(parent), m_parent(parent) { + // TODO: Need to implement updating this font if it is changed by the user + m_font = getMonospaceFont(parent); } + int SymbolTableModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent); return static_cast<int>(m_symbols.size()); } + int SymbolTableModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); // We have 3 columns: Address, Name, and Image return 3; } + QVariant SymbolTableModel::data(const QModelIndex& index, int role) const { - if (!index.isValid() || role != Qt::DisplayRole) { + if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::FontRole)) { return QVariant(); } - const KernelCacheAPI::KCSymbol& symbol = m_symbols.at(index.row()); + const KCSymbol& symbol = m_symbols.at(index.row()); - switch (index.column()) { - case 0: // Address column - return QString("0x%1").arg(symbol.address, 0, 16); // Display address as hexadecimal - case 1: // Name column - return QString::fromStdString(symbol.name); - case 2: // Image column - return QString::fromStdString(symbol.image); + switch (role) + { + case Qt::DisplayRole: + { + switch (index.column()) { + case 0: // Address column + return QString("0x%1").arg(symbol.address, 0, 16); // Display address as hexadecimal + case 1: // Name column + return QString::fromStdString(symbol.name); + case 2: // Image column + return QString::fromStdString(symbol.image); + default: + return QVariant(); + } + } + case Qt::FontRole: + return m_font; default: return QVariant(); } } + QVariant SymbolTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole || orientation != Qt::Horizontal) { return QVariant(); @@ -71,12 +77,14 @@ QVariant SymbolTableModel::headerData(int section, Qt::Orientation orientation, } } + void SymbolTableModel::updateSymbols() { m_symbols = m_parent->m_symbols; setFilter(m_filter); } -const KernelCacheAPI::KCSymbol& SymbolTableModel::symbolAt(int row) const { + +const KCSymbol& SymbolTableModel::symbolAt(int row) const { return m_symbols.at(row); } @@ -88,39 +96,38 @@ void SymbolTableModel::setFilter(std::string text) m_filter = text; m_symbols.clear(); - if (m_filter.empty()) - { - m_symbols = m_parent->m_symbols; - } - else + if (!m_filter.empty()) { m_symbols.reserve(m_parent->m_symbols.size()); for (const auto& symbol : m_parent->m_symbols) - { if (symbol.name.find(m_filter) != std::string::npos) - { m_symbols.push_back(symbol); - } - } m_symbols.shrink_to_fit(); } + else + { + m_symbols = m_parent->m_symbols; + } endResetModel(); } -SymbolTableView::SymbolTableView(QWidget* parent, Ref<KernelCacheAPI::KernelCache> cache) - : m_model(new SymbolTableModel(this)) { +SymbolTableView::SymbolTableView(QWidget* parent, Ref<KernelCache> cache) + : QTableView(parent), m_model(new SymbolTableModel(this)) { // Set up the filter model setModel(m_model); // Configure view settings horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + setEditTriggers(QAbstractItemView::NoEditTriggers); setSelectionBehavior(QAbstractItemView::SelectRows); setSelectionMode(QAbstractItemView::SingleSelection); - BackgroundThread::create(this)->thenBackground([this, cache=cache](){ + setSortingEnabled(true); + + BackgroundThread::create(this)->thenBackground([this, cache](){ // LogInfo("Symbol Search: Loading symbols..."); m_symbols = cache->LoadAllSymbolsAndWait(); // LogInfo("Symbol Search: Loaded 0x%zx symbols", m_symbols.size()); @@ -129,386 +136,267 @@ SymbolTableView::SymbolTableView(QWidget* parent, Ref<KernelCacheAPI::KernelCach })->start(); } + SymbolTableView::~SymbolTableView() { delete m_model; } + void SymbolTableView::setFilter(const std::string& filter) { m_model->setFilter(filter); } -KCTriageView::KCTriageView(QWidget* parent, BinaryViewRef data) : QWidget(parent), View(), m_data(data), m_cache(new KernelCacheAPI::KernelCache(data)) -{ - setBinaryDataNavigable(true); - setupView(this); - - m_triageCollection = new DockableTabCollection(); - m_triageTabs = new SplitTabWidget(m_triageCollection); - - auto triageTabStyle = new GlobalAreaTabStyle(); - m_triageTabs->setTabStyle(triageTabStyle); - - QSplitter* containerWidget = new QSplitter; - containerWidget->setOrientation(Qt::Vertical); - - QWidget* defaultWidget = nullptr; - - m_bottomRegionCollection = new DockableTabCollection(); - m_bottomRegionTabs = new SplitTabWidget(m_bottomRegionCollection); - m_bottomRegionTabs->setTabStyle(new GlobalAreaTabStyle()); +KCTriageViewType::KCTriageViewType() + : ViewType("KCTriage", "Kernel Cache Triage") +{} - auto loadImageTable = new FilterableTableView; - { - auto loadImageModel = new QStandardItemModel(0, 2, loadImageTable); - { - loadImageModel->setHorizontalHeaderLabels({"Name", "VM Address"}); - BackgroundThread::create(loadImageTable)->thenBackground([this](QVariant var) - { - QVariantList rows; - auto images = m_cache->GetImages(); +int KCTriageViewType::getPriority(BinaryViewRef data, const QString& filename) +{ + if (data->GetTypeName() == KC_VIEW_NAME) + return 100; + return 0; +} - auto newHeaders = std::make_shared<std::vector<KernelCacheAPI::KernelCacheMachOHeader>>(); - newHeaders->reserve(images.size()); - for (const auto& img : images) - { - if (auto header = m_cache->GetMachOHeaderForImage(img.name); header) - { - newHeaders->push_back(*header); - rows.push_back(QList<QVariant>{ - QString::fromStdString(img.name), - QString("0x%1").arg(header->textBase, 0, 16) - }); - } - } +QWidget* KCTriageViewType::create(BinaryViewRef data, ViewFrame* viewFrame) +{ + if (data->GetTypeName() != KC_VIEW_NAME) + return nullptr; + return new KCTriageView(viewFrame, data); +} - { - std::unique_lock<std::mutex> lock(m_headersMutex); - m_headers.swap(newHeaders); - } - return QVariant(rows); - })->thenMainThread([loadImageModel, loadImageTable](QVariant var){ - QVariantList rows = var.toList(); +void KCTriageViewType::Register() +{ + registerViewType(new KCTriageViewType()); +} - if (loadImageModel->rowCount() > 0) - { - loadImageModel->removeRows(0, loadImageModel->rowCount()); - } - for (const QVariant &rowVariant : rows) { - QVariantList row = rowVariant.toList(); +KCTriageView::KCTriageView(QWidget* parent, BinaryViewRef data) : QWidget(parent), View(), m_data(data), m_cache(new KernelCache(data)) +{ + setBinaryDataNavigable(true); + setupView(this); - QList<QStandardItem*> items; - for (const QVariant &cellValue : row) { - items.append(new QStandardItem(cellValue.toString())); - } + UIContext::registerNotification(this); - loadImageModel->appendRow(items); - loadImageTable->resizeColumnsToContents(); - } - })->start(); - } // loadImageModel + m_triageCollection = new DockableTabCollection(); + m_triageTabs = new SplitTabWidget(m_triageCollection); - auto loadImageButton = new CustomStyleFlatPushButton(); - { - connect(loadImageButton, &QPushButton::clicked, - [this, loadImageTable](bool) { - auto selected = loadImageTable->selectionModel()->selectedRows(); - if (selected.size() == 0) - { - return; - } + auto triageTabStyle = new GlobalAreaTabStyle(); + m_triageTabs->setTabStyle(triageTabStyle); - for (const auto& selection : selected) - { - auto name = selection.data().toString().toStdString(); - WorkerPriorityEnqueue([this, name]() { m_cache->LoadImageWithInstallName(name); }); - } - }); - loadImageButton->setText("Load"); + QWidget* defaultWidget = initImageTable(); + initSymbolTable(); - loadImageButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - loadImageButton->setMinimumWidth(100); - loadImageButton->setMinimumHeight(30); + m_layout = new QVBoxLayout(this); + m_layout->addWidget(m_triageTabs); + setLayout(m_layout); - } // loadImageButton - loadImageTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + // XXX: RefreshData - auto loadImageFilterEdit = new FilterEdit(loadImageTable); - { - connect(loadImageFilterEdit, &FilterEdit::textChanged, [loadImageTable](const QString& filter) { - loadImageTable->setFilter(filter.toStdString()); - }); - } // loadImageFilterEdit + m_triageTabs->selectWidget(defaultWidget); +} - connect(loadImageTable, &FilterableTableView::activated, this, [=](const QModelIndex& index) - { - auto selected = loadImageTable->selectionModel()->selectedRows(); - if (selected.size() == 0) - { - return; - } - for (const auto& selection : selected) - { - auto name = selection.data().toString().toStdString(); - WorkerPriorityEnqueue([this, name]() { m_cache->LoadImageWithInstallName(name); }); - } - }); +KCTriageView::~KCTriageView() +{ + UIContext::unregisterNotification(this); +} - auto loadImageLayout = new QVBoxLayout; - loadImageLayout->addWidget(loadImageFilterEdit); - loadImageLayout->addWidget(loadImageTable); - loadImageLayout->addWidget(loadImageButton); - auto loadImageWidget = new QWidget; - loadImageWidget->setLayout(loadImageLayout); +QWidget* KCTriageView::initImageTable() +{ + m_imageTable = new FilterableTableView(this); - m_bottomRegionTabs->addTab(loadImageWidget, "Load an Image"); + m_imageModel = new QStandardItemModel(0, 2, m_imageTable); + m_imageModel->setHorizontalHeaderLabels({"VM Address", "Name"}); - loadImageTable->setModel(loadImageModel); + // Apply custom column styling + m_imageTable->setItemDelegateForColumn(0, new AddressColorDelegate(m_imageTable)); - loadImageTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - loadImageTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + BackgroundThread::create(m_imageTable)->thenBackground([this](const QVariant var) { + QVariantList rows; - loadImageTable->setSelectionBehavior(QAbstractItemView::SelectRows); + auto images = m_cache->GetImages(); - m_triageTabs->addTab(loadImageWidget, "Images"); - defaultWidget = loadImageWidget; - m_triageTabs->setCanCloseTab(loadImageWidget, false); - } // loadImageTable + auto newHeaders = std::make_shared<std::vector<KernelCacheMachOHeader>>(); + newHeaders->reserve(images.size()); - auto symbolSearch = new SymbolTableView(this, m_cache); - { - auto symbolFilterEdit = new FilterEdit(symbolSearch); + for (const auto& img : images) { - connect(symbolFilterEdit, &FilterEdit::textChanged, [symbolSearch](const QString& filter) { - symbolSearch->setFilter(filter.toStdString()); - }); - } - - auto symbolLayout = new QVBoxLayout; - symbolLayout->addWidget(symbolFilterEdit); - symbolLayout->addWidget(symbolSearch); - - auto symbolWidget = new QWidget; - symbolWidget->setLayout(symbolLayout); - - symbolSearch->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); // Address - symbolSearch->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); // Name - symbolSearch->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); // Image - - symbolSearch->setSelectionBehavior(QAbstractItemView::SelectRows); - symbolSearch->setSelectionMode(QAbstractItemView::SingleSelection); - - std::function<void(uint64_t)> navigateToAddress = [=](uint64_t addr){ - ExecuteOnMainThread([addr, this](){ - if (BinaryNinja::Settings::Instance()->Get<bool>("ui.view.graph.preferred")) - m_data->Navigate("Graph:KCView", addr); - else - m_data->Navigate("Linear:KCView", addr); - }); - }; - - connect(symbolSearch, &SymbolTableView::activated, this, [=](const QModelIndex& index) + if (auto header = m_cache->GetMachOHeaderForImage(img.name); header) { - auto symbol = symbolSearch->getSymbolAtRow(index.row()); - WorkerPriorityEnqueue([this, symbol, navigateToAddress]() - { - if (m_data->IsValidOffset(symbol.address)) - navigateToAddress(symbol.address); - else - { - m_cache->LoadImageWithInstallName(symbol.image); - navigateToAddress(symbol.address); - } - }); - }); - - m_triageTabs->addTab(symbolWidget, "Symbol Search"); - m_triageTabs->setCanCloseTab(symbolWidget, false); - } // symbolSearch - - { // Doc tabs - - QTextBrowser *mainDocBrowser = new QTextBrowser(this); - { - mainDocBrowser->setOpenExternalLinks(true); - auto alphaHtml = - R"( -<h1>KernelCache Parser</h1> - -<p> This parser has support for MH_FILESET (>= macOS 11, >= iOS 14) kernels. </p> - -<h2> Getting the latest version of the plugin </h2> -<p> We frequently release "dev" builds which will contain the latest version of the KernelCache plugin (and many other things). </p> -<p> You can find instructions on how to install these builds <a href="https://docs.binary.ninja/guide/index.html#development-branch">here</a>. </p> - -<h3> Reading / building the source </h3> -<p> Like most of our platforms, architectures, debug information parsing, and the entire API and documentation, this plugin is open source. </p> -<p> You can read the source and find instructions for building it <a href="https://github.com/Vector35/binaryninja-api/tree/dev/view/kernelcache">here</a>. </p> -<p> Contributions are always welcome! </p> -)"; - mainDocBrowser->setHtml(alphaHtml); - - m_triageTabs->addTab(mainDocBrowser, "KernelCache Parser"); - m_triageTabs->setCanCloseTab(mainDocBrowser, false); - + newHeaders->push_back(*header); + rows.push_back(QList<QVariant>{ + QString("0x%1").arg(header->textBase, 0, 16), + QString::fromStdString(img.name) + }); + } } - } - containerWidget->addWidget(m_bottomRegionTabs); + std::unique_lock<std::mutex> lock(m_headersMutex); + m_headers.swap(newHeaders); - m_layout = new QVBoxLayout(this); - m_layout->addWidget(m_triageTabs); - setLayout(m_layout); + return QVariant(rows); + })->thenMainThread([this](const QVariant var) { + QVariantList rows = var.toList(); - m_triageTabs->selectWidget(defaultWidget); -} + if (m_imageModel->rowCount() > 0) + m_imageModel->removeRows(0, m_imageModel->rowCount()); + for (const QVariant &rowVariant : rows) { + QVariantList row = rowVariant.toList(); -QFont KCTriageView::getFont() -{ - return getMonospaceFont(this); -} + QList<QStandardItem*> items; + for (const QVariant &cellValue : row) + items.append(new QStandardItem(cellValue.toString())); + m_imageModel->appendRow(items); + m_imageTable->resizeColumnsToContents(); + } + })->start(); -BinaryViewRef KCTriageView::getData() -{ - return m_data; -} + auto loadImageButton = new QPushButton(); + connect(loadImageButton, &QPushButton::clicked, [this](bool) { + // Collect only visible selected rows + QModelIndexList visibleSelectedRows; + for (const auto& index : m_imageTable->selectionModel()->selectedRows()) { + if (!m_imageTable->isRowHidden(index.row())) { + visibleSelectedRows.append(index); + } + } + if (visibleSelectedRows.empty()) + return; -bool KCTriageView::navigate(uint64_t offset) -{ - return false; -} + for (const auto& selection : visibleSelectedRows) { + auto name = selection.data().toString().toStdString(); + WorkerPriorityEnqueue([this, name]() { m_cache->LoadImageWithInstallName(name); }); + } + }); + loadImageButton->setText("Load Selected"); + auto loadImageFilterEdit = new FilterEdit(m_imageTable); + connect(loadImageFilterEdit, &FilterEdit::textChanged, [this](const QString& filter) { + m_imageTable->setFilter(filter.toStdString()); + }); -uint64_t KCTriageView::getCurrentOffset() -{ - return 0; -} + connect(m_imageTable, &FilterableTableView::activated, this, [=](const QModelIndex& index) { + auto selected = m_imageModel->item(index.row(), 0); + auto name = selected->text().toStdString(); + WorkerPriorityEnqueue([this, name]() { m_cache->LoadImageWithInstallName(name); }); + }); + auto loadImageLayout = new QVBoxLayout; + loadImageLayout->addWidget(loadImageFilterEdit); + loadImageLayout->addWidget(m_imageTable); + loadImageLayout->addWidget(loadImageButton); -CollapsibleSection::CollapsibleSection(QWidget* parent) - : QWidget(parent) -{ - auto layout = new QVBoxLayout(this); - { - layout->setContentsMargins(0, 0, 0, 0); + auto buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(loadImageButton); + buttonLayout->setAlignment(Qt::AlignLeft); + loadImageLayout->addLayout(buttonLayout); - auto hLayout = new QHBoxLayout; - { - hLayout->setContentsMargins(0, 0, 0, 0); + auto loadImageWidget = new QWidget; + loadImageWidget->setLayout(loadImageLayout); - m_titleLabel = new QLabel; - m_titleLabel->setStyleSheet("font-weight: bold; font-size: 16px;"); - hLayout->addWidget(m_titleLabel, 1); + m_imageTable->setModel(m_imageModel); - m_subtitleRightLabel = new QLabel; - m_subtitleRightLabel->setStyleSheet("font-size: 12px;"); - hLayout->addWidget(m_subtitleRightLabel); + m_imageTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - m_collapseButton = new CustomStyleFlatPushButton; - m_collapseButton->setFlat(true); - m_collapseButton->setCheckable(true); - } + m_imageTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); + m_imageTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); - layout->addLayout(hLayout); - } + m_imageTable->setSelectionBehavior(QAbstractItemView::SelectRows); + m_imageTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_contentWidgetContainer = new QWidget; - { - layout->addWidget(m_contentWidgetContainer); - new QVBoxLayout(m_contentWidgetContainer); - } + m_imageTable->setSortingEnabled(true); -} + m_imageTable->verticalHeader()->setVisible(false); + m_triageTabs->addTab(loadImageWidget, "Images"); + m_triageTabs->setCanCloseTab(loadImageWidget, false); -void CollapsibleSection::setTitle(const QString& title) -{ - m_titleLabel->setText(title); + return loadImageWidget; // For use as the default widget } -void CollapsibleSection::setSubtitleRight(const QString& subtitle) +void KCTriageView::initSymbolTable() { - m_subtitleRightLabel->setVisible(subtitle != ""); - m_subtitleRightLabel->setText(subtitle); -} + m_symbolTable = new SymbolTableView(this, m_cache); + auto symbolFilterEdit = new FilterEdit(m_symbolTable); + connect(symbolFilterEdit, &FilterEdit::textChanged, [this](const QString& filter) { + m_symbolTable->setFilter(filter.toStdString()); + }); -void CollapsibleSection::setContentWidget(QWidget* contentWidget) -{ - m_contentWidget = contentWidget; - m_contentWidgetContainer->layout()->addWidget(contentWidget); -} + // Apply custom column styling + m_symbolTable->setItemDelegateForColumn(0, new AddressColorDelegate(m_symbolTable)); + auto symbolLayout = new QVBoxLayout; + symbolLayout->addWidget(symbolFilterEdit); + symbolLayout->addWidget(m_symbolTable); -QSize CollapsibleSection::sizeHint() const -{ - return QWidget::sizeHint(); -} + auto symbolWidget = new QWidget; + symbolWidget->setLayout(symbolLayout); + m_symbolTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); // Address + m_symbolTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); // Name + m_symbolTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); // Image -void CollapsibleSection::setCollapsed(bool collapsed, bool animated) -{ - if (collapsed == m_collapsed) - { - return; - } + m_symbolTable->setSelectionBehavior(QAbstractItemView::SelectRows); + m_symbolTable->setSelectionMode(QAbstractItemView::SingleSelection); - m_collapsed = collapsed; + std::function<void(uint64_t)> navigateToAddress = [=](uint64_t addr) { + ExecuteOnMainThread([addr, this](){ + if (Settings::Instance()->Get<bool>("ui.view.graph.preferred")) + m_data->Navigate("Graph:KCView", addr); + else + m_data->Navigate("Linear:KCView", addr); + }); + }; - if (m_collapsed) - { - m_contentWidget->hide(); - } - else + connect(m_symbolTable, &SymbolTableView::activated, this, [=](const QModelIndex& index) { - m_contentWidget->show(); - } + auto symbol = m_symbolTable->getSymbolAtRow(index.row()); + WorkerPriorityEnqueue([this, symbol, navigateToAddress]() { + if (m_data->IsValidOffset(symbol.address)) + navigateToAddress(symbol.address); + else + { + m_cache->LoadImageWithInstallName(symbol.image); + navigateToAddress(symbol.address); + } + }); + }); - if (animated) - { - m_onContentAddedAnimation->start(); - } + m_triageTabs->addTab(symbolWidget, "Symbols"); + m_triageTabs->setCanCloseTab(symbolWidget, false); } -KCTriageViewType::KCTriageViewType() - : ViewType("KCTriage", "Kernel Cache Triage") +QFont KCTriageView::getFont() { - + return getMonospaceFont(this); } -int KCTriageViewType::getPriority(BinaryViewRef data, const QString& filename) +BinaryViewRef KCTriageView::getData() { - if (data->GetTypeName() == KC_VIEW_NAME) - { - return 100; - } - return 0; + return m_data; } -QWidget* KCTriageViewType::create(BinaryViewRef data, ViewFrame* viewFrame) +bool KCTriageView::navigate(uint64_t offset) { - if (data->GetTypeName() != KC_VIEW_NAME) - { - return nullptr; - } - return new KCTriageView(viewFrame, data); + // TODO: We have to set this to true otherwise view restore does not pickup this view. + return true; } -void KCTriageViewType::Register() +uint64_t KCTriageView::getCurrentOffset() { - ViewType::registerViewType(new KCTriageViewType()); + return 0; } diff --git a/view/kernelcache/ui/kctriage.h b/view/kernelcache/ui/kctriage.h index a6b7f7ac..07c24fad 100644 --- a/view/kernelcache/ui/kctriage.h +++ b/view/kernelcache/ui/kctriage.h @@ -1,7 +1,3 @@ -// -// Created by kat on 8/15/24. -// - #include <kernelcacheapi.h> #include <binaryninjaapi.h> #include "uitypes.h" @@ -14,37 +10,29 @@ #include <QSortFilterProxyModel> #include <QHeaderView> #include "filter.h" +#include <QStyledItemDelegate> + +#include "ui/fontsettings.h" #ifndef BINARYNINJA_KCTRIAGE_H #define BINARYNINJA_KCTRIAGE_H -class CollapsibleSection : public QWidget +class AddressColorDelegate : public QStyledItemDelegate { - Q_OBJECT - - QLabel* m_titleLabel; - QLabel* m_subtitleRightLabel; - QPushButton* m_collapseButton; - - bool m_collapsed = true; - - Animation* m_onContentAddedAnimation; - - QWidget* m_contentWidgetContainer; - QWidget* m_contentWidget; - -protected: - QSize sizeHint() const override; public: - CollapsibleSection(QWidget* parent); - void setTitle(const QString& title); - void setSubtitleRight(const QString& subtitle); + explicit AddressColorDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {} - void setContentWidget(QWidget* contentWidget); + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override + { + QStyleOptionViewItem opt = option; + initStyleOption(&opt, index); - void setCollapsed(bool collapsed, bool animated = true); - bool isCollapsed() const { return m_collapsed; } + opt.palette.setColor(QPalette::Text, getThemeColor(BNThemeColor::AddressColor)); + opt.displayAlignment = Qt::AlignCenter | Qt::AlignVCenter; + + QStyledItemDelegate::paint(painter, opt, index); + } }; @@ -54,12 +42,13 @@ class FilterableTableView : public QTableView, public FilterTarget { bool m_filterByHiding; public: - FilterableTableView(QWidget* parent = nullptr, bool filterByHiding = true) + explicit FilterableTableView(QWidget* parent = nullptr, bool filterByHiding = true) : QTableView(parent), m_filterByHiding(filterByHiding) { viewport()->installEventFilter(this); + setFont(getMonospaceFont(parent)); } - ~FilterableTableView() override {} + ~FilterableTableView() override = default; void setFilter(const std::string& filter) override { if (!m_filterByHiding) @@ -112,7 +101,7 @@ public: bool eventFilter(QObject* obj, QEvent* event) override { if (event->type() == QEvent::KeyPress) { - QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); + auto keyEvent = dynamic_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Escape) { clearSelection(); return true; @@ -135,19 +124,18 @@ class SymbolTableModel : public QAbstractTableModel { Q_OBJECT SymbolTableView* m_parent; + QFont m_font; std::string m_filter; std::vector<KernelCacheAPI::KCSymbol> m_symbols; public: explicit SymbolTableModel(SymbolTableView* parent); - int rowCount(const QModelIndex& parent = QModelIndex()) const override; - int columnCount(const QModelIndex& parent = QModelIndex()) const override; - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - + int rowCount(const QModelIndex& parent) const override; + int columnCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; void updateSymbols(); - void setFilter(std::string text); const KernelCacheAPI::KCSymbol& symbolAt(int row) const; @@ -165,7 +153,7 @@ class SymbolTableView : public QTableView, public FilterTarget public: SymbolTableView(QWidget* parent, Ref<KernelCacheAPI::KernelCache> cache); - virtual ~SymbolTableView() override; + ~SymbolTableView() override; void scrollToFirstItem() override { if (model()->rowCount() > 0) { @@ -204,29 +192,36 @@ public: }; -class KCTriageView : public QWidget, public View +class KCTriageView : public QWidget, public View, public UIContextNotification { BinaryViewRef m_data; QVBoxLayout* m_layout; - Ref<KernelCacheAPI::KernelCache> m_cache; - std::mutex m_headersMutex; - std::shared_ptr<std::vector<KernelCacheAPI::KernelCacheMachOHeader>> m_headers; + Ref<KernelCacheAPI::KernelCache> m_cache; SplitTabWidget* m_triageTabs; DockableTabCollection* m_triageCollection; - SplitTabWidget* m_bottomRegionTabs; - DockableTabCollection* m_bottomRegionCollection; + FilterableTableView* m_imageTable; + QStandardItemModel* m_imageModel; + SymbolTableView* m_symbolTable; + + std::mutex m_headersMutex; + std::shared_ptr<std::vector<KernelCacheAPI::KernelCacheMachOHeader>> m_headers; public: KCTriageView(QWidget* parent, BinaryViewRef data); + ~KCTriageView() override; BinaryViewRef getData() override; void setSelectionOffsets(BNAddressRange range) override {}; QFont getFont() override; bool navigate(uint64_t offset) override; uint64_t getCurrentOffset() override; + +private: + QWidget* initImageTable(); + void initSymbolTable(); }; |
