Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 53 additions & 15 deletions examples/triage/exports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,10 @@ GenericExportsModel::GenericExportsModel(QWidget* parent, BinaryViewRef data): Q
}

m_updateTimer = new QTimer(this);
m_updateTimer->setSingleShot(true);
m_updateTimer->setInterval(500);
connect(m_updateTimer, &QTimer::timeout, this, &GenericExportsModel::updateModel);
connect(this, &GenericExportsModel::modelUpdate, this, [=, this]() {
if (m_updateTimer->isActive())
return;
m_updateTimer->start();
connect(this, &GenericExportsModel::updateTimerOnUIThread, this, [=, this]() {
updateTimer(m_needsUpdate);
});

m_data->RegisterNotification(this);
Expand All @@ -49,6 +46,10 @@ GenericExportsModel::~GenericExportsModel()

void GenericExportsModel::updateModel()
{
if (!m_needsUpdate)
return;

setNeedsUpdate(false);
beginResetModel();
m_allEntries.clear();
for (auto& sym : m_data->GetSymbolsOfType(FunctionSymbol))
Expand Down Expand Up @@ -237,40 +238,64 @@ void GenericExportsModel::setFilter(const std::string& filterText)
endResetModel();
}


void GenericExportsModel::OnAnalysisFunctionAdded(BinaryNinja::BinaryView* view, BinaryNinja::Function* func)
void GenericExportsModel::setNeedsUpdate(bool needed)
{
emit modelUpdate();
if (m_needsUpdate.exchange(needed) == needed)
return;

updateTimer(needed);
}

void GenericExportsModel::updateTimer(bool needsUpdate)
{
if (needsUpdate && !m_updateTimer->isActive())
m_updateTimer->start();
if (!needsUpdate && m_updateTimer->isActive())
m_updateTimer->stop();
}

void GenericExportsModel::OnAnalysisFunctionRemoved(BinaryNinja::BinaryView* view, BinaryNinja::Function* func)
void GenericExportsModel::pauseUpdates()
{
emit modelUpdate();
m_updatesPaused = true;
setNeedsUpdate(false);
}

void GenericExportsModel::resumeUpdates()
{
m_updatesPaused = false;
setNeedsUpdate(true);
}

void GenericExportsModel::OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* view, BinaryNinja::Function* func)
void GenericExportsModel::onBinaryViewNotification()
{
emit modelUpdate();
if (m_updatesPaused)
return;

// This can be called from any thread so we cannot directly
// update the timer. Emitting a signal is relatively expensive
// given how frequently we receive notifications, so we only
// emit a signal if we didn't already need an update.
if (!m_needsUpdate.exchange(true))
emit updateTimerOnUIThread();
}


void GenericExportsModel::OnSymbolAdded(BinaryNinja::BinaryView* view, BinaryNinja::Symbol* sym)
{
emit modelUpdate();
if ((sym->GetBinding() == GlobalBinding) || (sym->GetBinding() == WeakBinding))
onBinaryViewNotification();
}


void GenericExportsModel::OnSymbolUpdated(BinaryNinja::BinaryView* view, BinaryNinja::Symbol* sym)
{
emit modelUpdate();
onBinaryViewNotification();
}


void GenericExportsModel::OnSymbolRemoved(BinaryNinja::BinaryView* view, BinaryNinja::Symbol* sym)
{
emit modelUpdate();
onBinaryViewNotification();
}


Expand Down Expand Up @@ -403,6 +428,19 @@ void ExportsTreeView::keyPressEvent(QKeyEvent* event)
QTreeView::keyPressEvent(event);
}

void ExportsTreeView::showEvent(QShowEvent* event)
{
QTreeView::showEvent(event);
m_model->resumeUpdates();
}


void ExportsTreeView::hideEvent(QHideEvent* event)
{
QTreeView::hideEvent(event);
m_model->pauseUpdates();
}


ExportsWidget::ExportsWidget(QWidget* parent, TriageView* view, BinaryViewRef data) : QWidget(parent)
{
Expand Down
23 changes: 17 additions & 6 deletions examples/triage/exports.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,25 @@ class GenericExportsModel : public QAbstractItemModel, public BinaryNinja::Binar
BinaryViewRef m_data;
std::vector<SymbolRef> m_allEntries, m_entries;
std::string m_filter;
QTimer* m_updateTimer;
Qt::SortOrder m_sortOrder;
int m_sortCol;
bool m_hasOrdinals;
QTimer* m_updateTimer;

// Read from arbitrary threads while processing notifications.
std::atomic<bool> m_updatesPaused = false;
// Read/written from arbitrary threads while processing notifications.
std::atomic<bool> m_needsUpdate = true;

void performSort(int col, Qt::SortOrder order);
void updateModel();

signals:
void modelUpdate();
void updateTimer(bool);
void setNeedsUpdate(bool);
void onBinaryViewNotification();

signals:
void updateTimerOnUIThread();

public:
GenericExportsModel(QWidget* parent, BinaryViewRef data);
Expand All @@ -37,11 +46,11 @@ class GenericExportsModel : public QAbstractItemModel, public BinaryNinja::Binar
virtual void sort(int col, Qt::SortOrder order) override;
void setFilter(const std::string& filterText);

void pauseUpdates();
void resumeUpdates();

SymbolRef getSymbol(const QModelIndex& index);

virtual void OnAnalysisFunctionAdded(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override;
virtual void OnAnalysisFunctionRemoved(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override;
virtual void OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override;
virtual void OnSymbolAdded(BinaryNinja::BinaryView* view, BinaryNinja::Symbol* sym) override;
virtual void OnSymbolUpdated(BinaryNinja::BinaryView* view, BinaryNinja::Symbol* sym) override;
virtual void OnSymbolRemoved(BinaryNinja::BinaryView* view, BinaryNinja::Symbol* sym) override;
Expand Down Expand Up @@ -75,6 +84,8 @@ class ExportsTreeView : public QTreeView, public FilterTarget

protected:
virtual void keyPressEvent(QKeyEvent* event) override;
virtual void showEvent(QShowEvent* event) override;
virtual void hideEvent(QHideEvent* event) override;

private Q_SLOTS:
void exportSelected(const QModelIndex& cur, const QModelIndex& prev);
Expand Down
Loading