binaryninja/
flowgraph.rs

1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Interfaces for creating and displaying pretty CFGs in Binary Ninja.
16
17use binaryninjacore_sys::*;
18
19use crate::high_level_il::HighLevelILFunction;
20use crate::low_level_il::LowLevelILRegularFunction;
21use crate::medium_level_il::MediumLevelILFunction;
22use crate::rc::*;
23use crate::render_layer::CoreRenderLayer;
24
25pub mod edge;
26pub mod node;
27
28use crate::binary_view::BinaryView;
29use crate::function::Function;
30use crate::string::IntoCStr;
31pub use edge::EdgeStyle;
32pub use edge::FlowGraphEdge;
33pub use node::FlowGraphNode;
34
35pub type BranchType = BNBranchType;
36pub type EdgePenStyle = BNEdgePenStyle;
37pub type ThemeColor = BNThemeColor;
38pub type FlowGraphOption = BNFlowGraphOption;
39
40#[derive(PartialEq, Eq, Hash)]
41pub struct FlowGraph {
42    pub(crate) handle: *mut BNFlowGraph,
43}
44
45impl FlowGraph {
46    pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraph) -> Self {
47        Self { handle: raw }
48    }
49
50    pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraph) -> Ref<Self> {
51        Ref::new(Self { handle: raw })
52    }
53
54    pub fn new() -> Ref<Self> {
55        unsafe { FlowGraph::ref_from_raw(BNCreateFlowGraph()) }
56    }
57
58    pub fn has_updates(&self) -> bool {
59        let query_mode = unsafe { BNFlowGraphUpdateQueryMode(self.handle) };
60        match query_mode {
61            true => unsafe { BNFlowGraphHasUpdates(self.handle) },
62            false => false,
63        }
64    }
65
66    pub fn update(&self) -> Option<Ref<Self>> {
67        let new_graph = unsafe { BNUpdateFlowGraph(self.handle) };
68        if new_graph.is_null() {
69            return None;
70        }
71        Some(unsafe { FlowGraph::ref_from_raw(new_graph) })
72    }
73
74    pub fn show(&self, title: &str) {
75        let raw_title = title.to_cstr();
76        match self.view() {
77            None => unsafe {
78                BNShowGraphReport(std::ptr::null_mut(), raw_title.as_ptr(), self.handle);
79            },
80            Some(view) => unsafe {
81                BNShowGraphReport(view.handle, raw_title.as_ptr(), self.handle);
82            },
83        }
84    }
85
86    /// Whether flow graph layout is complete.
87    pub fn is_layout_complete(&self) -> bool {
88        unsafe { BNIsFlowGraphLayoutComplete(self.handle) }
89    }
90
91    pub fn nodes(&self) -> Array<FlowGraphNode> {
92        let mut count: usize = 0;
93        let nodes_ptr = unsafe { BNGetFlowGraphNodes(self.handle, &mut count as *mut usize) };
94        unsafe { Array::new(nodes_ptr, count, ()) }
95    }
96
97    pub fn function(&self) -> Option<Ref<Function>> {
98        unsafe {
99            let func_ptr = BNGetFunctionForFlowGraph(self.handle);
100            match func_ptr.is_null() {
101                false => Some(Function::ref_from_raw(func_ptr)),
102                true => None,
103            }
104        }
105    }
106
107    pub fn set_function(&self, func: Option<&Function>) {
108        let func_ptr = func.map(|f| f.handle).unwrap_or(std::ptr::null_mut());
109        unsafe { BNSetFunctionForFlowGraph(self.handle, func_ptr) }
110    }
111
112    pub fn view(&self) -> Option<Ref<BinaryView>> {
113        unsafe {
114            let view_ptr = BNGetViewForFlowGraph(self.handle);
115            match view_ptr.is_null() {
116                false => Some(BinaryView::ref_from_raw(view_ptr)),
117                true => None,
118            }
119        }
120    }
121
122    pub fn set_view(&self, view: Option<&BinaryView>) {
123        let view_ptr = view.map(|v| v.handle).unwrap_or(std::ptr::null_mut());
124        unsafe { BNSetViewForFlowGraph(self.handle, view_ptr) }
125    }
126
127    pub fn lifted_il(&self) -> Option<Ref<LowLevelILRegularFunction>> {
128        self.function()?.lifted_il().ok()
129    }
130
131    pub fn low_level_il(&self) -> Option<Ref<LowLevelILRegularFunction>> {
132        unsafe {
133            let llil_ptr = BNGetFlowGraphLowLevelILFunction(self.handle);
134            match llil_ptr.is_null() {
135                false => Some(LowLevelILRegularFunction::ref_from_raw(llil_ptr)),
136                true => None,
137            }
138        }
139    }
140
141    pub fn medium_level_il(&self) -> Option<Ref<MediumLevelILFunction>> {
142        unsafe {
143            let mlil_ptr = BNGetFlowGraphMediumLevelILFunction(self.handle);
144            match mlil_ptr.is_null() {
145                false => Some(MediumLevelILFunction::ref_from_raw(mlil_ptr)),
146                true => None,
147            }
148        }
149    }
150
151    pub fn high_level_il(&self, full_ast: bool) -> Option<Ref<HighLevelILFunction>> {
152        unsafe {
153            let hlil_ptr = BNGetFlowGraphHighLevelILFunction(self.handle);
154            match hlil_ptr.is_null() {
155                false => Some(HighLevelILFunction::ref_from_raw(hlil_ptr, full_ast)),
156                true => None,
157            }
158        }
159    }
160
161    pub fn get_node(&self, i: usize) -> Option<Ref<FlowGraphNode>> {
162        let node_ptr = unsafe { BNGetFlowGraphNode(self.handle, i) };
163        if node_ptr.is_null() {
164            None
165        } else {
166            Some(unsafe { FlowGraphNode::ref_from_raw(node_ptr) })
167        }
168    }
169
170    pub fn get_node_count(&self) -> usize {
171        unsafe { BNGetFlowGraphNodeCount(self.handle) }
172    }
173
174    pub fn has_nodes(&self) -> bool {
175        unsafe { BNFlowGraphHasNodes(self.handle) }
176    }
177
178    /// Returns the graph size in width, height form.
179    pub fn size(&self) -> (i32, i32) {
180        let width = unsafe { BNGetFlowGraphWidth(self.handle) };
181        let height = unsafe { BNGetFlowGraphHeight(self.handle) };
182        (width, height)
183    }
184
185    /// Returns the graph margins between nodes.
186    pub fn node_margins(&self) -> (i32, i32) {
187        let horizontal = unsafe { BNGetHorizontalFlowGraphNodeMargin(self.handle) };
188        let vertical = unsafe { BNGetVerticalFlowGraphNodeMargin(self.handle) };
189        (horizontal, vertical)
190    }
191
192    /// Sets the graph margins between nodes.
193    pub fn set_node_margins(&self, horizontal: i32, vertical: i32) {
194        unsafe { BNSetFlowGraphNodeMargins(self.handle, horizontal, vertical) };
195    }
196
197    pub fn append(&self, node: &FlowGraphNode) -> usize {
198        unsafe { BNAddFlowGraphNode(self.handle, node.handle) }
199    }
200
201    pub fn replace(&self, index: usize, node: &FlowGraphNode) {
202        unsafe { BNReplaceFlowGraphNode(self.handle, index, node.handle) }
203    }
204
205    pub fn clear(&self) {
206        unsafe { BNClearFlowGraphNodes(self.handle) }
207    }
208
209    pub fn set_option(&self, option: FlowGraphOption, value: bool) {
210        unsafe { BNSetFlowGraphOption(self.handle, option, value) }
211    }
212
213    pub fn is_option_set(&self, option: FlowGraphOption) -> bool {
214        unsafe { BNIsFlowGraphOptionSet(self.handle, option) }
215    }
216
217    /// A list of the currently applied [`CoreRenderLayer`]'s
218    pub fn render_layers(&self) -> Array<CoreRenderLayer> {
219        let mut count: usize = 0;
220        unsafe {
221            let handles = BNGetFlowGraphRenderLayers(self.handle, &mut count);
222            Array::new(handles, count, ())
223        }
224    }
225
226    /// Add a Render Layer to be applied to this [`FlowGraph`].
227    ///
228    /// NOTE: Layers will be applied in the order in which they are added.
229    pub fn add_render_layer(&self, layer: &CoreRenderLayer) {
230        unsafe { BNAddFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
231    }
232
233    /// Remove a Render Layer from being applied to this [`FlowGraph`].
234    pub fn remove_render_layer(&self, layer: &CoreRenderLayer) {
235        unsafe { BNRemoveFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
236    }
237}
238
239unsafe impl RefCountable for FlowGraph {
240    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
241        Ref::new(Self {
242            handle: BNNewFlowGraphReference(handle.handle),
243        })
244    }
245
246    unsafe fn dec_ref(handle: &Self) {
247        BNFreeFlowGraph(handle.handle);
248    }
249}
250
251impl ToOwned for FlowGraph {
252    type Owned = Ref<Self>;
253
254    fn to_owned(&self) -> Self::Owned {
255        unsafe { RefCountable::inc_ref(self) }
256    }
257}