binaryninja/
binary_view.rs

1// Copyright 2021-2026 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//! A view on binary data and queryable interface of a binary files analysis.
16//!
17//! The main analysis object is [`BinaryView`], and custom implementations can be implemented with [`CustomBinaryView`].
18
19use binaryninjacore_sys::*;
20
21// Used for documentation
22#[allow(unused)]
23pub use crate::workflow::AnalysisContext;
24
25use crate::architecture::{Architecture, CoreArchitecture};
26use crate::base_detection::BaseAddressDetection;
27use crate::basic_block::BasicBlock;
28use crate::binary_view::search::SearchQuery;
29use crate::component::Component;
30use crate::confidence::Conf;
31use crate::data_buffer::DataBuffer;
32use crate::debuginfo::DebugInfo;
33use crate::disassembly::DisassemblySettings;
34use crate::external_library::{ExternalLibrary, ExternalLocation};
35use crate::file_accessor::{Accessor, FileAccessor};
36use crate::file_metadata::FileMetadata;
37use crate::flowgraph::FlowGraph;
38use crate::function::{Function, FunctionViewType, Location, NativeBlock};
39use crate::linear_view::{LinearDisassemblyLine, LinearViewCursor};
40use crate::metadata::Metadata;
41use crate::platform::Platform;
42use crate::progress::{NoProgressCallback, ProgressCallback};
43use crate::project::file::ProjectFile;
44use crate::rc::*;
45use crate::references::{CodeReference, DataReference};
46use crate::relocation::Relocation;
47use crate::section::{Section, SectionBuilder};
48use crate::segment::{Segment, SegmentBuilder};
49use crate::settings::Settings;
50use crate::string::*;
51use crate::symbol::{Symbol, SymbolType};
52use crate::tags::{Tag, TagReference, TagType};
53use crate::types::{
54    FunctionParameter, NamedTypeReference, QualifiedName, QualifiedNameAndType,
55    QualifiedNameTypeAndId, ReturnValue, Type, TypeArchive, TypeArchiveId, TypeContainer,
56    TypeLibrary,
57};
58use crate::variable::DataVariable;
59use crate::workflow::Workflow;
60use crate::{Endianness, BN_FULL_CONFIDENCE};
61use std::collections::{BTreeMap, HashMap};
62use std::ffi::{c_char, c_void, CString};
63use std::fmt::{Debug, Display, Formatter};
64use std::mem::MaybeUninit;
65use std::ops::Range;
66use std::path::{Path, PathBuf};
67use std::ptr::NonNull;
68
69pub mod memory_map;
70pub mod reader;
71pub mod search;
72pub mod writer;
73
74pub use memory_map::{MemoryMap, MemoryRegionInfo, ResolvedRange};
75pub use reader::BinaryReader;
76pub use writer::BinaryWriter;
77
78pub type BinaryViewEventType = BNBinaryViewEventType;
79pub type AnalysisState = BNAnalysisState;
80pub type ModificationStatus = BNModificationStatus;
81pub type StringType = BNStringType;
82pub type FindFlag = BNFindFlag;
83
84/// Registers a new binary view type.
85pub fn register_binary_view_type<T>(view_type: T) -> (&'static T, BinaryViewType)
86where
87    T: CustomBinaryViewType,
88{
89    let name = T::NAME.to_cstr();
90    let long_name = T::LONG_NAME.to_cstr();
91    let leaked_type = Box::leak(Box::new(view_type));
92
93    let result = unsafe {
94        BNRegisterBinaryViewType(
95            name.as_ref().as_ptr() as *const _,
96            long_name.as_ref().as_ptr() as *const _,
97            &mut BNCustomBinaryViewType {
98                context: leaked_type as *mut _ as *mut std::os::raw::c_void,
99                create: Some(cb_create::<T>),
100                parse: Some(cb_parse::<T>),
101                isValidForData: Some(cb_valid::<T>),
102                isDeprecated: Some(cb_deprecated::<T>),
103                isForceLoadable: Some(cb_force_loadable::<T>),
104                getLoadSettingsForData: Some(cb_load_settings::<T>),
105                hasNoInitialContent: Some(cb_has_no_initial_content::<T>),
106            },
107        )
108    };
109
110    assert!(
111        !result.is_null(),
112        "BNRegisterBinaryViewType always returns a non-null handle"
113    );
114    let core_view_type = unsafe { BinaryViewType::from_raw(result) };
115    (leaked_type, core_view_type)
116}
117
118/// Interface for creating custom binary views of a given type, analogous to [`BinaryViewType`].
119pub trait CustomBinaryViewType: 'static + Sync {
120    /// The associated [`BinaryViewBase`] for which this type creates with [`CustomBinaryViewType::create_binary_view`].
121    type CustomBinaryView: CustomBinaryView;
122
123    /// The name of the binary view type.
124    const NAME: &'static str;
125
126    /// The longer name of the binary view type, defaults to [`CustomBinaryViewType::NAME`].
127    const LONG_NAME: &'static str = Self::NAME;
128
129    /// Is this [`CustomBinaryViewType`] deprecated and should not be used?
130    ///
131    /// We specify this such that the view type may still be used by existing databases, but not
132    /// newly created views.
133    const DEPRECATED: bool = false;
134
135    /// Is this [`CustomBinaryViewType`] able to be loaded forcefully?
136    ///
137    /// If so, it will be shown in the drop-down when a user opens a file with options.
138    const FORCE_LOADABLE: bool = false;
139
140    /// Do instances of this [`CustomBinaryViewType`] start with no loaded content?
141    ///
142    /// When true, the view has no meaningful default state: the user must make a
143    /// selection (e.g. load images from a shared cache) before any content exists.
144    ///
145    /// Callers can use this to suppress restoring the previously saved view state for
146    /// files not being loaded from a database, since a saved layout would reference
147    /// content that isn't available on reopening.
148    const HAS_NO_INITIAL_CONTENT: bool = false;
149
150    /// Constructs the custom binary view instance.
151    fn create_binary_view(&self, data: &BinaryView) -> Result<Self::CustomBinaryView, ()>;
152
153    /// Constructs the custom binary view instance to be used for configuration.
154    ///
155    /// This is the path that is used when opening a binary with "Open With Options", and is what populates
156    /// the sections and segments of the dialog along with settings like the image base (start) address.
157    ///
158    /// The default implementation for this will construct a new instance identical to that of [`CustomBinaryViewType::create_binary_view`].
159    ///
160    /// Overriding this is encouraged as you can skip actually applying data to the view such as functions,
161    /// symbols, and other data not required for configuration, especially because this binary view is created
162    /// only temporarily and will be discarded after configuration is complete.
163    fn create_binary_view_for_parse(
164        &self,
165        data: &BinaryView,
166    ) -> Result<Self::CustomBinaryView, ()> {
167        self.create_binary_view(data)
168    }
169
170    /// Is this [`BinaryViewType`] valid for the given the raw [`BinaryView`]?
171    ///
172    /// Typical implementations will read the magic bytes (e.g. 'MZ'), this is a performance-sensitive
173    /// path so prefer inexpensive checks rather than comprehensive ones.
174    fn is_valid_for(&self, data: &BinaryView) -> bool;
175
176    /// Get the settings for this view type.
177    ///
178    /// Most implementations will call [`Settings::new_with_id`] with a different id for each invocation.
179    ///
180    /// NOTE: Do not return the global settings instance (via [`Settings::global`]) as this is expected
181    /// to return a list of settings to overlay on top of those for the given `data`.
182    fn load_settings_for_data(&self, _data: &BinaryView) -> Option<Ref<Settings>> {
183        None
184    }
185}
186
187/// A [`BinaryViewType`] acts as a factory for [`BinaryView`] objects.
188///
189/// Each file format will have its own type, such as PE, ELF, or Mach-O.
190///
191/// Custom view types can be implemented using [`CustomBinaryViewType`].
192#[derive(Copy, Clone, PartialEq, Eq, Hash)]
193pub struct BinaryViewType {
194    pub handle: *mut BNBinaryViewType,
195}
196
197impl BinaryViewType {
198    pub(crate) unsafe fn from_raw(handle: *mut BNBinaryViewType) -> Self {
199        debug_assert!(!handle.is_null());
200        Self { handle }
201    }
202
203    pub fn list_all() -> Array<BinaryViewType> {
204        unsafe {
205            let mut count: usize = 0;
206            let types = BNGetBinaryViewTypes(&mut count as *mut _);
207            Array::new(types, count, ())
208        }
209    }
210
211    /// Enumerates all view types and checks to see if the given raw [`BinaryView`] is valid,
212    /// returning only those that are.
213    pub fn valid_types_for_data(data: &BinaryView) -> Array<BinaryViewType> {
214        unsafe {
215            let mut count: usize = 0;
216            let types = BNGetBinaryViewTypesForData(data.handle, &mut count as *mut _);
217            Array::new(types, count, ())
218        }
219    }
220
221    /// Looks up a binary view type by its name (_not_ the long name).
222    pub fn by_name(name: &str) -> Option<Self> {
223        let bytes = name.to_cstr();
224        let handle = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) };
225        if handle.is_null() {
226            None
227        } else {
228            Some(unsafe { BinaryViewType::from_raw(handle) })
229        }
230    }
231
232    /// The given name for the binary view type.
233    pub fn name(&self) -> String {
234        unsafe { BnString::into_string(BNGetBinaryViewTypeName(self.handle)) }
235    }
236
237    /// The given long name for the binary view type.
238    pub fn long_name(&self) -> String {
239        unsafe { BnString::into_string(BNGetBinaryViewTypeLongName(self.handle)) }
240    }
241
242    /// Register an architecture for selection via the `id` and `endianness`.
243    ///
244    /// If you need to peak at the [`BinaryView`] to determine the architecture, use [`BinaryViewType::register_platform_recognizer`]
245    /// instead of this.
246    pub fn register_arch<A: Architecture>(&self, id: u32, endianness: Endianness, arch: &A) {
247        unsafe {
248            BNRegisterArchitectureForViewType(self.handle, id, endianness, arch.as_ref().handle);
249        }
250    }
251
252    /// Register a platform for selection via the `id`.
253    ///
254    /// If you need to peak at the [`BinaryView`] to determine the platform, use [`BinaryViewType::register_platform_recognizer`]
255    /// instead of this.
256    pub fn register_platform(&self, id: u32, plat: &Platform) {
257        let arch = plat.arch();
258        unsafe {
259            BNRegisterPlatformForViewType(self.handle, id, arch.handle, plat.handle);
260        }
261    }
262
263    /// Expanded identification of [`Platform`] for [`BinaryViewType`]'s. Supersedes [`BinaryViewType::register_arch`]
264    /// and [`BinaryViewType::register_platform`], as these have certain edge cases (overloaded elf families, for example)
265    /// that can't be represented.
266    ///
267    /// The callback returns a [`Platform`] object or `None` (failure), and most recently added callbacks are called first
268    /// to allow plugins to override any default behaviors. When a callback returns a platform, architecture will be
269    /// derived from the identified platform.
270    ///
271    /// The [`BinaryView`] is the *parent* view (usually 'Raw') that the [`BinaryView`] is being created for. This
272    /// means that generally speaking, the callbacks need to be aware of the underlying file format. However, the
273    /// [`BinaryView`] implementation may have created data variables in the 'Raw' view by the time the callback is invoked.
274    /// Behavior regarding when this callback is invoked and what has been made available in the [`BinaryView`] passed as an
275    /// argument to the callback is up to the discretion of the [`BinaryView`] implementation.
276    ///
277    /// The `id` ind `endian` arguments are used as a filter to determine which registered [`Platform`] recognizer callbacks
278    /// are invoked.
279    ///
280    /// Support for this API tentatively requires explicit support in the [`BinaryView`] implementation.
281    pub fn register_platform_recognizer<R>(&self, id: u32, endian: Endianness, recognizer: R)
282    where
283        R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync,
284    {
285        #[repr(C)]
286        struct PlatformRecognizerHandlerContext<R>
287        where
288            R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync,
289        {
290            recognizer: R,
291        }
292
293        extern "C" fn cb_recognize_low_level_il<R>(
294            ctxt: *mut std::os::raw::c_void,
295            bv: *mut BNBinaryView,
296            metadata: *mut BNMetadata,
297        ) -> *mut BNPlatform
298        where
299            R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync,
300        {
301            let context = unsafe { &*(ctxt as *mut PlatformRecognizerHandlerContext<R>) };
302            let bv = unsafe { BinaryView::from_raw(bv).to_owned() };
303            let metadata = unsafe { Metadata::from_raw(metadata).to_owned() };
304            match (context.recognizer)(&bv, &metadata) {
305                Some(plat) => unsafe { Ref::into_raw(plat).handle },
306                None => std::ptr::null_mut(),
307            }
308        }
309
310        let recognizer = PlatformRecognizerHandlerContext { recognizer };
311        let raw = Box::into_raw(Box::new(recognizer));
312        unsafe {
313            BNRegisterPlatformRecognizerForViewType(
314                self.handle,
315                id as u64,
316                endian,
317                Some(cb_recognize_low_level_il::<R>),
318                raw as *mut std::os::raw::c_void,
319            )
320        }
321    }
322
323    /// Creates a new instance of the binary view for this given type, constructed with `data` as
324    /// the parent view.
325    ///
326    /// This will also call the initialization routine for the view, after calling this you should
327    /// be able to use the view as normal and ready to start analysis with [`BinaryView::update_analysis`].
328    pub fn create(&self, data: &BinaryView) -> Result<Ref<BinaryView>, ()> {
329        let handle = unsafe { BNCreateBinaryViewOfType(self.handle, data.handle) };
330        if handle.is_null() {
331            // TODO: Proper Result, possibly introduce BNSetError to populate.
332            return Err(());
333        }
334        unsafe { Ok(BinaryView::ref_from_raw(handle)) }
335    }
336
337    /// Creates a new instance of the binary view for parsing, this is a "specialize" version of the
338    /// regular [`BinaryViewType::create`] and is expected to be used when you only want to have the
339    /// view parsed and populated with information required for configuration, like with open with options.
340    pub fn parse(&self, data: &BinaryView) -> Result<Ref<BinaryView>, ()> {
341        let handle = unsafe { BNParseBinaryViewOfType(self.handle, data.handle) };
342        if handle.is_null() {
343            // TODO: Proper Result, possibly introduce BNSetError to populate.
344            return Err(());
345        }
346        unsafe { Ok(BinaryView::ref_from_raw(handle)) }
347    }
348
349    /// Is this [`BinaryViewType`] valid for the given the raw [`BinaryView`]?
350    ///
351    /// Typical implementations will read the magic bytes (e.g. 'MZ'), this is a performance-sensitive
352    /// path so prefer inexpensive checks rather than comprehensive ones.
353    pub fn is_valid_for(&self, data: &BinaryView) -> bool {
354        unsafe { BNIsBinaryViewTypeValidForData(self.handle, data.handle) }
355    }
356
357    /// Is this [`BinaryViewType`] deprecated and should not be used?
358    ///
359    /// We specify this such that the view type may still be used by existing databases, but not
360    /// newly created views.
361    pub fn is_deprecated(&self) -> bool {
362        unsafe { BNIsBinaryViewTypeDeprecated(self.handle) }
363    }
364
365    /// Is this [`BinaryViewType`] able to be loaded forcefully?
366    ///
367    /// If so, it will be shown in the drop-down when a user opens a file with options.
368    pub fn is_force_loadable(&self) -> bool {
369        unsafe { BNIsBinaryViewTypeForceLoadable(self.handle) }
370    }
371
372    /// Do instances of this [`BinaryViewType`] start with no loaded content?
373    ///
374    /// When true, the view has no meaningful default state: the user must make a
375    /// selection (e.g. load images from a shared cache) before any content exists.
376    ///
377    /// Callers can use this to suppress restoring the previously saved view state for
378    /// files not being loaded from a database, since a saved layout would reference
379    /// content that isn't available on reopening.
380    pub fn has_no_initial_content(&self) -> bool {
381        unsafe { BNBinaryViewTypeHasNoInitialContent(self.handle) }
382    }
383
384    pub fn load_settings_for_data(&self, data: &BinaryView) -> Option<Ref<Settings>> {
385        let settings_handle =
386            unsafe { BNGetBinaryViewLoadSettingsForData(self.handle, data.handle) };
387
388        if settings_handle.is_null() {
389            None
390        } else {
391            unsafe { Some(Settings::ref_from_raw(settings_handle)) }
392        }
393    }
394}
395
396impl Debug for BinaryViewType {
397    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
398        f.debug_struct("BinaryViewType")
399            .field("name", &self.name())
400            .field("long_name", &self.long_name())
401            .finish()
402    }
403}
404
405impl CoreArrayProvider for BinaryViewType {
406    type Raw = *mut BNBinaryViewType;
407    type Context = ();
408    type Wrapped<'a> = Guard<'a, BinaryViewType>;
409}
410
411unsafe impl CoreArrayProviderInner for BinaryViewType {
412    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
413        BNFreeBinaryViewTypeList(raw);
414    }
415
416    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
417        Guard::new(BinaryViewType::from_raw(*raw), &())
418    }
419}
420
421unsafe impl Send for BinaryViewType {}
422unsafe impl Sync for BinaryViewType {}
423
424/// Implemented for custom views, responsible for setting up the view state once the binary is open.
425pub trait CustomBinaryView: BinaryViewBase {
426    /// Initializes the opened binary view state.
427    ///
428    /// Use this to populate the [`BinaryView`] with sections, segments, and other view data.
429    ///
430    /// NOTE: You must add **at least** one segment to the view, otherwise calls to [`BinaryViewType::create`]
431    /// will fail.
432    ///
433    /// NOTE: This will be called on every subsequent open of a database, any view data applied here
434    /// should be expected to be regenerated on every open.
435    fn initialize(&mut self, view: &BinaryView) -> bool;
436
437    /// Called after deserialization of the current database snapshot has completed and all the
438    /// view data inside that snapshot has been applied to the view (like sections and segments).
439    ///
440    /// Useful if you need to regenerate temporary data based on the view state.
441    fn on_after_snapshot_data_applied(&mut self) {}
442}
443
444/// Wrapper around `C` when being passed to the custom view constructor so that we have the core
445/// view available to [`CustomBinaryView::initialize`], called from [`cb_init`].
446struct CustomBinaryViewContext<C: CustomBinaryView> {
447    // This is not ref-counted because we do not want to impact the lifetime of the core view, the lifetime
448    // of which is already bound to the lifetime of the custom view (to be freed when the custom view is freed).
449    core_view: MaybeUninit<BinaryView>,
450    view: C,
451}
452
453#[allow(clippy::len_without_is_empty)]
454pub trait BinaryViewBase {
455    fn read(&self, _buf: &mut [u8], _offset: u64) -> usize {
456        0
457    }
458
459    fn write(&self, _offset: u64, _data: &[u8]) -> usize {
460        0
461    }
462
463    fn insert(&self, _offset: u64, _data: &[u8]) -> usize {
464        0
465    }
466
467    fn remove(&self, _offset: u64, _len: usize) -> usize {
468        0
469    }
470
471    /// Check if the offset is valid for the current view.
472    fn offset_valid(&self, offset: u64) -> bool {
473        let mut buf = [0u8; 1];
474        self.read(&mut buf[..], offset) == buf.len()
475    }
476
477    /// Check if the offset is readable for the current view.
478    fn offset_readable(&self, offset: u64) -> bool {
479        self.offset_valid(offset)
480    }
481
482    /// Check if the offset is writable for the current view.
483    fn offset_writable(&self, offset: u64) -> bool {
484        self.offset_valid(offset)
485    }
486
487    /// Check if the offset is executable for the current view.
488    fn offset_executable(&self, offset: u64) -> bool {
489        self.offset_valid(offset)
490    }
491
492    /// Check if the offset is backed by the original file and not added after the fact.
493    fn offset_backed_by_file(&self, offset: u64) -> bool {
494        self.offset_valid(offset)
495    }
496
497    /// Get the next valid offset after the provided `offset`, useful if you need to iterate over all
498    /// readable offsets in the view.
499    fn next_valid_offset_after(&self, offset: u64) -> u64 {
500        let start = self.start();
501        if offset < start {
502            start
503        } else {
504            offset
505        }
506    }
507
508    /// Whether the data at the given `offset` been modified (patched).
509    fn modification_status(&self, _offset: u64) -> ModificationStatus {
510        ModificationStatus::Original
511    }
512
513    /// The lowest address in the view.
514    fn start(&self) -> u64 {
515        0
516    }
517
518    /// The length of the view.
519    fn len(&self) -> u64 {
520        0
521    }
522
523    fn executable(&self) -> bool {
524        true
525    }
526
527    fn relocatable(&self) -> bool {
528        false
529    }
530
531    fn entry_point(&self) -> u64 {
532        0
533    }
534
535    fn default_endianness(&self) -> Endianness;
536
537    fn address_size(&self) -> usize;
538
539    // TODO: Needs to take file accessor?
540    fn save(&self) -> bool {
541        false
542    }
543}
544
545#[derive(Debug, Clone)]
546pub struct ActiveAnalysisInfo {
547    pub func: Ref<Function>,
548    pub analysis_time: u64,
549    pub update_count: usize,
550    pub submit_count: usize,
551}
552
553#[derive(Debug, Clone)]
554pub struct AnalysisInfo {
555    pub state: AnalysisState,
556    pub analysis_time: u64,
557    pub active_info: Vec<ActiveAnalysisInfo>,
558}
559
560#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
561pub enum AnalysisProgress {
562    Initial,
563    Hold,
564    Idle,
565    Discovery,
566    Disassembling(usize, usize),
567    Analyzing(usize, usize),
568    ExtendedAnalysis,
569}
570
571impl Display for AnalysisProgress {
572    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
573        match self {
574            AnalysisProgress::Initial => {
575                write!(f, "Initial")
576            }
577            AnalysisProgress::Hold => {
578                write!(f, "Hold")
579            }
580            AnalysisProgress::Idle => {
581                write!(f, "Idle")
582            }
583            AnalysisProgress::Discovery => {
584                write!(f, "Discovery")
585            }
586            AnalysisProgress::Disassembling(count, total) => {
587                write!(f, "Disassembling ({count}/{total})")
588            }
589            AnalysisProgress::Analyzing(count, total) => {
590                write!(f, "Analyzing ({count}/{total})")
591            }
592            AnalysisProgress::ExtendedAnalysis => {
593                write!(f, "Extended Analysis")
594            }
595        }
596    }
597}
598
599impl From<BNAnalysisProgress> for AnalysisProgress {
600    fn from(value: BNAnalysisProgress) -> Self {
601        match value.state {
602            BNAnalysisState::InitialState => Self::Initial,
603            BNAnalysisState::HoldState => Self::Hold,
604            BNAnalysisState::IdleState => Self::Idle,
605            BNAnalysisState::DiscoveryState => Self::Discovery,
606            BNAnalysisState::DisassembleState => Self::Disassembling(value.count, value.total),
607            BNAnalysisState::AnalyzeState => Self::Analyzing(value.count, value.total),
608            BNAnalysisState::ExtendedAnalyzeState => Self::ExtendedAnalysis,
609        }
610    }
611}
612
613/// Represents the "whole view" of the binary and its analysis.
614///
615/// Analysis information:
616///
617/// - [`BinaryView::functions`]
618/// - [`BinaryView::data_variables`]
619/// - [`BinaryView::strings`]
620///
621/// Annotation information:
622///
623/// - [`BinaryView::symbols`]
624/// - [`BinaryView::tags_all_scopes`]
625/// - [`BinaryView::comments`]
626///
627/// Data representation and binary information:
628///
629/// - [`BinaryView::types`]
630/// - [`BinaryView::segments`]
631/// - [`BinaryView::sections`]
632///
633/// # Cleaning up
634///
635/// [`BinaryView`] has a cyclic relationship with the associated [`FileMetadata`], each holds a strong
636/// reference to one another, so to properly clean up/free the [`BinaryView`], you must manually close the
637/// file using [`FileMetadata::close`], this is not fixable in the general case, until [`FileMetadata`]
638/// has only a weak reference to the [`BinaryView`].
639#[derive(PartialEq, Eq, Hash)]
640pub struct BinaryView {
641    pub handle: *mut BNBinaryView,
642}
643
644impl BinaryView {
645    pub unsafe fn from_raw(handle: *mut BNBinaryView) -> Self {
646        debug_assert!(!handle.is_null());
647        Self { handle }
648    }
649
650    pub(crate) unsafe fn ref_from_raw(handle: *mut BNBinaryView) -> Ref<Self> {
651        debug_assert!(!handle.is_null());
652        Ref::new(Self { handle })
653    }
654
655    /// Create a core instance of the [`CustomBinaryView`].
656    pub fn from_custom<C: CustomBinaryView>(
657        view_type_name: &str,
658        file: &FileMetadata,
659        parent_view: &BinaryView,
660        view: C,
661    ) -> Result<Ref<Self>, ()> {
662        let type_name = view_type_name.to_cstr();
663        // We need to pass the core BinaryView when initializing the custom view state with [`CustomBinaryView::initialize`],
664        // and to do that we need to store the returned core view handle after creating the custom view.
665        let custom_context = CustomBinaryViewContext {
666            core_view: MaybeUninit::uninit(),
667            view,
668        };
669        // We leak to be freed in `cb_free_object`.
670        let leaked_view = Box::leak(Box::new(custom_context));
671        let handle = unsafe {
672            BNCreateCustomBinaryView(
673                type_name.as_ptr(),
674                file.handle,
675                parent_view.handle,
676                &mut BNCustomBinaryView {
677                    context: leaked_view as *mut CustomBinaryViewContext<C> as *mut _,
678                    init: Some(cb_init::<C>),
679                    freeObject: Some(cb_free_object::<C>),
680                    externalRefTaken: None,
681                    externalRefReleased: None,
682                    read: Some(cb_read::<C>),
683                    write: Some(cb_write::<C>),
684                    insert: Some(cb_insert::<C>),
685                    remove: Some(cb_remove::<C>),
686                    getModification: Some(cb_modification::<C>),
687                    isValidOffset: Some(cb_offset_valid::<C>),
688                    isOffsetReadable: Some(cb_offset_readable::<C>),
689                    isOffsetWritable: Some(cb_offset_writable::<C>),
690                    isOffsetExecutable: Some(cb_offset_executable::<C>),
691                    isOffsetBackedByFile: Some(cb_offset_backed_by_file::<C>),
692                    getNextValidOffset: Some(cb_next_valid_offset::<C>),
693                    getStart: Some(cb_start::<C>),
694                    getLength: Some(cb_length::<C>),
695                    getEntryPoint: Some(cb_entry_point::<C>),
696                    isExecutable: Some(cb_executable::<C>),
697                    getDefaultEndianness: Some(cb_endianness::<C>),
698                    isRelocatable: Some(cb_relocatable::<C>),
699                    getAddressSize: Some(cb_address_size::<C>),
700                    save: Some(cb_save::<C>),
701                    onAfterSnapshotDataApplied: Some(cb_on_after_snapshot_data_applied::<C>),
702                },
703            )
704        };
705        if handle.is_null() {
706            // We need to free the custom context manually.
707            let _ = unsafe { Box::from_raw(leaked_view) };
708            return Err(());
709        }
710        leaked_view.core_view = unsafe { MaybeUninit::new(BinaryView::from_raw(handle)) };
711        unsafe { Ok(Ref::new(Self { handle })) }
712    }
713
714    /// Construct the raw binary view from the given metadata.
715    ///
716    /// Before calling this, make sure you have a valid file path set for the [`FileMetadata`]. It is
717    /// required that the [`FileMetadata::file_path`] exist in the local filesystem.
718    pub fn from_metadata(meta: &FileMetadata) -> Result<Ref<Self>, ()> {
719        if !meta.file_path().exists() {
720            return Err(());
721        }
722        let file = meta.file_path().to_cstr();
723        let handle =
724            unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) };
725        if handle.is_null() {
726            return Err(());
727        }
728        unsafe { Ok(Ref::new(Self { handle })) }
729    }
730
731    /// Construct the raw binary view from the given `file_path` and metadata.
732    ///
733    /// This will implicitly set the metadata file path and then construct the view. If the metadata
734    /// already has the desired file path, use [`BinaryView::from_metadata`] instead.
735    pub fn from_path(meta: &FileMetadata, file_path: impl AsRef<Path>) -> Result<Ref<Self>, ()> {
736        meta.set_file_path(file_path.as_ref());
737        Self::from_metadata(meta)
738    }
739
740    // TODO: Provide an API that manages the lifetime of the accessor and the view.
741    /// Construct the raw binary view from the given `accessor` and metadata.
742    ///
743    /// It is the responsibility of the caller to keep the accessor alive for the lifetime of the view;
744    /// because of this, we mark the function as unsafe.
745    pub unsafe fn from_accessor<A: Accessor>(
746        meta: &FileMetadata,
747        accessor: &mut FileAccessor<A>,
748    ) -> Result<Ref<Self>, ()> {
749        let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut accessor.raw) };
750        if handle.is_null() {
751            return Err(());
752        }
753        unsafe { Ok(Ref::new(Self { handle })) }
754    }
755
756    /// Construct the raw binary view from the given `data` and metadata.
757    ///
758    /// The data will be copied into the view, so the caller does not need to keep the data alive.
759    pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Ref<Self> {
760        let handle = unsafe {
761            BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len())
762        };
763        assert!(
764            !handle.is_null(),
765            "BNCreateBinaryDataViewFromData should always succeed"
766        );
767        unsafe { Ref::new(Self { handle }) }
768    }
769
770    /// Save the original binary file to the provided `file_path` along with any modifications.
771    ///
772    /// WARNING: Currently, there is a possibility to deadlock if the analysis has queued up a main thread action
773    /// that tries to take the [`FileMetadata`] lock of the current view and is executed while we
774    /// are executing in this function.
775    ///
776    /// To avoid the above issue, use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there
777    /// are no queued up main thread actions.
778    pub fn save_to_path(&self, file_path: impl AsRef<Path>) -> bool {
779        let file = file_path.as_ref().to_cstr();
780        unsafe { BNSaveToFilename(self.handle, file.as_ptr() as *mut _) }
781    }
782
783    /// Save the original binary file to the provided [`FileAccessor`] along with any modifications.
784    ///
785    /// WARNING: Currently, there is a possibility to deadlock if the analysis has queued up a main thread action
786    /// that tries to take the [`FileMetadata`] lock of the current view and is executed while we
787    /// are executing in this function.
788    ///
789    /// To avoid the above issue, use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there
790    /// are no queued up main thread actions.
791    pub fn save_to_accessor<A: Accessor>(&self, file: &mut FileAccessor<A>) -> bool {
792        unsafe { BNSaveToFile(self.handle, &mut file.raw) }
793    }
794
795    pub fn file(&self) -> Ref<FileMetadata> {
796        unsafe {
797            let raw = BNGetFileForView(self.handle);
798            FileMetadata::ref_from_raw(raw)
799        }
800    }
801
802    pub fn parent_view(&self) -> Option<Ref<BinaryView>> {
803        let raw_view_ptr = unsafe { BNGetParentView(self.handle) };
804        match raw_view_ptr.is_null() {
805            false => Some(unsafe { BinaryView::ref_from_raw(raw_view_ptr) }),
806            true => None,
807        }
808    }
809
810    pub fn raw_view(&self) -> Option<Ref<BinaryView>> {
811        self.file().view_of_type("Raw")
812    }
813
814    pub fn view_type(&self) -> String {
815        let ptr: *mut c_char = unsafe { BNGetViewType(self.handle) };
816        unsafe { BnString::into_string(ptr) }
817    }
818
819    /// Reads up to `len` bytes from address `offset`
820    pub fn read_vec(&self, offset: u64, len: usize) -> Vec<u8> {
821        let mut ret = vec![0; len];
822        let size = self.read(&mut ret, offset);
823        ret.truncate(size);
824        ret
825    }
826
827    /// Appends up to `len` bytes from address `offset` into `dest`
828    pub fn read_into_vec(&self, dest: &mut Vec<u8>, offset: u64, len: usize) -> usize {
829        let starting_len = dest.len();
830        dest.resize(starting_len + len, 0);
831        let read_size = self.read(&mut dest[starting_len..], offset);
832        dest.truncate(starting_len + read_size);
833        read_size
834    }
835
836    /// Reads up to `len` bytes from the address `offset` returning a `CString` if available.
837    pub fn read_c_string_at(&self, offset: u64, len: usize) -> Option<CString> {
838        let mut buf = vec![0; len];
839        let size = self.read(&mut buf, offset);
840        let string = CString::new(buf[..size].to_vec()).ok()?;
841        Some(string)
842    }
843
844    /// Reads up to `len` bytes from the address `offset` returning a `String` if available.
845    pub fn read_utf8_string_at(&self, offset: u64, len: usize) -> Option<String> {
846        let mut buf = vec![0; len];
847        let size = self.read(&mut buf, offset);
848        let string = String::from_utf8(buf[..size].to_vec()).ok()?;
849        Some(string)
850    }
851
852    /// Search the view using the query options.
853    ///
854    /// In the `on_match` callback return `false` to stop searching.
855    pub fn search<C: FnMut(u64, &DataBuffer) -> bool>(
856        &self,
857        query: &SearchQuery,
858        on_match: C,
859    ) -> bool {
860        self.search_with_progress(query, on_match, NoProgressCallback)
861    }
862
863    /// Search the view using the query options.
864    ///
865    /// In the `on_match` callback return `false` to stop searching.
866    pub fn search_with_progress<P: ProgressCallback, C: FnMut(u64, &DataBuffer) -> bool>(
867        &self,
868        query: &SearchQuery,
869        mut on_match: C,
870        mut progress: P,
871    ) -> bool {
872        unsafe extern "C" fn cb_on_match<C: FnMut(u64, &DataBuffer) -> bool>(
873            ctx: *mut c_void,
874            offset: u64,
875            data: *mut BNDataBuffer,
876        ) -> bool {
877            let f = ctx as *mut C;
878            let buffer = DataBuffer::from_raw(data);
879            (*f)(offset, &buffer)
880        }
881
882        let query = query.to_json().to_cstr();
883        unsafe {
884            BNSearch(
885                self.handle,
886                query.as_ptr(),
887                &mut progress as *mut P as *mut c_void,
888                Some(P::cb_progress_callback),
889                &mut on_match as *const C as *mut c_void,
890                Some(cb_on_match::<C>),
891            )
892        }
893    }
894
895    pub fn find_next_data(&self, start: u64, end: u64, data: &DataBuffer) -> Option<u64> {
896        self.find_next_data_with_opts(
897            start,
898            end,
899            data,
900            FindFlag::FindCaseInsensitive,
901            NoProgressCallback,
902        )
903    }
904
905    /// # Warning
906    ///
907    /// This function is likely to be changed to take in a "query" structure. Or deprecated entirely.
908    pub fn find_next_data_with_opts<P: ProgressCallback>(
909        &self,
910        start: u64,
911        end: u64,
912        data: &DataBuffer,
913        flag: FindFlag,
914        mut progress: P,
915    ) -> Option<u64> {
916        let mut result: u64 = 0;
917        let found = unsafe {
918            BNFindNextDataWithProgress(
919                self.handle,
920                start,
921                end,
922                data.as_raw(),
923                &mut result,
924                flag,
925                &mut progress as *mut P as *mut c_void,
926                Some(P::cb_progress_callback),
927            )
928        };
929
930        if found {
931            Some(result)
932        } else {
933            None
934        }
935    }
936
937    pub fn find_next_constant(
938        &self,
939        start: u64,
940        end: u64,
941        constant: u64,
942        view_type: FunctionViewType,
943    ) -> Option<u64> {
944        // TODO: What are the best "default" settings?
945        let settings = DisassemblySettings::new();
946        self.find_next_constant_with_opts(
947            start,
948            end,
949            constant,
950            &settings,
951            view_type,
952            NoProgressCallback,
953        )
954    }
955
956    /// # Warning
957    ///
958    /// This function is likely to be changed to take in a "query" structure.
959    pub fn find_next_constant_with_opts<P: ProgressCallback>(
960        &self,
961        start: u64,
962        end: u64,
963        constant: u64,
964        disasm_settings: &DisassemblySettings,
965        view_type: FunctionViewType,
966        mut progress: P,
967    ) -> Option<u64> {
968        let mut result: u64 = 0;
969        let raw_view_type = FunctionViewType::into_raw(view_type);
970        let found = unsafe {
971            BNFindNextConstantWithProgress(
972                self.handle,
973                start,
974                end,
975                constant,
976                &mut result,
977                disasm_settings.handle,
978                raw_view_type,
979                &mut progress as *mut P as *mut c_void,
980                Some(P::cb_progress_callback),
981            )
982        };
983        FunctionViewType::free_raw(raw_view_type);
984
985        if found {
986            Some(result)
987        } else {
988            None
989        }
990    }
991
992    pub fn find_next_text(
993        &self,
994        start: u64,
995        end: u64,
996        text: &str,
997        view_type: FunctionViewType,
998    ) -> Option<u64> {
999        // TODO: What are the best "default" settings?
1000        let settings = DisassemblySettings::new();
1001        self.find_next_text_with_opts(
1002            start,
1003            end,
1004            text,
1005            &settings,
1006            FindFlag::FindCaseInsensitive,
1007            view_type,
1008            NoProgressCallback,
1009        )
1010    }
1011
1012    /// # Warning
1013    ///
1014    /// This function is likely to be changed to take in a "query" structure.
1015    pub fn find_next_text_with_opts<P: ProgressCallback>(
1016        &self,
1017        start: u64,
1018        end: u64,
1019        text: &str,
1020        disasm_settings: &DisassemblySettings,
1021        flag: FindFlag,
1022        view_type: FunctionViewType,
1023        mut progress: P,
1024    ) -> Option<u64> {
1025        let text = text.to_cstr();
1026        let raw_view_type = FunctionViewType::into_raw(view_type);
1027        let mut result: u64 = 0;
1028        let found = unsafe {
1029            BNFindNextTextWithProgress(
1030                self.handle,
1031                start,
1032                end,
1033                text.as_ptr(),
1034                &mut result,
1035                disasm_settings.handle,
1036                flag,
1037                raw_view_type,
1038                &mut progress as *mut P as *mut c_void,
1039                Some(P::cb_progress_callback),
1040            )
1041        };
1042        FunctionViewType::free_raw(raw_view_type);
1043
1044        if found {
1045            Some(result)
1046        } else {
1047            None
1048        }
1049    }
1050
1051    pub fn notify_data_written(&self, offset: u64, len: usize) {
1052        unsafe {
1053            BNNotifyDataWritten(self.handle, offset, len);
1054        }
1055    }
1056
1057    pub fn notify_data_inserted(&self, offset: u64, len: usize) {
1058        unsafe {
1059            BNNotifyDataInserted(self.handle, offset, len);
1060        }
1061    }
1062
1063    pub fn notify_data_removed(&self, offset: u64, len: usize) {
1064        unsafe {
1065            BNNotifyDataRemoved(self.handle, offset, len as u64);
1066        }
1067    }
1068
1069    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
1070    /// offset has code semantics.
1071    pub fn offset_has_code_semantics(&self, offset: u64) -> bool {
1072        unsafe { BNIsOffsetCodeSemantics(self.handle, offset) }
1073    }
1074
1075    /// Check if the offset is within a [`Section`] with [`crate::section::Semantics::External`].
1076    pub fn offset_has_extern_semantics(&self, offset: u64) -> bool {
1077        unsafe { BNIsOffsetExternSemantics(self.handle, offset) }
1078    }
1079
1080    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
1081    /// offset has writable semantics.
1082    pub fn offset_has_writable_semantics(&self, offset: u64) -> bool {
1083        unsafe { BNIsOffsetWritableSemantics(self.handle, offset) }
1084    }
1085
1086    /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the
1087    /// offset has read only semantics.
1088    pub fn offset_has_read_only_semantics(&self, offset: u64) -> bool {
1089        unsafe { BNIsOffsetReadOnlySemantics(self.handle, offset) }
1090    }
1091
1092    pub fn image_base(&self) -> u64 {
1093        unsafe { BNGetImageBase(self.handle) }
1094    }
1095
1096    pub fn original_image_base(&self) -> u64 {
1097        unsafe { BNGetOriginalImageBase(self.handle) }
1098    }
1099
1100    pub fn set_original_image_base(&self, image_base: u64) {
1101        unsafe { BNSetOriginalImageBase(self.handle, image_base) }
1102    }
1103
1104    /// The highest address in the view.
1105    pub fn end(&self) -> u64 {
1106        unsafe { BNGetEndOffset(self.handle) }
1107    }
1108
1109    pub fn add_analysis_option(&self, name: &str) {
1110        let name = name.to_cstr();
1111        unsafe { BNAddAnalysisOption(self.handle, name.as_ptr()) }
1112    }
1113
1114    pub fn has_initial_analysis(&self) -> bool {
1115        unsafe { BNHasInitialAnalysis(self.handle) }
1116    }
1117
1118    pub fn set_analysis_hold(&self, enable: bool) {
1119        unsafe { BNSetAnalysisHold(self.handle, enable) }
1120    }
1121
1122    /// Runs the analysis pipeline, analyzing any data that has been marked for updates.
1123    ///
1124    /// You can explicitly mark a function to be updated with:
1125    /// - [`Function::mark_updates_required`]
1126    /// - [`Function::mark_caller_updates_required`]
1127    ///
1128    /// NOTE: This is a **non-blocking** call, use [`BinaryView::update_analysis_and_wait`] if you
1129    /// require analysis to have completed before moving on.
1130    pub fn update_analysis(&self) {
1131        unsafe {
1132            BNUpdateAnalysis(self.handle);
1133        }
1134    }
1135
1136    /// Runs the analysis pipeline, analyzing any data that has been marked for updates.
1137    ///
1138    /// You can explicitly mark a function to be updated with:
1139    /// - [`Function::mark_updates_required`]
1140    /// - [`Function::mark_caller_updates_required`]
1141    ///
1142    /// NOTE: This is a **blocking** call, use [`BinaryView::update_analysis`] if you do not
1143    /// need to wait for the analysis update to finish.
1144    pub fn update_analysis_and_wait(&self) {
1145        unsafe {
1146            BNUpdateAnalysisAndWait(self.handle);
1147        }
1148    }
1149
1150    /// Causes **all** functions to be reanalyzed.
1151    ///
1152    /// Use [`BinaryView::update_analysis`] or [`BinaryView::update_analysis_and_wait`] instead
1153    /// if you want to incrementally update analysis.
1154    ///
1155    /// NOTE: This function does not wait for the analysis to finish.
1156    pub fn reanalyze(&self) {
1157        unsafe {
1158            BNReanalyzeAllFunctions(self.handle);
1159        }
1160    }
1161
1162    pub fn abort_analysis(&self) {
1163        unsafe { BNAbortAnalysis(self.handle) }
1164    }
1165
1166    pub fn analysis_is_aborted(&self) -> bool {
1167        unsafe { BNAnalysisIsAborted(self.handle) }
1168    }
1169
1170    pub fn workflow(&self) -> Ref<Workflow> {
1171        unsafe {
1172            let raw_ptr = BNGetWorkflowForBinaryView(self.handle);
1173            let nonnull = NonNull::new(raw_ptr).expect("All views must have a workflow");
1174            Workflow::ref_from_raw(nonnull)
1175        }
1176    }
1177
1178    pub fn analysis_info(&self) -> AnalysisInfo {
1179        let info_ptr = unsafe { BNGetAnalysisInfo(self.handle) };
1180        assert!(!info_ptr.is_null());
1181        let info = unsafe { *info_ptr };
1182        let active_infos = unsafe { std::slice::from_raw_parts(info.activeInfo, info.count) };
1183
1184        let mut active_info_list = vec![];
1185        for active_info in active_infos {
1186            let func = unsafe { Function::from_raw(active_info.func).to_owned() };
1187            active_info_list.push(ActiveAnalysisInfo {
1188                func,
1189                analysis_time: active_info.analysisTime,
1190                update_count: active_info.updateCount,
1191                submit_count: active_info.submitCount,
1192            });
1193        }
1194
1195        let result = AnalysisInfo {
1196            state: info.state,
1197            analysis_time: info.analysisTime,
1198            active_info: active_info_list,
1199        };
1200
1201        unsafe { BNFreeAnalysisInfo(info_ptr) };
1202        result
1203    }
1204
1205    pub fn analysis_progress(&self) -> AnalysisProgress {
1206        let progress_raw = unsafe { BNGetAnalysisProgress(self.handle) };
1207        AnalysisProgress::from(progress_raw)
1208    }
1209
1210    pub fn default_arch(&self) -> Option<CoreArchitecture> {
1211        unsafe {
1212            let raw = BNGetDefaultArchitecture(self.handle);
1213
1214            if raw.is_null() {
1215                return None;
1216            }
1217
1218            Some(CoreArchitecture::from_raw(raw))
1219        }
1220    }
1221
1222    pub fn set_default_arch<A: Architecture>(&self, arch: &A) {
1223        unsafe {
1224            BNSetDefaultArchitecture(self.handle, arch.as_ref().handle);
1225        }
1226    }
1227
1228    pub fn default_platform(&self) -> Option<Ref<Platform>> {
1229        unsafe {
1230            let raw = BNGetDefaultPlatform(self.handle);
1231
1232            if raw.is_null() {
1233                return None;
1234            }
1235
1236            Some(Platform::ref_from_raw(raw))
1237        }
1238    }
1239
1240    pub fn set_default_platform(&self, plat: &Platform) {
1241        unsafe {
1242            BNSetDefaultPlatform(self.handle, plat.handle);
1243        }
1244    }
1245
1246    pub fn base_address_detection(&self) -> Option<BaseAddressDetection> {
1247        unsafe {
1248            let handle = BNCreateBaseAddressDetection(self.handle);
1249            NonNull::new(handle).map(|base| BaseAddressDetection::from_raw(base))
1250        }
1251    }
1252
1253    pub fn instruction_len<A: Architecture>(&self, arch: &A, addr: u64) -> Option<usize> {
1254        unsafe {
1255            let size = BNGetInstructionLength(self.handle, arch.as_ref().handle, addr);
1256
1257            if size > 0 {
1258                Some(size)
1259            } else {
1260                None
1261            }
1262        }
1263    }
1264
1265    pub fn symbol_by_address(&self, addr: u64) -> Option<Ref<Symbol>> {
1266        unsafe {
1267            let raw_sym_ptr = BNGetSymbolByAddress(self.handle, addr, std::ptr::null_mut());
1268            match raw_sym_ptr.is_null() {
1269                false => Some(Symbol::ref_from_raw(raw_sym_ptr)),
1270                true => None,
1271            }
1272        }
1273    }
1274
1275    pub fn symbol_by_raw_name(&self, raw_name: impl IntoCStr) -> Option<Ref<Symbol>> {
1276        let raw_name = raw_name.to_cstr();
1277
1278        unsafe {
1279            let raw_sym_ptr =
1280                BNGetSymbolByRawName(self.handle, raw_name.as_ptr(), std::ptr::null_mut());
1281            match raw_sym_ptr.is_null() {
1282                false => Some(Symbol::ref_from_raw(raw_sym_ptr)),
1283                true => None,
1284            }
1285        }
1286    }
1287
1288    pub fn symbols(&self) -> Array<Symbol> {
1289        unsafe {
1290            let mut count = 0;
1291            let handles = BNGetSymbols(self.handle, &mut count, std::ptr::null_mut());
1292
1293            Array::new(handles, count, ())
1294        }
1295    }
1296
1297    pub fn symbols_by_name(&self, name: impl IntoCStr) -> Array<Symbol> {
1298        let raw_name = name.to_cstr();
1299
1300        unsafe {
1301            let mut count = 0;
1302            let handles = BNGetSymbolsByName(
1303                self.handle,
1304                raw_name.as_ptr(),
1305                &mut count,
1306                std::ptr::null_mut(),
1307            );
1308
1309            Array::new(handles, count, ())
1310        }
1311    }
1312
1313    pub fn symbols_in_range(&self, range: Range<u64>) -> Array<Symbol> {
1314        unsafe {
1315            let mut count = 0;
1316            let len = range.end.wrapping_sub(range.start);
1317            let handles = BNGetSymbolsInRange(
1318                self.handle,
1319                range.start,
1320                len,
1321                &mut count,
1322                std::ptr::null_mut(),
1323            );
1324
1325            Array::new(handles, count, ())
1326        }
1327    }
1328
1329    pub fn symbols_of_type(&self, ty: SymbolType) -> Array<Symbol> {
1330        unsafe {
1331            let mut count = 0;
1332            let handles =
1333                BNGetSymbolsOfType(self.handle, ty.into(), &mut count, std::ptr::null_mut());
1334
1335            Array::new(handles, count, ())
1336        }
1337    }
1338
1339    pub fn symbols_of_type_in_range(&self, ty: SymbolType, range: Range<u64>) -> Array<Symbol> {
1340        unsafe {
1341            let mut count = 0;
1342            let len = range.end.wrapping_sub(range.start);
1343            let handles = BNGetSymbolsOfTypeInRange(
1344                self.handle,
1345                ty.into(),
1346                range.start,
1347                len,
1348                &mut count,
1349                std::ptr::null_mut(),
1350            );
1351
1352            Array::new(handles, count, ())
1353        }
1354    }
1355
1356    pub fn define_auto_symbol(&self, sym: &Symbol) {
1357        unsafe {
1358            BNDefineAutoSymbol(self.handle, sym.handle);
1359        }
1360    }
1361
1362    /// Defines the symbol as well as the analysis object associated with the given symbol type, such as
1363    /// the data variable for a [`SymbolType::Data`], or the function for a [`SymbolType::Function`].
1364    /// Returns the symbol, as it was applied to the binary view.
1365    pub fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>(
1366        &self,
1367        sym: &Symbol,
1368        plat: &Platform,
1369        ty: T,
1370    ) -> Ref<Symbol> {
1371        let mut type_with_conf = BNTypeWithConfidence {
1372            type_: if let Some(t) = ty.into() {
1373                t.handle
1374            } else {
1375                std::ptr::null_mut()
1376            },
1377            confidence: BN_FULL_CONFIDENCE,
1378        };
1379
1380        unsafe {
1381            let raw_sym = BNDefineAutoSymbolAndVariableOrFunction(
1382                self.handle,
1383                plat.handle,
1384                sym.handle,
1385                &mut type_with_conf,
1386            );
1387            // We should always get the symbol back as it is defined.
1388            debug_assert!(
1389                !raw_sym.is_null(),
1390                "BNDefineAutoSymbolAndVariableOrFunction should not return null"
1391            );
1392            Symbol::ref_from_raw(raw_sym)
1393        }
1394    }
1395
1396    pub fn undefine_auto_symbol(&self, sym: &Symbol) {
1397        unsafe {
1398            BNUndefineAutoSymbol(self.handle, sym.handle);
1399        }
1400    }
1401
1402    pub fn define_user_symbol(&self, sym: &Symbol) {
1403        unsafe {
1404            BNDefineUserSymbol(self.handle, sym.handle);
1405        }
1406    }
1407
1408    pub fn undefine_user_symbol(&self, sym: &Symbol) {
1409        unsafe {
1410            BNUndefineUserSymbol(self.handle, sym.handle);
1411        }
1412    }
1413
1414    pub fn data_variables(&self) -> Array<DataVariable> {
1415        unsafe {
1416            let mut count = 0;
1417            let vars = BNGetDataVariables(self.handle, &mut count);
1418            Array::new(vars, count, ())
1419        }
1420    }
1421
1422    pub fn data_variable_at_address(&self, addr: u64) -> Option<DataVariable> {
1423        let mut dv = BNDataVariable::default();
1424        unsafe {
1425            if BNGetDataVariableAtAddress(self.handle, addr, &mut dv) {
1426                Some(DataVariable::from_owned_raw(dv))
1427            } else {
1428                None
1429            }
1430        }
1431    }
1432
1433    pub fn define_auto_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) {
1434        let mut owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
1435        unsafe {
1436            BNDefineDataVariable(self.handle, addr, &mut owned_raw_ty);
1437        }
1438    }
1439
1440    /// You likely would also like to call [`BinaryView::define_user_symbol`] to bind this data variable with a name
1441    pub fn define_user_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) {
1442        let mut owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
1443        unsafe {
1444            BNDefineUserDataVariable(self.handle, addr, &mut owned_raw_ty);
1445        }
1446    }
1447
1448    pub fn undefine_auto_data_var(&self, addr: u64, blacklist: Option<bool>) {
1449        unsafe {
1450            BNUndefineDataVariable(self.handle, addr, blacklist.unwrap_or(true));
1451        }
1452    }
1453
1454    pub fn undefine_user_data_var(&self, addr: u64) {
1455        unsafe {
1456            BNUndefineUserDataVariable(self.handle, addr);
1457        }
1458    }
1459
1460    pub fn define_auto_type<T: Into<QualifiedName>>(
1461        &self,
1462        name: T,
1463        source: &str,
1464        type_obj: &Type,
1465    ) -> QualifiedName {
1466        let mut raw_name = QualifiedName::into_raw(name.into());
1467        let source_str = source.to_cstr();
1468        let name_handle = unsafe {
1469            let id_str =
1470                BNGenerateAutoTypeId(source_str.as_ref().as_ptr() as *const _, &mut raw_name);
1471            let name_handle =
1472                BNDefineAnalysisType(self.handle, id_str, &mut raw_name, type_obj.handle);
1473            BNFreeString(id_str);
1474            name_handle
1475        };
1476        QualifiedName::free_raw(raw_name);
1477        QualifiedName::from_owned_raw(name_handle)
1478    }
1479
1480    pub fn define_auto_type_with_id<T: Into<QualifiedName>>(
1481        &self,
1482        name: T,
1483        id: &str,
1484        type_obj: &Type,
1485    ) -> QualifiedName {
1486        let mut raw_name = QualifiedName::into_raw(name.into());
1487        let id_str = id.to_cstr();
1488        let result_raw_name = unsafe {
1489            BNDefineAnalysisType(
1490                self.handle,
1491                id_str.as_ref().as_ptr() as *const _,
1492                &mut raw_name,
1493                type_obj.handle,
1494            )
1495        };
1496        QualifiedName::free_raw(raw_name);
1497        QualifiedName::from_owned_raw(result_raw_name)
1498    }
1499
1500    pub fn define_user_type<T: Into<QualifiedName>>(&self, name: T, type_obj: &Type) {
1501        let mut raw_name = QualifiedName::into_raw(name.into());
1502        unsafe { BNDefineUserAnalysisType(self.handle, &mut raw_name, type_obj.handle) }
1503        QualifiedName::free_raw(raw_name);
1504    }
1505
1506    pub fn define_auto_types<T, I>(
1507        &self,
1508        names_sources_and_types: T,
1509    ) -> HashMap<String, QualifiedName>
1510    where
1511        T: Iterator<Item = I>,
1512        I: Into<QualifiedNameTypeAndId>,
1513    {
1514        self.define_auto_types_with_progress(names_sources_and_types, NoProgressCallback)
1515    }
1516
1517    pub fn define_auto_types_with_progress<T, I, P>(
1518        &self,
1519        names_sources_and_types: T,
1520        mut progress: P,
1521    ) -> HashMap<String, QualifiedName>
1522    where
1523        T: Iterator<Item = I>,
1524        I: Into<QualifiedNameTypeAndId>,
1525        P: ProgressCallback,
1526    {
1527        let mut types: Vec<BNQualifiedNameTypeAndId> = names_sources_and_types
1528            .map(Into::into)
1529            .map(QualifiedNameTypeAndId::into_raw)
1530            .collect();
1531        let mut result_ids: *mut *mut c_char = std::ptr::null_mut();
1532        let mut result_names: *mut BNQualifiedName = std::ptr::null_mut();
1533
1534        let result_count = unsafe {
1535            BNDefineAnalysisTypes(
1536                self.handle,
1537                types.as_mut_ptr(),
1538                types.len(),
1539                Some(P::cb_progress_callback),
1540                &mut progress as *mut P as *mut c_void,
1541                &mut result_ids as *mut _,
1542                &mut result_names as *mut _,
1543            )
1544        };
1545
1546        for ty in types {
1547            QualifiedNameTypeAndId::free_raw(ty);
1548        }
1549
1550        let id_array = unsafe { Array::<BnString>::new(result_ids, result_count, ()) };
1551        let name_array = unsafe { Array::<QualifiedName>::new(result_names, result_count, ()) };
1552        id_array
1553            .into_iter()
1554            .zip(&name_array)
1555            .map(|(id, name)| (id.to_owned(), name))
1556            .collect()
1557    }
1558
1559    pub fn define_user_types<T, I>(&self, names_and_types: T)
1560    where
1561        T: Iterator<Item = I>,
1562        I: Into<QualifiedNameAndType>,
1563    {
1564        self.define_user_types_with_progress(names_and_types, NoProgressCallback);
1565    }
1566
1567    pub fn define_user_types_with_progress<T, I, P>(&self, names_and_types: T, mut progress: P)
1568    where
1569        T: Iterator<Item = I>,
1570        I: Into<QualifiedNameAndType>,
1571        P: ProgressCallback,
1572    {
1573        let mut types: Vec<BNQualifiedNameAndType> = names_and_types
1574            .map(Into::into)
1575            .map(QualifiedNameAndType::into_raw)
1576            .collect();
1577
1578        unsafe {
1579            BNDefineUserAnalysisTypes(
1580                self.handle,
1581                types.as_mut_ptr(),
1582                types.len(),
1583                Some(P::cb_progress_callback),
1584                &mut progress as *mut P as *mut c_void,
1585            )
1586        };
1587
1588        for ty in types {
1589            QualifiedNameAndType::free_raw(ty);
1590        }
1591    }
1592
1593    pub fn undefine_auto_type(&self, id: &str) {
1594        let id_str = id.to_cstr();
1595        unsafe {
1596            BNUndefineAnalysisType(self.handle, id_str.as_ref().as_ptr() as *const _);
1597        }
1598    }
1599
1600    pub fn undefine_user_type<T: Into<QualifiedName>>(&self, name: T) {
1601        let mut raw_name = QualifiedName::into_raw(name.into());
1602        unsafe { BNUndefineUserAnalysisType(self.handle, &mut raw_name) }
1603        QualifiedName::free_raw(raw_name);
1604    }
1605
1606    pub fn types(&self) -> Array<QualifiedNameAndType> {
1607        unsafe {
1608            let mut count = 0usize;
1609            let types = BNGetAnalysisTypeList(self.handle, &mut count);
1610            Array::new(types, count, ())
1611        }
1612    }
1613
1614    pub fn dependency_sorted_types(&self) -> Array<QualifiedNameAndType> {
1615        unsafe {
1616            let mut count = 0usize;
1617            let types = BNGetAnalysisDependencySortedTypeList(self.handle, &mut count);
1618            Array::new(types, count, ())
1619        }
1620    }
1621
1622    pub fn type_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<Ref<Type>> {
1623        let mut raw_name = QualifiedName::into_raw(name.into());
1624        unsafe {
1625            let type_handle = BNGetAnalysisTypeByName(self.handle, &mut raw_name);
1626            QualifiedName::free_raw(raw_name);
1627            if type_handle.is_null() {
1628                return None;
1629            }
1630            Some(Type::ref_from_raw(type_handle))
1631        }
1632    }
1633
1634    pub fn type_by_ref(&self, ref_: &NamedTypeReference) -> Option<Ref<Type>> {
1635        unsafe {
1636            let type_handle = BNGetAnalysisTypeByRef(self.handle, ref_.handle);
1637            if type_handle.is_null() {
1638                return None;
1639            }
1640            Some(Type::ref_from_raw(type_handle))
1641        }
1642    }
1643
1644    pub fn type_by_id(&self, id: &str) -> Option<Ref<Type>> {
1645        let id_str = id.to_cstr();
1646        unsafe {
1647            let type_handle = BNGetAnalysisTypeById(self.handle, id_str.as_ptr());
1648            if type_handle.is_null() {
1649                return None;
1650            }
1651            Some(Type::ref_from_raw(type_handle))
1652        }
1653    }
1654
1655    pub fn type_name_by_id(&self, id: &str) -> Option<QualifiedName> {
1656        let id_str = id.to_cstr();
1657        unsafe {
1658            let name_handle = BNGetAnalysisTypeNameById(self.handle, id_str.as_ptr());
1659            let name = QualifiedName::from_owned_raw(name_handle);
1660            // The core will return an empty qualified name if no type name was found.
1661            match name.items.is_empty() {
1662                true => None,
1663                false => Some(name),
1664            }
1665        }
1666    }
1667
1668    pub fn type_id_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<String> {
1669        let mut raw_name = QualifiedName::into_raw(name.into());
1670        unsafe {
1671            let id_cstr = BNGetAnalysisTypeId(self.handle, &mut raw_name);
1672            QualifiedName::free_raw(raw_name);
1673            let id = BnString::into_string(id_cstr);
1674            match id.is_empty() {
1675                true => None,
1676                false => Some(id),
1677            }
1678        }
1679    }
1680
1681    pub fn is_type_auto_defined<T: Into<QualifiedName>>(&self, name: T) -> bool {
1682        let mut raw_name = QualifiedName::into_raw(name.into());
1683        let result = unsafe { BNIsAnalysisTypeAutoDefined(self.handle, &mut raw_name) };
1684        QualifiedName::free_raw(raw_name);
1685        result
1686    }
1687
1688    pub fn segments(&self) -> Array<Segment> {
1689        unsafe {
1690            let mut count = 0;
1691            let raw_segments = BNGetSegments(self.handle, &mut count);
1692            Array::new(raw_segments, count, ())
1693        }
1694    }
1695
1696    pub fn segment_at(&self, addr: u64) -> Option<Ref<Segment>> {
1697        unsafe {
1698            let raw_seg = BNGetSegmentAt(self.handle, addr);
1699            match raw_seg.is_null() {
1700                false => Some(Segment::ref_from_raw(raw_seg)),
1701                true => None,
1702            }
1703        }
1704    }
1705
1706    /// Adds a segment to the view.
1707    ///
1708    /// NOTE: Consider using [BinaryView::begin_bulk_add_segments] and [BinaryView::end_bulk_add_segments]
1709    /// if you plan on adding a number of segments all at once, to avoid unnecessary MemoryMap updates.
1710    pub fn add_segment(&self, segment: SegmentBuilder) {
1711        segment.create(self.as_ref());
1712    }
1713
1714    // TODO: Replace with BulkModify guard.
1715    /// Start adding segments in bulk. Useful for adding large numbers of segments.
1716    ///
1717    /// After calling this any call to [BinaryView::add_segment] will be uncommitted until a call to
1718    /// [BinaryView::end_bulk_add_segments]
1719    ///
1720    /// If you wish to discard the uncommitted segments you can call [BinaryView::cancel_bulk_add_segments].
1721    ///
1722    /// NOTE: This **must** be paired with a later call to [BinaryView::end_bulk_add_segments] or
1723    /// [BinaryView::cancel_bulk_add_segments], otherwise segments added after this call will stay uncommitted.
1724    pub fn begin_bulk_add_segments(&self) {
1725        unsafe { BNBeginBulkAddSegments(self.handle) }
1726    }
1727
1728    // TODO: Replace with BulkModify guard.
1729    /// Commit all auto and user segments that have been added since the call to [Self::begin_bulk_add_segments].
1730    ///
1731    /// NOTE: This **must** be paired with a prior call to [Self::begin_bulk_add_segments], otherwise this
1732    /// does nothing and segments are added individually.
1733    pub fn end_bulk_add_segments(&self) {
1734        unsafe { BNEndBulkAddSegments(self.handle) }
1735    }
1736
1737    // TODO: Replace with BulkModify guard.
1738    /// Flushes the auto and user segments that have yet to be committed.
1739    ///
1740    /// This is to be used in conjunction with [Self::begin_bulk_add_segments]
1741    /// and [Self::end_bulk_add_segments], where the latter will commit the segments
1742    /// which have been added since [Self::begin_bulk_add_segments], this function
1743    /// will discard them so that they do not get added to the view.
1744    pub fn cancel_bulk_add_segments(&self) {
1745        unsafe { BNCancelBulkAddSegments(self.handle) }
1746    }
1747
1748    pub fn add_section(&self, section: SectionBuilder) {
1749        section.create(self.as_ref());
1750    }
1751
1752    pub fn remove_auto_section(&self, name: impl IntoCStr) {
1753        let raw_name = name.to_cstr();
1754        let raw_name_ptr = raw_name.as_ptr();
1755        unsafe {
1756            BNRemoveAutoSection(self.handle, raw_name_ptr);
1757        }
1758    }
1759
1760    pub fn remove_user_section(&self, name: impl IntoCStr) {
1761        let raw_name = name.to_cstr();
1762        let raw_name_ptr = raw_name.as_ptr();
1763        unsafe {
1764            BNRemoveUserSection(self.handle, raw_name_ptr);
1765        }
1766    }
1767
1768    pub fn section_by_name(&self, name: impl IntoCStr) -> Option<Ref<Section>> {
1769        unsafe {
1770            let raw_name = name.to_cstr();
1771            let name_ptr = raw_name.as_ptr();
1772            let raw_section_ptr = BNGetSectionByName(self.handle, name_ptr);
1773            match raw_section_ptr.is_null() {
1774                false => Some(Section::ref_from_raw(raw_section_ptr)),
1775                true => None,
1776            }
1777        }
1778    }
1779
1780    pub fn sections(&self) -> Array<Section> {
1781        unsafe {
1782            let mut count = 0;
1783            let sections = BNGetSections(self.handle, &mut count);
1784            Array::new(sections, count, ())
1785        }
1786    }
1787
1788    pub fn sections_at(&self, addr: u64) -> Array<Section> {
1789        unsafe {
1790            let mut count = 0;
1791            let sections = BNGetSectionsAt(self.handle, addr, &mut count);
1792            Array::new(sections, count, ())
1793        }
1794    }
1795
1796    pub fn memory_map(&self) -> MemoryMap {
1797        MemoryMap::new(self.as_ref().to_owned())
1798    }
1799
1800    /// Add an auto function at the given `address` with the views default platform.
1801    ///
1802    /// Use [`BinaryView::add_auto_function_with_platform`] if you wish to specify a platform.
1803    ///
1804    /// NOTE: The default platform **must** be set for this view!
1805    pub fn add_auto_function(&self, address: u64) -> Option<Ref<Function>> {
1806        let platform = self.default_platform()?;
1807        self.add_auto_function_with_platform(address, &platform)
1808    }
1809
1810    /// Add an auto function at the given `address` with the `platform`.
1811    ///
1812    /// Use [`BinaryView::add_auto_function_ext`] if you wish to specify a function type.
1813    ///
1814    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1815    pub fn add_auto_function_with_platform(
1816        &self,
1817        address: u64,
1818        platform: &Platform,
1819    ) -> Option<Ref<Function>> {
1820        self.add_auto_function_ext(address, platform, None, false)
1821    }
1822
1823    /// Add an auto function at the given `address` with the `platform` and function type.
1824    ///
1825    /// The `auto_discovered` flag is used to prevent or allow this created function to be deleted if
1826    /// it is never used (the function has no xrefs), if you are confident that this is a valid function
1827    /// set this to `false`.
1828    ///
1829    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1830    pub fn add_auto_function_ext(
1831        &self,
1832        address: u64,
1833        platform: &Platform,
1834        func_type: Option<&Type>,
1835        auto_discovered: bool,
1836    ) -> Option<Ref<Function>> {
1837        unsafe {
1838            let func_type = match func_type {
1839                Some(func_type) => func_type.handle,
1840                None => std::ptr::null_mut(),
1841            };
1842
1843            let handle = BNAddFunctionForAnalysis(
1844                self.handle,
1845                platform.handle,
1846                address,
1847                auto_discovered,
1848                func_type,
1849            );
1850
1851            if handle.is_null() {
1852                return None;
1853            }
1854
1855            Some(Function::ref_from_raw(handle))
1856        }
1857    }
1858
1859    /// Remove an auto function from the view.
1860    ///
1861    /// Pass `true` for `update_refs` to update all references of the function.
1862    ///
1863    /// NOTE: Unlike [`BinaryView::remove_user_function`], this will NOT prohibit the function from
1864    /// being re-added in the future, use [`BinaryView::remove_user_function`] to blacklist the
1865    /// function from being automatically created.
1866    pub fn remove_auto_function(&self, func: &Function, update_refs: bool) {
1867        unsafe {
1868            BNRemoveAnalysisFunction(self.handle, func.handle, update_refs);
1869        }
1870    }
1871
1872    /// Add a user function at the given `address` with the views default platform.
1873    ///
1874    /// Use [`BinaryView::add_user_function_with_platform`] if you wish to specify a platform.
1875    ///
1876    /// NOTE: The default platform **must** be set for this view!
1877    pub fn add_user_function(&self, addr: u64) -> Option<Ref<Function>> {
1878        let platform = self.default_platform()?;
1879        self.add_user_function_with_platform(addr, &platform)
1880    }
1881
1882    /// Add an auto function at the given `address` with the `platform`.
1883    ///
1884    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1885    pub fn add_user_function_with_platform(
1886        &self,
1887        addr: u64,
1888        platform: &Platform,
1889    ) -> Option<Ref<Function>> {
1890        unsafe {
1891            let func = BNCreateUserFunction(self.handle, platform.handle, addr);
1892            if func.is_null() {
1893                return None;
1894            }
1895            Some(Function::ref_from_raw(func))
1896        }
1897    }
1898
1899    /// Removes the function from the view and blacklists it from being created automatically.
1900    ///
1901    /// NOTE: If you call [`BinaryView::add_user_function`], it will override the blacklist.
1902    pub fn remove_user_function(&self, func: &Function) {
1903        unsafe { BNRemoveUserFunction(self.handle, func.handle) }
1904    }
1905
1906    pub fn has_functions(&self) -> bool {
1907        unsafe { BNHasFunctions(self.handle) }
1908    }
1909
1910    /// Add an entry point at the given `address` with the view's default platform.
1911    ///
1912    /// NOTE: The default platform **must** be set for this view!
1913    pub fn add_entry_point(&self, addr: u64) {
1914        if let Some(platform) = self.default_platform() {
1915            self.add_entry_point_with_platform(addr, &platform);
1916        }
1917    }
1918
1919    /// Add an entry point at the given `address` with the `platform`.
1920    ///
1921    /// NOTE: If the view's default platform is not set, this will set it to `platform`.
1922    pub fn add_entry_point_with_platform(&self, addr: u64, platform: &Platform) {
1923        unsafe {
1924            BNAddEntryPointForAnalysis(self.handle, platform.handle, addr);
1925        }
1926    }
1927
1928    pub fn entry_point_function(&self) -> Option<Ref<Function>> {
1929        unsafe {
1930            let raw_func_ptr = BNGetAnalysisEntryPoint(self.handle);
1931            match raw_func_ptr.is_null() {
1932                false => Some(Function::ref_from_raw(raw_func_ptr)),
1933                true => None,
1934            }
1935        }
1936    }
1937
1938    /// This list contains the analysis entry function, and functions like init_array, fini_array,
1939    /// and TLS callbacks etc.
1940    ///
1941    /// We see `entry_functions` as good starting points for analysis, these functions normally don't
1942    /// have internal references. Exported functions in a dll/so file are not included.
1943    pub fn entry_point_functions(&self) -> Array<Function> {
1944        unsafe {
1945            let mut count = 0;
1946            let functions = BNGetAllEntryFunctions(self.handle, &mut count);
1947
1948            Array::new(functions, count, ())
1949        }
1950    }
1951
1952    pub fn functions(&self) -> Array<Function> {
1953        unsafe {
1954            let mut count = 0;
1955            let functions = BNGetAnalysisFunctionList(self.handle, &mut count);
1956
1957            Array::new(functions, count, ())
1958        }
1959    }
1960
1961    /// List of functions *starting* at `addr`
1962    pub fn functions_at(&self, addr: u64) -> Array<Function> {
1963        unsafe {
1964            let mut count = 0;
1965            let functions = BNGetAnalysisFunctionsForAddress(self.handle, addr, &mut count);
1966
1967            Array::new(functions, count, ())
1968        }
1969    }
1970
1971    /// List of functions containing `addr`
1972    pub fn functions_containing(&self, addr: u64) -> Array<Function> {
1973        unsafe {
1974            let mut count = 0;
1975            let functions = BNGetAnalysisFunctionsContainingAddress(self.handle, addr, &mut count);
1976
1977            Array::new(functions, count, ())
1978        }
1979    }
1980
1981    /// List of functions with the given name.
1982    ///
1983    /// There is one special case where if you pass a string of the form `sub_[0-9a-f]+` then it will lookup all
1984    /// functions defined at the address matched by the regular expression if that symbol is not defined in the
1985    /// database.
1986    ///
1987    /// # Params
1988    /// - `name`: Name that the function should have
1989    /// - `plat`: Optional platform that the function should be defined for. Defaults to all platforms if `None` passed.
1990    pub fn functions_by_name(
1991        &self,
1992        name: impl IntoCStr,
1993        plat: Option<&Platform>,
1994    ) -> Vec<Ref<Function>> {
1995        let name = name.to_cstr();
1996        let symbols = self.symbols_by_name(&*name);
1997        let mut addresses: Vec<u64> = symbols.into_iter().map(|s| s.address()).collect();
1998        if addresses.is_empty() && name.to_bytes().starts_with(b"sub_") {
1999            if let Ok(str) = name.to_str() {
2000                if let Ok(address) = u64::from_str_radix(&str[4..], 16) {
2001                    addresses.push(address);
2002                }
2003            }
2004        }
2005
2006        let mut functions = Vec::new();
2007
2008        for address in addresses {
2009            let funcs = self.functions_at(address);
2010            for func in funcs.into_iter() {
2011                if func.start() == address && plat.is_none_or(|p| p == func.platform().as_ref()) {
2012                    functions.push(func.clone());
2013                }
2014            }
2015        }
2016
2017        functions
2018    }
2019
2020    pub fn function_at(&self, platform: &Platform, addr: u64) -> Option<Ref<Function>> {
2021        unsafe {
2022            let raw_func_ptr = BNGetAnalysisFunction(self.handle, platform.handle, addr);
2023            match raw_func_ptr.is_null() {
2024                false => Some(Function::ref_from_raw(raw_func_ptr)),
2025                true => None,
2026            }
2027        }
2028    }
2029
2030    pub fn function_start_before(&self, addr: u64) -> u64 {
2031        unsafe { BNGetPreviousFunctionStartBeforeAddress(self.handle, addr) }
2032    }
2033
2034    pub fn function_start_after(&self, addr: u64) -> u64 {
2035        unsafe { BNGetNextFunctionStartAfterAddress(self.handle, addr) }
2036    }
2037
2038    pub fn basic_blocks_containing(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> {
2039        unsafe {
2040            let mut count = 0;
2041            let blocks = BNGetBasicBlocksForAddress(self.handle, addr, &mut count);
2042            Array::new(blocks, count, NativeBlock::new())
2043        }
2044    }
2045
2046    pub fn basic_blocks_starting_at(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> {
2047        unsafe {
2048            let mut count = 0;
2049            let blocks = BNGetBasicBlocksStartingAtAddress(self.handle, addr, &mut count);
2050            Array::new(blocks, count, NativeBlock::new())
2051        }
2052    }
2053
2054    pub fn is_new_auto_function_analysis_suppressed(&self) -> bool {
2055        unsafe { BNGetNewAutoFunctionAnalysisSuppressed(self.handle) }
2056    }
2057
2058    pub fn set_new_auto_function_analysis_suppressed(&self, suppress: bool) {
2059        unsafe {
2060            BNSetNewAutoFunctionAnalysisSuppressed(self.handle, suppress);
2061        }
2062    }
2063
2064    // TODO: Should this instead be implemented on [`Function`] considering `src_func`? `Location` is local to the source function.
2065    pub fn should_skip_target_analysis(
2066        &self,
2067        src_loc: impl Into<Location>,
2068        src_func: &Function,
2069        src_end: u64,
2070        target: impl Into<Location>,
2071    ) -> bool {
2072        let src_loc = src_loc.into();
2073        let target = target.into();
2074        unsafe {
2075            BNShouldSkipTargetAnalysis(
2076                self.handle,
2077                &mut src_loc.into(),
2078                src_func.handle,
2079                src_end,
2080                &mut target.into(),
2081            )
2082        }
2083    }
2084
2085    pub fn read_buffer(&self, offset: u64, len: usize) -> Option<DataBuffer> {
2086        let read_buffer = unsafe { BNReadViewBuffer(self.handle, offset, len) };
2087        if read_buffer.is_null() {
2088            None
2089        } else {
2090            Some(DataBuffer::from_raw(read_buffer))
2091        }
2092    }
2093
2094    pub fn debug_info(&self) -> Ref<DebugInfo> {
2095        unsafe { DebugInfo::ref_from_raw(BNGetDebugInfo(self.handle)) }
2096    }
2097
2098    pub fn set_debug_info(&self, debug_info: &DebugInfo) {
2099        unsafe { BNSetDebugInfo(self.handle, debug_info.handle) }
2100    }
2101
2102    pub fn apply_debug_info(&self, debug_info: &DebugInfo) {
2103        unsafe { BNApplyDebugInfo(self.handle, debug_info.handle) }
2104    }
2105
2106    pub fn show_plaintext_report(&self, title: &str, plaintext: &str) {
2107        let title = title.to_cstr();
2108        let plaintext = plaintext.to_cstr();
2109        unsafe {
2110            BNShowPlainTextReport(
2111                self.handle,
2112                title.as_ref().as_ptr() as *mut _,
2113                plaintext.as_ref().as_ptr() as *mut _,
2114            )
2115        }
2116    }
2117
2118    pub fn show_markdown_report(&self, title: &str, contents: &str, plaintext: &str) {
2119        let title = title.to_cstr();
2120        let contents = contents.to_cstr();
2121        let plaintext = plaintext.to_cstr();
2122        unsafe {
2123            BNShowMarkdownReport(
2124                self.handle,
2125                title.as_ref().as_ptr() as *mut _,
2126                contents.as_ref().as_ptr() as *mut _,
2127                plaintext.as_ref().as_ptr() as *mut _,
2128            )
2129        }
2130    }
2131
2132    pub fn show_html_report(&self, title: &str, contents: &str, plaintext: &str) {
2133        let title = title.to_cstr();
2134        let contents = contents.to_cstr();
2135        let plaintext = plaintext.to_cstr();
2136        unsafe {
2137            BNShowHTMLReport(
2138                self.handle,
2139                title.as_ref().as_ptr() as *mut _,
2140                contents.as_ref().as_ptr() as *mut _,
2141                plaintext.as_ref().as_ptr() as *mut _,
2142            )
2143        }
2144    }
2145
2146    pub fn show_graph_report(&self, raw_name: &str, graph: &FlowGraph) {
2147        let raw_name = raw_name.to_cstr();
2148        unsafe {
2149            BNShowGraphReport(self.handle, raw_name.as_ptr(), graph.handle);
2150        }
2151    }
2152
2153    pub fn load_settings(&self, view_type_name: &str) -> Option<Ref<Settings>> {
2154        let view_type_name = view_type_name.to_cstr();
2155        let settings_handle =
2156            unsafe { BNBinaryViewGetLoadSettings(self.handle, view_type_name.as_ptr()) };
2157        match settings_handle.is_null() {
2158            true => None,
2159            false => Some(unsafe { Settings::ref_from_raw(settings_handle) }),
2160        }
2161    }
2162
2163    pub fn set_load_settings(&self, view_type_name: &str, settings: &Settings) {
2164        let view_type_name = view_type_name.to_cstr();
2165
2166        unsafe {
2167            BNBinaryViewSetLoadSettings(self.handle, view_type_name.as_ptr(), settings.handle)
2168        };
2169    }
2170
2171    /// Creates a new [`TagType`] and adds it to the view.
2172    ///
2173    /// # Arguments
2174    /// * `name` - the name for the tag
2175    /// * `icon` - the icon (recommended 1 emoji or 2 chars) for the tag
2176    pub fn create_tag_type(&self, name: &str, icon: &str) -> Ref<TagType> {
2177        let tag_type = TagType::create(self, name, icon);
2178        unsafe {
2179            BNAddTagType(self.handle, tag_type.handle);
2180        }
2181        tag_type
2182    }
2183
2184    /// Removes a [TagType] and all tags that use it
2185    pub fn remove_tag_type(&self, tag_type: &TagType) {
2186        unsafe { BNRemoveTagType(self.handle, tag_type.handle) }
2187    }
2188
2189    /// Get a tag type by its name.
2190    pub fn tag_type_by_name(&self, name: &str) -> Option<Ref<TagType>> {
2191        let name = name.to_cstr();
2192        unsafe {
2193            let handle = BNGetTagType(self.handle, name.as_ptr());
2194            if handle.is_null() {
2195                return None;
2196            }
2197            Some(TagType::ref_from_raw(handle))
2198        }
2199    }
2200
2201    /// Get all tags in all scopes
2202    pub fn tags_all_scopes(&self) -> Array<TagReference> {
2203        let mut count = 0;
2204        unsafe {
2205            let tag_references = BNGetAllTagReferences(self.handle, &mut count);
2206            Array::new(tag_references, count, ())
2207        }
2208    }
2209
2210    /// Get all tag types present for the view
2211    pub fn tag_types(&self) -> Array<TagType> {
2212        let mut count = 0;
2213        unsafe {
2214            let tag_types_raw = BNGetTagTypes(self.handle, &mut count);
2215            Array::new(tag_types_raw, count, ())
2216        }
2217    }
2218
2219    /// Get all tag references of a specific type
2220    pub fn tags_by_type(&self, tag_type: &TagType) -> Array<TagReference> {
2221        let mut count = 0;
2222        unsafe {
2223            let tag_references =
2224                BNGetAllTagReferencesOfType(self.handle, tag_type.handle, &mut count);
2225            Array::new(tag_references, count, ())
2226        }
2227    }
2228
2229    /// Get a tag by its id.
2230    ///
2231    /// Note this does not tell you anything about where it is used.
2232    pub fn tag_by_id(&self, id: &str) -> Option<Ref<Tag>> {
2233        let id = id.to_cstr();
2234        unsafe {
2235            let handle = BNGetTag(self.handle, id.as_ptr());
2236            if handle.is_null() {
2237                return None;
2238            }
2239            Some(Tag::ref_from_raw(handle))
2240        }
2241    }
2242
2243    /// Creates and adds a tag to an address
2244    ///
2245    /// User tag creations will be added to the undo buffer
2246    pub fn add_tag(&self, addr: u64, t: &TagType, data: &str, user: bool) {
2247        let tag = Tag::new(t, data);
2248
2249        unsafe { BNAddTag(self.handle, tag.handle, user) }
2250
2251        if user {
2252            unsafe { BNAddUserDataTag(self.handle, addr, tag.handle) }
2253        } else {
2254            unsafe { BNAddAutoDataTag(self.handle, addr, tag.handle) }
2255        }
2256    }
2257
2258    /// removes a Tag object at a data address.
2259    pub fn remove_auto_data_tag(&self, addr: u64, tag: &Tag) {
2260        unsafe { BNRemoveAutoDataTag(self.handle, addr, tag.handle) }
2261    }
2262
2263    /// removes a Tag object at a data address.
2264    /// Since this removes a user tag, it will be added to the current undo buffer.
2265    pub fn remove_user_data_tag(&self, addr: u64, tag: &Tag) {
2266        unsafe { BNRemoveUserDataTag(self.handle, addr, tag.handle) }
2267    }
2268
2269    /// Retrieves a list of comment addresses, the comments themselves can then be queried with
2270    /// the function [`BinaryView::comment_at`].
2271    ///
2272    /// If you would rather retrieve the contents of **all** comments at once you can do so with
2273    /// the helper function [`BinaryView::comments`].
2274    pub fn comment_references(&self) -> Array<CommentReference> {
2275        let mut count = 0;
2276        let addresses_raw = unsafe { BNGetGlobalCommentedAddresses(self.handle, &mut count) };
2277        unsafe { Array::new(addresses_raw, count, ()) }
2278    }
2279
2280    /// Retrieves a map of comment addresses to their contents.
2281    ///
2282    /// This is a helper function that eagerly reads the contents of all comments within the
2283    /// view, use [`BinaryView::comment_references`] instead if you do not wish to read all the comments.
2284    pub fn comments(&self) -> BTreeMap<u64, String> {
2285        self.comment_references()
2286            .iter()
2287            .filter_map(|cmt_ref| Some((cmt_ref.start, self.comment_at(cmt_ref.start)?)))
2288            .collect()
2289    }
2290
2291    pub fn comment_at(&self, addr: u64) -> Option<String> {
2292        unsafe {
2293            let comment_raw = BNGetGlobalCommentForAddress(self.handle, addr);
2294            match comment_raw.is_null() {
2295                false => Some(BnString::into_string(comment_raw)),
2296                true => None,
2297            }
2298        }
2299    }
2300
2301    /// Sets a comment for the [`BinaryView`] at the address specified.
2302    ///
2303    /// NOTE: This is different from setting a comment at the function-level. To set a comment in a
2304    /// function use [`Function::set_comment_at`]
2305    pub fn set_comment_at(&self, addr: u64, comment: &str) {
2306        let comment_raw = comment.to_cstr();
2307        unsafe { BNSetGlobalCommentForAddress(self.handle, addr, comment_raw.as_ptr()) }
2308    }
2309
2310    /// Retrieves a list of the next disassembly lines.
2311    ///
2312    /// Retrieves an [`Array`] over [`LinearDisassemblyLine`] objects for the
2313    /// next disassembly lines, and updates the [`LinearViewCursor`] passed in. This function can be called
2314    /// repeatedly to get more lines of linear disassembly.
2315    ///
2316    /// # Arguments
2317    /// * `pos` - Position to retrieve linear disassembly lines from
2318    pub fn get_next_linear_disassembly_lines(
2319        &self,
2320        pos: &mut LinearViewCursor,
2321    ) -> Array<LinearDisassemblyLine> {
2322        let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) };
2323
2324        while result.is_empty() {
2325            result = pos.lines();
2326            if !pos.next() {
2327                return result;
2328            }
2329        }
2330
2331        result
2332    }
2333
2334    /// Retrieves a list of the previous disassembly lines.
2335    ///
2336    /// `get_previous_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the
2337    /// previous disassembly lines, and updates the [LinearViewCursor] passed in. This function can be called
2338    /// repeatedly to get more lines of linear disassembly.
2339    ///
2340    /// # Arguments
2341    /// * `pos` - Position to retrieve linear disassembly lines relative to
2342    pub fn get_previous_linear_disassembly_lines(
2343        &self,
2344        pos: &mut LinearViewCursor,
2345    ) -> Array<LinearDisassemblyLine> {
2346        let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) };
2347        while result.is_empty() {
2348            if !pos.previous() {
2349                return result;
2350            }
2351
2352            result = pos.lines();
2353        }
2354
2355        result
2356    }
2357
2358    pub fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> {
2359        let key = key.to_cstr();
2360        let value: *mut BNMetadata =
2361            unsafe { BNBinaryViewQueryMetadata(self.handle, key.as_ptr()) };
2362        if value.is_null() {
2363            None
2364        } else {
2365            Some(unsafe { Metadata::ref_from_raw(value) })
2366        }
2367    }
2368
2369    /// Retrieve the metadata as the type `T`.
2370    ///
2371    /// Fails if the metadata does not exist, or if the metadata failed to coerce to type `T`.
2372    pub fn get_metadata<T>(&self, key: &str) -> Option<T>
2373    where
2374        T: for<'a> TryFrom<&'a Metadata>,
2375    {
2376        self.query_metadata(key)
2377            .and_then(|md| T::try_from(md.as_ref()).ok())
2378    }
2379
2380    pub fn store_metadata<V>(&self, key: &str, value: V, is_auto: bool)
2381    where
2382        V: Into<Ref<Metadata>>,
2383    {
2384        let md = value.into();
2385        let key = key.to_cstr();
2386        unsafe {
2387            BNBinaryViewStoreMetadata(self.handle, key.as_ptr(), md.as_ref().handle, is_auto)
2388        };
2389    }
2390
2391    pub fn remove_metadata(&self, key: &str) {
2392        let key = key.to_cstr();
2393        unsafe { BNBinaryViewRemoveMetadata(self.handle, key.as_ptr()) };
2394    }
2395
2396    /// Retrieves a list of [CodeReference]s pointing to a given address.
2397    pub fn code_refs_to_addr(&self, addr: u64) -> Array<CodeReference> {
2398        unsafe {
2399            let mut count = 0;
2400            let handle = BNGetCodeReferences(self.handle, addr, &mut count, false, 0);
2401            Array::new(handle, count, ())
2402        }
2403    }
2404
2405    /// Retrieves a list of [CodeReference]s pointing into a given [Range].
2406    pub fn code_refs_into_range(&self, range: Range<u64>) -> Array<CodeReference> {
2407        unsafe {
2408            let mut count = 0;
2409            let handle = BNGetCodeReferencesInRange(
2410                self.handle,
2411                range.start,
2412                range.end - range.start,
2413                &mut count,
2414                false,
2415                0,
2416            );
2417            Array::new(handle, count, ())
2418        }
2419    }
2420
2421    /// Retrieves a list of addresses pointed to by a given address.
2422    pub fn code_refs_from_addr(&self, addr: u64, func: Option<&Function>) -> Vec<u64> {
2423        unsafe {
2424            let mut count = 0;
2425            let code_ref =
2426                CodeReference::new(addr, func.map(|f| f.to_owned()), func.map(|f| f.arch()));
2427            let mut raw_code_ref = CodeReference::into_owned_raw(&code_ref);
2428            let addresses = BNGetCodeReferencesFrom(self.handle, &mut raw_code_ref, &mut count);
2429            let res = std::slice::from_raw_parts(addresses, count).to_vec();
2430            BNFreeAddressList(addresses);
2431            res
2432        }
2433    }
2434
2435    /// Retrieves a list of [DataReference]s pointing to a given address.
2436    pub fn data_refs_to_addr(&self, addr: u64) -> Array<DataReference> {
2437        unsafe {
2438            let mut count = 0;
2439            let handle = BNGetDataReferences(self.handle, addr, &mut count, false, 0);
2440            Array::new(handle, count, ())
2441        }
2442    }
2443
2444    /// Retrieves a list of [DataReference]s pointing into a given [Range].
2445    pub fn data_refs_into_range(&self, range: Range<u64>) -> Array<DataReference> {
2446        unsafe {
2447            let mut count = 0;
2448            let handle = BNGetDataReferencesInRange(
2449                self.handle,
2450                range.start,
2451                range.end - range.start,
2452                &mut count,
2453                false,
2454                0,
2455            );
2456            Array::new(handle, count, ())
2457        }
2458    }
2459
2460    /// Retrieves a list of [DataReference]s originating from a given address.
2461    pub fn data_refs_from_addr(&self, addr: u64) -> Array<DataReference> {
2462        unsafe {
2463            let mut count = 0;
2464            let handle = BNGetDataReferencesFrom(self.handle, addr, &mut count);
2465            Array::new(handle, count, ())
2466        }
2467    }
2468
2469    /// Retrieves a list of [CodeReference]s for locations in code that use a given named type.
2470    pub fn code_refs_using_type_name<T: Into<QualifiedName>>(
2471        &self,
2472        name: T,
2473    ) -> Array<CodeReference> {
2474        let mut raw_name = QualifiedName::into_raw(name.into());
2475        unsafe {
2476            let mut count = 0;
2477            let handle =
2478                BNGetCodeReferencesForType(self.handle, &mut raw_name, &mut count, false, 0);
2479            QualifiedName::free_raw(raw_name);
2480            Array::new(handle, count, ())
2481        }
2482    }
2483
2484    /// Retrieves a list of [DataReference]s for locations in data that use a given named type.
2485    pub fn data_refs_using_type_name<T: Into<QualifiedName>>(
2486        &self,
2487        name: T,
2488    ) -> Array<DataReference> {
2489        let mut raw_name = QualifiedName::into_raw(name.into());
2490        unsafe {
2491            let mut count = 0;
2492            let handle =
2493                BNGetDataReferencesForType(self.handle, &mut raw_name, &mut count, false, 0);
2494            QualifiedName::free_raw(raw_name);
2495            Array::new(handle, count, ())
2496        }
2497    }
2498
2499    pub fn relocations_at(&self, addr: u64) -> Array<Relocation> {
2500        unsafe {
2501            let mut count = 0;
2502            let handle = BNGetRelocationsAt(self.handle, addr, &mut count);
2503            Array::new(handle, count, ())
2504        }
2505    }
2506
2507    pub fn relocation_ranges(&self) -> Vec<Range<u64>> {
2508        let ranges = unsafe {
2509            let mut count = 0;
2510            let reloc_ranges_ptr = BNGetRelocationRanges(self.handle, &mut count);
2511            let ranges = std::slice::from_raw_parts(reloc_ranges_ptr, count).to_vec();
2512            BNFreeRelocationRanges(reloc_ranges_ptr);
2513            ranges
2514        };
2515
2516        // TODO: impl From BNRange for Range?
2517        ranges
2518            .iter()
2519            .map(|range| Range {
2520                start: range.start,
2521                end: range.end,
2522            })
2523            .collect()
2524    }
2525
2526    pub fn component_by_guid(&self, guid: &str) -> Option<Ref<Component>> {
2527        let name = guid.to_cstr();
2528        let result = unsafe { BNGetComponentByGuid(self.handle, name.as_ptr()) };
2529        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
2530    }
2531
2532    pub fn root_component(&self) -> Option<Ref<Component>> {
2533        let result = unsafe { BNGetRootComponent(self.handle) };
2534        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
2535    }
2536
2537    pub fn component_by_path(&self, path: &str) -> Option<Ref<Component>> {
2538        let path = path.to_cstr();
2539        let result = unsafe { BNGetComponentByPath(self.handle, path.as_ptr()) };
2540        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
2541    }
2542
2543    pub fn remove_component(&self, component: &Component) -> bool {
2544        unsafe { BNRemoveComponent(self.handle, component.handle.as_ptr()) }
2545    }
2546
2547    pub fn remove_component_by_guid(&self, guid: &str) -> bool {
2548        let path = guid.to_cstr();
2549        unsafe { BNRemoveComponentByGuid(self.handle, path.as_ptr()) }
2550    }
2551
2552    pub fn data_variable_parent_components(
2553        &self,
2554        data_variable: &DataVariable,
2555    ) -> Array<Component> {
2556        let mut count = 0;
2557        let result = unsafe {
2558            BNGetDataVariableParentComponents(self.handle, data_variable.address, &mut count)
2559        };
2560        unsafe { Array::new(result, count, ()) }
2561    }
2562
2563    pub fn external_libraries(&self) -> Array<ExternalLibrary> {
2564        let mut count = 0;
2565        let result = unsafe { BNBinaryViewGetExternalLibraries(self.handle, &mut count) };
2566        unsafe { Array::new(result, count, ()) }
2567    }
2568
2569    pub fn external_library(&self, name: &str) -> Option<Ref<ExternalLibrary>> {
2570        let name_ptr = name.to_cstr();
2571        let result = unsafe { BNBinaryViewGetExternalLibrary(self.handle, name_ptr.as_ptr()) };
2572        let result_ptr = NonNull::new(result)?;
2573        Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) })
2574    }
2575
2576    pub fn remove_external_library(&self, name: &str) {
2577        let name_ptr = name.to_cstr();
2578        unsafe { BNBinaryViewRemoveExternalLibrary(self.handle, name_ptr.as_ptr()) };
2579    }
2580
2581    pub fn add_external_library(
2582        &self,
2583        name: &str,
2584        backing_file: Option<&ProjectFile>,
2585        auto: bool,
2586    ) -> Option<Ref<ExternalLibrary>> {
2587        let name_ptr = name.to_cstr();
2588        let result = unsafe {
2589            BNBinaryViewAddExternalLibrary(
2590                self.handle,
2591                name_ptr.as_ptr(),
2592                backing_file
2593                    .map(|b| b.handle.as_ptr())
2594                    .unwrap_or(std::ptr::null_mut()),
2595                auto,
2596            )
2597        };
2598        NonNull::new(result).map(|h| unsafe { ExternalLibrary::ref_from_raw(h) })
2599    }
2600
2601    pub fn external_locations(&self) -> Array<ExternalLocation> {
2602        let mut count = 0;
2603        let result = unsafe { BNBinaryViewGetExternalLocations(self.handle, &mut count) };
2604        unsafe { Array::new(result, count, ()) }
2605    }
2606
2607    pub fn external_location_from_symbol(&self, symbol: &Symbol) -> Option<Ref<ExternalLocation>> {
2608        let result = unsafe { BNBinaryViewGetExternalLocation(self.handle, symbol.handle) };
2609        let result_ptr = NonNull::new(result)?;
2610        Some(unsafe { ExternalLocation::ref_from_raw(result_ptr) })
2611    }
2612
2613    pub fn remove_external_location(&self, location: &ExternalLocation) {
2614        self.remove_external_location_from_symbol(&location.source_symbol())
2615    }
2616
2617    pub fn remove_external_location_from_symbol(&self, symbol: &Symbol) {
2618        unsafe { BNBinaryViewRemoveExternalLocation(self.handle, symbol.handle) };
2619    }
2620
2621    // TODO: This is awful, rewrite this.
2622    pub fn add_external_location(
2623        &self,
2624        symbol: &Symbol,
2625        library: &ExternalLibrary,
2626        target_symbol_name: &str,
2627        target_address: Option<u64>,
2628        target_is_auto: bool,
2629    ) -> Option<Ref<ExternalLocation>> {
2630        let target_symbol_name = target_symbol_name.to_cstr();
2631        let target_address_ptr = target_address
2632            .map(|a| a as *mut u64)
2633            .unwrap_or(std::ptr::null_mut());
2634        let result = unsafe {
2635            BNBinaryViewAddExternalLocation(
2636                self.handle,
2637                symbol.handle,
2638                library.handle.as_ptr(),
2639                target_symbol_name.as_ptr(),
2640                target_address_ptr,
2641                target_is_auto,
2642            )
2643        };
2644        NonNull::new(result).map(|h| unsafe { ExternalLocation::ref_from_raw(h) })
2645    }
2646
2647    /// Type container for all types (user and auto) in the Binary View.
2648    ///
2649    /// NOTE: Modifying an auto type will promote it to a user type.
2650    pub fn type_container(&self) -> TypeContainer {
2651        let type_container_ptr = NonNull::new(unsafe { BNGetAnalysisTypeContainer(self.handle) });
2652        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2653        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
2654    }
2655
2656    /// Type container for user types in the Binary View.
2657    pub fn user_type_container(&self) -> TypeContainer {
2658        let type_container_ptr =
2659            NonNull::new(unsafe { BNGetAnalysisUserTypeContainer(self.handle) });
2660        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2661        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }.clone()
2662    }
2663
2664    /// Type container for auto types in the Binary View.
2665    ///
2666    /// NOTE: Unlike [`Self::type_container`] modification of auto types will **NOT** promote it to a user type.
2667    pub fn auto_type_container(&self) -> TypeContainer {
2668        let type_container_ptr =
2669            NonNull::new(unsafe { BNGetAnalysisAutoTypeContainer(self.handle) });
2670        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2671        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
2672    }
2673
2674    pub fn type_libraries(&self) -> Array<TypeLibrary> {
2675        let mut count = 0;
2676        let result = unsafe { BNGetBinaryViewTypeLibraries(self.handle, &mut count) };
2677        unsafe { Array::new(result, count, ()) }
2678    }
2679
2680    /// Make the contents of a type library available for type/import resolution
2681    pub fn add_type_library(&self, library: &TypeLibrary) {
2682        unsafe { BNAddBinaryViewTypeLibrary(self.handle, library.as_raw()) }
2683    }
2684
2685    pub fn type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> {
2686        let name = name.to_cstr();
2687        let result = unsafe { BNGetBinaryViewTypeLibrary(self.handle, name.as_ptr()) };
2688        NonNull::new(result).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
2689    }
2690
2691    /// Should be called by custom [`BinaryView`] implementations when they have successfully
2692    /// imported an object from a type library (eg a symbol's type). Values recorded with this
2693    /// function will then be queryable via [`BinaryView::lookup_imported_object_library`].
2694    ///
2695    /// * `lib` - Type Library containing the imported type
2696    /// * `name` - Name of the object in the type library
2697    /// * `addr` - address of symbol at import site
2698    /// * `platform` - Platform of symbol at import site
2699    pub fn record_imported_object_library<T: Into<QualifiedName>>(
2700        &self,
2701        lib: &TypeLibrary,
2702        name: T,
2703        addr: u64,
2704        platform: &Platform,
2705    ) {
2706        let mut raw_name = QualifiedName::into_raw(name.into());
2707        unsafe {
2708            BNBinaryViewRecordImportedObjectLibrary(
2709                self.handle,
2710                platform.handle,
2711                addr,
2712                lib.as_raw(),
2713                &mut raw_name,
2714            )
2715        }
2716        QualifiedName::free_raw(raw_name);
2717    }
2718
2719    /// Recursively imports a type from the specified type library, or, if no library was
2720    /// explicitly provided, the first type library associated with the current [`BinaryView`] that
2721    /// provides the name requested.
2722    ///
2723    /// This may have the impact of loading other type libraries as dependencies on other type
2724    /// libraries are lazily resolved when references to types provided by them are first encountered.
2725    ///
2726    /// Note that the name actually inserted into the view may not match the name as it exists in
2727    /// the type library in the event of a name conflict. To aid in this, the [`Type`] object
2728    /// returned is a `NamedTypeReference` to the deconflicted name used.
2729    pub fn import_type_library_type<T: Into<QualifiedName>>(
2730        &self,
2731        name: T,
2732        lib: Option<&TypeLibrary>,
2733    ) -> Option<Ref<Type>> {
2734        let mut lib_ref = lib
2735            .as_ref()
2736            .map(|l| unsafe { l.as_raw() } as *mut _)
2737            .unwrap_or(std::ptr::null_mut());
2738        let mut raw_name = QualifiedName::into_raw(name.into());
2739        let result =
2740            unsafe { BNBinaryViewImportTypeLibraryType(self.handle, &mut lib_ref, &mut raw_name) };
2741        QualifiedName::free_raw(raw_name);
2742        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2743    }
2744
2745    /// Recursively imports an object (function) from the specified type library, or, if no library was
2746    /// explicitly provided, the first type library associated with the current [`BinaryView`] that
2747    /// provides the name requested.
2748    ///
2749    /// This may have the impact of loading other type libraries as dependencies on other type
2750    /// libraries are lazily resolved when references to types provided by them are first encountered.
2751    ///
2752    /// NOTE: If you are implementing a custom [`BinaryView`] and use this method to import object types,
2753    /// you should then call [BinaryView::record_imported_object_library] with the details of
2754    /// where the object is located.
2755    pub fn import_type_library_object<T: Into<QualifiedName>>(
2756        &self,
2757        name: T,
2758        lib: Option<&TypeLibrary>,
2759    ) -> Option<Ref<Type>> {
2760        let mut lib_ref = lib
2761            .as_ref()
2762            .map(|l| unsafe { l.as_raw() } as *mut _)
2763            .unwrap_or(std::ptr::null_mut());
2764        let mut raw_name = QualifiedName::into_raw(name.into());
2765        let result = unsafe {
2766            BNBinaryViewImportTypeLibraryObject(self.handle, &mut lib_ref, &mut raw_name)
2767        };
2768        QualifiedName::free_raw(raw_name);
2769        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2770    }
2771
2772    /// Recursively imports a [`Type`] given its GUID from available type libraries.
2773    pub fn import_type_by_guid(&self, guid: &str) -> Option<Ref<Type>> {
2774        let guid = guid.to_cstr();
2775        let result = unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.handle, guid.as_ptr()) };
2776        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2777    }
2778
2779    /// Recursively exports `type_obj` into `lib` as a type with name `name`.
2780    ///
2781    /// As other referenced types are encountered, they are either copied into the destination type library or
2782    /// else the type library that provided the referenced type is added as a dependency for the destination library.
2783    pub fn export_type_to_library<T: Into<QualifiedName>>(
2784        &self,
2785        lib: &TypeLibrary,
2786        name: T,
2787        type_obj: &Type,
2788    ) {
2789        let mut raw_name = QualifiedName::into_raw(name.into());
2790        unsafe {
2791            BNBinaryViewExportTypeToTypeLibrary(
2792                self.handle,
2793                lib.as_raw(),
2794                &mut raw_name,
2795                type_obj.handle,
2796            )
2797        }
2798        QualifiedName::free_raw(raw_name);
2799    }
2800
2801    /// Recursively exports `type_obj` into `lib` as a type with name `name`.
2802    ///
2803    /// As other referenced types are encountered, they are either copied into the destination type library or
2804    /// else the type library that provided the referenced type is added as a dependency for the destination library.
2805    pub fn export_object_to_library<T: Into<QualifiedName>>(
2806        &self,
2807        lib: &TypeLibrary,
2808        name: T,
2809        type_obj: &Type,
2810    ) {
2811        let mut raw_name = QualifiedName::into_raw(name.into());
2812        unsafe {
2813            BNBinaryViewExportObjectToTypeLibrary(
2814                self.handle,
2815                lib.as_raw(),
2816                &mut raw_name,
2817                type_obj.handle,
2818            )
2819        }
2820        QualifiedName::free_raw(raw_name);
2821    }
2822
2823    /// Gives you details of which type library and name was used to determine
2824    /// the type of a symbol at a given address
2825    ///
2826    /// * `addr` - address of symbol at import site
2827    /// * `platform` - Platform of symbol at import site
2828    pub fn lookup_imported_object_library(
2829        &self,
2830        addr: u64,
2831        platform: &Platform,
2832    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
2833        let mut result_lib = std::ptr::null_mut();
2834        let mut result_name = BNQualifiedName::default();
2835        let success = unsafe {
2836            BNBinaryViewLookupImportedObjectLibrary(
2837                self.handle,
2838                platform.handle,
2839                addr,
2840                &mut result_lib,
2841                &mut result_name,
2842            )
2843        };
2844        if !success {
2845            return None;
2846        }
2847        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
2848        let name = QualifiedName::from_owned_raw(result_name);
2849        Some((lib, name))
2850    }
2851
2852    /// Gives you details of from which type library and name a given type in the analysis was imported.
2853    ///
2854    /// * `name` - Name of type in analysis
2855    pub fn lookup_imported_type_library<T: Into<QualifiedName>>(
2856        &self,
2857        name: T,
2858    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
2859        let raw_name = QualifiedName::into_raw(name.into());
2860        let mut result_lib = std::ptr::null_mut();
2861        let mut result_name = BNQualifiedName::default();
2862        let success = unsafe {
2863            BNBinaryViewLookupImportedTypeLibrary(
2864                self.handle,
2865                &raw_name,
2866                &mut result_lib,
2867                &mut result_name,
2868            )
2869        };
2870        QualifiedName::free_raw(raw_name);
2871        if !success {
2872            return None;
2873        }
2874        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
2875        let name = QualifiedName::from_owned_raw(result_name);
2876        Some((lib, name))
2877    }
2878
2879    /// Retrieve all known strings in the binary.
2880    ///
2881    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
2882    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2883    /// data and convert it to a representable form.
2884    ///
2885    /// Some helpers for reading strings are available:
2886    ///
2887    /// - [`BinaryView::read_c_string_at`]
2888    /// - [`BinaryView::read_utf8_string_at`]
2889    ///
2890    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
2891    /// and other settings.
2892    pub fn strings(&self) -> Array<StringReference> {
2893        unsafe {
2894            let mut count = 0;
2895            let strings = BNGetStrings(self.handle, &mut count);
2896            Array::new(strings, count, ())
2897        }
2898    }
2899
2900    /// Retrieve the string that falls on a given virtual address.
2901    ///
2902    /// NOTE: This returns a [`StringReference`] and since strings may not be representable as a Rust
2903    /// [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2904    /// data and convert it to a representable form.
2905    ///
2906    /// Some helpers for reading strings are available:
2907    ///
2908    /// - [`BinaryView::read_c_string_at`]
2909    /// - [`BinaryView::read_utf8_string_at`]
2910    ///
2911    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
2912    /// and other settings.
2913    pub fn string_at(&self, addr: u64) -> Option<StringReference> {
2914        let mut str_ref = BNStringReference::default();
2915        let success = unsafe { BNGetStringAtAddress(self.handle, addr, &mut str_ref) };
2916        if success {
2917            Some(str_ref.into())
2918        } else {
2919            None
2920        }
2921    }
2922
2923    /// Retrieve all known strings within the provided `range`.
2924    ///
2925    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
2926    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
2927    /// data and convert it to a representable form.
2928    ///
2929    /// Some helpers for reading strings are available:
2930    ///
2931    /// - [`BinaryView::read_c_string_at`]
2932    /// - [`BinaryView::read_utf8_string_at`]
2933    ///
2934    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
2935    /// and other settings.
2936    pub fn strings_in_range(&self, range: Range<u64>) -> Array<StringReference> {
2937        unsafe {
2938            let mut count = 0;
2939            let strings = BNGetStringsInRange(
2940                self.handle,
2941                range.start,
2942                range.end - range.start,
2943                &mut count,
2944            );
2945            Array::new(strings, count, ())
2946        }
2947    }
2948
2949    /// Retrieve the attached type archives as their [`TypeArchiveId`].
2950    ///
2951    /// Using the returned id you can retrieve the [`TypeArchive`] with [`BinaryView::type_archive_by_id`].
2952    pub fn attached_type_archives(&self) -> Vec<TypeArchiveId> {
2953        let mut ids: *mut *mut c_char = std::ptr::null_mut();
2954        let mut paths: *mut *mut c_char = std::ptr::null_mut();
2955        let count = unsafe { BNBinaryViewGetTypeArchives(self.handle, &mut ids, &mut paths) };
2956        // We discard the path here, you can retrieve it later with [`BinaryView::type_archive_path_by_id`].
2957        // This is so we can simplify the return type which will commonly just want to query through to the type
2958        // archive itself.
2959        let _path_list = unsafe { Array::<BnString>::new(paths, count, ()) };
2960        let id_list = unsafe { Array::<BnString>::new(ids, count, ()) };
2961        id_list
2962            .into_iter()
2963            .map(|id| TypeArchiveId(id.to_string()))
2964            .collect()
2965    }
2966
2967    /// Look up a connected [`TypeArchive`] by its `id`.
2968    ///
2969    /// NOTE: A [`TypeArchive`] can be attached but not connected, returning `None`.
2970    pub fn type_archive_by_id(&self, id: &TypeArchiveId) -> Option<Ref<TypeArchive>> {
2971        let id = id.0.as_str().to_cstr();
2972        let result = unsafe { BNBinaryViewGetTypeArchive(self.handle, id.as_ptr()) };
2973        let result_ptr = NonNull::new(result)?;
2974        Some(unsafe { TypeArchive::ref_from_raw(result_ptr) })
2975    }
2976
2977    /// Look up the path for an attached (but not necessarily connected) [`TypeArchive`] by its `id`.
2978    pub fn type_archive_path_by_id(&self, id: &TypeArchiveId) -> Option<PathBuf> {
2979        let id = id.0.as_str().to_cstr();
2980        let result = unsafe { BNBinaryViewGetTypeArchivePath(self.handle, id.as_ptr()) };
2981        if result.is_null() {
2982            return None;
2983        }
2984        let path_str = unsafe { BnString::into_string(result) };
2985        Some(PathBuf::from(path_str))
2986    }
2987
2988    pub fn deref_return_value_named_type_references(
2989        &self,
2990        return_value: &ReturnValue,
2991    ) -> ReturnValue {
2992        ReturnValue {
2993            ty: Conf::new(
2994                return_value.ty.contents.deref_named_type_reference(self),
2995                return_value.ty.confidence,
2996            ),
2997            location: return_value.location.clone(),
2998        }
2999    }
3000
3001    pub fn deref_parameter_named_type_references(
3002        &self,
3003        params: &[FunctionParameter],
3004    ) -> Vec<FunctionParameter> {
3005        params
3006            .iter()
3007            .map(|param| FunctionParameter {
3008                ty: Conf::new(
3009                    param.ty.contents.deref_named_type_reference(self),
3010                    param.ty.confidence,
3011                ),
3012                name: param.name.clone(),
3013                location: param.location.clone(),
3014            })
3015            .collect()
3016    }
3017}
3018
3019impl BinaryViewBase for BinaryView {
3020    fn read(&self, buf: &mut [u8], offset: u64) -> usize {
3021        unsafe { BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) }
3022    }
3023
3024    fn write(&self, offset: u64, data: &[u8]) -> usize {
3025        unsafe { BNWriteViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
3026    }
3027
3028    fn insert(&self, offset: u64, data: &[u8]) -> usize {
3029        unsafe { BNInsertViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
3030    }
3031
3032    fn remove(&self, offset: u64, len: usize) -> usize {
3033        unsafe { BNRemoveViewData(self.handle, offset, len as u64) }
3034    }
3035
3036    fn offset_valid(&self, offset: u64) -> bool {
3037        unsafe { BNIsValidOffset(self.handle, offset) }
3038    }
3039
3040    fn offset_readable(&self, offset: u64) -> bool {
3041        unsafe { BNIsOffsetReadable(self.handle, offset) }
3042    }
3043
3044    fn offset_writable(&self, offset: u64) -> bool {
3045        unsafe { BNIsOffsetWritable(self.handle, offset) }
3046    }
3047
3048    fn offset_executable(&self, offset: u64) -> bool {
3049        unsafe { BNIsOffsetExecutable(self.handle, offset) }
3050    }
3051
3052    fn offset_backed_by_file(&self, offset: u64) -> bool {
3053        unsafe { BNIsOffsetBackedByFile(self.handle, offset) }
3054    }
3055
3056    fn next_valid_offset_after(&self, offset: u64) -> u64 {
3057        unsafe { BNGetNextValidOffset(self.handle, offset) }
3058    }
3059
3060    fn modification_status(&self, offset: u64) -> ModificationStatus {
3061        unsafe { BNGetModification(self.handle, offset) }
3062    }
3063
3064    fn start(&self) -> u64 {
3065        unsafe { BNGetStartOffset(self.handle) }
3066    }
3067
3068    fn len(&self) -> u64 {
3069        unsafe { BNGetViewLength(self.handle) }
3070    }
3071
3072    fn executable(&self) -> bool {
3073        unsafe { BNIsExecutableView(self.handle) }
3074    }
3075
3076    fn relocatable(&self) -> bool {
3077        unsafe { BNIsRelocatable(self.handle) }
3078    }
3079
3080    fn entry_point(&self) -> u64 {
3081        unsafe { BNGetEntryPoint(self.handle) }
3082    }
3083
3084    fn default_endianness(&self) -> Endianness {
3085        unsafe { BNGetDefaultEndianness(self.handle) }
3086    }
3087
3088    fn address_size(&self) -> usize {
3089        unsafe { BNGetViewAddressSize(self.handle) }
3090    }
3091}
3092
3093unsafe impl RefCountable for BinaryView {
3094    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
3095        Ref::new(Self {
3096            handle: BNNewViewReference(handle.handle),
3097        })
3098    }
3099
3100    unsafe fn dec_ref(handle: &Self) {
3101        BNFreeBinaryView(handle.handle);
3102    }
3103}
3104
3105impl AsRef<BinaryView> for BinaryView {
3106    fn as_ref(&self) -> &Self {
3107        self
3108    }
3109}
3110
3111impl ToOwned for BinaryView {
3112    type Owned = Ref<Self>;
3113
3114    fn to_owned(&self) -> Self::Owned {
3115        unsafe { RefCountable::inc_ref(self) }
3116    }
3117}
3118
3119unsafe impl Send for BinaryView {}
3120unsafe impl Sync for BinaryView {}
3121
3122impl std::fmt::Debug for BinaryView {
3123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3124        f.debug_struct("BinaryView")
3125            .field("view_type", &self.view_type())
3126            .field("file", &self.file())
3127            .field("original_image_base", &self.original_image_base())
3128            .field("start", &self.start())
3129            .field("end", &self.end())
3130            .field("len", &self.len())
3131            .field("default_platform", &self.default_platform())
3132            .field("default_arch", &self.default_arch())
3133            .field("default_endianness", &self.default_endianness())
3134            .field("entry_point", &self.entry_point())
3135            .field(
3136                "entry_point_functions",
3137                &self.entry_point_functions().to_vec(),
3138            )
3139            .field("address_size", &self.address_size())
3140            .field("sections", &self.sections().to_vec())
3141            .field("segments", &self.segments().to_vec())
3142            .finish()
3143    }
3144}
3145
3146pub trait BinaryViewEventHandler: 'static + Sync {
3147    fn on_event(&self, binary_view: &BinaryView);
3148}
3149
3150impl<F: Fn(&BinaryView) + 'static + Sync> BinaryViewEventHandler for F {
3151    fn on_event(&self, binary_view: &BinaryView) {
3152        self(binary_view);
3153    }
3154}
3155
3156/// Registers an event listener for binary view events.
3157///
3158/// # Example
3159///
3160/// ```no_run
3161/// use binaryninja::binary_view::{
3162///     register_binary_view_event, BinaryView, BinaryViewEventHandler, BinaryViewEventType,
3163/// };
3164///
3165/// struct EventHandlerContext {
3166///     // Context holding state available to event handler
3167/// }
3168///
3169/// impl BinaryViewEventHandler for EventHandlerContext {
3170///     fn on_event(&self, binary_view: &BinaryView) {
3171///         // handle event
3172///     }
3173/// }
3174///
3175/// #[no_mangle]
3176/// pub extern "C" fn CorePluginInit() {
3177///     let context = EventHandlerContext {};
3178///
3179///     register_binary_view_event(
3180///         BinaryViewEventType::BinaryViewInitialAnalysisCompletionEvent,
3181///         context,
3182///     );
3183/// }
3184/// ```
3185pub fn register_binary_view_event<Handler>(event_type: BinaryViewEventType, handler: Handler)
3186where
3187    Handler: BinaryViewEventHandler,
3188{
3189    unsafe extern "C" fn on_event<Handler: BinaryViewEventHandler>(
3190        ctx: *mut c_void,
3191        view: *mut BNBinaryView,
3192    ) {
3193        ffi_wrap!("EventHandler::on_event", {
3194            let context = unsafe { &*(ctx as *const Handler) };
3195            context.on_event(&BinaryView::ref_from_raw(BNNewViewReference(view)));
3196        })
3197    }
3198
3199    let boxed = Box::new(handler);
3200    let raw = Box::into_raw(boxed);
3201
3202    unsafe {
3203        BNRegisterBinaryViewEvent(event_type, Some(on_event::<Handler>), raw as *mut c_void);
3204    }
3205}
3206
3207#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
3208pub struct CommentReference {
3209    pub start: u64,
3210}
3211
3212impl From<u64> for CommentReference {
3213    fn from(start: u64) -> Self {
3214        Self { start }
3215    }
3216}
3217
3218impl CoreArrayProvider for CommentReference {
3219    type Raw = u64;
3220    type Context = ();
3221    type Wrapped<'a> = Self;
3222}
3223
3224unsafe impl CoreArrayProviderInner for CommentReference {
3225    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
3226        BNFreeAddressList(raw)
3227    }
3228
3229    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
3230        Self::from(*raw)
3231    }
3232}
3233
3234#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
3235pub struct StringReference {
3236    pub ty: StringType,
3237    pub start: u64,
3238    pub length: usize,
3239}
3240
3241impl From<BNStringReference> for StringReference {
3242    fn from(raw: BNStringReference) -> Self {
3243        Self {
3244            ty: raw.type_,
3245            start: raw.start,
3246            length: raw.length,
3247        }
3248    }
3249}
3250
3251impl From<StringReference> for BNStringReference {
3252    fn from(raw: StringReference) -> Self {
3253        Self {
3254            type_: raw.ty,
3255            start: raw.start,
3256            length: raw.length,
3257        }
3258    }
3259}
3260
3261impl CoreArrayProvider for StringReference {
3262    type Raw = BNStringReference;
3263    type Context = ();
3264    type Wrapped<'a> = Self;
3265}
3266
3267unsafe impl CoreArrayProviderInner for StringReference {
3268    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
3269        BNFreeStringReferenceList(raw)
3270    }
3271
3272    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
3273        Self::from(*raw)
3274    }
3275}
3276
3277#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
3278pub struct AddressRange {
3279    pub start: u64,
3280    pub end: u64,
3281}
3282
3283impl From<BNAddressRange> for AddressRange {
3284    fn from(raw: BNAddressRange) -> Self {
3285        Self {
3286            start: raw.start,
3287            end: raw.end,
3288        }
3289    }
3290}
3291
3292impl From<AddressRange> for BNAddressRange {
3293    fn from(raw: AddressRange) -> Self {
3294        Self {
3295            start: raw.start,
3296            end: raw.end,
3297        }
3298    }
3299}
3300
3301impl CoreArrayProvider for AddressRange {
3302    type Raw = BNAddressRange;
3303    type Context = ();
3304    type Wrapped<'a> = Self;
3305}
3306
3307unsafe impl CoreArrayProviderInner for AddressRange {
3308    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
3309        BNFreeAddressRanges(raw);
3310    }
3311
3312    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
3313        Self::from(*raw)
3314    }
3315}
3316
3317extern "C" fn cb_valid<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> bool
3318where
3319    T: CustomBinaryViewType,
3320{
3321    let view_type = unsafe { &*(ctxt as *mut T) };
3322    let data = unsafe { BinaryView::ref_from_raw(BNNewViewReference(data)) };
3323    let _span = ffi_span!("CustomBinaryViewType::is_valid_for", data);
3324    view_type.is_valid_for(&data)
3325}
3326
3327extern "C" fn cb_deprecated<T>(_ctxt: *mut c_void) -> bool
3328where
3329    T: CustomBinaryViewType,
3330{
3331    T::DEPRECATED
3332}
3333
3334extern "C" fn cb_force_loadable<T>(_ctxt: *mut c_void) -> bool
3335where
3336    T: CustomBinaryViewType,
3337{
3338    T::FORCE_LOADABLE
3339}
3340
3341extern "C" fn cb_has_no_initial_content<T>(_ctxt: *mut c_void) -> bool
3342where
3343    T: CustomBinaryViewType,
3344{
3345    T::HAS_NO_INITIAL_CONTENT
3346}
3347
3348extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
3349where
3350    T: CustomBinaryViewType,
3351{
3352    ffi_wrap!("CustomBinaryViewType::create", unsafe {
3353        let view_type = &*(ctxt as *mut T);
3354        let data = BinaryView::from_raw(data);
3355        let _span = ffi_span!("CustomBinaryViewType::create", data);
3356        match view_type.create_binary_view(&data) {
3357            Ok(custom_view) => {
3358                match BinaryView::from_custom(T::NAME, &data.file(), &data, custom_view) {
3359                    Ok(custom_view) => Ref::into_raw(custom_view).handle,
3360                    Err(_) => std::ptr::null_mut(),
3361                }
3362            }
3363            Err(_) => std::ptr::null_mut(),
3364        }
3365    })
3366}
3367
3368extern "C" fn cb_parse<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
3369where
3370    T: CustomBinaryViewType,
3371{
3372    ffi_wrap!("CustomBinaryViewType::parse", unsafe {
3373        let view_type = &*(ctxt as *mut T);
3374        let data = BinaryView::from_raw(data);
3375        let _span = ffi_span!("CustomBinaryViewType::parse", data);
3376        match view_type.create_binary_view_for_parse(&data) {
3377            Ok(custom_view) => {
3378                match BinaryView::from_custom(T::NAME, &data.file(), &data, custom_view) {
3379                    Ok(custom_view) => Ref::into_raw(custom_view).handle,
3380                    Err(_) => std::ptr::null_mut(),
3381                }
3382            }
3383            Err(_) => std::ptr::null_mut(),
3384        }
3385    })
3386}
3387
3388extern "C" fn cb_load_settings<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNSettings
3389where
3390    T: CustomBinaryViewType,
3391{
3392    ffi_wrap!("CustomBinaryViewType::load_settings", unsafe {
3393        let view_type = &*(ctxt as *mut T);
3394        let data = BinaryView::from_raw(data);
3395
3396        let _span = ffi_span!("CustomBinaryViewType::load_settings", data);
3397        match view_type.load_settings_for_data(&data) {
3398            Some(load_settings) => Ref::into_raw(load_settings).handle,
3399            None => std::ptr::null_mut(),
3400        }
3401    })
3402}
3403
3404extern "C" fn cb_init<C>(ctxt: *mut c_void) -> bool
3405where
3406    C: CustomBinaryView,
3407{
3408    ffi_wrap!("BinaryViewBase::init", unsafe {
3409        let context = &mut *(ctxt as *mut CustomBinaryViewContext<C>);
3410        // SAFETY: The core view has been initialized by [`BinaryView::from_custom`], so it should be valid.
3411        // SAFETY: The custom view is not being touched by anything else at the point this function is called,
3412        // so it should be safe to mutably borrow it.
3413        context.view.initialize(context.core_view.assume_init_ref())
3414    })
3415}
3416
3417extern "C" fn cb_on_after_snapshot_data_applied<C>(ctxt: *mut c_void)
3418where
3419    C: CustomBinaryView,
3420{
3421    ffi_wrap!("BinaryViewBase::onAfterSnapshotDataApplied", unsafe {
3422        let context = &mut *(ctxt as *mut CustomBinaryViewContext<C>);
3423        // SAFETY: The custom view is not being touched by anything else at the point this function is called,
3424        // so it should be safe to mutably borrow it.
3425        context.view.on_after_snapshot_data_applied();
3426    })
3427}
3428
3429extern "C" fn cb_free_object<C>(ctxt: *mut c_void)
3430where
3431    C: CustomBinaryView,
3432{
3433    ffi_wrap!("BinaryViewBase::freeObject", unsafe {
3434        let context = ctxt as *mut CustomBinaryViewContext<C>;
3435        let _context = Box::from_raw(context);
3436    })
3437}
3438
3439extern "C" fn cb_read<C>(ctxt: *mut c_void, dest: *mut c_void, offset: u64, len: usize) -> usize
3440where
3441    C: CustomBinaryView,
3442{
3443    ffi_wrap!("BinaryViewBase::read", unsafe {
3444        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3445        let dest = std::slice::from_raw_parts_mut(dest as *mut u8, len);
3446        context.view.read(dest, offset)
3447    })
3448}
3449
3450extern "C" fn cb_write<C>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize
3451where
3452    C: CustomBinaryView,
3453{
3454    ffi_wrap!("BinaryViewBase::write", unsafe {
3455        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3456        let src = std::slice::from_raw_parts(src as *const u8, len);
3457        context.view.write(offset, src)
3458    })
3459}
3460
3461extern "C" fn cb_insert<C>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize
3462where
3463    C: CustomBinaryView,
3464{
3465    ffi_wrap!("BinaryViewBase::insert", unsafe {
3466        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3467        let src = std::slice::from_raw_parts(src as *const u8, len);
3468        context.view.insert(offset, src)
3469    })
3470}
3471
3472extern "C" fn cb_remove<C>(ctxt: *mut c_void, offset: u64, len: u64) -> usize
3473where
3474    C: CustomBinaryView,
3475{
3476    ffi_wrap!("BinaryViewBase::remove", unsafe {
3477        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3478        context.view.remove(offset, len as usize)
3479    })
3480}
3481
3482extern "C" fn cb_modification<C>(ctxt: *mut c_void, offset: u64) -> ModificationStatus
3483where
3484    C: CustomBinaryView,
3485{
3486    ffi_wrap!("BinaryViewBase::modification_status", unsafe {
3487        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3488        context.view.modification_status(offset)
3489    })
3490}
3491
3492extern "C" fn cb_offset_valid<C>(ctxt: *mut c_void, offset: u64) -> bool
3493where
3494    C: CustomBinaryView,
3495{
3496    ffi_wrap!("BinaryViewBase::offset_valid", unsafe {
3497        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3498        context.view.offset_valid(offset)
3499    })
3500}
3501
3502extern "C" fn cb_offset_readable<C>(ctxt: *mut c_void, offset: u64) -> bool
3503where
3504    C: CustomBinaryView,
3505{
3506    ffi_wrap!("BinaryViewBase::readable", unsafe {
3507        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3508        context.view.offset_readable(offset)
3509    })
3510}
3511
3512extern "C" fn cb_offset_writable<C>(ctxt: *mut c_void, offset: u64) -> bool
3513where
3514    C: CustomBinaryView,
3515{
3516    ffi_wrap!("BinaryViewBase::writable", unsafe {
3517        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3518        context.view.offset_writable(offset)
3519    })
3520}
3521
3522extern "C" fn cb_offset_executable<C>(ctxt: *mut c_void, offset: u64) -> bool
3523where
3524    C: CustomBinaryView,
3525{
3526    ffi_wrap!("BinaryViewBase::offset_executable", unsafe {
3527        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3528        context.view.offset_executable(offset)
3529    })
3530}
3531
3532extern "C" fn cb_offset_backed_by_file<C>(ctxt: *mut c_void, offset: u64) -> bool
3533where
3534    C: CustomBinaryView,
3535{
3536    ffi_wrap!("BinaryViewBase::offset_backed_by_file", unsafe {
3537        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3538        context.view.offset_backed_by_file(offset)
3539    })
3540}
3541
3542extern "C" fn cb_next_valid_offset<C>(ctxt: *mut c_void, offset: u64) -> u64
3543where
3544    C: CustomBinaryView,
3545{
3546    ffi_wrap!("BinaryViewBase::next_valid_offset_after", unsafe {
3547        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3548        context.view.next_valid_offset_after(offset)
3549    })
3550}
3551
3552extern "C" fn cb_start<C>(ctxt: *mut c_void) -> u64
3553where
3554    C: CustomBinaryView,
3555{
3556    ffi_wrap!("BinaryViewBase::start", unsafe {
3557        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3558        context.view.start()
3559    })
3560}
3561
3562extern "C" fn cb_length<C>(ctxt: *mut c_void) -> u64
3563where
3564    C: CustomBinaryView,
3565{
3566    ffi_wrap!("BinaryViewBase::len", unsafe {
3567        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3568        context.view.len()
3569    })
3570}
3571
3572extern "C" fn cb_entry_point<C>(ctxt: *mut c_void) -> u64
3573where
3574    C: CustomBinaryView,
3575{
3576    ffi_wrap!("BinaryViewBase::entry_point", unsafe {
3577        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3578        context.view.entry_point()
3579    })
3580}
3581
3582extern "C" fn cb_executable<C>(ctxt: *mut c_void) -> bool
3583where
3584    C: CustomBinaryView,
3585{
3586    ffi_wrap!("BinaryViewBase::executable", unsafe {
3587        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3588        context.view.executable()
3589    })
3590}
3591
3592extern "C" fn cb_endianness<C>(ctxt: *mut c_void) -> Endianness
3593where
3594    C: CustomBinaryView,
3595{
3596    ffi_wrap!("BinaryViewBase::default_endianness", unsafe {
3597        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3598        context.view.default_endianness()
3599    })
3600}
3601
3602extern "C" fn cb_relocatable<C>(ctxt: *mut c_void) -> bool
3603where
3604    C: CustomBinaryView,
3605{
3606    ffi_wrap!("BinaryViewBase::relocatable", unsafe {
3607        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3608        context.view.relocatable()
3609    })
3610}
3611
3612extern "C" fn cb_address_size<C>(ctxt: *mut c_void) -> usize
3613where
3614    C: CustomBinaryView,
3615{
3616    ffi_wrap!("BinaryViewBase::address_size", unsafe {
3617        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3618        context.view.address_size()
3619    })
3620}
3621
3622extern "C" fn cb_save<C>(ctxt: *mut c_void, _file: *mut BNFileAccessor) -> bool
3623where
3624    C: CustomBinaryView,
3625{
3626    ffi_wrap!("BinaryViewBase::save", unsafe {
3627        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3628        // TODO: Need to pass file accessor to save to.
3629        // let file = FileAccessor::from_raw(file);
3630        context.view.save()
3631    })
3632}