summaryrefslogtreecommitdiff
path: root/rust/src/binaryview.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/binaryview.rs')
-rw-r--r--rust/src/binaryview.rs1964
1 files changed, 0 insertions, 1964 deletions
diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs
deleted file mode 100644
index 47f0c18d..00000000
--- a/rust/src/binaryview.rs
+++ /dev/null
@@ -1,1964 +0,0 @@
-// Copyright 2021-2024 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.
-
-//! A view on binary data and queryable interface of a binary file.
-//!
-//! One key job of BinaryView is file format parsing which allows Binary Ninja to read, write, insert, remove portions of the file given a virtual address. For the purposes of this documentation we define a virtual address as the memory address that the various pieces of the physical file will be loaded at.
-//! TODO : Mirror the Python docs for this
-
-use binaryninjacore_sys::*;
-
-pub use binaryninjacore_sys::BNAnalysisState as AnalysisState;
-pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus;
-
-use std::collections::HashMap;
-use std::ffi::{c_char, c_void};
-use std::ops::Range;
-use std::{ops, ptr, result, slice};
-
-use crate::architecture::{Architecture, CoreArchitecture};
-use crate::basicblock::BasicBlock;
-use crate::component::{Component, ComponentBuilder, IntoComponentGuid};
-use crate::databuffer::DataBuffer;
-use crate::debuginfo::DebugInfo;
-use crate::fileaccessor::FileAccessor;
-use crate::filemetadata::FileMetadata;
-use crate::flowgraph::FlowGraph;
-use crate::function::{Function, NativeBlock};
-use crate::linearview::{LinearDisassemblyLine, LinearViewCursor};
-use crate::metadata::Metadata;
-use crate::platform::Platform;
-use crate::relocation::Relocation;
-use crate::section::{Section, SectionBuilder};
-use crate::segment::{Segment, SegmentBuilder};
-use crate::settings::Settings;
-use crate::symbol::{Symbol, SymbolType};
-use crate::tags::{Tag, TagType};
-use crate::typelibrary::TypeLibrary;
-use crate::types::{
- Conf, DataVariable, NamedTypeReference, QualifiedName, QualifiedNameAndType, Type,
-};
-use crate::Endianness;
-
-use crate::rc::*;
-use crate::references::{CodeReference, DataReference};
-use crate::string::*;
-
-// TODO : general reorg of modules related to bv
-
-pub type Result<R> = result::Result<R, ()>;
-
-#[allow(clippy::len_without_is_empty)]
-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 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()
- }
-
- fn offset_readable(&self, offset: u64) -> bool {
- self.offset_valid(offset)
- }
-
- fn offset_writable(&self, offset: u64) -> bool {
- self.offset_valid(offset)
- }
-
- fn offset_executable(&self, offset: u64) -> bool {
- self.offset_valid(offset)
- }
-
- fn offset_backed_by_file(&self, offset: u64) -> bool {
- self.offset_valid(offset)
- }
-
- fn next_valid_offset_after(&self, offset: u64) -> u64 {
- let start = self.as_ref().start();
-
- if offset < start {
- start
- } else {
- offset
- }
- }
-
- #[allow(unused)]
- fn modification_status(&self, offset: u64) -> ModificationStatus {
- ModificationStatus::Original
- }
-
- fn start(&self) -> u64 {
- 0
- }
-
- fn len(&self) -> usize {
- 0
- }
-
- fn executable(&self) -> bool {
- true
- }
-
- fn relocatable(&self) -> bool {
- true
- }
-
- fn entry_point(&self) -> u64;
- fn default_endianness(&self) -> Endianness;
- fn address_size(&self) -> usize;
-
- // TODO saving fileaccessor
- fn save(&self) -> bool {
- self.as_ref()
- .parent_view()
- .map(|bv| bv.save())
- .unwrap_or(false)
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct ActiveAnalysisInfo {
- pub func: Ref<Function>,
- pub analysis_time: u64,
- pub update_count: usize,
- pub submit_count: usize,
-}
-
-#[derive(Debug, Clone)]
-pub struct AnalysisInfo {
- pub state: AnalysisState,
- pub analysis_time: u64,
- pub active_info: Vec<ActiveAnalysisInfo>,
-}
-
-#[derive(Debug, Clone)]
-pub struct AnalysisProgress {
- pub state: AnalysisState,
- pub count: usize,
- pub total: usize,
-}
-
-// TODO: Copied from debuginfo.rs, this should be consolidated
-struct ProgressContext(Option<Box<dyn Fn(usize, usize) -> Result<()>>>);
-
-extern "C" fn cb_progress(ctxt: *mut c_void, cur: usize, max: usize) -> bool {
- ffi_wrap!("BinaryViewExt::cb_progress", unsafe {
- let progress = ctxt as *mut ProgressContext;
- match &(*progress).0 {
- Some(func) => (func)(cur, max).is_ok(),
- None => true,
- }
- })
-}
-
-pub trait BinaryViewExt: BinaryViewBase {
- fn file(&self) -> Ref<FileMetadata> {
- unsafe {
- let raw = BNGetFileForView(self.as_ref().handle);
-
- Ref::new(FileMetadata::from_raw(raw))
- }
- }
-
- fn type_name(&self) -> BnString {
- let ptr: *mut c_char = unsafe { BNGetViewType(self.as_ref().handle) };
- unsafe { BnString::from_raw(ptr) }
- }
-
- fn parent_view(&self) -> Result<Ref<BinaryView>> {
- let handle = unsafe { BNGetParentView(self.as_ref().handle) };
-
- if handle.is_null() {
- return Err(());
- }
-
- unsafe { Ok(BinaryView::from_raw(handle)) }
- }
-
- fn raw_view(&self) -> Result<Ref<BinaryView>> {
- let raw = "Raw".into_bytes_with_nul();
-
- let handle =
- unsafe { BNGetFileViewOfType(self.file().as_ref().handle, raw.as_ptr() as *mut _) };
-
- if handle.is_null() {
- return Err(());
- }
-
- unsafe { Ok(BinaryView::from_raw(handle)) }
- }
-
- fn view_type(&self) -> BnString {
- let ptr: *mut c_char = unsafe { BNGetViewType(self.as_ref().handle) };
- unsafe { BnString::from_raw(ptr) }
- }
-
- /// Reads up to `len` bytes from address `offset`
- 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);
-
- ret
- }
-
- /// Appends up to `len` bytes from address `offset` into `dest`
- 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);
- dest.truncate(starting_len + read_size);
- read_size
- }
-
- fn notify_data_written(&self, offset: u64, len: usize) {
- 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);
- }
- }
-
- fn notify_data_removed(&self, offset: u64, len: usize) {
- unsafe {
- BNNotifyDataRemoved(self.as_ref().handle, offset, len as u64);
- }
- }
-
- fn offset_has_code_semantics(&self, offset: u64) -> bool {
- unsafe { BNIsOffsetCodeSemantics(self.as_ref().handle, offset) }
- }
-
- fn offset_has_writable_semantics(&self, offset: u64) -> bool {
- unsafe { BNIsOffsetWritableSemantics(self.as_ref().handle, offset) }
- }
-
- fn original_image_base(&self) -> u64 {
- unsafe {
- BNGetOriginalImageBase(self.as_ref().handle)
- }
- }
-
- fn set_original_image_base(&self, image_base: u64) {
- unsafe {
- BNSetOriginalImageBase(self.as_ref().handle, image_base)
- }
- }
-
- fn end(&self) -> u64 {
- unsafe { BNGetEndOffset(self.as_ref().handle) }
- }
-
- fn add_analysis_option(&self, name: impl BnStrCompatible) {
- unsafe {
- BNAddAnalysisOption(
- self.as_ref().handle,
- name.into_bytes_with_nul().as_ref().as_ptr() as *mut _,
- )
- }
- }
-
- fn has_initial_analysis(&self) -> bool {
- unsafe { BNHasInitialAnalysis(self.as_ref().handle) }
- }
-
- fn set_analysis_hold(&self, enable: bool) {
- unsafe { BNSetAnalysisHold(self.as_ref().handle, enable) }
- }
-
- fn update_analysis(&self) {
- unsafe {
- BNUpdateAnalysis(self.as_ref().handle);
- }
- }
-
- fn update_analysis_and_wait(&self) {
- unsafe {
- BNUpdateAnalysisAndWait(self.as_ref().handle);
- }
- }
-
- fn abort_analysis(&self) {
- unsafe { BNAbortAnalysis(self.as_ref().handle) }
- }
-
- fn analysis_info(&self) -> Result<AnalysisInfo> {
- let info_ref = unsafe { BNGetAnalysisInfo(self.as_ref().handle) };
- if info_ref.is_null() {
- return Err(());
- }
- let info = unsafe { *info_ref };
- let active_infos = unsafe { slice::from_raw_parts(info.activeInfo, info.count) };
-
- let mut active_info_list = vec![];
- for active_info in active_infos {
- let func = unsafe { Function::from_raw(BNNewFunctionReference(active_info.func)) };
- active_info_list.push(ActiveAnalysisInfo {
- func,
- analysis_time: active_info.analysisTime,
- update_count: active_info.updateCount,
- submit_count: active_info.submitCount,
- });
- }
-
- let result = AnalysisInfo {
- state: info.state,
- analysis_time: info.analysisTime,
- active_info: vec![],
- };
-
- unsafe { BNFreeAnalysisInfo(info_ref) };
- Ok(result)
- }
-
- fn analysis_progress(&self) -> AnalysisProgress {
- let progress = unsafe { BNGetAnalysisProgress(self.as_ref().handle) };
- AnalysisProgress {
- state: progress.state,
- count: progress.count,
- total: progress.total,
- }
- }
-
- fn default_arch(&self) -> Option<CoreArchitecture> {
- unsafe {
- let raw = BNGetDefaultArchitecture(self.as_ref().handle);
-
- if raw.is_null() {
- return None;
- }
-
- Some(CoreArchitecture::from_raw(raw))
- }
- }
-
- fn set_default_arch<A: Architecture>(&self, arch: &A) {
- unsafe {
- BNSetDefaultArchitecture(self.as_ref().handle, arch.as_ref().0);
- }
- }
-
- fn default_platform(&self) -> Option<Ref<Platform>> {
- unsafe {
- let raw = BNGetDefaultPlatform(self.as_ref().handle);
-
- if raw.is_null() {
- return None;
- }
-
- Some(Platform::ref_from_raw(raw))
- }
- }
-
- fn set_default_platform(&self, plat: &Platform) {
- unsafe {
- BNSetDefaultPlatform(self.as_ref().handle, plat.handle);
- }
- }
-
- fn instruction_len<A: Architecture>(&self, arch: &A, addr: u64) -> Option<usize> {
- unsafe {
- let size = BNGetInstructionLength(self.as_ref().handle, arch.as_ref().0, addr);
-
- if size > 0 {
- Some(size)
- } else {
- None
- }
- }
- }
-
- fn symbol_by_address(&self, addr: u64) -> Result<Ref<Symbol>> {
- unsafe {
- let raw_sym = BNGetSymbolByAddress(self.as_ref().handle, addr, ptr::null_mut());
-
- if raw_sym.is_null() {
- return Err(());
- }
-
- Ok(Symbol::ref_from_raw(raw_sym))
- }
- }
-
- fn symbol_by_raw_name<S: BnStrCompatible>(&self, raw_name: S) -> Result<Ref<Symbol>> {
- let raw_name = raw_name.into_bytes_with_nul();
-
- unsafe {
- 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(());
- }
-
- Ok(Symbol::ref_from_raw(raw_sym))
- }
- }
-
- fn symbols(&self) -> Array<Symbol> {
- unsafe {
- let mut count = 0;
- let handles = BNGetSymbols(self.as_ref().handle, &mut count, ptr::null_mut());
-
- Array::new(handles, count, ())
- }
- }
-
- fn symbols_by_name<S: BnStrCompatible>(&self, name: S) -> Array<Symbol> {
- let raw_name = name.into_bytes_with_nul();
-
- 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(),
- );
-
- Array::new(handles, count, ())
- }
- }
-
- fn symbols_in_range(&self, range: ops::Range<u64>) -> Array<Symbol> {
- 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(),
- );
-
- Array::new(handles, count, ())
- }
- }
-
- 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());
-
- Array::new(handles, count, ())
- }
- }
-
- 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(),
- );
-
- Array::new(handles, count, ())
- }
- }
-
- fn define_auto_symbol(&self, sym: &Symbol) {
- 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,
- ) -> Result<Ref<Symbol>> {
- let raw_type = if let Some(t) = ty.into() {
- t.handle
- } else {
- ptr::null_mut()
- };
-
- unsafe {
- let raw_sym = BNDefineAutoSymbolAndVariableOrFunction(
- self.as_ref().handle,
- plat.handle,
- sym.handle,
- raw_type,
- );
-
- if raw_sym.is_null() {
- return Err(());
- }
-
- Ok(Symbol::ref_from_raw(raw_sym))
- }
- }
-
- fn undefine_auto_symbol(&self, sym: &Symbol) {
- unsafe {
- BNUndefineAutoSymbol(self.as_ref().handle, sym.handle);
- }
- }
-
- fn define_user_symbol(&self, sym: &Symbol) {
- unsafe {
- BNDefineUserSymbol(self.as_ref().handle, sym.handle);
- }
- }
-
- fn undefine_user_symbol(&self, sym: &Symbol) {
- unsafe {
- BNUndefineUserSymbol(self.as_ref().handle, sym.handle);
- }
- }
-
- fn data_variables(&self) -> Array<DataVariable> {
- unsafe {
- let mut count = 0;
- let vars = BNGetDataVariables(self.as_ref().handle, &mut count);
-
- Array::new(vars, count, ())
- }
- }
-
- fn data_variable_at_address(&self, addr: u64) -> Option<Ref<DataVariable>> {
- let dv = BNDataVariable::default();
- unsafe {
- if BNGetDataVariableAtAddress(self.as_ref().handle, addr, std::mem::transmute(&dv)) {
- Some(DataVariable(dv).to_owned())
- } else {
- None
- }
- }
- }
-
- fn define_auto_data_var<'a, T: Into<Conf<&'a Type>>>(&self, addr: u64, ty: T) {
- unsafe {
- BNDefineDataVariable(self.as_ref().handle, addr, &mut ty.into().into());
- }
- }
-
- /// You likely would also like to call [`Self::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) {
- unsafe {
- BNDefineUserDataVariable(self.as_ref().handle, addr, &mut ty.into().into());
- }
- }
-
- fn undefine_auto_data_var(&self, addr: u64, blacklist: Option<bool>) {
- unsafe {
- BNUndefineDataVariable(self.as_ref().handle, addr, blacklist.unwrap_or(true));
- }
- }
-
- fn undefine_user_data_var(&self, addr: u64) {
- unsafe {
- BNUndefineUserDataVariable(self.as_ref().handle, addr);
- }
- }
-
- fn define_auto_type<S: BnStrCompatible>(
- &self,
- name: S,
- source: S,
- type_obj: &Type,
- ) -> QualifiedName {
- let mut qualified_name = QualifiedName::from(name);
- let source_str = source.into_bytes_with_nul();
- let name_handle = unsafe {
- let id_str = BNGenerateAutoTypeId(
- source_str.as_ref().as_ptr() as *const _,
- &mut qualified_name.0,
- );
- BNDefineAnalysisType(
- self.as_ref().handle,
- id_str,
- &mut qualified_name.0,
- type_obj.handle,
- )
- };
- QualifiedName(name_handle)
- }
-
- fn define_auto_type_with_id<S: BnStrCompatible>(
- &self,
- name: S,
- id: S,
- type_obj: &Type,
- ) -> QualifiedName {
- let mut qualified_name = QualifiedName::from(name);
- let id_str = id.into_bytes_with_nul();
- let name_handle = unsafe {
- BNDefineAnalysisType(
- self.as_ref().handle,
- id_str.as_ref().as_ptr() as *const _,
- &mut qualified_name.0,
- type_obj.handle,
- )
- };
- QualifiedName(name_handle)
- }
-
- fn define_user_type<S: BnStrCompatible>(&self, name: S, type_obj: &Type) {
- let mut qualified_name = QualifiedName::from(name);
- unsafe {
- BNDefineUserAnalysisType(self.as_ref().handle, &mut qualified_name.0, type_obj.handle)
- }
- }
-
- fn define_auto_types<S: BnStrCompatible>(
- &self,
- names_sources_and_types: Vec<(S, S, &Type)>,
- progress: Option<Box<dyn Fn(usize, usize) -> Result<()>>>,
- ) -> HashMap<String, QualifiedName> {
- let mut names = vec![];
- let mut ids = vec![];
- let mut types = vec![];
- let mut api_types =
- Vec::<BNQualifiedNameTypeAndId>::with_capacity(names_sources_and_types.len());
- for (name, source, type_obj) in names_sources_and_types.into_iter() {
- names.push(QualifiedName::from(name));
- ids.push(source.into_bytes_with_nul());
- types.push(type_obj);
- }
-
- for ((name, source), type_obj) in names.iter().zip(ids.iter()).zip(types.iter()) {
- api_types.push(BNQualifiedNameTypeAndId {
- name: name.0,
- id: source.as_ref().as_ptr() as *mut _,
- type_: type_obj.handle,
- });
- }
-
- let mut progress_raw = ProgressContext(progress);
- let mut result_ids: *mut *mut c_char = ptr::null_mut();
- let mut result_names: *mut BNQualifiedName = ptr::null_mut();
- let result_count = unsafe {
- BNDefineAnalysisTypes(
- self.as_ref().handle,
- api_types.as_mut_ptr(),
- api_types.len(),
- Some(cb_progress),
- &mut progress_raw as *mut _ as *mut c_void,
- &mut result_ids as *mut _,
- &mut result_names as *mut _,
- )
- };
-
- let mut result = HashMap::with_capacity(result_count);
-
- let id_array = unsafe { Array::<BnString>::new(result_ids, result_count, ()) };
- let name_array = unsafe { Array::<QualifiedName>::new(result_names, result_count, ()) };
-
- for (id, name) in id_array.iter().zip(name_array.iter()) {
- result.insert(id.to_owned(), name.clone());
- }
-
- result
- }
-
- fn define_user_types<S: BnStrCompatible>(
- &self,
- names_and_types: Vec<(S, &Type)>,
- progress: Option<Box<dyn Fn(usize, usize) -> Result<()>>>,
- ) {
- let mut names = vec![];
- let mut types = vec![];
- let mut api_types = Vec::<BNQualifiedNameAndType>::with_capacity(names_and_types.len());
- for (name, type_obj) in names_and_types.into_iter() {
- names.push(QualifiedName::from(name));
- types.push(type_obj);
- }
-
- for (name, type_obj) in names.iter().zip(types.iter()) {
- api_types.push(BNQualifiedNameAndType {
- name: name.0,
- type_: type_obj.handle,
- });
- }
-
- let mut progress_raw = ProgressContext(progress);
- unsafe {
- BNDefineUserAnalysisTypes(
- self.as_ref().handle,
- api_types.as_mut_ptr(),
- api_types.len(),
- Some(cb_progress),
- &mut progress_raw as *mut _ as *mut c_void,
- )
- };
- }
-
- fn undefine_auto_type<S: BnStrCompatible>(&self, id: S) {
- let id_str = id.into_bytes_with_nul();
- unsafe {
- BNUndefineAnalysisType(self.as_ref().handle, id_str.as_ref().as_ptr() as *const _);
- }
- }
-
- fn undefine_user_type<S: BnStrCompatible>(&self, name: S) {
- let mut qualified_name = QualifiedName::from(name);
- unsafe { BNUndefineUserAnalysisType(self.as_ref().handle, &mut qualified_name.0) }
- }
-
- fn types(&self) -> Array<QualifiedNameAndType> {
- unsafe {
- let mut count = 0usize;
- let types = BNGetAnalysisTypeList(self.as_ref().handle, &mut count);
- Array::new(types, count, ())
- }
- }
-
- fn dependency_sorted_types(&self) -> Array<QualifiedNameAndType> {
- unsafe {
- let mut count = 0usize;
- let types = BNGetAnalysisDependencySortedTypeList(self.as_ref().handle, &mut count);
- Array::new(types, count, ())
- }
- }
-
- fn get_type_by_name<S: BnStrCompatible>(&self, name: S) -> Option<Ref<Type>> {
- unsafe {
- let mut qualified_name = QualifiedName::from(name);
- let type_handle = BNGetAnalysisTypeByName(self.as_ref().handle, &mut qualified_name.0);
- if type_handle.is_null() {
- return None;
- }
- Some(Type::ref_from_raw(type_handle))
- }
- }
-
- fn get_type_by_ref(&self, ref_: &NamedTypeReference) -> Option<Ref<Type>> {
- unsafe {
- let type_handle = BNGetAnalysisTypeByRef(self.as_ref().handle, ref_.handle);
- if type_handle.is_null() {
- return None;
- }
- Some(Type::ref_from_raw(type_handle))
- }
- }
-
- fn get_type_by_id<S: BnStrCompatible>(&self, id: S) -> Option<Ref<Type>> {
- unsafe {
- let id_str = id.into_bytes_with_nul();
- let type_handle =
- BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _);
- if type_handle.is_null() {
- return None;
- }
- Some(Type::ref_from_raw(type_handle))
- }
- }
-
- fn get_type_name_by_id<S: BnStrCompatible>(&self, id: S) -> Option<QualifiedName> {
- unsafe {
- let id_str = id.into_bytes_with_nul();
- let name_handle =
- BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _);
- let name = QualifiedName(name_handle);
- if name.strings().is_empty() {
- return None;
- }
- Some(name)
- }
- }
-
- fn get_type_id<S: BnStrCompatible>(&self, name: S) -> Option<BnString> {
- unsafe {
- let mut qualified_name = QualifiedName::from(name);
- let id_cstr = BNGetAnalysisTypeId(self.as_ref().handle, &mut qualified_name.0);
- let id = BnString::from_raw(id_cstr);
- if id.is_empty() {
- return None;
- }
- Some(id)
- }
- }
-
- fn is_type_auto_defined<S: BnStrCompatible>(&self, name: S) -> bool {
- unsafe {
- let mut qualified_name = QualifiedName::from(name);
- BNIsAnalysisTypeAutoDefined(self.as_ref().handle, &mut qualified_name.0)
- }
- }
-
- fn segments(&self) -> Array<Segment> {
- unsafe {
- let mut count = 0;
- let segs = BNGetSegments(self.as_ref().handle, &mut count);
-
- Array::new(segs, count, ())
- }
- }
-
- fn segment_at(&self, addr: u64) -> Option<Segment> {
- unsafe {
- let raw_seg = BNGetSegmentAt(self.as_ref().handle, addr);
- if !raw_seg.is_null() {
- Some(Segment::from_raw(raw_seg))
- } else {
- None
- }
- }
- }
-
- /// Adds a segment to the view.
- ///
- /// NOTE: Consider using [BinaryViewExt::begin_bulk_add_segments] and [BinaryViewExt::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) {
- segment.create(self.as_ref());
- }
-
- /// Start adding segments in bulk. Useful for adding large numbers of segments.
- ///
- /// After calling this any call to [BinaryViewExt::add_segment] will be uncommited until a call to
- /// [BinaryViewExt::end_bulk_add_segments]
- ///
- /// If you wish to discard the uncommited segments you can call [BinaryViewExt::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 uncommited.
- fn begin_bulk_add_segments(&self) {
- unsafe {
- BNBeginBulkAddSegments(self.as_ref().handle)
- }
- }
-
- /// Commit all auto and user segments that have been added since the call to [Self::begin_bulk_add_segments].
- ///
- /// 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)
- }
- }
-
- /// Flushes the auto and user segments that have yet to be committed.
- ///
- /// This is to be used in conjunction with [Self::begin_bulk_add_segments]
- /// 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)
- }
- }
-
-
- fn add_section<S: BnStrCompatible>(&self, section: SectionBuilder<S>) {
- section.create(self.as_ref());
- }
-
- fn remove_auto_section<S: BnStrCompatible>(&self, name: S) {
- let name = name.into_bytes_with_nul();
- let name_ptr = name.as_ref().as_ptr() as *mut _;
-
- unsafe {
- BNRemoveAutoSection(self.as_ref().handle, name_ptr);
- }
- }
-
- fn remove_user_section<S: BnStrCompatible>(&self, name: S) {
- let name = name.into_bytes_with_nul();
- let name_ptr = name.as_ref().as_ptr() as *mut _;
-
- unsafe {
- BNRemoveUserSection(self.as_ref().handle, name_ptr);
- }
- }
-
- fn section_by_name<S: BnStrCompatible>(&self, name: S) -> Result<Section> {
- unsafe {
- let raw_name = name.into_bytes_with_nul();
- 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() {
- return Err(());
- }
-
- Ok(Section::from_raw(raw_section))
- }
- }
-
- fn sections(&self) -> Array<Section> {
- unsafe {
- let mut count = 0;
- let sections = BNGetSections(self.as_ref().handle, &mut count);
-
- Array::new(sections, count, ())
- }
- }
-
- fn sections_at(&self, addr: u64) -> Array<Section> {
- unsafe {
- let mut count = 0;
- let sections = BNGetSectionsAt(self.as_ref().handle, addr, &mut count);
-
- Array::new(sections, count, ())
- }
- }
-
- fn add_auto_function(&self, plat: &Platform, addr: u64) -> Option<Ref<Function>> {
- unsafe {
- let handle = BNAddFunctionForAnalysis(
- self.as_ref().handle,
- plat.handle,
- addr,
- false,
- ptr::null_mut(),
- );
-
- if handle.is_null() {
- return None;
- }
-
- Some(Function::from_raw(handle))
- }
- }
-
- fn add_function_with_type(
- &self,
- plat: &Platform,
- addr: u64,
- auto_discovered: bool,
- func_type: Option<&Type>,
- ) -> Option<Ref<Function>> {
- unsafe {
- let func_type = match func_type {
- Some(func_type) => func_type.handle,
- None => ptr::null_mut(),
- };
-
- let handle = BNAddFunctionForAnalysis(
- self.as_ref().handle,
- plat.handle,
- addr,
- auto_discovered,
- func_type,
- );
-
- if handle.is_null() {
- return None;
- }
-
- Some(Function::from_raw(handle))
- }
- }
-
- fn add_entry_point(&self, plat: &Platform, addr: u64) {
- unsafe {
- BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr);
- }
- }
-
- fn create_user_function(&self, plat: &Platform, addr: u64) -> Result<Ref<Function>> {
- unsafe {
- let func = BNCreateUserFunction(self.as_ref().handle, plat.handle, addr);
-
- if func.is_null() {
- return Err(());
- }
-
- Ok(Function::from_raw(func))
- }
- }
-
- fn has_functions(&self) -> bool {
- unsafe { BNHasFunctions(self.as_ref().handle) }
- }
-
- fn entry_point_function(&self) -> Result<Ref<Function>> {
- unsafe {
- let func = BNGetAnalysisEntryPoint(self.as_ref().handle);
-
- if func.is_null() {
- return Err(());
- }
-
- Ok(Function::from_raw(func))
- }
- }
-
- fn entry_point_functions(&self) -> Array<Function> {
- unsafe {
- let mut count = 0;
- let functions = BNGetAllEntryFunctions(self.as_ref().handle, &mut count);
-
- Array::new(functions, count, ())
- }
- }
-
- fn functions(&self) -> Array<Function> {
- unsafe {
- let mut count = 0;
- let functions = BNGetAnalysisFunctionList(self.as_ref().handle, &mut count);
-
- Array::new(functions, count, ())
- }
- }
-
- /// List of functions *starting* at `addr`
- fn functions_at(&self, addr: u64) -> Array<Function> {
- unsafe {
- let mut count = 0;
- let functions =
- BNGetAnalysisFunctionsForAddress(self.as_ref().handle, addr, &mut count);
-
- Array::new(functions, count, ())
- }
- }
-
- // List of functions containing `addr`
- fn functions_containing(&self, addr: u64) -> Array<Function> {
- unsafe {
- let mut count = 0;
- let functions =
- BNGetAnalysisFunctionsContainingAddress(self.as_ref().handle, addr, &mut count);
-
- Array::new(functions, count, ())
- }
- }
-
- fn function_at(&self, platform: &Platform, addr: u64) -> Result<Ref<Function>> {
- unsafe {
- let handle = BNGetAnalysisFunction(self.as_ref().handle, platform.handle, addr);
-
- if handle.is_null() {
- return Err(());
- }
-
- Ok(Function::from_raw(handle))
- }
- }
-
- fn function_start_before(&self, addr: u64) -> u64 {
- unsafe { BNGetPreviousFunctionStartBeforeAddress(self.as_ref().handle, addr) }
- }
-
- fn function_start_after(&self, addr: u64) -> u64 {
- unsafe { BNGetNextFunctionStartAfterAddress(self.as_ref().handle, addr) }
- }
-
- 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);
-
- Array::new(blocks, count, NativeBlock::new())
- }
- }
-
- 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);
-
- Array::new(blocks, count, NativeBlock::new())
- }
- }
-
- fn is_new_auto_function_analysis_suppressed(&self) -> bool {
- unsafe { BNGetNewAutoFunctionAnalysisSuppressed(self.as_ref().handle) }
- }
-
- fn set_new_auto_function_analysis_suppressed(&self, suppress: bool) {
- 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 debug_info(&self) -> Ref<DebugInfo> {
- unsafe { DebugInfo::from_raw(BNGetDebugInfo(self.as_ref().handle)) }
- }
-
- fn set_debug_info(&self, debug_info: &DebugInfo) {
- unsafe { BNSetDebugInfo(self.as_ref().handle, debug_info.handle) }
- }
-
- fn apply_debug_info(&self, debug_info: &DebugInfo) {
- unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) }
- }
-
- fn show_graph_report<S: BnStrCompatible>(&self, raw_name: S, graph: &FlowGraph) {
- let raw_name = raw_name.into_bytes_with_nul();
- unsafe {
- BNShowGraphReport(
- self.as_ref().handle,
- raw_name.as_ref().as_ptr() as *mut _,
- graph.handle,
- );
- }
- }
-
- fn load_settings<S: BnStrCompatible>(&self, view_type_name: S) -> Result<Ref<Settings>> {
- let view_type_name = view_type_name.into_bytes_with_nul();
- let settings_handle = unsafe {
- BNBinaryViewGetLoadSettings(
- self.as_ref().handle,
- view_type_name.as_ref().as_ptr() as *mut _,
- )
- };
-
- if settings_handle.is_null() {
- Err(())
- } else {
- Ok(unsafe { Settings::from_raw(settings_handle) })
- }
- }
-
- fn set_load_settings<S: BnStrCompatible>(&self, view_type_name: S, settings: &Settings) {
- let view_type_name = view_type_name.into_bytes_with_nul();
-
- unsafe {
- BNBinaryViewSetLoadSettings(
- self.as_ref().handle,
- view_type_name.as_ref().as_ptr() as *mut _,
- settings.handle,
- )
- };
- }
-
- /// 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<N: BnStrCompatible, I: BnStrCompatible>(
- &self,
- name: N,
- icon: I,
- ) -> Ref<TagType> {
- let tag_type = TagType::create(self.as_ref(), name, icon);
- unsafe {
- BNAddTagType(self.as_ref().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) }
- }
-
- /// Get a tag type by its name.
- fn get_tag_type<S: BnStrCompatible>(&self, name: S) -> Option<Ref<TagType>> {
- let name = name.into_bytes_with_nul();
-
- unsafe {
- let handle = BNGetTagType(self.as_ref().handle, name.as_ref().as_ptr() as *mut _);
- if handle.is_null() {
- return None;
- }
- Some(TagType::from_raw(handle))
- }
- }
-
- /// Get a tag by its id.
- ///
- /// Note this does not tell you anything about where it is used.
- fn get_tag<S: BnStrCompatible>(&self, id: S) -> Option<Ref<Tag>> {
- let id = id.into_bytes_with_nul();
- unsafe {
- let handle = BNGetTag(self.as_ref().handle, id.as_ref().as_ptr() as *mut _);
- if handle.is_null() {
- return None;
- }
- Some(Tag::from_raw(handle))
- }
- }
-
- /// Creates and adds a tag to an address
- ///
- /// User tag creations will be added to the undo buffer
- fn add_tag<S: BnStrCompatible>(&self, addr: u64, t: &TagType, data: S, user: bool) {
- let tag = Tag::new(t, data);
-
- unsafe { BNAddTag(self.as_ref().handle, tag.handle, user) }
-
- if user {
- unsafe { BNAddUserDataTag(self.as_ref().handle, addr, tag.handle) }
- } else {
- unsafe { BNAddAutoDataTag(self.as_ref().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) }
- }
-
- /// 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) }
- }
-
- /// Retrieves a list of the next disassembly lines.
- ///
- /// `get_next_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the
- /// next disassembly lines, and updates the [LinearViewCursor] passed in. This function can be called
- /// repeatedly to get more lines of linear disassembly.
- ///
- /// # Arguments
- /// * `pos` - Position to retrieve linear disassembly lines from
- fn get_next_linear_disassembly_lines(
- &self,
- pos: &mut LinearViewCursor,
- ) -> Array<LinearDisassemblyLine> {
- let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) };
-
- while result.is_empty() {
- result = pos.lines();
- if !pos.next() {
- return result;
- }
- }
-
- result
- }
-
- /// Retrieves a list of the previous disassembly lines.
- ///
- /// `get_previous_linear_disassembly_lines` retrieves an [Array] over [LinearDisassemblyLine] objects for the
- /// previous disassembly lines, and updates the [LinearViewCursor] passed in. This function can be called
- /// repeatedly to get more lines of linear disassembly.
- ///
- /// # Arguments
- /// * `pos` - Position to retrieve linear disassembly lines relative to
- fn get_previous_linear_disassembly_lines(
- &self,
- pos: &mut LinearViewCursor,
- ) -> Array<LinearDisassemblyLine> {
- let mut result = unsafe { Array::new(std::ptr::null_mut(), 0, ()) };
- while result.is_empty() {
- if !pos.previous() {
- return result;
- }
-
- result = pos.lines();
- }
-
- result
- }
-
- fn query_metadata<S: BnStrCompatible>(&self, key: S) -> Option<Ref<Metadata>> {
- let value: *mut BNMetadata = unsafe {
- BNBinaryViewQueryMetadata(
- self.as_ref().handle,
- key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
- )
- };
- if value.is_null() {
- None
- } else {
- Some(unsafe { Metadata::ref_from_raw(value) })
- }
- }
-
- fn get_metadata<T, S: BnStrCompatible>(&self, key: S) -> Option<Result<T>>
- where
- T: for<'a> TryFrom<&'a Metadata>,
- {
- self.query_metadata(key)
- .map(|md| T::try_from(md.as_ref()).map_err(|_| ()))
- }
-
- fn store_metadata<V, S: BnStrCompatible>(&self, key: S, value: V, is_auto: bool)
- where
- V: Into<Ref<Metadata>>,
- {
- let md = value.into();
- unsafe {
- BNBinaryViewStoreMetadata(
- self.as_ref().handle,
- key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
- md.as_ref().handle,
- is_auto,
- )
- };
- }
-
- fn remove_metadata<S: BnStrCompatible>(&self, key: S) {
- unsafe {
- BNBinaryViewRemoveMetadata(
- self.as_ref().handle,
- key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
- )
- };
- }
-
- /// Retrieves a list of [CodeReference]s pointing to a given address.
- fn get_code_refs(&self, addr: u64) -> Array<CodeReference> {
- unsafe {
- let mut count = 0;
- let handle = BNGetCodeReferences(self.as_ref().handle, addr, &mut count);
- Array::new(handle, count, ())
- }
- }
-
- /// Retrieves a list of addresses pointed to by a given address.
- fn get_code_refs_from(&self, addr: u64, func: Option<&Function>) -> Vec<u64> {
- unsafe {
- let mut count = 0;
- // TODO: We could have done a [CodeReference] however it seems to be poorly written.
- // TODO: It uses manually drop on a ref that only gets dropped in the array, insane behavior.
- // TODO: For now just construct it manually.
- let mut src = BNReferenceSource {
- func: func.map(|f| f.handle).unwrap_or(std::ptr::null_mut()),
- arch: func.map(|f| f.arch().0).unwrap_or(std::ptr::null_mut()),
- addr,
- };
- let addresses = BNGetCodeReferencesFrom(self.as_ref().handle, &mut src, &mut count);
- let res = std::slice::from_raw_parts(addresses, count).to_vec();
- BNFreeAddressList(addresses);
- res
- }
- }
-
- /// Retrieves a list of [CodeReference]s pointing into a given [Range].
- fn get_code_refs_in_range(&self, range: Range<u64>) -> Array<CodeReference> {
- unsafe {
- let mut count = 0;
- let handle = BNGetCodeReferencesInRange(
- self.as_ref().handle,
- range.start,
- range.end - range.start,
- &mut count,
- );
- Array::new(handle, count, ())
- }
- }
-
- /// Retrieves a list of [DataReference]s pointing to a given address.
- fn get_data_refs(&self, addr: u64) -> Array<DataReference> {
- unsafe {
- let mut count = 0;
- let handle = BNGetDataReferences(self.as_ref().handle, addr, &mut count);
- Array::new(handle, count, ())
- }
- }
-
- /// Retrieves a list of [DataReference]s originating from a given address.
- fn get_data_refs_from(&self, addr: u64) -> Array<DataReference> {
- unsafe {
- let mut count = 0;
- let handle = BNGetDataReferencesFrom(self.as_ref().handle, addr, &mut count);
- Array::new(handle, count, ())
- }
- }
-
- /// Retrieves a list of [DataReference]s pointing into a given [Range].
- fn get_data_refs_in_range(&self, range: Range<u64>) -> Array<DataReference> {
- unsafe {
- let mut count = 0;
- let handle = BNGetDataReferencesInRange(
- self.as_ref().handle,
- range.start,
- range.end - range.start,
- &mut count,
- );
- Array::new(handle, count, ())
- }
- }
-
- /// Retrieves a list of [CodeReference]s for locations in code that use a given named type.
- ///
- /// TODO: It might be cleaner if this used an already allocated type from the core and
- /// used its name instead of this slightly-gross [QualifiedName] hack. Since the returned
- /// object doesn't have any [QualifiedName], I'm assuming the core does not alias
- /// the [QualifiedName] we pass to it and it is safe to destroy it on [Drop], as in this function.
- fn get_code_refs_for_type<B: BnStrCompatible>(&self, name: B) -> Array<CodeReference> {
- unsafe {
- let mut count = 0;
- let q_name = &mut QualifiedName::from(name).0;
- let handle = BNGetCodeReferencesForType(
- self.as_ref().handle,
- q_name as *mut BNQualifiedName,
- &mut count,
- );
- Array::new(handle, count, ())
- }
- }
- /// Retrieves a list of [DataReference]s instances of a given named type in data.
- ///
- /// TODO: It might be cleaner if this used an already allocated type from the core and
- /// used its name instead of this slightly-gross [QualifiedName] hack. Since the returned
- /// object doesn't have any [QualifiedName], I'm assuming the core does not alias
- /// the [QualifiedName] we pass to it and it is safe to destroy it on [Drop], as in this function.
- fn get_data_refs_for_type<B: BnStrCompatible>(&self, name: B) -> Array<DataReference> {
- unsafe {
- let mut count = 0;
- let q_name = &mut QualifiedName::from(name).0;
- let handle = BNGetDataReferencesForType(
- self.as_ref().handle,
- q_name as *mut BNQualifiedName,
- &mut count,
- );
- Array::new(handle, count, ())
- }
- }
-
- fn get_relocations_at(&self, addr: u64) -> Array<Relocation> {
- unsafe {
- let mut count = 0;
- let handle = BNGetRelocationsAt(self.as_ref().handle, addr, &mut count);
- Array::new(handle, count, ())
- }
- }
-
- fn get_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 ranges = std::slice::from_raw_parts(reloc_ranges_ptr, count).to_vec();
- BNFreeRelocationRanges(reloc_ranges_ptr);
- ranges
- };
-
- // TODO: impl From BNRange for Range?
- ranges
- .iter()
- .map(|range| Range {
- start: range.start,
- end: range.end,
- })
- .collect()
- }
-
- fn component_by_guid<S: BnStrCompatible>(&self, guid: S) -> Option<Component> {
- let name = guid.into_bytes_with_nul();
- let result = unsafe {
- BNGetComponentByGuid(
- self.as_ref().handle,
- name.as_ref().as_ptr() as *const core::ffi::c_char,
- )
- };
- core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) })
- }
-
- fn root_component(&self) -> Option<Component> {
- let result = unsafe { BNGetRootComponent(self.as_ref().handle) };
- core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) })
- }
-
- fn component_builder(&self) -> ComponentBuilder {
- ComponentBuilder::new_from_raw(self.as_ref().handle)
- }
-
- fn component_by_path<P: BnStrCompatible>(&self, path: P) -> Option<Component> {
- let path = path.into_bytes_with_nul();
- let result = unsafe {
- BNGetComponentByPath(
- self.as_ref().handle,
- path.as_ref().as_ptr() as *const core::ffi::c_char,
- )
- };
- core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) })
- }
-
- fn remove_component(&self, component: &Component) -> bool {
- unsafe { BNRemoveComponent(self.as_ref().handle, component.as_raw()) }
- }
-
- fn remove_component_by_guid<P: IntoComponentGuid>(&self, guid: P) -> bool {
- let path = guid.component_guid();
- unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) }
- }
-
- 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,
- )
- };
- 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()) }
- }
-
- fn type_library_by_name<S: BnStrCompatible>(&self, name: S) -> Option<TypeLibrary> {
- let name = name.into_bytes_with_nul();
- let result = unsafe {
- BNGetBinaryViewTypeLibrary(
- self.as_ref().handle,
- name.as_ref().as_ptr() as *const core::ffi::c_char,
- )
- };
- core::ptr::NonNull::new(result).map(|h| unsafe { TypeLibrary::from_raw(h) })
- }
-
- /// Should be called by custom py:py:class:`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].
- ///
- /// * `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(
- &self,
- lib: &TypeLibrary,
- name: &QualifiedName,
- addr: u64,
- platform: &Platform,
- ) {
- unsafe {
- BNBinaryViewRecordImportedObjectLibrary(
- self.as_ref().handle,
- platform.handle,
- addr,
- lib.as_raw(),
- &name.0 as *const _ as *mut _,
- )
- }
- }
-
- /// Recursively imports a type from the specified type library, or, if
- /// no library was explicitly provided, the first type library associated with the current [BinaryView]
- /// that provides the name requested.
- ///
- /// This may have the impact of loading other type libraries as dependencies on other type libraries are lazily resolved
- /// when references to types provided by them are first encountered.
- ///
- /// 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(
- &self,
- name: &QualifiedName,
- mut lib: Option<TypeLibrary>,
- ) -> Option<Ref<Type>> {
- let mut lib_ref = lib
- .as_mut()
- .map(|l| unsafe { l.as_raw() } as *mut _)
- .unwrap_or(ptr::null_mut());
- let result = unsafe {
- BNBinaryViewImportTypeLibraryType(
- self.as_ref().handle,
- &mut lib_ref,
- &name.0 as *const _ as *mut _,
- )
- };
- (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
- }
-
- /// Recursively imports an object from the specified type library, or, if
- /// no library was explicitly provided, the first type library associated with the current [BinaryView]
- /// that provides the name requested.
- ///
- /// This may have the impact of loading other type libraries as dependencies on other type 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 where the object is located.
- fn import_type_object(
- &self,
- name: &QualifiedName,
- mut lib: Option<TypeLibrary>,
- ) -> Option<Ref<Type>> {
- let mut lib_ref = lib
- .as_mut()
- .map(|l| unsafe { l.as_raw() } as *mut _)
- .unwrap_or(ptr::null_mut());
- let result = unsafe {
- BNBinaryViewImportTypeLibraryObject(
- self.as_ref().handle,
- &mut lib_ref,
- &name.0 as *const _ as *mut _,
- )
- };
- (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
- }
-
- /// Recursively imports a type interface given its GUID.
- ///
- /// .. note:: To support this type of lookup a type library must have
- /// contain a metadata key called "type_guids" which is a map
- /// Dict[string_guid, string_type_name] or
- /// Dict[string_guid, Tuple[string_type_name, type_library_name]]
- fn import_type_by_guid<S: BnStrCompatible>(&self, guid: S) -> Option<Ref<Type>> {
- let guid = guid.into_bytes_with_nul();
- let result = unsafe {
- BNBinaryViewImportTypeLibraryTypeByGuid(
- self.as_ref().handle,
- guid.as_ref().as_ptr() as *const c_char,
- )
- };
- (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) })
- }
-
- /// Recursively exports `type_obj` into `lib` as a type with name `name`
- ///
- /// 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(&self, lib: &TypeLibrary, name: &QualifiedName, type_obj: &Type) {
- unsafe {
- BNBinaryViewExportTypeToTypeLibrary(
- self.as_ref().handle,
- lib.as_raw(),
- &name.0 as *const _ as *mut _,
- type_obj.handle,
- )
- }
- }
-
- /// Recursively exports `type_obj` into `lib` as a type with name `name`
- ///
- /// 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(&self, lib: &TypeLibrary, name: &QualifiedName, type_obj: &Type) {
- unsafe {
- BNBinaryViewExportObjectToTypeLibrary(
- self.as_ref().handle,
- lib.as_raw(),
- &name.0 as *const _ as *mut _,
- type_obj.handle,
- )
- }
- }
-
- /// Gives you details of which type library and name was used to determine
- /// the type of a symbol at a given address
- ///
- /// * `addr` - address of symbol at import site
- /// * `platform` - Platform of symbol at import site
- fn lookup_imported_object_library(
- &self,
- addr: u64,
- platform: &Platform,
- ) -> Option<(TypeLibrary, QualifiedName)> {
- let mut result_lib = ptr::null_mut();
- let mut result_name = Default::default();
- let success = unsafe {
- BNBinaryViewLookupImportedObjectLibrary(
- self.as_ref().handle,
- platform.handle,
- addr,
- &mut result_lib,
- &mut result_name,
- )
- };
- if !success {
- return None;
- }
- let lib = unsafe { TypeLibrary::from_raw(ptr::NonNull::new(result_lib)?) };
- let name = QualifiedName(result_name);
- Some((lib, name))
- }
-
- /// 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(
- &self,
- name: &QualifiedNameAndType,
- ) -> Option<(TypeLibrary, QualifiedName)> {
- let mut result_lib = ptr::null_mut();
- let mut result_name = Default::default();
- let success = unsafe {
- BNBinaryViewLookupImportedTypeLibrary(
- self.as_ref().handle,
- &name.0 as *const _ as *mut _,
- &mut result_lib,
- &mut result_name,
- )
- };
- if !success {
- return None;
- }
- let lib = unsafe { TypeLibrary::from_raw(ptr::NonNull::new(result_lib)?) };
- let name = QualifiedName(result_name);
- Some((lib, name))
- }
-}
-
-impl<T: BinaryViewBase> BinaryViewExt for T {}
-
-#[derive(PartialEq, Eq, Hash)]
-pub struct BinaryView {
- pub(crate) handle: *mut BNBinaryView,
-}
-
-impl BinaryView {
- pub(crate) unsafe fn from_raw(handle: *mut BNBinaryView) -> Ref<Self> {
- debug_assert!(!handle.is_null());
-
- Ref::new(Self { handle })
- }
-
- pub fn from_filename<S: BnStrCompatible>(
- meta: &mut FileMetadata,
- filename: S,
- ) -> Result<Ref<Self>> {
- let file = filename.into_bytes_with_nul();
-
- let handle = unsafe {
- BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ref().as_ptr() as *mut _)
- };
-
- if handle.is_null() {
- return Err(());
- }
-
- unsafe { Ok(Ref::new(Self { handle })) }
- }
-
- pub fn from_accessor(meta: &FileMetadata, file: &mut FileAccessor) -> Result<Ref<Self>> {
- let handle =
- unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.api_object as *mut _) };
-
- if handle.is_null() {
- return Err(());
- }
-
- unsafe { Ok(Ref::new(Self { handle })) }
- }
-
- pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Result<Ref<Self>> {
- let handle = unsafe {
- BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len())
- };
-
- if handle.is_null() {
- return Err(());
- }
-
- unsafe { Ok(Ref::new(Self { handle })) }
- }
-}
-
-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()) }
- }
-
- fn write(&self, offset: u64, data: &[u8]) -> usize {
- unsafe { BNWriteViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
- }
-
- fn insert(&self, offset: u64, data: &[u8]) -> usize {
- unsafe { BNInsertViewData(self.handle, offset, data.as_ptr() as *const _, data.len()) }
- }
-
- fn remove(&self, offset: u64, len: usize) -> usize {
- unsafe { BNRemoveViewData(self.handle, offset, len as u64) }
- }
-
- fn modification_status(&self, offset: u64) -> ModificationStatus {
- unsafe { BNGetModification(self.handle, offset) }
- }
-
- fn offset_valid(&self, offset: u64) -> bool {
- unsafe { BNIsValidOffset(self.handle, offset) }
- }
-
- fn offset_readable(&self, offset: u64) -> bool {
- unsafe { BNIsOffsetReadable(self.handle, offset) }
- }
-
- fn offset_writable(&self, offset: u64) -> bool {
- unsafe { BNIsOffsetWritable(self.handle, offset) }
- }
-
- fn offset_executable(&self, offset: u64) -> bool {
- unsafe { BNIsOffsetExecutable(self.handle, offset) }
- }
-
- fn offset_backed_by_file(&self, offset: u64) -> bool {
- unsafe { BNIsOffsetBackedByFile(self.handle, offset) }
- }
-
- fn next_valid_offset_after(&self, offset: u64) -> u64 {
- unsafe { BNGetNextValidOffset(self.handle, offset) }
- }
-
- fn default_endianness(&self) -> Endianness {
- unsafe { BNGetDefaultEndianness(self.handle) }
- }
-
- fn relocatable(&self) -> bool {
- unsafe { BNIsRelocatable(self.handle) }
- }
-
- fn address_size(&self) -> usize {
- unsafe { BNGetViewAddressSize(self.handle) }
- }
-
- fn start(&self) -> u64 {
- unsafe { BNGetStartOffset(self.handle) }
- }
-
- fn len(&self) -> usize {
- unsafe { BNGetViewLength(self.handle) as usize }
- }
-
- fn entry_point(&self) -> u64 {
- unsafe { BNGetEntryPoint(self.handle) }
- }
-
- fn executable(&self) -> bool {
- unsafe { BNIsExecutableView(self.handle) }
- }
-}
-
-unsafe impl RefCountable for BinaryView {
- unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
- Ref::new(Self {
- handle: BNNewViewReference(handle.handle),
- })
- }
-
- unsafe fn dec_ref(handle: &Self) {
- BNFreeBinaryView(handle.handle);
- }
-}
-
-impl AsRef<BinaryView> for BinaryView {
- fn as_ref(&self) -> &Self {
- self
- }
-}
-
-impl ToOwned for BinaryView {
- type Owned = Ref<Self>;
-
- fn to_owned(&self) -> Self::Owned {
- unsafe { RefCountable::inc_ref(self) }
- }
-}
-
-unsafe impl Send for BinaryView {}
-unsafe impl Sync for BinaryView {}
-
-impl std::fmt::Debug for BinaryView {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(
- f,
- "BinaryView (type: `{}`): '{}', len {:#x}",
- self.view_type(),
- self.file().filename(),
- self.len()
- )
- }
-}
-
-pub trait BinaryViewEventHandler: 'static + Sync {
- fn on_event(&self, binary_view: &BinaryView);
-}
-
-pub type BinaryViewEventType = BNBinaryViewEventType;
-
-/// Registers an event listener for binary view events.
-///
-/// # Example
-///
-/// ```no_run
-/// use binaryninja::binaryview::{BinaryView, BinaryViewEventHandler, BinaryViewEventType, register_binary_view_event};
-///
-/// struct EventHandlerContext {
-/// // Context holding state available to event handler
-/// }
-///
-/// impl BinaryViewEventHandler for EventHandlerContext {
-/// fn on_event(&self, binary_view: &BinaryView) {
-/// // handle event
-/// }
-/// }
-///
-/// #[no_mangle]
-/// pub extern "C" fn CorePluginInit() {
-/// let context = EventHandlerContext { };
-///
-/// register_binary_view_event(
-/// BinaryViewEventType::BinaryViewInitialAnalysisCompletionEvent,
-/// context,
-/// );
-/// }
-/// ```
-pub fn register_binary_view_event<Handler>(event_type: BinaryViewEventType, handler: Handler)
-where
- Handler: BinaryViewEventHandler,
-{
- unsafe extern "C" fn on_event<Handler: BinaryViewEventHandler>(
- ctx: *mut ::std::os::raw::c_void,
- view: *mut BNBinaryView,
- ) {
- ffi_wrap!("EventHandler::on_event", {
- let context = unsafe { &*(ctx as *const Handler) };
- context.on_event(&BinaryView::from_raw(BNNewViewReference(view)));
- })
- }
-
- let boxed = Box::new(handler);
- let raw = Box::into_raw(boxed);
-
- unsafe {
- BNRegisterBinaryViewEvent(
- event_type,
- Some(on_event::<Handler>),
- raw as *mut ::std::os::raw::c_void,
- );
- }
-}