binaryninja/flowgraph/
layout.rs1use crate::flowgraph::{FlowGraph, FlowGraphNode};
4use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable};
5use crate::string::{BnString, IntoCStr};
6use binaryninjacore_sys::*;
7use std::ffi::c_void;
8use std::ptr::NonNull;
9
10pub fn register_flowgraph_layout<C: FlowGraphLayout>(
12 name: &str,
13 custom: C,
14) -> (&'static C, CoreFlowGraphLayout) {
15 let renderer = Box::leak(Box::new(custom));
16 let mut callbacks = BNCustomFlowGraphLayout {
17 context: renderer as *mut _ as *mut c_void,
18 layout: Some(cb_layout::<C>),
19 };
20 let name_raw = name.to_cstr();
21 let result = unsafe { BNRegisterFlowGraphLayout(name_raw.as_ptr(), &mut callbacks) };
22 let core = unsafe { CoreFlowGraphLayout::from_raw(NonNull::new(result).unwrap()) };
23 (renderer, core)
24}
25
26pub trait FlowGraphLayout: Sized + Sync + Send + 'static {
28 fn layout(&self, graph: &FlowGraph, nodes: &[FlowGraphNode]) -> bool;
37}
38
39pub struct CoreFlowGraphLayout {
40 pub(crate) handle: NonNull<BNFlowGraphLayout>,
41}
42
43impl CoreFlowGraphLayout {
44 pub(crate) unsafe fn from_raw(handle: NonNull<BNFlowGraphLayout>) -> CoreFlowGraphLayout {
45 Self { handle }
46 }
47
48 pub fn all() -> Array<CoreFlowGraphLayout> {
49 let mut count = 0;
50 let result = unsafe { BNGetFlowGraphLayouts(&mut count) };
51 unsafe { Array::new(result, count, ()) }
52 }
53
54 pub fn by_name(name: &str) -> Option<CoreFlowGraphLayout> {
55 let name_raw = name.to_cstr();
56 let layout_ptr = unsafe { BNGetFlowGraphLayoutByName(name_raw.as_ptr()) };
57 Some(unsafe { CoreFlowGraphLayout::from_raw(NonNull::new(layout_ptr)?) })
58 }
59
60 pub fn name(&self) -> String {
61 unsafe { BnString::into_string(BNGetFlowGraphLayoutName(self.handle.as_ptr())) }
62 }
63}
64
65impl FlowGraphLayout for CoreFlowGraphLayout {
66 fn layout(&self, graph: &FlowGraph, nodes: &[FlowGraphNode]) -> bool {
67 unsafe {
69 BNFlowGraphLayoutLayout(
70 self.handle.as_ptr(),
71 graph.handle,
72 nodes.as_ptr() as *mut _,
73 nodes.len(),
74 )
75 }
76 }
77}
78
79impl CoreArrayProvider for CoreFlowGraphLayout {
80 type Raw = *mut BNFlowGraphLayout;
81 type Context = ();
82 type Wrapped<'a> = Self;
83}
84
85unsafe impl CoreArrayProviderInner for CoreFlowGraphLayout {
86 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
87 BNFreeFlowGraphLayoutList(raw)
88 }
89
90 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
91 let handle = NonNull::new(*raw).unwrap();
93 CoreFlowGraphLayout::from_raw(handle)
94 }
95}
96
97unsafe impl Send for CoreFlowGraphLayout {}
98unsafe impl Sync for CoreFlowGraphLayout {}
99
100pub struct FlowGraphLayoutRequest {
102 pub(crate) handle: NonNull<BNFlowGraphLayoutRequest>,
103}
104
105impl FlowGraphLayoutRequest {
106 pub(crate) unsafe fn ref_from_raw(
107 handle: NonNull<BNFlowGraphLayoutRequest>,
108 ) -> Ref<FlowGraphLayoutRequest> {
109 Ref::new(Self { handle })
110 }
111
112 pub fn graph(&self) -> Ref<FlowGraph> {
114 unsafe {
115 FlowGraph::ref_from_raw(BNGetGraphForFlowGraphLayoutRequest(self.handle.as_ptr()))
116 }
117 }
118
119 pub fn is_complete(&self) -> bool {
121 unsafe { BNIsFlowGraphLayoutRequestComplete(self.handle.as_ptr()) }
122 }
123
124 pub fn abort(&self) {
126 unsafe { BNAbortFlowGraphLayoutRequest(self.handle.as_ptr()) }
127 }
128}
129
130impl ToOwned for FlowGraphLayoutRequest {
131 type Owned = Ref<Self>;
132
133 fn to_owned(&self) -> Self::Owned {
134 unsafe { RefCountable::inc_ref(self) }
135 }
136}
137
138unsafe impl RefCountable for FlowGraphLayoutRequest {
139 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
140 Ref::new(Self {
141 handle: NonNull::new(BNNewFlowGraphLayoutRequestReference(handle.handle.as_ptr()))
142 .unwrap(),
143 })
144 }
145
146 unsafe fn dec_ref(handle: &Self) {
147 BNFreeFlowGraphLayoutRequest(handle.handle.as_ptr());
148 }
149}
150
151unsafe extern "C" fn cb_layout<C: FlowGraphLayout>(
152 ctxt: *mut c_void,
153 graph: *mut BNFlowGraph,
154 nodes: *mut *mut BNFlowGraphNode,
155 node_count: usize,
156) -> bool {
157 let ctxt = ctxt as *mut C;
158 let nodes_slice = core::slice::from_raw_parts(nodes, node_count);
159 let nodes: Vec<_> = nodes_slice
160 .iter()
161 .map(|ptr| unsafe { FlowGraphNode::from_raw(*ptr) })
162 .collect();
163 (*ctxt).layout(&FlowGraph::from_raw(graph), &nodes)
164}