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