binaryninja/
flowgraph.rs

1// Copyright 2021-2026 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 EdgePenStyle = BNEdgePenStyle;
36pub type ThemeColor = BNThemeColor;
37pub type FlowGraphOption = BNFlowGraphOption;
38
39#[derive(PartialEq, Eq, Hash)]
40pub struct FlowGraph {
41    pub(crate) handle: *mut BNFlowGraph,
42}
43
44impl FlowGraph {
45    pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraph) -> Self {
46        Self { handle: raw }
47    }
48
49    pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraph) -> Ref<Self> {
50        Ref::new(Self { handle: raw })
51    }
52
53    pub fn new() -> Ref<Self> {
54        unsafe { FlowGraph::ref_from_raw(BNCreateFlowGraph()) }
55    }
56
57    pub fn has_updates(&self) -> bool {
58        let query_mode = unsafe { BNFlowGraphUpdateQueryMode(self.handle) };
59        match query_mode {
60            true => unsafe { BNFlowGraphHasUpdates(self.handle) },
61            false => false,
62        }
63    }
64
65    pub fn update(&self) -> Option<Ref<Self>> {
66        let new_graph = unsafe { BNUpdateFlowGraph(self.handle) };
67        if new_graph.is_null() {
68            return None;
69        }
70        Some(unsafe { FlowGraph::ref_from_raw(new_graph) })
71    }
72
73    pub fn show(&self, title: &str) {
74        let raw_title = title.to_cstr();
75        match self.view() {
76            None => unsafe {
77                BNShowGraphReport(std::ptr::null_mut(), raw_title.as_ptr(), self.handle);
78            },
79            Some(view) => unsafe {
80                BNShowGraphReport(view.handle, raw_title.as_ptr(), self.handle);
81            },
82        }
83    }
84
85    /// Whether flow graph layout is complete.
86    pub fn is_layout_complete(&self) -> bool {
87        unsafe { BNIsFlowGraphLayoutComplete(self.handle) }
88    }
89
90    pub fn nodes(&self) -> Array<FlowGraphNode> {
91        let mut count: usize = 0;
92        let nodes_ptr = unsafe { BNGetFlowGraphNodes(self.handle, &mut count as *mut usize) };
93        unsafe { Array::new(nodes_ptr, count, ()) }
94    }
95
96    pub fn function(&self) -> Option<Ref<Function>> {
97        unsafe {
98            let func_ptr = BNGetFunctionForFlowGraph(self.handle);
99            match func_ptr.is_null() {
100                false => Some(Function::ref_from_raw(func_ptr)),
101                true => None,
102            }
103        }
104    }
105
106    pub fn set_function(&self, func: Option<&Function>) {
107        let func_ptr = func.map(|f| f.handle).unwrap_or(std::ptr::null_mut());
108        unsafe { BNSetFunctionForFlowGraph(self.handle, func_ptr) }
109    }
110
111    pub fn view(&self) -> Option<Ref<BinaryView>> {
112        unsafe {
113            let view_ptr = BNGetViewForFlowGraph(self.handle);
114            match view_ptr.is_null() {
115                false => Some(BinaryView::ref_from_raw(view_ptr)),
116                true => None,
117            }
118        }
119    }
120
121    pub fn set_view(&self, view: Option<&BinaryView>) {
122        let view_ptr = view.map(|v| v.handle).unwrap_or(std::ptr::null_mut());
123        unsafe { BNSetViewForFlowGraph(self.handle, view_ptr) }
124    }
125
126    pub fn lifted_il(&self) -> Option<Ref<LowLevelILRegularFunction>> {
127        self.function()?.lifted_il().ok()
128    }
129
130    pub fn low_level_il(&self) -> Option<Ref<LowLevelILRegularFunction>> {
131        unsafe {
132            let llil_ptr = BNGetFlowGraphLowLevelILFunction(self.handle);
133            match llil_ptr.is_null() {
134                false => Some(LowLevelILRegularFunction::ref_from_raw(llil_ptr)),
135                true => None,
136            }
137        }
138    }
139
140    pub fn medium_level_il(&self) -> Option<Ref<MediumLevelILFunction>> {
141        unsafe {
142            let mlil_ptr = BNGetFlowGraphMediumLevelILFunction(self.handle);
143            match mlil_ptr.is_null() {
144                false => Some(MediumLevelILFunction::ref_from_raw(mlil_ptr)),
145                true => None,
146            }
147        }
148    }
149
150    pub fn high_level_il(&self, full_ast: bool) -> Option<Ref<HighLevelILFunction>> {
151        unsafe {
152            let hlil_ptr = BNGetFlowGraphHighLevelILFunction(self.handle);
153            match hlil_ptr.is_null() {
154                false => Some(HighLevelILFunction::ref_from_raw(hlil_ptr, full_ast)),
155                true => None,
156            }
157        }
158    }
159
160    pub fn get_node(&self, i: usize) -> Option<Ref<FlowGraphNode>> {
161        let node_ptr = unsafe { BNGetFlowGraphNode(self.handle, i) };
162        if node_ptr.is_null() {
163            None
164        } else {
165            Some(unsafe { FlowGraphNode::ref_from_raw(node_ptr) })
166        }
167    }
168
169    pub fn get_node_count(&self) -> usize {
170        unsafe { BNGetFlowGraphNodeCount(self.handle) }
171    }
172
173    pub fn has_nodes(&self) -> bool {
174        unsafe { BNFlowGraphHasNodes(self.handle) }
175    }
176
177    /// Returns the graph size in width, height form.
178    pub fn size(&self) -> (i32, i32) {
179        let width = unsafe { BNGetFlowGraphWidth(self.handle) };
180        let height = unsafe { BNGetFlowGraphHeight(self.handle) };
181        (width, height)
182    }
183
184    /// Returns the graph margins between nodes.
185    pub fn node_margins(&self) -> (i32, i32) {
186        let horizontal = unsafe { BNGetHorizontalFlowGraphNodeMargin(self.handle) };
187        let vertical = unsafe { BNGetVerticalFlowGraphNodeMargin(self.handle) };
188        (horizontal, vertical)
189    }
190
191    /// Sets the graph margins between nodes.
192    pub fn set_node_margins(&self, horizontal: i32, vertical: i32) {
193        unsafe { BNSetFlowGraphNodeMargins(self.handle, horizontal, vertical) };
194    }
195
196    pub fn append(&self, node: &FlowGraphNode) -> usize {
197        unsafe { BNAddFlowGraphNode(self.handle, node.handle) }
198    }
199
200    pub fn replace(&self, index: usize, node: &FlowGraphNode) {
201        unsafe { BNReplaceFlowGraphNode(self.handle, index, node.handle) }
202    }
203
204    pub fn clear(&self) {
205        unsafe { BNClearFlowGraphNodes(self.handle) }
206    }
207
208    pub fn set_option(&self, option: FlowGraphOption, value: bool) {
209        unsafe { BNSetFlowGraphOption(self.handle, option, value) }
210    }
211
212    pub fn is_option_set(&self, option: FlowGraphOption) -> bool {
213        unsafe { BNIsFlowGraphOptionSet(self.handle, option) }
214    }
215
216    /// A list of the currently applied [`CoreRenderLayer`]'s
217    pub fn render_layers(&self) -> Array<CoreRenderLayer> {
218        let mut count: usize = 0;
219        unsafe {
220            let handles = BNGetFlowGraphRenderLayers(self.handle, &mut count);
221            Array::new(handles, count, ())
222        }
223    }
224
225    /// Add a Render Layer to be applied to this [`FlowGraph`].
226    ///
227    /// NOTE: Layers will be applied in the order in which they are added.
228    pub fn add_render_layer(&self, layer: &CoreRenderLayer) {
229        unsafe { BNAddFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
230    }
231
232    /// Remove a Render Layer from being applied to this [`FlowGraph`].
233    pub fn remove_render_layer(&self, layer: &CoreRenderLayer) {
234        unsafe { BNRemoveFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
235    }
236}
237
238unsafe impl RefCountable for FlowGraph {
239    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
240        Ref::new(Self {
241            handle: BNNewFlowGraphReference(handle.handle),
242        })
243    }
244
245    unsafe fn dec_ref(handle: &Self) {
246        BNFreeFlowGraph(handle.handle);
247    }
248}
249
250impl ToOwned for FlowGraph {
251    type Owned = Ref<Self>;
252
253    fn to_owned(&self) -> Self::Owned {
254        unsafe { RefCountable::inc_ref(self) }
255    }
256}