1use binaryninjacore_sys::*;
78use std::ffi::c_void;
79
80use crate::progress::{NoProgressCallback, ProgressCallback};
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 ffi_wrap!("CustomDebugInfoParser::is_valid", unsafe {
219 let cmd = &*(ctxt as *const C);
220 let view = BinaryView::ref_from_raw(view);
221
222 cmd.is_valid(&view)
223 })
224 }
225
226 extern "C" fn cb_parse_info<C>(
227 ctxt: *mut c_void,
228 debug_info: *mut BNDebugInfo,
229 view: *mut BNBinaryView,
230 debug_file: *mut BNBinaryView,
231 progress: Option<unsafe extern "C" fn(*mut c_void, usize, usize) -> bool>,
232 progress_ctxt: *mut c_void,
233 ) -> bool
234 where
235 C: CustomDebugInfoParser,
236 {
237 ffi_wrap!("CustomDebugInfoParser::parse_info", unsafe {
238 let cmd = &*(ctxt as *const C);
239 let view = BinaryView::ref_from_raw(view);
240 let debug_file = BinaryView::ref_from_raw(debug_file);
241 let mut debug_info = DebugInfo::ref_from_raw(debug_info);
242
243 cmd.parse_info(
244 &mut debug_info,
245 &view,
246 &debug_file,
247 Box::new(move |cur: usize, max: usize| match progress {
248 Some(func) => {
249 if func(progress_ctxt, cur, max) {
250 Ok(())
251 } else {
252 Err(())
253 }
254 }
255 _ => Ok(()),
256 }),
257 )
258 })
259 }
260
261 let name = name.to_cstr();
262 let name_ptr = name.as_ptr();
263 let ctxt = Box::into_raw(Box::new(parser_callbacks));
264
265 unsafe {
266 DebugInfoParser::from_raw(BNRegisterDebugInfoParser(
267 name_ptr,
268 Some(cb_is_valid::<C>),
269 Some(cb_parse_info::<C>),
270 ctxt as *mut _,
271 ))
272 }
273 }
274}
275
276unsafe impl RefCountable for DebugInfoParser {
277 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
278 Ref::new(Self {
279 handle: BNNewDebugInfoParserReference(handle.handle),
280 })
281 }
282
283 unsafe fn dec_ref(handle: &Self) {
284 BNFreeDebugInfoParserReference(handle.handle);
285 }
286}
287
288impl ToOwned for DebugInfoParser {
289 type Owned = Ref<Self>;
290
291 fn to_owned(&self) -> Self::Owned {
292 unsafe { RefCountable::inc_ref(self) }
293 }
294}
295
296impl CoreArrayProvider for DebugInfoParser {
297 type Raw = *mut BNDebugInfoParser;
298 type Context = ();
299 type Wrapped<'a> = Guard<'a, DebugInfoParser>;
300}
301
302unsafe impl CoreArrayProviderInner for DebugInfoParser {
303 unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) {
304 BNFreeDebugInfoParserList(raw, count);
305 }
306
307 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
308 Guard::new(Self { handle: *raw }, context)
309 }
310}
311
312pub struct DebugFunctionInfo {
321 short_name: Option<String>,
323 full_name: Option<String>,
324 raw_name: Option<String>,
325 type_: Option<Ref<Type>>,
326 address: u64,
327 platform: Option<Ref<Platform>>,
328 components: Vec<String>,
329 local_variables: Vec<NamedVariableWithType>,
330}
331
332impl DebugFunctionInfo {
333 pub(crate) fn from_raw(value: &BNDebugFunctionInfo) -> Self {
334 let raw_components =
335 unsafe { std::slice::from_raw_parts(value.components, value.componentN) };
336 let components = raw_components
337 .iter()
338 .filter_map(|&c| raw_to_string(c))
339 .collect();
340 let raw_local_variables =
341 unsafe { std::slice::from_raw_parts(value.localVariables, value.localVariableN) };
342 let local_variables = raw_local_variables
343 .iter()
344 .map(NamedVariableWithType::from_raw)
345 .collect();
346 Self {
347 short_name: raw_to_string(value.shortName),
348 full_name: raw_to_string(value.fullName),
349 raw_name: raw_to_string(value.rawName),
350 type_: if value.type_.is_null() {
351 None
352 } else {
353 Some(unsafe { Type::from_raw(value.type_) }.to_owned())
354 },
355 address: value.address,
356 platform: if value.platform.is_null() {
357 None
358 } else {
359 Some(unsafe { Platform::from_raw(value.platform) }.to_owned())
360 },
361 components,
362 local_variables,
363 }
364 }
365}
366
367impl DebugFunctionInfo {
368 #[allow(clippy::too_many_arguments)]
369 pub fn new(
370 short_name: Option<String>,
371 full_name: Option<String>,
372 raw_name: Option<String>,
373 type_: Option<Ref<Type>>,
374 address: Option<u64>,
375 platform: Option<Ref<Platform>>,
376 components: Vec<String>,
377 local_variables: Vec<NamedVariableWithType>,
378 ) -> Self {
379 Self {
380 short_name,
381 full_name,
382 raw_name,
383 type_,
384 address: address.unwrap_or(0),
385 platform,
386 components,
387 local_variables,
388 }
389 }
390}
391
392#[derive(PartialEq, Eq, Hash)]
409pub struct DebugInfo {
410 pub(crate) handle: *mut BNDebugInfo,
411}
412
413impl DebugInfo {
414 pub(crate) unsafe fn ref_from_raw(handle: *mut BNDebugInfo) -> Ref<Self> {
415 debug_assert!(!handle.is_null());
416 Ref::new(Self { handle })
417 }
418
419 pub fn types_by_name(&self, parser_name: &str) -> Vec<NameAndType> {
421 let parser_name = parser_name.to_cstr();
422
423 let mut count: usize = 0;
424 let debug_types_ptr =
425 unsafe { BNGetDebugTypes(self.handle, parser_name.as_ptr(), &mut count) };
426 let result: Vec<_> = unsafe {
427 std::slice::from_raw_parts_mut(debug_types_ptr, count)
428 .iter()
429 .map(NameAndType::from_raw)
430 .collect()
431 };
432
433 unsafe { BNFreeDebugTypes(debug_types_ptr, count) };
434 result
435 }
436
437 pub fn types(&self) -> Vec<NameAndType> {
438 let mut count: usize = 0;
439 let debug_types_ptr =
440 unsafe { BNGetDebugTypes(self.handle, std::ptr::null_mut(), &mut count) };
441 let result: Vec<_> = unsafe {
442 std::slice::from_raw_parts_mut(debug_types_ptr, count)
443 .iter()
444 .map(NameAndType::from_raw)
445 .collect()
446 };
447
448 unsafe { BNFreeDebugTypes(debug_types_ptr, count) };
449 result
450 }
451
452 pub fn functions_by_name(&self, parser_name: &str) -> Vec<DebugFunctionInfo> {
454 let parser_name = parser_name.to_cstr();
455
456 let mut count: usize = 0;
457 let functions_ptr =
458 unsafe { BNGetDebugFunctions(self.handle, parser_name.as_ptr(), &mut count) };
459
460 let result: Vec<DebugFunctionInfo> = unsafe {
461 std::slice::from_raw_parts_mut(functions_ptr, count)
462 .iter()
463 .map(DebugFunctionInfo::from_raw)
464 .collect()
465 };
466
467 unsafe { BNFreeDebugFunctions(functions_ptr, count) };
468 result
469 }
470
471 pub fn functions(&self) -> Vec<DebugFunctionInfo> {
472 let mut count: usize = 0;
473 let functions_ptr =
474 unsafe { BNGetDebugFunctions(self.handle, std::ptr::null_mut(), &mut count) };
475
476 let result: Vec<DebugFunctionInfo> = unsafe {
477 std::slice::from_raw_parts_mut(functions_ptr, count)
478 .iter()
479 .map(DebugFunctionInfo::from_raw)
480 .collect()
481 };
482
483 unsafe { BNFreeDebugFunctions(functions_ptr, count) };
484 result
485 }
486
487 pub fn data_variables_by_name(&self, parser_name: &str) -> Vec<NamedDataVariableWithType> {
489 let parser_name = parser_name.to_cstr();
490
491 let mut count: usize = 0;
492 let data_variables_ptr =
493 unsafe { BNGetDebugDataVariables(self.handle, parser_name.as_ptr(), &mut count) };
494
495 let result: Vec<NamedDataVariableWithType> = unsafe {
496 std::slice::from_raw_parts_mut(data_variables_ptr, count)
497 .iter()
498 .map(NamedDataVariableWithType::from_raw)
499 .collect()
500 };
501
502 unsafe { BNFreeDataVariablesAndName(data_variables_ptr, count) };
503 result
504 }
505
506 pub fn data_variables(&self) -> Vec<NamedDataVariableWithType> {
507 let mut count: usize = 0;
508 let data_variables_ptr =
509 unsafe { BNGetDebugDataVariables(self.handle, std::ptr::null_mut(), &mut count) };
510
511 let result: Vec<NamedDataVariableWithType> = unsafe {
512 std::slice::from_raw_parts_mut(data_variables_ptr, count)
513 .iter()
514 .map(NamedDataVariableWithType::from_raw)
515 .collect()
516 };
517
518 unsafe { BNFreeDataVariablesAndName(data_variables_ptr, count) };
519 result
520 }
521
522 pub fn type_by_name(&self, parser_name: &str, name: &str) -> Option<Ref<Type>> {
523 let parser_name = parser_name.to_cstr();
524 let name = name.to_cstr();
525
526 let result =
527 unsafe { BNGetDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) };
528 if !result.is_null() {
529 Some(unsafe { Type::ref_from_raw(result) })
530 } else {
531 None
532 }
533 }
534
535 pub fn get_data_variable_by_name(
536 &self,
537 parser_name: &str,
538 name: &str,
539 ) -> Option<NamedDataVariableWithType> {
540 let parser_name = parser_name.to_cstr();
541 let name = name.to_cstr();
542 let mut dv = BNDataVariableAndName::default();
543 unsafe {
544 if BNGetDebugDataVariableByName(
545 self.handle,
546 parser_name.as_ptr(),
547 name.as_ptr(),
548 &mut dv,
549 ) {
550 Some(NamedDataVariableWithType::from_owned_raw(dv))
551 } else {
552 None
553 }
554 }
555 }
556
557 pub fn get_data_variable_by_address(
558 &self,
559 parser_name: &str,
560 address: u64,
561 ) -> Option<NamedDataVariableWithType> {
562 let parser_name = parser_name.to_cstr();
563 let mut dv = BNDataVariableAndName::default();
564 unsafe {
565 if BNGetDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address, &mut dv)
566 {
567 Some(NamedDataVariableWithType::from_owned_raw(dv))
568 } else {
569 None
570 }
571 }
572 }
573
574 pub fn get_types_by_name(&self, name: &str) -> Vec<NameAndType> {
576 let mut count: usize = 0;
577 let name = name.to_cstr();
578 let raw_names_and_types_ptr =
579 unsafe { BNGetDebugTypesByName(self.handle, name.as_ptr(), &mut count) };
580
581 let raw_names_and_types: &[BNNameAndType] =
582 unsafe { std::slice::from_raw_parts(raw_names_and_types_ptr, count) };
583
584 let names_and_types = raw_names_and_types
585 .iter()
586 .map(NameAndType::from_raw)
587 .collect();
588
589 unsafe { BNFreeNameAndTypeList(raw_names_and_types_ptr, count) };
590 names_and_types
591 }
592
593 pub fn get_data_variables_by_name(&self, name: &str) -> Vec<(String, u64, Ref<Type>)> {
595 let name = name.to_cstr();
596
597 let mut count: usize = 0;
598 let raw_variables_and_names =
599 unsafe { BNGetDebugDataVariablesByName(self.handle, name.as_ptr(), &mut count) };
600
601 let variables_and_names: &[*mut BNDataVariableAndName] =
602 unsafe { std::slice::from_raw_parts(raw_variables_and_names as *mut _, count) };
603
604 let result = variables_and_names
605 .iter()
606 .take(count)
607 .map(|&variable_and_name| unsafe {
608 (
609 raw_to_string((*variable_and_name).name).unwrap(),
610 (*variable_and_name).address,
611 Type::from_raw((*variable_and_name).type_).to_owned(),
612 )
613 })
614 .collect();
615
616 unsafe { BNFreeDataVariablesAndName(raw_variables_and_names, count) };
617 result
618 }
619
620 pub fn get_data_variables_by_address(&self, address: u64) -> Vec<(String, String, Ref<Type>)> {
622 let mut count: usize = 0;
623 let raw_variables_and_names =
624 unsafe { BNGetDebugDataVariablesByAddress(self.handle, address, &mut count) };
625
626 let variables_and_names: &[*mut BNDataVariableAndNameAndDebugParser] =
627 unsafe { std::slice::from_raw_parts(raw_variables_and_names as *mut _, count) };
628
629 let result = variables_and_names
630 .iter()
631 .take(count)
632 .map(|&variable_and_name| unsafe {
633 (
634 raw_to_string((*variable_and_name).parser).unwrap(),
635 raw_to_string((*variable_and_name).name).unwrap(),
636 Type::from_raw((*variable_and_name).type_).to_owned(),
637 )
638 })
639 .collect();
640
641 unsafe { BNFreeDataVariableAndNameAndDebugParserList(raw_variables_and_names, count) };
642 result
643 }
644
645 pub fn remove_parser_info(&self, parser_name: &str) -> bool {
646 let parser_name = parser_name.to_cstr();
647
648 unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ptr()) }
649 }
650
651 pub fn remove_parser_types(&self, parser_name: &str) -> bool {
652 let parser_name = parser_name.to_cstr();
653
654 unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ptr()) }
655 }
656
657 pub fn remove_parser_functions(&self, parser_name: &str) -> bool {
658 let parser_name = parser_name.to_cstr();
659
660 unsafe { BNRemoveDebugParserFunctions(self.handle, parser_name.as_ptr()) }
661 }
662
663 pub fn remove_parser_data_variables(&self, parser_name: &str) -> bool {
664 let parser_name = parser_name.to_cstr();
665
666 unsafe { BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ptr()) }
667 }
668
669 pub fn remove_type_by_name(&self, parser_name: &str, name: &str) -> bool {
670 let parser_name = parser_name.to_cstr();
671 let name = name.to_cstr();
672
673 unsafe { BNRemoveDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) }
674 }
675
676 pub fn remove_function_by_index(&self, parser_name: &str, index: usize) -> bool {
677 let parser_name = parser_name.to_cstr();
678
679 unsafe { BNRemoveDebugFunctionByIndex(self.handle, parser_name.as_ptr(), index) }
680 }
681
682 pub fn remove_data_variable_by_address(&self, parser_name: &str, address: u64) -> bool {
683 let parser_name = parser_name.to_cstr();
684
685 unsafe { BNRemoveDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address) }
686 }
687
688 pub fn add_type(&self, name: &str, new_type: &Type, components: &[&str]) -> bool {
690 let raw_components: Vec<_> = components.iter().map(|&c| c.as_ptr()).collect();
692
693 let name = name.to_cstr();
694 unsafe {
695 BNAddDebugType(
696 self.handle,
697 name.as_ptr(),
698 new_type.handle,
699 raw_components.as_ptr() as *mut _,
700 components.len(),
701 )
702 }
703 }
704
705 pub fn add_function(&self, new_func: &DebugFunctionInfo) -> bool {
707 let short_name_bytes = new_func.short_name.as_ref().map(|name| name.to_cstr());
708 let short_name = short_name_bytes
709 .as_ref()
710 .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _);
711 let full_name_bytes = new_func.full_name.as_ref().map(|name| name.to_cstr());
712 let full_name = full_name_bytes
713 .as_ref()
714 .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _);
715 let raw_name_bytes = new_func.raw_name.as_ref().map(|name| name.to_cstr());
716 let raw_name = raw_name_bytes
717 .as_ref()
718 .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _);
719
720 let mut components_array: Vec<*mut ::std::os::raw::c_char> =
721 Vec::with_capacity(new_func.components.len());
722
723 let mut local_variables_array: Vec<BNVariableNameAndType> =
724 Vec::with_capacity(new_func.local_variables.len());
725
726 unsafe {
727 for component in &new_func.components {
728 let component = component.to_cstr();
729 components_array.push(BNAllocString(component.as_ptr()));
730 }
731
732 for local_variable in &new_func.local_variables {
733 local_variables_array.push(NamedVariableWithType::into_raw(local_variable.clone()));
735 }
736
737 let result = BNAddDebugFunction(
738 self.handle,
739 &mut BNDebugFunctionInfo {
740 shortName: short_name,
741 fullName: full_name,
742 rawName: raw_name,
743 address: new_func.address,
744 type_: match &new_func.type_ {
745 Some(type_) => type_.handle,
746 _ => std::ptr::null_mut(),
747 },
748 platform: match &new_func.platform {
749 Some(platform) => platform.handle,
750 _ => std::ptr::null_mut(),
751 },
752 components: components_array.as_ptr() as _,
753 componentN: new_func.components.len(),
754 localVariables: local_variables_array.as_ptr() as _,
755 localVariableN: local_variables_array.len(),
756 },
757 );
758
759 for i in components_array {
760 BnString::free_raw(i);
761 }
762
763 for i in &local_variables_array {
764 NamedVariableWithType::free_raw(*i);
765 }
766 result
767 }
768 }
769
770 pub fn add_data_variable(
772 &self,
773 address: u64,
774 t: &Type,
775 name: Option<&str>,
776 components: &[&str],
777 ) -> bool {
778 let mut components_array: Vec<*const ::std::os::raw::c_char> =
779 Vec::with_capacity(components.len());
780 for component in components {
781 components_array.push(component.as_ptr() as _);
782 }
783
784 match name {
785 Some(name) => {
786 let name = name.to_cstr();
787 unsafe {
788 BNAddDebugDataVariable(
789 self.handle,
790 address,
791 t.handle,
792 name.as_ptr(),
793 components.as_ptr() as _,
794 components.len(),
795 )
796 }
797 }
798 None => unsafe {
799 BNAddDebugDataVariable(
800 self.handle,
801 address,
802 t.handle,
803 std::ptr::null_mut(),
804 components.as_ptr() as _,
805 components.len(),
806 )
807 },
808 }
809 }
810
811 pub fn add_data_variable_info(&self, var: NamedDataVariableWithType) -> bool {
812 let raw_data_var = NamedDataVariableWithType::into_raw(var);
813 let success = unsafe { BNAddDebugDataVariableInfo(self.handle, &raw_data_var) };
814 NamedDataVariableWithType::free_raw(raw_data_var);
815 success
816 }
817}
818
819unsafe impl RefCountable for DebugInfo {
820 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
821 Ref::new(Self {
822 handle: BNNewDebugInfoReference(handle.handle),
823 })
824 }
825
826 unsafe fn dec_ref(handle: &Self) {
827 BNFreeDebugInfoReference(handle.handle);
828 }
829}
830
831impl ToOwned for DebugInfo {
832 type Owned = Ref<Self>;
833
834 fn to_owned(&self) -> Self::Owned {
835 unsafe { RefCountable::inc_ref(self) }
836 }
837}