binaryninja/
debuginfo.rs1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// TODO : These docs are here, but could afford to be cleaned up
16
17//! Parsers and providers of debug information to Binary Ninja.
18//!
19//! The debug information is used by Binary Ninja as ground-truth information about the attributes of functions,
20//! types, and variables that Binary Ninja's analysis pipeline would otherwise work to deduce. By providing
21//! debug info, Binary Ninja's output can be generated quicker, more accurately, and more completely.
22//!
23//! A DebugInfoParser consists of:
24//! 1. A name
25//! 2. An `is_valid` function which takes a BV and returns a bool
26//! 3. A `parse` function which takes a `DebugInfo` object and uses the member functions `add_type`, `add_function`, and `add_data_variable` to populate all the info it can.
27//! And finally calling `binaryninja::debuginfo::DebugInfoParser::register` to register it with the core.
28//!
29//! Here's a minimal, complete example boilerplate-plugin:
30//! ```no_run
31//! use binaryninja::{
32//! binary_view::BinaryView,
33//! debuginfo::{CustomDebugInfoParser, DebugInfo, DebugInfoParser},
34//! };
35//!
36//! struct ExampleDebugInfoParser;
37//!
38//! impl CustomDebugInfoParser for ExampleDebugInfoParser {
39//! fn is_valid(&self, _view: &BinaryView) -> bool {
40//! true
41//! }
42//!
43//! fn parse_info(
44//! &self,
45//! _debug_info: &mut DebugInfo,
46//! _view: &BinaryView,
47//! _debug_file: &BinaryView,
48//! _progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
49//! ) -> bool {
50//! println!("Parsing info");
51//! true
52//! }
53//! }
54//!
55//! #[no_mangle]
56//! pub extern "C" fn CorePluginInit() -> bool {
57//! DebugInfoParser::register("example debug info parser", ExampleDebugInfoParser {});
58//! true
59//! }
60//! ```
61//!
62//! `DebugInfo` will then be automatically applied to binary views that contain debug information (via the setting `analysis.debugInfo.internal`), binary views that provide valid external debug info files (`analysis.debugInfo.external`), or manually fetched/applied as below:
63//! ```no_run
64//! # use binaryninja::debuginfo::DebugInfoParser;
65//! # use binaryninja::binary_view::BinaryViewExt;
66//! let bv = binaryninja::load("example").unwrap();
67//! let valid_parsers = DebugInfoParser::parsers_for_view(&bv);
68//! let parser = valid_parsers.get(0);
69//! let debug_info = parser.parse_debug_info(&bv, &bv, None).unwrap();
70//! bv.apply_debug_info(&debug_info);
71//! ```
72//!
73//! Multiple debug-info parsers can manually contribute debug info for a binary view by simply calling `parse_debug_info` with the
74//! `DebugInfo` object just returned. This is automatic when opening a binary view with multiple valid debug info parsers. If you
75//! wish to set the debug info for a binary view without applying it as well, you can call `binaryninja::binaryview::BinaryView::set_debug_info`.
76
77use 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
90/// Implement this trait to implement a debug info parser. See `DebugInfoParser` for more details.
91pub 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/// Represents the registered parsers and providers of debug information to Binary Ninja.
104/// See `binaryninja::debuginfo` for more information
105#[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 /// Returns debug info parser of the given name, if it exists
118 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 /// List all debug-info parsers
130 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 /// Returns a list of debug-info parsers that are valid for the provided binary view
137 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 /// Returns the name of the current parser
144 pub fn name(&self) -> String {
145 unsafe { BnString::into_string(BNGetDebugInfoParserName(self.handle)) }
146 }
147
148 /// Returns whether this debug-info parser is valid for the provided binary view
149 pub fn is_valid_for_view(&self, view: &BinaryView) -> bool {
150 unsafe { BNIsDebugInfoParserValidForView(self.handle, view.handle) }
151 }
152
153 /// Returns [`DebugInfo`] populated with debug info by this debug-info parser.
154 ///
155 /// Only provide a `DebugInfo` object if you wish to append to the existing debug info
156 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 /// Returns [`DebugInfo`] populated with debug info by this debug-info parser.
171 ///
172 /// Only provide a `DebugInfo` object if you wish to append to the existing debug info
173 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 // Registers a DebugInfoParser. See `binaryninja::debuginfo::DebugInfoParser` for more details.
210 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
312///////////////////////
313// DebugFunctionInfo
314
315/// Collates ground-truth function-external attributes for use in BinaryNinja's internal analysis.
316///
317/// When contributing function info, provide only what you know - BinaryNinja will figure out everything else that it can, as it usually does.
318///
319/// Functions will not be created if an address is not provided, but will be able to be queried from debug info for later user analysis.
320pub struct DebugFunctionInfo {
321 // TODO: These need to be BnString if we want to support invalid UTF-8
322 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///////////////
393// DebugInfo
394
395/// Provides an interface to both provide and query debug info. The DebugInfo object is used
396/// internally by the binary view to which it is applied to determine the attributes of functions, types, and variables
397/// that would otherwise be costly to deduce.
398///
399/// DebugInfo objects themselves are independent of binary views; their data can be sourced from any arbitrary binary
400/// views and be applied to any other arbitrary binary view. A DebugInfo object can also contain debug info from multiple
401/// DebugInfoParsers. This makes it possible to gather debug info that may be distributed across several different
402/// formats and files.
403///
404/// DebugInfo cannot be instantiated by the user, instead get it from either the binary view (see `binaryninja::binaryview::BinaryView::debug_info`)
405/// or a debug-info parser (see `binaryninja::debuginfo::DebugInfoParser::parse_debug_info`).
406///
407/// Please note that calling one of `add_*` functions will not work outside of a debuginfo plugin.
408#[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 /// Returns all types within the parser
420 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 /// Returns all functions within the parser
453 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 /// Returns all data variables within the parser
488 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 /// Returns a list of [`NameAndType`] where the `name` is the parser the type originates from.
575 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 // The tuple is (DebugInfoParserName, address, type)
594 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 /// The tuple is (DebugInfoParserName, TypeName, type)
621 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 /// Adds a type scoped under the current parser's name to the debug info
689 pub fn add_type(&self, name: &str, new_type: &Type, components: &[&str]) -> bool {
690 // SAFETY: Lifetime of `components` will live long enough, so passing as_ptr is safe.
691 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 /// Adds a function scoped under the current parser's name to the debug info
706 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 // NOTE: must be manually freed after call to BNAddDebugFunction is over.
734 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 /// Adds a data variable scoped under the current parser's name to the debug info
771 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}