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 function: Some(function.to_owned()),
103 basic_block: Some(block.to_owned()),
104 contents: text,
105 }
106 };
107
108 let obj_ident = object.identifier();
110 if !lines.is_empty()
111 && (obj_ident.name.starts_with("HLIL") || obj_ident.name.starts_with("Language"))
112 {
113 let function = lines[0]
115 .function
116 .to_owned()
117 .expect("HLIL body has no function");
118 return self.apply_to_hlil_body(&function, lines);
119 }
120
121 let mut line_blocks: Vec<Vec<LinearDisassemblyLine>> = Vec::new();
125 for line in lines {
126 let Some(last_block) = line_blocks.last_mut() else {
127 line_blocks.push(vec![line]);
129 continue;
130 };
131
132 let Some(last_line) = last_block.last() else {
133 last_block.push(line);
135 continue;
136 };
137
138 if last_line.basic_block == line.basic_block && last_line.ty == line.ty {
141 last_block.push(line);
143 } else {
144 line_blocks.push(vec![line]);
146 }
147 }
148
149 line_blocks
150 .into_iter()
151 .filter_map(|line_block| {
152 let probe_line = line_block.first()?;
153 Some((probe_line.ty, probe_line.basic_block.to_owned(), line_block))
154 })
155 .flat_map(|(line_ty, basic_block, lines)| {
156 match (basic_block, line_ty) {
157 (Some(block), LinearDisassemblyLineType::CodeDisassemblyLineType) => {
158 let function = block.function();
160 let text_lines = lines.into_iter().map(|line| line.contents).collect();
161 let new_text_lines = self.apply_to_block(&block, text_lines);
162 new_text_lines
163 .into_iter()
164 .map(|line| text_to_lines(&function, &block, line))
165 .collect()
166 }
167 _ => {
168 self.apply_to_misc_lines(
170 object,
171 _prev_object.as_deref(),
172 _next_object.as_deref(),
173 lines,
174 )
175 }
176 }
177 })
178 .collect()
179 }
180
181 fn apply_to_disassembly_block(
185 &self,
186 _block: &BasicBlock<NativeBlock>,
187 lines: Vec<DisassemblyTextLine>,
188 ) -> Vec<DisassemblyTextLine> {
189 lines
190 }
191
192 fn apply_to_llil_block(
196 &self,
197 _block: &BasicBlock<NativeBlock>,
198 lines: Vec<DisassemblyTextLine>,
199 ) -> Vec<DisassemblyTextLine> {
200 lines
201 }
202
203 fn apply_to_mlil_block(
207 &self,
208 _block: &BasicBlock<NativeBlock>,
209 lines: Vec<DisassemblyTextLine>,
210 ) -> Vec<DisassemblyTextLine> {
211 lines
212 }
213
214 fn apply_to_hlil_block(
222 &self,
223 _block: &BasicBlock<NativeBlock>,
224 lines: Vec<DisassemblyTextLine>,
225 ) -> Vec<DisassemblyTextLine> {
226 lines
227 }
228
229 fn apply_to_hlil_body(
237 &self,
238 _function: &Function,
239 lines: Vec<LinearDisassemblyLine>,
240 ) -> Vec<LinearDisassemblyLine> {
241 lines
242 }
243
244 fn apply_to_misc_lines(
249 &self,
250 _object: &mut LinearViewObject,
251 _prev_object: Option<&LinearViewObject>,
252 _next_object: Option<&LinearViewObject>,
253 lines: Vec<LinearDisassemblyLine>,
254 ) -> Vec<LinearDisassemblyLine> {
255 lines
256 }
257
258 fn apply_to_block(
269 &self,
270 block: &BasicBlock<NativeBlock>,
271 lines: Vec<DisassemblyTextLine>,
272 ) -> Vec<DisassemblyTextLine> {
273 match block.block_type() {
274 BasicBlockType::Native => self.apply_to_disassembly_block(block, lines),
275 BasicBlockType::LowLevelIL => self.apply_to_llil_block(block, lines),
276 BasicBlockType::MediumLevelIL => self.apply_to_mlil_block(block, lines),
277 BasicBlockType::HighLevelIL => self.apply_to_hlil_block(block, lines),
278 }
279 }
280}
281
282#[repr(transparent)]
283pub struct CoreRenderLayer {
284 pub(crate) handle: NonNull<BNRenderLayer>,
285}
286
287impl CoreRenderLayer {
288 pub fn from_raw(handle: NonNull<BNRenderLayer>) -> Self {
289 Self { handle }
290 }
291
292 pub fn all() -> Array<CoreRenderLayer> {
293 let mut count = 0;
294 let result = unsafe { BNGetRenderLayerList(&mut count) };
295 unsafe { Array::new(result, count, ()) }
296 }
297
298 pub fn from_name(name: &str) -> Option<CoreRenderLayer> {
299 let name_raw = name.to_cstr();
300 let result = unsafe { BNGetRenderLayerByName(name_raw.as_ptr()) };
301 NonNull::new(result).map(Self::from_raw)
302 }
303
304 pub fn default_state(&self) -> RenderLayerDefaultState {
305 let raw = unsafe { BNGetRenderLayerDefaultEnableState(self.handle.as_ptr()) };
306 RenderLayerDefaultState::from(raw)
307 }
308
309 pub fn apply_to_flow_graph(&self, graph: &FlowGraph) {
310 unsafe { BNApplyRenderLayerToFlowGraph(self.handle.as_ptr(), graph.handle) }
311 }
312
313 pub fn apply_to_linear_view_object(
314 &self,
315 object: &LinearViewObject,
316 prev_object: Option<&LinearViewObject>,
317 next_object: Option<&LinearViewObject>,
318 lines: Vec<LinearDisassemblyLine>,
319 ) -> Vec<LinearDisassemblyLine> {
320 let mut lines_raw: Vec<_> = lines
321 .into_iter()
322 .map(LinearDisassemblyLine::into_raw)
324 .collect();
325
326 let prev_object_ptr = prev_object
327 .map(|o| o.handle)
328 .unwrap_or(std::ptr::null_mut());
329 let next_object_ptr = next_object
330 .map(|o| o.handle)
331 .unwrap_or(std::ptr::null_mut());
332
333 let mut new_lines = std::ptr::null_mut();
334 let mut new_line_count = 0;
335
336 unsafe {
337 BNApplyRenderLayerToLinearViewObject(
338 self.handle.as_ptr(),
339 object.handle,
340 prev_object_ptr,
341 next_object_ptr,
342 lines_raw.as_mut_ptr(),
343 lines_raw.len(),
344 &mut new_lines,
345 &mut new_line_count,
346 )
347 };
348
349 for line in lines_raw {
350 LinearDisassemblyLine::free_raw(line);
351 }
352
353 let raw: Array<LinearDisassemblyLine> =
354 unsafe { Array::new(new_lines, new_line_count, ()) };
355 raw.to_vec()
356 }
357}
358
359impl CoreArrayProvider for CoreRenderLayer {
360 type Raw = *mut BNRenderLayer;
361 type Context = ();
362 type Wrapped<'a> = Self;
363}
364
365unsafe impl CoreArrayProviderInner for CoreRenderLayer {
366 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
367 BNFreeRenderLayerList(raw)
368 }
369
370 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
371 let handle = NonNull::new(*raw).unwrap();
373 CoreRenderLayer::from_raw(handle)
374 }
375}
376
377unsafe extern "C" fn cb_apply_to_flow_graph<T: RenderLayer>(
378 ctxt: *mut c_void,
379 graph: *mut BNFlowGraph,
380) {
381 let ctxt: &mut T = &mut *(ctxt as *mut T);
382 let mut flow_graph = FlowGraph::from_raw(graph);
384 ctxt.apply_to_flow_graph(&mut flow_graph);
385}
386
387unsafe extern "C" fn cb_apply_to_linear_view_object<T: RenderLayer>(
388 ctxt: *mut c_void,
389 object: *mut BNLinearViewObject,
390 prev: *mut BNLinearViewObject,
391 next: *mut BNLinearViewObject,
392 in_lines: *mut BNLinearDisassemblyLine,
393 in_line_count: usize,
394 out_lines: *mut *mut BNLinearDisassemblyLine,
395 out_line_count: *mut usize,
396) {
397 let ctxt: &mut T = &mut *(ctxt as *mut T);
398 let mut object = LinearViewObject::from_raw(object);
400 let mut prev_object = if !prev.is_null() {
401 Some(LinearViewObject::from_raw(prev))
402 } else {
403 None
404 };
405 let mut next_object = if !next.is_null() {
406 Some(LinearViewObject::from_raw(next))
407 } else {
408 None
409 };
410
411 let raw_lines = std::slice::from_raw_parts(in_lines, in_line_count);
412 let lines: Vec<_> = raw_lines
414 .iter()
415 .map(|line| LinearDisassemblyLine::from_raw(line))
416 .collect();
417
418 let new_lines = ctxt.apply_to_linear_object(
419 &mut object,
420 prev_object.as_mut(),
421 next_object.as_mut(),
422 lines,
423 );
424
425 unsafe {
426 *out_line_count = new_lines.len();
427 let boxed_new_lines: Box<[_]> = new_lines
428 .into_iter()
429 .map(LinearDisassemblyLine::into_raw)
431 .collect();
432 *out_lines = Box::leak(boxed_new_lines).as_mut_ptr();
434 }
435}
436
437unsafe extern "C" fn cb_free_lines(
438 _ctxt: *mut c_void,
439 lines: *mut BNLinearDisassemblyLine,
440 line_count: usize,
441) {
442 let lines_ptr = std::ptr::slice_from_raw_parts_mut(lines, line_count);
443 let boxed_lines = Box::from_raw(lines_ptr);
444 for line in boxed_lines {
445 LinearDisassemblyLine::free_raw(line);
446 }
447}