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 let errors: Array<TypeParserError> = unsafe { Array::new(errors, error_count, ()) };
205 Err(errors.to_vec())
206 }
207 }
208}
209
210impl Default for CoreTypeParser {
211 fn default() -> Self {
212 unsafe { Self::from_raw(NonNull::new(BNGetDefaultTypeParser()).unwrap()) }
214 }
215}
216
217pub trait TypeParser {
219 fn get_option_text(&self, option: TypeParserOption, value: &str) -> Option<String>;
226
227 fn preprocess_source(
236 &self,
237 source: &str,
238 file_name: &str,
239 platform: &Platform,
240 existing_types: &TypeContainer,
241 options: &[String],
242 include_dirs: &[PathBuf],
243 ) -> Result<String, Vec<TypeParserError>>;
244
245 fn parse_types_from_source(
255 &self,
256 source: &str,
257 file_name: &str,
258 platform: &Platform,
259 existing_types: &TypeContainer,
260 options: &[String],
261 include_dirs: &[PathBuf],
262 auto_type_source: &str,
263 ) -> Result<TypeParserResult, Vec<TypeParserError>>;
264
265 fn parse_type_string(
271 &self,
272 source: &str,
273 platform: &Platform,
274 existing_types: &TypeContainer,
275 ) -> Result<QualifiedNameAndType, Vec<TypeParserError>>;
276}
277
278impl CoreArrayProvider for CoreTypeParser {
279 type Raw = *mut BNTypeParser;
280 type Context = ();
281 type Wrapped<'a> = Self;
282}
283
284unsafe impl CoreArrayProviderInner for CoreTypeParser {
285 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
286 BNFreeTypeParserList(raw)
287 }
288
289 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
290 let handle = NonNull::new(*raw).unwrap();
292 CoreTypeParser::from_raw(handle)
293 }
294}
295
296#[derive(Clone, Debug, Eq, PartialEq)]
297pub struct TypeParserError {
298 pub severity: TypeParserErrorSeverity,
299 pub message: String,
300 pub file_name: String,
301 pub line: u64,
302 pub column: u64,
303}
304
305impl TypeParserError {
306 pub(crate) fn from_raw(value: &BNTypeParserError) -> Self {
307 Self {
308 severity: value.severity,
309 message: raw_to_string(value.message).unwrap(),
310 file_name: raw_to_string(value.fileName).unwrap(),
311 line: value.line,
312 column: value.column,
313 }
314 }
315
316 pub(crate) fn from_owned_raw(value: BNTypeParserError) -> Self {
317 let owned = Self::from_raw(&value);
318 Self::free_raw(value);
319 owned
320 }
321
322 pub(crate) fn into_raw(value: Self) -> BNTypeParserError {
323 BNTypeParserError {
324 severity: value.severity,
325 message: BnString::into_raw(BnString::new(value.message)),
326 fileName: BnString::into_raw(BnString::new(value.file_name)),
327 line: value.line,
328 column: value.column,
329 }
330 }
331
332 pub(crate) fn free_raw(value: BNTypeParserError) {
333 unsafe { BnString::free_raw(value.message) };
334 unsafe { BnString::free_raw(value.fileName) };
335 }
336
337 pub fn new(
338 severity: TypeParserErrorSeverity,
339 message: String,
340 file_name: String,
341 line: u64,
342 column: u64,
343 ) -> Self {
344 Self {
345 severity,
346 message,
347 file_name,
348 line,
349 column,
350 }
351 }
352}
353
354impl CoreArrayProvider for TypeParserError {
355 type Raw = BNTypeParserError;
356 type Context = ();
357 type Wrapped<'a> = Self;
358}
359
360unsafe impl CoreArrayProviderInner for TypeParserError {
361 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
362 unsafe { BNFreeTypeParserErrors(raw, count) }
363 }
364
365 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
366 Self::from_raw(raw)
367 }
368}
369
370#[derive(Debug, Eq, PartialEq, Default)]
371pub struct TypeParserResult {
372 pub types: Vec<ParsedType>,
373 pub variables: Vec<ParsedType>,
374 pub functions: Vec<ParsedType>,
375}
376
377impl TypeParserResult {
378 pub(crate) fn from_raw(value: &BNTypeParserResult) -> Self {
379 let raw_types = unsafe { std::slice::from_raw_parts(value.types, value.typeCount) };
380 let types = raw_types.iter().map(ParsedType::from_raw).collect();
381 let raw_variables =
382 unsafe { std::slice::from_raw_parts(value.variables, value.variableCount) };
383 let variables = raw_variables.iter().map(ParsedType::from_raw).collect();
384 let raw_functions =
385 unsafe { std::slice::from_raw_parts(value.functions, value.functionCount) };
386 let functions = raw_functions.iter().map(ParsedType::from_raw).collect();
387 TypeParserResult {
388 types,
389 variables,
390 functions,
391 }
392 }
393
394 pub(crate) fn into_raw(value: Self) -> BNTypeParserResult {
398 let boxed_raw_types: Box<[BNParsedType]> = value
399 .types
400 .into_iter()
401 .map(ParsedType::into_raw)
403 .collect();
404 let boxed_raw_variables: Box<[BNParsedType]> = value
405 .variables
406 .into_iter()
407 .map(ParsedType::into_raw)
409 .collect();
410 let boxed_raw_functions: Box<[BNParsedType]> = value
411 .functions
412 .into_iter()
413 .map(ParsedType::into_raw)
415 .collect();
416 BNTypeParserResult {
417 typeCount: boxed_raw_types.len(),
418 types: Box::leak(boxed_raw_types).as_mut_ptr(),
420 variableCount: boxed_raw_variables.len(),
421 variables: Box::leak(boxed_raw_variables).as_mut_ptr(),
423 functionCount: boxed_raw_functions.len(),
424 functions: Box::leak(boxed_raw_functions).as_mut_ptr(),
426 }
427 }
428
429 pub(crate) fn free_raw(mut value: BNTypeParserResult) {
430 unsafe { BNFreeTypeParserResult(&mut value) };
433 }
434
435 pub(crate) fn free_owned_raw(value: BNTypeParserResult) {
436 let raw_types = std::ptr::slice_from_raw_parts_mut(value.types, value.typeCount);
437 let boxed_types = unsafe { Box::from_raw(raw_types) };
439 for parsed_type in boxed_types {
440 ParsedType::free_raw(parsed_type);
441 }
442 let raw_variables =
443 std::ptr::slice_from_raw_parts_mut(value.variables, value.variableCount);
444 let boxed_variables = unsafe { Box::from_raw(raw_variables) };
446 for parsed_type in boxed_variables {
447 ParsedType::free_raw(parsed_type);
448 }
449 let raw_functions =
450 std::ptr::slice_from_raw_parts_mut(value.functions, value.functionCount);
451 let boxed_functions = unsafe { Box::from_raw(raw_functions) };
453 for parsed_type in boxed_functions {
454 ParsedType::free_raw(parsed_type);
455 }
456 }
457}
458
459#[derive(Debug, Clone, Eq, PartialEq)]
460pub struct ParsedType {
461 pub name: QualifiedName,
462 pub ty: Ref<Type>,
463 pub user: bool,
464}
465
466impl ParsedType {
467 pub(crate) fn from_raw(value: &BNParsedType) -> Self {
468 Self {
469 name: QualifiedName::from_raw(&value.name),
470 ty: unsafe { Type::from_raw(value.type_).to_owned() },
471 user: value.isUser,
472 }
473 }
474
475 pub(crate) fn from_owned_raw(value: BNParsedType) -> Self {
476 let owned = Self::from_raw(&value);
477 Self::free_raw(value);
478 owned
479 }
480
481 pub(crate) fn into_raw(value: Self) -> BNParsedType {
482 BNParsedType {
483 name: QualifiedName::into_raw(value.name),
484 type_: unsafe { Ref::into_raw(value.ty) }.handle,
485 isUser: value.user,
486 }
487 }
488
489 pub(crate) fn free_raw(value: BNParsedType) {
490 QualifiedName::free_raw(value.name);
491 let _ = unsafe { Type::ref_from_raw(value.type_) };
492 }
493
494 pub fn new(name: QualifiedName, ty: Ref<Type>, user: bool) -> Self {
495 Self { name, ty, user }
496 }
497}
498
499impl CoreArrayProvider for ParsedType {
500 type Raw = BNParsedType;
501 type Context = ();
502 type Wrapped<'b> = Self;
503}
504
505unsafe impl CoreArrayProviderInner for ParsedType {
506 unsafe fn free(_raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
507 }
510
511 unsafe fn wrap_raw<'b>(raw: &'b Self::Raw, _context: &'b Self::Context) -> Self::Wrapped<'b> {
512 ParsedType::from_raw(raw)
513 }
514}
515
516unsafe extern "C" fn cb_get_option_text<T: TypeParser>(
517 ctxt: *mut ::std::os::raw::c_void,
518 option: BNTypeParserOption,
519 value: *const c_char,
520 result: *mut *mut c_char,
521) -> bool {
522 let ctxt: &mut T = &mut *(ctxt as *mut T);
523 if let Some(inner_result) = ctxt.get_option_text(option, &raw_to_string(value).unwrap()) {
524 let bn_inner_result = BnString::new(inner_result);
525 *result = BnString::into_raw(bn_inner_result);
527 true
528 } else {
529 *result = std::ptr::null_mut();
530 false
531 }
532}
533
534unsafe extern "C" fn cb_preprocess_source<T: TypeParser>(
535 ctxt: *mut c_void,
536 source: *const c_char,
537 file_name: *const c_char,
538 platform: *mut BNPlatform,
539 existing_types: *mut BNTypeContainer,
540 options: *const *const c_char,
541 option_count: usize,
542 include_dirs: *const *const c_char,
543 include_dir_count: usize,
544 result: *mut *mut c_char,
545 errors: *mut *mut BNTypeParserError,
546 error_count: *mut usize,
547) -> bool {
548 let ctxt: &mut T = &mut *(ctxt as *mut T);
549 let platform = Platform { handle: platform };
550 let existing_types_ptr = NonNull::new(existing_types).unwrap();
551 let existing_types = TypeContainer::from_raw(existing_types_ptr);
552 let options_raw = unsafe { std::slice::from_raw_parts(options, option_count) };
553 let options: Vec<_> = options_raw
554 .iter()
555 .filter_map(|&r| raw_to_string(r))
556 .collect();
557 let includes_raw = unsafe { std::slice::from_raw_parts(include_dirs, include_dir_count) };
558 let includes: Vec<_> = includes_raw
559 .iter()
560 .filter_map(|&r| Some(PathBuf::from(raw_to_string(r)?)))
561 .collect();
562 match ctxt.preprocess_source(
563 &raw_to_string(source).unwrap(),
564 &raw_to_string(file_name).unwrap(),
565 &platform,
566 &existing_types,
567 &options,
568 &includes,
569 ) {
570 Ok(inner_result) => {
571 let bn_inner_result = BnString::new(inner_result);
572 *result = BnString::into_raw(bn_inner_result);
574 *errors = std::ptr::null_mut();
575 *error_count = 0;
576 true
577 }
578 Err(inner_errors) => {
579 *result = std::ptr::null_mut();
580 *error_count = inner_errors.len();
581 let inner_errors: Box<[_]> = inner_errors
583 .into_iter()
584 .map(TypeParserError::into_raw)
585 .collect();
586 *errors = Box::leak(inner_errors).as_mut_ptr();
588 false
589 }
590 }
591}
592
593unsafe extern "C" fn cb_parse_types_from_source<T: TypeParser>(
594 ctxt: *mut c_void,
595 source: *const c_char,
596 file_name: *const c_char,
597 platform: *mut BNPlatform,
598 existing_types: *mut BNTypeContainer,
599 options: *const *const c_char,
600 option_count: usize,
601 include_dirs: *const *const c_char,
602 include_dir_count: usize,
603 auto_type_source: *const c_char,
604 result: *mut BNTypeParserResult,
605 errors: *mut *mut BNTypeParserError,
606 error_count: *mut usize,
607) -> bool {
608 let ctxt: &mut T = &mut *(ctxt as *mut T);
609 let platform = Platform { handle: platform };
610 let existing_types_ptr = NonNull::new(existing_types).unwrap();
611 let existing_types = TypeContainer::from_raw(existing_types_ptr);
612 let options_raw = unsafe { std::slice::from_raw_parts(options, option_count) };
613 let options: Vec<_> = options_raw
614 .iter()
615 .filter_map(|&r| raw_to_string(r))
616 .collect();
617 let includes_raw = unsafe { std::slice::from_raw_parts(include_dirs, include_dir_count) };
618 let includes: Vec<_> = includes_raw
619 .iter()
620 .filter_map(|&r| Some(PathBuf::from(raw_to_string(r)?)))
621 .collect();
622 match ctxt.parse_types_from_source(
623 &raw_to_string(source).unwrap(),
624 &raw_to_string(file_name).unwrap(),
625 &platform,
626 &existing_types,
627 &options,
628 &includes,
629 &raw_to_string(auto_type_source).unwrap(),
630 ) {
631 Ok(type_parser_result) => {
632 *result = TypeParserResult::into_raw(type_parser_result);
633 *errors = std::ptr::null_mut();
634 *error_count = 0;
635 true
636 }
637 Err(inner_errors) => {
638 *error_count = inner_errors.len();
639 let inner_errors: Box<[_]> = inner_errors
640 .into_iter()
641 .map(TypeParserError::into_raw)
642 .collect();
643 *result = Default::default();
644 *errors = Box::leak(inner_errors).as_mut_ptr();
646 false
647 }
648 }
649}
650
651unsafe extern "C" fn cb_parse_type_string<T: TypeParser>(
652 ctxt: *mut c_void,
653 source: *const c_char,
654 platform: *mut BNPlatform,
655 existing_types: *mut BNTypeContainer,
656 result: *mut BNQualifiedNameAndType,
657 errors: *mut *mut BNTypeParserError,
658 error_count: *mut usize,
659) -> bool {
660 let ctxt: &mut T = &mut *(ctxt as *mut T);
661 let platform = Platform { handle: platform };
662 let existing_types_ptr = NonNull::new(existing_types).unwrap();
663 let existing_types = TypeContainer::from_raw(existing_types_ptr);
664 match ctxt.parse_type_string(&raw_to_string(source).unwrap(), &platform, &existing_types) {
665 Ok(inner_result) => {
666 *result = QualifiedNameAndType::into_raw(inner_result);
667 *errors = std::ptr::null_mut();
668 *error_count = 0;
669 true
670 }
671 Err(inner_errors) => {
672 *error_count = inner_errors.len();
673 let inner_errors: Box<[_]> = inner_errors
674 .into_iter()
675 .map(TypeParserError::into_raw)
676 .collect();
677 *result = Default::default();
678 *errors = Box::leak(inner_errors).as_mut_ptr();
680 false
681 }
682 }
683}
684
685unsafe extern "C" fn cb_free_string(_ctxt: *mut c_void, string: *mut c_char) {
686 BnString::free_raw(string);
688}
689
690unsafe extern "C" fn cb_free_result(_ctxt: *mut c_void, result: *mut BNTypeParserResult) {
691 TypeParserResult::free_owned_raw(*result);
692}
693
694unsafe extern "C" fn cb_free_error_list(
695 _ctxt: *mut c_void,
696 errors: *mut BNTypeParserError,
697 error_count: usize,
698) {
699 let errors = std::ptr::slice_from_raw_parts_mut(errors, error_count);
700 let boxed_errors = Box::from_raw(errors);
701 for error in boxed_errors {
702 TypeParserError::free_raw(error);
703 }
704}