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