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
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        // SAFETY: CoreLanguageRepresentationFunctionType and BNCoreLanguageRepresentationFunctionType
226        // transparent
227        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    // NOTE freed by function_type_free_lines_ffi
500    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    // TODO Make an Arc? conflict with free?
522}
523
524unsafe extern "C" fn cb_external_ref_released<C: LanguageRepresentationFunction>(
525    _ctxt: *mut c_void,
526) {
527    // TODO Make an Arc? conflict with free?
528}
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}