Skip to content

Commit 0647103

Browse files
committed
Flow graph improvements in Rust API
- Fixed some misc bugs - Added real FlowGraphEdge type - Added accessors for node edges - Added interaction handler to the flow graph example to dump the flow graph to stdin - Split out the flow graph API into smaller files
1 parent d3a36c6 commit 0647103

File tree

4 files changed

+353
-172
lines changed

4 files changed

+353
-172
lines changed

rust/examples/flowgraph.rs

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,82 @@
1+
use binaryninja::flowgraph::edge::EdgeStyle;
2+
use binaryninja::flowgraph::FlowGraphNode;
3+
use binaryninja::interaction::form::Form;
4+
use binaryninja::interaction::handler::{
5+
register_interaction_handler, InteractionHandler, InteractionHandlerTask,
6+
};
7+
use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet, MessageBoxIcon};
18
use binaryninja::{
29
binary_view::{BinaryView, BinaryViewExt},
310
disassembly::{DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind},
4-
flowgraph::{BranchType, EdgePenStyle, EdgeStyle, FlowGraph, FlowGraphNode, ThemeColor},
11+
flowgraph::{BranchType, EdgePenStyle, FlowGraph, ThemeColor},
512
};
613

14+
pub struct GraphPrinter;
15+
16+
impl GraphPrinter {
17+
pub fn print_graph(&self, _view: &BinaryView, _graph: &FlowGraph) {
18+
println!("Printing flow graph:");
19+
for node in &_graph.nodes() {
20+
// Print all disassembly lines in the node
21+
println!("Node @ {:?}:", node.position());
22+
println!("------------------");
23+
println!("Disassembly lines:");
24+
for line in &node.lines() {
25+
println!(" {}", line.to_string());
26+
}
27+
28+
// Print outgoing edges
29+
println!("Outgoing edges:");
30+
for edge in &node.outgoing_edges() {
31+
let target_node_pos = edge.target.position();
32+
println!(" {:?} => {:?}", edge.branch_type, target_node_pos,);
33+
}
34+
println!("------------------");
35+
}
36+
}
37+
}
38+
39+
impl InteractionHandler for GraphPrinter {
40+
fn show_message_box(
41+
&mut self,
42+
_title: &str,
43+
_text: &str,
44+
_buttons: MessageBoxButtonSet,
45+
_icon: MessageBoxIcon,
46+
) -> MessageBoxButtonResult {
47+
MessageBoxButtonResult::CancelButton
48+
}
49+
50+
fn open_url(&mut self, _url: &str) -> bool {
51+
false
52+
}
53+
54+
fn run_progress_dialog(
55+
&mut self,
56+
_title: &str,
57+
_can_cancel: bool,
58+
_task: &InteractionHandlerTask,
59+
) -> bool {
60+
false
61+
}
62+
63+
fn show_plain_text_report(&mut self, _view: &BinaryView, title: &str, contents: &str) {
64+
println!("Plain text report");
65+
println!("Title: {}", title);
66+
println!("Contents: {}", contents);
67+
}
68+
69+
fn show_graph_report(&mut self, _view: &BinaryView, title: &str, _graph: &FlowGraph) {
70+
println!("Graph report");
71+
println!("Title: {}", title);
72+
self.print_graph(_view, _graph);
73+
}
74+
75+
fn get_form_input(&mut self, _form: &mut Form) -> bool {
76+
false
77+
}
78+
}
79+
780
fn test_graph(view: &BinaryView) {
881
let graph = FlowGraph::new();
982

@@ -15,8 +88,10 @@ fn test_graph(view: &BinaryView) {
1588

1689
let node_a = FlowGraphNode::new(&graph);
1790
node_a.set_lines(disassembly_lines_a);
91+
node_a.set_position(1337, 7331);
1892

1993
let node_b = FlowGraphNode::new(&graph);
94+
node_b.set_position(100, 200);
2095
let disassembly_lines_b = vec![DisassemblyTextLine::new(vec![
2196
InstructionTextToken::new("Li", InstructionTextTokenKind::Text),
2297
InstructionTextToken::new("ne", InstructionTextTokenKind::Text),
@@ -49,8 +124,8 @@ fn main() {
49124
.load("/bin/cat")
50125
.expect("Couldn't open `/bin/cat`");
51126

52-
// TODO: Register BNInteractionHandlerCallbacks with showGraphReport pointing at our function
53-
// TODO: Idea: register showGraphReport that dumps a dotgraph to stdin
127+
// Register the interaction handler so we can see the graph report headlessly.
128+
register_interaction_handler(GraphPrinter);
54129

55130
test_graph(&bv);
56131
}

rust/src/flowgraph.rs

Lines changed: 7 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@
1414

1515
//! Interfaces for creating and displaying pretty CFGs in Binary Ninja.
1616
17-
use crate::disassembly::DisassemblyTextLine;
18-
use crate::rc::*;
1917
use binaryninjacore_sys::*;
2018

21-
use crate::basic_block::{BasicBlock, BlockContext};
22-
use crate::function::HighlightColor;
2319
use crate::high_level_il::HighLevelILFunction;
2420
use crate::low_level_il::RegularLowLevelILFunction;
2521
use crate::medium_level_il::MediumLevelILFunction;
22+
use crate::rc::*;
2623
use crate::render_layer::CoreRenderLayer;
2724

25+
pub mod edge;
26+
pub mod node;
27+
28+
pub use edge::FlowGraphEdge;
29+
pub use node::FlowGraphNode;
30+
2831
pub type BranchType = BNBranchType;
2932
pub type EdgePenStyle = BNEdgePenStyle;
3033
pub type ThemeColor = BNThemeColor;
@@ -162,168 +165,3 @@ impl ToOwned for FlowGraph {
162165
unsafe { RefCountable::inc_ref(self) }
163166
}
164167
}
165-
166-
#[derive(PartialEq, Eq, Hash)]
167-
pub struct FlowGraphNode {
168-
pub(crate) handle: *mut BNFlowGraphNode,
169-
}
170-
171-
impl FlowGraphNode {
172-
pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraphNode) -> Self {
173-
Self { handle: raw }
174-
}
175-
176-
pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraphNode) -> Ref<Self> {
177-
Ref::new(Self { handle: raw })
178-
}
179-
180-
pub fn new(graph: &FlowGraph) -> Ref<Self> {
181-
unsafe { FlowGraphNode::ref_from_raw(BNCreateFlowGraphNode(graph.handle)) }
182-
}
183-
184-
pub fn basic_block<C: BlockContext>(&self, context: C) -> Option<Ref<BasicBlock<C>>> {
185-
let block_ptr = unsafe { BNGetFlowGraphBasicBlock(self.handle) };
186-
if block_ptr.is_null() {
187-
return None;
188-
}
189-
Some(unsafe { BasicBlock::ref_from_raw(block_ptr, context) })
190-
}
191-
192-
pub fn set_basic_block<C: BlockContext>(&self, block: Option<&BasicBlock<C>>) {
193-
match block {
194-
Some(block) => unsafe { BNSetFlowGraphBasicBlock(self.handle, block.handle) },
195-
None => unsafe { BNSetFlowGraphBasicBlock(self.handle, std::ptr::null_mut()) },
196-
}
197-
}
198-
199-
pub fn lines(&self) -> Array<DisassemblyTextLine> {
200-
let mut count = 0;
201-
let result = unsafe { BNGetFlowGraphNodeLines(self.handle, &mut count) };
202-
assert!(!result.is_null());
203-
unsafe { Array::new(result, count, ()) }
204-
}
205-
206-
pub fn set_lines(&self, lines: impl IntoIterator<Item = DisassemblyTextLine>) {
207-
// NOTE: This will create allocations and increment tag refs, we must call DisassemblyTextLine::free_raw
208-
let mut raw_lines: Vec<BNDisassemblyTextLine> = lines
209-
.into_iter()
210-
.map(DisassemblyTextLine::into_raw)
211-
.collect();
212-
unsafe {
213-
BNSetFlowGraphNodeLines(self.handle, raw_lines.as_mut_ptr(), raw_lines.len());
214-
for raw_line in raw_lines {
215-
DisassemblyTextLine::free_raw(raw_line);
216-
}
217-
}
218-
}
219-
220-
/// Returns the graph position of the node in X, Y form.
221-
pub fn position(&self) -> (i32, i32) {
222-
let pos_x = unsafe { BNGetFlowGraphNodeX(self.handle) };
223-
let pos_y = unsafe { BNGetFlowGraphNodeY(self.handle) };
224-
(pos_x, pos_y)
225-
}
226-
227-
/// Sets the graph position of the node.
228-
pub fn set_position(&self, x: i32, y: i32) {
229-
unsafe { BNFlowGraphNodeSetX(self.handle, x) };
230-
unsafe { BNFlowGraphNodeSetX(self.handle, y) };
231-
}
232-
233-
pub fn highlight_color(&self) -> HighlightColor {
234-
let raw = unsafe { BNGetFlowGraphNodeHighlight(self.handle) };
235-
HighlightColor::from(raw)
236-
}
237-
238-
pub fn set_highlight_color(&self, highlight: HighlightColor) {
239-
unsafe { BNSetFlowGraphNodeHighlight(self.handle, highlight.into()) };
240-
}
241-
242-
// TODO: Add getters and setters for edges
243-
244-
pub fn add_outgoing_edge(
245-
&self,
246-
type_: BranchType,
247-
target: &FlowGraphNode,
248-
edge_style: EdgeStyle,
249-
) {
250-
unsafe {
251-
BNAddFlowGraphNodeOutgoingEdge(self.handle, type_, target.handle, edge_style.into())
252-
}
253-
}
254-
}
255-
256-
unsafe impl RefCountable for FlowGraphNode {
257-
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
258-
Ref::new(Self {
259-
handle: BNNewFlowGraphNodeReference(handle.handle),
260-
})
261-
}
262-
263-
unsafe fn dec_ref(handle: &Self) {
264-
BNFreeFlowGraphNode(handle.handle);
265-
}
266-
}
267-
268-
impl ToOwned for FlowGraphNode {
269-
type Owned = Ref<Self>;
270-
271-
fn to_owned(&self) -> Self::Owned {
272-
unsafe { RefCountable::inc_ref(self) }
273-
}
274-
}
275-
276-
impl CoreArrayProvider for FlowGraphNode {
277-
type Raw = *mut BNFlowGraphNode;
278-
type Context = ();
279-
type Wrapped<'a> = Guard<'a, FlowGraphNode>;
280-
}
281-
282-
unsafe impl CoreArrayProviderInner for FlowGraphNode {
283-
unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) {
284-
BNFreeFlowGraphNodeList(raw, count);
285-
}
286-
287-
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
288-
Guard::new(Self::from_raw(*raw), context)
289-
}
290-
}
291-
292-
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
293-
pub struct EdgeStyle {
294-
style: EdgePenStyle,
295-
width: usize,
296-
color: ThemeColor,
297-
}
298-
299-
impl EdgeStyle {
300-
pub fn new(style: EdgePenStyle, width: usize, color: ThemeColor) -> Self {
301-
Self {
302-
style,
303-
width,
304-
color,
305-
}
306-
}
307-
}
308-
309-
impl Default for EdgeStyle {
310-
fn default() -> Self {
311-
Self::new(EdgePenStyle::SolidLine, 0, ThemeColor::AddressColor)
312-
}
313-
}
314-
315-
impl From<BNEdgeStyle> for EdgeStyle {
316-
fn from(style: BNEdgeStyle) -> Self {
317-
Self::new(style.style, style.width, style.color)
318-
}
319-
}
320-
321-
impl From<EdgeStyle> for BNEdgeStyle {
322-
fn from(style: EdgeStyle) -> Self {
323-
Self {
324-
style: style.style,
325-
width: style.width,
326-
color: style.color,
327-
}
328-
}
329-
}

0 commit comments

Comments
 (0)