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