diff options
| author | kat <kat@vector35.com> | 2025-07-06 15:05:01 -0400 |
|---|---|---|
| committer | kat <kat@vector35.com> | 2025-07-07 07:37:23 -0400 |
| commit | 768f7c78465fb93936e5ca50a0ca712664fe54e7 (patch) | |
| tree | 78c73e0022d6006882e365a257595a5b55a37432 /view/kernelcache/ui/symboltable.cpp | |
| parent | 8f3e251c42169fb4fe8db9403d900571434d88ff (diff) | |
KernelCache rewrite
Diffstat (limited to 'view/kernelcache/ui/symboltable.cpp')
| -rw-r--r-- | view/kernelcache/ui/symboltable.cpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/view/kernelcache/ui/symboltable.cpp b/view/kernelcache/ui/symboltable.cpp new file mode 100644 index 00000000..5c86b3b4 --- /dev/null +++ b/view/kernelcache/ui/symboltable.cpp @@ -0,0 +1,216 @@ +#include <progresstask.h> +#include "symboltable.h" + +#include <QHeaderView> + +#include "ui/fontsettings.h" + +#include "binaryninjaapi.h" + +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_modelSymbols.size()); +} + + +int SymbolTableModel::columnCount(const QModelIndex& parent) const { + Q_UNUSED(parent); + // We have 3 columns: Address, Type, Name + return 3; +} + + +QVariant SymbolTableModel::data(const QModelIndex& index, int role) const { + if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::FontRole)) { + return QVariant(); + } + + switch (role) + { + case Qt::DisplayRole: + { + auto symbol = symbolAt(index.row()); + auto symbolType = GetSymbolTypeAsString(symbol.type); + + switch (index.column()) + { + case 0: // Address column + return QString("0x%1").arg(symbol.address, 0, 16); // Display address as hexadecimal + case 1: // Type column + return QString::fromUtf8(symbolType.c_str(), symbolType.size()); + case 2: // Name column + return QString::fromUtf8(symbol.name.c_str(), symbol.name.size()); + 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(); + } + + switch (section) { + case 0: + return QString("Address"); + case 1: + return QString("Type"); + case 2: + return QString("Name"); + default: + return QVariant(); + } +} + + +void SymbolTableModel::sort(int column, Qt::SortOrder order) +{ + beginResetModel(); + + std::function<bool(const CacheSymbol&, const CacheSymbol&)> comparator; + + switch (column) + { + case 0: // Address column + comparator = [](const CacheSymbol& a, const CacheSymbol& b) { + return a.address < b.address; + }; + break; + case 1: // Type column + comparator = [](const CacheSymbol& a, const CacheSymbol& b) { + return GetSymbolTypeAsString(a.type) < GetSymbolTypeAsString(b.type); + }; + break; + case 2: // Name column + comparator = [](const CacheSymbol& a, const CacheSymbol& b) { + return a.name < b.name; + }; + break; + default: + endResetModel(); + return; + } + + if (order == Qt::DescendingOrder) + { + std::sort(m_modelSymbols.begin(), m_modelSymbols.end(), + [&comparator](const CacheSymbol& a, const CacheSymbol& b) { + return comparator(b, a); + }); + } + else + { + std::sort(m_modelSymbols.begin(), m_modelSymbols.end(), comparator); + } + + endResetModel(); +} + + +void SymbolTableModel::updateSymbols(std::vector<CacheSymbol>&& symbols) +{ + m_preparedSymbols = symbols; + setFilter(m_filter); +} + + +const CacheSymbol& SymbolTableModel::symbolAt(int row) const +{ + return m_modelSymbols.at(row); +} + + +void SymbolTableModel::setFilter(std::string text) +{ + beginResetModel(); + + m_filter = text; + m_modelSymbols = {}; + + // Skip filtering if no filter applied. + if (!m_filter.empty()) + { + m_modelSymbols.reserve(m_preparedSymbols.size()); + for (const auto& symbol : m_preparedSymbols) + if (((std::string_view)symbol.name).find(m_filter) != std::string::npos) + m_modelSymbols.push_back(symbol); + m_modelSymbols.shrink_to_fit(); + } + else + { + m_modelSymbols = m_preparedSymbols; + } + + endResetModel(); +} + + +SymbolTableView::SymbolTableView(QWidget* parent) + : QTableView(parent), m_model(new SymbolTableModel(this)) { + + // Set up the filter model + setModel(m_model); + + // Configure view settings + horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); + horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed); + horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); + setEditTriggers(QAbstractItemView::NoEditTriggers); + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::SingleSelection); + verticalHeader()->setVisible(false); + + setSortingEnabled(true); +} + +SymbolTableView::~SymbolTableView() { + delete m_model; +} + +void SymbolTableView::populateSymbols(BinaryView &view) +{ + if (auto controller = KernelCacheController::GetController(view)) { + typedef std::vector<CacheSymbol> SymbolList; + // Retrieve the symbols from the controller in a future than pass that to the model. + QPointer<QFutureWatcher<SymbolList>> watcher = new QFutureWatcher<SymbolList>(this); + connect(watcher, &QFutureWatcher<SymbolList>::finished, this, [watcher, this]() { + if (watcher) + { + auto symbols = watcher->result(); + m_model->updateSymbols(std::move(symbols)); + } + }); + QFuture<SymbolList> future = QtConcurrent::run([controller]() { + return controller->GetSymbols(); + }); + watcher->setFuture(future); + connect(this, &QObject::destroyed, this, [watcher]() { + if (watcher && watcher->isRunning()) { + watcher->cancel(); + watcher->waitForFinished(); + } + }); + } +} + +void SymbolTableView::setFilter(const std::string& filter) { + m_model->setFilter(filter); +} |
