diff options
Diffstat (limited to 'rust/src/custom_binary_view.rs')
| -rw-r--r-- | rust/src/custom_binary_view.rs | 961 |
1 files changed, 0 insertions, 961 deletions
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, - }) - } -} |
