1#![allow(unused)]
2use binaryninjacore_sys::*;
3use std::ffi::{c_char, c_void};
4use std::fmt::Debug;
5use std::path::PathBuf;
6use std::ptr::NonNull;
7
8use crate::platform::Platform;
9use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
10use crate::string::{raw_to_string, BnString, IntoCStr};
11use crate::types::{QualifiedName, QualifiedNameAndType, Type, TypeContainer};
12
13pub type TypeParserErrorSeverity = BNTypeParserErrorSeverity;
14pub type TypeParserOption = BNTypeParserOption;
15
16pub fn register_type_parser<T: TypeParser>(
18 name: &str,
19 parser: T,
20) -> (&'static mut T, CoreTypeParser) {
21 let parser = Box::leak(Box::new(parser));
22 let mut callback = BNTypeParserCallbacks {
23 context: parser as *mut _ as *mut c_void,
24 getOptionText: Some(cb_get_option_text::<T>),
25 preprocessSource: Some(cb_preprocess_source::<T>),
26 parseTypesFromSource: Some(cb_parse_types_from_source::<T>),
27 parseTypeString: Some(cb_parse_type_string::<T>),
28 freeString: Some(cb_free_string),
29 freeResult: Some(cb_free_result),
30 freeErrorList: Some(cb_free_error_list),
31 };
32 let name = name.to_cstr();
33 let result = unsafe { BNRegisterTypeParser(name.as_ptr(), &mut callback) };
34 let core = unsafe { CoreTypeParser::from_raw(NonNull::new(result).unwrap()) };
35 (parser, core)
36}
37
38#[repr(transparent)]
39pub struct CoreTypeParser {
40 pub(crate) handle: NonNull<BNTypeParser>,
41}
42
43impl CoreTypeParser {
44 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeParser>) -> Self {
45 Self { handle }
46 }
47
48 pub fn parsers() -> Array<CoreTypeParser> {
49 let mut count = 0;
50 let result = unsafe { BNGetTypeParserList(&mut count) };
51 unsafe { Array::new(result, count, ()) }
52 }
53
54 pub fn parser_by_name(name: &str) -> Option<CoreTypeParser> {
55 let name_raw = name.to_cstr();
56 let result = unsafe { BNGetTypeParserByName(name_raw.as_ptr()) };
57 NonNull::new(result).map(|x| unsafe { Self::from_raw(x) })
58 }
59
60 pub fn name(&self) -> String {
61 let result = unsafe { BNGetTypeParserName(self.handle.as_ptr()) };
62 assert!(!result.is_null());
63 unsafe { BnString::into_string(result) }
64 }
65}
66
67impl TypeParser for CoreTypeParser {
68 fn get_option_text(&self, option: TypeParserOption, value: &str) -> Option<String> {
69 let mut output = std::ptr::null_mut();
70 let value_ptr = std::ptr::null_mut();
71 let result = unsafe {
72 BNGetTypeParserOptionText(self.handle.as_ptr(), option, value_ptr, &mut output)
73 };
74 result.then(|| {
75 assert!(!output.is_null());
76 unsafe { BnString::into_string(value_ptr) }
77 })
78 }
79
80 fn preprocess_source(
81 &self,
82 source: &str,
83 file_name: &str,
84 platform: &Platform,
85 existing_types: &TypeContainer,
86 options: &[String],
87 include_directories: &[PathBuf],
88 ) -> Result<String, Vec<TypeParserError>> {
89 let source_cstr = BnString::new(source);
90 let file_name_cstr = BnString::new(file_name);
91 let options: Vec<_> = options.iter().map(|o| o.to_cstr()).collect();
92 let options_raw: Vec<*const c_char> = options.iter().map(|o| o.as_ptr()).collect();
93 let include_directories: Vec<_> = include_directories
94 .iter()
95 .map(|d| d.clone().to_cstr())
96 .collect();
97 let include_directories_raw: Vec<*const c_char> =
98 include_directories.iter().map(|d| d.as_ptr()).collect();
99 let mut result = std::ptr::null_mut();
100 let mut errors = std::ptr::null_mut();
101 let mut error_count = 0;
102 let success = unsafe {
103 BNTypeParserPreprocessSource(
104 self.handle.as_ptr(),
105 source_cstr.as_ptr(),
106 file_name_cstr.as_ptr(),
107 platform.handle,
108 existing_types.handle.as_ptr(),
109 options_raw.as_ptr(),
110 options_raw.len(),
111 include_directories_raw.as_ptr(),
112 include_directories_raw.len(),
113 &mut result,
114 &mut errors,
115 &mut error_count,
116 )
117 };
118 if success {
119 assert!(!result.is_null());
120 let bn_result = unsafe { BnString::into_string(result) };
121 Ok(bn_result)
122 } else {
123 let errors: Array<TypeParserError> = unsafe { Array::new(errors, error_count, ()) };
124 Err(errors.to_vec())
125 }
126 }
127
128 fn parse_types_from_source(
129 &self,
130 source: &str,
131 file_name: &str,
132 platform: &Platform,
133 existing_types: &TypeContainer,
134 options: &[String],
135 include_directories: &[PathBuf],
136 auto_type_source: &str,
137 ) -> Result<TypeParserResult, Vec<TypeParserError>> {
138 let source_cstr = BnString::new(source);
139 let file_name_cstr = BnString::new(file_name);
140 let options: Vec<_> = options.iter().map(|o| o.to_cstr()).collect();
141 let options_raw: Vec<*const c_char> = options.iter().map(|o| o.as_ptr()).collect();
142 let include_directories: Vec<_> = include_directories
143 .iter()
144 .map(|d| d.clone().to_cstr())
145 .collect();
146 let include_directories_raw: Vec<*const c_char> =
147 include_directories.iter().map(|d| d.as_ptr()).collect();
148 let auto_type_source = BnString::new(auto_type_source);
149 let mut raw_result = BNTypeParserResult::default();
150 let mut errors = std::ptr::null_mut();
151 let mut error_count = 0;
152 let success = unsafe {
153 BNTypeParserParseTypesFromSource(
154 self.handle.as_ptr(),
155 source_cstr.as_ptr(),
156 file_name_cstr.as_ptr(),
157 platform.handle,
158 existing_types.handle.as_ptr(),
159 options_raw.as_ptr(),
160 options_raw.len(),
161 include_directories_raw.as_ptr(),
162 include_directories_raw.len(),
163 auto_type_source.as_ptr(),
164 &mut raw_result,
165 &mut errors,
166 &mut error_count,
167 )
168 };
169 if success {
170 let result = TypeParserResult::from_raw(&raw_result);
171 TypeParserResult::free_raw(raw_result);
173 Ok(result)
174 } else {
175 let errors: Array<TypeParserError> = unsafe { Array::new(errors, error_count, ()) };
176 Err(errors.to_vec())
177 }
178 }
179
180 fn parse_type_string(
181 &self,
182 source: &str,
183 platform: &Platform,
184 existing_types: &TypeContainer,
185 ) -> Result<QualifiedNameAndType, Vec<TypeParserError>> {
186 let source_cstr = BnString::new(source);
187 let mut output = BNQualifiedNameAndType::default();
188 let mut errors = std::ptr::null_mut();
189 let mut error_count = 0;
190 let result = unsafe {
191 BNTypeParserParseTypeString(
192 self.handle.as_ptr(),
193 source_cstr.as_ptr(),
194 platform.handle,
195 existing_types.handle.as_ptr(),
196 &mut output,
197 &mut errors,
198 &mut error_count,
199 )
200 };
201 if result {
202 Ok(QualifiedNameAndType::from_owned_raw(output))
203 } else {
204 unsafe { BNFreeQualifiedNameAndType(&mut output) };
205 let errors: Array<TypeParserError> = unsafe { Array::new(errors, error_count, ()) };
206 Err(errors.to_vec())
207 }
208 }
209}
210
211impl Default for CoreTypeParser {
212 fn default() -> Self {
213 unsafe { Self::from_raw(NonNull::new(BNGetDefaultTypeParser()).unwrap()) }
215 }
216}
217
218pub trait TypeParser {
220 fn get_option_text(&self, option: TypeParserOption, value: &str) -> Option<String>;
227
228 fn preprocess_source(
237 &self,
238 source: &str,
239 file_name: &str,
240 platform: &Platform,
241 existing_types: &TypeContainer,
242 options: &[String],
243 include_dirs: &[PathBuf],
244 ) -> Result<String, Vec<TypeParserError>>;
245
246 fn parse_types_from_source(
256 &self,
257 source: &str,
258 file_name: &str,
259 platform: &Platform,
260 existing_types: &TypeContainer,
261 options: &[String],
262 include_dirs: &[PathBuf],
263 auto_type_source: &str,
264 ) -> Result<TypeParserResult, Vec<TypeParserError>>;
265
266 fn parse_type_string(
272 &self,
273 source: &str,
274 platform: &Platform,
275 existing_types: &TypeContainer,
276 ) -> Result<QualifiedNameAndType, Vec<TypeParserError>>;
277}
278
279impl CoreArrayProvider for CoreTypeParser {
280 type Raw = *mut BNTypeParser;
281 type Context = ();
282 type Wrapped<'a> = Self;
283}
284
285unsafe impl CoreArrayProviderInner for CoreTypeParser {
286 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
287 BNFreeTypeParserList(raw)
288 }
289
290 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
291 let handle = NonNull::new(*raw).unwrap();
293 CoreTypeParser::from_raw(handle)
294 }
295}
296
297#[derive(Clone, Debug, Eq, PartialEq)]
298pub struct TypeParserError {
299 pub severity: TypeParserErrorSeverity,
300 pub message: String,
301 pub file_name: String,
302 pub line: u64,
303 pub column: u64,
304}
305
306impl TypeParserError {
307 pub(crate) fn from_raw(value: &BNTypeParserError) -> Self {
308 Self {
309 severity: value.severity,
310 message: raw_to_string(value.message).unwrap(),
311 file_name: raw_to_string(value.fileName).unwrap(),
312 line: value.line,
313 column: value.column,
314 }
315 }
316
317 pub(crate) fn from_owned_raw(value: BNTypeParserError) -> Self {
318 let owned = Self::from_raw(&value);
319 Self::free_raw(value);
320 owned
321 }
322
323 pub(crate) fn into_raw(value: Self) -> BNTypeParserError {
324 BNTypeParserError {
325 severity: value.severity,
326 message: BnString::into_raw(BnString::new(value.message)),
327 fileName: BnString::into_raw(BnString::new(value.file_name)),
328 line: value.line,
329 column: value.column,
330 }
331 }
332
333 pub(crate) fn free_raw(value: BNTypeParserError) {
334 unsafe { BnString::free_raw(value.message) };
335 unsafe { BnString::free_raw(value.fileName) };
336 }
337
338 pub fn new(
339 severity: TypeParserErrorSeverity,
340 message: String,
341 file_name: String,
342 line: u64,
343 column: u64,
344 ) -> Self {
345 Self {
346 severity,
347 message,
348 file_name,
349 line,
350 column,
351 }
352 }
353}
354
355impl CoreArrayProvider for TypeParserError {
356 type Raw = BNTypeParserError;
357 type Context = ();
358 type Wrapped<'a> = Self;
359}
360
361unsafe impl CoreArrayProviderInner for TypeParserError {
362 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
363 unsafe { BNFreeTypeParserErrors(raw, count) }
364 }
365
366 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
367 Self::from_raw(raw)
368 }
369}
370
371#[derive(Debug, Eq, PartialEq, Default)]
372pub struct TypeParserResult {
373 pub types: Vec<ParsedType>,
374 pub variables: Vec<ParsedType>,
375 pub functions: Vec<ParsedType>,
376}
377
378impl TypeParserResult {
379 pub(crate) fn from_raw(value: &BNTypeParserResult) -> Self {
380 let raw_types = unsafe { std::slice::from_raw_parts(value.types, value.typeCount) };
381 let types = raw_types.iter().map(ParsedType::from_raw).collect();
382 let raw_variables =
383 unsafe { std::slice::from_raw_parts(value.variables, value.variableCount) };
384 let variables = raw_variables.iter().map(ParsedType::from_raw).collect();
385 let raw_functions =
386 unsafe { std::slice::from_raw_parts(value.functions, value.functionCount) };
387 let functions = raw_functions.iter().map(ParsedType::from_raw).collect();
388 TypeParserResult {
389 types,
390 variables,
391 functions,
392 }
393 }
394
395 pub(crate) fn into_raw(value: Self) -> BNTypeParserResult {
399 let boxed_raw_types: Box<[BNParsedType]> = value
400 .types
401 .into_iter()
402 .map(ParsedType::into_raw)
404 .collect();
405 let boxed_raw_variables: Box<[BNParsedType]> = value
406 .variables
407 .into_iter()
408 .map(ParsedType::into_raw)
410 .collect();
411 let boxed_raw_functions: Box<[BNParsedType]> = value
412 .functions
413 .into_iter()
414 .map(ParsedType::into_raw)
416 .collect();
417 BNTypeParserResult {
418 typeCount: boxed_raw_types.len(),
419 types: Box::leak(boxed_raw_types).as_mut_ptr(),
421 variableCount: boxed_raw_variables.len(),
422 variables: Box::leak(boxed_raw_variables).as_mut_ptr(),
424 functionCount: boxed_raw_functions.len(),
425 functions: Box::leak(boxed_raw_functions).as_mut_ptr(),
427 }
428 }
429
430 pub(crate) fn free_raw(mut value: BNTypeParserResult) {
431 unsafe { BNFreeTypeParserResult(&mut value) };
434 }
435
436 pub(crate) fn free_owned_raw(value: BNTypeParserResult) {
437 let raw_types = std::ptr::slice_from_raw_parts_mut(value.types, value.typeCount);
438 let boxed_types = unsafe { Box::from_raw(raw_types) };
440 for parsed_type in boxed_types {
441 ParsedType::free_raw(parsed_type);
442 }
443 let raw_variables =
444 std::ptr::slice_from_raw_parts_mut(value.variables, value.variableCount);
445 let boxed_variables = unsafe { Box::from_raw(raw_variables) };
447 for parsed_type in boxed_variables {
448 ParsedType::free_raw(parsed_type);
449 }
450 let raw_functions =
451 std::ptr::slice_from_raw_parts_mut(value.functions, value.functionCount);
452 let boxed_functions = unsafe { Box::from_raw(raw_functions) };
454 for parsed_type in boxed_functions {
455 ParsedType::free_raw(parsed_type);
456 }
457 }
458}
459
460#[derive(Debug, Clone, Eq, PartialEq)]
461pub struct ParsedType {
462 pub name: QualifiedName,
463 pub ty: Ref<Type>,
464 pub user: bool,
465}
466
467impl ParsedType {
468 pub(crate) fn from_raw(value: &BNParsedType) -> Self {
469 Self {
470 name: QualifiedName::from_raw(&value.name),
471 ty: unsafe { Type::from_raw(value.type_).to_owned() },
472 user: value.isUser,
473 }
474 }
475
476 pub(crate) fn from_owned_raw(value: BNParsedType) -> Self {
477 let owned = Self::from_raw(&value);
478 Self::free_raw(value);
479 owned
480 }
481
482 pub(crate) fn into_raw(value: Self) -> BNParsedType {
483 BNParsedType {
484 name: QualifiedName::into_raw(value.name),
485 type_: unsafe { Ref::into_raw(value.ty) }.handle,
486 isUser: value.user,
487 }
488 }
489
490 pub(crate) fn free_raw(value: BNParsedType) {
491 QualifiedName::free_raw(value.name);
492 let _ = unsafe { Type::ref_from_raw(value.type_) };
493 }
494
495 pub fn new(name: QualifiedName, ty: Ref<Type>, user: bool) -> Self {
496 Self { name, ty, user }
497 }
498}
499
500impl CoreArrayProvider for ParsedType {
501 type Raw = BNParsedType;
502 type Context = ();
503 type Wrapped<'b> = Self;
504}
505
506unsafe impl CoreArrayProviderInner for ParsedType {
507 unsafe fn free(_raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
508 }
511
512 unsafe fn wrap_raw<'b>(raw: &'b Self::Raw, _context: &'b Self::Context) -> Self::Wrapped<'b> {
513 ParsedType::from_raw(raw)
514 }
515}
516
517unsafe extern "C" fn cb_get_option_text<T: TypeParser>(
518 ctxt: *mut ::std::os::raw::c_void,
519 option: BNTypeParserOption,
520 value: *const c_char,
521 result: *mut *mut c_char,
522) -> bool {
523 let ctxt: &mut T = &mut *(ctxt as *mut T);
524 if let Some(inner_result) = ctxt.get_option_text(option, &raw_to_string(value).unwrap()) {
525 let bn_inner_result = BnString::new(inner_result);
526 *result = BnString::into_raw(bn_inner_result);
528 true
529 } else {
530 *result = std::ptr::null_mut();
531 false
532 }
533}
534
535unsafe extern "C" fn cb_preprocess_source<T: TypeParser>(
536 ctxt: *mut c_void,
537 source: *const c_char,
538 file_name: *const c_char,
539 platform: *mut BNPlatform,
540 existing_types: *mut BNTypeContainer,
541 options: *const *const c_char,
542 option_count: usize,
543 include_dirs: *const *const c_char,
544 include_dir_count: usize,
545 result: *mut *mut c_char,
546 errors: *mut *mut BNTypeParserError,
547 error_count: *mut usize,
548) -> bool {
549 let ctxt: &mut T = &mut *(ctxt as *mut T);
550 let platform = Platform { handle: platform };
551 let existing_types_ptr = NonNull::new(existing_types).unwrap();
552 let existing_types = TypeContainer::from_raw(existing_types_ptr);
553 let options_raw = unsafe { std::slice::from_raw_parts(options, option_count) };
554 let options: Vec<_> = options_raw
555 .iter()
556 .filter_map(|&r| raw_to_string(r))
557 .collect();
558 let includes_raw = unsafe { std::slice::from_raw_parts(include_dirs, include_dir_count) };
559 let includes: Vec<_> = includes_raw
560 .iter()
561 .filter_map(|&r| Some(PathBuf::from(raw_to_string(r)?)))
562 .collect();
563 match ctxt.preprocess_source(
564 &raw_to_string(source).unwrap(),
565 &raw_to_string(file_name).unwrap(),
566 &platform,
567 &existing_types,
568 &options,
569 &includes,
570 ) {
571 Ok(inner_result) => {
572 let bn_inner_result = BnString::new(inner_result);
573 *result = BnString::into_raw(bn_inner_result);
575 *errors = std::ptr::null_mut();
576 *error_count = 0;
577 true
578 }
579 Err(inner_errors) => {
580 *result = std::ptr::null_mut();
581 *error_count = inner_errors.len();
582 let inner_errors: Box<[_]> = inner_errors
584 .into_iter()
585 .map(TypeParserError::into_raw)
586 .collect();
587 *errors = Box::leak(inner_errors).as_mut_ptr();
589 false
590 }
591 }
592}
593
594unsafe extern "C" fn cb_parse_types_from_source<T: TypeParser>(
595 ctxt: *mut c_void,
596 source: *const c_char,
597 file_name: *const c_char,
598 platform: *mut BNPlatform,
599 existing_types: *mut BNTypeContainer,
600 options: *const *const c_char,
601 option_count: usize,
602 include_dirs: *const *const c_char,
603 include_dir_count: usize,
604 auto_type_source: *const c_char,
605 result: *mut BNTypeParserResult,
606 errors: *mut *mut BNTypeParserError,
607 error_count: *mut usize,
608) -> bool {
609 let ctxt: &mut T = &mut *(ctxt as *mut T);
610 let platform = Platform { handle: platform };
611 let existing_types_ptr = NonNull::new(existing_types).unwrap();
612 let existing_types = TypeContainer::from_raw(existing_types_ptr);
613 let options_raw = unsafe { std::slice::from_raw_parts(options, option_count) };
614 let options: Vec<_> = options_raw
615 .iter()
616 .filter_map(|&r| raw_to_string(r))
617 .collect();
618 let includes_raw = unsafe { std::slice::from_raw_parts(include_dirs, include_dir_count) };
619 let includes: Vec<_> = includes_raw
620 .iter()
621 .filter_map(|&r| Some(PathBuf::from(raw_to_string(r)?)))
622 .collect();
623 match ctxt.parse_types_from_source(
624 &raw_to_string(source).unwrap(),
625 &raw_to_string(file_name).unwrap(),
626 &platform,
627 &existing_types,
628 &options,
629 &includes,
630 &raw_to_string(auto_type_source).unwrap(),
631 ) {
632 Ok(type_parser_result) => {
633 *result = TypeParserResult::into_raw(type_parser_result);
634 *errors = std::ptr::null_mut();
635 *error_count = 0;
636 true
637 }
638 Err(inner_errors) => {
639 *error_count = inner_errors.len();
640 let inner_errors: Box<[_]> = inner_errors
641 .into_iter()
642 .map(TypeParserError::into_raw)
643 .collect();
644 *result = Default::default();
645 *errors = Box::leak(inner_errors).as_mut_ptr();
647 false
648 }
649 }
650}
651
652unsafe extern "C" fn cb_parse_type_string<T: TypeParser>(
653 ctxt: *mut c_void,
654 source: *const c_char,
655 platform: *mut BNPlatform,
656 existing_types: *mut BNTypeContainer,
657 result: *mut BNQualifiedNameAndType,
658 errors: *mut *mut BNTypeParserError,
659 error_count: *mut usize,
660) -> bool {
661 let ctxt: &mut T = &mut *(ctxt as *mut T);
662 let platform = Platform { handle: platform };
663 let existing_types_ptr = NonNull::new(existing_types).unwrap();
664 let existing_types = TypeContainer::from_raw(existing_types_ptr);
665 match ctxt.parse_type_string(&raw_to_string(source).unwrap(), &platform, &existing_types) {
666 Ok(inner_result) => {
667 *result = QualifiedNameAndType::into_raw(inner_result);
668 *errors = std::ptr::null_mut();
669 *error_count = 0;
670 true
671 }
672 Err(inner_errors) => {
673 *error_count = inner_errors.len();
674 let inner_errors: Box<[_]> = inner_errors
675 .into_iter()
676 .map(TypeParserError::into_raw)
677 .collect();
678 *result = Default::default();
679 *errors = Box::leak(inner_errors).as_mut_ptr();
681 false
682 }
683 }
684}
685
686unsafe extern "C" fn cb_free_string(_ctxt: *mut c_void, string: *mut c_char) {
687 BnString::free_raw(string);
689}
690
691unsafe extern "C" fn cb_free_result(_ctxt: *mut c_void, result: *mut BNTypeParserResult) {
692 TypeParserResult::free_owned_raw(*result);
693}
694
695unsafe extern "C" fn cb_free_error_list(
696 _ctxt: *mut c_void,
697 errors: *mut BNTypeParserError,
698 error_count: usize,
699) {
700 let errors = std::ptr::slice_from_raw_parts_mut(errors, error_count);
701 let boxed_errors = Box::from_raw(errors);
702 for error in boxed_errors {
703 TypeParserError::free_raw(error);
704 }
705}