binaryninja/
debuginfo.rs

1// 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}