binaryninja/flowgraph/
node.rs

1use crate::basic_block::{BasicBlock, BlockContext};
2use crate::disassembly::DisassemblyTextLine;
3use crate::flowgraph::edge::{EdgeStyle, FlowGraphEdge};
4use crate::flowgraph::{BranchType, FlowGraph};
5use crate::function::HighlightColor;
6use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
7use binaryninjacore_sys::*;
8use std::fmt::{Debug, Formatter};
9
10#[derive(PartialEq, Eq, Hash)]
11pub struct FlowGraphNode {
12    pub(crate) handle: *mut BNFlowGraphNode,
13}
14
15impl FlowGraphNode {
16    pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraphNode) -> Self {
17        Self { handle: raw }
18    }
19
20    pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraphNode) -> Ref<Self> {
21        Ref::new(Self { handle: raw })
22    }
23
24    pub fn new(graph: &FlowGraph) -> Ref<Self> {
25        unsafe { FlowGraphNode::ref_from_raw(BNCreateFlowGraphNode(graph.handle)) }
26    }
27
28    pub fn basic_block<C: BlockContext>(&self, context: C) -> Option<Ref<BasicBlock<C>>> {
29        let block_ptr = unsafe { BNGetFlowGraphBasicBlock(self.handle) };
30        if block_ptr.is_null() {
31            return None;
32        }
33        Some(unsafe { BasicBlock::ref_from_raw(block_ptr, context) })
34    }
35
36    pub fn set_basic_block<C: BlockContext>(&self, block: Option<&BasicBlock<C>>) {
37        match block {
38            Some(block) => unsafe { BNSetFlowGraphBasicBlock(self.handle, block.handle) },
39            None => unsafe { BNSetFlowGraphBasicBlock(self.handle, std::ptr::null_mut()) },
40        }
41    }
42
43    pub fn lines(&self) -> Array<DisassemblyTextLine> {
44        let mut count = 0;
45        let result = unsafe { BNGetFlowGraphNodeLines(self.handle, &mut count) };
46        assert!(!result.is_null());
47        unsafe { Array::new(result, count, ()) }
48    }
49
50    pub fn set_lines(&self, lines: impl IntoIterator<Item = DisassemblyTextLine>) {
51        // NOTE: This will create allocations and increment tag refs, we must call DisassemblyTextLine::free_raw
52        let mut raw_lines: Vec<BNDisassemblyTextLine> = lines
53            .into_iter()
54            .map(DisassemblyTextLine::into_raw)
55            .collect();
56        unsafe {
57            BNSetFlowGraphNodeLines(self.handle, raw_lines.as_mut_ptr(), raw_lines.len());
58            for raw_line in raw_lines {
59                DisassemblyTextLine::free_raw(raw_line);
60            }
61        }
62    }
63
64    /// Returns the graph position of the node in X, Y form.
65    pub fn position(&self) -> (i32, i32) {
66        let pos_x = unsafe { BNGetFlowGraphNodeX(self.handle) };
67        let pos_y = unsafe { BNGetFlowGraphNodeY(self.handle) };
68        (pos_x, pos_y)
69    }
70
71    /// Sets the graph position of the node.
72    pub fn set_position(&self, x: i32, y: i32) {
73        unsafe { BNFlowGraphNodeSetX(self.handle, x) };
74        unsafe { BNFlowGraphNodeSetY(self.handle, y) };
75    }
76
77    pub fn highlight_color(&self) -> HighlightColor {
78        let raw = unsafe { BNGetFlowGraphNodeHighlight(self.handle) };
79        HighlightColor::from(raw)
80    }
81
82    pub fn set_highlight_color(&self, highlight: HighlightColor) {
83        unsafe { BNSetFlowGraphNodeHighlight(self.handle, highlight.into()) };
84    }
85
86    pub fn incoming_edges(&self) -> Array<FlowGraphEdge> {
87        let mut count = 0;
88        let result = unsafe { BNGetFlowGraphNodeIncomingEdges(self.handle, &mut count) };
89        assert!(!result.is_null());
90        unsafe { Array::new(result, count, ()) }
91    }
92
93    pub fn outgoing_edges(&self) -> Array<FlowGraphEdge> {
94        let mut count = 0;
95        let result = unsafe { BNGetFlowGraphNodeOutgoingEdges(self.handle, &mut count) };
96        assert!(!result.is_null());
97        unsafe { Array::new(result, count, ()) }
98    }
99
100    /// Connects two flow graph nodes with an edge.
101    pub fn add_outgoing_edge(
102        &self,
103        type_: BranchType,
104        target: &FlowGraphNode,
105        edge_style: EdgeStyle,
106    ) {
107        unsafe {
108            BNAddFlowGraphNodeOutgoingEdge(self.handle, type_, target.handle, edge_style.into())
109        }
110    }
111}
112
113impl Debug for FlowGraphNode {
114    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
115        f.debug_struct("FlowGraphNode")
116            .field("lines", &self.lines().to_vec())
117            .finish()
118    }
119}
120
121unsafe impl RefCountable for FlowGraphNode {
122    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
123        Ref::new(Self {
124            handle: BNNewFlowGraphNodeReference(handle.handle),
125        })
126    }
127
128    unsafe fn dec_ref(handle: &Self) {
129        BNFreeFlowGraphNode(handle.handle);
130    }
131}
132
133impl ToOwned for FlowGraphNode {
134    type Owned = Ref<Self>;
135
136    fn to_owned(&self) -> Self::Owned {
137        unsafe { RefCountable::inc_ref(self) }
138    }
139}
140
141impl CoreArrayProvider for FlowGraphNode {
142    type Raw = *mut BNFlowGraphNode;
143    type Context = ();
144    type Wrapped<'a> = Guard<'a, FlowGraphNode>;
145}
146
147unsafe impl CoreArrayProviderInner for FlowGraphNode {
148    unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) {
149        BNFreeFlowGraphNodeList(raw, count);
150    }
151
152    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
153        Guard::new(Self::from_raw(*raw), context)
154    }
155}