diff options
Diffstat (limited to 'rust/src/binary_view.rs')
| -rw-r--r-- | rust/src/binary_view.rs | 1913 |
1 files changed, 1306 insertions, 607 deletions
diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index b65367a2..8d49e55e 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -13,6 +13,8 @@ // limitations under the License. //! A view on binary data and queryable interface of a binary files analysis. +//! +//! The main analysis object is [`BinaryView`], and custom implementations can be implemented with [`CustomBinaryView`]. use binaryninjacore_sys::*; @@ -57,11 +59,11 @@ use crate::workflow::Workflow; use crate::{Endianness, BN_FULL_CONFIDENCE}; use std::collections::{BTreeMap, HashMap}; use std::ffi::{c_char, c_void, CString}; -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Display, Formatter}; +use std::mem::MaybeUninit; use std::ops::Range; use std::path::{Path, PathBuf}; use std::ptr::NonNull; -use std::{result, slice}; pub mod memory_map; pub mod reader; @@ -72,15 +74,377 @@ pub use memory_map::{MemoryMap, MemoryRegionInfo, ResolvedRange}; pub use reader::BinaryReader; pub use writer::BinaryWriter; -pub type Result<R> = result::Result<R, ()>; pub type BinaryViewEventType = BNBinaryViewEventType; pub type AnalysisState = BNAnalysisState; pub type ModificationStatus = BNModificationStatus; pub type StringType = BNStringType; pub type FindFlag = BNFindFlag; +/// Registers a new binary view type. +pub fn register_binary_view_type<T>(view_type: T) -> (&'static T, BinaryViewType) +where + T: CustomBinaryViewType, +{ + let name = T::NAME.to_cstr(); + let long_name = T::LONG_NAME.to_cstr(); + let leaked_type = Box::leak(Box::new(view_type)); + + let result = unsafe { + BNRegisterBinaryViewType( + name.as_ref().as_ptr() as *const _, + long_name.as_ref().as_ptr() as *const _, + &mut BNCustomBinaryViewType { + context: leaked_type as *mut _ as *mut std::os::raw::c_void, + create: Some(cb_create::<T>), + parse: Some(cb_parse::<T>), + isValidForData: Some(cb_valid::<T>), + isDeprecated: Some(cb_deprecated::<T>), + isForceLoadable: Some(cb_force_loadable::<T>), + getLoadSettingsForData: Some(cb_load_settings::<T>), + hasNoInitialContent: Some(cb_has_no_initial_content::<T>), + }, + ) + }; + + assert!( + !result.is_null(), + "BNRegisterBinaryViewType always returns a non-null handle" + ); + let core_view_type = unsafe { BinaryViewType::from_raw(result) }; + (leaked_type, core_view_type) +} + +/// Interface for creating custom binary views of a given type, analogous to [`BinaryViewType`]. +pub trait CustomBinaryViewType: 'static + Sync { + /// The associated [`BinaryViewBase`] for which this type creates with [`CustomBinaryViewType::create_binary_view`]. + type CustomBinaryView: CustomBinaryView; + + /// The name of the binary view type. + const NAME: &'static str; + + /// The longer name of the binary view type, defaults to [`CustomBinaryViewType::NAME`]. + const LONG_NAME: &'static str = Self::NAME; + + /// Is this [`CustomBinaryViewType`] deprecated and should not be used? + /// + /// We specify this such that the view type may still be used by existing databases, but not + /// newly created views. + const DEPRECATED: bool = false; + + /// Is this [`CustomBinaryViewType`] able to be loaded forcefully? + /// + /// If so, it will be shown in the drop-down when a user opens a file with options. + const FORCE_LOADABLE: bool = false; + + /// Do instances of this [`CustomBinaryViewType`] start with no loaded content? + /// + /// When true, the view has no meaningful default state: the user must make a + /// selection (e.g. load images from a shared cache) before any content exists. + /// + /// Callers can use this to suppress restoring the previously saved view state for + /// files not being loaded from a database, since a saved layout would reference + /// content that isn't available on reopening. + const HAS_NO_INITIAL_CONTENT: bool = false; + + /// Constructs the custom binary view instance. + fn create_binary_view(&self, data: &BinaryView) -> Result<Self::CustomBinaryView, ()>; + + /// Constructs the custom binary view instance to be used for configuration. + /// + /// This is the path that is used when opening a binary with "Open With Options", and is what populates + /// the sections and segments of the dialog along with settings like the image base (start) address. + /// + /// The default implementation for this will construct a new instance identical to that of [`CustomBinaryViewType::create_binary_view`]. + /// + /// Overriding this is encouraged as you can skip actually applying data to the view such as functions, + /// symbols, and other data not required for configuration, especially because this binary view is created + /// only temporarily and will be discarded after configuration is complete. + fn create_binary_view_for_parse( + &self, + data: &BinaryView, + ) -> Result<Self::CustomBinaryView, ()> { + self.create_binary_view(data) + } + + /// Is this [`BinaryViewType`] valid for the given the raw [`BinaryView`]? + /// + /// Typical implementations will read the magic bytes (e.g. 'MZ'), this is a performance-sensitive + /// path so prefer inexpensive checks rather than comprehensive ones. + fn is_valid_for(&self, data: &BinaryView) -> bool; + + fn load_settings_for_data(&self, _data: &BinaryView) -> Ref<Settings> { + Settings::new() + } +} + +/// A [`BinaryViewType`] acts as a factory for [`BinaryView`] objects. +/// +/// Each file format will have its own type, such as PE, ELF, or Mach-O. +/// +/// Custom view types can be implemented using [`CustomBinaryViewType`]. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct BinaryViewType { + pub handle: *mut BNBinaryViewType, +} + +impl BinaryViewType { + pub(crate) unsafe fn from_raw(handle: *mut BNBinaryViewType) -> Self { + debug_assert!(!handle.is_null()); + Self { handle } + } + + pub fn list_all() -> Array<BinaryViewType> { + unsafe { + let mut count: usize = 0; + let types = BNGetBinaryViewTypes(&mut count as *mut _); + Array::new(types, count, ()) + } + } + + /// Enumerates all view types and checks to see if the given raw [`BinaryView`] is valid, + /// returning only those that are. + pub fn valid_types_for_data(data: &BinaryView) -> Array<BinaryViewType> { + unsafe { + let mut count: usize = 0; + let types = BNGetBinaryViewTypesForData(data.handle, &mut count as *mut _); + Array::new(types, count, ()) + } + } + + /// Looks up a binary view type by its name (_not_ the long name). + pub fn by_name(name: &str) -> Option<Self> { + let bytes = name.to_cstr(); + let handle = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; + if handle.is_null() { + None + } else { + Some(unsafe { BinaryViewType::from_raw(handle) }) + } + } + + /// The given name for the binary view type. + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNGetBinaryViewTypeName(self.handle)) } + } + + /// The given long name for the binary view type. + pub fn long_name(&self) -> String { + unsafe { BnString::into_string(BNGetBinaryViewTypeLongName(self.handle)) } + } + + /// Register an architecture for selection via the `id` and `endianness`. + /// + /// If you need to peak at the [`BinaryView`] to determine the architecture, use [`BinaryViewType::register_platform_recognizer`] + /// instead of this. + pub fn register_arch<A: Architecture>(&self, id: u32, endianness: Endianness, arch: &A) { + unsafe { + BNRegisterArchitectureForViewType(self.handle, id, endianness, arch.as_ref().handle); + } + } + + /// Register a platform for selection via the `id`. + /// + /// If you need to peak at the [`BinaryView`] to determine the platform, use [`BinaryViewType::register_platform_recognizer`] + /// instead of this. + pub fn register_platform(&self, id: u32, plat: &Platform) { + let arch = plat.arch(); + unsafe { + BNRegisterPlatformForViewType(self.handle, id, arch.handle, plat.handle); + } + } + + /// Expanded identification of [`Platform`] for [`BinaryViewType`]'s. Supersedes [`BinaryViewType::register_arch`] + /// and [`BinaryViewType::register_platform`], as these have certain edge cases (overloaded elf families, for example) + /// that can't be represented. + /// + /// The callback returns a [`Platform`] object or `None` (failure), and most recently added callbacks are called first + /// to allow plugins to override any default behaviors. When a callback returns a platform, architecture will be + /// derived from the identified platform. + /// + /// The [`BinaryView`] is the *parent* view (usually 'Raw') that the [`BinaryView`] is being created for. This + /// means that generally speaking, the callbacks need to be aware of the underlying file format. However, the + /// [`BinaryView`] implementation may have created data variables in the 'Raw' view by the time the callback is invoked. + /// Behavior regarding when this callback is invoked and what has been made available in the [`BinaryView`] passed as an + /// argument to the callback is up to the discretion of the [`BinaryView`] implementation. + /// + /// The `id` ind `endian` arguments are used as a filter to determine which registered [`Platform`] recognizer callbacks + /// are invoked. + /// + /// Support for this API tentatively requires explicit support in the [`BinaryView`] implementation. + pub fn register_platform_recognizer<R>(&self, id: u32, endian: Endianness, recognizer: R) + where + R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync, + { + #[repr(C)] + struct PlatformRecognizerHandlerContext<R> + where + R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync, + { + recognizer: R, + } + + extern "C" fn cb_recognize_low_level_il<R>( + ctxt: *mut std::os::raw::c_void, + bv: *mut BNBinaryView, + metadata: *mut BNMetadata, + ) -> *mut BNPlatform + where + R: 'static + Fn(&BinaryView, &Metadata) -> Option<Ref<Platform>> + Send + Sync, + { + let context = unsafe { &*(ctxt as *mut PlatformRecognizerHandlerContext<R>) }; + let bv = unsafe { BinaryView::from_raw(bv).to_owned() }; + let metadata = unsafe { Metadata::from_raw(metadata).to_owned() }; + match (context.recognizer)(&bv, &metadata) { + Some(plat) => unsafe { Ref::into_raw(plat).handle }, + None => std::ptr::null_mut(), + } + } + + let recognizer = PlatformRecognizerHandlerContext { recognizer }; + let raw = Box::into_raw(Box::new(recognizer)); + unsafe { + BNRegisterPlatformRecognizerForViewType( + self.handle, + id as u64, + endian, + Some(cb_recognize_low_level_il::<R>), + raw as *mut std::os::raw::c_void, + ) + } + } + + /// Creates a new instance of the binary view for this given type, constructed with `data` as + /// the parent view. + /// + /// This will also call the initialization routine for the view, after calling this you should + /// be able to use the view as normal and ready to start analysis with [`BinaryView::update_analysis`]. + pub fn create(&self, data: &BinaryView) -> Result<Ref<BinaryView>, ()> { + let handle = unsafe { BNCreateBinaryViewOfType(self.handle, data.handle) }; + if handle.is_null() { + // TODO: Proper Result, possibly introduce BNSetError to populate. + return Err(()); + } + unsafe { Ok(BinaryView::ref_from_raw(handle)) } + } + + /// Creates a new instance of the binary view for parsing, this is a "specialize" version of the + /// regular [`BinaryViewType::create`] and is expected to be used when you only want to have the + /// view parsed and populated with information required for configuration, like with open with options. + pub fn parse(&self, data: &BinaryView) -> Result<Ref<BinaryView>, ()> { + let handle = unsafe { BNParseBinaryViewOfType(self.handle, data.handle) }; + if handle.is_null() { + // TODO: Proper Result, possibly introduce BNSetError to populate. + return Err(()); + } + unsafe { Ok(BinaryView::ref_from_raw(handle)) } + } + + /// Is this [`BinaryViewType`] valid for the given the raw [`BinaryView`]? + /// + /// Typical implementations will read the magic bytes (e.g. 'MZ'), this is a performance-sensitive + /// path so prefer inexpensive checks rather than comprehensive ones. + pub fn is_valid_for(&self, data: &BinaryView) -> bool { + unsafe { BNIsBinaryViewTypeValidForData(self.handle, data.handle) } + } + + /// Is this [`BinaryViewType`] deprecated and should not be used? + /// + /// We specify this such that the view type may still be used by existing databases, but not + /// newly created views. + pub fn is_deprecated(&self) -> bool { + unsafe { BNIsBinaryViewTypeDeprecated(self.handle) } + } + + /// Is this [`BinaryViewType`] able to be loaded forcefully? + /// + /// If so, it will be shown in the drop-down when a user opens a file with options. + pub fn is_force_loadable(&self) -> bool { + unsafe { BNIsBinaryViewTypeForceLoadable(self.handle) } + } + + /// Do instances of this [`BinaryViewType`] start with no loaded content? + /// + /// When true, the view has no meaningful default state: the user must make a + /// selection (e.g. load images from a shared cache) before any content exists. + /// + /// Callers can use this to suppress restoring the previously saved view state for + /// files not being loaded from a database, since a saved layout would reference + /// content that isn't available on reopening. + pub fn has_no_initial_content(&self) -> bool { + unsafe { BNBinaryViewTypeHasNoInitialContent(self.handle) } + } + + pub fn load_settings_for_data(&self, data: &BinaryView) -> Option<Ref<Settings>> { + let settings_handle = + unsafe { BNGetBinaryViewLoadSettingsForData(self.handle, data.handle) }; + + if settings_handle.is_null() { + None + } else { + unsafe { Some(Settings::ref_from_raw(settings_handle)) } + } + } +} + +impl Debug for BinaryViewType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BinaryViewType") + .field("name", &self.name()) + .field("long_name", &self.long_name()) + .finish() + } +} + +impl CoreArrayProvider for BinaryViewType { + type Raw = *mut BNBinaryViewType; + type Context = (); + type Wrapped<'a> = Guard<'a, BinaryViewType>; +} + +unsafe impl CoreArrayProviderInner for BinaryViewType { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeBinaryViewTypeList(raw); + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Guard::new(BinaryViewType::from_raw(*raw), &()) + } +} + +unsafe impl Send for BinaryViewType {} +unsafe impl Sync for BinaryViewType {} + +/// Implemented for custom views, responsible for setting up the view state once the binary is open. +pub trait CustomBinaryView: BinaryViewBase { + /// Initializes the opened binary view state. + /// + /// Use this to populate the [`BinaryView`] with sections, segments, and other view data. + /// + /// NOTE: You must add **at least** one segment to the view, otherwise calls to [`BinaryViewType::create`] + /// will fail. + /// + /// NOTE: This will be called on every subsequent open of a database, any view data applied here + /// should be expected to be regenerated on every open. + fn initialize(&mut self, view: &BinaryView) -> bool; + + /// Called after deserialization of the current database snapshot has completed and all the + /// view data inside that snapshot has been applied to the view (like sections and segments). + /// + /// Useful if you need to regenerate temporary data based on the view state. + fn on_after_snapshot_data_applied(&mut self) {} +} + +/// Wrapper around `C` when being passed to the custom view constructor so that we have the core +/// view available to [`CustomBinaryView::initialize`], called from [`cb_init`]. +struct CustomBinaryViewContext<C: CustomBinaryView> { + // This is not ref-counted because we do not want to impact the lifetime of the core view, the lifetime + // of which is already bound to the lifetime of the custom view (to be freed when the custom view is freed). + core_view: MaybeUninit<BinaryView>, + view: C, +} + #[allow(clippy::len_without_is_empty)] -pub trait BinaryViewBase: AsRef<BinaryView> { +pub trait BinaryViewBase { fn read(&self, _buf: &mut [u8], _offset: u64) -> usize { 0 } @@ -100,10 +464,7 @@ pub trait BinaryViewBase: AsRef<BinaryView> { /// Check if the offset is valid for the current view. fn offset_valid(&self, offset: u64) -> bool { let mut buf = [0u8; 1]; - - // don't use self.read so that if segments were used we - // check against those as well - self.as_ref().read(&mut buf[..], offset) == buf.len() + self.read(&mut buf[..], offset) == buf.len() } /// Check if the offset is readable for the current view. @@ -129,8 +490,7 @@ pub trait BinaryViewBase: AsRef<BinaryView> { /// Get the next valid offset after the provided `offset`, useful if you need to iterate over all /// readable offsets in the view. fn next_valid_offset_after(&self, offset: u64) -> u64 { - let start = self.as_ref().start(); - + let start = self.start(); if offset < start { start } else { @@ -158,18 +518,20 @@ pub trait BinaryViewBase: AsRef<BinaryView> { } fn relocatable(&self) -> bool { - true + false + } + + fn entry_point(&self) -> u64 { + 0 } - fn entry_point(&self) -> u64; fn default_endianness(&self) -> Endianness; + fn address_size(&self) -> usize; + // TODO: Needs to take file accessor? fn save(&self) -> bool { - self.as_ref() - .parent_view() - .map(|view| view.save()) - .unwrap_or(false) + false } } @@ -241,33 +603,214 @@ impl From<BNAnalysisProgress> for AnalysisProgress { } } -pub trait BinaryViewExt: BinaryViewBase { - fn file(&self) -> Ref<FileMetadata> { +/// Represents the "whole view" of the binary and its analysis. +/// +/// Analysis information: +/// +/// - [`BinaryView::functions`] +/// - [`BinaryView::data_variables`] +/// - [`BinaryView::strings`] +/// +/// Annotation information: +/// +/// - [`BinaryView::symbols`] +/// - [`BinaryView::tags_all_scopes`] +/// - [`BinaryView::comments`] +/// +/// Data representation and binary information: +/// +/// - [`BinaryView::types`] +/// - [`BinaryView::segments`] +/// - [`BinaryView::sections`] +/// +/// # Cleaning up +/// +/// [`BinaryView`] has a cyclic relationship with the associated [`FileMetadata`], each holds a strong +/// reference to one another, so to properly clean up/free the [`BinaryView`], you must manually close the +/// file using [`FileMetadata::close`], this is not fixable in the general case, until [`FileMetadata`] +/// has only a weak reference to the [`BinaryView`]. +#[derive(PartialEq, Eq, Hash)] +pub struct BinaryView { + pub handle: *mut BNBinaryView, +} + +impl BinaryView { + pub unsafe fn from_raw(handle: *mut BNBinaryView) -> Self { + debug_assert!(!handle.is_null()); + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: *mut BNBinaryView) -> Ref<Self> { + debug_assert!(!handle.is_null()); + Ref::new(Self { handle }) + } + + /// Create a core instance of the [`CustomBinaryView`]. + pub fn from_custom<C: CustomBinaryView>( + view_type_name: &str, + file: &FileMetadata, + parent_view: &BinaryView, + view: C, + ) -> Result<Ref<Self>, ()> { + let type_name = view_type_name.to_cstr(); + // We need to pass the core BinaryView when initializing the custom view state with [`CustomBinaryView::initialize`], + // and to do that we need to store the returned core view handle after creating the custom view. + let custom_context = CustomBinaryViewContext { + core_view: MaybeUninit::uninit(), + view, + }; + // We leak to be freed in `cb_free_object`. + let leaked_view = Box::leak(Box::new(custom_context)); + let handle = unsafe { + BNCreateCustomBinaryView( + type_name.as_ptr(), + file.handle, + parent_view.handle, + &mut BNCustomBinaryView { + context: leaked_view as *mut CustomBinaryViewContext<C> as *mut _, + init: Some(cb_init::<C>), + freeObject: Some(cb_free_object::<C>), + externalRefTaken: None, + externalRefReleased: None, + read: Some(cb_read::<C>), + write: Some(cb_write::<C>), + insert: Some(cb_insert::<C>), + remove: Some(cb_remove::<C>), + getModification: Some(cb_modification::<C>), + isValidOffset: Some(cb_offset_valid::<C>), + isOffsetReadable: Some(cb_offset_readable::<C>), + isOffsetWritable: Some(cb_offset_writable::<C>), + isOffsetExecutable: Some(cb_offset_executable::<C>), + isOffsetBackedByFile: Some(cb_offset_backed_by_file::<C>), + getNextValidOffset: Some(cb_next_valid_offset::<C>), + getStart: Some(cb_start::<C>), + getLength: Some(cb_length::<C>), + getEntryPoint: Some(cb_entry_point::<C>), + isExecutable: Some(cb_executable::<C>), + getDefaultEndianness: Some(cb_endianness::<C>), + isRelocatable: Some(cb_relocatable::<C>), + getAddressSize: Some(cb_address_size::<C>), + save: Some(cb_save::<C>), + onAfterSnapshotDataApplied: Some(cb_on_after_snapshot_data_applied::<C>), + }, + ) + }; + if handle.is_null() { + // We need to free the custom context manually. + let _ = unsafe { Box::from_raw(leaked_view) }; + return Err(()); + } + leaked_view.core_view = unsafe { MaybeUninit::new(BinaryView::from_raw(handle)) }; + unsafe { Ok(Ref::new(Self { handle })) } + } + + /// Construct the raw binary view from the given metadata. + /// + /// Before calling this, make sure you have a valid file path set for the [`FileMetadata`]. It is + /// required that the [`FileMetadata::file_path`] exist in the local filesystem. + pub fn from_metadata(meta: &FileMetadata) -> Result<Ref<Self>, ()> { + if !meta.file_path().exists() { + return Err(()); + } + let file = meta.file_path().to_cstr(); + let handle = + unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) }; + if handle.is_null() { + return Err(()); + } + unsafe { Ok(Ref::new(Self { handle })) } + } + + /// Construct the raw binary view from the given `file_path` and metadata. + /// + /// This will implicitly set the metadata file path and then construct the view. If the metadata + /// already has the desired file path, use [`BinaryView::from_metadata`] instead. + pub fn from_path(meta: &FileMetadata, file_path: impl AsRef<Path>) -> Result<Ref<Self>, ()> { + meta.set_file_path(file_path.as_ref()); + Self::from_metadata(meta) + } + + // TODO: Provide an API that manages the lifetime of the accessor and the view. + /// Construct the raw binary view from the given `accessor` and metadata. + /// + /// It is the responsibility of the caller to keep the accessor alive for the lifetime of the view; + /// because of this, we mark the function as unsafe. + pub unsafe fn from_accessor<A: Accessor>( + meta: &FileMetadata, + accessor: &mut FileAccessor<A>, + ) -> Result<Ref<Self>, ()> { + let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut accessor.raw) }; + if handle.is_null() { + return Err(()); + } + unsafe { Ok(Ref::new(Self { handle })) } + } + + /// Construct the raw binary view from the given `data` and metadata. + /// + /// The data will be copied into the view, so the caller does not need to keep the data alive. + pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Ref<Self> { + let handle = unsafe { + BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len()) + }; + assert!( + !handle.is_null(), + "BNCreateBinaryDataViewFromData should always succeed" + ); + unsafe { Ref::new(Self { handle }) } + } + + /// Save the original binary file to the provided `file_path` along with any modifications. + /// + /// WARNING: Currently, there is a possibility to deadlock if the analysis has queued up a main thread action + /// that tries to take the [`FileMetadata`] lock of the current view and is executed while we + /// are executing in this function. + /// + /// To avoid the above issue, use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there + /// are no queued up main thread actions. + pub fn save_to_path(&self, file_path: impl AsRef<Path>) -> bool { + let file = file_path.as_ref().to_cstr(); + unsafe { BNSaveToFilename(self.handle, file.as_ptr() as *mut _) } + } + + /// Save the original binary file to the provided [`FileAccessor`] along with any modifications. + /// + /// WARNING: Currently, there is a possibility to deadlock if the analysis has queued up a main thread action + /// that tries to take the [`FileMetadata`] lock of the current view and is executed while we + /// are executing in this function. + /// + /// To avoid the above issue, use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there + /// are no queued up main thread actions. + pub fn save_to_accessor<A: Accessor>(&self, file: &mut FileAccessor<A>) -> bool { + unsafe { BNSaveToFile(self.handle, &mut file.raw) } + } + + pub fn file(&self) -> Ref<FileMetadata> { unsafe { - let raw = BNGetFileForView(self.as_ref().handle); + let raw = BNGetFileForView(self.handle); FileMetadata::ref_from_raw(raw) } } - fn parent_view(&self) -> Option<Ref<BinaryView>> { - let raw_view_ptr = unsafe { BNGetParentView(self.as_ref().handle) }; + pub fn parent_view(&self) -> Option<Ref<BinaryView>> { + let raw_view_ptr = unsafe { BNGetParentView(self.handle) }; match raw_view_ptr.is_null() { false => Some(unsafe { BinaryView::ref_from_raw(raw_view_ptr) }), true => None, } } - fn raw_view(&self) -> Option<Ref<BinaryView>> { + pub fn raw_view(&self) -> Option<Ref<BinaryView>> { self.file().view_of_type("Raw") } - fn view_type(&self) -> String { - let ptr: *mut c_char = unsafe { BNGetViewType(self.as_ref().handle) }; + pub fn view_type(&self) -> String { + let ptr: *mut c_char = unsafe { BNGetViewType(self.handle) }; unsafe { BnString::into_string(ptr) } } /// Reads up to `len` bytes from address `offset` - fn read_vec(&self, offset: u64, len: usize) -> Vec<u8> { + pub fn read_vec(&self, offset: u64, len: usize) -> Vec<u8> { let mut ret = vec![0; len]; let size = self.read(&mut ret, offset); ret.truncate(size); @@ -275,7 +818,7 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Appends up to `len` bytes from address `offset` into `dest` - fn read_into_vec(&self, dest: &mut Vec<u8>, offset: u64, len: usize) -> usize { + pub fn read_into_vec(&self, dest: &mut Vec<u8>, offset: u64, len: usize) -> usize { let starting_len = dest.len(); dest.resize(starting_len + len, 0); let read_size = self.read(&mut dest[starting_len..], offset); @@ -284,7 +827,7 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Reads up to `len` bytes from the address `offset` returning a `CString` if available. - fn read_c_string_at(&self, offset: u64, len: usize) -> Option<CString> { + pub fn read_c_string_at(&self, offset: u64, len: usize) -> Option<CString> { let mut buf = vec![0; len]; let size = self.read(&mut buf, offset); let string = CString::new(buf[..size].to_vec()).ok()?; @@ -292,7 +835,7 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Reads up to `len` bytes from the address `offset` returning a `String` if available. - fn read_utf8_string_at(&self, offset: u64, len: usize) -> Option<String> { + pub fn read_utf8_string_at(&self, offset: u64, len: usize) -> Option<String> { let mut buf = vec![0; len]; let size = self.read(&mut buf, offset); let string = String::from_utf8(buf[..size].to_vec()).ok()?; @@ -302,14 +845,18 @@ pub trait BinaryViewExt: BinaryViewBase { /// Search the view using the query options. /// /// In the `on_match` callback return `false` to stop searching. - fn search<C: FnMut(u64, &DataBuffer) -> bool>(&self, query: &SearchQuery, on_match: C) -> bool { + pub fn search<C: FnMut(u64, &DataBuffer) -> bool>( + &self, + query: &SearchQuery, + on_match: C, + ) -> bool { self.search_with_progress(query, on_match, NoProgressCallback) } /// Search the view using the query options. /// /// In the `on_match` callback return `false` to stop searching. - fn search_with_progress<P: ProgressCallback, C: FnMut(u64, &DataBuffer) -> bool>( + pub fn search_with_progress<P: ProgressCallback, C: FnMut(u64, &DataBuffer) -> bool>( &self, query: &SearchQuery, mut on_match: C, @@ -328,7 +875,7 @@ pub trait BinaryViewExt: BinaryViewBase { let query = query.to_json().to_cstr(); unsafe { BNSearch( - self.as_ref().handle, + self.handle, query.as_ptr(), &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), @@ -338,7 +885,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn find_next_data(&self, start: u64, end: u64, data: &DataBuffer) -> Option<u64> { + pub fn find_next_data(&self, start: u64, end: u64, data: &DataBuffer) -> Option<u64> { self.find_next_data_with_opts( start, end, @@ -351,7 +898,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Warning /// /// This function is likely to be changed to take in a "query" structure. Or deprecated entirely. - fn find_next_data_with_opts<P: ProgressCallback>( + pub fn find_next_data_with_opts<P: ProgressCallback>( &self, start: u64, end: u64, @@ -362,7 +909,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut result: u64 = 0; let found = unsafe { BNFindNextDataWithProgress( - self.as_ref().handle, + self.handle, start, end, data.as_raw(), @@ -380,7 +927,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn find_next_constant( + pub fn find_next_constant( &self, start: u64, end: u64, @@ -402,7 +949,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Warning /// /// This function is likely to be changed to take in a "query" structure. - fn find_next_constant_with_opts<P: ProgressCallback>( + pub fn find_next_constant_with_opts<P: ProgressCallback>( &self, start: u64, end: u64, @@ -415,7 +962,7 @@ pub trait BinaryViewExt: BinaryViewBase { let raw_view_type = FunctionViewType::into_raw(view_type); let found = unsafe { BNFindNextConstantWithProgress( - self.as_ref().handle, + self.handle, start, end, constant, @@ -435,7 +982,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn find_next_text( + pub fn find_next_text( &self, start: u64, end: u64, @@ -458,7 +1005,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Warning /// /// This function is likely to be changed to take in a "query" structure. - fn find_next_text_with_opts<P: ProgressCallback>( + pub fn find_next_text_with_opts<P: ProgressCallback>( &self, start: u64, end: u64, @@ -473,7 +1020,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut result: u64 = 0; let found = unsafe { BNFindNextTextWithProgress( - self.as_ref().handle, + self.handle, start, end, text.as_ptr(), @@ -494,75 +1041,75 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn notify_data_written(&self, offset: u64, len: usize) { + pub fn notify_data_written(&self, offset: u64, len: usize) { unsafe { - BNNotifyDataWritten(self.as_ref().handle, offset, len); + BNNotifyDataWritten(self.handle, offset, len); } } - fn notify_data_inserted(&self, offset: u64, len: usize) { + pub fn notify_data_inserted(&self, offset: u64, len: usize) { unsafe { - BNNotifyDataInserted(self.as_ref().handle, offset, len); + BNNotifyDataInserted(self.handle, offset, len); } } - fn notify_data_removed(&self, offset: u64, len: usize) { + pub fn notify_data_removed(&self, offset: u64, len: usize) { unsafe { - BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64); + BNNotifyDataRemoved(self.handle, offset, len as u64); } } /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the /// offset has code semantics. - fn offset_has_code_semantics(&self, offset: u64) -> bool { - unsafe { BNIsOffsetCodeSemantics(self.as_ref().handle, offset) } + pub fn offset_has_code_semantics(&self, offset: u64) -> bool { + unsafe { BNIsOffsetCodeSemantics(self.handle, offset) } } /// Check if the offset is within a [`Section`] with [`crate::section::Semantics::External`]. - fn offset_has_extern_semantics(&self, offset: u64) -> bool { - unsafe { BNIsOffsetExternSemantics(self.as_ref().handle, offset) } + pub fn offset_has_extern_semantics(&self, offset: u64) -> bool { + unsafe { BNIsOffsetExternSemantics(self.handle, offset) } } /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the /// offset has writable semantics. - fn offset_has_writable_semantics(&self, offset: u64) -> bool { - unsafe { BNIsOffsetWritableSemantics(self.as_ref().handle, offset) } + pub fn offset_has_writable_semantics(&self, offset: u64) -> bool { + unsafe { BNIsOffsetWritableSemantics(self.handle, offset) } } /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the /// offset has read only semantics. - fn offset_has_read_only_semantics(&self, offset: u64) -> bool { - unsafe { BNIsOffsetReadOnlySemantics(self.as_ref().handle, offset) } + pub fn offset_has_read_only_semantics(&self, offset: u64) -> bool { + unsafe { BNIsOffsetReadOnlySemantics(self.handle, offset) } } - fn image_base(&self) -> u64 { - unsafe { BNGetImageBase(self.as_ref().handle) } + pub fn image_base(&self) -> u64 { + unsafe { BNGetImageBase(self.handle) } } - fn original_image_base(&self) -> u64 { - unsafe { BNGetOriginalImageBase(self.as_ref().handle) } + pub fn original_image_base(&self) -> u64 { + unsafe { BNGetOriginalImageBase(self.handle) } } - fn set_original_image_base(&self, image_base: u64) { - unsafe { BNSetOriginalImageBase(self.as_ref().handle, image_base) } + pub fn set_original_image_base(&self, image_base: u64) { + unsafe { BNSetOriginalImageBase(self.handle, image_base) } } /// The highest address in the view. - fn end(&self) -> u64 { - unsafe { BNGetEndOffset(self.as_ref().handle) } + pub fn end(&self) -> u64 { + unsafe { BNGetEndOffset(self.handle) } } - fn add_analysis_option(&self, name: &str) { + pub fn add_analysis_option(&self, name: &str) { let name = name.to_cstr(); - unsafe { BNAddAnalysisOption(self.as_ref().handle, name.as_ptr()) } + unsafe { BNAddAnalysisOption(self.handle, name.as_ptr()) } } - fn has_initial_analysis(&self) -> bool { - unsafe { BNHasInitialAnalysis(self.as_ref().handle) } + pub fn has_initial_analysis(&self) -> bool { + unsafe { BNHasInitialAnalysis(self.handle) } } - fn set_analysis_hold(&self, enable: bool) { - unsafe { BNSetAnalysisHold(self.as_ref().handle, enable) } + pub fn set_analysis_hold(&self, enable: bool) { + unsafe { BNSetAnalysisHold(self.handle, enable) } } /// Runs the analysis pipeline, analyzing any data that has been marked for updates. @@ -571,11 +1118,11 @@ pub trait BinaryViewExt: BinaryViewBase { /// - [`Function::mark_updates_required`] /// - [`Function::mark_caller_updates_required`] /// - /// NOTE: This is a **non-blocking** call, use [`BinaryViewExt::update_analysis_and_wait`] if you + /// NOTE: This is a **non-blocking** call, use [`BinaryView::update_analysis_and_wait`] if you /// require analysis to have completed before moving on. - fn update_analysis(&self) { + pub fn update_analysis(&self) { unsafe { - BNUpdateAnalysis(self.as_ref().handle); + BNUpdateAnalysis(self.handle); } } @@ -585,47 +1132,47 @@ pub trait BinaryViewExt: BinaryViewBase { /// - [`Function::mark_updates_required`] /// - [`Function::mark_caller_updates_required`] /// - /// NOTE: This is a **blocking** call, use [`BinaryViewExt::update_analysis`] if you do not + /// NOTE: This is a **blocking** call, use [`BinaryView::update_analysis`] if you do not /// need to wait for the analysis update to finish. - fn update_analysis_and_wait(&self) { + pub fn update_analysis_and_wait(&self) { unsafe { - BNUpdateAnalysisAndWait(self.as_ref().handle); + BNUpdateAnalysisAndWait(self.handle); } } /// Causes **all** functions to be reanalyzed. /// - /// Use [`BinaryViewExt::update_analysis`] or [`BinaryViewExt::update_analysis_and_wait`] instead + /// Use [`BinaryView::update_analysis`] or [`BinaryView::update_analysis_and_wait`] instead /// if you want to incrementally update analysis. /// /// NOTE: This function does not wait for the analysis to finish. - fn reanalyze(&self) { + pub fn reanalyze(&self) { unsafe { - BNReanalyzeAllFunctions(self.as_ref().handle); + BNReanalyzeAllFunctions(self.handle); } } - fn abort_analysis(&self) { - unsafe { BNAbortAnalysis(self.as_ref().handle) } + pub fn abort_analysis(&self) { + unsafe { BNAbortAnalysis(self.handle) } } - fn analysis_is_aborted(&self) -> bool { - unsafe { BNAnalysisIsAborted(self.as_ref().handle) } + pub fn analysis_is_aborted(&self) -> bool { + unsafe { BNAnalysisIsAborted(self.handle) } } - fn workflow(&self) -> Ref<Workflow> { + pub fn workflow(&self) -> Ref<Workflow> { unsafe { - let raw_ptr = BNGetWorkflowForBinaryView(self.as_ref().handle); + let raw_ptr = BNGetWorkflowForBinaryView(self.handle); let nonnull = NonNull::new(raw_ptr).expect("All views must have a workflow"); Workflow::ref_from_raw(nonnull) } } - fn analysis_info(&self) -> AnalysisInfo { - let info_ptr = unsafe { BNGetAnalysisInfo(self.as_ref().handle) }; + pub fn analysis_info(&self) -> AnalysisInfo { + let info_ptr = unsafe { BNGetAnalysisInfo(self.handle) }; assert!(!info_ptr.is_null()); let info = unsafe { *info_ptr }; - let active_infos = unsafe { slice::from_raw_parts(info.activeInfo, info.count) }; + let active_infos = unsafe { std::slice::from_raw_parts(info.activeInfo, info.count) }; let mut active_info_list = vec![]; for active_info in active_infos { @@ -648,14 +1195,14 @@ pub trait BinaryViewExt: BinaryViewBase { result } - fn analysis_progress(&self) -> AnalysisProgress { - let progress_raw = unsafe { BNGetAnalysisProgress(self.as_ref().handle) }; + pub fn analysis_progress(&self) -> AnalysisProgress { + let progress_raw = unsafe { BNGetAnalysisProgress(self.handle) }; AnalysisProgress::from(progress_raw) } - fn default_arch(&self) -> Option<CoreArchitecture> { + pub fn default_arch(&self) -> Option<CoreArchitecture> { unsafe { - let raw = BNGetDefaultArchitecture(self.as_ref().handle); + let raw = BNGetDefaultArchitecture(self.handle); if raw.is_null() { return None; @@ -665,15 +1212,15 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn set_default_arch<A: Architecture>(&self, arch: &A) { + pub fn set_default_arch<A: Architecture>(&self, arch: &A) { unsafe { - BNSetDefaultArchitecture(self.as_ref().handle, arch.as_ref().handle); + BNSetDefaultArchitecture(self.handle, arch.as_ref().handle); } } - fn default_platform(&self) -> Option<Ref<Platform>> { + pub fn default_platform(&self) -> Option<Ref<Platform>> { unsafe { - let raw = BNGetDefaultPlatform(self.as_ref().handle); + let raw = BNGetDefaultPlatform(self.handle); if raw.is_null() { return None; @@ -683,22 +1230,22 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn set_default_platform(&self, plat: &Platform) { + pub fn set_default_platform(&self, plat: &Platform) { unsafe { - BNSetDefaultPlatform(self.as_ref().handle, plat.handle); + BNSetDefaultPlatform(self.handle, plat.handle); } } - fn base_address_detection(&self) -> Option<BaseAddressDetection> { + pub fn base_address_detection(&self) -> Option<BaseAddressDetection> { unsafe { - let handle = BNCreateBaseAddressDetection(self.as_ref().handle); + let handle = BNCreateBaseAddressDetection(self.handle); NonNull::new(handle).map(|base| BaseAddressDetection::from_raw(base)) } } - fn instruction_len<A: Architecture>(&self, arch: &A, addr: u64) -> Option<usize> { + pub fn instruction_len<A: Architecture>(&self, arch: &A, addr: u64) -> Option<usize> { unsafe { - let size = BNGetInstructionLength(self.as_ref().handle, arch.as_ref().handle, addr); + let size = BNGetInstructionLength(self.handle, arch.as_ref().handle, addr); if size > 0 { Some(size) @@ -708,10 +1255,9 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbol_by_address(&self, addr: u64) -> Option<Ref<Symbol>> { + pub fn symbol_by_address(&self, addr: u64) -> Option<Ref<Symbol>> { unsafe { - let raw_sym_ptr = - BNGetSymbolByAddress(self.as_ref().handle, addr, std::ptr::null_mut()); + let raw_sym_ptr = BNGetSymbolByAddress(self.handle, addr, std::ptr::null_mut()); match raw_sym_ptr.is_null() { false => Some(Symbol::ref_from_raw(raw_sym_ptr)), true => None, @@ -719,15 +1265,12 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbol_by_raw_name(&self, raw_name: impl IntoCStr) -> Option<Ref<Symbol>> { + pub fn symbol_by_raw_name(&self, raw_name: impl IntoCStr) -> Option<Ref<Symbol>> { let raw_name = raw_name.to_cstr(); unsafe { - let raw_sym_ptr = BNGetSymbolByRawName( - self.as_ref().handle, - raw_name.as_ptr(), - std::ptr::null_mut(), - ); + let raw_sym_ptr = + BNGetSymbolByRawName(self.handle, raw_name.as_ptr(), std::ptr::null_mut()); match raw_sym_ptr.is_null() { false => Some(Symbol::ref_from_raw(raw_sym_ptr)), true => None, @@ -735,22 +1278,22 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbols(&self) -> Array<Symbol> { + pub fn symbols(&self) -> Array<Symbol> { unsafe { let mut count = 0; - let handles = BNGetSymbols(self.as_ref().handle, &mut count, std::ptr::null_mut()); + let handles = BNGetSymbols(self.handle, &mut count, std::ptr::null_mut()); Array::new(handles, count, ()) } } - fn symbols_by_name(&self, name: impl IntoCStr) -> Array<Symbol> { + pub fn symbols_by_name(&self, name: impl IntoCStr) -> Array<Symbol> { let raw_name = name.to_cstr(); unsafe { let mut count = 0; let handles = BNGetSymbolsByName( - self.as_ref().handle, + self.handle, raw_name.as_ptr(), &mut count, std::ptr::null_mut(), @@ -760,12 +1303,12 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbols_in_range(&self, range: Range<u64>) -> Array<Symbol> { + pub fn symbols_in_range(&self, range: Range<u64>) -> Array<Symbol> { unsafe { let mut count = 0; let len = range.end.wrapping_sub(range.start); let handles = BNGetSymbolsInRange( - self.as_ref().handle, + self.handle, range.start, len, &mut count, @@ -776,26 +1319,22 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbols_of_type(&self, ty: SymbolType) -> Array<Symbol> { + pub fn symbols_of_type(&self, ty: SymbolType) -> Array<Symbol> { unsafe { let mut count = 0; - let handles = BNGetSymbolsOfType( - self.as_ref().handle, - ty.into(), - &mut count, - std::ptr::null_mut(), - ); + let handles = + BNGetSymbolsOfType(self.handle, ty.into(), &mut count, std::ptr::null_mut()); Array::new(handles, count, ()) } } - fn symbols_of_type_in_range(&self, ty: SymbolType, range: Range<u64>) -> Array<Symbol> { + pub fn symbols_of_type_in_range(&self, ty: SymbolType, range: Range<u64>) -> Array<Symbol> { unsafe { let mut count = 0; let len = range.end.wrapping_sub(range.start); let handles = BNGetSymbolsOfTypeInRange( - self.as_ref().handle, + self.handle, ty.into(), range.start, len, @@ -807,18 +1346,21 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn define_auto_symbol(&self, sym: &Symbol) { + pub fn define_auto_symbol(&self, sym: &Symbol) { unsafe { - BNDefineAutoSymbol(self.as_ref().handle, sym.handle); + BNDefineAutoSymbol(self.handle, sym.handle); } } - fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>( + /// Defines the symbol as well as the analysis object associated with the given symbol type, such as + /// the data variable for a [`SymbolType::Data`], or the function for a [`SymbolType::Function`]. + /// Returns the symbol, as it was applied to the binary view. + pub fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>( &self, sym: &Symbol, plat: &Platform, ty: T, - ) -> Result<Ref<Symbol>> { + ) -> Ref<Symbol> { let mut type_with_conf = BNTypeWithConfidence { type_: if let Some(t) = ty.into() { t.handle @@ -830,50 +1372,50 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { let raw_sym = BNDefineAutoSymbolAndVariableOrFunction( - self.as_ref().handle, + self.handle, plat.handle, sym.handle, &mut type_with_conf, ); - - if raw_sym.is_null() { - return Err(()); - } - - Ok(Symbol::ref_from_raw(raw_sym)) + // We should always get the symbol back as it is defined. + debug_assert!( + !raw_sym.is_null(), + "BNDefineAutoSymbolAndVariableOrFunction should not return null" + ); + Symbol::ref_from_raw(raw_sym) } } - fn undefine_auto_symbol(&self, sym: &Symbol) { + pub fn undefine_auto_symbol(&self, sym: &Symbol) { unsafe { - BNUndefineAutoSymbol(self.as_ref().handle, sym.handle); + BNUndefineAutoSymbol(self.handle, sym.handle); } } - fn define_user_symbol(&self, sym: &Symbol) { + pub fn define_user_symbol(&self, sym: &Symbol) { unsafe { - BNDefineUserSymbol(self.as_ref().handle, sym.handle); + BNDefineUserSymbol(self.handle, sym.handle); } } - fn undefine_user_symbol(&self, sym: &Symbol) { + pub fn undefine_user_symbol(&self, sym: &Symbol) { unsafe { - BNUndefineUserSymbol(self.as_ref().handle, sym.handle); + BNUndefineUserSymbol(self.handle, sym.handle); } } - fn data_variables(&self) -> Array<DataVariable> { + pub fn data_variables(&self) -> Array<DataVariable> { unsafe { let mut count = 0; - let vars = BNGetDataVariables(self.as_ref().handle, &mut count); + let vars = BNGetDataVariables(self.handle, &mut count); Array::new(vars, count, ()) } } - fn data_variable_at_address(&self, addr: u64) -> Option<DataVariable> { + pub fn data_variable_at_address(&self, addr: u64) -> Option<DataVariable> { let mut dv = BNDataVariable::default(); unsafe { - if BNGetDataVariableAtAddress(self.as_ref().handle, addr, &mut dv) { + if BNGetDataVariableAtAddress(self.handle, addr, &mut dv) { Some(DataVariable::from_owned_raw(dv)) } else { None @@ -881,34 +1423,34 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn define_auto_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) { + pub fn define_auto_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) { let mut owned_raw_ty = Conf::<&Type>::into_raw(ty.into()); unsafe { - BNDefineDataVariable(self.as_ref().handle, addr, &mut owned_raw_ty); + BNDefineDataVariable(self.handle, addr, &mut owned_raw_ty); } } - /// You likely would also like to call [`BinaryViewExt::define_user_symbol`] to bind this data variable with a name - fn define_user_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) { + /// You likely would also like to call [`BinaryView::define_user_symbol`] to bind this data variable with a name + pub fn define_user_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) { let mut owned_raw_ty = Conf::<&Type>::into_raw(ty.into()); unsafe { - BNDefineUserDataVariable(self.as_ref().handle, addr, &mut owned_raw_ty); + BNDefineUserDataVariable(self.handle, addr, &mut owned_raw_ty); } } - fn undefine_auto_data_var(&self, addr: u64, blacklist: Option<bool>) { + pub fn undefine_auto_data_var(&self, addr: u64, blacklist: Option<bool>) { unsafe { - BNUndefineDataVariable(self.as_ref().handle, addr, blacklist.unwrap_or(true)); + BNUndefineDataVariable(self.handle, addr, blacklist.unwrap_or(true)); } } - fn undefine_user_data_var(&self, addr: u64) { + pub fn undefine_user_data_var(&self, addr: u64) { unsafe { - BNUndefineUserDataVariable(self.as_ref().handle, addr); + BNUndefineUserDataVariable(self.handle, addr); } } - fn define_auto_type<T: Into<QualifiedName>>( + pub fn define_auto_type<T: Into<QualifiedName>>( &self, name: T, source: &str, @@ -919,13 +1461,13 @@ pub trait BinaryViewExt: BinaryViewBase { let name_handle = unsafe { let id_str = BNGenerateAutoTypeId(source_str.as_ref().as_ptr() as *const _, &mut raw_name); - BNDefineAnalysisType(self.as_ref().handle, id_str, &mut raw_name, type_obj.handle) + BNDefineAnalysisType(self.handle, id_str, &mut raw_name, type_obj.handle) }; QualifiedName::free_raw(raw_name); QualifiedName::from_owned_raw(name_handle) } - fn define_auto_type_with_id<T: Into<QualifiedName>>( + pub fn define_auto_type_with_id<T: Into<QualifiedName>>( &self, name: T, id: &str, @@ -935,7 +1477,7 @@ pub trait BinaryViewExt: BinaryViewBase { let id_str = id.to_cstr(); let result_raw_name = unsafe { BNDefineAnalysisType( - self.as_ref().handle, + self.handle, id_str.as_ref().as_ptr() as *const _, &mut raw_name, type_obj.handle, @@ -945,13 +1487,16 @@ pub trait BinaryViewExt: BinaryViewBase { QualifiedName::from_owned_raw(result_raw_name) } - fn define_user_type<T: Into<QualifiedName>>(&self, name: T, type_obj: &Type) { + pub fn define_user_type<T: Into<QualifiedName>>(&self, name: T, type_obj: &Type) { let mut raw_name = QualifiedName::into_raw(name.into()); - unsafe { BNDefineUserAnalysisType(self.as_ref().handle, &mut raw_name, type_obj.handle) } + unsafe { BNDefineUserAnalysisType(self.handle, &mut raw_name, type_obj.handle) } QualifiedName::free_raw(raw_name); } - fn define_auto_types<T, I>(&self, names_sources_and_types: T) -> HashMap<String, QualifiedName> + pub fn define_auto_types<T, I>( + &self, + names_sources_and_types: T, + ) -> HashMap<String, QualifiedName> where T: Iterator<Item = I>, I: Into<QualifiedNameTypeAndId>, @@ -959,7 +1504,7 @@ pub trait BinaryViewExt: BinaryViewBase { self.define_auto_types_with_progress(names_sources_and_types, NoProgressCallback) } - fn define_auto_types_with_progress<T, I, P>( + pub fn define_auto_types_with_progress<T, I, P>( &self, names_sources_and_types: T, mut progress: P, @@ -978,7 +1523,7 @@ pub trait BinaryViewExt: BinaryViewBase { let result_count = unsafe { BNDefineAnalysisTypes( - self.as_ref().handle, + self.handle, types.as_mut_ptr(), types.len(), Some(P::cb_progress_callback), @@ -1001,7 +1546,7 @@ pub trait BinaryViewExt: BinaryViewBase { .collect() } - fn define_user_types<T, I>(&self, names_and_types: T) + pub fn define_user_types<T, I>(&self, names_and_types: T) where T: Iterator<Item = I>, I: Into<QualifiedNameAndType>, @@ -1009,7 +1554,7 @@ pub trait BinaryViewExt: BinaryViewBase { self.define_user_types_with_progress(names_and_types, NoProgressCallback); } - fn define_user_types_with_progress<T, I, P>(&self, names_and_types: T, mut progress: P) + pub fn define_user_types_with_progress<T, I, P>(&self, names_and_types: T, mut progress: P) where T: Iterator<Item = I>, I: Into<QualifiedNameAndType>, @@ -1022,7 +1567,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNDefineUserAnalysisTypes( - self.as_ref().handle, + self.handle, types.as_mut_ptr(), types.len(), Some(P::cb_progress_callback), @@ -1035,39 +1580,39 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn undefine_auto_type(&self, id: &str) { + pub fn undefine_auto_type(&self, id: &str) { let id_str = id.to_cstr(); unsafe { - BNUndefineAnalysisType(self.as_ref().handle, id_str.as_ref().as_ptr() as *const _); + BNUndefineAnalysisType(self.handle, id_str.as_ref().as_ptr() as *const _); } } - fn undefine_user_type<T: Into<QualifiedName>>(&self, name: T) { + pub fn undefine_user_type<T: Into<QualifiedName>>(&self, name: T) { let mut raw_name = QualifiedName::into_raw(name.into()); - unsafe { BNUndefineUserAnalysisType(self.as_ref().handle, &mut raw_name) } + unsafe { BNUndefineUserAnalysisType(self.handle, &mut raw_name) } QualifiedName::free_raw(raw_name); } - fn types(&self) -> Array<QualifiedNameAndType> { + pub fn types(&self) -> Array<QualifiedNameAndType> { unsafe { let mut count = 0usize; - let types = BNGetAnalysisTypeList(self.as_ref().handle, &mut count); + let types = BNGetAnalysisTypeList(self.handle, &mut count); Array::new(types, count, ()) } } - fn dependency_sorted_types(&self) -> Array<QualifiedNameAndType> { + pub fn dependency_sorted_types(&self) -> Array<QualifiedNameAndType> { unsafe { let mut count = 0usize; - let types = BNGetAnalysisDependencySortedTypeList(self.as_ref().handle, &mut count); + let types = BNGetAnalysisDependencySortedTypeList(self.handle, &mut count); Array::new(types, count, ()) } } - fn type_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<Ref<Type>> { + pub fn type_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<Ref<Type>> { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { - let type_handle = BNGetAnalysisTypeByName(self.as_ref().handle, &mut raw_name); + let type_handle = BNGetAnalysisTypeByName(self.handle, &mut raw_name); QualifiedName::free_raw(raw_name); if type_handle.is_null() { return None; @@ -1076,9 +1621,9 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_by_ref(&self, ref_: &NamedTypeReference) -> Option<Ref<Type>> { + pub fn type_by_ref(&self, ref_: &NamedTypeReference) -> Option<Ref<Type>> { unsafe { - let type_handle = BNGetAnalysisTypeByRef(self.as_ref().handle, ref_.handle); + let type_handle = BNGetAnalysisTypeByRef(self.handle, ref_.handle); if type_handle.is_null() { return None; } @@ -1086,10 +1631,10 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_by_id(&self, id: &str) -> Option<Ref<Type>> { + pub fn type_by_id(&self, id: &str) -> Option<Ref<Type>> { let id_str = id.to_cstr(); unsafe { - let type_handle = BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ptr()); + let type_handle = BNGetAnalysisTypeById(self.handle, id_str.as_ptr()); if type_handle.is_null() { return None; } @@ -1097,10 +1642,10 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_name_by_id(&self, id: &str) -> Option<QualifiedName> { + pub fn type_name_by_id(&self, id: &str) -> Option<QualifiedName> { let id_str = id.to_cstr(); unsafe { - let name_handle = BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ptr()); + let name_handle = BNGetAnalysisTypeNameById(self.handle, id_str.as_ptr()); let name = QualifiedName::from_owned_raw(name_handle); // The core will return an empty qualified name if no type name was found. match name.items.is_empty() { @@ -1110,10 +1655,10 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_id_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<String> { + pub fn type_id_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<String> { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { - let id_cstr = BNGetAnalysisTypeId(self.as_ref().handle, &mut raw_name); + let id_cstr = BNGetAnalysisTypeId(self.handle, &mut raw_name); QualifiedName::free_raw(raw_name); let id = BnString::into_string(id_cstr); match id.is_empty() { @@ -1123,24 +1668,24 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn is_type_auto_defined<T: Into<QualifiedName>>(&self, name: T) -> bool { + pub fn is_type_auto_defined<T: Into<QualifiedName>>(&self, name: T) -> bool { let mut raw_name = QualifiedName::into_raw(name.into()); - let result = unsafe { BNIsAnalysisTypeAutoDefined(self.as_ref().handle, &mut raw_name) }; + let result = unsafe { BNIsAnalysisTypeAutoDefined(self.handle, &mut raw_name) }; QualifiedName::free_raw(raw_name); result } - fn segments(&self) -> Array<Segment> { + pub fn segments(&self) -> Array<Segment> { unsafe { let mut count = 0; - let raw_segments = BNGetSegments(self.as_ref().handle, &mut count); + let raw_segments = BNGetSegments(self.handle, &mut count); Array::new(raw_segments, count, ()) } } - fn segment_at(&self, addr: u64) -> Option<Ref<Segment>> { + pub fn segment_at(&self, addr: u64) -> Option<Ref<Segment>> { unsafe { - let raw_seg = BNGetSegmentAt(self.as_ref().handle, addr); + let raw_seg = BNGetSegmentAt(self.handle, addr); match raw_seg.is_null() { false => Some(Segment::ref_from_raw(raw_seg)), true => None, @@ -1150,24 +1695,24 @@ pub trait BinaryViewExt: BinaryViewBase { /// Adds a segment to the view. /// - /// NOTE: Consider using [BinaryViewExt::begin_bulk_add_segments] and [BinaryViewExt::end_bulk_add_segments] + /// NOTE: Consider using [BinaryView::begin_bulk_add_segments] and [BinaryView::end_bulk_add_segments] /// if you plan on adding a number of segments all at once, to avoid unnecessary MemoryMap updates. - fn add_segment(&self, segment: SegmentBuilder) { + pub fn add_segment(&self, segment: SegmentBuilder) { segment.create(self.as_ref()); } // TODO: Replace with BulkModify guard. /// Start adding segments in bulk. Useful for adding large numbers of segments. /// - /// After calling this any call to [BinaryViewExt::add_segment] will be uncommitted until a call to - /// [BinaryViewExt::end_bulk_add_segments] + /// After calling this any call to [BinaryView::add_segment] will be uncommitted until a call to + /// [BinaryView::end_bulk_add_segments] /// - /// If you wish to discard the uncommitted segments you can call [BinaryViewExt::cancel_bulk_add_segments]. + /// If you wish to discard the uncommitted segments you can call [BinaryView::cancel_bulk_add_segments]. /// - /// NOTE: This **must** be paired with a later call to [BinaryViewExt::end_bulk_add_segments] or - /// [BinaryViewExt::cancel_bulk_add_segments], otherwise segments added after this call will stay uncommitted. - fn begin_bulk_add_segments(&self) { - unsafe { BNBeginBulkAddSegments(self.as_ref().handle) } + /// NOTE: This **must** be paired with a later call to [BinaryView::end_bulk_add_segments] or + /// [BinaryView::cancel_bulk_add_segments], otherwise segments added after this call will stay uncommitted. + pub fn begin_bulk_add_segments(&self) { + unsafe { BNBeginBulkAddSegments(self.handle) } } // TODO: Replace with BulkModify guard. @@ -1175,8 +1720,8 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// NOTE: This **must** be paired with a prior call to [Self::begin_bulk_add_segments], otherwise this /// does nothing and segments are added individually. - fn end_bulk_add_segments(&self) { - unsafe { BNEndBulkAddSegments(self.as_ref().handle) } + pub fn end_bulk_add_segments(&self) { + unsafe { BNEndBulkAddSegments(self.handle) } } // TODO: Replace with BulkModify guard. @@ -1186,35 +1731,35 @@ pub trait BinaryViewExt: BinaryViewBase { /// and [Self::end_bulk_add_segments], where the latter will commit the segments /// which have been added since [Self::begin_bulk_add_segments], this function /// will discard them so that they do not get added to the view. - fn cancel_bulk_add_segments(&self) { - unsafe { BNCancelBulkAddSegments(self.as_ref().handle) } + pub fn cancel_bulk_add_segments(&self) { + unsafe { BNCancelBulkAddSegments(self.handle) } } - fn add_section(&self, section: SectionBuilder) { + pub fn add_section(&self, section: SectionBuilder) { section.create(self.as_ref()); } - fn remove_auto_section(&self, name: impl IntoCStr) { + pub fn remove_auto_section(&self, name: impl IntoCStr) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { - BNRemoveAutoSection(self.as_ref().handle, raw_name_ptr); + BNRemoveAutoSection(self.handle, raw_name_ptr); } } - fn remove_user_section(&self, name: impl IntoCStr) { + pub fn remove_user_section(&self, name: impl IntoCStr) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { - BNRemoveUserSection(self.as_ref().handle, raw_name_ptr); + BNRemoveUserSection(self.handle, raw_name_ptr); } } - fn section_by_name(&self, name: impl IntoCStr) -> Option<Ref<Section>> { + pub fn section_by_name(&self, name: impl IntoCStr) -> Option<Ref<Section>> { unsafe { let raw_name = name.to_cstr(); let name_ptr = raw_name.as_ptr(); - let raw_section_ptr = BNGetSectionByName(self.as_ref().handle, name_ptr); + let raw_section_ptr = BNGetSectionByName(self.handle, name_ptr); match raw_section_ptr.is_null() { false => Some(Section::ref_from_raw(raw_section_ptr)), true => None, @@ -1222,42 +1767,42 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn sections(&self) -> Array<Section> { + pub fn sections(&self) -> Array<Section> { unsafe { let mut count = 0; - let sections = BNGetSections(self.as_ref().handle, &mut count); + let sections = BNGetSections(self.handle, &mut count); Array::new(sections, count, ()) } } - fn sections_at(&self, addr: u64) -> Array<Section> { + pub fn sections_at(&self, addr: u64) -> Array<Section> { unsafe { let mut count = 0; - let sections = BNGetSectionsAt(self.as_ref().handle, addr, &mut count); + let sections = BNGetSectionsAt(self.handle, addr, &mut count); Array::new(sections, count, ()) } } - fn memory_map(&self) -> MemoryMap { + pub fn memory_map(&self) -> MemoryMap { MemoryMap::new(self.as_ref().to_owned()) } /// Add an auto function at the given `address` with the views default platform. /// - /// Use [`BinaryViewExt::add_auto_function_with_platform`] if you wish to specify a platform. + /// Use [`BinaryView::add_auto_function_with_platform`] if you wish to specify a platform. /// /// NOTE: The default platform **must** be set for this view! - fn add_auto_function(&self, address: u64) -> Option<Ref<Function>> { + pub fn add_auto_function(&self, address: u64) -> Option<Ref<Function>> { let platform = self.default_platform()?; self.add_auto_function_with_platform(address, &platform) } /// Add an auto function at the given `address` with the `platform`. /// - /// Use [`BinaryViewExt::add_auto_function_ext`] if you wish to specify a function type. + /// Use [`BinaryView::add_auto_function_ext`] if you wish to specify a function type. /// /// NOTE: If the view's default platform is not set, this will set it to `platform`. - fn add_auto_function_with_platform( + pub fn add_auto_function_with_platform( &self, address: u64, platform: &Platform, @@ -1268,7 +1813,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Add an auto function at the given `address` with the `platform` and function type. /// /// NOTE: If the view's default platform is not set, this will set it to `platform`. - fn add_auto_function_ext( + pub fn add_auto_function_ext( &self, address: u64, platform: &Platform, @@ -1280,13 +1825,8 @@ pub trait BinaryViewExt: BinaryViewBase { None => std::ptr::null_mut(), }; - let handle = BNAddFunctionForAnalysis( - self.as_ref().handle, - platform.handle, - address, - true, - func_type, - ); + let handle = + BNAddFunctionForAnalysis(self.handle, platform.handle, address, true, func_type); if handle.is_null() { return None; @@ -1300,21 +1840,21 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// Pass `true` for `update_refs` to update all references of the function. /// - /// NOTE: Unlike [`BinaryViewExt::remove_user_function`], this will NOT prohibit the function from - /// being re-added in the future, use [`BinaryViewExt::remove_user_function`] to blacklist the + /// NOTE: Unlike [`BinaryView::remove_user_function`], this will NOT prohibit the function from + /// being re-added in the future, use [`BinaryView::remove_user_function`] to blacklist the /// function from being automatically created. - fn remove_auto_function(&self, func: &Function, update_refs: bool) { + pub fn remove_auto_function(&self, func: &Function, update_refs: bool) { unsafe { - BNRemoveAnalysisFunction(self.as_ref().handle, func.handle, update_refs); + BNRemoveAnalysisFunction(self.handle, func.handle, update_refs); } } /// Add a user function at the given `address` with the views default platform. /// - /// Use [`BinaryViewExt::add_user_function_with_platform`] if you wish to specify a platform. + /// Use [`BinaryView::add_user_function_with_platform`] if you wish to specify a platform. /// /// NOTE: The default platform **must** be set for this view! - fn add_user_function(&self, addr: u64) -> Option<Ref<Function>> { + pub fn add_user_function(&self, addr: u64) -> Option<Ref<Function>> { let platform = self.default_platform()?; self.add_user_function_with_platform(addr, &platform) } @@ -1322,13 +1862,13 @@ pub trait BinaryViewExt: BinaryViewBase { /// Add an auto function at the given `address` with the `platform`. /// /// NOTE: If the view's default platform is not set, this will set it to `platform`. - fn add_user_function_with_platform( + pub fn add_user_function_with_platform( &self, addr: u64, platform: &Platform, ) -> Option<Ref<Function>> { unsafe { - let func = BNCreateUserFunction(self.as_ref().handle, platform.handle, addr); + let func = BNCreateUserFunction(self.handle, platform.handle, addr); if func.is_null() { return None; } @@ -1338,19 +1878,19 @@ pub trait BinaryViewExt: BinaryViewBase { /// Removes the function from the view and blacklists it from being created automatically. /// - /// NOTE: If you call [`BinaryViewExt::add_user_function`], it will override the blacklist. - fn remove_user_function(&self, func: &Function) { - unsafe { BNRemoveUserFunction(self.as_ref().handle, func.handle) } + /// NOTE: If you call [`BinaryView::add_user_function`], it will override the blacklist. + pub fn remove_user_function(&self, func: &Function) { + unsafe { BNRemoveUserFunction(self.handle, func.handle) } } - fn has_functions(&self) -> bool { - unsafe { BNHasFunctions(self.as_ref().handle) } + pub fn has_functions(&self) -> bool { + unsafe { BNHasFunctions(self.handle) } } /// Add an entry point at the given `address` with the view's default platform. /// /// NOTE: The default platform **must** be set for this view! - fn add_entry_point(&self, addr: u64) { + pub fn add_entry_point(&self, addr: u64) { if let Some(platform) = self.default_platform() { self.add_entry_point_with_platform(addr, &platform); } @@ -1359,15 +1899,15 @@ pub trait BinaryViewExt: BinaryViewBase { /// Add an entry point at the given `address` with the `platform`. /// /// NOTE: If the view's default platform is not set, this will set it to `platform`. - fn add_entry_point_with_platform(&self, addr: u64, platform: &Platform) { + pub fn add_entry_point_with_platform(&self, addr: u64, platform: &Platform) { unsafe { - BNAddEntryPointForAnalysis(self.as_ref().handle, platform.handle, addr); + BNAddEntryPointForAnalysis(self.handle, platform.handle, addr); } } - fn entry_point_function(&self) -> Option<Ref<Function>> { + pub fn entry_point_function(&self) -> Option<Ref<Function>> { unsafe { - let raw_func_ptr = BNGetAnalysisEntryPoint(self.as_ref().handle); + let raw_func_ptr = BNGetAnalysisEntryPoint(self.handle); match raw_func_ptr.is_null() { false => Some(Function::ref_from_raw(raw_func_ptr)), true => None, @@ -1380,41 +1920,39 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// We see `entry_functions` as good starting points for analysis, these functions normally don't /// have internal references. Exported functions in a dll/so file are not included. - fn entry_point_functions(&self) -> Array<Function> { + pub fn entry_point_functions(&self) -> Array<Function> { unsafe { let mut count = 0; - let functions = BNGetAllEntryFunctions(self.as_ref().handle, &mut count); + let functions = BNGetAllEntryFunctions(self.handle, &mut count); Array::new(functions, count, ()) } } - fn functions(&self) -> Array<Function> { + pub fn functions(&self) -> Array<Function> { unsafe { let mut count = 0; - let functions = BNGetAnalysisFunctionList(self.as_ref().handle, &mut count); + let functions = BNGetAnalysisFunctionList(self.handle, &mut count); Array::new(functions, count, ()) } } /// List of functions *starting* at `addr` - fn functions_at(&self, addr: u64) -> Array<Function> { + pub fn functions_at(&self, addr: u64) -> Array<Function> { unsafe { let mut count = 0; - let functions = - BNGetAnalysisFunctionsForAddress(self.as_ref().handle, addr, &mut count); + let functions = BNGetAnalysisFunctionsForAddress(self.handle, addr, &mut count); Array::new(functions, count, ()) } } /// List of functions containing `addr` - fn functions_containing(&self, addr: u64) -> Array<Function> { + pub fn functions_containing(&self, addr: u64) -> Array<Function> { unsafe { let mut count = 0; - let functions = - BNGetAnalysisFunctionsContainingAddress(self.as_ref().handle, addr, &mut count); + let functions = BNGetAnalysisFunctionsContainingAddress(self.handle, addr, &mut count); Array::new(functions, count, ()) } @@ -1429,7 +1967,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Params /// - `name`: Name that the function should have /// - `plat`: Optional platform that the function should be defined for. Defaults to all platforms if `None` passed. - fn functions_by_name( + pub fn functions_by_name( &self, name: impl IntoCStr, plat: Option<&Platform>, @@ -1459,9 +1997,9 @@ pub trait BinaryViewExt: BinaryViewBase { functions } - fn function_at(&self, platform: &Platform, addr: u64) -> Option<Ref<Function>> { + pub fn function_at(&self, platform: &Platform, addr: u64) -> Option<Ref<Function>> { unsafe { - let raw_func_ptr = BNGetAnalysisFunction(self.as_ref().handle, platform.handle, addr); + let raw_func_ptr = BNGetAnalysisFunction(self.handle, platform.handle, addr); match raw_func_ptr.is_null() { false => Some(Function::ref_from_raw(raw_func_ptr)), true => None, @@ -1469,42 +2007,42 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn function_start_before(&self, addr: u64) -> u64 { - unsafe { BNGetPreviousFunctionStartBeforeAddress(self.as_ref().handle, addr) } + pub fn function_start_before(&self, addr: u64) -> u64 { + unsafe { BNGetPreviousFunctionStartBeforeAddress(self.handle, addr) } } - fn function_start_after(&self, addr: u64) -> u64 { - unsafe { BNGetNextFunctionStartAfterAddress(self.as_ref().handle, addr) } + pub fn function_start_after(&self, addr: u64) -> u64 { + unsafe { BNGetNextFunctionStartAfterAddress(self.handle, addr) } } - fn basic_blocks_containing(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> { + pub fn basic_blocks_containing(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> { unsafe { let mut count = 0; - let blocks = BNGetBasicBlocksForAddress(self.as_ref().handle, addr, &mut count); + let blocks = BNGetBasicBlocksForAddress(self.handle, addr, &mut count); Array::new(blocks, count, NativeBlock::new()) } } - fn basic_blocks_starting_at(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> { + pub fn basic_blocks_starting_at(&self, addr: u64) -> Array<BasicBlock<NativeBlock>> { unsafe { let mut count = 0; - let blocks = BNGetBasicBlocksStartingAtAddress(self.as_ref().handle, addr, &mut count); + let blocks = BNGetBasicBlocksStartingAtAddress(self.handle, addr, &mut count); Array::new(blocks, count, NativeBlock::new()) } } - fn is_new_auto_function_analysis_suppressed(&self) -> bool { - unsafe { BNGetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle) } + pub fn is_new_auto_function_analysis_suppressed(&self) -> bool { + unsafe { BNGetNewAutoFunctionAnalysisSuppressed(self.handle) } } - fn set_new_auto_function_analysis_suppressed(&self, suppress: bool) { + pub fn set_new_auto_function_analysis_suppressed(&self, suppress: bool) { unsafe { - BNSetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle, suppress); + BNSetNewAutoFunctionAnalysisSuppressed(self.handle, suppress); } } // TODO: Should this instead be implemented on [`Function`] considering `src_func`? `Location` is local to the source function. - fn should_skip_target_analysis( + pub fn should_skip_target_analysis( &self, src_loc: impl Into<Location>, src_func: &Function, @@ -1515,7 +2053,7 @@ pub trait BinaryViewExt: BinaryViewBase { let target = target.into(); unsafe { BNShouldSkipTargetAnalysis( - self.as_ref().handle, + self.handle, &mut src_loc.into(), src_func.handle, src_end, @@ -1524,8 +2062,8 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn read_buffer(&self, offset: u64, len: usize) -> Option<DataBuffer> { - let read_buffer = unsafe { BNReadViewBuffer(self.as_ref().handle, offset, len) }; + pub fn read_buffer(&self, offset: u64, len: usize) -> Option<DataBuffer> { + let read_buffer = unsafe { BNReadViewBuffer(self.handle, offset, len) }; if read_buffer.is_null() { None } else { @@ -1533,37 +2071,37 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn debug_info(&self) -> Ref<DebugInfo> { - unsafe { DebugInfo::ref_from_raw(BNGetDebugInfo(self.as_ref().handle)) } + pub fn debug_info(&self) -> Ref<DebugInfo> { + unsafe { DebugInfo::ref_from_raw(BNGetDebugInfo(self.handle)) } } - fn set_debug_info(&self, debug_info: &DebugInfo) { - unsafe { BNSetDebugInfo(self.as_ref().handle, debug_info.handle) } + pub fn set_debug_info(&self, debug_info: &DebugInfo) { + unsafe { BNSetDebugInfo(self.handle, debug_info.handle) } } - fn apply_debug_info(&self, debug_info: &DebugInfo) { - unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) } + pub fn apply_debug_info(&self, debug_info: &DebugInfo) { + unsafe { BNApplyDebugInfo(self.handle, debug_info.handle) } } - fn show_plaintext_report(&self, title: &str, plaintext: &str) { + pub fn show_plaintext_report(&self, title: &str, plaintext: &str) { let title = title.to_cstr(); let plaintext = plaintext.to_cstr(); unsafe { BNShowPlainTextReport( - self.as_ref().handle, + self.handle, title.as_ref().as_ptr() as *mut _, plaintext.as_ref().as_ptr() as *mut _, ) } } - fn show_markdown_report(&self, title: &str, contents: &str, plaintext: &str) { + pub fn show_markdown_report(&self, title: &str, contents: &str, plaintext: &str) { let title = title.to_cstr(); let contents = contents.to_cstr(); let plaintext = plaintext.to_cstr(); unsafe { BNShowMarkdownReport( - self.as_ref().handle, + self.handle, title.as_ref().as_ptr() as *mut _, contents.as_ref().as_ptr() as *mut _, plaintext.as_ref().as_ptr() as *mut _, @@ -1571,13 +2109,13 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn show_html_report(&self, title: &str, contents: &str, plaintext: &str) { + pub fn show_html_report(&self, title: &str, contents: &str, plaintext: &str) { let title = title.to_cstr(); let contents = contents.to_cstr(); let plaintext = plaintext.to_cstr(); unsafe { BNShowHTMLReport( - self.as_ref().handle, + self.handle, title.as_ref().as_ptr() as *mut _, contents.as_ref().as_ptr() as *mut _, plaintext.as_ref().as_ptr() as *mut _, @@ -1585,60 +2123,54 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn show_graph_report(&self, raw_name: &str, graph: &FlowGraph) { + pub fn show_graph_report(&self, raw_name: &str, graph: &FlowGraph) { let raw_name = raw_name.to_cstr(); unsafe { - BNShowGraphReport(self.as_ref().handle, raw_name.as_ptr(), graph.handle); + BNShowGraphReport(self.handle, raw_name.as_ptr(), graph.handle); } } - fn load_settings(&self, view_type_name: &str) -> Result<Ref<Settings>> { + pub fn load_settings(&self, view_type_name: &str) -> Option<Ref<Settings>> { let view_type_name = view_type_name.to_cstr(); let settings_handle = - unsafe { BNBinaryViewGetLoadSettings(self.as_ref().handle, view_type_name.as_ptr()) }; - - if settings_handle.is_null() { - Err(()) - } else { - Ok(unsafe { Settings::ref_from_raw(settings_handle) }) + unsafe { BNBinaryViewGetLoadSettings(self.handle, view_type_name.as_ptr()) }; + match settings_handle.is_null() { + true => None, + false => Some(unsafe { Settings::ref_from_raw(settings_handle) }), } } - fn set_load_settings(&self, view_type_name: &str, settings: &Settings) { + pub fn set_load_settings(&self, view_type_name: &str, settings: &Settings) { let view_type_name = view_type_name.to_cstr(); unsafe { - BNBinaryViewSetLoadSettings( - self.as_ref().handle, - view_type_name.as_ptr(), - settings.handle, - ) + BNBinaryViewSetLoadSettings(self.handle, view_type_name.as_ptr(), settings.handle) }; } - /// Creates a new [TagType] and adds it to the view. + /// Creates a new [`TagType`] and adds it to the view. /// /// # Arguments /// * `name` - the name for the tag /// * `icon` - the icon (recommended 1 emoji or 2 chars) for the tag - fn create_tag_type(&self, name: &str, icon: &str) -> Ref<TagType> { - let tag_type = TagType::create(self.as_ref(), name, icon); + pub fn create_tag_type(&self, name: &str, icon: &str) -> Ref<TagType> { + let tag_type = TagType::create(self, name, icon); unsafe { - BNAddTagType(self.as_ref().handle, tag_type.handle); + BNAddTagType(self.handle, tag_type.handle); } tag_type } /// Removes a [TagType] and all tags that use it - fn remove_tag_type(&self, tag_type: &TagType) { - unsafe { BNRemoveTagType(self.as_ref().handle, tag_type.handle) } + pub fn remove_tag_type(&self, tag_type: &TagType) { + unsafe { BNRemoveTagType(self.handle, tag_type.handle) } } /// Get a tag type by its name. - fn tag_type_by_name(&self, name: &str) -> Option<Ref<TagType>> { + pub fn tag_type_by_name(&self, name: &str) -> Option<Ref<TagType>> { let name = name.to_cstr(); unsafe { - let handle = BNGetTagType(self.as_ref().handle, name.as_ptr()); + let handle = BNGetTagType(self.handle, name.as_ptr()); if handle.is_null() { return None; } @@ -1647,29 +2179,29 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Get all tags in all scopes - fn tags_all_scopes(&self) -> Array<TagReference> { + pub fn tags_all_scopes(&self) -> Array<TagReference> { let mut count = 0; unsafe { - let tag_references = BNGetAllTagReferences(self.as_ref().handle, &mut count); + let tag_references = BNGetAllTagReferences(self.handle, &mut count); Array::new(tag_references, count, ()) } } /// Get all tag types present for the view - fn tag_types(&self) -> Array<TagType> { + pub fn tag_types(&self) -> Array<TagType> { let mut count = 0; unsafe { - let tag_types_raw = BNGetTagTypes(self.as_ref().handle, &mut count); + let tag_types_raw = BNGetTagTypes(self.handle, &mut count); Array::new(tag_types_raw, count, ()) } } /// Get all tag references of a specific type - fn tags_by_type(&self, tag_type: &TagType) -> Array<TagReference> { + pub fn tags_by_type(&self, tag_type: &TagType) -> Array<TagReference> { let mut count = 0; unsafe { let tag_references = - BNGetAllTagReferencesOfType(self.as_ref().handle, tag_type.handle, &mut count); + BNGetAllTagReferencesOfType(self.handle, tag_type.handle, &mut count); Array::new(tag_references, count, ()) } } @@ -1677,10 +2209,10 @@ pub trait BinaryViewExt: BinaryViewBase { /// Get a tag by its id. /// /// Note this does not tell you anything about where it is used. - fn tag_by_id(&self, id: &str) -> Option<Ref<Tag>> { + pub fn tag_by_id(&self, id: &str) -> Option<Ref<Tag>> { let id = id.to_cstr(); unsafe { - let handle = BNGetTag(self.as_ref().handle, id.as_ptr()); + let handle = BNGetTag(self.handle, id.as_ptr()); if handle.is_null() { return None; } @@ -1691,55 +2223,54 @@ pub trait BinaryViewExt: BinaryViewBase { /// Creates and adds a tag to an address /// /// User tag creations will be added to the undo buffer - fn add_tag(&self, addr: u64, t: &TagType, data: &str, user: bool) { + pub fn add_tag(&self, addr: u64, t: &TagType, data: &str, user: bool) { let tag = Tag::new(t, data); - unsafe { BNAddTag(self.as_ref().handle, tag.handle, user) } + unsafe { BNAddTag(self.handle, tag.handle, user) } if user { - unsafe { BNAddUserDataTag(self.as_ref().handle, addr, tag.handle) } + unsafe { BNAddUserDataTag(self.handle, addr, tag.handle) } } else { - unsafe { BNAddAutoDataTag(self.as_ref().handle, addr, tag.handle) } + unsafe { BNAddAutoDataTag(self.handle, addr, tag.handle) } } } /// removes a Tag object at a data address. - fn remove_auto_data_tag(&self, addr: u64, tag: &Tag) { - unsafe { BNRemoveAutoDataTag(self.as_ref().handle, addr, tag.handle) } + pub fn remove_auto_data_tag(&self, addr: u64, tag: &Tag) { + unsafe { BNRemoveAutoDataTag(self.handle, addr, tag.handle) } } /// removes a Tag object at a data address. /// Since this removes a user tag, it will be added to the current undo buffer. - fn remove_user_data_tag(&self, addr: u64, tag: &Tag) { - unsafe { BNRemoveUserDataTag(self.as_ref().handle, addr, tag.handle) } + pub fn remove_user_data_tag(&self, addr: u64, tag: &Tag) { + unsafe { BNRemoveUserDataTag(self.handle, addr, tag.handle) } } /// Retrieves a list of comment addresses, the comments themselves can then be queried with - /// the function [`BinaryViewExt::comment_at`]. + /// the function [`BinaryView::comment_at`]. /// /// If you would rather retrieve the contents of **all** comments at once you can do so with - /// the helper function [`BinaryViewExt::comments`]. - fn comment_references(&self) -> Array<CommentReference> { + /// the helper function [`BinaryView::comments`]. + pub fn comment_references(&self) -> Array<CommentReference> { let mut count = 0; - let addresses_raw = - unsafe { BNGetGlobalCommentedAddresses(self.as_ref().handle, &mut count) }; + let addresses_raw = unsafe { BNGetGlobalCommentedAddresses(self.handle, &mut count) }; unsafe { Array::new(addresses_raw, count, ()) } } /// Retrieves a map of comment addresses to their contents. /// /// This is a helper function that eagerly reads the contents of all comments within the - /// view, use [`BinaryViewExt::comment_references`] instead if you do not wish to read all the comments. - fn comments(&self) -> BTreeMap<u64, String> { + /// view, use [`BinaryView::comment_references`] instead if you do not wish to read all the comments. + pub fn comments(&self) -> BTreeMap<u64, String> { self.comment_references() .iter() .filter_map(|cmt_ref| Some((cmt_ref.start, self.comment_at(cmt_ref.start)?))) .collect() } - fn comment_at(&self, addr: u64) -> Option<String> { + pub fn comment_at(&self, addr: u64) -> Option<String> { unsafe { - let comment_raw = BNGetGlobalCommentForAddress(self.as_ref().handle, addr); + let comment_raw = BNGetGlobalCommentForAddress(self.handle, addr); match comment_raw.is_null() { false => Some(BnString::into_string(comment_raw)), true => None, @@ -1751,9 +2282,9 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// NOTE: This is different from setting a comment at the function-level. To set a comment in a /// function use [`Function::set_comment_at`] - fn set_comment_at(&self, addr: u64, comment: &str) { + pub fn set_comment_at(&self, addr: u64, comment: &str) { let comment_raw = comment.to_cstr(); - unsafe { BNSetGlobalCommentForAddress(self.as_ref().handle, addr, comment_raw.as_ptr()) } + unsafe { BNSetGlobalCommentForAddress(self.handle, addr, comment_raw.as_ptr()) } } /// Retrieves a list of the next disassembly lines. @@ -1764,7 +2295,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// # Arguments /// * `pos` - Position to retrieve linear disassembly lines from - fn get_next_linear_disassembly_lines( + pub fn get_next_linear_disassembly_lines( &self, pos: &mut LinearViewCursor, ) -> Array<LinearDisassemblyLine> { @@ -1788,7 +2319,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// # Arguments /// * `pos` - Position to retrieve linear disassembly lines relative to - fn get_previous_linear_disassembly_lines( + pub fn get_previous_linear_disassembly_lines( &self, pos: &mut LinearViewCursor, ) -> Array<LinearDisassemblyLine> { @@ -1804,10 +2335,10 @@ pub trait BinaryViewExt: BinaryViewBase { result } - fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> { + pub fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> { let key = key.to_cstr(); let value: *mut BNMetadata = - unsafe { BNBinaryViewQueryMetadata(self.as_ref().handle, key.as_ptr()) }; + unsafe { BNBinaryViewQueryMetadata(self.handle, key.as_ptr()) }; if value.is_null() { None } else { @@ -1818,50 +2349,45 @@ pub trait BinaryViewExt: BinaryViewBase { /// Retrieve the metadata as the type `T`. /// /// Fails if the metadata does not exist, or if the metadata failed to coerce to type `T`. - fn get_metadata<T>(&self, key: &str) -> Option<Result<T>> + pub fn get_metadata<T>(&self, key: &str) -> Option<T> where T: for<'a> TryFrom<&'a Metadata>, { self.query_metadata(key) - .map(|md| T::try_from(md.as_ref()).map_err(|_| ())) + .and_then(|md| T::try_from(md.as_ref()).ok()) } - fn store_metadata<V>(&self, key: &str, value: V, is_auto: bool) + pub fn store_metadata<V>(&self, key: &str, value: V, is_auto: bool) where V: Into<Ref<Metadata>>, { let md = value.into(); let key = key.to_cstr(); unsafe { - BNBinaryViewStoreMetadata( - self.as_ref().handle, - key.as_ptr(), - md.as_ref().handle, - is_auto, - ) + BNBinaryViewStoreMetadata(self.handle, key.as_ptr(), md.as_ref().handle, is_auto) }; } - fn remove_metadata(&self, key: &str) { + pub fn remove_metadata(&self, key: &str) { let key = key.to_cstr(); - unsafe { BNBinaryViewRemoveMetadata(self.as_ref().handle, key.as_ptr()) }; + unsafe { BNBinaryViewRemoveMetadata(self.handle, key.as_ptr()) }; } /// Retrieves a list of [CodeReference]s pointing to a given address. - fn code_refs_to_addr(&self, addr: u64) -> Array<CodeReference> { + pub fn code_refs_to_addr(&self, addr: u64) -> Array<CodeReference> { unsafe { let mut count = 0; - let handle = BNGetCodeReferences(self.as_ref().handle, addr, &mut count, false, 0); + let handle = BNGetCodeReferences(self.handle, addr, &mut count, false, 0); Array::new(handle, count, ()) } } /// Retrieves a list of [CodeReference]s pointing into a given [Range]. - fn code_refs_into_range(&self, range: Range<u64>) -> Array<CodeReference> { + pub fn code_refs_into_range(&self, range: Range<u64>) -> Array<CodeReference> { unsafe { let mut count = 0; let handle = BNGetCodeReferencesInRange( - self.as_ref().handle, + self.handle, range.start, range.end - range.start, &mut count, @@ -1873,14 +2399,13 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Retrieves a list of addresses pointed to by a given address. - fn code_refs_from_addr(&self, addr: u64, func: Option<&Function>) -> Vec<u64> { + pub fn code_refs_from_addr(&self, addr: u64, func: Option<&Function>) -> Vec<u64> { unsafe { let mut count = 0; let code_ref = CodeReference::new(addr, func.map(|f| f.to_owned()), func.map(|f| f.arch())); let mut raw_code_ref = CodeReference::into_owned_raw(&code_ref); - let addresses = - BNGetCodeReferencesFrom(self.as_ref().handle, &mut raw_code_ref, &mut count); + let addresses = BNGetCodeReferencesFrom(self.handle, &mut raw_code_ref, &mut count); let res = std::slice::from_raw_parts(addresses, count).to_vec(); BNFreeAddressList(addresses); res @@ -1888,20 +2413,20 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Retrieves a list of [DataReference]s pointing to a given address. - fn data_refs_to_addr(&self, addr: u64) -> Array<DataReference> { + pub fn data_refs_to_addr(&self, addr: u64) -> Array<DataReference> { unsafe { let mut count = 0; - let handle = BNGetDataReferences(self.as_ref().handle, addr, &mut count, false, 0); + let handle = BNGetDataReferences(self.handle, addr, &mut count, false, 0); Array::new(handle, count, ()) } } /// Retrieves a list of [DataReference]s pointing into a given [Range]. - fn data_refs_into_range(&self, range: Range<u64>) -> Array<DataReference> { + pub fn data_refs_into_range(&self, range: Range<u64>) -> Array<DataReference> { unsafe { let mut count = 0; let handle = BNGetDataReferencesInRange( - self.as_ref().handle, + self.handle, range.start, range.end - range.start, &mut count, @@ -1913,60 +2438,56 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Retrieves a list of [DataReference]s originating from a given address. - fn data_refs_from_addr(&self, addr: u64) -> Array<DataReference> { + pub fn data_refs_from_addr(&self, addr: u64) -> Array<DataReference> { unsafe { let mut count = 0; - let handle = BNGetDataReferencesFrom(self.as_ref().handle, addr, &mut count); + let handle = BNGetDataReferencesFrom(self.handle, addr, &mut count); Array::new(handle, count, ()) } } /// Retrieves a list of [CodeReference]s for locations in code that use a given named type. - fn code_refs_using_type_name<T: Into<QualifiedName>>(&self, name: T) -> Array<CodeReference> { + pub fn code_refs_using_type_name<T: Into<QualifiedName>>( + &self, + name: T, + ) -> Array<CodeReference> { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { let mut count = 0; - let handle = BNGetCodeReferencesForType( - self.as_ref().handle, - &mut raw_name, - &mut count, - false, - 0, - ); + let handle = + BNGetCodeReferencesForType(self.handle, &mut raw_name, &mut count, false, 0); QualifiedName::free_raw(raw_name); Array::new(handle, count, ()) } } /// Retrieves a list of [DataReference]s for locations in data that use a given named type. - fn data_refs_using_type_name<T: Into<QualifiedName>>(&self, name: T) -> Array<DataReference> { + pub fn data_refs_using_type_name<T: Into<QualifiedName>>( + &self, + name: T, + ) -> Array<DataReference> { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { let mut count = 0; - let handle = BNGetDataReferencesForType( - self.as_ref().handle, - &mut raw_name, - &mut count, - false, - 0, - ); + let handle = + BNGetDataReferencesForType(self.handle, &mut raw_name, &mut count, false, 0); QualifiedName::free_raw(raw_name); Array::new(handle, count, ()) } } - fn relocations_at(&self, addr: u64) -> Array<Relocation> { + pub fn relocations_at(&self, addr: u64) -> Array<Relocation> { unsafe { let mut count = 0; - let handle = BNGetRelocationsAt(self.as_ref().handle, addr, &mut count); + let handle = BNGetRelocationsAt(self.handle, addr, &mut count); Array::new(handle, count, ()) } } - fn relocation_ranges(&self) -> Vec<Range<u64>> { + pub fn relocation_ranges(&self) -> Vec<Range<u64>> { let ranges = unsafe { let mut count = 0; - let reloc_ranges_ptr = BNGetRelocationRanges(self.as_ref().handle, &mut count); + let reloc_ranges_ptr = BNGetRelocationRanges(self.handle, &mut count); let ranges = std::slice::from_raw_parts(reloc_ranges_ptr, count).to_vec(); BNFreeRelocationRanges(reloc_ranges_ptr); ranges @@ -1982,64 +2503,62 @@ pub trait BinaryViewExt: BinaryViewBase { .collect() } - fn component_by_guid(&self, guid: &str) -> Option<Ref<Component>> { + pub fn component_by_guid(&self, guid: &str) -> Option<Ref<Component>> { let name = guid.to_cstr(); - let result = unsafe { BNGetComponentByGuid(self.as_ref().handle, name.as_ptr()) }; + let result = unsafe { BNGetComponentByGuid(self.handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } - fn root_component(&self) -> Option<Ref<Component>> { - let result = unsafe { BNGetRootComponent(self.as_ref().handle) }; + pub fn root_component(&self) -> Option<Ref<Component>> { + let result = unsafe { BNGetRootComponent(self.handle) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } - fn component_by_path(&self, path: &str) -> Option<Ref<Component>> { + pub fn component_by_path(&self, path: &str) -> Option<Ref<Component>> { let path = path.to_cstr(); - let result = unsafe { BNGetComponentByPath(self.as_ref().handle, path.as_ptr()) }; + let result = unsafe { BNGetComponentByPath(self.handle, path.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } - fn remove_component(&self, component: &Component) -> bool { - unsafe { BNRemoveComponent(self.as_ref().handle, component.handle.as_ptr()) } + pub fn remove_component(&self, component: &Component) -> bool { + unsafe { BNRemoveComponent(self.handle, component.handle.as_ptr()) } } - fn remove_component_by_guid(&self, guid: &str) -> bool { + pub fn remove_component_by_guid(&self, guid: &str) -> bool { let path = guid.to_cstr(); - unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) } + unsafe { BNRemoveComponentByGuid(self.handle, path.as_ptr()) } } - fn data_variable_parent_components(&self, data_variable: &DataVariable) -> Array<Component> { + pub fn data_variable_parent_components( + &self, + data_variable: &DataVariable, + ) -> Array<Component> { let mut count = 0; let result = unsafe { - BNGetDataVariableParentComponents( - self.as_ref().handle, - data_variable.address, - &mut count, - ) + BNGetDataVariableParentComponents(self.handle, data_variable.address, &mut count) }; unsafe { Array::new(result, count, ()) } } - fn external_libraries(&self) -> Array<ExternalLibrary> { + pub fn external_libraries(&self) -> Array<ExternalLibrary> { let mut count = 0; - let result = unsafe { BNBinaryViewGetExternalLibraries(self.as_ref().handle, &mut count) }; + let result = unsafe { BNBinaryViewGetExternalLibraries(self.handle, &mut count) }; unsafe { Array::new(result, count, ()) } } - fn external_library(&self, name: &str) -> Option<Ref<ExternalLibrary>> { + pub fn external_library(&self, name: &str) -> Option<Ref<ExternalLibrary>> { let name_ptr = name.to_cstr(); - let result = - unsafe { BNBinaryViewGetExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; + let result = unsafe { BNBinaryViewGetExternalLibrary(self.handle, name_ptr.as_ptr()) }; let result_ptr = NonNull::new(result)?; Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) }) } - fn remove_external_library(&self, name: &str) { + pub fn remove_external_library(&self, name: &str) { let name_ptr = name.to_cstr(); - unsafe { BNBinaryViewRemoveExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; + unsafe { BNBinaryViewRemoveExternalLibrary(self.handle, name_ptr.as_ptr()) }; } - fn add_external_library( + pub fn add_external_library( &self, name: &str, backing_file: Option<&ProjectFile>, @@ -2048,7 +2567,7 @@ pub trait BinaryViewExt: BinaryViewBase { let name_ptr = name.to_cstr(); let result = unsafe { BNBinaryViewAddExternalLibrary( - self.as_ref().handle, + self.handle, name_ptr.as_ptr(), backing_file .map(|b| b.handle.as_ptr()) @@ -2059,29 +2578,28 @@ pub trait BinaryViewExt: BinaryViewBase { NonNull::new(result).map(|h| unsafe { ExternalLibrary::ref_from_raw(h) }) } - fn external_locations(&self) -> Array<ExternalLocation> { + pub fn external_locations(&self) -> Array<ExternalLocation> { let mut count = 0; - let result = unsafe { BNBinaryViewGetExternalLocations(self.as_ref().handle, &mut count) }; + let result = unsafe { BNBinaryViewGetExternalLocations(self.handle, &mut count) }; unsafe { Array::new(result, count, ()) } } - fn external_location_from_symbol(&self, symbol: &Symbol) -> Option<Ref<ExternalLocation>> { - let result = - unsafe { BNBinaryViewGetExternalLocation(self.as_ref().handle, symbol.handle) }; + pub fn external_location_from_symbol(&self, symbol: &Symbol) -> Option<Ref<ExternalLocation>> { + let result = unsafe { BNBinaryViewGetExternalLocation(self.handle, symbol.handle) }; let result_ptr = NonNull::new(result)?; Some(unsafe { ExternalLocation::ref_from_raw(result_ptr) }) } - fn remove_external_location(&self, location: &ExternalLocation) { + pub fn remove_external_location(&self, location: &ExternalLocation) { self.remove_external_location_from_symbol(&location.source_symbol()) } - fn remove_external_location_from_symbol(&self, symbol: &Symbol) { - unsafe { BNBinaryViewRemoveExternalLocation(self.as_ref().handle, symbol.handle) }; + pub fn remove_external_location_from_symbol(&self, symbol: &Symbol) { + unsafe { BNBinaryViewRemoveExternalLocation(self.handle, symbol.handle) }; } // TODO: This is awful, rewrite this. - fn add_external_location( + pub fn add_external_location( &self, symbol: &Symbol, library: &ExternalLibrary, @@ -2095,7 +2613,7 @@ pub trait BinaryViewExt: BinaryViewBase { .unwrap_or(std::ptr::null_mut()); let result = unsafe { BNBinaryViewAddExternalLocation( - self.as_ref().handle, + self.handle, symbol.handle, library.handle.as_ptr(), target_symbol_name.as_ptr(), @@ -2109,17 +2627,16 @@ pub trait BinaryViewExt: BinaryViewBase { /// Type container for all types (user and auto) in the Binary View. /// /// NOTE: Modifying an auto type will promote it to a user type. - fn type_container(&self) -> TypeContainer { - let type_container_ptr = - NonNull::new(unsafe { BNGetAnalysisTypeContainer(self.as_ref().handle) }); + pub fn type_container(&self) -> TypeContainer { + let type_container_ptr = NonNull::new(unsafe { BNGetAnalysisTypeContainer(self.handle) }); // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw` unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) } } /// Type container for user types in the Binary View. - fn user_type_container(&self) -> TypeContainer { + pub fn user_type_container(&self) -> TypeContainer { let type_container_ptr = - NonNull::new(unsafe { BNGetAnalysisUserTypeContainer(self.as_ref().handle) }); + NonNull::new(unsafe { BNGetAnalysisUserTypeContainer(self.handle) }); // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw` unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) }.clone() } @@ -2127,39 +2644,39 @@ pub trait BinaryViewExt: BinaryViewBase { /// Type container for auto types in the Binary View. /// /// NOTE: Unlike [`Self::type_container`] modification of auto types will **NOT** promote it to a user type. - fn auto_type_container(&self) -> TypeContainer { + pub fn auto_type_container(&self) -> TypeContainer { let type_container_ptr = - NonNull::new(unsafe { BNGetAnalysisAutoTypeContainer(self.as_ref().handle) }); + NonNull::new(unsafe { BNGetAnalysisAutoTypeContainer(self.handle) }); // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw` unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) } } - fn type_libraries(&self) -> Array<TypeLibrary> { + pub fn type_libraries(&self) -> Array<TypeLibrary> { let mut count = 0; - let result = unsafe { BNGetBinaryViewTypeLibraries(self.as_ref().handle, &mut count) }; + let result = unsafe { BNGetBinaryViewTypeLibraries(self.handle, &mut count) }; unsafe { Array::new(result, count, ()) } } /// Make the contents of a type library available for type/import resolution - fn add_type_library(&self, library: &TypeLibrary) { - unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) } + pub fn add_type_library(&self, library: &TypeLibrary) { + unsafe { BNAddBinaryViewTypeLibrary(self.handle, library.as_raw()) } } - fn type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> { + pub fn type_library_by_name(&self, name: &str) -> Option<Ref<TypeLibrary>> { let name = name.to_cstr(); - let result = unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_ptr()) }; + let result = unsafe { BNGetBinaryViewTypeLibrary(self.handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { TypeLibrary::ref_from_raw(h) }) } /// Should be called by custom [`BinaryView`] implementations when they have successfully /// imported an object from a type library (eg a symbol's type). Values recorded with this - /// function will then be queryable via [`BinaryViewExt::lookup_imported_object_library`]. + /// function will then be queryable via [`BinaryView::lookup_imported_object_library`]. /// /// * `lib` - Type Library containing the imported type /// * `name` - Name of the object in the type library /// * `addr` - address of symbol at import site /// * `platform` - Platform of symbol at import site - fn record_imported_object_library<T: Into<QualifiedName>>( + pub fn record_imported_object_library<T: Into<QualifiedName>>( &self, lib: &TypeLibrary, name: T, @@ -2169,7 +2686,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { BNBinaryViewRecordImportedObjectLibrary( - self.as_ref().handle, + self.handle, platform.handle, addr, lib.as_raw(), @@ -2189,7 +2706,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Note that the name actually inserted into the view may not match the name as it exists in /// the type library in the event of a name conflict. To aid in this, the [`Type`] object /// returned is a `NamedTypeReference` to the deconflicted name used. - fn import_type_library_type<T: Into<QualifiedName>>( + pub fn import_type_library_type<T: Into<QualifiedName>>( &self, name: T, lib: Option<&TypeLibrary>, @@ -2199,9 +2716,8 @@ pub trait BinaryViewExt: BinaryViewBase { .map(|l| unsafe { l.as_raw() } as *mut _) .unwrap_or(std::ptr::null_mut()); let mut raw_name = QualifiedName::into_raw(name.into()); - let result = unsafe { - BNBinaryViewImportTypeLibraryType(self.as_ref().handle, &mut lib_ref, &mut raw_name) - }; + let result = + unsafe { BNBinaryViewImportTypeLibraryType(self.handle, &mut lib_ref, &mut raw_name) }; QualifiedName::free_raw(raw_name); (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } @@ -2214,9 +2730,9 @@ pub trait BinaryViewExt: BinaryViewBase { /// libraries are lazily resolved when references to types provided by them are first encountered. /// /// NOTE: If you are implementing a custom [`BinaryView`] and use this method to import object types, - /// you should then call [BinaryViewExt::record_imported_object_library] with the details of + /// you should then call [BinaryView::record_imported_object_library] with the details of /// where the object is located. - fn import_type_library_object<T: Into<QualifiedName>>( + pub fn import_type_library_object<T: Into<QualifiedName>>( &self, name: T, lib: Option<&TypeLibrary>, @@ -2227,17 +2743,16 @@ pub trait BinaryViewExt: BinaryViewBase { .unwrap_or(std::ptr::null_mut()); let mut raw_name = QualifiedName::into_raw(name.into()); let result = unsafe { - BNBinaryViewImportTypeLibraryObject(self.as_ref().handle, &mut lib_ref, &mut raw_name) + BNBinaryViewImportTypeLibraryObject(self.handle, &mut lib_ref, &mut raw_name) }; QualifiedName::free_raw(raw_name); (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } /// Recursively imports a [`Type`] given its GUID from available type libraries. - fn import_type_by_guid(&self, guid: &str) -> Option<Ref<Type>> { + pub fn import_type_by_guid(&self, guid: &str) -> Option<Ref<Type>> { let guid = guid.to_cstr(); - let result = - unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.as_ref().handle, guid.as_ptr()) }; + let result = unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.handle, guid.as_ptr()) }; (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } @@ -2245,7 +2760,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// As other referenced types are encountered, they are either copied into the destination type library or /// else the type library that provided the referenced type is added as a dependency for the destination library. - fn export_type_to_library<T: Into<QualifiedName>>( + pub fn export_type_to_library<T: Into<QualifiedName>>( &self, lib: &TypeLibrary, name: T, @@ -2254,7 +2769,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { BNBinaryViewExportTypeToTypeLibrary( - self.as_ref().handle, + self.handle, lib.as_raw(), &mut raw_name, type_obj.handle, @@ -2267,7 +2782,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// As other referenced types are encountered, they are either copied into the destination type library or /// else the type library that provided the referenced type is added as a dependency for the destination library. - fn export_object_to_library<T: Into<QualifiedName>>( + pub fn export_object_to_library<T: Into<QualifiedName>>( &self, lib: &TypeLibrary, name: T, @@ -2276,7 +2791,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { BNBinaryViewExportObjectToTypeLibrary( - self.as_ref().handle, + self.handle, lib.as_raw(), &mut raw_name, type_obj.handle, @@ -2290,7 +2805,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// * `addr` - address of symbol at import site /// * `platform` - Platform of symbol at import site - fn lookup_imported_object_library( + pub fn lookup_imported_object_library( &self, addr: u64, platform: &Platform, @@ -2299,7 +2814,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut result_name = BNQualifiedName::default(); let success = unsafe { BNBinaryViewLookupImportedObjectLibrary( - self.as_ref().handle, + self.handle, platform.handle, addr, &mut result_lib, @@ -2317,7 +2832,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Gives you details of from which type library and name a given type in the analysis was imported. /// /// * `name` - Name of type in analysis - fn lookup_imported_type_library<T: Into<QualifiedName>>( + pub fn lookup_imported_type_library<T: Into<QualifiedName>>( &self, name: T, ) -> Option<(Ref<TypeLibrary>, QualifiedName)> { @@ -2326,7 +2841,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut result_name = BNQualifiedName::default(); let success = unsafe { BNBinaryViewLookupImportedTypeLibrary( - self.as_ref().handle, + self.handle, &raw_name, &mut result_lib, &mut result_name, @@ -2349,15 +2864,15 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// Some helpers for reading strings are available: /// - /// - [`BinaryViewExt::read_c_string_at`] - /// - [`BinaryViewExt::read_utf8_string_at`] + /// - [`BinaryView::read_c_string_at`] + /// - [`BinaryView::read_utf8_string_at`] /// /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength` /// and other settings. - fn strings(&self) -> Array<StringReference> { + pub fn strings(&self) -> Array<StringReference> { unsafe { let mut count = 0; - let strings = BNGetStrings(self.as_ref().handle, &mut count); + let strings = BNGetStrings(self.handle, &mut count); Array::new(strings, count, ()) } } @@ -2370,14 +2885,14 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// Some helpers for reading strings are available: /// - /// - [`BinaryViewExt::read_c_string_at`] - /// - [`BinaryViewExt::read_utf8_string_at`] + /// - [`BinaryView::read_c_string_at`] + /// - [`BinaryView::read_utf8_string_at`] /// /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength` /// and other settings. - fn string_at(&self, addr: u64) -> Option<StringReference> { + pub fn string_at(&self, addr: u64) -> Option<StringReference> { let mut str_ref = BNStringReference::default(); - let success = unsafe { BNGetStringAtAddress(self.as_ref().handle, addr, &mut str_ref) }; + let success = unsafe { BNGetStringAtAddress(self.handle, addr, &mut str_ref) }; if success { Some(str_ref.into()) } else { @@ -2393,16 +2908,16 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// Some helpers for reading strings are available: /// - /// - [`BinaryViewExt::read_c_string_at`] - /// - [`BinaryViewExt::read_utf8_string_at`] + /// - [`BinaryView::read_c_string_at`] + /// - [`BinaryView::read_utf8_string_at`] /// /// NOTE: This returns discovered strings and is therefore governed by `analysis.limits.minStringLength` /// and other settings. - fn strings_in_range(&self, range: Range<u64>) -> Array<StringReference> { + pub fn strings_in_range(&self, range: Range<u64>) -> Array<StringReference> { unsafe { let mut count = 0; let strings = BNGetStringsInRange( - self.as_ref().handle, + self.handle, range.start, range.end - range.start, &mut count, @@ -2413,14 +2928,13 @@ pub trait BinaryViewExt: BinaryViewBase { /// Retrieve the attached type archives as their [`TypeArchiveId`]. /// - /// Using the returned id you can retrieve the [`TypeArchive`] with [`BinaryViewExt::type_archive_by_id`]. - fn attached_type_archives(&self) -> Vec<TypeArchiveId> { + /// Using the returned id you can retrieve the [`TypeArchive`] with [`BinaryView::type_archive_by_id`]. + pub fn attached_type_archives(&self) -> Vec<TypeArchiveId> { let mut ids: *mut *mut c_char = std::ptr::null_mut(); let mut paths: *mut *mut c_char = std::ptr::null_mut(); - let count = - unsafe { BNBinaryViewGetTypeArchives(self.as_ref().handle, &mut ids, &mut paths) }; - // We discard the path here, you can retrieve it later with [`BinaryViewExt::type_archive_path_by_id`], - // this is so we can simplify the return type which will commonly just want to query through to the type + let count = unsafe { BNBinaryViewGetTypeArchives(self.handle, &mut ids, &mut paths) }; + // We discard the path here, you can retrieve it later with [`BinaryView::type_archive_path_by_id`]. + // This is so we can simplify the return type which will commonly just want to query through to the type // archive itself. let _path_list = unsafe { Array::<BnString>::new(paths, count, ()) }; let id_list = unsafe { Array::<BnString>::new(ids, count, ()) }; @@ -2433,17 +2947,17 @@ pub trait BinaryViewExt: BinaryViewBase { /// Look up a connected [`TypeArchive`] by its `id`. /// /// NOTE: A [`TypeArchive`] can be attached but not connected, returning `None`. - fn type_archive_by_id(&self, id: &TypeArchiveId) -> Option<Ref<TypeArchive>> { + pub fn type_archive_by_id(&self, id: &TypeArchiveId) -> Option<Ref<TypeArchive>> { let id = id.0.as_str().to_cstr(); - let result = unsafe { BNBinaryViewGetTypeArchive(self.as_ref().handle, id.as_ptr()) }; + let result = unsafe { BNBinaryViewGetTypeArchive(self.handle, id.as_ptr()) }; let result_ptr = NonNull::new(result)?; Some(unsafe { TypeArchive::ref_from_raw(result_ptr) }) } /// Look up the path for an attached (but not necessarily connected) [`TypeArchive`] by its `id`. - fn type_archive_path_by_id(&self, id: &TypeArchiveId) -> Option<PathBuf> { + pub fn type_archive_path_by_id(&self, id: &TypeArchiveId) -> Option<PathBuf> { let id = id.0.as_str().to_cstr(); - let result = unsafe { BNBinaryViewGetTypeArchivePath(self.as_ref().handle, id.as_ptr()) }; + let result = unsafe { BNBinaryViewGetTypeArchivePath(self.handle, id.as_ptr()) }; if result.is_null() { return None; } @@ -2452,132 +2966,6 @@ pub trait BinaryViewExt: BinaryViewBase { } } -impl<T: BinaryViewBase> BinaryViewExt for T {} - -/// Represents the "whole view" of the binary and its analysis. -/// -/// Analysis information: -/// -/// - [`BinaryViewExt::functions`] -/// - [`BinaryViewExt::data_variables`] -/// - [`BinaryViewExt::strings`] -/// -/// Annotation information: -/// -/// - [`BinaryViewExt::symbols`] -/// - [`BinaryViewExt::tags_all_scopes`] -/// - [`BinaryViewExt::comments`] -/// -/// Data representation and binary information: -/// -/// - [`BinaryViewExt::types`] -/// - [`BinaryViewExt::segments`] -/// - [`BinaryViewExt::sections`] -/// -/// # Cleaning up -/// -/// [`BinaryView`] has a cyclic relationship with the associated [`FileMetadata`], each holds a strong -/// reference to one another, so to properly clean up/free the [`BinaryView`], you must manually close the -/// file using [`FileMetadata::close`], this is not fixable in the general case, until [`FileMetadata`] -/// has only a weak reference to the [`BinaryView`]. -#[derive(PartialEq, Eq, Hash)] -pub struct BinaryView { - pub handle: *mut BNBinaryView, -} - -impl BinaryView { - pub unsafe fn from_raw(handle: *mut BNBinaryView) -> Self { - debug_assert!(!handle.is_null()); - Self { handle } - } - - pub(crate) unsafe fn ref_from_raw(handle: *mut BNBinaryView) -> Ref<Self> { - debug_assert!(!handle.is_null()); - Ref::new(Self { handle }) - } - - /// Construct the raw binary view from the given metadata. - /// - /// Before calling this, make sure you have a valid file path set for the [`FileMetadata`]. It is - /// required that the [`FileMetadata::file_path`] exist in the local filesystem. - pub fn from_metadata(meta: &FileMetadata) -> Result<Ref<Self>> { - if !meta.file_path().exists() { - return Err(()); - } - let file = meta.file_path().to_cstr(); - let handle = - unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) }; - if handle.is_null() { - return Err(()); - } - unsafe { Ok(Ref::new(Self { handle })) } - } - - /// Construct the raw binary view from the given `file_path` and metadata. - /// - /// This will implicitly set the metadata file path and then construct the view. If the metadata - /// already has the desired file path, use [`BinaryView::from_metadata`] instead. - pub fn from_path(meta: &FileMetadata, file_path: impl AsRef<Path>) -> Result<Ref<Self>> { - meta.set_file_path(file_path.as_ref()); - Self::from_metadata(meta) - } - - // TODO: Provide an API that manages the lifetime of the accessor and the view. - /// Construct the raw binary view from the given `accessor` and metadata. - /// - /// It is the responsibility of the caller to keep the accessor alive for the lifetime of the view; - /// because of this, we mark the function as unsafe. - pub unsafe fn from_accessor<A: Accessor>( - meta: &FileMetadata, - accessor: &mut FileAccessor<A>, - ) -> Result<Ref<Self>> { - let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut accessor.raw) }; - if handle.is_null() { - return Err(()); - } - unsafe { Ok(Ref::new(Self { handle })) } - } - - /// Construct the raw binary view from the given `data` and metadata. - /// - /// The data will be copied into the view, so the caller does not need to keep the data alive. - pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Ref<Self> { - let handle = unsafe { - BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len()) - }; - assert!( - !handle.is_null(), - "BNCreateBinaryDataViewFromData should always succeed" - ); - unsafe { Ref::new(Self { handle }) } - } - - /// Save the original binary file to the provided `file_path` along with any modifications. - /// - /// WARNING: Currently there is a possibility to deadlock if the analysis has queued up a main thread action - /// that tries to take the [`FileMetadata`] lock of the current view, and is executed while we - /// are executing in this function. - /// - /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there - /// are no queued up main thread actions. - pub fn save_to_path(&self, file_path: impl AsRef<Path>) -> bool { - let file = file_path.as_ref().to_cstr(); - unsafe { BNSaveToFilename(self.handle, file.as_ptr() as *mut _) } - } - - /// Save the original binary file to the provided [`FileAccessor`] along with any modifications. - /// - /// WARNING: Currently there is a possibility to deadlock if the analysis has queued up a main thread action - /// that tries to take the [`FileMetadata`] lock of the current view, and is executed while we - /// are executing in this function. - /// - /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there - /// are no queued up main thread actions. - pub fn save_to_accessor<A: Accessor>(&self, file: &mut FileAccessor<A>) -> bool { - unsafe { BNSaveToFile(self.handle, &mut file.raw) } - } -} - impl BinaryViewBase for BinaryView { fn read(&self, buf: &mut [u8], offset: u64) -> usize { unsafe { BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) } @@ -2749,7 +3137,7 @@ where Handler: BinaryViewEventHandler, { unsafe extern "C" fn on_event<Handler: BinaryViewEventHandler>( - ctx: *mut ::std::os::raw::c_void, + ctx: *mut c_void, view: *mut BNBinaryView, ) { ffi_wrap!("EventHandler::on_event", { @@ -2762,11 +3150,7 @@ where let raw = Box::into_raw(boxed); unsafe { - BNRegisterBinaryViewEvent( - event_type, - Some(on_event::<Handler>), - raw as *mut ::std::os::raw::c_void, - ); + BNRegisterBinaryViewEvent(event_type, Some(on_event::<Handler>), raw as *mut c_void); } } @@ -2879,3 +3263,318 @@ unsafe impl CoreArrayProviderInner for AddressRange { Self::from(*raw) } } + +extern "C" fn cb_valid<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> bool +where + T: CustomBinaryViewType, +{ + let view_type = unsafe { &*(ctxt as *mut T) }; + let data = unsafe { BinaryView::ref_from_raw(BNNewViewReference(data)) }; + let _span = ffi_span!("CustomBinaryViewType::is_valid_for", data); + view_type.is_valid_for(&data) +} + +extern "C" fn cb_deprecated<T>(_ctxt: *mut c_void) -> bool +where + T: CustomBinaryViewType, +{ + T::DEPRECATED +} + +extern "C" fn cb_force_loadable<T>(_ctxt: *mut c_void) -> bool +where + T: CustomBinaryViewType, +{ + T::FORCE_LOADABLE +} + +extern "C" fn cb_has_no_initial_content<T>(_ctxt: *mut c_void) -> bool +where + T: CustomBinaryViewType, +{ + T::HAS_NO_INITIAL_CONTENT +} + +extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView +where + T: CustomBinaryViewType, +{ + ffi_wrap!("CustomBinaryViewType::create", unsafe { + let view_type = &*(ctxt as *mut T); + let data = BinaryView::from_raw(data); + let _span = ffi_span!("CustomBinaryViewType::create", data); + match view_type.create_binary_view(&data) { + Ok(custom_view) => { + match BinaryView::from_custom(T::NAME, &data.file(), &data, custom_view) { + Ok(custom_view) => Ref::into_raw(custom_view).handle, + Err(_) => std::ptr::null_mut(), + } + } + Err(_) => std::ptr::null_mut(), + } + }) +} + +extern "C" fn cb_parse<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView +where + T: CustomBinaryViewType, +{ + ffi_wrap!("CustomBinaryViewType::parse", unsafe { + let view_type = &*(ctxt as *mut T); + let data = BinaryView::from_raw(data); + let _span = ffi_span!("CustomBinaryViewType::parse", data); + match view_type.create_binary_view_for_parse(&data) { + Ok(custom_view) => { + match BinaryView::from_custom(T::NAME, &data.file(), &data, custom_view) { + Ok(custom_view) => Ref::into_raw(custom_view).handle, + Err(_) => std::ptr::null_mut(), + } + } + Err(_) => std::ptr::null_mut(), + } + }) +} + +extern "C" fn cb_load_settings<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNSettings +where + T: CustomBinaryViewType, +{ + ffi_wrap!("CustomBinaryViewType::load_settings", unsafe { + let view_type = &*(ctxt as *mut T); + let data = BinaryView::from_raw(data); + + let _span = ffi_span!("CustomBinaryViewType::load_settings", data); + let settings = view_type.load_settings_for_data(&data); + Ref::into_raw(settings).handle + }) +} + +extern "C" fn cb_init<C>(ctxt: *mut c_void) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::init", unsafe { + let context = &mut *(ctxt as *mut CustomBinaryViewContext<C>); + // SAFETY: The core view has been initialized by [`BinaryView::from_custom`], so it should be valid. + // SAFETY: The custom view is not being touched by anything else at the point this function is called, + // so it should be safe to mutably borrow it. + context.view.initialize(context.core_view.assume_init_ref()) + }) +} + +extern "C" fn cb_on_after_snapshot_data_applied<C>(ctxt: *mut c_void) +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::onAfterSnapshotDataApplied", unsafe { + let context = &mut *(ctxt as *mut CustomBinaryViewContext<C>); + // SAFETY: The custom view is not being touched by anything else at the point this function is called, + // so it should be safe to mutably borrow it. + context.view.on_after_snapshot_data_applied(); + }) +} + +extern "C" fn cb_free_object<C>(ctxt: *mut c_void) +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::freeObject", unsafe { + let context = ctxt as *mut CustomBinaryViewContext<C>; + let _context = Box::from_raw(context); + }) +} + +extern "C" fn cb_read<C>(ctxt: *mut c_void, dest: *mut c_void, offset: u64, len: usize) -> usize +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::read", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + let dest = std::slice::from_raw_parts_mut(dest as *mut u8, len); + context.view.read(dest, offset) + }) +} + +extern "C" fn cb_write<C>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::write", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + let src = std::slice::from_raw_parts(src as *const u8, len); + context.view.write(offset, src) + }) +} + +extern "C" fn cb_insert<C>(ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize) -> usize +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::insert", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + let src = std::slice::from_raw_parts(src as *const u8, len); + context.view.insert(offset, src) + }) +} + +extern "C" fn cb_remove<C>(ctxt: *mut c_void, offset: u64, len: u64) -> usize +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::remove", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.remove(offset, len as usize) + }) +} + +extern "C" fn cb_modification<C>(ctxt: *mut c_void, offset: u64) -> ModificationStatus +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::modification_status", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.modification_status(offset) + }) +} + +extern "C" fn cb_offset_valid<C>(ctxt: *mut c_void, offset: u64) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::offset_valid", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.offset_valid(offset) + }) +} + +extern "C" fn cb_offset_readable<C>(ctxt: *mut c_void, offset: u64) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::readable", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.offset_readable(offset) + }) +} + +extern "C" fn cb_offset_writable<C>(ctxt: *mut c_void, offset: u64) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::writable", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.offset_writable(offset) + }) +} + +extern "C" fn cb_offset_executable<C>(ctxt: *mut c_void, offset: u64) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::offset_executable", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.offset_executable(offset) + }) +} + +extern "C" fn cb_offset_backed_by_file<C>(ctxt: *mut c_void, offset: u64) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::offset_backed_by_file", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.offset_backed_by_file(offset) + }) +} + +extern "C" fn cb_next_valid_offset<C>(ctxt: *mut c_void, offset: u64) -> u64 +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::next_valid_offset_after", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.next_valid_offset_after(offset) + }) +} + +extern "C" fn cb_start<C>(ctxt: *mut c_void) -> u64 +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::start", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.start() + }) +} + +extern "C" fn cb_length<C>(ctxt: *mut c_void) -> u64 +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::len", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.len() + }) +} + +extern "C" fn cb_entry_point<C>(ctxt: *mut c_void) -> u64 +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::entry_point", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.entry_point() + }) +} + +extern "C" fn cb_executable<C>(ctxt: *mut c_void) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::executable", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.executable() + }) +} + +extern "C" fn cb_endianness<C>(ctxt: *mut c_void) -> Endianness +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::default_endianness", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.default_endianness() + }) +} + +extern "C" fn cb_relocatable<C>(ctxt: *mut c_void) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::relocatable", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.relocatable() + }) +} + +extern "C" fn cb_address_size<C>(ctxt: *mut c_void) -> usize +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::address_size", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + context.view.address_size() + }) +} + +extern "C" fn cb_save<C>(ctxt: *mut c_void, _file: *mut BNFileAccessor) -> bool +where + C: CustomBinaryView, +{ + ffi_wrap!("BinaryViewBase::save", unsafe { + let context = &*(ctxt as *mut CustomBinaryViewContext<C>); + // TODO: Need to pass file accessor to save to. + // let file = FileAccessor::from_raw(file); + context.view.save() + }) +} |
