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