Skip to main content

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