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