1use crate::basic_block::{BasicBlock, BasicBlockType};
4use crate::disassembly::DisassemblyTextLine;
5use crate::flowgraph::FlowGraph;
6use crate::function::{Function, NativeBlock};
7use crate::linear_view::{LinearDisassemblyLine, LinearDisassemblyLineType, LinearViewObject};
8use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
9use crate::string::IntoCStr;
10use binaryninjacore_sys::*;
11use std::ffi::c_void;
12use std::ptr::NonNull;
13
14#[repr(u32)]
16#[derive(Clone, Copy, Debug, PartialEq, Default)]
17pub enum RenderLayerDefaultState {
18 #[default]
22 Disabled = 0,
23 Enabled = 1,
25 AlwaysEnabled = 2,
27}
28
29impl From<BNRenderLayerDefaultEnableState> for RenderLayerDefaultState {
30 fn from(value: BNRenderLayerDefaultEnableState) -> Self {
31 match value {
32 BNRenderLayerDefaultEnableState::DisabledByDefaultRenderLayerDefaultEnableState => {
33 Self::Disabled
34 }
35 BNRenderLayerDefaultEnableState::EnabledByDefaultRenderLayerDefaultEnableState => {
36 Self::Enabled
37 }
38 BNRenderLayerDefaultEnableState::AlwaysEnabledRenderLayerDefaultEnableState => {
39 Self::AlwaysEnabled
40 }
41 }
42 }
43}
44
45impl From<RenderLayerDefaultState> for BNRenderLayerDefaultEnableState {
46 fn from(value: RenderLayerDefaultState) -> Self {
47 match value {
48 RenderLayerDefaultState::Disabled => {
49 Self::DisabledByDefaultRenderLayerDefaultEnableState
50 }
51 RenderLayerDefaultState::Enabled => Self::EnabledByDefaultRenderLayerDefaultEnableState,
52 RenderLayerDefaultState::AlwaysEnabled => {
53 Self::AlwaysEnabledRenderLayerDefaultEnableState
54 }
55 }
56 }
57}
58
59pub fn register_render_layer<T: RenderLayer>(
61 name: &str,
62 render_layer: T,
63 default_state: RenderLayerDefaultState,
64) -> (&'static mut T, CoreRenderLayer) {
65 let render_layer = Box::leak(Box::new(render_layer));
66 let mut callback = BNRenderLayerCallbacks {
67 context: render_layer as *mut _ as *mut c_void,
68 applyToFlowGraph: Some(cb_apply_to_flow_graph::<T>),
69 applyToLinearViewObject: Some(cb_apply_to_linear_view_object::<T>),
70 freeLines: Some(cb_free_lines),
71 };
72 let name = name.to_cstr();
73 let result =
74 unsafe { BNRegisterRenderLayer(name.as_ptr(), &mut callback, default_state.into()) };
75 let core = CoreRenderLayer::from_raw(NonNull::new(result).unwrap());
76 (render_layer, core)
77}
78
79pub trait RenderLayer: Sized {
80 fn apply_to_flow_graph(&self, graph: &mut FlowGraph) {
82 for node in &graph.nodes() {
83 if let Some(block) = node.basic_block(NativeBlock::new()) {
84 let new_lines = self.apply_to_block(&block, node.lines().to_vec());
85 node.set_lines(new_lines);
86 }
87 }
88 }
89
90 fn apply_to_linear_object(
92 &self,
93 object: &mut LinearViewObject,
94 _prev_object: Option<&mut LinearViewObject>,
95 _next_object: Option<&mut LinearViewObject>,
96 lines: Vec<LinearDisassemblyLine>,
97 ) -> Vec<LinearDisassemblyLine> {
98 let text_to_lines =
99 |function: &Function, block: &BasicBlock<NativeBlock>, text: DisassemblyTextLine| {
100 LinearDisassemblyLine {
101 ty: LinearDisassemblyLineType::CodeDisassemblyLineType,
102 view: Some(function.view()),
103 function: Some(function.to_owned()),
104 basic_block: Some(block.to_owned()),
105 contents: text,
106 }
107 };
108
109 let obj_ident = object.identifier();
111 if !lines.is_empty()
112 && (obj_ident.name.starts_with("HLIL") || obj_ident.name.starts_with("Language"))
113 {
114 let function = lines[0]
116 .function
117 .to_owned()
118 .expect("HLIL body has no function");
119 return self.apply_to_hlil_body(&function, lines);
120 }
121
122 let mut line_blocks: Vec<Vec<LinearDisassemblyLine>> = Vec::new();
126 for line in lines {
127 let Some(last_block) = line_blocks.last_mut() else {
128 line_blocks.push(vec![line]);
130 continue;
131 };
132
133 let Some(last_line) = last_block.last() else {
134 last_block.push(line);
136 continue;
137 };
138
139 if last_line.basic_block == line.basic_block && last_line.ty == line.ty {
142 last_block.push(line);
144 } else {
145 line_blocks.push(vec![line]);
147 }
148 }
149
150 line_blocks
151 .into_iter()
152 .filter_map(|line_block| {
153 let probe_line = line_block.first()?;
154 Some((probe_line.ty, probe_line.basic_block.to_owned(), line_block))
155 })
156 .flat_map(|(line_ty, basic_block, lines)| {
157 match (basic_block, line_ty) {
158 (Some(block), LinearDisassemblyLineType::CodeDisassemblyLineType) => {
159 let function = block.function();
161 let text_lines = lines.into_iter().map(|line| line.contents).collect();
162 let new_text_lines = self.apply_to_block(&block, text_lines);
163 new_text_lines
164 .into_iter()
165 .map(|line| text_to_lines(&function, &block, line))
166 .collect()
167 }
168 _ => {
169 self.apply_to_misc_lines(
171 object,
172 _prev_object.as_deref(),
173 _next_object.as_deref(),
174 lines,
175 )
176 }
177 }
178 })
179 .collect()
180 }
181
182 fn apply_to_disassembly_block(
186 &self,
187 _block: &BasicBlock<NativeBlock>,
188 lines: Vec<DisassemblyTextLine>,
189 ) -> Vec<DisassemblyTextLine> {
190 lines
191 }
192
193 fn apply_to_llil_block(
197 &self,
198 _block: &BasicBlock<NativeBlock>,
199 lines: Vec<DisassemblyTextLine>,
200 ) -> Vec<DisassemblyTextLine> {
201 lines
202 }
203
204 fn apply_to_mlil_block(
208 &self,
209 _block: &BasicBlock<NativeBlock>,
210 lines: Vec<DisassemblyTextLine>,
211 ) -> Vec<DisassemblyTextLine> {
212 lines
213 }
214
215 fn apply_to_hlil_block(
223 &self,
224 _block: &BasicBlock<NativeBlock>,
225 lines: Vec<DisassemblyTextLine>,
226 ) -> Vec<DisassemblyTextLine> {
227 lines
228 }
229
230 fn apply_to_hlil_body(
238 &self,
239 _function: &Function,
240 lines: Vec<LinearDisassemblyLine>,
241 ) -> Vec<LinearDisassemblyLine> {
242 lines
243 }
244
245 fn apply_to_misc_lines(
250 &self,
251 _object: &mut LinearViewObject,
252 _prev_object: Option<&LinearViewObject>,
253 _next_object: Option<&LinearViewObject>,
254 lines: Vec<LinearDisassemblyLine>,
255 ) -> Vec<LinearDisassemblyLine> {
256 lines
257 }
258
259 fn apply_to_block(
270 &self,
271 block: &BasicBlock<NativeBlock>,
272 lines: Vec<DisassemblyTextLine>,
273 ) -> Vec<DisassemblyTextLine> {
274 match block.block_type() {
275 BasicBlockType::Native => self.apply_to_disassembly_block(block, lines),
276 BasicBlockType::LowLevelIL => self.apply_to_llil_block(block, lines),
277 BasicBlockType::MediumLevelIL => self.apply_to_mlil_block(block, lines),
278 BasicBlockType::HighLevelIL => self.apply_to_hlil_block(block, lines),
279 }
280 }
281}
282
283#[repr(transparent)]
284pub struct CoreRenderLayer {
285 pub(crate) handle: NonNull<BNRenderLayer>,
286}
287
288impl CoreRenderLayer {
289 pub fn from_raw(handle: NonNull<BNRenderLayer>) -> Self {
290 Self { handle }
291 }
292
293 pub fn all() -> Array<CoreRenderLayer> {
294 let mut count = 0;
295 let result = unsafe { BNGetRenderLayerList(&mut count) };
296 unsafe { Array::new(result, count, ()) }
297 }
298
299 pub fn from_name(name: &str) -> Option<CoreRenderLayer> {
300 let name_raw = name.to_cstr();
301 let result = unsafe { BNGetRenderLayerByName(name_raw.as_ptr()) };
302 NonNull::new(result).map(Self::from_raw)
303 }
304
305 pub fn default_state(&self) -> RenderLayerDefaultState {
306 let raw = unsafe { BNGetRenderLayerDefaultEnableState(self.handle.as_ptr()) };
307 RenderLayerDefaultState::from(raw)
308 }
309
310 pub fn apply_to_flow_graph(&self, graph: &FlowGraph) {
311 unsafe { BNApplyRenderLayerToFlowGraph(self.handle.as_ptr(), graph.handle) }
312 }
313
314 pub fn apply_to_linear_view_object(
315 &self,
316 object: &LinearViewObject,
317 prev_object: Option<&LinearViewObject>,
318 next_object: Option<&LinearViewObject>,
319 lines: Vec<LinearDisassemblyLine>,
320 ) -> Vec<LinearDisassemblyLine> {
321 let mut lines_raw: Vec<_> = lines
322 .into_iter()
323 .map(LinearDisassemblyLine::into_raw)
325 .collect();
326
327 let prev_object_ptr = prev_object
328 .map(|o| o.handle)
329 .unwrap_or(std::ptr::null_mut());
330 let next_object_ptr = next_object
331 .map(|o| o.handle)
332 .unwrap_or(std::ptr::null_mut());
333
334 let mut new_lines = std::ptr::null_mut();
335 let mut new_line_count = 0;
336
337 unsafe {
338 BNApplyRenderLayerToLinearViewObject(
339 self.handle.as_ptr(),
340 object.handle,
341 prev_object_ptr,
342 next_object_ptr,
343 lines_raw.as_mut_ptr(),
344 lines_raw.len(),
345 &mut new_lines,
346 &mut new_line_count,
347 )
348 };
349
350 for line in lines_raw {
351 LinearDisassemblyLine::free_raw(line);
352 }
353
354 let raw: Array<LinearDisassemblyLine> =
355 unsafe { Array::new(new_lines, new_line_count, ()) };
356 raw.to_vec()
357 }
358}
359
360impl CoreArrayProvider for CoreRenderLayer {
361 type Raw = *mut BNRenderLayer;
362 type Context = ();
363 type Wrapped<'a> = Self;
364}
365
366unsafe impl CoreArrayProviderInner for CoreRenderLayer {
367 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
368 BNFreeRenderLayerList(raw)
369 }
370
371 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
372 let handle = NonNull::new(*raw).unwrap();
374 CoreRenderLayer::from_raw(handle)
375 }
376}
377
378unsafe extern "C" fn cb_apply_to_flow_graph<T: RenderLayer>(
379 ctxt: *mut c_void,
380 graph: *mut BNFlowGraph,
381) {
382 let ctxt: &mut T = &mut *(ctxt as *mut T);
383 let mut flow_graph = FlowGraph::from_raw(graph);
385 ctxt.apply_to_flow_graph(&mut flow_graph);
386}
387
388unsafe extern "C" fn cb_apply_to_linear_view_object<T: RenderLayer>(
389 ctxt: *mut c_void,
390 object: *mut BNLinearViewObject,
391 prev: *mut BNLinearViewObject,
392 next: *mut BNLinearViewObject,
393 in_lines: *mut BNLinearDisassemblyLine,
394 in_line_count: usize,
395 out_lines: *mut *mut BNLinearDisassemblyLine,
396 out_line_count: *mut usize,
397) {
398 let ctxt: &mut T = &mut *(ctxt as *mut T);
399 let mut object = LinearViewObject::from_raw(object);
401 let mut prev_object = if !prev.is_null() {
402 Some(LinearViewObject::from_raw(prev))
403 } else {
404 None
405 };
406 let mut next_object = if !next.is_null() {
407 Some(LinearViewObject::from_raw(next))
408 } else {
409 None
410 };
411
412 let raw_lines = std::slice::from_raw_parts(in_lines, in_line_count);
413 let lines: Vec<_> = raw_lines
415 .iter()
416 .map(|line| LinearDisassemblyLine::from_raw(line))
417 .collect();
418
419 let new_lines = ctxt.apply_to_linear_object(
420 &mut object,
421 prev_object.as_mut(),
422 next_object.as_mut(),
423 lines,
424 );
425
426 unsafe {
427 *out_line_count = new_lines.len();
428 let boxed_new_lines: Box<[_]> = new_lines
429 .into_iter()
430 .map(LinearDisassemblyLine::into_raw)
432 .collect();
433 *out_lines = Box::leak(boxed_new_lines).as_mut_ptr();
435 }
436}
437
438unsafe extern "C" fn cb_free_lines(
439 _ctxt: *mut c_void,
440 lines: *mut BNLinearDisassemblyLine,
441 line_count: usize,
442) {
443 let lines_ptr = std::ptr::slice_from_raw_parts_mut(lines, line_count);
444 let boxed_lines = Box::from_raw(lines_ptr);
445 for line in boxed_lines {
446 LinearDisassemblyLine::free_raw(line);
447 }
448}