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