binaryninja/
language_representation.rs

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// NOTE static, it never gets freed, so we can clone/copy it
121#[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        // SAFETY: CoreLanguageRepresentationFunctionType and BNCoreLanguageRepresentationFunctionType
227        // transparent
228        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    // NOTE freed by function_type_free_lines_ffi
501    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    // TODO Make an Arc? conflict with free?
523}
524
525unsafe extern "C" fn cb_external_ref_released<C: LanguageRepresentationFunction>(
526    _ctxt: *mut c_void,
527) {
528    // TODO Make an Arc? conflict with free?
529}
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}