1use crate::high_level_il::HighLevelILFunction;
18use crate::low_level_il::LowLevelILRegularFunction;
19use crate::medium_level_il::MediumLevelILFunction;
20use crate::rc::*;
21use crate::render_layer::CoreRenderLayer;
22use binaryninjacore_sys::*;
23use std::ffi::c_void;
24use std::ptr::NonNull;
25use std::time::Duration;
26
27pub mod edge;
28pub mod layout;
29pub mod node;
30
31use crate::binary_view::BinaryView;
32use crate::flowgraph::layout::FlowGraphLayoutRequest;
33use crate::function::Function;
34use crate::string::IntoCStr;
35pub use edge::EdgeStyle;
36pub use edge::FlowGraphEdge;
37pub use node::FlowGraphNode;
38
39pub type EdgePenStyle = BNEdgePenStyle;
40pub type ThemeColor = BNThemeColor;
41pub type FlowGraphOption = BNFlowGraphOption;
42
43#[repr(transparent)]
44#[derive(PartialEq, Eq, Hash)]
45pub struct FlowGraph {
46 pub(crate) handle: *mut BNFlowGraph,
47}
48
49impl FlowGraph {
50 pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraph) -> Self {
51 Self { handle: raw }
52 }
53
54 pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraph) -> Ref<Self> {
55 Ref::new(Self { handle: raw })
56 }
57
58 pub fn new() -> Ref<Self> {
62 unsafe { FlowGraph::ref_from_raw(BNCreateFlowGraph()) }
63 }
64
65 pub fn request_layout<C: FnOnce() + Send + 'static>(
70 &self,
71 on_complete: C,
72 ) -> Ref<FlowGraphLayoutRequest> {
73 let context = Box::into_raw(Box::new(on_complete));
74 let request_raw_ptr = unsafe {
75 BNStartFlowGraphLayout(self.handle, context as *mut _, Some(cb_on_complete::<C>))
76 };
77 let request_ptr =
78 NonNull::new(request_raw_ptr).expect("BNStartFlowGraphLayout returned null");
79 unsafe { FlowGraphLayoutRequest::ref_from_raw(request_ptr) }
80 }
81
82 pub fn request_layout_and_wait(&self, timeout: Duration) -> bool {
88 let (tx, rx) = std::sync::mpsc::channel();
89 let _request = self.request_layout(move || {
91 let _ = tx.send(());
92 });
93 rx.recv_timeout(timeout).is_ok()
94 }
95
96 pub fn has_updates(&self) -> bool {
97 let query_mode = unsafe { BNFlowGraphUpdateQueryMode(self.handle) };
98 match query_mode {
99 true => unsafe { BNFlowGraphHasUpdates(self.handle) },
100 false => false,
101 }
102 }
103
104 pub fn update(&self) -> Option<Ref<Self>> {
105 let new_graph = unsafe { BNUpdateFlowGraph(self.handle) };
106 if new_graph.is_null() {
107 return None;
108 }
109 Some(unsafe { FlowGraph::ref_from_raw(new_graph) })
110 }
111
112 pub fn show(&self, title: &str) {
117 let raw_title = title.to_cstr();
118 match self.view() {
119 None => unsafe {
120 BNShowGraphReport(std::ptr::null_mut(), raw_title.as_ptr(), self.handle);
121 },
122 Some(view) => unsafe {
123 BNShowGraphReport(view.handle, raw_title.as_ptr(), self.handle);
124 },
125 }
126 }
127
128 pub fn is_layout_complete(&self) -> bool {
130 unsafe { BNIsFlowGraphLayoutComplete(self.handle) }
131 }
132
133 pub fn nodes(&self) -> Array<FlowGraphNode> {
139 let mut count: usize = 0;
140 let nodes_ptr = unsafe { BNGetFlowGraphNodes(self.handle, &mut count) };
141 unsafe { Array::new(nodes_ptr, count, ()) }
142 }
143
144 pub fn visible_nodes(
149 &self,
150 left: i32,
151 top: i32,
152 right: i32,
153 bottom: i32,
154 ) -> Array<FlowGraphNode> {
155 let mut count: usize = 0;
156 let nodes_ptr = unsafe {
157 BNGetFlowGraphNodesInRegion(self.handle, left, top, right, bottom, &mut count)
158 };
159 unsafe { Array::new(nodes_ptr, count, ()) }
160 }
161
162 pub fn function(&self) -> Option<Ref<Function>> {
163 unsafe {
164 let func_ptr = BNGetFunctionForFlowGraph(self.handle);
165 match func_ptr.is_null() {
166 false => Some(Function::ref_from_raw(func_ptr)),
167 true => None,
168 }
169 }
170 }
171
172 pub fn set_function(&self, func: Option<&Function>) {
173 let func_ptr = func.map(|f| f.handle).unwrap_or(std::ptr::null_mut());
174 unsafe { BNSetFunctionForFlowGraph(self.handle, func_ptr) }
175 }
176
177 pub fn view(&self) -> Option<Ref<BinaryView>> {
178 unsafe {
179 let view_ptr = BNGetViewForFlowGraph(self.handle);
180 match view_ptr.is_null() {
181 false => Some(BinaryView::ref_from_raw(view_ptr)),
182 true => None,
183 }
184 }
185 }
186
187 pub fn set_view(&self, view: Option<&BinaryView>) {
188 let view_ptr = view.map(|v| v.handle).unwrap_or(std::ptr::null_mut());
189 unsafe { BNSetViewForFlowGraph(self.handle, view_ptr) }
190 }
191
192 pub fn lifted_il(&self) -> Option<Ref<LowLevelILRegularFunction>> {
193 self.function()?.lifted_il().ok()
194 }
195
196 pub fn low_level_il(&self) -> Option<Ref<LowLevelILRegularFunction>> {
197 unsafe {
198 let llil_ptr = BNGetFlowGraphLowLevelILFunction(self.handle);
199 match llil_ptr.is_null() {
200 false => Some(LowLevelILRegularFunction::ref_from_raw(llil_ptr)),
201 true => None,
202 }
203 }
204 }
205
206 pub fn medium_level_il(&self) -> Option<Ref<MediumLevelILFunction>> {
207 unsafe {
208 let mlil_ptr = BNGetFlowGraphMediumLevelILFunction(self.handle);
209 match mlil_ptr.is_null() {
210 false => Some(MediumLevelILFunction::ref_from_raw(mlil_ptr)),
211 true => None,
212 }
213 }
214 }
215
216 pub fn high_level_il(&self, full_ast: bool) -> Option<Ref<HighLevelILFunction>> {
217 unsafe {
218 let hlil_ptr = BNGetFlowGraphHighLevelILFunction(self.handle);
219 match hlil_ptr.is_null() {
220 false => Some(HighLevelILFunction::ref_from_raw(hlil_ptr, full_ast)),
221 true => None,
222 }
223 }
224 }
225
226 pub fn get_node(&self, i: usize) -> Option<Ref<FlowGraphNode>> {
227 let node_ptr = unsafe { BNGetFlowGraphNode(self.handle, i) };
228 if node_ptr.is_null() {
229 None
230 } else {
231 Some(unsafe { FlowGraphNode::ref_from_raw(node_ptr) })
232 }
233 }
234
235 pub fn get_node_count(&self) -> usize {
236 unsafe { BNGetFlowGraphNodeCount(self.handle) }
237 }
238
239 pub fn has_nodes(&self) -> bool {
240 unsafe { BNFlowGraphHasNodes(self.handle) }
241 }
242
243 pub fn size(&self) -> (i32, i32) {
245 let width = unsafe { BNGetFlowGraphWidth(self.handle) };
246 let height = unsafe { BNGetFlowGraphHeight(self.handle) };
247 (width, height)
248 }
249
250 pub fn set_size(&self, width: i32, height: i32) {
252 unsafe { BNFlowGraphSetWidth(self.handle, width) };
253 unsafe { BNFlowGraphSetHeight(self.handle, height) };
254 }
255
256 pub fn node_margins(&self) -> (i32, i32) {
258 let horizontal = unsafe { BNGetHorizontalFlowGraphNodeMargin(self.handle) };
259 let vertical = unsafe { BNGetVerticalFlowGraphNodeMargin(self.handle) };
260 (horizontal, vertical)
261 }
262
263 pub fn set_node_margins(&self, horizontal: i32, vertical: i32) {
265 unsafe { BNSetFlowGraphNodeMargins(self.handle, horizontal, vertical) };
266 }
267
268 pub fn is_node_valid(&self, node: &FlowGraphNode) -> bool {
269 unsafe { BNIsNodeValidForFlowGraph(self.handle, node.handle) }
270 }
271
272 pub fn append(&self, node: &FlowGraphNode) -> usize {
276 unsafe { BNAddFlowGraphNode(self.handle, node.handle) }
277 }
278
279 pub fn replace(&self, index: usize, node: &FlowGraphNode) {
283 unsafe { BNReplaceFlowGraphNode(self.handle, index, node.handle) }
284 }
285
286 pub fn clear(&self) {
290 unsafe { BNClearFlowGraphNodes(self.handle) }
291 }
292
293 pub fn set_option(&self, option: FlowGraphOption, value: bool) {
294 unsafe { BNSetFlowGraphOption(self.handle, option, value) }
295 }
296
297 pub fn is_option_set(&self, option: FlowGraphOption) -> bool {
298 unsafe { BNIsFlowGraphOptionSet(self.handle, option) }
299 }
300
301 pub fn render_layers(&self) -> Array<CoreRenderLayer> {
303 let mut count: usize = 0;
304 unsafe {
305 let handles = BNGetFlowGraphRenderLayers(self.handle, &mut count);
306 Array::new(handles, count, ())
307 }
308 }
309
310 pub fn add_render_layer(&self, layer: &CoreRenderLayer) {
314 unsafe { BNAddFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
315 }
316
317 pub fn remove_render_layer(&self, layer: &CoreRenderLayer) {
319 unsafe { BNRemoveFlowGraphRenderLayer(self.handle, layer.handle.as_ptr()) };
320 }
321}
322
323unsafe impl RefCountable for FlowGraph {
324 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
325 Ref::new(Self {
326 handle: BNNewFlowGraphReference(handle.handle),
327 })
328 }
329
330 unsafe fn dec_ref(handle: &Self) {
331 BNFreeFlowGraph(handle.handle);
332 }
333}
334
335impl ToOwned for FlowGraph {
336 type Owned = Ref<Self>;
337
338 fn to_owned(&self) -> Self::Owned {
339 unsafe { RefCountable::inc_ref(self) }
340 }
341}
342
343unsafe extern "C" fn cb_on_complete<C: FnOnce()>(ctxt: *mut c_void) {
344 let ctxt: Box<C> = unsafe { Box::from_raw(ctxt as *mut C) };
347 ctxt();
348}