1use std::ffi::{c_char, c_void};
2use std::mem::MaybeUninit;
3use std::ptr::NonNull;
4
5use binaryninjacore_sys::*;
6
7use crate::architecture::{Architecture, CoreArchitecture};
8use crate::basic_block::{BasicBlock, BlockContext};
9use crate::binary_view::BinaryView;
10use crate::disassembly::{DisassemblySettings, DisassemblyTextLine};
11use crate::function::{Function, HighlightColor};
12use crate::high_level_il::token_emitter::HighLevelILTokenEmitter;
13use crate::high_level_il::{HighLevelExpressionIndex, HighLevelILFunction};
14use crate::line_formatter::CoreLineFormatter;
15use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable};
16use crate::string::{BnString, IntoCStr};
17use crate::types::{CoreTypeParser, CoreTypePrinter};
18
19pub type InstructionTextTokenContext = BNInstructionTextTokenContext;
20pub type ScopeType = BNScopeType;
21pub type BraceRequirement = BNBraceRequirement;
22pub type SymbolDisplayType = BNSymbolDisplayType;
23pub type OperatorPrecedence = BNOperatorPrecedence;
24pub type SymbolDisplayResult = BNSymbolDisplayResult;
25
26pub fn register_language_representation_function_type<
27 C: LanguageRepresentationFunctionType,
28 F: FnOnce(CoreLanguageRepresentationFunctionType) -> C,
29>(
30 creator: F,
31 name: &str,
32) -> CoreLanguageRepresentationFunctionType {
33 let custom = Box::leak(Box::new(MaybeUninit::uninit()));
34 let mut callbacks = BNCustomLanguageRepresentationFunctionType {
35 context: custom as *mut MaybeUninit<C> as *mut c_void,
36 create: Some(cb_create::<C>),
37 isValid: Some(cb_is_valid::<C>),
38 getTypePrinter: Some(cb_get_type_printer::<C>),
39 getTypeParser: Some(cb_get_type_parser::<C>),
40 getLineFormatter: Some(cb_get_line_formatter::<C>),
41 getFunctionTypeTokens: Some(cb_get_function_type_tokens::<C>),
42 freeLines: Some(cb_free_lines),
43 };
44 let name = name.to_cstr();
45 let core =
46 unsafe { BNRegisterLanguageRepresentationFunctionType(name.as_ptr(), &mut callbacks) };
47 let core =
48 unsafe { CoreLanguageRepresentationFunctionType::from_raw(NonNull::new(core).unwrap()) };
49 custom.write(creator(core));
50 core
51}
52
53pub trait LanguageRepresentationFunction: Send + Sync {
54 fn on_token_emitter_init(&self, tokens: &HighLevelILTokenEmitter);
55
56 fn expr_text(
57 &self,
58 il: &HighLevelILFunction,
59 expr_index: HighLevelExpressionIndex,
60 tokens: &HighLevelILTokenEmitter,
61 settings: &DisassemblySettings,
62 as_full_ast: bool,
63 precedence: OperatorPrecedence,
64 statement: bool,
65 );
66
67 fn begin_lines(
68 &self,
69 il: &HighLevelILFunction,
70 expr_index: HighLevelExpressionIndex,
71 tokens: &HighLevelILTokenEmitter,
72 );
73
74 fn end_lines(
75 &self,
76 il: &HighLevelILFunction,
77 expr_index: HighLevelExpressionIndex,
78 tokens: &HighLevelILTokenEmitter,
79 );
80
81 fn comment_start_string(&self) -> &str;
82
83 fn comment_end_string(&self) -> &str;
84
85 fn annotation_start_string(&self) -> &str;
86
87 fn annotation_end_string(&self) -> &str;
88}
89
90pub trait LanguageRepresentationFunctionType: Send + Sync {
91 fn create(
92 &self,
93 arch: &CoreArchitecture,
94 owner: &Function,
95 high_level_il: &HighLevelILFunction,
96 ) -> Ref<CoreLanguageRepresentationFunction>;
97
98 fn is_valid(&self, view: &BinaryView) -> bool;
99
100 fn type_printer(&self) -> Option<CoreTypePrinter> {
101 None
102 }
103
104 fn type_parser(&self) -> Option<CoreTypeParser> {
105 None
106 }
107
108 fn line_formatter(&self) -> Option<CoreLineFormatter> {
109 None
110 }
111
112 fn function_type_tokens(
113 &self,
114 func: &Function,
115 settings: &DisassemblySettings,
116 ) -> Vec<DisassemblyTextLine>;
117}
118
119#[repr(transparent)]
121#[derive(Clone, Copy)]
122pub struct CoreLanguageRepresentationFunctionType {
123 handle: NonNull<BNLanguageRepresentationFunctionType>,
124}
125
126unsafe impl Send for CoreLanguageRepresentationFunctionType {}
127unsafe impl Sync for CoreLanguageRepresentationFunctionType {}
128
129impl CoreLanguageRepresentationFunctionType {
130 pub(crate) unsafe fn from_raw(handle: NonNull<BNLanguageRepresentationFunctionType>) -> Self {
131 Self { handle }
132 }
133
134 pub(crate) fn as_raw(&self) -> *mut BNLanguageRepresentationFunctionType {
135 self.handle.as_ptr()
136 }
137
138 pub fn from_name(name: &str) -> Option<Self> {
139 let name = name.to_cstr();
140 let result = unsafe { BNGetLanguageRepresentationFunctionTypeByName(name.as_ptr()) };
141 NonNull::new(result).map(|handle| unsafe { Self::from_raw(handle) })
142 }
143
144 pub fn all() -> Array<Self> {
145 let mut count = 0;
146 let result = unsafe { BNGetLanguageRepresentationFunctionTypeList(&mut count) };
147 unsafe { Array::new(result, count, ()) }
148 }
149
150 pub fn tokens(
151 &self,
152 func: &Function,
153 settings: &DisassemblySettings,
154 ) -> Array<DisassemblyTextLine> {
155 let mut count = 0;
156 let result = unsafe {
157 BNGetLanguageRepresentationFunctionTypeFunctionTypeTokens(
158 self.handle.as_ptr(),
159 func.handle,
160 settings.handle,
161 &mut count,
162 )
163 };
164 unsafe { Array::new(result, count, ()) }
165 }
166
167 pub fn name(&self) -> BnString {
168 unsafe {
169 BnString::from_raw(BNGetLanguageRepresentationFunctionTypeName(
170 self.handle.as_ptr(),
171 ))
172 }
173 }
174
175 pub fn create(&self, func: &Function) -> Ref<CoreLanguageRepresentationFunction> {
176 let repr_func = unsafe {
177 BNCreateLanguageRepresentationFunction(
178 self.handle.as_ptr(),
179 func.arch().handle,
180 func.handle,
181 match func.high_level_il(false) {
182 Ok(hlil) => hlil.handle,
183 Err(_) => std::ptr::null_mut(),
184 },
185 )
186 };
187
188 unsafe {
189 CoreLanguageRepresentationFunction::ref_from_raw(NonNull::new(repr_func).unwrap())
190 }
191 }
192
193 pub fn is_valid(&self, view: &BinaryView) -> bool {
194 unsafe { BNIsLanguageRepresentationFunctionTypeValid(self.handle.as_ptr(), view.handle) }
195 }
196
197 pub fn printer(&self) -> CoreTypePrinter {
198 let type_printer =
199 unsafe { BNGetLanguageRepresentationFunctionTypePrinter(self.handle.as_ptr()) };
200 unsafe { CoreTypePrinter::from_raw(NonNull::new(type_printer).unwrap()) }
201 }
202
203 pub fn parser(&self) -> CoreTypeParser {
204 let type_parser =
205 unsafe { BNGetLanguageRepresentationFunctionTypeParser(self.handle.as_ptr()) };
206 unsafe { CoreTypeParser::from_raw(NonNull::new(type_parser).unwrap()) }
207 }
208
209 pub fn line_formatter(&self) -> CoreLineFormatter {
210 let formatter =
211 unsafe { BNGetLanguageRepresentationFunctionTypeLineFormatter(self.handle.as_ptr()) };
212 CoreLineFormatter::from_raw(NonNull::new(formatter).unwrap())
213 }
214}
215
216impl CoreArrayProvider for CoreLanguageRepresentationFunctionType {
217 type Raw = *mut BNLanguageRepresentationFunctionType;
218 type Context = ();
219 type Wrapped<'a> = &'a CoreLanguageRepresentationFunctionType;
220}
221
222unsafe impl CoreArrayProviderInner for CoreLanguageRepresentationFunctionType {
223 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
224 BNFreeLanguageRepresentationFunctionTypeList(raw)
225 }
226
227 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
228 std::mem::transmute::<
231 &*mut BNLanguageRepresentationFunctionType,
232 &CoreLanguageRepresentationFunctionType,
233 >(raw)
234 }
235}
236
237pub struct CoreLanguageRepresentationFunction {
238 handle: NonNull<BNLanguageRepresentationFunction>,
239}
240
241impl CoreLanguageRepresentationFunction {
242 pub(crate) unsafe fn ref_from_raw(
243 handle: NonNull<BNLanguageRepresentationFunction>,
244 ) -> Ref<Self> {
245 unsafe { Ref::new(Self { handle }) }
246 }
247
248 pub fn new<C: LanguageRepresentationFunction, A: Architecture>(
249 repr_type: &CoreLanguageRepresentationFunctionType,
250 repr_context: C,
251 arch: &A,
252 func: &Function,
253 high_level_il: &HighLevelILFunction,
254 ) -> Ref<Self> {
255 let core_arch: &CoreArchitecture = arch.as_ref();
256 let context: &mut C = Box::leak(Box::new(repr_context));
257 let mut callbacks = BNCustomLanguageRepresentationFunction {
258 context: context as *mut C as *mut c_void,
259 freeObject: Some(cb_free_object::<C>),
260 externalRefTaken: Some(cb_external_ref_taken::<C>),
261 externalRefReleased: Some(cb_external_ref_released::<C>),
262 initTokenEmitter: Some(cb_init_token_emitter::<C>),
263 getExprText: Some(cb_get_expr_text::<C>),
264 beginLines: Some(cb_begin_lines::<C>),
265 endLines: Some(cb_end_lines::<C>),
266 getCommentStartString: Some(cb_get_comment_start_string::<C>),
267 getCommentEndString: Some(cb_get_comment_end_string::<C>),
268 getAnnotationStartString: Some(cb_get_annotation_start_string::<C>),
269 getAnnotationEndString: Some(cb_get_annotation_end_string::<C>),
270 };
271 let handle = unsafe {
272 BNCreateCustomLanguageRepresentationFunction(
273 repr_type.as_raw(),
274 core_arch.handle,
275 func.handle,
276 high_level_il.handle,
277 &mut callbacks,
278 )
279 };
280 unsafe { Self::ref_from_raw(NonNull::new(handle).unwrap()) }
281 }
282
283 pub fn expr_text(
284 &self,
285 il: &HighLevelILFunction,
286 expr_index: HighLevelExpressionIndex,
287 settings: &DisassemblySettings,
288 as_full_ast: bool,
289 precedence: OperatorPrecedence,
290 statement: bool,
291 ) -> Array<DisassemblyTextLine> {
292 let mut count = 0;
293 let result = unsafe {
294 BNGetLanguageRepresentationFunctionExprText(
295 self.handle.as_ptr(),
296 il.handle,
297 expr_index.0,
298 settings.handle,
299 as_full_ast,
300 precedence,
301 statement,
302 &mut count,
303 )
304 };
305 unsafe { Array::new(result, count, ()) }
306 }
307
308 pub fn linear_lines(
309 &self,
310 il: &HighLevelILFunction,
311 expr_index: HighLevelExpressionIndex,
312 settings: &DisassemblySettings,
313 as_full_ast: bool,
314 ) -> Array<DisassemblyTextLine> {
315 let mut count = 0;
316 let result = unsafe {
317 BNGetLanguageRepresentationFunctionLinearLines(
318 self.handle.as_ptr(),
319 il.handle,
320 expr_index.0,
321 settings.handle,
322 as_full_ast,
323 &mut count,
324 )
325 };
326 unsafe { Array::new(result, count, ()) }
327 }
328
329 pub fn block_lines<C: BlockContext>(
330 &self,
331 block: &BasicBlock<C>,
332 settings: &DisassemblySettings,
333 ) -> Array<DisassemblyTextLine> {
334 let mut count = 0;
335 let result = unsafe {
336 BNGetLanguageRepresentationFunctionBlockLines(
337 self.handle.as_ptr(),
338 block.handle,
339 settings.handle,
340 &mut count,
341 )
342 };
343 unsafe { Array::new(result, count, ()) }
344 }
345
346 pub fn highlight<C: BlockContext>(&self, block: &BasicBlock<C>) -> HighlightColor {
347 let result = unsafe {
348 BNGetLanguageRepresentationFunctionHighlight(self.handle.as_ptr(), block.handle)
349 };
350 result.into()
351 }
352
353 pub fn get_type(&self) -> CoreLanguageRepresentationFunctionType {
354 let repr_type = unsafe { BNGetLanguageRepresentationType(self.handle.as_ptr()) };
355 unsafe {
356 CoreLanguageRepresentationFunctionType::from_raw(NonNull::new(repr_type).unwrap())
357 }
358 }
359
360 pub fn arch(&self) -> CoreArchitecture {
361 let arch = unsafe { BNGetLanguageRepresentationArchitecture(self.handle.as_ptr()) };
362 unsafe { CoreArchitecture::from_raw(arch) }
363 }
364
365 pub fn owner_function(&self) -> Ref<Function> {
366 let func = unsafe { BNGetLanguageRepresentationOwnerFunction(self.handle.as_ptr()) };
367 unsafe { Function::ref_from_raw(func) }
368 }
369
370 pub fn hlil(&self) -> Ref<HighLevelILFunction> {
371 let hlil = unsafe { BNGetLanguageRepresentationILFunction(self.handle.as_ptr()) };
372 unsafe { HighLevelILFunction::ref_from_raw(hlil, false) }
373 }
374
375 pub fn comment_start_string(&self) -> BnString {
376 unsafe {
377 BnString::from_raw(BNGetLanguageRepresentationFunctionCommentStartString(
378 self.handle.as_ptr(),
379 ))
380 }
381 }
382
383 pub fn comment_end_string(&self) -> BnString {
384 unsafe {
385 BnString::from_raw(BNGetLanguageRepresentationFunctionCommentEndString(
386 self.handle.as_ptr(),
387 ))
388 }
389 }
390
391 pub fn annotation_start_string(&self) -> BnString {
392 unsafe {
393 BnString::from_raw(BNGetLanguageRepresentationFunctionAnnotationStartString(
394 self.handle.as_ptr(),
395 ))
396 }
397 }
398
399 pub fn annotation_end_string(&self) -> BnString {
400 unsafe {
401 BnString::from_raw(BNGetLanguageRepresentationFunctionAnnotationEndString(
402 self.handle.as_ptr(),
403 ))
404 }
405 }
406}
407
408unsafe impl RefCountable for CoreLanguageRepresentationFunction {
409 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
410 Self::ref_from_raw(
411 NonNull::new(BNNewLanguageRepresentationFunctionReference(
412 handle.handle.as_ptr(),
413 ))
414 .unwrap(),
415 )
416 }
417
418 unsafe fn dec_ref(handle: &Self) {
419 BNFreeLanguageRepresentationFunction(handle.handle.as_ptr())
420 }
421}
422
423impl ToOwned for CoreLanguageRepresentationFunction {
424 type Owned = Ref<Self>;
425
426 fn to_owned(&self) -> Self::Owned {
427 unsafe { <Self as RefCountable>::inc_ref(self) }
428 }
429}
430
431unsafe extern "C" fn cb_create<C: LanguageRepresentationFunctionType>(
432 ctxt: *mut c_void,
433 arch: *mut BNArchitecture,
434 owner: *mut BNFunction,
435 high_level_il: *mut BNHighLevelILFunction,
436) -> *mut BNLanguageRepresentationFunction {
437 let ctxt = ctxt as *mut C;
438 let arch = CoreArchitecture::from_raw(arch);
439 let owner = Function::from_raw(owner);
440 let high_level_il = HighLevelILFunction {
441 full_ast: false,
442 handle: high_level_il,
443 };
444 let result = (*ctxt).create(&arch, &owner, &high_level_il);
445 Ref::into_raw(result).handle.as_ptr()
446}
447
448unsafe extern "C" fn cb_is_valid<C: LanguageRepresentationFunctionType>(
449 ctxt: *mut c_void,
450 view: *mut BNBinaryView,
451) -> bool {
452 let ctxt = ctxt as *mut C;
453 let view = BinaryView::from_raw(view);
454 (*ctxt).is_valid(&view)
455}
456
457unsafe extern "C" fn cb_get_type_printer<C: LanguageRepresentationFunctionType>(
458 ctxt: *mut c_void,
459) -> *mut BNTypePrinter {
460 let ctxt = ctxt as *mut C;
461 match (*ctxt).type_printer() {
462 None => std::ptr::null_mut(),
463 Some(printer) => printer.handle.as_ptr(),
464 }
465}
466
467unsafe extern "C" fn cb_get_type_parser<C: LanguageRepresentationFunctionType>(
468 ctxt: *mut c_void,
469) -> *mut BNTypeParser {
470 let ctxt = ctxt as *mut C;
471 match (*ctxt).type_parser() {
472 None => std::ptr::null_mut(),
473 Some(parser) => parser.handle.as_ptr(),
474 }
475}
476
477unsafe extern "C" fn cb_get_line_formatter<C: LanguageRepresentationFunctionType>(
478 ctxt: *mut c_void,
479) -> *mut BNLineFormatter {
480 let ctxt = ctxt as *mut C;
481 match (*ctxt).line_formatter() {
482 None => std::ptr::null_mut(),
483 Some(formatter) => formatter.handle.as_ptr(),
484 }
485}
486
487unsafe extern "C" fn cb_get_function_type_tokens<C: LanguageRepresentationFunctionType>(
488 ctxt: *mut c_void,
489 func: *mut BNFunction,
490 settings: *mut BNDisassemblySettings,
491 count: *mut usize,
492) -> *mut BNDisassemblyTextLine {
493 let ctxt = ctxt as *mut C;
494 let func = Function::from_raw(func);
495 let settings = DisassemblySettings { handle: settings };
496 let result = (*ctxt).function_type_tokens(&func, &settings);
497 *count = result.len();
498 let result: Box<[BNDisassemblyTextLine]> = result
499 .into_iter()
500 .map(DisassemblyTextLine::into_raw)
501 .collect();
502 Box::leak(result).as_mut_ptr()
504}
505
506unsafe extern "C" fn cb_free_lines(
507 _ctxt: *mut c_void,
508 lines: *mut BNDisassemblyTextLine,
509 count: usize,
510) {
511 let lines: Box<[BNDisassemblyTextLine]> =
512 Box::from_raw(std::ptr::slice_from_raw_parts_mut(lines, count));
513 for line in lines {
514 DisassemblyTextLine::free_raw(line);
515 }
516}
517
518unsafe extern "C" fn cb_free_object<C: LanguageRepresentationFunction>(ctxt: *mut c_void) {
519 let ctxt = ctxt as *mut C;
520 drop(Box::from_raw(ctxt))
521}
522
523unsafe extern "C" fn cb_external_ref_taken<C: LanguageRepresentationFunction>(_ctxt: *mut c_void) {
524 }
526
527unsafe extern "C" fn cb_external_ref_released<C: LanguageRepresentationFunction>(
528 _ctxt: *mut c_void,
529) {
530 }
532
533unsafe extern "C" fn cb_init_token_emitter<C: LanguageRepresentationFunction>(
534 ctxt: *mut c_void,
535 tokens: *mut BNHighLevelILTokenEmitter,
536) {
537 let ctxt = ctxt as *mut C;
538 let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap());
539 (*ctxt).on_token_emitter_init(&tokens)
540}
541
542unsafe extern "C" fn cb_get_expr_text<C: LanguageRepresentationFunction>(
543 ctxt: *mut c_void,
544 il: *mut BNHighLevelILFunction,
545 expr_index: usize,
546 tokens: *mut BNHighLevelILTokenEmitter,
547 settings: *mut BNDisassemblySettings,
548 as_full_ast: bool,
549 precedence: BNOperatorPrecedence,
550 statement: bool,
551) {
552 let ctxt = ctxt as *mut C;
553 let il = HighLevelILFunction {
554 full_ast: as_full_ast,
555 handle: il,
556 };
557 let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap());
558 let settings = DisassemblySettings { handle: settings };
559 (*ctxt).expr_text(
560 &il,
561 expr_index.into(),
562 &tokens,
563 &settings,
564 as_full_ast,
565 precedence,
566 statement,
567 );
568}
569
570unsafe extern "C" fn cb_begin_lines<C: LanguageRepresentationFunction>(
571 ctxt: *mut c_void,
572 il: *mut BNHighLevelILFunction,
573 expr_index: usize,
574 tokens: *mut BNHighLevelILTokenEmitter,
575) {
576 let ctxt = ctxt as *mut C;
577 let il = HighLevelILFunction {
578 full_ast: false,
579 handle: il,
580 };
581 let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap());
582 (*ctxt).begin_lines(&il, expr_index.into(), &tokens)
583}
584
585unsafe extern "C" fn cb_end_lines<C: LanguageRepresentationFunction>(
586 ctxt: *mut c_void,
587 il: *mut BNHighLevelILFunction,
588 expr_index: usize,
589 tokens: *mut BNHighLevelILTokenEmitter,
590) {
591 let ctxt = ctxt as *mut C;
592 let il = HighLevelILFunction {
593 full_ast: false,
594 handle: il,
595 };
596 let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap());
597 (*ctxt).end_lines(&il, expr_index.into(), &tokens)
598}
599
600unsafe extern "C" fn cb_get_comment_start_string<C: LanguageRepresentationFunction>(
601 ctxt: *mut c_void,
602) -> *mut c_char {
603 let ctxt = ctxt as *mut C;
604 let result = (*ctxt).comment_start_string();
605 BnString::into_raw(BnString::new(result))
606}
607
608unsafe extern "C" fn cb_get_comment_end_string<C: LanguageRepresentationFunction>(
609 ctxt: *mut c_void,
610) -> *mut c_char {
611 let ctxt = ctxt as *mut C;
612 let result = (*ctxt).comment_end_string();
613 BnString::into_raw(BnString::new(result))
614}
615
616unsafe extern "C" fn cb_get_annotation_start_string<C: LanguageRepresentationFunction>(
617 ctxt: *mut c_void,
618) -> *mut c_char {
619 let ctxt = ctxt as *mut C;
620 let result = (*ctxt).annotation_start_string();
621 BnString::into_raw(BnString::new(result))
622}
623
624unsafe extern "C" fn cb_get_annotation_end_string<C: LanguageRepresentationFunction>(
625 ctxt: *mut c_void,
626) -> *mut c_char {
627 let ctxt = ctxt as *mut C;
628 let result = (*ctxt).annotation_end_string();
629 BnString::into_raw(BnString::new(result))
630}