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