binaryninja/flowgraph/
node.rs

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