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