1use binaryninjacore_sys::*;
77use std::ffi::c_void;
78
79use crate::progress::{NoProgressCallback, ProgressCallback};
80use crate::string::strings_to_string_list;
81use crate::variable::{NamedDataVariableWithType, NamedVariableWithType};
82use crate::{
83 binary_view::BinaryView,
84 platform::Platform,
85 rc::*,
86 string::{raw_to_string, BnString, IntoCStr},
87 types::{NameAndType, Type},
88};
89
90pub trait CustomDebugInfoParser: 'static + Sync {
92 fn is_valid(&self, view: &BinaryView) -> bool;
93
94 fn parse_info(
95 &self,
96 debug_info: &mut DebugInfo,
97 view: &BinaryView,
98 debug_file: &BinaryView,
99 progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
100 ) -> bool;
101}
102
103#[derive(PartialEq, Eq, Hash)]
106pub struct DebugInfoParser {
107 pub(crate) handle: *mut BNDebugInfoParser,
108}
109
110impl DebugInfoParser {
111 pub(crate) unsafe fn from_raw(handle: *mut BNDebugInfoParser) -> Ref<Self> {
112 debug_assert!(!handle.is_null());
113
114 Ref::new(Self { handle })
115 }
116
117 pub fn from_name(name: &str) -> Result<Ref<Self>, ()> {
119 let name = name.to_cstr();
120 let parser = unsafe { BNGetDebugInfoParserByName(name.as_ptr()) };
121
122 if parser.is_null() {
123 Err(())
124 } else {
125 unsafe { Ok(Self::from_raw(parser)) }
126 }
127 }
128
129 pub fn list() -> Array<DebugInfoParser> {
131 let mut count = 0;
132 let raw_parsers = unsafe { BNGetDebugInfoParsers(&mut count as *mut _) };
133 unsafe { Array::new(raw_parsers, count, ()) }
134 }
135
136 pub fn parsers_for_view(bv: &BinaryView) -> Array<DebugInfoParser> {
138 let mut count = 0;
139 let raw_parsers = unsafe { BNGetDebugInfoParsersForView(bv.handle, &mut count as *mut _) };
140 unsafe { Array::new(raw_parsers, count, ()) }
141 }
142
143 pub fn name(&self) -> String {
145 unsafe { BnString::into_string(BNGetDebugInfoParserName(self.handle)) }
146 }
147
148 pub fn is_valid_for_view(&self, view: &BinaryView) -> bool {
150 unsafe { BNIsDebugInfoParserValidForView(self.handle, view.handle) }
151 }
152
153 pub fn parse_debug_info(
157 &self,
158 view: &BinaryView,
159 debug_file: &BinaryView,
160 existing_debug_info: Option<&DebugInfo>,
161 ) -> Option<Ref<DebugInfo>> {
162 self.parse_debug_info_with_progress(
163 view,
164 debug_file,
165 existing_debug_info,
166 NoProgressCallback,
167 )
168 }
169
170 pub fn parse_debug_info_with_progress<P: ProgressCallback>(
174 &self,
175 view: &BinaryView,
176 debug_file: &BinaryView,
177 existing_debug_info: Option<&DebugInfo>,
178 mut progress: P,
179 ) -> Option<Ref<DebugInfo>> {
180 let info: *mut BNDebugInfo = match existing_debug_info {
181 Some(debug_info) => unsafe {
182 BNParseDebugInfo(
183 self.handle,
184 view.handle,
185 debug_file.handle,
186 debug_info.handle,
187 Some(P::cb_progress_callback),
188 &mut progress as *mut P as *mut c_void,
189 )
190 },
191 None => unsafe {
192 BNParseDebugInfo(
193 self.handle,
194 view.handle,
195 debug_file.handle,
196 std::ptr::null_mut(),
197 Some(P::cb_progress_callback),
198 &mut progress as *mut P as *mut c_void,
199 )
200 },
201 };
202
203 if info.is_null() {
204 return None;
205 }
206 Some(unsafe { DebugInfo::ref_from_raw(info) })
207 }
208
209 pub fn register<C>(name: &str, parser_callbacks: C) -> Ref<Self>
211 where
212 C: CustomDebugInfoParser,
213 {
214 extern "C" fn cb_is_valid<C>(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool
215 where
216 C: CustomDebugInfoParser,
217 {
218 let cmd = unsafe { &*(ctxt as *const C) };
219 let view = unsafe { BinaryView::ref_from_raw(view) };
220 let _span = ffi_span!("CustomDebugInfoParser::is_valid", view);
221 cmd.is_valid(&view)
222 }
223
224 extern "C" fn cb_parse_info<C>(
225 ctxt: *mut c_void,
226 debug_info: *mut BNDebugInfo,
227 view: *mut BNBinaryView,
228 debug_file: *mut BNBinaryView,
229 progress: Option<unsafe extern "C" fn(*mut c_void, usize, usize) -> bool>,
230 progress_ctxt: *mut c_void,
231 ) -> bool
232 where
233 C: CustomDebugInfoParser,
234 {
235 let cmd = unsafe { &*(ctxt as *const C) };
236 let view = unsafe { BinaryView::ref_from_raw(view) };
237 let debug_file = unsafe { BinaryView::ref_from_raw(debug_file) };
238 let mut debug_info = unsafe { DebugInfo::ref_from_raw(debug_info) };
239
240 let _span = ffi_span!("CustomDebugInfoParser::parse_info", view);
241 cmd.parse_info(
242 &mut debug_info,
243 &view,
244 &debug_file,
245 Box::new(move |cur: usize, max: usize| match progress {
246 Some(func) => unsafe {
247 if func(progress_ctxt, cur, max) {
248 Ok(())
249 } else {
250 Err(())
251 }
252 },
253 _ => Ok(()),
254 }),
255 )
256 }
257
258 let name = name.to_cstr();
259 let name_ptr = name.as_ptr();
260 let ctxt = Box::into_raw(Box::new(parser_callbacks));
261
262 unsafe {
263 DebugInfoParser::from_raw(BNRegisterDebugInfoParser(
264 name_ptr,
265 Some(cb_is_valid::<C>),
266 Some(cb_parse_info::<C>),
267 ctxt as *mut _,
268 ))
269 }
270 }
271}
272
273unsafe impl RefCountable for DebugInfoParser {
274 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
275 Ref::new(Self {
276 handle: BNNewDebugInfoParserReference(handle.handle),
277 })
278 }
279
280 unsafe fn dec_ref(handle: &Self) {
281 BNFreeDebugInfoParserReference(handle.handle);
282 }
283}
284
285impl ToOwned for DebugInfoParser {
286 type Owned = Ref<Self>;
287
288 fn to_owned(&self) -> Self::Owned {
289 unsafe { RefCountable::inc_ref(self) }
290 }
291}
292
293impl CoreArrayProvider for DebugInfoParser {
294 type Raw = *mut BNDebugInfoParser;
295 type Context = ();
296 type Wrapped<'a> = Guard<'a, DebugInfoParser>;
297}
298
299unsafe impl CoreArrayProviderInner for DebugInfoParser {
300 unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) {
301 BNFreeDebugInfoParserList(raw, count);
302 }
303
304 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
305 Guard::new(Self { handle: *raw }, context)
306 }
307}
308
309pub struct DebugFunctionInfo {
318 short_name: Option<String>,
320 full_name: Option<String>,
321 raw_name: Option<String>,
322 type_: Option<Ref<Type>>,
323 address: u64,
324 platform: Option<Ref<Platform>>,
325 components: Vec<String>,
326 local_variables: Vec<NamedVariableWithType>,
327}
328
329impl DebugFunctionInfo {
330 pub(crate) fn from_raw(value: &BNDebugFunctionInfo) -> Self {
331 let raw_components =
332 unsafe { std::slice::from_raw_parts(value.components, value.componentN) };
333 let components = raw_components
334 .iter()
335 .filter_map(|&c| raw_to_string(c))
336 .collect();
337 let raw_local_variables =
338 unsafe { std::slice::from_raw_parts(value.localVariables, value.localVariableN) };
339 let local_variables = raw_local_variables
340 .iter()
341 .map(NamedVariableWithType::from_raw)
342 .collect();
343 Self {
344 short_name: raw_to_string(value.shortName),
345 full_name: raw_to_string(value.fullName),
346 raw_name: raw_to_string(value.rawName),
347 type_: if value.type_.is_null() {
348 None
349 } else {
350 Some(unsafe { Type::from_raw(value.type_) }.to_owned())
351 },
352 address: value.address,
353 platform: if value.platform.is_null() {
354 None
355 } else {
356 Some(unsafe { Platform::from_raw(value.platform) }.to_owned())
357 },
358 components,
359 local_variables,
360 }
361 }
362}
363
364impl DebugFunctionInfo {
365 #[allow(clippy::too_many_arguments)]
366 pub fn new(
367 short_name: Option<String>,
368 full_name: Option<String>,
369 raw_name: Option<String>,
370 type_: Option<Ref<Type>>,
371 address: Option<u64>,
372 platform: Option<Ref<Platform>>,
373 components: Vec<String>,
374 local_variables: Vec<NamedVariableWithType>,
375 ) -> Self {
376 Self {
377 short_name,
378 full_name,
379 raw_name,
380 type_,
381 address: address.unwrap_or(0),
382 platform,
383 components,
384 local_variables,
385 }
386 }
387}
388
389#[derive(PartialEq, Eq, Hash)]
406pub struct DebugInfo {
407 pub(crate) handle: *mut BNDebugInfo,
408}
409
410impl DebugInfo {
411 pub(crate) unsafe fn ref_from_raw(handle: *mut BNDebugInfo) -> Ref<Self> {
412 debug_assert!(!handle.is_null());
413 Ref::new(Self { handle })
414 }
415
416 pub fn types_by_name(&self, parser_name: &str) -> Array<NameAndType> {
418 let parser_name = parser_name.to_cstr();
419 let mut count: usize = 0;
420 let debug_types_ptr =
421 unsafe { BNGetDebugTypes(self.handle, parser_name.as_ptr(), &mut count) };
422 unsafe { Array::new(debug_types_ptr, count, ()) }
423 }
424
425 pub fn types(&self) -> Array<NameAndType> {
426 let mut count: usize = 0;
427 let debug_types_ptr =
428 unsafe { BNGetDebugTypes(self.handle, std::ptr::null_mut(), &mut count) };
429 unsafe { Array::new(debug_types_ptr, count, ()) }
430 }
431
432 pub fn functions_by_name(&self, parser_name: &str) -> Vec<DebugFunctionInfo> {
434 let parser_name = parser_name.to_cstr();
435
436 let mut count: usize = 0;
437 let functions_ptr =
438 unsafe { BNGetDebugFunctions(self.handle, parser_name.as_ptr(), &mut count) };
439
440 let result: Vec<DebugFunctionInfo> = unsafe {
441 std::slice::from_raw_parts_mut(functions_ptr, count)
442 .iter()
443 .map(DebugFunctionInfo::from_raw)
444 .collect()
445 };
446
447 unsafe { BNFreeDebugFunctions(functions_ptr, count) };
448 result
449 }
450
451 pub fn functions(&self) -> Vec<DebugFunctionInfo> {
452 let mut count: usize = 0;
453 let functions_ptr =
454 unsafe { BNGetDebugFunctions(self.handle, std::ptr::null_mut(), &mut count) };
455
456 let result: Vec<DebugFunctionInfo> = unsafe {
457 std::slice::from_raw_parts_mut(functions_ptr, count)
458 .iter()
459 .map(DebugFunctionInfo::from_raw)
460 .collect()
461 };
462
463 unsafe { BNFreeDebugFunctions(functions_ptr, count) };
464 result
465 }
466
467 pub fn data_variables_by_name(&self, parser_name: &str) -> Array<NamedDataVariableWithType> {
469 let parser_name = parser_name.to_cstr();
470 let mut count: usize = 0;
471 let data_variables_ptr =
472 unsafe { BNGetDebugDataVariables(self.handle, parser_name.as_ptr(), &mut count) };
473 unsafe { Array::new(data_variables_ptr, count, ()) }
474 }
475
476 pub fn data_variables(&self) -> Array<NamedDataVariableWithType> {
477 let mut count: usize = 0;
478 let data_variables_ptr =
479 unsafe { BNGetDebugDataVariables(self.handle, std::ptr::null_mut(), &mut count) };
480 unsafe { Array::new(data_variables_ptr, count, ()) }
481 }
482
483 pub fn type_by_name(&self, parser_name: &str, name: &str) -> Option<Ref<Type>> {
484 let parser_name = parser_name.to_cstr();
485 let name = name.to_cstr();
486
487 let result =
488 unsafe { BNGetDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) };
489 if !result.is_null() {
490 Some(unsafe { Type::ref_from_raw(result) })
491 } else {
492 None
493 }
494 }
495
496 pub fn get_data_variable_by_name(
497 &self,
498 parser_name: &str,
499 name: &str,
500 ) -> Option<NamedDataVariableWithType> {
501 let parser_name = parser_name.to_cstr();
502 let name = name.to_cstr();
503 let mut dv = BNDataVariableAndName::default();
504 unsafe {
505 if BNGetDebugDataVariableByName(
506 self.handle,
507 parser_name.as_ptr(),
508 name.as_ptr(),
509 &mut dv,
510 ) {
511 Some(NamedDataVariableWithType::from_owned_raw(dv))
512 } else {
513 None
514 }
515 }
516 }
517
518 pub fn get_data_variable_by_address(
519 &self,
520 parser_name: &str,
521 address: u64,
522 ) -> Option<NamedDataVariableWithType> {
523 let parser_name = parser_name.to_cstr();
524 let mut dv = BNDataVariableAndName::default();
525 unsafe {
526 if BNGetDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address, &mut dv)
527 {
528 Some(NamedDataVariableWithType::from_owned_raw(dv))
529 } else {
530 None
531 }
532 }
533 }
534
535 pub fn get_types_by_name(&self, name: &str) -> Array<NameAndType> {
537 let name = name.to_cstr();
538 let mut count: usize = 0;
539 let raw_names_and_types_ptr =
540 unsafe { BNGetDebugTypesByName(self.handle, name.as_ptr(), &mut count) };
541 unsafe { Array::new(raw_names_and_types_ptr, count, ()) }
542 }
543
544 pub fn get_data_variables_by_name(&self, name: &str) -> Array<NamedDataVariableWithType> {
546 let name = name.to_cstr();
547 let mut count: usize = 0;
548 let raw_variables_and_names =
549 unsafe { BNGetDebugDataVariablesByName(self.handle, name.as_ptr(), &mut count) };
550 unsafe { Array::new(raw_variables_and_names, count, ()) }
551 }
552
553 pub fn get_data_variables_by_address(&self, address: u64) -> Vec<(String, String, Ref<Type>)> {
555 let mut count: usize = 0;
556 let raw_variables_and_names =
557 unsafe { BNGetDebugDataVariablesByAddress(self.handle, address, &mut count) };
558
559 let variables_and_names: &[*mut BNDataVariableAndNameAndDebugParser] =
560 unsafe { std::slice::from_raw_parts(raw_variables_and_names as *mut _, count) };
561
562 let result = variables_and_names
563 .iter()
564 .take(count)
565 .map(|&variable_and_name| unsafe {
566 (
567 raw_to_string((*variable_and_name).parser).unwrap(),
568 raw_to_string((*variable_and_name).name).unwrap(),
569 Type::from_raw((*variable_and_name).type_).to_owned(),
570 )
571 })
572 .collect();
573
574 unsafe { BNFreeDataVariableAndNameAndDebugParserList(raw_variables_and_names, count) };
575 result
576 }
577
578 pub fn remove_parser_info(&self, parser_name: &str) -> bool {
579 let parser_name = parser_name.to_cstr();
580
581 unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ptr()) }
582 }
583
584 pub fn remove_parser_types(&self, parser_name: &str) -> bool {
585 let parser_name = parser_name.to_cstr();
586
587 unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ptr()) }
588 }
589
590 pub fn remove_parser_functions(&self, parser_name: &str) -> bool {
591 let parser_name = parser_name.to_cstr();
592
593 unsafe { BNRemoveDebugParserFunctions(self.handle, parser_name.as_ptr()) }
594 }
595
596 pub fn remove_parser_data_variables(&self, parser_name: &str) -> bool {
597 let parser_name = parser_name.to_cstr();
598
599 unsafe { BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ptr()) }
600 }
601
602 pub fn remove_type_by_name(&self, parser_name: &str, name: &str) -> bool {
603 let parser_name = parser_name.to_cstr();
604 let name = name.to_cstr();
605
606 unsafe { BNRemoveDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) }
607 }
608
609 pub fn remove_function_by_index(&self, parser_name: &str, index: usize) -> bool {
610 let parser_name = parser_name.to_cstr();
611
612 unsafe { BNRemoveDebugFunctionByIndex(self.handle, parser_name.as_ptr(), index) }
613 }
614
615 pub fn remove_data_variable_by_address(&self, parser_name: &str, address: u64) -> bool {
616 let parser_name = parser_name.to_cstr();
617
618 unsafe { BNRemoveDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address) }
619 }
620
621 pub fn add_type(&self, name: &str, new_type: &Type, components: &[&str]) -> bool {
623 let raw_components_ptr = strings_to_string_list(components);
625 let name = name.to_cstr();
626 let result = unsafe {
627 BNAddDebugType(
628 self.handle,
629 name.as_ptr(),
630 new_type.handle,
631 raw_components_ptr as *mut _,
632 components.len(),
633 )
634 };
635 unsafe { BNFreeStringList(raw_components_ptr, components.len()) };
636 result
637 }
638
639 pub fn add_function(&self, new_func: &DebugFunctionInfo) -> bool {
641 let short_name_bytes = new_func.short_name.as_ref().map(|name| name.to_cstr());
642 let short_name = short_name_bytes
643 .as_ref()
644 .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _);
645 let full_name_bytes = new_func.full_name.as_ref().map(|name| name.to_cstr());
646 let full_name = full_name_bytes
647 .as_ref()
648 .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _);
649 let raw_name_bytes = new_func.raw_name.as_ref().map(|name| name.to_cstr());
650 let raw_name = raw_name_bytes
651 .as_ref()
652 .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _);
653
654 let mut components_array: Vec<*mut ::std::os::raw::c_char> =
655 Vec::with_capacity(new_func.components.len());
656
657 let mut local_variables_array: Vec<BNVariableNameAndType> =
658 Vec::with_capacity(new_func.local_variables.len());
659
660 unsafe {
661 for component in &new_func.components {
662 let component = component.to_cstr();
663 components_array.push(BNAllocString(component.as_ptr()));
664 }
665
666 for local_variable in &new_func.local_variables {
667 local_variables_array.push(NamedVariableWithType::into_raw(local_variable.clone()));
669 }
670
671 let result = BNAddDebugFunction(
672 self.handle,
673 &mut BNDebugFunctionInfo {
674 shortName: short_name,
675 fullName: full_name,
676 rawName: raw_name,
677 address: new_func.address,
678 type_: match &new_func.type_ {
679 Some(type_) => type_.handle,
680 _ => std::ptr::null_mut(),
681 },
682 platform: match &new_func.platform {
683 Some(platform) => platform.handle,
684 _ => std::ptr::null_mut(),
685 },
686 components: components_array.as_ptr() as _,
687 componentN: new_func.components.len(),
688 localVariables: local_variables_array.as_ptr() as _,
689 localVariableN: local_variables_array.len(),
690 },
691 );
692
693 for i in components_array {
694 BnString::free_raw(i);
695 }
696
697 for i in &local_variables_array {
698 NamedVariableWithType::free_raw(*i);
699 }
700 result
701 }
702 }
703
704 pub fn add_data_variable(
706 &self,
707 address: u64,
708 t: &Type,
709 name: Option<&str>,
710 components: &[&str],
711 ) -> bool {
712 let mut components_array: Vec<*const ::std::os::raw::c_char> =
713 Vec::with_capacity(components.len());
714 for component in components {
715 components_array.push(component.as_ptr() as _);
716 }
717
718 match name {
719 Some(name) => {
720 let name = name.to_cstr();
721 unsafe {
722 BNAddDebugDataVariable(
723 self.handle,
724 address,
725 t.handle,
726 name.as_ptr(),
727 components.as_ptr() as _,
728 components.len(),
729 )
730 }
731 }
732 None => unsafe {
733 BNAddDebugDataVariable(
734 self.handle,
735 address,
736 t.handle,
737 std::ptr::null_mut(),
738 components.as_ptr() as _,
739 components.len(),
740 )
741 },
742 }
743 }
744
745 pub fn add_data_variable_info(&self, var: NamedDataVariableWithType) -> bool {
746 let raw_data_var = NamedDataVariableWithType::into_raw(var);
747 let success = unsafe { BNAddDebugDataVariableInfo(self.handle, &raw_data_var) };
748 NamedDataVariableWithType::free_raw(raw_data_var);
749 success
750 }
751}
752
753unsafe impl RefCountable for DebugInfo {
754 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
755 Ref::new(Self {
756 handle: BNNewDebugInfoReference(handle.handle),
757 })
758 }
759
760 unsafe fn dec_ref(handle: &Self) {
761 BNFreeDebugInfoReference(handle.handle);
762 }
763}
764
765impl ToOwned for DebugInfo {
766 type Owned = Ref<Self>;
767
768 fn to_owned(&self) -> Self::Owned {
769 unsafe { RefCountable::inc_ref(self) }
770 }
771}