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, CodeXref, DataReference, DataXref};
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 the references made by code to a given [Range], each with its source and target.
2487    pub fn incoming_code_refs(&self, range: Range<u64>) -> Array<CodeXref> {
2488        unsafe {
2489            let mut count = 0;
2490            let handle = BNGetIncomingCodeReferences(
2491                self.handle,
2492                range.start,
2493                range.end - range.start,
2494                &mut count,
2495                false,
2496                0,
2497            );
2498            Array::new(handle, count, ())
2499        }
2500    }
2501
2502    /// Retrieves a list of addresses pointed to by a given address.
2503    pub fn code_refs_from_addr(&self, addr: u64, func: Option<&Function>) -> Vec<u64> {
2504        unsafe {
2505            let mut count = 0;
2506            let code_ref =
2507                CodeReference::new(addr, func.map(|f| f.to_owned()), func.map(|f| f.arch()));
2508            let mut raw_code_ref = CodeReference::into_owned_raw(&code_ref);
2509            let addresses = BNGetCodeReferencesFrom(self.handle, &mut raw_code_ref, &mut count);
2510            let res = std::slice::from_raw_parts(addresses, count).to_vec();
2511            BNFreeAddressList(addresses);
2512            res
2513        }
2514    }
2515
2516    /// Retrieves the references made by code in a given [Range], each with its source and target.
2517    ///
2518    /// With `func`, only references made by that function are returned. Otherwise references
2519    /// made by every function with code in the range are returned.
2520    pub fn outgoing_code_refs(
2521        &self,
2522        range: Range<u64>,
2523        func: Option<&Function>,
2524    ) -> Array<CodeXref> {
2525        unsafe {
2526            let mut count = 0;
2527            let handle = BNGetOutgoingCodeReferences(
2528                self.handle,
2529                range.start,
2530                range.end - range.start,
2531                func.map(|f| f.handle).unwrap_or(std::ptr::null_mut()),
2532                &mut count,
2533                false,
2534                0,
2535            );
2536            Array::new(handle, count, ())
2537        }
2538    }
2539
2540    /// Retrieves a list of [DataReference]s pointing to a given address.
2541    pub fn data_refs_to_addr(&self, addr: u64) -> Array<DataReference> {
2542        unsafe {
2543            let mut count = 0;
2544            let handle = BNGetDataReferences(self.handle, addr, &mut count, false, 0);
2545            Array::new(handle, count, ())
2546        }
2547    }
2548
2549    /// Retrieves a list of [DataReference]s pointing into a given [Range].
2550    pub fn data_refs_into_range(&self, range: Range<u64>) -> Array<DataReference> {
2551        unsafe {
2552            let mut count = 0;
2553            let handle = BNGetDataReferencesInRange(
2554                self.handle,
2555                range.start,
2556                range.end - range.start,
2557                &mut count,
2558                false,
2559                0,
2560            );
2561            Array::new(handle, count, ())
2562        }
2563    }
2564
2565    /// Retrieves the references made by data to a given [Range], each with its source and target.
2566    pub fn incoming_data_refs(&self, range: Range<u64>) -> Array<DataXref> {
2567        unsafe {
2568            let mut count = 0;
2569            let handle = BNGetIncomingDataReferences(
2570                self.handle,
2571                range.start,
2572                range.end - range.start,
2573                &mut count,
2574                false,
2575                0,
2576            );
2577            Array::new(handle, count, ())
2578        }
2579    }
2580
2581    /// Retrieves a list of [DataReference]s originating from a given address.
2582    pub fn data_refs_from_addr(&self, addr: u64) -> Array<DataReference> {
2583        unsafe {
2584            let mut count = 0;
2585            let handle = BNGetDataReferencesFrom(self.handle, addr, &mut count);
2586            Array::new(handle, count, ())
2587        }
2588    }
2589
2590    /// Retrieves the references made by data in a given [Range], each with its source and target.
2591    pub fn outgoing_data_refs(&self, range: Range<u64>) -> Array<DataXref> {
2592        unsafe {
2593            let mut count = 0;
2594            let handle = BNGetOutgoingDataReferences(
2595                self.handle,
2596                range.start,
2597                range.end - range.start,
2598                &mut count,
2599                false,
2600                0,
2601            );
2602            Array::new(handle, count, ())
2603        }
2604    }
2605
2606    /// Retrieves a list of [CodeReference]s for locations in code that use a given named type.
2607    pub fn code_refs_using_type_name<T: Into<QualifiedName>>(
2608        &self,
2609        name: T,
2610    ) -> Array<CodeReference> {
2611        let mut raw_name = QualifiedName::into_raw(name.into());
2612        unsafe {
2613            let mut count = 0;
2614            let handle =
2615                BNGetCodeReferencesForType(self.handle, &mut raw_name, &mut count, false, 0);
2616            QualifiedName::free_raw(raw_name);
2617            Array::new(handle, count, ())
2618        }
2619    }
2620
2621    /// Retrieves a list of [DataReference]s for locations in data that use a given named type.
2622    pub fn data_refs_using_type_name<T: Into<QualifiedName>>(
2623        &self,
2624        name: T,
2625    ) -> Array<DataReference> {
2626        let mut raw_name = QualifiedName::into_raw(name.into());
2627        unsafe {
2628            let mut count = 0;
2629            let handle =
2630                BNGetDataReferencesForType(self.handle, &mut raw_name, &mut count, false, 0);
2631            QualifiedName::free_raw(raw_name);
2632            Array::new(handle, count, ())
2633        }
2634    }
2635
2636    pub fn relocations_at(&self, addr: u64) -> Array<Relocation> {
2637        unsafe {
2638            let mut count = 0;
2639            let handle = BNGetRelocationsAt(self.handle, addr, &mut count);
2640            Array::new(handle, count, ())
2641        }
2642    }
2643
2644    pub fn relocation_ranges(&self) -> Vec<Range<u64>> {
2645        let ranges = unsafe {
2646            let mut count = 0;
2647            let reloc_ranges_ptr = BNGetRelocationRanges(self.handle, &mut count);
2648            let ranges = std::slice::from_raw_parts(reloc_ranges_ptr, count).to_vec();
2649            BNFreeRelocationRanges(reloc_ranges_ptr);
2650            ranges
2651        };
2652
2653        // TODO: impl From BNRange for Range?
2654        ranges
2655            .iter()
2656            .map(|range| Range {
2657                start: range.start,
2658                end: range.end,
2659            })
2660            .collect()
2661    }
2662
2663    pub fn component_by_guid(&self, guid: &str) -> Option<Ref<Component>> {
2664        let name = guid.to_cstr();
2665        let result = unsafe { BNGetComponentByGuid(self.handle, name.as_ptr()) };
2666        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
2667    }
2668
2669    pub fn root_component(&self) -> Option<Ref<Component>> {
2670        let result = unsafe { BNGetRootComponent(self.handle) };
2671        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
2672    }
2673
2674    pub fn component_by_path(&self, path: &str) -> Option<Ref<Component>> {
2675        let path = path.to_cstr();
2676        let result = unsafe { BNGetComponentByPath(self.handle, path.as_ptr()) };
2677        NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) })
2678    }
2679
2680    pub fn remove_component(&self, component: &Component) -> bool {
2681        unsafe { BNRemoveComponent(self.handle, component.handle.as_ptr()) }
2682    }
2683
2684    pub fn remove_component_by_guid(&self, guid: &str) -> bool {
2685        let path = guid.to_cstr();
2686        unsafe { BNRemoveComponentByGuid(self.handle, path.as_ptr()) }
2687    }
2688
2689    pub fn data_variable_parent_components(
2690        &self,
2691        data_variable: &DataVariable,
2692    ) -> Array<Component> {
2693        let mut count = 0;
2694        let result = unsafe {
2695            BNGetDataVariableParentComponents(self.handle, data_variable.address, &mut count)
2696        };
2697        unsafe { Array::new(result, count, ()) }
2698    }
2699
2700    pub fn external_libraries(&self) -> Array<ExternalLibrary> {
2701        let mut count = 0;
2702        let result = unsafe { BNBinaryViewGetExternalLibraries(self.handle, &mut count) };
2703        unsafe { Array::new(result, count, ()) }
2704    }
2705
2706    pub fn external_library(&self, name: &str) -> Option<Ref<ExternalLibrary>> {
2707        let name_ptr = name.to_cstr();
2708        let result = unsafe { BNBinaryViewGetExternalLibrary(self.handle, name_ptr.as_ptr()) };
2709        let result_ptr = NonNull::new(result)?;
2710        Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) })
2711    }
2712
2713    pub fn remove_external_library(&self, name: &str) {
2714        let name_ptr = name.to_cstr();
2715        unsafe { BNBinaryViewRemoveExternalLibrary(self.handle, name_ptr.as_ptr()) };
2716    }
2717
2718    pub fn add_external_library(
2719        &self,
2720        name: &str,
2721        backing_file: Option<&ProjectFile>,
2722        auto: bool,
2723    ) -> Option<Ref<ExternalLibrary>> {
2724        let name_ptr = name.to_cstr();
2725        let result = unsafe {
2726            BNBinaryViewAddExternalLibrary(
2727                self.handle,
2728                name_ptr.as_ptr(),
2729                backing_file
2730                    .map(|b| b.handle.as_ptr())
2731                    .unwrap_or(std::ptr::null_mut()),
2732                auto,
2733            )
2734        };
2735        NonNull::new(result).map(|h| unsafe { ExternalLibrary::ref_from_raw(h) })
2736    }
2737
2738    pub fn external_locations(&self) -> Array<ExternalLocation> {
2739        let mut count = 0;
2740        let result = unsafe { BNBinaryViewGetExternalLocations(self.handle, &mut count) };
2741        unsafe { Array::new(result, count, ()) }
2742    }
2743
2744    pub fn external_location_from_symbol(&self, symbol: &Symbol) -> Option<Ref<ExternalLocation>> {
2745        let result = unsafe { BNBinaryViewGetExternalLocation(self.handle, symbol.handle) };
2746        let result_ptr = NonNull::new(result)?;
2747        Some(unsafe { ExternalLocation::ref_from_raw(result_ptr) })
2748    }
2749
2750    pub fn remove_external_location(&self, location: &ExternalLocation) {
2751        self.remove_external_location_from_symbol(&location.source_symbol())
2752    }
2753
2754    pub fn remove_external_location_from_symbol(&self, symbol: &Symbol) {
2755        unsafe { BNBinaryViewRemoveExternalLocation(self.handle, symbol.handle) };
2756    }
2757
2758    // TODO: This is awful, rewrite this.
2759    pub fn add_external_location(
2760        &self,
2761        symbol: &Symbol,
2762        library: &ExternalLibrary,
2763        target_symbol_name: &str,
2764        target_address: Option<u64>,
2765        target_is_auto: bool,
2766    ) -> Option<Ref<ExternalLocation>> {
2767        let target_symbol_name = target_symbol_name.to_cstr();
2768        let target_address_ptr = target_address
2769            .map(|a| a as *mut u64)
2770            .unwrap_or(std::ptr::null_mut());
2771        let result = unsafe {
2772            BNBinaryViewAddExternalLocation(
2773                self.handle,
2774                symbol.handle,
2775                library.handle.as_ptr(),
2776                target_symbol_name.as_ptr(),
2777                target_address_ptr,
2778                target_is_auto,
2779            )
2780        };
2781        NonNull::new(result).map(|h| unsafe { ExternalLocation::ref_from_raw(h) })
2782    }
2783
2784    /// Type container for all types (user and auto) in the Binary View.
2785    ///
2786    /// NOTE: Modifying an auto type will promote it to a user type.
2787    pub fn type_container(&self) -> TypeContainer {
2788        let type_container_ptr = NonNull::new(unsafe { BNGetAnalysisTypeContainer(self.handle) });
2789        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2790        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
2791    }
2792
2793    /// Type container for user types in the Binary View.
2794    pub fn user_type_container(&self) -> TypeContainer {
2795        let type_container_ptr =
2796            NonNull::new(unsafe { BNGetAnalysisUserTypeContainer(self.handle) });
2797        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2798        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }.clone()
2799    }
2800
2801    /// Type container for auto types in the Binary View.
2802    ///
2803    /// NOTE: Unlike [`Self::type_container`] modification of auto types will **NOT** promote it to a user type.
2804    pub fn auto_type_container(&self) -> TypeContainer {
2805        let type_container_ptr =
2806            NonNull::new(unsafe { BNGetAnalysisAutoTypeContainer(self.handle) });
2807        // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw`
2808        unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }
2809    }
2810
2811    pub fn type_libraries(&self) -> Array<TypeLibrary> {
2812        let mut count = 0;
2813        let result = unsafe { BNGetBinaryViewTypeLibraries(self.handle, &mut count) };
2814        unsafe { Array::new(result, count, ()) }
2815    }
2816
2817    /// Make the contents of a type library available for type/import resolution
2818    pub fn add_type_library(&self, library: &TypeLibrary) {
2819        unsafe { BNAddBinaryViewTypeLibrary(self.handle, library.as_raw()) }
2820    }
2821
2822    pub fn type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> {
2823        let name = name.to_cstr();
2824        let result = unsafe { BNGetBinaryViewTypeLibrary(self.handle, name.as_ptr()) };
2825        NonNull::new(result).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
2826    }
2827
2828    /// Should be called by custom [`BinaryView`] implementations when they have successfully
2829    /// imported an object from a type library (eg a symbol's type). Values recorded with this
2830    /// function will then be queryable via [`BinaryView::lookup_imported_object_library`].
2831    ///
2832    /// * `lib` - Type Library containing the imported type
2833    /// * `name` - Name of the object in the type library
2834    /// * `addr` - address of symbol at import site
2835    /// * `platform` - Platform of symbol at import site
2836    pub fn record_imported_object_library<T: Into<QualifiedName>>(
2837        &self,
2838        lib: &TypeLibrary,
2839        name: T,
2840        addr: u64,
2841        platform: &Platform,
2842    ) {
2843        let mut raw_name = QualifiedName::into_raw(name.into());
2844        unsafe {
2845            BNBinaryViewRecordImportedObjectLibrary(
2846                self.handle,
2847                platform.handle,
2848                addr,
2849                lib.as_raw(),
2850                &mut raw_name,
2851            )
2852        }
2853        QualifiedName::free_raw(raw_name);
2854    }
2855
2856    /// Recursively imports a type from the specified type library, or, if no library was
2857    /// explicitly provided, the first type library associated with the current [`BinaryView`] that
2858    /// provides the name requested.
2859    ///
2860    /// This may have the impact of loading other type libraries as dependencies on other type
2861    /// libraries are lazily resolved when references to types provided by them are first encountered.
2862    ///
2863    /// Note that the name actually inserted into the view may not match the name as it exists in
2864    /// the type library in the event of a name conflict. To aid in this, the [`Type`] object
2865    /// returned is a `NamedTypeReference` to the deconflicted name used.
2866    pub fn import_type_library_type<T: Into<QualifiedName>>(
2867        &self,
2868        name: T,
2869        lib: Option<&TypeLibrary>,
2870    ) -> Option<Ref<Type>> {
2871        let mut lib_ref = lib
2872            .as_ref()
2873            .map(|l| unsafe { l.as_raw() } as *mut _)
2874            .unwrap_or(std::ptr::null_mut());
2875        let mut raw_name = QualifiedName::into_raw(name.into());
2876        let result =
2877            unsafe { BNBinaryViewImportTypeLibraryType(self.handle, &mut lib_ref, &mut raw_name) };
2878        QualifiedName::free_raw(raw_name);
2879        // Core stores a new reference to the library the type came from in `lib_ref`.
2880        if let Some(lib_ref) = NonNull::new(lib_ref) {
2881            drop(unsafe { TypeLibrary::ref_from_raw(lib_ref) });
2882        }
2883        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2884    }
2885
2886    /// Recursively imports an object (function) from the specified type library, or, if no library was
2887    /// explicitly provided, the first type library associated with the current [`BinaryView`] that
2888    /// provides the name requested.
2889    ///
2890    /// This may have the impact of loading other type libraries as dependencies on other type
2891    /// libraries are lazily resolved when references to types provided by them are first encountered.
2892    ///
2893    /// NOTE: If you are implementing a custom [`BinaryView`] and use this method to import object types,
2894    /// you should then call [BinaryView::record_imported_object_library] with the details of
2895    /// where the object is located.
2896    pub fn import_type_library_object<T: Into<QualifiedName>>(
2897        &self,
2898        name: T,
2899        lib: Option<&TypeLibrary>,
2900    ) -> Option<Ref<Type>> {
2901        let mut lib_ref = lib
2902            .as_ref()
2903            .map(|l| unsafe { l.as_raw() } as *mut _)
2904            .unwrap_or(std::ptr::null_mut());
2905        let mut raw_name = QualifiedName::into_raw(name.into());
2906        let result = unsafe {
2907            BNBinaryViewImportTypeLibraryObject(self.handle, &mut lib_ref, &mut raw_name)
2908        };
2909        QualifiedName::free_raw(raw_name);
2910        // Core stores a new reference to the library the object came from in `lib_ref`.
2911        if let Some(lib_ref) = NonNull::new(lib_ref) {
2912            drop(unsafe { TypeLibrary::ref_from_raw(lib_ref) });
2913        }
2914        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2915    }
2916
2917    /// Recursively imports a [`Type`] given its GUID from available type libraries.
2918    pub fn import_type_by_guid(&self, guid: &str) -> Option<Ref<Type>> {
2919        let guid = guid.to_cstr();
2920        let result = unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.handle, guid.as_ptr()) };
2921        (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
2922    }
2923
2924    /// Recursively exports `type_obj` into `lib` as a type with name `name`.
2925    ///
2926    /// As other referenced types are encountered, they are either copied into the destination type library or
2927    /// else the type library that provided the referenced type is added as a dependency for the destination library.
2928    pub fn export_type_to_library<T: Into<QualifiedName>>(
2929        &self,
2930        lib: &TypeLibrary,
2931        name: T,
2932        type_obj: &Type,
2933    ) {
2934        let mut raw_name = QualifiedName::into_raw(name.into());
2935        unsafe {
2936            BNBinaryViewExportTypeToTypeLibrary(
2937                self.handle,
2938                lib.as_raw(),
2939                &mut raw_name,
2940                type_obj.handle,
2941            )
2942        }
2943        QualifiedName::free_raw(raw_name);
2944    }
2945
2946    /// Recursively exports `type_obj` into `lib` as a type with name `name`.
2947    ///
2948    /// As other referenced types are encountered, they are either copied into the destination type library or
2949    /// else the type library that provided the referenced type is added as a dependency for the destination library.
2950    pub fn export_object_to_library<T: Into<QualifiedName>>(
2951        &self,
2952        lib: &TypeLibrary,
2953        name: T,
2954        type_obj: &Type,
2955    ) {
2956        let mut raw_name = QualifiedName::into_raw(name.into());
2957        unsafe {
2958            BNBinaryViewExportObjectToTypeLibrary(
2959                self.handle,
2960                lib.as_raw(),
2961                &mut raw_name,
2962                type_obj.handle,
2963            )
2964        }
2965        QualifiedName::free_raw(raw_name);
2966    }
2967
2968    /// Gives you details of which type library and name was used to determine
2969    /// the type of a symbol at a given address
2970    ///
2971    /// * `addr` - address of symbol at import site
2972    /// * `platform` - Platform of symbol at import site
2973    pub fn lookup_imported_object_library(
2974        &self,
2975        addr: u64,
2976        platform: &Platform,
2977    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
2978        let mut result_lib = std::ptr::null_mut();
2979        let mut result_name = BNQualifiedName::default();
2980        let success = unsafe {
2981            BNBinaryViewLookupImportedObjectLibrary(
2982                self.handle,
2983                platform.handle,
2984                addr,
2985                &mut result_lib,
2986                &mut result_name,
2987            )
2988        };
2989        if !success {
2990            return None;
2991        }
2992        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
2993        let name = QualifiedName::from_owned_raw(result_name);
2994        Some((lib, name))
2995    }
2996
2997    /// Gives you details of from which type library and name a given type in the analysis was imported.
2998    ///
2999    /// * `name` - Name of type in analysis
3000    pub fn lookup_imported_type_library<T: Into<QualifiedName>>(
3001        &self,
3002        name: T,
3003    ) -> Option<(Ref<TypeLibrary>, QualifiedName)> {
3004        let raw_name = QualifiedName::into_raw(name.into());
3005        let mut result_lib = std::ptr::null_mut();
3006        let mut result_name = BNQualifiedName::default();
3007        let success = unsafe {
3008            BNBinaryViewLookupImportedTypeLibrary(
3009                self.handle,
3010                &raw_name,
3011                &mut result_lib,
3012                &mut result_name,
3013            )
3014        };
3015        QualifiedName::free_raw(raw_name);
3016        if !success {
3017            return None;
3018        }
3019        let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) };
3020        let name = QualifiedName::from_owned_raw(result_name);
3021        Some((lib, name))
3022    }
3023
3024    /// Retrieve all known strings in the binary.
3025    ///
3026    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
3027    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
3028    /// data and convert it to a representable form.
3029    ///
3030    /// Some helpers for reading strings are available:
3031    ///
3032    /// - [`BinaryView::read_c_string_at`]
3033    /// - [`BinaryView::read_utf8_string_at`]
3034    ///
3035    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
3036    /// and other settings.
3037    pub fn strings(&self) -> Array<StringReference> {
3038        unsafe {
3039            let mut count = 0;
3040            let strings = BNGetStrings(self.handle, &mut count);
3041            Array::new(strings, count, ())
3042        }
3043    }
3044
3045    /// Retrieve the string that falls on a given virtual address.
3046    ///
3047    /// NOTE: This returns a [`StringReference`] and since strings may not be representable as a Rust
3048    /// [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
3049    /// data and convert it to a representable form.
3050    ///
3051    /// Some helpers for reading strings are available:
3052    ///
3053    /// - [`BinaryView::read_c_string_at`]
3054    /// - [`BinaryView::read_utf8_string_at`]
3055    ///
3056    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
3057    /// and other settings.
3058    pub fn string_at(&self, addr: u64) -> Option<StringReference> {
3059        let mut str_ref = BNStringReference::default();
3060        let success = unsafe { BNGetStringAtAddress(self.handle, addr, &mut str_ref) };
3061        if success {
3062            Some(str_ref.into())
3063        } else {
3064            None
3065        }
3066    }
3067
3068    /// Retrieve all known strings within the provided `range`.
3069    ///
3070    /// NOTE: This returns a list of [`StringReference`] as strings may not be representable
3071    /// as a [`String`] or even a [`BnString`]. It is the caller's responsibility to read the underlying
3072    /// data and convert it to a representable form.
3073    ///
3074    /// Some helpers for reading strings are available:
3075    ///
3076    /// - [`BinaryView::read_c_string_at`]
3077    /// - [`BinaryView::read_utf8_string_at`]
3078    ///
3079    /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength`
3080    /// and other settings.
3081    pub fn strings_in_range(&self, range: Range<u64>) -> Array<StringReference> {
3082        unsafe {
3083            let mut count = 0;
3084            let strings = BNGetStringsInRange(
3085                self.handle,
3086                range.start,
3087                range.end - range.start,
3088                &mut count,
3089            );
3090            Array::new(strings, count, ())
3091        }
3092    }
3093
3094    /// Retrieve the attached type archives as their [`TypeArchiveId`].
3095    ///
3096    /// Using the returned id you can retrieve the [`TypeArchive`] with [`BinaryView::type_archive_by_id`].
3097    pub fn attached_type_archives(&self) -> Vec<TypeArchiveId> {
3098        let mut ids: *mut *mut c_char = std::ptr::null_mut();
3099        let mut paths: *mut *mut c_char = std::ptr::null_mut();
3100        let count = unsafe { BNBinaryViewGetTypeArchives(self.handle, &mut ids, &mut paths) };
3101        // We discard the path here, you can retrieve it later with [`BinaryView::type_archive_path_by_id`].
3102        // This is so we can simplify the return type which will commonly just want to query through to the type
3103        // archive itself.
3104        let _path_list = unsafe { Array::<BnString>::new(paths, count, ()) };
3105        let id_list = unsafe { Array::<BnString>::new(ids, count, ()) };
3106        id_list
3107            .into_iter()
3108            .map(|id| TypeArchiveId(id.to_string()))
3109            .collect()
3110    }
3111
3112    /// Look up a connected [`TypeArchive`] by its `id`.
3113    ///
3114    /// NOTE: A [`TypeArchive`] can be attached but not connected, returning `None`.
3115    pub fn type_archive_by_id(&self, id: &TypeArchiveId) -> Option<Ref<TypeArchive>> {
3116        let id = id.0.as_str().to_cstr();
3117        let result = unsafe { BNBinaryViewGetTypeArchive(self.handle, id.as_ptr()) };
3118        let result_ptr = NonNull::new(result)?;
3119        Some(unsafe { TypeArchive::ref_from_raw(result_ptr) })
3120    }
3121
3122    /// Look up the path for an attached (but not necessarily connected) [`TypeArchive`] by its `id`.
3123    pub fn type_archive_path_by_id(&self, id: &TypeArchiveId) -> Option<PathBuf> {
3124        let id = id.0.as_str().to_cstr();
3125        let result = unsafe { BNBinaryViewGetTypeArchivePath(self.handle, id.as_ptr()) };
3126        if result.is_null() {
3127            return None;
3128        }
3129        let path_str = unsafe { BnString::into_string(result) };
3130        Some(PathBuf::from(path_str))
3131    }
3132
3133    pub fn deref_return_value_named_type_references(
3134        &self,
3135        return_value: &ReturnValue,
3136    ) -> ReturnValue {
3137        ReturnValue {
3138            ty: Conf::new(
3139                return_value.ty.contents.deref_named_type_reference(self),
3140                return_value.ty.confidence,
3141            ),
3142            location: return_value.location.clone(),
3143        }
3144    }
3145
3146    pub fn deref_parameter_named_type_references(
3147        &self,
3148        params: &[FunctionParameter],
3149    ) -> Vec<FunctionParameter> {
3150        params
3151            .iter()
3152            .map(|param| FunctionParameter {
3153                ty: Conf::new(
3154                    param.ty.contents.deref_named_type_reference(self),
3155                    param.ty.confidence,
3156                ),
3157                name: param.name.clone(),
3158                location: param.location.clone(),
3159            })
3160            .collect()
3161    }
3162}
3163
3164impl BinaryViewBase for BinaryView {
3165    fn read(&self, buf: &mut [u8], offset: u64) -> usize {
3166        unsafe { BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) }
3167    }
3168
3169    fn write(&self, offset: u64, data: &[u8]) -> usize {
3170        unsafe { BNWriteViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
3171    }
3172
3173    fn insert(&self, offset: u64, data: &[u8]) -> usize {
3174        unsafe { BNInsertViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
3175    }
3176
3177    fn remove(&self, offset: u64, len: usize) -> usize {
3178        unsafe { BNRemoveViewData(self.handle, offset, len as u64) }
3179    }
3180
3181    fn offset_valid(&self, offset: u64) -> bool {
3182        unsafe { BNIsValidOffset(self.handle, offset) }
3183    }
3184
3185    fn offset_readable(&self, offset: u64) -> bool {
3186        unsafe { BNIsOffsetReadable(self.handle, offset) }
3187    }
3188
3189    fn offset_writable(&self, offset: u64) -> bool {
3190        unsafe { BNIsOffsetWritable(self.handle, offset) }
3191    }
3192
3193    fn offset_executable(&self, offset: u64) -> bool {
3194        unsafe { BNIsOffsetExecutable(self.handle, offset) }
3195    }
3196
3197    fn offset_backed_by_file(&self, offset: u64) -> bool {
3198        unsafe { BNIsOffsetBackedByFile(self.handle, offset) }
3199    }
3200
3201    fn next_valid_offset_after(&self, offset: u64) -> u64 {
3202        unsafe { BNGetNextValidOffset(self.handle, offset) }
3203    }
3204
3205    fn modification_status(&self, offset: u64) -> ModificationStatus {
3206        unsafe { BNGetModification(self.handle, offset) }
3207    }
3208
3209    fn start(&self) -> u64 {
3210        unsafe { BNGetStartOffset(self.handle) }
3211    }
3212
3213    fn len(&self) -> u64 {
3214        unsafe { BNGetViewLength(self.handle) }
3215    }
3216
3217    fn executable(&self) -> bool {
3218        unsafe { BNIsExecutableView(self.handle) }
3219    }
3220
3221    fn relocatable(&self) -> bool {
3222        unsafe { BNIsRelocatable(self.handle) }
3223    }
3224
3225    fn entry_point(&self) -> u64 {
3226        unsafe { BNGetEntryPoint(self.handle) }
3227    }
3228
3229    fn default_endianness(&self) -> Endianness {
3230        unsafe { BNGetDefaultEndianness(self.handle) }
3231    }
3232
3233    fn address_size(&self) -> usize {
3234        unsafe { BNGetViewAddressSize(self.handle) }
3235    }
3236}
3237
3238unsafe impl RefCountable for BinaryView {
3239    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
3240        Ref::new(Self {
3241            handle: BNNewViewReference(handle.handle),
3242        })
3243    }
3244
3245    unsafe fn dec_ref(handle: &Self) {
3246        BNFreeBinaryView(handle.handle);
3247    }
3248}
3249
3250impl AsRef<BinaryView> for BinaryView {
3251    fn as_ref(&self) -> &Self {
3252        self
3253    }
3254}
3255
3256impl ToOwned for BinaryView {
3257    type Owned = Ref<Self>;
3258
3259    fn to_owned(&self) -> Self::Owned {
3260        unsafe { RefCountable::inc_ref(self) }
3261    }
3262}
3263
3264unsafe impl Send for BinaryView {}
3265unsafe impl Sync for BinaryView {}
3266
3267impl std::fmt::Debug for BinaryView {
3268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3269        f.debug_struct("BinaryView")
3270            .field("view_type", &self.view_type())
3271            .field("file", &self.file())
3272            .field("original_image_base", &self.original_image_base())
3273            .field("start", &self.start())
3274            .field("end", &self.end())
3275            .field("len", &self.len())
3276            .field("default_platform", &self.default_platform())
3277            .field("default_arch", &self.default_arch())
3278            .field("default_endianness", &self.default_endianness())
3279            .field("entry_point", &self.entry_point())
3280            .field(
3281                "entry_point_functions",
3282                &self.entry_point_functions().to_vec(),
3283            )
3284            .field("address_size", &self.address_size())
3285            .field("sections", &self.sections().to_vec())
3286            .field("segments", &self.segments().to_vec())
3287            .finish()
3288    }
3289}
3290
3291pub trait BinaryViewEventHandler: 'static + Sync {
3292    fn on_event(&self, binary_view: &BinaryView);
3293}
3294
3295impl<F: Fn(&BinaryView) + 'static + Sync> BinaryViewEventHandler for F {
3296    fn on_event(&self, binary_view: &BinaryView) {
3297        self(binary_view);
3298    }
3299}
3300
3301/// Registers an event listener for binary view events.
3302///
3303/// # Example
3304///
3305/// ```no_run
3306/// use binaryninja::binary_view::{
3307///     register_binary_view_event, BinaryView, BinaryViewEventHandler, BinaryViewEventType,
3308/// };
3309///
3310/// struct EventHandlerContext {
3311///     // Context holding state available to event handler
3312/// }
3313///
3314/// impl BinaryViewEventHandler for EventHandlerContext {
3315///     fn on_event(&self, binary_view: &BinaryView) {
3316///         // handle event
3317///     }
3318/// }
3319///
3320/// #[no_mangle]
3321/// pub extern "C" fn CorePluginInit() {
3322///     let context = EventHandlerContext {};
3323///
3324///     register_binary_view_event(
3325///         BinaryViewEventType::BinaryViewInitialAnalysisCompletionEvent,
3326///         context,
3327///     );
3328/// }
3329/// ```
3330pub fn register_binary_view_event<Handler>(event_type: BinaryViewEventType, handler: Handler)
3331where
3332    Handler: BinaryViewEventHandler,
3333{
3334    unsafe extern "C" fn on_event<Handler: BinaryViewEventHandler>(
3335        ctx: *mut c_void,
3336        view: *mut BNBinaryView,
3337    ) {
3338        ffi_wrap!("EventHandler::on_event", {
3339            let context = unsafe { &*(ctx as *const Handler) };
3340            context.on_event(&BinaryView::ref_from_raw(BNNewViewReference(view)));
3341        })
3342    }
3343
3344    let boxed = Box::new(handler);
3345    let raw = Box::into_raw(boxed);
3346
3347    unsafe {
3348        BNRegisterBinaryViewEvent(event_type, Some(on_event::<Handler>), raw as *mut c_void);
3349    }
3350}
3351
3352#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
3353pub struct CommentReference {
3354    pub start: u64,
3355}
3356
3357impl From<u64> for CommentReference {
3358    fn from(start: u64) -> Self {
3359        Self { start }
3360    }
3361}
3362
3363impl CoreArrayProvider for CommentReference {
3364    type Raw = u64;
3365    type Context = ();
3366    type Wrapped<'a> = Self;
3367}
3368
3369unsafe impl CoreArrayProviderInner for CommentReference {
3370    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
3371        BNFreeAddressList(raw)
3372    }
3373
3374    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
3375        Self::from(*raw)
3376    }
3377}
3378
3379#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
3380pub struct StringReference {
3381    pub ty: StringType,
3382    pub start: u64,
3383    pub length: usize,
3384}
3385
3386impl From<BNStringReference> for StringReference {
3387    fn from(raw: BNStringReference) -> Self {
3388        Self {
3389            ty: raw.type_,
3390            start: raw.start,
3391            length: raw.length,
3392        }
3393    }
3394}
3395
3396impl From<StringReference> for BNStringReference {
3397    fn from(raw: StringReference) -> Self {
3398        Self {
3399            type_: raw.ty,
3400            start: raw.start,
3401            length: raw.length,
3402        }
3403    }
3404}
3405
3406impl CoreArrayProvider for StringReference {
3407    type Raw = BNStringReference;
3408    type Context = ();
3409    type Wrapped<'a> = Self;
3410}
3411
3412unsafe impl CoreArrayProviderInner for StringReference {
3413    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
3414        BNFreeStringReferenceList(raw)
3415    }
3416
3417    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
3418        Self::from(*raw)
3419    }
3420}
3421
3422#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
3423pub struct AddressRange {
3424    pub start: u64,
3425    pub end: u64,
3426}
3427
3428impl From<BNAddressRange> for AddressRange {
3429    fn from(raw: BNAddressRange) -> Self {
3430        Self {
3431            start: raw.start,
3432            end: raw.end,
3433        }
3434    }
3435}
3436
3437impl From<AddressRange> for BNAddressRange {
3438    fn from(raw: AddressRange) -> Self {
3439        Self {
3440            start: raw.start,
3441            end: raw.end,
3442        }
3443    }
3444}
3445
3446impl CoreArrayProvider for AddressRange {
3447    type Raw = BNAddressRange;
3448    type Context = ();
3449    type Wrapped<'a> = Self;
3450}
3451
3452unsafe impl CoreArrayProviderInner for AddressRange {
3453    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
3454        BNFreeAddressRanges(raw);
3455    }
3456
3457    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
3458        Self::from(*raw)
3459    }
3460}
3461
3462extern "C" fn cb_valid<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> bool
3463where
3464    T: CustomBinaryViewType,
3465{
3466    let view_type = unsafe { &*(ctxt as *mut T) };
3467    let data = unsafe { BinaryView::ref_from_raw(BNNewViewReference(data)) };
3468    let _span = ffi_span!("CustomBinaryViewType::is_valid_for", data);
3469    view_type.is_valid_for(&data)
3470}
3471
3472extern "C" fn cb_deprecated<T>(_ctxt: *mut c_void) -> bool
3473where
3474    T: CustomBinaryViewType,
3475{
3476    T::DEPRECATED
3477}
3478
3479extern "C" fn cb_force_loadable<T>(_ctxt: *mut c_void) -> bool
3480where
3481    T: CustomBinaryViewType,
3482{
3483    T::FORCE_LOADABLE
3484}
3485
3486extern "C" fn cb_has_no_initial_content<T>(_ctxt: *mut c_void) -> bool
3487where
3488    T: CustomBinaryViewType,
3489{
3490    T::HAS_NO_INITIAL_CONTENT
3491}
3492
3493extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
3494where
3495    T: CustomBinaryViewType,
3496{
3497    ffi_wrap!("CustomBinaryViewType::create", unsafe {
3498        let view_type = &*(ctxt as *mut T);
3499        let data = BinaryView::from_raw(data);
3500        let _span = ffi_span!("CustomBinaryViewType::create", data);
3501        match view_type.create_binary_view(&data) {
3502            Ok(custom_view) => {
3503                match BinaryView::from_custom(T::NAME, &data.file(), &data, custom_view) {
3504                    Ok(custom_view) => Ref::into_raw(custom_view).handle,
3505                    Err(_) => std::ptr::null_mut(),
3506                }
3507            }
3508            Err(_) => std::ptr::null_mut(),
3509        }
3510    })
3511}
3512
3513extern "C" fn cb_parse<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
3514where
3515    T: CustomBinaryViewType,
3516{
3517    ffi_wrap!("CustomBinaryViewType::parse", unsafe {
3518        let view_type = &*(ctxt as *mut T);
3519        let data = BinaryView::from_raw(data);
3520        let _span = ffi_span!("CustomBinaryViewType::parse", data);
3521        match view_type.create_binary_view_for_parse(&data) {
3522            Ok(custom_view) => {
3523                match BinaryView::from_custom(T::NAME, &data.file(), &data, custom_view) {
3524                    Ok(custom_view) => Ref::into_raw(custom_view).handle,
3525                    Err(_) => std::ptr::null_mut(),
3526                }
3527            }
3528            Err(_) => std::ptr::null_mut(),
3529        }
3530    })
3531}
3532
3533extern "C" fn cb_load_settings<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNSettings
3534where
3535    T: CustomBinaryViewType,
3536{
3537    ffi_wrap!("CustomBinaryViewType::load_settings", unsafe {
3538        let view_type = &*(ctxt as *mut T);
3539        let data = BinaryView::from_raw(data);
3540
3541        let _span = ffi_span!("CustomBinaryViewType::load_settings", data);
3542        match view_type.load_settings_for_data(&data) {
3543            Some(load_settings) => Ref::into_raw(load_settings).handle,
3544            None => std::ptr::null_mut(),
3545        }
3546    })
3547}
3548
3549extern "C" fn cb_init<C>(ctxt: *mut c_void) -> bool
3550where
3551    C: CustomBinaryView,
3552{
3553    ffi_wrap!("BinaryViewBase::init", unsafe {
3554        let context = &mut *(ctxt as *mut CustomBinaryViewContext<C>);
3555        // SAFETY: The core view has been initialized by [`BinaryView::from_custom`], so it should be valid.
3556        // SAFETY: The custom view is not being touched by anything else at the point this function is called,
3557        // so it should be safe to mutably borrow it.
3558        context.view.initialize(context.core_view.assume_init_ref())
3559    })
3560}
3561
3562extern "C" fn cb_on_after_snapshot_data_applied<C>(ctxt: *mut c_void)
3563where
3564    C: CustomBinaryView,
3565{
3566    ffi_wrap!("BinaryViewBase::onAfterSnapshotDataApplied", unsafe {
3567        let context = &mut *(ctxt as *mut CustomBinaryViewContext<C>);
3568        // SAFETY: The custom view is not being touched by anything else at the point this function is called,
3569        // so it should be safe to mutably borrow it.
3570        context.view.on_after_snapshot_data_applied();
3571    })
3572}
3573
3574extern "C" fn cb_free_object<C>(ctxt: *mut c_void)
3575where
3576    C: CustomBinaryView,
3577{
3578    ffi_wrap!("BinaryViewBase::freeObject", unsafe {
3579        let context = ctxt as *mut CustomBinaryViewContext<C>;
3580        let _context = Box::from_raw(context);
3581    })
3582}
3583
3584extern "C" fn cb_read<C>(ctxt: *mut c_void, dest: *mut c_void, offset: u64, len: usize) -> usize
3585where
3586    C: CustomBinaryView,
3587{
3588    ffi_wrap!("BinaryViewBase::read", unsafe {
3589        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3590        let dest = std::slice::from_raw_parts_mut(dest as *mut u8, len);
3591        context.view.read(dest, offset)
3592    })
3593}
3594
3595extern "C" fn cb_write<C>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize
3596where
3597    C: CustomBinaryView,
3598{
3599    ffi_wrap!("BinaryViewBase::write", unsafe {
3600        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3601        let src = std::slice::from_raw_parts(src as *const u8, len);
3602        context.view.write(offset, src)
3603    })
3604}
3605
3606extern "C" fn cb_insert<C>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize
3607where
3608    C: CustomBinaryView,
3609{
3610    ffi_wrap!("BinaryViewBase::insert", unsafe {
3611        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3612        let src = std::slice::from_raw_parts(src as *const u8, len);
3613        context.view.insert(offset, src)
3614    })
3615}
3616
3617extern "C" fn cb_remove<C>(ctxt: *mut c_void, offset: u64, len: u64) -> usize
3618where
3619    C: CustomBinaryView,
3620{
3621    ffi_wrap!("BinaryViewBase::remove", unsafe {
3622        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3623        context.view.remove(offset, len as usize)
3624    })
3625}
3626
3627extern "C" fn cb_modification<C>(ctxt: *mut c_void, offset: u64) -> ModificationStatus
3628where
3629    C: CustomBinaryView,
3630{
3631    ffi_wrap!("BinaryViewBase::modification_status", unsafe {
3632        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3633        context.view.modification_status(offset)
3634    })
3635}
3636
3637extern "C" fn cb_offset_valid<C>(ctxt: *mut c_void, offset: u64) -> bool
3638where
3639    C: CustomBinaryView,
3640{
3641    ffi_wrap!("BinaryViewBase::offset_valid", unsafe {
3642        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3643        context.view.offset_valid(offset)
3644    })
3645}
3646
3647extern "C" fn cb_offset_readable<C>(ctxt: *mut c_void, offset: u64) -> bool
3648where
3649    C: CustomBinaryView,
3650{
3651    ffi_wrap!("BinaryViewBase::readable", unsafe {
3652        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3653        context.view.offset_readable(offset)
3654    })
3655}
3656
3657extern "C" fn cb_offset_writable<C>(ctxt: *mut c_void, offset: u64) -> bool
3658where
3659    C: CustomBinaryView,
3660{
3661    ffi_wrap!("BinaryViewBase::writable", unsafe {
3662        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3663        context.view.offset_writable(offset)
3664    })
3665}
3666
3667extern "C" fn cb_offset_executable<C>(ctxt: *mut c_void, offset: u64) -> bool
3668where
3669    C: CustomBinaryView,
3670{
3671    ffi_wrap!("BinaryViewBase::offset_executable", unsafe {
3672        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3673        context.view.offset_executable(offset)
3674    })
3675}
3676
3677extern "C" fn cb_offset_backed_by_file<C>(ctxt: *mut c_void, offset: u64) -> bool
3678where
3679    C: CustomBinaryView,
3680{
3681    ffi_wrap!("BinaryViewBase::offset_backed_by_file", unsafe {
3682        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3683        context.view.offset_backed_by_file(offset)
3684    })
3685}
3686
3687extern "C" fn cb_next_valid_offset<C>(ctxt: *mut c_void, offset: u64) -> u64
3688where
3689    C: CustomBinaryView,
3690{
3691    ffi_wrap!("BinaryViewBase::next_valid_offset_after", unsafe {
3692        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3693        context.view.next_valid_offset_after(offset)
3694    })
3695}
3696
3697extern "C" fn cb_start<C>(ctxt: *mut c_void) -> u64
3698where
3699    C: CustomBinaryView,
3700{
3701    ffi_wrap!("BinaryViewBase::start", unsafe {
3702        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3703        context.view.start()
3704    })
3705}
3706
3707extern "C" fn cb_length<C>(ctxt: *mut c_void) -> u64
3708where
3709    C: CustomBinaryView,
3710{
3711    ffi_wrap!("BinaryViewBase::len", unsafe {
3712        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3713        context.view.len()
3714    })
3715}
3716
3717extern "C" fn cb_entry_point<C>(ctxt: *mut c_void) -> u64
3718where
3719    C: CustomBinaryView,
3720{
3721    ffi_wrap!("BinaryViewBase::entry_point", unsafe {
3722        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3723        context.view.entry_point()
3724    })
3725}
3726
3727extern "C" fn cb_executable<C>(ctxt: *mut c_void) -> bool
3728where
3729    C: CustomBinaryView,
3730{
3731    ffi_wrap!("BinaryViewBase::executable", unsafe {
3732        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3733        context.view.executable()
3734    })
3735}
3736
3737extern "C" fn cb_endianness<C>(ctxt: *mut c_void) -> Endianness
3738where
3739    C: CustomBinaryView,
3740{
3741    ffi_wrap!("BinaryViewBase::default_endianness", unsafe {
3742        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3743        context.view.default_endianness()
3744    })
3745}
3746
3747extern "C" fn cb_relocatable<C>(ctxt: *mut c_void) -> bool
3748where
3749    C: CustomBinaryView,
3750{
3751    ffi_wrap!("BinaryViewBase::relocatable", unsafe {
3752        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3753        context.view.relocatable()
3754    })
3755}
3756
3757extern "C" fn cb_address_size<C>(ctxt: *mut c_void) -> usize
3758where
3759    C: CustomBinaryView,
3760{
3761    ffi_wrap!("BinaryViewBase::address_size", unsafe {
3762        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3763        context.view.address_size()
3764    })
3765}
3766
3767extern "C" fn cb_save<C>(ctxt: *mut c_void, file: *mut BNFileAccessor) -> bool
3768where
3769    C: CustomBinaryView,
3770{
3771    ffi_wrap!("BinaryViewBase::save", unsafe {
3772        let context = &*(ctxt as *mut CustomBinaryViewContext<C>);
3773        let mut file = BorrowedFileAccessor::from_raw(file);
3774        // SAFETY: The core view has been initialized by [`BinaryView::from_custom`], and saving can
3775        // only occur after the custom view has been created.
3776        context
3777            .view
3778            .save(context.core_view.assume_init_ref(), &mut file)
3779    })
3780}