diff options
| author | Mason Reed <mason@vector35.com> | 2026-04-21 18:10:51 -0700 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2026-05-10 17:13:08 -0700 |
| commit | c4ba6d79ae3b96d56cc6b3744e7c64e004ecd161 (patch) | |
| tree | 5762fc3ff58b57caec5f42176faf6635c464b4f3 /rust | |
| parent | 8269a8ac29e59c7949af753dac5c1f36bb700903 (diff) | |
[Rust] Refactor `binary_view` module
- Remove the "viral" `BinaryViewExt` trait and its blanket impl
- Split up the binary view type from the custom trait impl
- Simplify and fix bugs regarding custom binary view initialization
- Rewrite Minidump binary view example, parses the PE headers to create proper sections now
- Add some extra documentation
- Add unit test for custom binary view
Diffstat (limited to 'rust')
48 files changed, 1426 insertions, 1631 deletions
diff --git a/rust/README.md b/rust/README.md index 55dccdff..bed6065e 100644 --- a/rust/README.md +++ b/rust/README.md @@ -21,7 +21,6 @@ If you are worried about breaking changes, avoid modules with warnings about ins ```rust use binaryninja::headless::Session; -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; fn main() { let headless_session = Session::new().expect("Failed to initialize session"); @@ -30,7 +29,6 @@ fn main() { .expect("Couldn't open `/bin/cat`"); println!("File: `{}`", bv.file()); - println!("File size: `{:#x}`", bv.len()); println!("Function count: {}", bv.functions().len()); for func in &bv.functions() { diff --git a/rust/examples/bndb_to_type_library.rs b/rust/examples/bndb_to_type_library.rs index 2cfaf83e..b733dde0 100644 --- a/rust/examples/bndb_to_type_library.rs +++ b/rust/examples/bndb_to_type_library.rs @@ -1,6 +1,5 @@ // Usage: cargo run --example bndb_to_type_library <bndb_path> <type_library_path> -use binaryninja::binary_view::BinaryViewExt; use binaryninja::tracing::TracingLogListener; use binaryninja::types::{QualifiedName, TypeLibrary}; use tracing_indicatif::span_ext::IndicatifSpanExt; diff --git a/rust/examples/decompile.rs b/rust/examples/decompile.rs index 155de81c..30465a05 100644 --- a/rust/examples/decompile.rs +++ b/rust/examples/decompile.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryView, BinaryViewBase}; use binaryninja::disassembly::{DisassemblyOption, DisassemblySettings}; use binaryninja::function::Function; use binaryninja::linear_view::LinearViewObject; diff --git a/rust/examples/disassemble.rs b/rust/examples/disassemble.rs index df33aade..245f24d7 100644 --- a/rust/examples/disassemble.rs +++ b/rust/examples/disassemble.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::BinaryViewBase; use binaryninja::disassembly::{DisassemblyOption, DisassemblySettings, DisassemblyTextRenderer}; use binaryninja::function::Function; use binaryninja::tracing::TracingLogListener; diff --git a/rust/examples/flowgraph.rs b/rust/examples/flowgraph.rs index cb03234e..30307c3f 100644 --- a/rust/examples/flowgraph.rs +++ b/rust/examples/flowgraph.rs @@ -9,7 +9,7 @@ use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet, Mess use binaryninja::tracing::TracingLogListener; use binaryninja::{ architecture::BranchType, - binary_view::{BinaryView, BinaryViewExt}, + binary_view::BinaryView, disassembly::{DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind}, flowgraph::{EdgePenStyle, FlowGraph, ThemeColor}, }; diff --git a/rust/examples/high_level_il.rs b/rust/examples/high_level_il.rs index 57b735e9..28081a76 100644 --- a/rust/examples/high_level_il.rs +++ b/rust/examples/high_level_il.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::BinaryViewBase; use binaryninja::tracing::TracingLogListener; fn main() { diff --git a/rust/examples/medium_level_il.rs b/rust/examples/medium_level_il.rs index e2c0edee..4e9cac83 100644 --- a/rust/examples/medium_level_il.rs +++ b/rust/examples/medium_level_il.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::BinaryViewBase; use binaryninja::tracing::TracingLogListener; fn main() { diff --git a/rust/examples/simple.rs b/rust/examples/simple.rs index c01ef74e..5f063ede 100644 --- a/rust/examples/simple.rs +++ b/rust/examples/simple.rs @@ -1,5 +1,5 @@ use binaryninja::architecture::Architecture; -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::BinaryViewBase; use binaryninja::tracing::TracingLogListener; fn main() { diff --git a/rust/examples/workflow.rs b/rust/examples/workflow.rs index bfbbbdb2..a827b0a2 100644 --- a/rust/examples/workflow.rs +++ b/rust/examples/workflow.rs @@ -1,4 +1,3 @@ -use binaryninja::binary_view::BinaryViewExt; use binaryninja::low_level_il::expression::{ExpressionHandler, LowLevelILExpressionKind}; use binaryninja::low_level_il::instruction::InstructionHandler; use binaryninja::low_level_il::VisitorAction; 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() + }) +} diff --git a/rust/src/binary_view/writer.rs b/rust/src/binary_view/writer.rs index 512418e4..57f431fe 100644 --- a/rust/src/binary_view/writer.rs +++ b/rust/src/binary_view/writer.rs @@ -17,7 +17,7 @@ use binaryninjacore_sys::*; use std::fmt::Debug; -use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; +use crate::binary_view::{BinaryView, BinaryViewBase}; use crate::Endianness; use crate::rc::Ref; diff --git a/rust/src/collaboration/file.rs b/rust/src/collaboration/file.rs index dbe2b8b9..84860dd8 100644 --- a/rust/src/collaboration/file.rs +++ b/rust/src/collaboration/file.rs @@ -11,7 +11,7 @@ use super::{ Remote, RemoteFolder, RemoteProject, RemoteSnapshot, }; -use crate::binary_view::{BinaryView, BinaryViewExt}; +use crate::binary_view::BinaryView; use crate::database::Database; use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback, SplitProgressBuilder}; diff --git a/rust/src/collaboration/project.rs b/rust/src/collaboration/project.rs index 3a24ea8b..8ee53f6a 100644 --- a/rust/src/collaboration/project.rs +++ b/rust/src/collaboration/project.rs @@ -8,11 +8,10 @@ use binaryninjacore_sys::*; use super::{ sync, CollaborationPermissionLevel, NameChangeset, Permission, Remote, RemoteFile, - RemoteFileType, RemoteFolder, + RemoteFileType, RemoteFolder, RemoteUser, }; -use crate::binary_view::{BinaryView, BinaryViewExt}; -use crate::collaboration::RemoteUser; +use crate::binary_view::BinaryView; use crate::database::Database; use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; diff --git a/rust/src/collaboration/snapshot.rs b/rust/src/collaboration/snapshot.rs index 203d8677..3e99805d 100644 --- a/rust/src/collaboration/snapshot.rs +++ b/rust/src/collaboration/snapshot.rs @@ -3,7 +3,7 @@ use std::ptr::NonNull; use std::time::SystemTime; use super::{sync, Remote, RemoteFile, RemoteProject}; -use crate::binary_view::{BinaryView, BinaryViewExt}; +use crate::binary_view::BinaryView; use crate::collaboration::undo::{RemoteUndoEntry, RemoteUndoEntryId}; use crate::database::snapshot::Snapshot; use crate::progress::{NoProgressCallback, ProgressCallback}; diff --git a/rust/src/collaboration/sync.rs b/rust/src/collaboration/sync.rs index 72c57a46..1bf9c010 100644 --- a/rust/src/collaboration/sync.rs +++ b/rust/src/collaboration/sync.rs @@ -6,7 +6,7 @@ use std::ffi::{c_char, c_void}; use std::path::{Path, PathBuf}; use std::ptr::NonNull; -use crate::binary_view::{BinaryView, BinaryViewExt}; +use crate::binary_view::BinaryView; use crate::database::{snapshot::Snapshot, Database}; use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; @@ -138,7 +138,7 @@ pub fn get_remote_for_local_database(database: &Database) -> Result<Option<Ref<R .ok_or(()) } -/// Get the Remote for a BinaryView +/// Get the [`Remote`] for the given [`BinaryView`]. pub fn get_remote_for_binary_view(bv: &BinaryView) -> Result<Option<Ref<Remote>>, ()> { let Some(db) = bv.file().database() else { return Ok(None); diff --git a/rust/src/component.rs b/rust/src/component.rs index f038d5c3..c99081fa 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -1,4 +1,4 @@ -use crate::binary_view::{BinaryView, BinaryViewExt}; +use crate::binary_view::BinaryView; use crate::function::Function; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::string::{BnString, IntoCStr}; diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs deleted file mode 100644 index 84f39171..00000000 --- a/rust/src/custom_binary_view.rs +++ /dev/null @@ -1,961 +0,0 @@ -// Copyright 2021-2026 Vector 35 Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! An interface for providing your own [BinaryView]s to Binary Ninja. - -use binaryninjacore_sys::*; - -pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus; - -use std::fmt::Debug; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::os::raw::c_void; -use std::ptr; -use std::slice; - -use crate::architecture::Architecture; -use crate::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt, Result}; -use crate::metadata::Metadata; -use crate::platform::Platform; -use crate::rc::*; -use crate::settings::Settings; -use crate::string::*; -use crate::Endianness; - -/// Registers a custom `BinaryViewType` with the core. -/// -/// The `constructor` argument is called immediately after successful registration of the type with -/// the core. The `BinaryViewType` argument passed to `constructor` is the object that the -/// `AsRef<BinaryViewType>` -/// implementation of the `CustomBinaryViewType` must return. -pub fn register_view_type<T, F>(name: &str, long_name: &str, constructor: F) -> &'static T -where - T: CustomBinaryViewType, - F: FnOnce(BinaryViewType) -> T, -{ - 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!("BinaryViewTypeBase::is_valid_for", data); - view_type.is_valid_for(&data) - } - - extern "C" fn cb_deprecated<T>(ctxt: *mut c_void) -> bool - where - T: CustomBinaryViewType, - { - ffi_wrap!("BinaryViewTypeBase::is_deprecated", unsafe { - let view_type = &*(ctxt as *mut T); - view_type.is_deprecated() - }) - } - - extern "C" fn cb_force_loadable<T>(ctxt: *mut c_void) -> bool - where - T: CustomBinaryViewType, - { - ffi_wrap!("BinaryViewTypeBase::is_force_loadable", unsafe { - let view_type = &*(ctxt as *mut T); - view_type.is_force_loadable() - }) - } - - extern "C" fn cb_has_no_initial_content<T>(ctxt: *mut c_void) -> bool - where - T: CustomBinaryViewType, - { - ffi_wrap!("BinaryViewTypeBase::has_no_initial_content", unsafe { - let view_type = &*(ctxt as *mut T); - view_type.has_no_initial_content() - }) - } - - extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView - where - T: CustomBinaryViewType, - { - ffi_wrap!("BinaryViewTypeBase::create", unsafe { - let view_type = &*(ctxt as *mut T); - let data = BinaryView::ref_from_raw(BNNewViewReference(data)); - - let builder = CustomViewBuilder { - view_type, - actual_parent: &data, - }; - - let _span = ffi_span!("BinaryViewTypeBase::create", data); - match view_type.create_custom_view(&data, builder) { - Ok(bv) => { - // force a leak of the Ref; failure to do this would result - // in the refcount going to 0 in the process of returning it - // to the core -- we're transferring ownership of the Ref here - Ref::into_raw(bv.handle).handle - } - Err(_) => ptr::null_mut(), - } - }) - } - - extern "C" fn cb_parse<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView - where - T: CustomBinaryViewType, - { - ffi_wrap!("BinaryViewTypeBase::parse", unsafe { - let view_type = &*(ctxt as *mut T); - let data = BinaryView::ref_from_raw(BNNewViewReference(data)); - - let builder = CustomViewBuilder { - view_type, - actual_parent: &data, - }; - - let _span = ffi_span!("BinaryViewTypeBase::parse", data); - match view_type.parse_custom_view(&data, builder) { - Ok(bv) => { - // force a leak of the Ref; failure to do this would result - // in the refcount going to 0 in the process of returning it - // to the core -- we're transferring ownership of the Ref here - Ref::into_raw(bv.handle).handle - } - Err(_) => ptr::null_mut(), - } - }) - } - - extern "C" fn cb_load_settings<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNSettings - where - T: CustomBinaryViewType, - { - ffi_wrap!("BinaryViewTypeBase::load_settings", unsafe { - let view_type = &*(ctxt as *mut T); - let data = BinaryView::ref_from_raw(BNNewViewReference(data)); - - let _span = ffi_span!("BinaryViewTypeBase::load_settings", data); - match view_type.load_settings_for_data(&data) { - Some(settings) => Ref::into_raw(settings).handle, - None => ptr::null_mut() as *mut _, - } - }) - } - - let name = name.to_cstr(); - let name_ptr = name.as_ptr(); - - let long_name = long_name.to_cstr(); - let long_name_ptr = long_name.as_ptr(); - - let ctxt = Box::leak(Box::new(MaybeUninit::zeroed())); - - let mut bn_obj = BNCustomBinaryViewType { - context: ctxt.as_mut_ptr() as *mut _, - 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>), - }; - - unsafe { - let handle = BNRegisterBinaryViewType(name_ptr, long_name_ptr, &mut bn_obj as *mut _); - if handle.is_null() { - // avoid leaking the space allocated for the type, but also - // avoid running its Drop impl (if any -- not that there should - // be one since view types live for the life of the process) as - // MaybeUninit suppress the Drop implementation of it's inner type - drop(Box::from_raw(ctxt)); - panic!("bvt registration failed"); - } - - ctxt.write(constructor(BinaryViewType { handle })); - ctxt.assume_init_mut() - } -} - -pub trait BinaryViewTypeBase: AsRef<BinaryViewType> { - /// 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; - - /// 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. - fn is_deprecated(&self) -> bool { - false - } - - /// 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. - fn is_force_loadable(&self) -> bool { - false - } - - /// 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 previously-saved view state for - /// files not being loaded from a database, since a saved layout would reference - /// content that isn't available on reopen. - fn has_no_initial_content(&self) -> bool { - false - } - - fn default_load_settings_for_data(&self, data: &BinaryView) -> Option<Ref<Settings>> { - let settings_handle = - unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().handle, data.handle) }; - - if settings_handle.is_null() { - None - } else { - unsafe { Some(Settings::ref_from_raw(settings_handle)) } - } - } - - fn load_settings_for_data(&self, _data: &BinaryView) -> Option<Ref<Settings>> { - None - } -} - -pub trait BinaryViewTypeExt: BinaryViewTypeBase { - fn name(&self) -> String { - unsafe { BnString::into_string(BNGetBinaryViewTypeName(self.as_ref().handle)) } - } - - fn long_name(&self) -> String { - unsafe { BnString::into_string(BNGetBinaryViewTypeLongName(self.as_ref().handle)) } - } - - fn register_arch<A: Architecture>(&self, id: u32, endianness: Endianness, arch: &A) { - unsafe { - BNRegisterArchitectureForViewType( - self.as_ref().handle, - id, - endianness, - arch.as_ref().handle, - ); - } - } - - fn register_platform(&self, id: u32, plat: &Platform) { - let arch = plat.arch(); - - unsafe { - BNRegisterPlatformForViewType(self.as_ref().handle, id, arch.handle, plat.handle); - } - } - - /// Expanded identification of [`Platform`] for [`BinaryViewType`]'s. Supersedes [`BinaryViewTypeExt::register_arch`] - /// and [`BinaryViewTypeExt::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 datavars 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. - 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 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 }; - // TODO: Currently we leak `recognizer`. - let raw = Box::into_raw(Box::new(recognizer)); - - unsafe { - BNRegisterPlatformRecognizerForViewType( - self.as_ref().handle, - id as u64, - endian, - Some(cb_recognize_low_level_il::<R>), - raw as *mut c_void, - ) - } - } - - fn open(&self, data: &BinaryView) -> Result<Ref<BinaryView>> { - let handle = unsafe { BNCreateBinaryViewOfType(self.as_ref().handle, data.handle) }; - - if handle.is_null() { - // TODO: Proper Result, possibly introduce BNSetError to populate. - return Err(()); - } - - unsafe { Ok(BinaryView::ref_from_raw(handle)) } - } - - fn parse(&self, data: &BinaryView) -> Result<Ref<BinaryView>> { - let handle = unsafe { BNParseBinaryViewOfType(self.as_ref().handle, data.handle) }; - - if handle.is_null() { - // TODO: Proper Result, possibly introduce BNSetError to populate. - return Err(()); - } - - unsafe { Ok(BinaryView::ref_from_raw(handle)) } - } -} - -impl<T: BinaryViewTypeBase> BinaryViewTypeExt for T {} - -/// A [`BinaryViewType`] acts as a factory for [`BinaryView`] objects. -/// -/// Each file format will have its own type, such as PE, ELF, or Mach-O. -#[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 BinaryViewType by its short name - pub fn by_name(name: &str) -> Result<Self> { - let bytes = name.to_cstr(); - let handle = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; - match handle.is_null() { - false => Ok(unsafe { BinaryViewType::from_raw(handle) }), - true => Err(()), - } - } -} - -impl BinaryViewTypeBase for BinaryViewType { - fn is_valid_for(&self, data: &BinaryView) -> bool { - unsafe { BNIsBinaryViewTypeValidForData(self.handle, data.handle) } - } - - fn is_deprecated(&self) -> bool { - unsafe { BNIsBinaryViewTypeDeprecated(self.handle) } - } - - fn is_force_loadable(&self) -> bool { - unsafe { BNIsBinaryViewTypeForceLoadable(self.handle) } - } - - fn has_no_initial_content(&self) -> bool { - unsafe { BNBinaryViewTypeHasNoInitialContent(self.handle) } - } - - 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 std::fmt::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), &()) - } -} - -impl AsRef<BinaryViewType> for BinaryViewType { - fn as_ref(&self) -> &Self { - self - } -} - -unsafe impl Send for BinaryViewType {} -unsafe impl Sync for BinaryViewType {} - -pub trait CustomBinaryViewType: 'static + BinaryViewTypeBase + Sync { - fn create_custom_view<'builder>( - &self, - data: &BinaryView, - builder: CustomViewBuilder<'builder, Self>, - ) -> Result<CustomView<'builder>>; - - fn parse_custom_view<'builder>( - &self, - data: &BinaryView, - builder: CustomViewBuilder<'builder, Self>, - ) -> Result<CustomView<'builder>> { - // TODO: Check to make sure data.type_name is not Self::type_name ? - self.create_custom_view(data, builder) - } -} - -/// Represents a request from the core to instantiate a custom BinaryView -pub struct CustomViewBuilder<'a, T: CustomBinaryViewType + ?Sized> { - view_type: &'a T, - actual_parent: &'a BinaryView, -} - -pub unsafe trait CustomBinaryView: 'static + BinaryViewBase + Sync + Sized { - type Args: Send; - - fn new(handle: &BinaryView, args: &Self::Args) -> Result<Self>; - fn init(&mut self, args: Self::Args) -> Result<()>; - fn on_after_snapshot_data_applied(&mut self) {} -} - -/// Represents a partially initialized custom `BinaryView` that should be returned to the core -/// from the `create_custom_view` method of a `CustomBinaryViewType`. -#[must_use] -pub struct CustomView<'builder> { - // this object can't actually be treated like a real - // BinaryView as it isn't fully initialized until the - // core receives it from the BNCustomBinaryViewType::create - // callback. - handle: Ref<BinaryView>, - _builder: PhantomData<&'builder ()>, -} - -impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { - /// Begins creating a custom BinaryView. - /// - /// This function may only be called from the `create_custom_view` function of a - /// `CustomBinaryViewType`. - /// - /// `parent` specifies the view that the core will treat as the parent view, that - /// Segments created against the created view will be backed by `parent`. It will - /// usually be (but is not required to be) the `data` argument of the `create_custom_view` - /// callback. - /// - /// `constructor` will not be called until well after the value returned by this function - /// has been returned by `create_custom_view` callback to the core, and may not ever - /// be called if the value returned by this function is dropped or leaked. - /// - /// # Errors - /// - /// This function will fail if the `FileMetadata` object associated with the *expected* parent - /// (i.e., the `data` argument passed to the `create_custom_view` function) already has an - /// associated `BinaryView` of the same `CustomBinaryViewType`. Multiple `BinaryView` objects - /// of the same `BinaryViewType` belonging to the same `FileMetadata` object is prohibited and - /// can cause strange, delayed segmentation faults. - /// - /// # Safety - /// - /// `constructor` should avoid doing anything with the object it returns, especially anything - /// that would cause the core to invoke any of the `BinaryViewBase` methods. The core isn't - /// going to consider the object fully initialized until after that callback has run. - /// - /// The `BinaryView` argument passed to the constructor function is the object that is expected - /// to be returned by the `AsRef<BinaryView>` implementation required by the `BinaryViewBase` trait. - /// TODO FIXME whelp this is broke going to need 2 init callbacks - pub fn create<V>(self, parent: &BinaryView, view_args: V::Args) -> Result<CustomView<'a>> - where - V: CustomBinaryView, - { - let file = self.actual_parent.file(); - let view_type = self.view_type; - - let view_name = view_type.name(); - - if let Some(bv) = file.view_of_type(&view_name) { - // while it seems to work most of the time, you can get really unlucky - // if a free of the existing view of the same type kicks off while - // BNCreateBinaryViewOfType is still running. the freeObject callback - // will run for the new view before we've even finished initializing, - // and that's all she wrote. - // - // even if we deal with it gracefully in cb_free_object, - // BNCreateBinaryViewOfType is still going to crash, so we're just - // going to try and stop this from happening in the first place. - tracing::error!( - "attempt to create duplicate view of type '{}' (existing: {:?})", - view_name, - bv.handle - ); - - return Err(()); - } - - // struct representing the context of a BNCustomBinaryView. Can be safely - // dropped at any moment. - struct CustomViewContext<V> - where - V: CustomBinaryView, - { - raw_handle: *mut BNBinaryView, - state: CustomViewContextState<V>, - } - - enum CustomViewContextState<V> - where - V: CustomBinaryView, - { - Uninitialized { args: V::Args }, - Initialized { view: V }, - // dummy state, used as a helper to change states, only happen if the - // `new` or `init` function fails. - None, - } - - impl<V: CustomBinaryView> CustomViewContext<V> { - fn assume_init_ref(&self) -> &V { - let CustomViewContextState::Initialized { view } = &self.state else { - panic!("CustomViewContextState in invalid state"); - }; - view - } - } - - extern "C" fn cb_init<V>(ctxt: *mut c_void) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::init", unsafe { - let context = &mut *(ctxt as *mut CustomViewContext<V>); - let handle = BinaryView::ref_from_raw(context.raw_handle); - - // take the uninitialized state and use the args to call init - let mut state = CustomViewContextState::None; - core::mem::swap(&mut context.state, &mut state); - let CustomViewContextState::Uninitialized { args } = state else { - panic!("CustomViewContextState in invalid state"); - }; - match V::new(handle.as_ref(), &args) { - Ok(mut view) => match view.init(args) { - Ok(_) => { - // put the initialized state - context.state = CustomViewContextState::Initialized { view }; - true - } - Err(_) => { - tracing::error!( - "CustomBinaryView::init failed; custom view returned Err" - ); - false - } - }, - Err(_) => { - tracing::error!("CustomBinaryView::new failed; custom view returned Err"); - false - } - } - }) - } - - extern "C" fn cb_on_after_snapshot_data_applied<V>(ctxt: *mut c_void) - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::onAfterSnapshotDataApplied", unsafe { - let context = &mut *(ctxt as *mut CustomViewContext<V>); - if let CustomViewContextState::Initialized { view } = &mut context.state { - view.on_after_snapshot_data_applied(); - } - }) - } - - extern "C" fn cb_free_object<V>(ctxt: *mut c_void) - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::freeObject", unsafe { - let context = ctxt as *mut CustomViewContext<V>; - let context = Box::from_raw(context); - - if context.raw_handle.is_null() { - // being called here is essentially a guarantee that BNCreateBinaryViewOfType - // is above above us on the call stack somewhere -- no matter what we do, a crash - // is pretty much certain at this point. - // - // this has been observed when two views of the same BinaryViewType are created - // against the same BNFileMetaData object, and one of the views gets freed while - // the second one is being initialized -- somehow the partially initialized one - // gets freed before BNCreateBinaryViewOfType returns. - // - // multiples views of the same BinaryViewType in a BNFileMetaData object are - // prohibited, so an API contract was violated in order to get here. - // - // if we're here, it's too late to do anything about it, though we can at least not - // run the destructor on the custom view since that memory is uninitialized. - tracing::error!( - "BinaryViewBase::freeObject called on partially initialized object! crash imminent!" - ); - } else if matches!( - &context.state, - CustomViewContextState::None | CustomViewContextState::Uninitialized { .. } - ) { - // making it here means somebody went out of their way to leak a BinaryView - // after calling BNCreateCustomView and never gave the BNBinaryView handle - // to the core (which would have called cb_init) - // - // the result is a half-initialized BinaryView that the core will happily hand out - // references to via BNGetFileViewofType even though it was never initialized - // all the way. - // - // TODO update when this corner case gets fixed in the core? - // - // we can't do anything to prevent this, but we can at least have the crash - // not be our fault. - tracing::error!("BinaryViewBase::freeObject called on leaked/never initialized custom view!"); - } - }) - } - - extern "C" fn cb_read<V>( - ctxt: *mut c_void, - dest: *mut c_void, - offset: u64, - len: usize, - ) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::read", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - let dest = slice::from_raw_parts_mut(dest as *mut u8, len); - context.assume_init_ref().read(dest, offset) - }) - } - - extern "C" fn cb_write<V>( - ctxt: *mut c_void, - offset: u64, - src: *const c_void, - len: usize, - ) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::write", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - let src = slice::from_raw_parts(src as *const u8, len); - context.assume_init_ref().write(offset, src) - }) - } - - extern "C" fn cb_insert<V>( - ctxt: *mut c_void, - offset: u64, - src: *const c_void, - len: usize, - ) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::insert", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - let src = slice::from_raw_parts(src as *const u8, len); - context.assume_init_ref().insert(offset, src) - }) - } - - extern "C" fn cb_remove<V>(ctxt: *mut c_void, offset: u64, len: u64) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::remove", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().remove(offset, len as usize) - }) - } - - extern "C" fn cb_modification<V>(ctxt: *mut c_void, offset: u64) -> ModificationStatus - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::modification_status", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().modification_status(offset) - }) - } - - extern "C" fn cb_offset_valid<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::offset_valid", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().offset_valid(offset) - }) - } - - extern "C" fn cb_offset_readable<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::readable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().offset_readable(offset) - }) - } - - extern "C" fn cb_offset_writable<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::writable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().offset_writable(offset) - }) - } - - extern "C" fn cb_offset_executable<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::offset_executable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().offset_executable(offset) - }) - } - - extern "C" fn cb_offset_backed_by_file<V>(ctxt: *mut c_void, offset: u64) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::offset_backed_by_file", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().offset_backed_by_file(offset) - }) - } - - extern "C" fn cb_next_valid_offset<V>(ctxt: *mut c_void, offset: u64) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::next_valid_offset_after", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().next_valid_offset_after(offset) - }) - } - - extern "C" fn cb_start<V>(ctxt: *mut c_void) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::start", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().start() - }) - } - - extern "C" fn cb_length<V>(ctxt: *mut c_void) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::len", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().len() - }) - } - - extern "C" fn cb_entry_point<V>(ctxt: *mut c_void) -> u64 - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::entry_point", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().entry_point() - }) - } - - extern "C" fn cb_executable<V>(ctxt: *mut c_void) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::executable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - context.assume_init_ref().executable() - }) - } - - extern "C" fn cb_endianness<V>(ctxt: *mut c_void) -> Endianness - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::default_endianness", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.assume_init_ref().default_endianness() - }) - } - - extern "C" fn cb_relocatable<V>(ctxt: *mut c_void) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::relocatable", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.assume_init_ref().relocatable() - }) - } - - extern "C" fn cb_address_size<V>(ctxt: *mut c_void) -> usize - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::address_size", unsafe { - let context = &*(ctxt as *mut CustomViewContext<V>); - - context.assume_init_ref().address_size() - }) - } - - extern "C" fn cb_save<V>(ctxt: *mut c_void, _fa: *mut BNFileAccessor) -> bool - where - V: CustomBinaryView, - { - ffi_wrap!("BinaryViewBase::save", unsafe { - let _context = &*(ctxt as *mut CustomViewContext<V>); - false - }) - } - - let ctxt = Box::new(CustomViewContext::<V> { - raw_handle: ptr::null_mut(), - state: CustomViewContextState::Uninitialized { args: view_args }, - }); - - let ctxt = Box::into_raw(ctxt); - - let mut bn_obj = BNCustomBinaryView { - context: ctxt as *mut _, - init: Some(cb_init::<V>), - freeObject: Some(cb_free_object::<V>), - externalRefTaken: None, - externalRefReleased: None, - read: Some(cb_read::<V>), - write: Some(cb_write::<V>), - insert: Some(cb_insert::<V>), - remove: Some(cb_remove::<V>), - getModification: Some(cb_modification::<V>), - isValidOffset: Some(cb_offset_valid::<V>), - isOffsetReadable: Some(cb_offset_readable::<V>), - isOffsetWritable: Some(cb_offset_writable::<V>), - isOffsetExecutable: Some(cb_offset_executable::<V>), - isOffsetBackedByFile: Some(cb_offset_backed_by_file::<V>), - getNextValidOffset: Some(cb_next_valid_offset::<V>), - getStart: Some(cb_start::<V>), - getLength: Some(cb_length::<V>), - getEntryPoint: Some(cb_entry_point::<V>), - isExecutable: Some(cb_executable::<V>), - getDefaultEndianness: Some(cb_endianness::<V>), - isRelocatable: Some(cb_relocatable::<V>), - getAddressSize: Some(cb_address_size::<V>), - save: Some(cb_save::<V>), - onAfterSnapshotDataApplied: Some(cb_on_after_snapshot_data_applied::<V>), - }; - - let view_name = view_name.to_cstr(); - unsafe { - let res = BNCreateCustomBinaryView( - view_name.as_ptr(), - file.handle, - parent.handle, - &mut bn_obj, - ); - assert!( - !res.is_null(), - "BNCreateCustomBinaryView cannot return null" - ); - (*ctxt).raw_handle = res; - Ok(CustomView { - handle: BinaryView::ref_from_raw(res), - _builder: PhantomData, - }) - } - } - - pub fn wrap_existing(self, wrapped_view: Ref<BinaryView>) -> Result<CustomView<'a>> { - Ok(CustomView { - handle: wrapped_view, - _builder: PhantomData, - }) - } -} diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index f4cee4ff..2710537f 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -62,7 +62,6 @@ //! `DebugInfo` will then be automatically applied to binary views that contain debug information (via the setting `analysis.debugInfo.internal`), binary views that provide valid external debug info files (`analysis.debugInfo.external`), or manually fetched/applied as below: //! ```no_run //! # use binaryninja::debuginfo::DebugInfoParser; -//! # use binaryninja::binary_view::BinaryViewExt; //! let bv = binaryninja::load("example").unwrap(); //! let valid_parsers = DebugInfoParser::parsers_for_view(&bv); //! let parser = valid_parsers.get(0); diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index d1c63216..45d142bf 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -34,7 +34,6 @@ pub(crate) fn time_from_bn(timestamp: u64) -> SystemTime { #[macro_export] macro_rules! ffi_span { ($name:expr, $bv:expr) => {{ - use $crate::binary_view::BinaryViewExt; #[allow(unused_imports)] use $crate::file_metadata::FileMetadata; ::tracing::info_span!($name, session_id = $bv.file().session_id().0).entered() diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index b58daa55..7b8a60fd 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -30,7 +30,7 @@ use crate::project::file::ProjectFile; use std::ptr::NonNull; #[allow(unused_imports)] -use crate::custom_binary_view::BinaryViewType; +use crate::binary_view::BinaryViewType; new_id_type!(SessionId, usize); @@ -472,6 +472,9 @@ impl FileMetadata { /// The [`BinaryViewType`]s associated with this file. /// /// For example, opening a PE binary will have the following: "Raw", "PE". + /// + /// Because the type may not have been registered, and the actual [`BinaryViewType`] is not available, + /// we instead return the name of the view type. pub fn view_types(&self) -> Array<BnString> { let mut count = 0; unsafe { diff --git a/rust/src/function.rs b/rust/src/function.rs index c19e2107..90432af6 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -17,7 +17,7 @@ use binaryninjacore_sys::*; use crate::{ architecture::{Architecture, CoreArchitecture, CoreRegister, Register}, basic_block::{BasicBlock, BlockContext}, - binary_view::{BinaryView, BinaryViewExt}, + binary_view::BinaryView, calling_convention::CoreCallingConvention, component::Component, disassembly::{DisassemblySettings, DisassemblyTextLine}, @@ -1157,7 +1157,7 @@ impl Function { /// Function.add_tag, you'll create an "address tag". These are good for labeling /// specific instructions. /// - /// For tagging arbitrary data, consider [BinaryViewExt::add_tag]. + /// For tagging arbitrary data, consider [BinaryView::add_tag]. /// /// * `tag_type_name` - The name of the tag type for this Tag. /// * `data` - Additional data for the Tag. @@ -1167,7 +1167,7 @@ impl Function { /// # Example /// /// ```no_run - /// # use binaryninja::binary_view::{BinaryView, BinaryViewExt}; + /// # use binaryninja::binary_view::BinaryView; /// # use binaryninja::function::Function; /// # let fun: Function = todo!(); /// # let bv: BinaryView = todo!(); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 5f23a9f6..f420fa30 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -37,7 +37,6 @@ pub mod collaboration; pub mod command; pub mod component; pub mod confidence; -pub mod custom_binary_view; pub mod data_buffer; pub mod data_notification; pub mod data_renderer; diff --git a/rust/src/platform.rs b/rust/src/platform.rs index bf135fae..e70e1277 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -176,7 +176,7 @@ impl Platform { pub fn type_container(&self) -> TypeContainer { let type_container_ptr = NonNull::new(unsafe { BNGetPlatformTypeContainer(self.handle) }); // NOTE: I have no idea how this isn't a UAF, see the note in `TypeContainer::from_raw` - // TODO: We are cloning here for platforms but we dont need to do this for [BinaryViewExt::type_container] + // TODO: We are cloning here for platforms but we dont need to do this for [BinaryView::type_container] // TODO: Why does this require that we, construct a TypeContainer, duplicate the type container, then drop the original. unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) } } diff --git a/rust/src/section.rs b/rust/src/section.rs index 7668f548..ee7e0ec7 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -81,7 +81,6 @@ impl Section { /// /// ```no_run /// # use binaryninja::section::Section; - /// # use binaryninja::binary_view::BinaryViewExt; /// let bv = binaryninja::load("example").unwrap(); /// bv.add_section(Section::builder("example".to_string(), 0..1024).align(4).entry_size(4)) /// ``` diff --git a/rust/src/segment.rs b/rust/src/segment.rs index 348d8f67..a042d1fd 100644 --- a/rust/src/segment.rs +++ b/rust/src/segment.rs @@ -41,6 +41,9 @@ impl SegmentBuilder { } } + /// The range of the data in the parent binary view. + /// + /// If this is not specified, then the segment is "unbacked" and will contain no data. pub fn parent_backing(mut self, parent_backing: Range<u64>) -> Self { self.parent_backing = Some(parent_backing); self @@ -107,7 +110,6 @@ impl Segment { /// /// ```no_run /// # use binaryninja::segment::{Segment, SegmentFlags}; - /// # use binaryninja::binary_view::BinaryViewExt; /// let bv = binaryninja::load("example").unwrap(); /// let segment_flags = SegmentFlags::new().writable(true).readable(true); /// bv.add_segment(Segment::builder(0..0x1000).flags(segment_flags)) diff --git a/rust/src/types.rs b/rust/src/types.rs index 65e50040..f45d93bc 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -36,7 +36,7 @@ use binaryninjacore_sys::*; use crate::{ architecture::Architecture, - binary_view::{BinaryView, BinaryViewExt}, + binary_view::BinaryView, calling_convention::CoreCallingConvention, rc::*, string::{BnString, IntoCStr}, @@ -643,7 +643,6 @@ impl Drop for TypeBuilder { /// As an example, defining a _named_ type within a [`BinaryView`]: /// /// ```no_run -/// # use crate::binaryninja::binary_view::BinaryViewExt; /// # use binaryninja::types::Type; /// let bv = binaryninja::load("example.bin").unwrap(); /// let my_custom_type_1 = Type::named_int(5, false, "my_w"); diff --git a/rust/src/types/library.rs b/rust/src/types/library.rs index 8743b896..9b543362 100644 --- a/rust/src/types/library.rs +++ b/rust/src/types/library.rs @@ -17,8 +17,6 @@ use std::ptr::NonNull; // Used for doc comments #[allow(unused_imports)] use crate::binary_view::BinaryView; -#[allow(unused_imports)] -use crate::binary_view::BinaryViewExt; // TODO: Introduce a FinalizedTypeLibrary that cannot be mutated, so we do not have APIs that are unusable. @@ -261,7 +259,7 @@ impl TypeLibrary { /// Referenced types will not automatically be added, so make sure to add referenced types to the /// library or use [`TypeLibrary::add_type_source`] to mark the references originating source. /// - /// To add objects from a binary view, prefer using [`BinaryViewExt::export_object_to_library`] which + /// To add objects from a binary view, prefer using [`BinaryView::export_object_to_library`] which /// will automatically pull in all referenced types and record additional dependencies as needed. pub fn add_named_object(&self, name: QualifiedName, type_: &Type) { let mut raw_name = QualifiedName::into_raw(name); @@ -280,7 +278,7 @@ impl TypeLibrary { /// Referenced types will not automatically be added, so make sure to add referenced types to the /// library or use [`TypeLibrary::add_type_source`] to mark the references originating source. /// - /// To add types from a binary view, prefer using [`BinaryViewExt::export_type_to_library`] which + /// To add types from a binary view, prefer using [`BinaryView::export_type_to_library`] which /// will automatically pull in all referenced types and record additional dependencies as needed. pub fn add_named_type(&self, name: QualifiedName, type_: &Type) { let mut raw_name = QualifiedName::into_raw(name); @@ -320,7 +318,7 @@ impl TypeLibrary { /// Get the object (function) associated with the given name, if any. /// - /// Prefer [`BinaryViewExt::import_type_library_object`] as it will recursively import types required. + /// Prefer [`BinaryView::import_type_library_object`] as it will recursively import types required. pub fn get_named_object(&self, name: QualifiedName) -> Option<Ref<Type>> { let mut raw_name = QualifiedName::into_raw(name); let t = unsafe { BNGetTypeLibraryNamedObject(self.as_raw(), &mut raw_name) }; @@ -330,7 +328,7 @@ impl TypeLibrary { /// Get the type associated with the given name, if any. /// - /// Prefer [`BinaryViewExt::import_type_library_type`] as it will recursively import types required. + /// Prefer [`BinaryView::import_type_library_type`] as it will recursively import types required. pub fn get_named_type(&self, name: QualifiedName) -> Option<Ref<Type>> { let mut raw_name = QualifiedName::into_raw(name); let t = unsafe { BNGetTypeLibraryNamedType(self.as_raw(), &mut raw_name) }; diff --git a/rust/src/types/structure.rs b/rust/src/types/structure.rs index 3b609287..6dd8048a 100644 --- a/rust/src/types/structure.rs +++ b/rust/src/types/structure.rs @@ -7,9 +7,9 @@ use crate::types::{ use binaryninjacore_sys::*; use std::fmt::{Debug, Formatter}; -// Needed for doc comments +// Used for documentation purposes. #[allow(unused)] -use crate::binary_view::BinaryViewExt; +use crate::binary_view::BinaryView; #[derive(PartialEq, Eq, Hash)] pub struct StructureBuilder { @@ -18,7 +18,6 @@ pub struct StructureBuilder { /// ```no_run /// // Includes -/// # use binaryninja::binary_view::BinaryViewExt; /// use binaryninja::types::{MemberAccess, MemberScope, Structure, StructureBuilder, Type}; /// /// // Types to use in the members @@ -349,7 +348,7 @@ impl Structure { /// /// We must pass a [`TypeContainer`] here so that we can resolve base structure members, as they /// are treated as members through this function. Typically, you get the [`TypeContainer`] - /// through the binary view with [`BinaryViewExt::type_container`]. + /// through the binary view with [`BinaryView::type_container`]. pub fn members_at_offset( &self, container: &TypeContainer, @@ -382,7 +381,7 @@ impl Structure { /// Returns the list of all structure members, including inherited ones. /// /// Because we must traverse through base structures, we have to provide the [`TypeContainer`]; - /// in most cases it is ok to provide the binary views container via [`BinaryViewExt::type_container`]. + /// in most cases it is ok to provide the binary views container via [`BinaryView::type_container`]. pub fn members_including_inherited( &self, container: &TypeContainer, diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index e53e0001..72d02237 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -2,7 +2,7 @@ use binaryninjacore_sys::*; // Needed for documentation. #[allow(unused)] -use crate::binary_view::{memory_map::MemoryMap, BinaryViewBase, BinaryViewExt}; +use crate::binary_view::{memory_map::MemoryMap, BinaryViewBase}; use crate::basic_block::BasicBlock; use crate::binary_view::BinaryView; diff --git a/rust/tests/base_detection.rs b/rust/tests/base_detection.rs index e42c6071..5addcb29 100644 --- a/rust/tests/base_detection.rs +++ b/rust/tests/base_detection.rs @@ -1,5 +1,4 @@ use binaryninja::base_detection::{BaseAddressDetectionConfidence, BaseAddressDetectionSettings}; -use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use std::path::PathBuf; diff --git a/rust/tests/binary_reader.rs b/rust/tests/binary_reader.rs index 0adac464..9aca3efe 100644 --- a/rust/tests/binary_reader.rs +++ b/rust/tests/binary_reader.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryReader, BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryReader, BinaryViewBase}; use binaryninja::headless::Session; use std::io::{Read, Seek, SeekFrom}; use std::path::PathBuf; diff --git a/rust/tests/binary_view.rs b/rust/tests/binary_view.rs index 11caf3d0..ff5f0514 100644 --- a/rust/tests/binary_view.rs +++ b/rust/tests/binary_view.rs @@ -1,15 +1,18 @@ use binaryninja::binary_view::search::SearchQuery; use binaryninja::binary_view::{ - AnalysisProgress, AnalysisState, BinaryViewBase, BinaryViewExt, StringType, + register_binary_view_type, AnalysisProgress, BinaryView, BinaryViewBase, CustomBinaryView, + CustomBinaryViewType, StringType, }; use binaryninja::data_buffer::DataBuffer; -use binaryninja::file_metadata::SaveSettings; +use binaryninja::file_metadata::{FileMetadata, SaveSettings}; use binaryninja::function::{Function, FunctionViewType}; use binaryninja::headless::Session; use binaryninja::main_thread::execute_on_main_thread_and_wait; use binaryninja::platform::Platform; use binaryninja::rc::Ref; +use binaryninja::segment::SegmentBuilder; use binaryninja::symbol::{Symbol, SymbolBuilder, SymbolType}; +use binaryninja::Endianness; use std::collections::{BTreeMap, HashSet}; use std::path::PathBuf; @@ -203,3 +206,73 @@ fn test_deterministic_functions() { insta::assert_debug_snapshot!(snapshot_name, functions); } } + +struct MyBinaryViewType; + +impl CustomBinaryViewType for MyBinaryViewType { + type CustomBinaryView = MyBinaryView; + const NAME: &'static str = "MyBinaryView"; + + fn create_binary_view(&self, _data: &BinaryView) -> Result<Self::CustomBinaryView, ()> { + Ok(MyBinaryView) + } + + fn is_valid_for(&self, data: &BinaryView) -> bool { + let mut buffer = [0u8; 4]; + data.read(&mut buffer, 0); + buffer == [0x42, 0x42, 0x42, 0x42] + } +} + +struct MyBinaryView; + +impl BinaryViewBase for MyBinaryView { + fn default_endianness(&self) -> Endianness { + Endianness::LittleEndian + } + + fn address_size(&self) -> usize { + 4 + } +} + +impl CustomBinaryView for MyBinaryView { + fn initialize(&mut self, view: &BinaryView) -> bool { + let test_sym = SymbolBuilder::new(SymbolType::Symbolic, "hello", 0).create(); + view.define_auto_symbol(&test_sym); + view.add_segment(SegmentBuilder::new(0..4).parent_backing(0..4).is_auto(true)); + true + } +} + +#[test] +fn test_custom_view() { + let _session = Session::new().expect("Failed to initialize session"); + let invalid_view = BinaryView::from_data(&FileMetadata::new(), &[0x0, 0x0, 0x0, 0x0]); + let valid_view = BinaryView::from_data(&FileMetadata::new(), &[0x42, 0x42, 0x42, 0x42]); + assert_eq!(MyBinaryViewType.is_valid_for(&invalid_view), false); + assert_eq!(MyBinaryViewType.is_valid_for(&valid_view), true); + + let (_, core_type) = register_binary_view_type(MyBinaryViewType); + assert_eq!(core_type.is_valid_for(&invalid_view), false); + assert_eq!(core_type.is_valid_for(&valid_view), true); + assert_eq!(core_type.name(), "MyBinaryView"); + assert_eq!(core_type.is_deprecated(), false); + assert_eq!(core_type.is_force_loadable(), false); + + let created_view = core_type + .create(&valid_view) + .expect("Failed to create view"); + assert_eq!(created_view.analysis_progress(), AnalysisProgress::Initial); + + let hello_symbol = created_view + .symbol_by_address(0) + .expect("Failed to get symbol"); + assert_eq!(hello_symbol.to_string(), "hello"); + + assert_eq!( + created_view.read_vec(0, 4), + vec![0x42, 0x42, 0x42, 0x42], + "View not backed by the parent data" + ); +} diff --git a/rust/tests/binary_writer.rs b/rust/tests/binary_writer.rs index b74b2837..e6881b98 100644 --- a/rust/tests/binary_writer.rs +++ b/rust/tests/binary_writer.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryReader, BinaryViewBase, BinaryViewExt, BinaryWriter}; +use binaryninja::binary_view::{BinaryReader, BinaryViewBase, BinaryWriter}; use binaryninja::headless::Session; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; diff --git a/rust/tests/collaboration.rs b/rust/tests/collaboration.rs index 914935b5..36066cf7 100644 --- a/rust/tests/collaboration.rs +++ b/rust/tests/collaboration.rs @@ -1,4 +1,3 @@ -use binaryninja::binary_view::BinaryViewExt; use binaryninja::collaboration::{NoNameChangeset, Remote, RemoteFileType, RemoteProject}; use binaryninja::file_metadata::SaveSettings; use binaryninja::headless::Session; diff --git a/rust/tests/component.rs b/rust/tests/component.rs index 3341f0d7..2cddb468 100644 --- a/rust/tests/component.rs +++ b/rust/tests/component.rs @@ -1,4 +1,3 @@ -use binaryninja::binary_view::BinaryViewExt; use binaryninja::component::ComponentBuilder; use binaryninja::headless::Session; use std::path::PathBuf; diff --git a/rust/tests/data_notification.rs b/rust/tests/data_notification.rs index 669c8474..f277692a 100644 --- a/rust/tests/data_notification.rs +++ b/rust/tests/data_notification.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::BinaryView; use binaryninja::data_notification::*; use binaryninja::function::Function; use binaryninja::headless::Session; diff --git a/rust/tests/data_renderer.rs b/rust/tests/data_renderer.rs index fdf39697..a2ab372d 100644 --- a/rust/tests/data_renderer.rs +++ b/rust/tests/data_renderer.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::BinaryView; use binaryninja::data_renderer::{ register_data_renderer, render_lines_for_data, CustomDataRenderer, RegistrationType, TypeContext, diff --git a/rust/tests/debug_info.rs b/rust/tests/debug_info.rs index 407b41d5..3627b4a0 100644 --- a/rust/tests/debug_info.rs +++ b/rust/tests/debug_info.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::BinaryView; use binaryninja::debuginfo::*; use binaryninja::headless::Session; use binaryninja::types::{MemberAccess, MemberScope, StructureBuilder, Type, TypeBuilder}; diff --git a/rust/tests/function.rs b/rust/tests/function.rs index 507b405d..c7c9af73 100644 --- a/rust/tests/function.rs +++ b/rust/tests/function.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::BinaryView; use binaryninja::file_metadata::FileMetadata; use binaryninja::headless::Session; use binaryninja::platform::Platform; diff --git a/rust/tests/high_level_il.rs b/rust/tests/high_level_il.rs index d3a4b05a..aeb15cc6 100644 --- a/rust/tests/high_level_il.rs +++ b/rust/tests/high_level_il.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::BinaryViewBase; use binaryninja::headless::Session; use binaryninja::high_level_il::{ HighLevelExpressionIndex, HighLevelILInstructionKind, HighLevelInstructionIndex, diff --git a/rust/tests/language_representation.rs b/rust/tests/language_representation.rs index f4aeb7bd..78af7d7f 100644 --- a/rust/tests/language_representation.rs +++ b/rust/tests/language_representation.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use binaryninja::architecture::CoreArchitecture; -use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::BinaryView; use binaryninja::disassembly::{ DisassemblySettings, DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind, }; diff --git a/rust/tests/low_level_il.rs b/rust/tests/low_level_il.rs index e6f8d8ff..efae0a62 100644 --- a/rust/tests/low_level_il.rs +++ b/rust/tests/low_level_il.rs @@ -1,7 +1,6 @@ use binaryninja::architecture::{ Architecture, ArchitectureExt, CoreArchitecture, Intrinsic, Register, }; -use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use binaryninja::low_level_il::expression::{ ExpressionHandler, LowLevelExpressionIndex, LowLevelILExpressionKind, diff --git a/rust/tests/medium_level_il.rs b/rust/tests/medium_level_il.rs index a921965f..d4f76345 100644 --- a/rust/tests/medium_level_il.rs +++ b/rust/tests/medium_level_il.rs @@ -1,4 +1,3 @@ -use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use binaryninja::medium_level_il::{ MediumLevelExpressionIndex, MediumLevelILInstructionKind, MediumLevelILLiftedInstructionKind, diff --git a/rust/tests/render_layer.rs b/rust/tests/render_layer.rs index 6f6ebc98..6ca391df 100644 --- a/rust/tests/render_layer.rs +++ b/rust/tests/render_layer.rs @@ -1,5 +1,4 @@ use binaryninja::basic_block::BasicBlock; -use binaryninja::binary_view::BinaryViewExt; use binaryninja::disassembly::{DisassemblyOption, DisassemblySettings, DisassemblyTextLine}; use binaryninja::function::NativeBlock; use binaryninja::headless::Session; diff --git a/rust/tests/section.rs b/rust/tests/section.rs index ea3d8e06..ab1703c6 100644 --- a/rust/tests/section.rs +++ b/rust/tests/section.rs @@ -1,4 +1,3 @@ -use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use binaryninja::section::{SectionBuilder, Semantics}; use std::path::PathBuf; diff --git a/rust/tests/type_container.rs b/rust/tests/type_container.rs index a0916ef4..ab4cbb0b 100644 --- a/rust/tests/type_container.rs +++ b/rust/tests/type_container.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::BinaryView; use binaryninja::file_metadata::FileMetadata; use binaryninja::headless::Session; use binaryninja::platform::Platform; diff --git a/rust/tests/type_library.rs b/rust/tests/type_library.rs index 19115f35..559aae7c 100644 --- a/rust/tests/type_library.rs +++ b/rust/tests/type_library.rs @@ -1,4 +1,3 @@ -use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; use binaryninja::platform::Platform; use binaryninja::types::{Type, TypeClass, TypeLibrary}; diff --git a/rust/tests/types.rs b/rust/tests/types.rs index c13a1c88..a661b4ed 100644 --- a/rust/tests/types.rs +++ b/rust/tests/types.rs @@ -1,4 +1,4 @@ -use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::binary_view::BinaryView; use binaryninja::confidence::Conf; use binaryninja::file_metadata::FileMetadata; use binaryninja::headless::Session; |
