diff options
| author | KyleMiles <krm504@nyu.edu> | 2021-01-21 18:35:20 +0000 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2021-01-21 19:07:07 +0000 |
| commit | 2fcacc55d5466a7d17bdc0b3ce988772aa6d0653 (patch) | |
| tree | 9d0f2ba19117843575936f2b93e0b6a578a84dc8 /rust/src/binaryview.rs | |
| parent | a0da07c5c2860a5bd69921d38e438bbc1d43912f (diff) | |
cargo fmt and all my changes
Diffstat (limited to 'rust/src/binaryview.rs')
| -rw-r--r-- | rust/src/binaryview.rs | 951 |
1 files changed, 191 insertions, 760 deletions
diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs index b6d1d1a7..a011b9e0 100644 --- a/rust/src/binaryview.rs +++ b/rust/src/binaryview.rs @@ -1,45 +1,60 @@ +// Copyright 2021 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. + use binaryninjacore_sys::*; pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus; -use std::result; -use std::slice; use std::ops; -use std::marker::PhantomData; - -use std::os::raw::{c_void, c_char}; -use std::mem; use std::ptr; - -use crate::Endianness; +use std::result; use crate::architecture::Architecture; use crate::architecture::CoreArchitecture; -use crate::platform::Platform; -use crate::filemetadata::FileMetadata; +use crate::basicblock::BasicBlock; +use crate::databuffer::DataBuffer; use crate::fileaccessor::FileAccessor; -use crate::symbol::{SymType, Symbol}; -use crate::segment::{Segment, SegmentBuilder}; -use crate::section::{Section, SectionBuilder}; +use crate::filemetadata::FileMetadata; +use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; -use crate::basicblock::BasicBlock; -use crate::types::Type; -use crate::settings::Settings; +use crate::platform::Platform; +use crate::section::{Section, SectionBuilder}; +use crate::segment::{Segment, SegmentBuilder}; +use crate::symbol::{Symbol, SymbolType}; +use crate::types::{QualifiedName, Type}; +use crate::Endianness; -use crate::string::*; use crate::rc::*; +use crate::string::*; -// TODO -// merge filemetadata/fileaccessor under here? -// general reorg of modules related to bv +// TODO : general reorg of modules related to bv pub type Result<R> = result::Result<R, ()>; pub trait BinaryViewBase: AsRef<BinaryView> { - fn read(&self, _buf: &mut [u8], _offset: u64) -> usize { 0 } - fn write(&self, _offset: u64, _data: &[u8]) -> usize { 0 } - fn insert(&self, _offset: u64, _data: &[u8]) -> usize { 0 } - fn remove(&self, _offset: u64, _len: usize) -> usize { 0 } + fn read(&self, _buf: &mut [u8], _offset: u64) -> usize { + 0 + } + fn write(&self, _offset: u64, _data: &[u8]) -> usize { + 0 + } + fn insert(&self, _offset: u64, _data: &[u8]) -> usize { + 0 + } + fn remove(&self, _offset: u64, _len: usize) -> usize { + 0 + } fn offset_valid(&self, offset: u64) -> bool { let mut buf = [0u8; 1]; @@ -80,11 +95,19 @@ pub trait BinaryViewBase: AsRef<BinaryView> { ModificationStatus::Original } - fn start(&self) -> u64 { 0 } - fn len(&self) -> usize { 0 } + fn start(&self) -> u64 { + 0 + } + fn len(&self) -> usize { + 0 + } - fn executable(&self) -> bool { true } - fn relocatable(&self) -> bool { true } + fn executable(&self) -> bool { + true + } + fn relocatable(&self) -> bool { + true + } fn entry_point(&self) -> u64; fn default_endianness(&self) -> Endianness; @@ -126,7 +149,7 @@ pub trait BinaryViewExt: BinaryViewBase { let res; { - let dest_slice = ret.get_unchecked_mut(0 .. len); + let dest_slice = ret.get_unchecked_mut(0..len); res = self.read(dest_slice, offset); } @@ -149,7 +172,7 @@ pub trait BinaryViewExt: BinaryViewBase { let res; { - let dest_slice = dest.get_unchecked_mut(starting_len .. starting_len + len); + let dest_slice = dest.get_unchecked_mut(starting_len..starting_len + len); res = self.read(dest_slice, offset); } @@ -162,15 +185,21 @@ pub trait BinaryViewExt: BinaryViewBase { } fn notify_data_written(&self, offset: u64, len: usize) { - unsafe { BNNotifyDataWritten(self.as_ref().handle, offset, len); } + unsafe { + BNNotifyDataWritten(self.as_ref().handle, offset, len); + } } fn notify_data_inserted(&self, offset: u64, len: usize) { - unsafe { BNNotifyDataInserted(self.as_ref().handle, offset, len); } + unsafe { + BNNotifyDataInserted(self.as_ref().handle, offset, len); + } } fn notify_data_removed(&self, offset: u64, len: usize) { - unsafe { BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64); } + unsafe { + BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64); + } } fn offset_has_code_semantics(&self, offset: u64) -> bool { @@ -186,7 +215,9 @@ pub trait BinaryViewExt: BinaryViewBase { } fn update_analysis_and_wait(&self) { - unsafe { BNUpdateAnalysisAndWait(self.as_ref().handle); } + unsafe { + BNUpdateAnalysisAndWait(self.as_ref().handle); + } } fn default_arch(&self) -> Option<CoreArchitecture> { @@ -253,7 +284,11 @@ pub trait BinaryViewExt: BinaryViewBase { let raw_name = raw_name.as_bytes_with_nul(); unsafe { - let raw_sym = BNGetSymbolByRawName(self.as_ref().handle, raw_name.as_ref().as_ptr() as *mut _, ptr::null_mut()); + let raw_sym = BNGetSymbolByRawName( + self.as_ref().handle, + raw_name.as_ref().as_ptr() as *mut _, + ptr::null_mut(), + ); if raw_sym.is_null() { return Err(()); @@ -277,7 +312,12 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { let mut count = 0; - let handles = BNGetSymbolsByName(self.as_ref().handle, raw_name.as_ref().as_ptr() as *mut _, &mut count, ptr::null_mut()); + let handles = BNGetSymbolsByName( + self.as_ref().handle, + raw_name.as_ref().as_ptr() as *mut _, + &mut count, + ptr::null_mut(), + ); Array::new(handles, count, ()) } @@ -287,55 +327,96 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { let mut count = 0; let len = range.end.wrapping_sub(range.start); - let handles = BNGetSymbolsInRange(self.as_ref().handle, range.start, len, &mut count, ptr::null_mut()); + let handles = BNGetSymbolsInRange( + self.as_ref().handle, + range.start, + len, + &mut count, + ptr::null_mut(), + ); Array::new(handles, count, ()) } } - fn symbols_of_type(&self, ty: SymType) -> Array<Symbol> { + 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, ptr::null_mut()); + let handles = + BNGetSymbolsOfType(self.as_ref().handle, ty.into(), &mut count, ptr::null_mut()); Array::new(handles, count, ()) } } - fn symbols_of_type_in_range(&self, ty: SymType, range: ops::Range<u64>) -> Array<Symbol> { + fn symbols_of_type_in_range(&self, ty: SymbolType, range: ops::Range<u64>) -> Array<Symbol> { unsafe { let mut count = 0; let len = range.end.wrapping_sub(range.start); - let handles = BNGetSymbolsOfTypeInRange(self.as_ref().handle, ty.into(), range.start, len, &mut count, ptr::null_mut()); + let handles = BNGetSymbolsOfTypeInRange( + self.as_ref().handle, + ty.into(), + range.start, + len, + &mut count, + ptr::null_mut(), + ); Array::new(handles, count, ()) } } fn define_auto_symbol(&self, sym: &Symbol) { - unsafe { BNDefineAutoSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNDefineAutoSymbol(self.as_ref().handle, sym.handle); + } } - fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>(&self, sym: &Symbol, plat: &Platform, ty: T) { + fn define_auto_symbol_with_type<'a, T: Into<Option<&'a Type>>>( + &self, + sym: &Symbol, + plat: &Platform, + ty: T, + ) { let raw_type = if let Some(t) = ty.into() { t.handle } else { ptr::null_mut() }; - unsafe { BNDefineAutoSymbolAndVariableOrFunction(self.as_ref().handle, plat.handle, sym.handle, raw_type); } + unsafe { + BNDefineAutoSymbolAndVariableOrFunction( + self.as_ref().handle, + plat.handle, + sym.handle, + raw_type, + ); + } } fn undefine_auto_symbol(&self, sym: &Symbol) { - unsafe { BNUndefineAutoSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNUndefineAutoSymbol(self.as_ref().handle, sym.handle); + } } fn define_user_symbol(&self, sym: &Symbol) { - unsafe { BNDefineUserSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNDefineUserSymbol(self.as_ref().handle, sym.handle); + } } fn undefine_user_symbol(&self, sym: &Symbol) { - unsafe { BNUndefineUserSymbol(self.as_ref().handle, sym.handle); } + unsafe { + BNUndefineUserSymbol(self.as_ref().handle, sym.handle); + } + } + + fn define_user_type<S: BnStrCompatible>(&self, name: S, type_obj: &Type) { + unsafe { + let mut qualified_name = QualifiedName::from(name); + BNDefineUserAnalysisType(self.as_ref().handle, &mut qualified_name.0, type_obj.handle) + } } fn segments(&self) -> Array<Segment> { @@ -349,7 +430,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn segment_at(&self, addr: u64) -> Option<Segment> { unsafe { - let raw_seg = BNGetSegmentAt(self.as_ref().handle, addr); + let raw_seg = BNGetSegmentAt(self.as_ref().handle, addr); if !raw_seg.is_null() { Some(Segment::from_raw(raw_seg)) } else { @@ -370,20 +451,24 @@ pub trait BinaryViewExt: BinaryViewBase { let name = name.as_bytes_with_nul(); let name_ptr = name.as_ref().as_ptr() as *mut _; - unsafe { BNRemoveAutoSection(self.as_ref().handle, name_ptr); } + unsafe { + BNRemoveAutoSection(self.as_ref().handle, name_ptr); + } } fn remove_user_section<S: BnStrCompatible>(&self, name: S) { let name = name.as_bytes_with_nul(); let name_ptr = name.as_ref().as_ptr() as *mut _; - unsafe { BNRemoveUserSection(self.as_ref().handle, name_ptr); } + unsafe { + BNRemoveUserSection(self.as_ref().handle, name_ptr); + } } fn section_by_name<S: BnStrCompatible>(&self, name: S) -> Result<Section> { unsafe { let raw_name = name.as_bytes_with_nul(); - let name_ptr = raw_name.as_ref().as_ptr() as * mut _; + let name_ptr = raw_name.as_ref().as_ptr() as *mut _; let raw_section = BNGetSectionByName(self.as_ref().handle, name_ptr); if raw_section.is_null() { @@ -413,15 +498,21 @@ pub trait BinaryViewExt: BinaryViewBase { } fn add_auto_function(&self, plat: &Platform, addr: u64) { - unsafe { BNAddFunctionForAnalysis(self.as_ref().handle, plat.handle, addr); } + unsafe { + BNAddFunctionForAnalysis(self.as_ref().handle, plat.handle, addr); + } } fn add_entry_point(&self, plat: &Platform, addr: u64) { - unsafe { BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr); } + unsafe { + BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr); + } } fn create_user_function(&self, plat: &Platform, addr: u64) { - unsafe { BNCreateUserFunction(self.as_ref().handle, plat.handle, addr); } + unsafe { + BNCreateUserFunction(self.as_ref().handle, plat.handle, addr); + } } fn has_functions(&self) -> bool { @@ -453,7 +544,8 @@ pub trait BinaryViewExt: BinaryViewBase { 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.as_ref().handle, addr, &mut count); Array::new(functions, count, ()) } @@ -494,7 +586,29 @@ pub trait BinaryViewExt: BinaryViewBase { } fn set_new_auto_function_analysis_suppressed(&self, suppress: bool) { - unsafe { BNSetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle, suppress); } + unsafe { + BNSetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle, suppress); + } + } + + fn read_buffer(&self, offset: u64, len: usize) -> Result<DataBuffer> { + let read_buffer = unsafe { BNReadViewBuffer(self.as_ref().handle, offset, len) }; + if read_buffer.is_null() { + Err(()) + } else { + Ok(DataBuffer::from_raw(read_buffer)) + } + } + + fn show_graph_report<S: BnStrCompatible>(&self, raw_name: S, graph: FlowGraph) { + let raw_name = raw_name.as_bytes_with_nul(); + unsafe { + BNShowGraphReport( + self.as_ref().handle, + raw_name.as_ref().as_ptr() as *mut _, + graph.as_ref().handle, + ); + } } } @@ -505,20 +619,22 @@ pub struct BinaryView { pub(crate) handle: *mut BNBinaryView, } -unsafe impl Send for BinaryView {} -unsafe impl Sync for BinaryView {} - impl BinaryView { - pub(crate) unsafe fn from_raw(handle: *mut BNBinaryView) -> Self { + pub unsafe fn from_raw(handle: *mut BNBinaryView) -> Self { debug_assert!(!handle.is_null()); Self { handle } } - pub fn from_filename<S: BnStrCompatible>(meta: &FileMetadata, filename: S) -> Result<Ref<Self>> { + pub fn from_filename<S: BnStrCompatible>( + meta: &FileMetadata, + filename: S, + ) -> Result<Ref<Self>> { let file = filename.as_bytes_with_nul(); - let handle = unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ref().as_ptr() as *mut _) }; + let handle = unsafe { + BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ref().as_ptr() as *mut _) + }; if handle.is_null() { return Err(()); @@ -528,7 +644,8 @@ impl BinaryView { } pub fn from_accessor(meta: &FileMetadata, file: &mut FileAccessor) -> Result<Ref<Self>> { - let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.api_object as *mut _) }; + let handle = + unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.api_object as *mut _) }; if handle.is_null() { return Err(()); @@ -538,7 +655,9 @@ impl BinaryView { } pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Result<Ref<Self>> { - let handle = unsafe { BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len()) }; + let handle = unsafe { + BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len()) + }; if handle.is_null() { return Err(()); @@ -548,17 +667,9 @@ impl BinaryView { } } -impl AsRef<BinaryView> for BinaryView { - fn as_ref(&self) -> &Self { - self - } -} - 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()) - } + unsafe { BNReadViewData(self.handle, buf.as_mut_ptr() as *mut _, offset, buf.len()) } } fn write(&self, offset: u64, data: &[u8]) -> usize { @@ -630,14 +741,6 @@ impl BinaryViewBase for BinaryView { } } -impl ToOwned for BinaryView { - type Owned = Ref<Self>; - - fn to_owned(&self) -> Self::Owned { - unsafe { RefCountable::inc_ref(self) } - } -} - unsafe impl RefCountable for BinaryView { unsafe fn inc_ref(handle: &Self) -> Ref<Self> { Ref::new(Self { @@ -650,691 +753,19 @@ unsafe impl RefCountable for BinaryView { } } -pub trait BinaryViewTypeBase: AsRef<BinaryViewType> { - fn is_valid_for(&self, data: &BinaryView) -> bool; - - fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> { - unsafe { - Ref::new(Settings::from_raw(BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle))) - } - } -} - -pub trait BinaryViewTypeExt: BinaryViewTypeBase { - fn name(&self) -> BnString { - unsafe { - BnString::from_raw(BNGetBinaryViewTypeName(self.as_ref().0)) - } - } - - fn long_name(&self) -> BnString { - unsafe { - BnString::from_raw(BNGetBinaryViewTypeLongName(self.as_ref().0)) - } - } - - fn register_arch<A: Architecture>(&self, id: u32, endianness: Endianness, arch: &A) - { - unsafe { - BNRegisterArchitectureForViewType(self.as_ref().0, id, endianness, arch.as_ref().0); - } - } - - fn register_platform(&self, id: u32, plat: &Platform) - { - let arch = plat.arch(); - - unsafe { - BNRegisterPlatformForViewType(self.as_ref().0, id, arch.0, plat.handle); - } - } - - fn open(&self, data: &BinaryView) -> Result<Ref<BinaryView>> { - let handle = unsafe { BNCreateBinaryViewOfType(self.as_ref().0, data.handle) }; - - if handle.is_null() { - error!("failed to create BinaryView of BinaryViewType '{}'", self.name()); - return Err(()); - } - - unsafe { - Ok(Ref::new(BinaryView::from_raw(handle))) - } - } -} - -impl<T: BinaryViewTypeBase> BinaryViewTypeExt for T {} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct BinaryViewType(*mut BNBinaryViewType); - -unsafe impl Send for BinaryViewType {} -unsafe impl Sync for BinaryViewType {} - -impl BinaryViewType { - pub fn list_all() -> Array<BinaryViewType> { - unsafe { - let mut count: usize = 0; - let types = BNGetBinaryViewTypes(&mut count as *mut _); - - Array::new(types, count, ()) - } - } - - pub fn list_valid_types_for(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<N: BnStrCompatible>(name: N) -> Result<Self> { - let bytes = name.as_bytes_with_nul(); - - let res = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; - - match res.is_null() { - false => Ok(BinaryViewType(res)), - true => Err(()), - } - } - -} - -impl AsRef<BinaryViewType> for BinaryViewType { +impl AsRef<BinaryView> for BinaryView { fn as_ref(&self) -> &Self { self } } -impl BinaryViewTypeBase for BinaryViewType { - fn is_valid_for(&self, data: &BinaryView) -> bool { - unsafe { BNIsBinaryViewTypeValidForData(self.0, data.handle) } - } - - fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> { - unsafe { - Ref::new(Settings::from_raw(BNGetBinaryViewLoadSettingsForData(self.0, data.handle))) - } - } -} - -unsafe impl CoreOwnedArrayProvider for BinaryViewType { - type Raw = *mut BNBinaryViewType; - type Context = (); - - unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { - BNFreeBinaryViewTypeList(raw); - } -} - -unsafe impl<'a> CoreOwnedArrayWrapper<'a> for BinaryViewType { - type Wrapped = BinaryViewType; - - unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped { - BinaryViewType(*raw) - } -} - -pub unsafe trait CustomBinaryView: 'static + BinaryViewBase + Sync + Sized { - type Args: Send; - - fn new(handle: BinaryView, args: &Self::Args) -> Result<Self>; - fn init(&self, args: Self::Args) -> Result<()>; -} - -pub trait CustomBinaryViewType: 'static + BinaryViewTypeBase + Sync { - fn create_custom_view<'builder>(&self, data: &BinaryView, builder: CustomViewBuilder<'builder, Self>) -> Result<CustomView<'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, -} - -/// 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 ()>, -} - - -/// 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<S, T, F>(name: S, long_name: S, constructor: F) -> &'static T -where - S: BnStrCompatible, - T: CustomBinaryViewType, - F: FnOnce(BinaryViewType) -> T, -{ - extern "C" fn cb_valid<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> bool - where - T: CustomBinaryViewType - { - ffi_wrap!("BinaryViewTypeBase::is_valid_for", unsafe { - let view_type = &*(ctxt as *mut T); - let data = BinaryView::from_raw(data); - - view_type.is_valid_for(&data) - }) - } - - 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::from_raw(data); - - let builder = CustomViewBuilder { - view_type: view_type, - actual_parent: &data, - }; - - if let Ok(bv) = view_type.create_custom_view(&data, builder) { - // 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 - } else { - error!("CustomBinaryViewType::create_custom_view returned 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 { - 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::from_raw(data); - - Ref::into_raw(view_type.load_settings_for_data(&data)).handle - }) - } - - let name = name.as_bytes_with_nul(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - - let long_name = long_name.as_bytes_with_nul(); - let long_name_ptr = long_name.as_ref().as_ptr() as *mut _; - - let ctxt = Box::new(unsafe { mem::uninitialized::<T>() }); - let ctxt = Box::into_raw(ctxt); - - let mut bn_obj = BNCustomBinaryViewType { - context: ctxt as *mut _, - create: Some(cb_create::<T>), - parse: Some(cb_parse::<T>), - isValidForData: Some(cb_valid::<T>), - getLoadSettingsForData: Some(cb_load_settings::<T>), - }; - - unsafe { - let res = BNRegisterBinaryViewType(name_ptr, long_name_ptr, &mut bn_obj as *mut _); - - if res.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) - mem::forget(*Box::from_raw(ctxt)); - - panic!("bvt registration failed"); - } - - ptr::write(ctxt, constructor(BinaryViewType(res))); - - &*ctxt - } -} - -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 welp 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.metadata(); - let view_type = self.view_type; - - let view_name = view_type.name(); - - if let Ok(bv) = file.get_view_of_type(view_name.as_cstr()) { - // while it seems to work most of the time, you can get really unlucky - // if the 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. - error!("attempt to create duplicate view of type '{}' (existing: {:?})", view_name.as_str(), bv.handle); - - return Err(()); - } - - // wildly unsafe struct representing the context of a BNCustomBinaryView - // this type should *never* be allowed to drop as the fields are in varying - // states of uninitialized/already consumed throughout the life of the object. - struct CustomViewContext<V> - where - V: CustomBinaryView, - { - view: V, - raw_handle: *mut BNBinaryView, - initialized: bool, - args: V::Args, - } - - 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::from_raw(context.raw_handle); - - if let Ok(v) = V::new(handle, &context.args) { - ptr::write(&mut context.view, v); - context.initialized = true; - - if context.view.init(ptr::read(&context.args)).is_ok() { - true - } else { - error!("CustomBinaryView::init failed; custom view returned Err"); - false - } - } else { - error!("CustomBinaryView::new failed; custom view returned Err"); - false - } - }) - } - - 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.initialized { - mem::forget(context.args); // already consumed - mem::drop(context.view); // cb_init was called - } else { - mem::drop(context.args); // never consumed - mem::forget(context.view); // cb_init was not called, is uninit - - 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 unitialized. - error!("BinaryViewBase::freeObject called on partially initialized object! crash imminent!"); - } else if !context.initialized { - // 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. - 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.view.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.view.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.view.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.view.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.view.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.view.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.view.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.view.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.view.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.view.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.view.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.view.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.view.len() as u64 - }) - } - - 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.view.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.view.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.view.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.view.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.view.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> { - view: unsafe { mem::uninitialized() }, - raw_handle: ptr::null_mut(), - initialized: false, - 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>), - }; - - unsafe { - let res = BNCreateCustomBinaryView(view_name.as_cstr().as_ptr(), file.handle, parent.handle, &mut bn_obj); - - if res.is_null() { - // TODO not sure when this can even happen, let alone what we're supposed to do about - // it. cb_init isn't normally called until later, and cb_free_object definitely won't - // have been called, so we'd at least be on the hook for freeing that stuff... - // probably. - // - // no idea how to force this to fail so I can test this, so just going to do the - // reasonable thing and panic. - panic!("failed to create custom binary view!"); - } - - (*ctxt).raw_handle = res; - - Ok(CustomView { - handle: Ref::new(BinaryView::from_raw(res)), - _builder: PhantomData, - }) - } - } +impl ToOwned for BinaryView { + type Owned = Ref<Self>; - pub fn wrap_existing(self, wrapped_view: Ref<BinaryView>) -> Result<CustomView<'a>> - { - Ok(CustomView { - handle: wrapped_view, - _builder: PhantomData, - }) + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } } } +unsafe impl Send for BinaryView {} +unsafe impl Sync for BinaryView {} |
