From bfa6fce83383e7be1458a917f8e6dbf71bdab28b Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 4 Jun 2018 14:12:26 -0400 Subject: Generic flow graph API and report collections --- flowgraphnode.cpp | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 flowgraphnode.cpp (limited to 'flowgraphnode.cpp') diff --git a/flowgraphnode.cpp b/flowgraphnode.cpp new file mode 100644 index 00000000..a49cb0d0 --- /dev/null +++ b/flowgraphnode.cpp @@ -0,0 +1,203 @@ +// Copyright (c) 2015-2017 Vector 35 LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace std; + + +FlowGraphNode::FlowGraphNode(FlowGraph* graph) +{ + m_object = BNCreateFlowGraphNode(graph->GetGraphObject()); + m_cachedLinesValid = false; + m_cachedEdgesValid = false; +} + + +FlowGraphNode::FlowGraphNode(BNFlowGraphNode* node) +{ + m_object = node; + m_cachedLinesValid = false; + m_cachedEdgesValid = false; +} + + +Ref FlowGraphNode::GetBasicBlock() const +{ + return new BasicBlock(BNGetFlowGraphBasicBlock(m_object)); +} + + +void FlowGraphNode::SetBasicBlock(BasicBlock* block) +{ + BNSetFlowGraphBasicBlock(m_object, block ? block->GetObject() : nullptr); +} + + +int FlowGraphNode::GetX() const +{ + return BNGetFlowGraphNodeX(m_object); +} + + +int FlowGraphNode::GetY() const +{ + return BNGetFlowGraphNodeY(m_object); +} + + +int FlowGraphNode::GetWidth() const +{ + return BNGetFlowGraphNodeWidth(m_object); +} + + +int FlowGraphNode::GetHeight() const +{ + return BNGetFlowGraphNodeHeight(m_object); +} + + +const vector& FlowGraphNode::GetLines() +{ + if (m_cachedLinesValid) + return m_cachedLines; + + size_t count; + BNDisassemblyTextLine* lines = BNGetFlowGraphNodeLines(m_object, &count); + + vector result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + DisassemblyTextLine line; + line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; + line.highlight = lines[i].highlight; + line.tokens.reserve(lines[i].count); + for (size_t j = 0; j < lines[i].count; j++) + { + InstructionTextToken token; + token.type = lines[i].tokens[j].type; + token.text = lines[i].tokens[j].text; + token.value = lines[i].tokens[j].value; + token.size = lines[i].tokens[j].size; + token.operand = lines[i].tokens[j].operand; + token.context = lines[i].tokens[j].context; + token.confidence = lines[i].tokens[j].confidence; + token.address = lines[i].tokens[j].address; + line.tokens.push_back(token); + } + result.push_back(line); + } + + BNFreeDisassemblyTextLines(lines, count); + m_cachedLines = result; + m_cachedLinesValid = true; + return m_cachedLines; +} + + +void FlowGraphNode::SetLines(const vector& lines) +{ + BNDisassemblyTextLine* buf = new BNDisassemblyTextLine[lines.size()]; + for (size_t i = 0; i < lines.size(); i++) + { + const DisassemblyTextLine& line = lines[i]; + buf[i].addr = line.addr; + buf[i].instrIndex = line.instrIndex; + buf[i].highlight = line.highlight; + buf[i].tokens = new BNInstructionTextToken[line.tokens.size()]; + buf[i].count = line.tokens.size(); + for (size_t j = 0; j < line.tokens.size(); j++) + { + const InstructionTextToken& token = line.tokens[j]; + buf[i].tokens[j].type = token.type; + buf[i].tokens[j].text = BNAllocString(token.text.c_str()); + buf[i].tokens[j].value = token.value; + buf[i].tokens[j].size = token.size; + buf[i].tokens[j].operand = token.operand; + buf[i].tokens[j].context = token.context; + buf[i].tokens[j].confidence = token.confidence; + buf[i].tokens[j].address = token.address; + } + } + + BNSetFlowGraphNodeLines(m_object, buf, lines.size()); + + for (size_t i = 0; i < lines.size(); i++) + { + for (size_t j = 0; j < buf[i].count; j++) + BNFreeString(buf[i].tokens[j].text); + delete[] buf[i].tokens; + } + delete[] buf; + + m_cachedLines = lines; + m_cachedLinesValid = true; +} + + +const vector& FlowGraphNode::GetOutgoingEdges() +{ + if (m_cachedEdgesValid) + return m_cachedEdges; + + size_t count; + BNFlowGraphEdge* edges = BNGetFlowGraphNodeOutgoingEdges(m_object, &count); + + vector result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + FlowGraphEdge edge; + edge.type = edges[i].type; + edge.target = edges[i].target ? new FlowGraphNode(BNNewFlowGraphNodeReference(edges[i].target)) : nullptr; + edge.points.insert(edge.points.begin(), &edges[i].points[0], &edges[i].points[edges[i].pointCount]); + edge.backEdge = edges[i].backEdge; + result.push_back(edge); + } + + BNFreeFlowGraphNodeOutgoingEdgeList(edges, count); + m_cachedEdges = result; + m_cachedEdgesValid = true; + return m_cachedEdges; +} + + +void FlowGraphNode::AddOutgoingEdge(BNBranchType type, FlowGraphNode* target) +{ + BNAddFlowGraphNodeOutgoingEdge(m_object, type, target->GetObject()); + m_cachedEdges.clear(); + m_cachedEdgesValid = false; +} + + +BNHighlightColor FlowGraphNode::GetHighlight() const +{ + return BNGetFlowGraphNodeHighlight(m_object); +} + + +void FlowGraphNode::SetHighlight(const BNHighlightColor& color) +{ + BNSetFlowGraphNodeHighlight(m_object, color); +} -- cgit v1.3.1 From 657bc3ff2d000508bd4b4468e83ce37591655e17 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 2 Aug 2018 22:46:23 -0400 Subject: Fix crash on flow graphs with no associated basic block --- flowgraphnode.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'flowgraphnode.cpp') diff --git a/flowgraphnode.cpp b/flowgraphnode.cpp index a49cb0d0..eea033a8 100644 --- a/flowgraphnode.cpp +++ b/flowgraphnode.cpp @@ -42,7 +42,10 @@ FlowGraphNode::FlowGraphNode(BNFlowGraphNode* node) Ref FlowGraphNode::GetBasicBlock() const { - return new BasicBlock(BNGetFlowGraphBasicBlock(m_object)); + BNBasicBlock* block = BNGetFlowGraphBasicBlock(m_object); + if (!block) + return nullptr; + return new BasicBlock(block); } -- cgit v1.3.1 From 1df50c8093bf3b949055d2670836fa1bb742fc1b Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 14 Aug 2018 19:59:58 -0400 Subject: Modify flow graph API to support multiple layout requests for a single graph --- binaryninjaapi.h | 27 +++++++---- binaryninjacore.h | 10 ++-- binaryview.cpp | 2 +- flowgraph.cpp | 128 +++++++++++++++++++++++++++----------------------- flowgraphnode.cpp | 2 +- interaction.cpp | 6 +-- python/flowgraph.py | 59 ++++++++++++++--------- python/interaction.py | 2 +- 8 files changed, 137 insertions(+), 99 deletions(-) (limited to 'flowgraphnode.cpp') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 2c467a35..67d2f7f8 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2598,14 +2598,28 @@ namespace BinaryNinja void SetHighlight(const BNHighlightColor& color); }; - class FlowGraph: public RefCountObject + class FlowGraphLayoutRequest: public RefCountObject { - BNFlowGraph* m_graph; + BNFlowGraphLayoutRequest* m_object; std::function m_completeFunc; - std::map> m_cachedNodes; static void CompleteCallback(void* ctxt); + public: + FlowGraphLayoutRequest(FlowGraph* graph, const std::function& completeFunc); + virtual ~FlowGraphLayoutRequest(); + + BNFlowGraphLayoutRequest* GetObject() const { return m_object; } + + Ref GetGraph() const; + bool IsComplete() const; + void Abort(); + }; + + class FlowGraph: public CoreRefCountObject + { + std::map> m_cachedNodes; + static void PrepareForLayoutCallback(void* ctxt); static void PopulateNodesCallback(void* ctxt); static void CompleteLayoutCallback(void* ctxt); @@ -2621,9 +2635,6 @@ namespace BinaryNinja public: FlowGraph(); - ~FlowGraph(); - - BNFlowGraph* GetGraphObject() const { return m_graph; } Ref GetFunction() const; void SetFunction(Function* func); @@ -2632,10 +2643,8 @@ namespace BinaryNinja int GetVerticalNodeMargin() const; void SetNodeMargins(int horiz, int vert); - void StartLayout(); + Ref StartLayout(const std::function& func); bool IsLayoutComplete(); - void OnComplete(const std::function& func); - void Abort(); std::vector> GetNodes(); Ref GetNode(size_t i); diff --git a/binaryninjacore.h b/binaryninjacore.h index 3e060c61..7e353ff0 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -124,6 +124,7 @@ extern "C" struct BNDownloadInstance; struct BNFlowGraph; struct BNFlowGraphNode; + struct BNFlowGraphLayoutRequest; struct BNSymbol; struct BNTemporaryFile; struct BNLowLevelILFunction; @@ -2654,10 +2655,13 @@ extern "C" BINARYNINJACOREAPI int BNGetVerticalFlowGraphNodeMargin(BNFlowGraph* graph); BINARYNINJACOREAPI void BNSetFlowGraphNodeMargins(BNFlowGraph* graph, int horiz, int vert); - BINARYNINJACOREAPI void BNStartFlowGraphLayout(BNFlowGraph* graph); + BINARYNINJACOREAPI BNFlowGraphLayoutRequest* BNStartFlowGraphLayout(BNFlowGraph* graph, void* ctxt, void (*func)(void* ctxt)); BINARYNINJACOREAPI bool BNIsFlowGraphLayoutComplete(BNFlowGraph* graph); - BINARYNINJACOREAPI void BNSetFlowGraphCompleteCallback(BNFlowGraph* graph, void* ctxt, void (*func)(void* ctxt)); - BINARYNINJACOREAPI void BNAbortFlowGraph(BNFlowGraph* graph); + BINARYNINJACOREAPI BNFlowGraphLayoutRequest* BNNewFlowGraphLayoutRequestReference(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI void BNFreeFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI bool BNIsFlowGraphLayoutRequestComplete(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI BNFlowGraph* BNGetGraphForFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* layout); + BINARYNINJACOREAPI void BNAbortFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* graph); BINARYNINJACOREAPI bool BNIsILFlowGraph(BNFlowGraph* graph); BINARYNINJACOREAPI bool BNIsLowLevelILFlowGraph(BNFlowGraph* graph); BINARYNINJACOREAPI bool BNIsMediumLevelILFlowGraph(BNFlowGraph* graph); diff --git a/binaryview.cpp b/binaryview.cpp index da516184..258b0153 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1720,7 +1720,7 @@ void BinaryView::ShowHTMLReport(const string& title, const string& contents, con void BinaryView::ShowGraphReport(const string& title, FlowGraph* graph) { - BNShowGraphReport(m_object, title.c_str(), graph->GetGraphObject()); + BNShowGraphReport(m_object, title.c_str(), graph->GetObject()); } diff --git a/flowgraph.cpp b/flowgraph.cpp index 81950367..dc7e628e 100644 --- a/flowgraph.cpp +++ b/flowgraph.cpp @@ -24,37 +24,65 @@ using namespace BinaryNinja; using namespace std; -FlowGraph::FlowGraph() +FlowGraphLayoutRequest::FlowGraphLayoutRequest(FlowGraph* graph, const std::function& completeFunc): + m_completeFunc(completeFunc) { - BNCustomFlowGraph callbacks; - callbacks.context = this; - callbacks.prepareForLayout = PrepareForLayoutCallback; - callbacks.populateNodes = PopulateNodesCallback; - callbacks.completeLayout = CompleteLayoutCallback; - m_graph = BNCreateCustomFlowGraph(&callbacks); + m_object = BNStartFlowGraphLayout(graph->GetObject(), this, CompleteCallback); } -FlowGraph::FlowGraph(BNFlowGraph* graph): m_graph(graph) +FlowGraphLayoutRequest::~FlowGraphLayoutRequest() { + // This object is going away, so ensure that any pending completion routines are + // no longer called + Abort(); + + BNFreeFlowGraphLayoutRequest(m_object); } -FlowGraph::~FlowGraph() +void FlowGraphLayoutRequest::CompleteCallback(void* ctxt) { - // This object is going away, so ensure that any pending completion routines are - // no longer called - if (m_completeFunc) - Abort(); + FlowGraphLayoutRequest* layout = (FlowGraphLayoutRequest*)ctxt; + layout->m_completeFunc(); +} - BNFreeFlowGraph(m_graph); + +Ref FlowGraphLayoutRequest::GetGraph() const +{ + return new CoreFlowGraph(BNGetGraphForFlowGraphLayoutRequest(m_object)); } -void FlowGraph::CompleteCallback(void* ctxt) +bool FlowGraphLayoutRequest::IsComplete() const { - FlowGraph* graph = (FlowGraph*)ctxt; - graph->m_completeFunc(); + return BNIsFlowGraphLayoutRequestComplete(m_object); +} + + +void FlowGraphLayoutRequest::Abort() +{ + // Must clear the callback with the core before clearing our own function object, as until it + // is cleared in the core it can be called at any time from a different thread. + BNAbortFlowGraphLayoutRequest(m_object); + m_completeFunc = []() {}; +} + + +FlowGraph::FlowGraph() +{ + BNCustomFlowGraph callbacks; + callbacks.context = this; + callbacks.prepareForLayout = PrepareForLayoutCallback; + callbacks.populateNodes = PopulateNodesCallback; + callbacks.completeLayout = CompleteLayoutCallback; + m_object = BNCreateCustomFlowGraph(&callbacks); +} + + +FlowGraph::FlowGraph(BNFlowGraph* graph) +{ + m_object = graph; } @@ -85,13 +113,13 @@ BNFlowGraph* FlowGraph::UpdateCallback(void* ctxt) Ref result = graph->Update(); if (!result) return nullptr; - return BNNewFlowGraphReference(result->GetGraphObject()); + return BNNewFlowGraphReference(result->GetObject()); } void FlowGraph::FinishPrepareForLayout() { - BNFinishPrepareForLayout(m_graph); + BNFinishPrepareForLayout(m_object); } @@ -113,7 +141,7 @@ void FlowGraph::CompleteLayout() Ref FlowGraph::GetFunction() const { - BNFunction* func = BNGetFunctionForFlowGraph(m_graph); + BNFunction* func = BNGetFunctionForFlowGraph(m_object); if (!func) return nullptr; return new Function(BNNewFunctionReference(func)); @@ -122,60 +150,44 @@ Ref FlowGraph::GetFunction() const void FlowGraph::SetFunction(Function* func) { - BNSetFunctionForFlowGraph(m_graph, func ? func->GetObject() : nullptr); + BNSetFunctionForFlowGraph(m_object, func ? func->GetObject() : nullptr); } int FlowGraph::GetHorizontalNodeMargin() const { - return BNGetHorizontalFlowGraphNodeMargin(m_graph); + return BNGetHorizontalFlowGraphNodeMargin(m_object); } int FlowGraph::GetVerticalNodeMargin() const { - return BNGetVerticalFlowGraphNodeMargin(m_graph); + return BNGetVerticalFlowGraphNodeMargin(m_object); } void FlowGraph::SetNodeMargins(int horiz, int vert) { - BNSetFlowGraphNodeMargins(m_graph, horiz, vert); + BNSetFlowGraphNodeMargins(m_object, horiz, vert); } -void FlowGraph::StartLayout() +Ref FlowGraph::StartLayout(const std::function& func) { - BNStartFlowGraphLayout(m_graph); + return new FlowGraphLayoutRequest(this, func); } bool FlowGraph::IsLayoutComplete() { - return BNIsFlowGraphLayoutComplete(m_graph); -} - - -void FlowGraph::OnComplete(const std::function& func) -{ - m_completeFunc = func; - BNSetFlowGraphCompleteCallback(m_graph, this, CompleteCallback); -} - - -void FlowGraph::Abort() -{ - // Must clear the callback with the core before clearing our own function object, as until it - // is cleared in the core it can be called at any time from a different thread. - BNAbortFlowGraph(m_graph); - m_completeFunc = []() {}; + return BNIsFlowGraphLayoutComplete(m_object); } vector> FlowGraph::GetNodes() { size_t count; - BNFlowGraphNode** nodes = BNGetFlowGraphNodes(m_graph, &count); + BNFlowGraphNode** nodes = BNGetFlowGraphNodes(m_object, &count); vector> result; result.reserve(count); @@ -201,7 +213,7 @@ vector> FlowGraph::GetNodes() Ref FlowGraph::GetNode(size_t i) { - BNFlowGraphNode* node = BNGetFlowGraphNode(m_graph, i); + BNFlowGraphNode* node = BNGetFlowGraphNode(m_object, i); if (!node) return nullptr; @@ -222,33 +234,33 @@ Ref FlowGraph::GetNode(size_t i) bool FlowGraph::HasNodes() const { - return BNFlowGraphHasNodes(m_graph); + return BNFlowGraphHasNodes(m_object); } size_t FlowGraph::AddNode(FlowGraphNode* node) { m_cachedNodes[node->GetObject()] = node; - return BNAddFlowGraphNode(m_graph, node->GetObject()); + return BNAddFlowGraphNode(m_object, node->GetObject()); } int FlowGraph::GetWidth() const { - return BNGetFlowGraphWidth(m_graph); + return BNGetFlowGraphWidth(m_object); } int FlowGraph::GetHeight() const { - return BNGetFlowGraphHeight(m_graph); + return BNGetFlowGraphHeight(m_object); } vector> FlowGraph::GetNodesInRegion(int left, int top, int right, int bottom) { size_t count; - BNFlowGraphNode** nodes = BNGetFlowGraphNodesInRegion(m_graph, left, top, right, bottom, &count); + BNFlowGraphNode** nodes = BNGetFlowGraphNodesInRegion(m_object, left, top, right, bottom, &count); vector> result; result.reserve(count); @@ -274,25 +286,25 @@ vector> FlowGraph::GetNodesInRegion(int left, int top, int ri bool FlowGraph::IsILGraph() const { - return BNIsILFlowGraph(m_graph); + return BNIsILFlowGraph(m_object); } bool FlowGraph::IsLowLevelILGraph() const { - return BNIsLowLevelILFlowGraph(m_graph); + return BNIsLowLevelILFlowGraph(m_object); } bool FlowGraph::IsMediumLevelILGraph() const { - return BNIsMediumLevelILFlowGraph(m_graph); + return BNIsMediumLevelILFlowGraph(m_object); } Ref FlowGraph::GetLowLevelILFunction() const { - BNLowLevelILFunction* func = BNGetFlowGraphLowLevelILFunction(m_graph); + BNLowLevelILFunction* func = BNGetFlowGraphLowLevelILFunction(m_object); if (!func) return nullptr; return new LowLevelILFunction(func); @@ -301,7 +313,7 @@ Ref FlowGraph::GetLowLevelILFunction() const Ref FlowGraph::GetMediumLevelILFunction() const { - BNMediumLevelILFunction* func = BNGetFlowGraphMediumLevelILFunction(m_graph); + BNMediumLevelILFunction* func = BNGetFlowGraphMediumLevelILFunction(m_object); if (!func) return nullptr; return new MediumLevelILFunction(func); @@ -310,13 +322,13 @@ Ref FlowGraph::GetMediumLevelILFunction() const void FlowGraph::SetLowLevelILFunction(LowLevelILFunction* func) { - BNSetFlowGraphLowLevelILFunction(m_graph, func ? func->GetObject() : nullptr); + BNSetFlowGraphLowLevelILFunction(m_object, func ? func->GetObject() : nullptr); } void FlowGraph::SetMediumLevelILFunction(MediumLevelILFunction* func) { - BNSetFlowGraphMediumLevelILFunction(m_graph, func ? func->GetObject() : nullptr); + BNSetFlowGraphMediumLevelILFunction(m_object, func ? func->GetObject() : nullptr); } @@ -339,7 +351,7 @@ CoreFlowGraph::CoreFlowGraph(BNFlowGraph* graph): FlowGraph(graph) Ref CoreFlowGraph::Update() { - BNFlowGraph* graph = BNUpdateFlowGraph(GetGraphObject()); + BNFlowGraph* graph = BNUpdateFlowGraph(GetObject()); if (!graph) return nullptr; return new CoreFlowGraph(graph); diff --git a/flowgraphnode.cpp b/flowgraphnode.cpp index eea033a8..60912df1 100644 --- a/flowgraphnode.cpp +++ b/flowgraphnode.cpp @@ -26,7 +26,7 @@ using namespace std; FlowGraphNode::FlowGraphNode(FlowGraph* graph) { - m_object = BNCreateFlowGraphNode(graph->GetGraphObject()); + m_object = BNCreateFlowGraphNode(graph->GetObject()); m_cachedLinesValid = false; m_cachedEdgesValid = false; } diff --git a/interaction.cpp b/interaction.cpp index da3942bb..b2e62482 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -431,9 +431,9 @@ void BinaryNinja::ShowGraphReport(const string& title, FlowGraph* graph) { Ref func = graph->GetFunction(); if (func) - BNShowGraphReport(func->GetView()->GetObject(), title.c_str(), graph->GetGraphObject()); + BNShowGraphReport(func->GetView()->GetObject(), title.c_str(), graph->GetObject()); else - BNShowGraphReport(nullptr, title.c_str(), graph->GetGraphObject()); + BNShowGraphReport(nullptr, title.c_str(), graph->GetObject()); } @@ -691,5 +691,5 @@ void ReportCollection::AddHTMLReport(Ref view, const string& title, void ReportCollection::AddGraphReport(Ref view, const string& title, Ref graph) { - BNAddGraphReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), graph->GetGraphObject()); + BNAddGraphReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), graph->GetObject()); } diff --git a/python/flowgraph.py b/python/flowgraph.py index 884d6587..6d1174d6 100644 --- a/python/flowgraph.py +++ b/python/flowgraph.py @@ -263,6 +263,38 @@ class FlowGraphNode(object): core.BNAddFlowGraphNodeOutgoingEdge(self.handle, edge_type, target.handle) +class FlowGraphLayoutRequest(object): + def __init__(self, graph, callback = None): + self.on_complete = callback + self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._complete) + self.handle = core.BNStartFlowGraphLayout(graph.handle, None, self._cb) + + def __del__(self): + self.abort() + core.BNFreeFlowGraphLayoutRequest(self.handle) + + def _complete(self, ctxt): + try: + if self._on_complete is not None: + self._on_complete() + except: + log.log_error(traceback.format_exc()) + + @property + def complete(self): + """Whether flow graph layout is complete (read-only)""" + return core.BNIsFlowGraphLayoutRequestComplete(self.handle) + + @property + def graph(self): + """Flow graph that is being processed (read-only)""" + return CoreFlowGraph(core.BNGetGraphForFlowGraphLayoutRequest(self.handle)) + + def abort(self): + core.BNAbortFlowGraphLayoutRequest(self.handle) + self.on_complete = None + + class FlowGraph(object): def __init__(self, handle = None): if handle is None: @@ -274,12 +306,8 @@ class FlowGraph(object): self._ext_cb.update = self._ext_cb.update.__class__(self._update) handle = core.BNCreateCustomFlowGraph(self._ext_cb) self.handle = handle - self._on_complete = None - self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._complete) def __del__(self): - if self._on_complete is not None: - self.abort() core.BNFreeFlowGraph(self.handle) def __eq__(self, value): @@ -460,15 +488,8 @@ class FlowGraph(object): finally: core.BNFreeFlowGraphNodeList(nodes, count.value) - def _complete(self, ctxt): - try: - if self._on_complete is not None: - self._on_complete() - except: - log.log_error(traceback.format_exc()) - - def layout(self): - core.BNStartFlowGraphLayout(self.handle) + def layout(self, callback = None): + return FlowGraphLayoutRequest(self, callback) def _wait_complete(self): self._wait_cond.acquire() @@ -477,21 +498,13 @@ class FlowGraph(object): def layout_and_wait(self): self._wait_cond = threading.Condition() - self.on_complete(self._wait_complete) - self.layout() + request = self.layout(self._wait_complete) self._wait_cond.acquire() - while not self.complete: + while not request.complete: self._wait_cond.wait() self._wait_cond.release() - def on_complete(self, callback): - self._on_complete = callback - core.BNSetFlowGraphCompleteCallback(self.handle, None, self._cb) - - def abort(self): - core.BNAbortFlowGraph(self.handle) - def get_nodes_in_region(self, left, top, right, bottom): count = ctypes.c_ulonglong() nodes = core.BNGetFlowGraphNodesInRegion(self.handle, left, top, right, bottom, count) diff --git a/python/interaction.py b/python/interaction.py index 0170e6aa..e53312cf 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -23,7 +23,7 @@ import traceback # Binary Ninja components from binaryninja import _binaryninjacore as core -from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult +from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult, ReportType from binaryninja import binaryview from binaryninja import log from binaryninja import flowgraph -- cgit v1.3.1