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