diff options
| author | Mason Reed <mason@vector35.com> | 2026-02-22 17:08:21 -0800 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2026-02-23 00:09:44 -0800 |
| commit | b18bdad6c94a8e234108d531f0c480c7104abebe (patch) | |
| tree | b0edb86cfae52c37635ef0b5cac491220bc3ef24 /rust/src | |
| parent | dbd54d67a6d523f64615f653d82d8224cd09870a (diff) | |
[Rust] Misc documentation and cleanup
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/binary_view.rs | 107 | ||||
| -rw-r--r-- | rust/src/custom_binary_view.rs | 18 | ||||
| -rw-r--r-- | rust/src/file_metadata.rs | 172 | ||||
| -rw-r--r-- | rust/src/main_thread.rs | 8 | ||||
| -rw-r--r-- | rust/src/types/printer.rs | 1 | ||||
| -rw-r--r-- | rust/src/workflow.rs | 227 |
6 files changed, 218 insertions, 315 deletions
diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 25ec6d48..93819098 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -12,14 +12,7 @@ // 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 +//! A view on binary data and queryable interface of a binary files analysis. use binaryninjacore_sys::*; @@ -104,6 +97,7 @@ pub trait BinaryViewBase: AsRef<BinaryView> { 0 } + /// Check if the offset is valid for the current view. fn offset_valid(&self, offset: u64) -> bool { let mut buf = [0u8; 1]; @@ -112,22 +106,28 @@ pub trait BinaryViewBase: AsRef<BinaryView> { self.as_ref().read(&mut buf[..], offset) == buf.len() } + /// Check if the offset is readable for the current view. fn offset_readable(&self, offset: u64) -> bool { self.offset_valid(offset) } + /// Check if the offset is writable for the current view. fn offset_writable(&self, offset: u64) -> bool { self.offset_valid(offset) } + /// Check if the offset is executable for the current view. fn offset_executable(&self, offset: u64) -> bool { self.offset_valid(offset) } + /// Check if the offset is backed by the original file and not added after the fact. fn offset_backed_by_file(&self, offset: u64) -> bool { self.offset_valid(offset) } + /// Get the next valid offset after the provided `offset`, useful if you need to iterate over all + /// readable offsets in the view. fn next_valid_offset_after(&self, offset: u64) -> u64 { let start = self.as_ref().start(); @@ -138,15 +138,17 @@ pub trait BinaryViewBase: AsRef<BinaryView> { } } - #[allow(unused)] - fn modification_status(&self, offset: u64) -> ModificationStatus { + /// Whether the data at the given `offset` been modified (patched). + fn modification_status(&self, _offset: u64) -> ModificationStatus { ModificationStatus::Original } + /// The lowest address in the view. fn start(&self) -> u64 { 0 } + /// The length of the view. fn len(&self) -> u64 { 0 } @@ -546,8 +548,6 @@ pub trait BinaryViewExt: BinaryViewBase { } /// The highest address in the view. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::end`]. fn end(&self) -> u64 { unsafe { BNGetEndOffset(self.as_ref().handle) } } @@ -2454,6 +2454,26 @@ pub trait BinaryViewExt: BinaryViewBase { impl<T: BinaryViewBase> BinaryViewExt for T {} +/// Represents the "whole view" of the binary and its analysis. +/// +/// Analysis information: +/// +/// - [`BinaryViewExt::functions`] +/// - [`BinaryViewExt::data_variables`] +/// - [`BinaryViewExt::strings`] +/// +/// Annotation information: +/// +/// - [`BinaryViewExt::symbols`] +/// - [`BinaryViewExt::tags_all_scopes`] +/// - [`BinaryViewExt::comments`] +/// +/// Data representation and binary information: +/// +/// - [`BinaryViewExt::types`] +/// - [`BinaryViewExt::segments`] +/// - [`BinaryViewExt::sections`] +/// /// # Cleaning up /// /// [`BinaryView`] has a cyclic relationship with the associated [`FileMetadata`], each holds a strong @@ -2476,9 +2496,10 @@ impl BinaryView { Ref::new(Self { handle }) } - /// Construct the raw binary view from the given metadata. Before calling this make sure you have - /// a valid file path set for the [`FileMetadata`]. It is required that the [`FileMetadata::file_path`] - /// exist on the local filesystem. + /// Construct the raw binary view from the given metadata. + /// + /// Before calling this, make sure you have a valid file path set for the [`FileMetadata`]. It is + /// required that the [`FileMetadata::file_path`] exist in the local filesystem. pub fn from_metadata(meta: &FileMetadata) -> Result<Ref<Self>> { if !meta.file_path().exists() { return Err(()); @@ -2486,11 +2507,9 @@ impl BinaryView { let file = meta.file_path().to_cstr(); let handle = unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) }; - if handle.is_null() { return Err(()); } - unsafe { Ok(Ref::new(Self { handle })) } } @@ -2503,29 +2522,34 @@ impl BinaryView { Self::from_metadata(meta) } - pub fn from_accessor<A: Accessor>( + // TODO: Provide an API that manages the lifetime of the accessor and the view. + /// Construct the raw binary view from the given `accessor` and metadata. + /// + /// It is the responsibility of the caller to keep the accessor alive for the lifetime of the view; + /// because of this, we mark the function as unsafe. + pub unsafe fn from_accessor<A: Accessor>( meta: &FileMetadata, - file: &mut FileAccessor<A>, + accessor: &mut FileAccessor<A>, ) -> Result<Ref<Self>> { - let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.raw) }; - + let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut accessor.raw) }; if handle.is_null() { return Err(()); } - unsafe { Ok(Ref::new(Self { handle })) } } - pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Result<Ref<Self>> { + /// Construct the raw binary view from the given `data` and metadata. + /// + /// The data will be copied into the view, so the caller does not need to keep the data alive. + pub fn from_data(meta: &FileMetadata, data: &[u8]) -> Ref<Self> { let handle = unsafe { BNCreateBinaryDataViewFromData(meta.handle, data.as_ptr() as *mut _, data.len()) }; - - if handle.is_null() { - return Err(()); - } - - unsafe { Ok(Ref::new(Self { handle })) } + assert!( + !handle.is_null(), + "BNCreateBinaryDataViewFromData should always succeed" + ); + unsafe { Ref::new(Self { handle }) } } /// Save the original binary file to the provided `file_path` along with any modifications. @@ -2571,45 +2595,26 @@ impl BinaryViewBase for BinaryView { unsafe { BNRemoveViewData(self.handle, offset, len as u64) } } - /// Check if the offset is valid for the current view. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_valid`]. fn offset_valid(&self, offset: u64) -> bool { unsafe { BNIsValidOffset(self.handle, offset) } } - /// Check if the offset is readable for the current view. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_valid`]. fn offset_readable(&self, offset: u64) -> bool { unsafe { BNIsOffsetReadable(self.handle, offset) } } - /// Check if the offset is writable for the current view. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_writable`]. fn offset_writable(&self, offset: u64) -> bool { unsafe { BNIsOffsetWritable(self.handle, offset) } } - /// Check if the offset is executable for the current view. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_executable`]. fn offset_executable(&self, offset: u64) -> bool { unsafe { BNIsOffsetExecutable(self.handle, offset) } } - /// Check if the offset is backed by the original file and not added after the fact. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::is_offset_backed_by_file`]. fn offset_backed_by_file(&self, offset: u64) -> bool { unsafe { BNIsOffsetBackedByFile(self.handle, offset) } } - /// Get the next valid offset after the provided `offset`, useful if you need to iterate over all - /// readable offsets in the view. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::next_valid_offset`]. fn next_valid_offset_after(&self, offset: u64) -> u64 { unsafe { BNGetNextValidOffset(self.handle, offset) } } @@ -2618,16 +2623,10 @@ impl BinaryViewBase for BinaryView { unsafe { BNGetModification(self.handle, offset) } } - /// The lowest address in the view. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::start`]. fn start(&self) -> u64 { unsafe { BNGetStartOffset(self.handle) } } - /// The length of the view, lowest to highest address. - /// - /// NOTE: If operating within a [`Workflow`], consider using [`AnalysisContext::length`]. fn len(&self) -> u64 { unsafe { BNGetViewLength(self.handle) } } diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs index 4cd49931..4d21ce89 100644 --- a/rust/src/custom_binary_view.rs +++ b/rust/src/custom_binary_view.rs @@ -178,12 +178,23 @@ where } 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 } @@ -319,6 +330,9 @@ pub trait BinaryViewTypeExt: BinaryViewTypeBase { 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, @@ -338,7 +352,9 @@ impl BinaryViewType { } } - pub fn list_valid_types_for(data: &BinaryView) -> Array<BinaryViewType> { + /// 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 _); diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index bb783158..5862647f 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! The [`FileMetadata`] struct provides information about a file and owns its available [`BinaryView`]s. + use crate::binary_view::BinaryView; use crate::database::Database; use crate::rc::*; @@ -22,12 +24,90 @@ use std::ffi::c_void; use std::fmt::{Debug, Display, Formatter}; use std::path::{Path, PathBuf}; -use crate::progress::ProgressCallback; +use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; -use std::ptr::{self, NonNull}; +use std::ptr::NonNull; + +#[allow(unused_imports)] +use crate::custom_binary_view::BinaryViewType; new_id_type!(SessionId, usize); +pub type SaveOption = BNSaveOption; + +/// Settings to alter the behavior of creating snapshots saved within a [`Database`]. +pub struct SaveSettings { + pub(crate) handle: *mut BNSaveSettings, +} + +impl SaveSettings { + pub fn new() -> Ref<Self> { + Self::ref_from_raw(unsafe { BNCreateSaveSettings() }) + } + + fn ref_from_raw(handle: *mut BNSaveSettings) -> Ref<Self> { + unsafe { Ref::new(Self { handle }) } + } + + /// Sets the specified `option` to `true` and returns a ref counted `SaveSettings` that can + /// continued to be chained. + pub fn with_option(&self, option: SaveOption) -> Ref<Self> { + self.set_option(option, true); + self.to_owned() + } + + pub fn set_option(&self, option: SaveOption, value: bool) { + unsafe { BNSetSaveSettingsOption(self.handle, option, value) } + } + + pub fn option(&self, option: SaveOption) -> bool { + unsafe { BNIsSaveSettingsOptionSet(self.handle, option) } + } + + /// When saving an automatic snapshot via [`FileMetadata::save_auto_snapshot`] this name will be + /// used for the newly written snapshot. + pub fn snapshot_name(&self) -> String { + unsafe { BnString::into_string(BNGetSaveSettingsName(self.handle)) } + } + + pub fn set_snapshot_name(&self, name: &str) { + let name = name.to_cstr(); + unsafe { BNSetSaveSettingsName(self.handle, name.as_ptr()) } + } +} + +unsafe impl Send for SaveSettings {} +unsafe impl Sync for SaveSettings {} + +impl ToOwned for SaveSettings { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +unsafe impl RefCountable for SaveSettings { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewSaveSettingsReference(handle.handle), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeSaveSettings(handle.handle); + } +} + +/// File metadata provides information about a file in the context of Binary Ninja. It contains no +/// analysis information, only information useful for identifying a file, such as the [`FileMetadata::file_path`]. +/// +/// Another responsibility of the [`FileMetadata`] is to own the available [`BinaryView`]s for the +/// file, such as the "Raw" view and any other views that may be created for the file. +/// +/// **Important**: Because [`FileMetadata`] holds a strong reference to the [`BinaryView`]s and those +/// views hold a strong reference to the file metadata, to end the cyclic reference a call to the +/// [`FileMetadata::close`] is required. #[derive(PartialEq, Eq, Hash)] pub struct FileMetadata { pub(crate) handle: *mut BNFileMetadata, @@ -42,12 +122,14 @@ impl FileMetadata { unsafe { Ref::new(Self { handle }) } } + /// Create an empty [`FileMetadata`] with no associated file path. + /// + /// Unless you are creating an ephemeral file with no backing, prefer [`FileMetadata::with_file_path`]. pub fn new() -> Ref<Self> { Self::ref_from_raw(unsafe { BNCreateFileMetadata() }) } - /// Build a [`FileMetadata`] with the given `path`, this is uncommon as you are likely to want to - /// open a [`BinaryView`] + /// Build a [`FileMetadata`] with the given `path`. pub fn with_file_path(path: &Path) -> Ref<Self> { let ret = FileMetadata::new(); ret.set_file_path(path); @@ -61,6 +143,7 @@ impl FileMetadata { } } + /// An id unique to this [`FileMetadata`], mostly used for associating logs with a specific file. pub fn session_id(&self) -> SessionId { let raw = unsafe { BNFileMetadataGetSessionId(self.handle) }; SessionId(raw) @@ -187,16 +270,23 @@ impl FileMetadata { } } + /// Whether the file is currently flagged as modified. + /// + /// When this returns `true`, the UI will prompt to save the database on close, as well as display + /// a dot in the files tab. pub fn is_modified(&self) -> bool { unsafe { BNIsFileModified(self.handle) } } + /// Marks the file as modified such that we can prompt to save the database on close. pub fn mark_modified(&self) { unsafe { BNMarkFileModified(self.handle); } } + /// Marks the file as saved such that [`FileMetadata::is_modified`] and [`FileMetadata::is_analysis_changed`] + /// will return `false` and the undo buffer associated with this [`FileMetadata`] will be updated. pub fn mark_saved(&self) { unsafe { BNMarkFileSaved(self.handle); @@ -207,13 +297,19 @@ impl FileMetadata { unsafe { BNIsAnalysisChanged(self.handle) } } + /// Checks to see if the database exists for the file. pub fn is_database_backed(&self) -> bool { + // TODO: This seems to be a useless function. Replace with a call to file.database().is_some()? self.is_database_backed_for_view_type("") } + /// Checks to see if the file metadata has a [`Database`], and then checks to see if the `view_type` + /// is available. + /// + /// NOTE: Passing an empty string will simply check if the database exists. pub fn is_database_backed_for_view_type(&self, view_type: &str) -> bool { let view_type = view_type.to_cstr(); - + // TODO: This seems to be a useless function. Replace with a call to file.database().is_some()? unsafe { BNIsBackedByDatabase(self.handle, view_type.as_ref().as_ptr() as *const _) } } @@ -310,10 +406,23 @@ impl FileMetadata { } } + /// Retrieve the raw view for the file, this should always be present. + /// + /// The "Raw" view is a special [`BinaryView`] that holds data required for updating and creating + /// [`Database`]s such as the view and load settings. + pub fn raw_view(&self) -> Ref<BinaryView> { + self.view_of_type("Raw") + .expect("Raw view should always be present") + } + + /// The current view for the file. + /// + /// For example, opening a PE file and navigating to the linear view will return "Linear:PE". pub fn current_view(&self) -> String { unsafe { BnString::into_string(BNGetCurrentView(self.handle)) } } + /// The current offset navigated to within the [`FileMetadata::current_view`]. pub fn current_offset(&self) -> u64 { unsafe { BNGetCurrentOffset(self.handle) } } @@ -360,6 +469,9 @@ impl FileMetadata { } } + /// The [`BinaryViewType`]s associated with this file. + /// + /// For example, opening a PE binary will have the following: "Raw", "PE". pub fn view_types(&self) -> Array<BnString> { let mut count = 0; unsafe { @@ -376,32 +488,26 @@ impl FileMetadata { } } - pub fn create_database(&self, file_path: impl AsRef<Path>) -> bool { - // Databases are created with the root view (Raw). - let Some(raw_view) = self.view_of_type("Raw") else { - return false; - }; - - let file_path = file_path.as_ref().to_cstr(); - unsafe { - BNCreateDatabase( - raw_view.handle, - file_path.as_ptr() as *mut _, - ptr::null_mut(), - ) - } + /// Create a database for the file and its views at `file_path`. + /// + /// NOTE: Calling this while analysis is running will flag the next load of the database to + /// regenerate the current analysis. + pub fn create_database(&self, file_path: impl AsRef<Path>, settings: &SaveSettings) -> bool { + self.create_database_with_progress(file_path, settings, NoProgressCallback) } - // TODO: Pass settings? + /// Create a database for the file and its views at `file_path`, with a progress callback. + /// + /// NOTE: Calling this while analysis is running will flag the next load of the database to + /// regenerate the current analysis. pub fn create_database_with_progress<P: ProgressCallback>( &self, file_path: impl AsRef<Path>, + settings: &SaveSettings, mut progress: P, ) -> bool { // Databases are created with the root view (Raw). - let Some(raw_view) = self.view_of_type("Raw") else { - return false; - }; + let raw_view = self.raw_view(); let file_path = file_path.as_ref().to_cstr(); unsafe { BNCreateDatabaseWithProgress( @@ -409,20 +515,22 @@ impl FileMetadata { file_path.as_ptr() as *mut _, &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), - ptr::null_mut(), + settings.handle, ) } } + /// Save a new snapshot of the current file. + /// + /// NOTE: Calling this while analysis is running will flag the next load of the database to + /// regenerate the current analysis. pub fn save_auto_snapshot(&self) -> bool { // Snapshots are saved with the root view (Raw). - let Some(raw_view) = self.view_of_type("Raw") else { - return false; - }; - - unsafe { BNSaveAutoSnapshot(raw_view.handle, ptr::null_mut() as *mut _) } + let raw_view = self.raw_view(); + unsafe { BNSaveAutoSnapshot(raw_view.handle, std::ptr::null_mut() as *mut _) } } + // TODO: Deprecate this function? Does not seem to do anything different than `open_database`. pub fn open_database_for_configuration(&self, file: &Path) -> Result<Ref<BinaryView>, ()> { let file = file.to_cstr(); unsafe { @@ -437,6 +545,7 @@ impl FileMetadata { } } + // TODO: How this relates to `BNLoadFilename`? pub fn open_database(&self, file: &Path) -> Result<Ref<BinaryView>, ()> { let file = file.to_cstr(); let view = unsafe { BNOpenExistingDatabase(self.handle, file.as_ptr()) }; @@ -448,6 +557,7 @@ impl FileMetadata { } } + // TODO: How this relates to `BNLoadFilename`? pub fn open_database_with_progress<P: ProgressCallback>( &self, file: &Path, @@ -471,7 +581,9 @@ impl FileMetadata { } } - /// Get the current database + /// Get the database attached to this file. + /// + /// Only available if this file is a database, or has called [`FileMetadata::create_database`]. pub fn database(&self) -> Option<Ref<Database>> { let result = unsafe { BNGetFileMetadataDatabase(self.handle) }; NonNull::new(result).map(|handle| unsafe { Database::ref_from_raw(handle) }) diff --git a/rust/src/main_thread.rs b/rust/src/main_thread.rs index f6fdc7cf..cf4c37f1 100644 --- a/rust/src/main_thread.rs +++ b/rust/src/main_thread.rs @@ -21,9 +21,9 @@ impl MainThreadActionExecutor { } } -/// Execute passed function on the main thread. Returns `None` if already running on the main thread. +/// Execute the passed function on the main thread. Returns `None` if already running on the main thread. /// -/// When not running in headless this will block the UI. +/// When not running in headless, this will block the UI. pub fn execute_on_main_thread<F: Fn() + 'static>(f: F) -> Option<Ref<MainThreadAction>> { let boxed_executor = Box::new(MainThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); @@ -39,9 +39,9 @@ pub fn execute_on_main_thread<F: Fn() + 'static>(f: F) -> Option<Ref<MainThreadA } } -/// Execute passed function on the main thread and wait until the function is finished. +/// Execute the passed function on the main thread and wait until the function is finished. /// -/// When not running in headless this will block the UI. +/// When not running in headless, this will block the UI. pub fn execute_on_main_thread_and_wait<F: Fn() + 'static>(f: F) { let boxed_executor = Box::new(MainThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); diff --git a/rust/src/types/printer.rs b/rust/src/types/printer.rs index d168434e..51845df7 100644 --- a/rust/src/types/printer.rs +++ b/rust/src/types/printer.rs @@ -338,6 +338,7 @@ impl CoreTypePrinter { raw_names.as_mut_ptr(), raw_types.as_mut_ptr(), raw_types.len(), + // TODO: Add a print_all_types that accepts a set of type containers. data.handle, padding_cols as c_int, escaping, diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index d06890f1..e53e0001 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -5,15 +5,13 @@ use binaryninjacore_sys::*; use crate::binary_view::{memory_map::MemoryMap, BinaryViewBase, BinaryViewExt}; use crate::basic_block::BasicBlock; -use crate::binary_view::{AddressRange, BinaryView}; +use crate::binary_view::BinaryView; use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; use crate::high_level_il::HighLevelILFunction; use crate::low_level_il::{LowLevelILMutableFunction, LowLevelILRegularFunction}; use crate::medium_level_il::MediumLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::section::Section; -use crate::segment::{Segment, SegmentFlags}; use crate::string::{BnString, IntoCStr}; use std::ffi::c_char; use std::ptr; @@ -131,229 +129,6 @@ impl AnalysisContext { blocks.iter().map(|block| block.handle).collect(); unsafe { BNSetBasicBlockList(self.handle.as_ptr(), blocks_raw.as_mut_ptr(), blocks.len()) } } - - // Settings cache access - lock-free access to cached settings - - /// Get a boolean setting from the cached settings - pub fn get_setting_bool(&self, key: &str) -> bool { - let key = key.to_cstr(); - unsafe { BNAnalysisContextGetSettingBool(self.handle.as_ptr(), key.as_ptr()) } - } - - /// Get a double setting from the cached settings - pub fn get_setting_double(&self, key: &str) -> f64 { - let key = key.to_cstr(); - unsafe { BNAnalysisContextGetSettingDouble(self.handle.as_ptr(), key.as_ptr()) } - } - - /// Get a signed 64-bit integer setting from the cached settings - pub fn get_setting_int64(&self, key: &str) -> i64 { - let key = key.to_cstr(); - unsafe { BNAnalysisContextGetSettingInt64(self.handle.as_ptr(), key.as_ptr()) } - } - - /// Get an unsigned 64-bit integer setting from the cached settings - pub fn get_setting_uint64(&self, key: &str) -> u64 { - let key = key.to_cstr(); - unsafe { BNAnalysisContextGetSettingUInt64(self.handle.as_ptr(), key.as_ptr()) } - } - - /// Get a string setting from the cached settings - pub fn get_setting_string(&self, key: &str) -> BnString { - let key = key.to_cstr(); - unsafe { - let result = BNAnalysisContextGetSettingString(self.handle.as_ptr(), key.as_ptr()); - BnString::from_raw(result) - } - } - - /// Get a string list setting from the cached settings - pub fn get_setting_string_list(&self, key: &str) -> Array<BnString> { - let key = key.to_cstr(); - unsafe { - let mut count = 0; - let result = BNAnalysisContextGetSettingStringList( - self.handle.as_ptr(), - key.as_ptr(), - &mut count, - ); - Array::new(result, count, ()) - } - } - - /// Check if an offset is mapped in the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryView::offset_valid`]. - pub fn is_offset_valid(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsValidOffset(self.handle.as_ptr(), offset) } - } - - /// Check if an offset is readable in the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryView::offset_readable`]. - pub fn is_offset_readable(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetReadable(self.handle.as_ptr(), offset) } - } - - /// Check if an offset is writable in the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryView::offset_writable`]. - pub fn is_offset_writable(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetWritable(self.handle.as_ptr(), offset) } - } - - /// Check if an offset is executable in the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryView::offset_executable`]. - pub fn is_offset_executable(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetExecutable(self.handle.as_ptr(), offset) } - } - - /// Check if an offset is backed by file in the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryView::offset_backed_by_file`]. - pub fn is_offset_backed_by_file(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetBackedByFile(self.handle.as_ptr(), offset) } - } - - /// Check if an offset has code semantics in the cached section map. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::offset_has_code_semantics`]. - pub fn is_offset_code_semantics(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetCodeSemantics(self.handle.as_ptr(), offset) } - } - - /// Check if an offset has external semantics in the cached section map. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::offset_has_extern_semantics`]. - pub fn is_offset_extern_semantics(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetExternSemantics(self.handle.as_ptr(), offset) } - } - - /// Check if an offset has writable semantics in the cached section map. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::offset_has_writable_semantics`]. - pub fn is_offset_writable_semantics(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetWritableSemantics(self.handle.as_ptr(), offset) } - } - - /// Check if an offset has read-only semantics in the cached section map. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::offset_has_read_only_semantics`]. - pub fn is_offset_readonly_semantics(&self, offset: u64) -> bool { - unsafe { BNAnalysisContextIsOffsetReadOnlySemantics(self.handle.as_ptr(), offset) } - } - - /// Get all sections from the cached section map. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::sections`]. - pub fn sections(&self) -> Array<Section> { - unsafe { - let mut count = 0; - let sections = BNAnalysisContextGetSections(self.handle.as_ptr(), &mut count); - Array::new(sections, count, ()) - } - } - - /// Get a section by name from the cached section map. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::section_by_name`]. - pub fn section_by_name(&self, name: impl IntoCStr) -> Option<Ref<Section>> { - unsafe { - let raw_name = name.to_cstr(); - let name_ptr = raw_name.as_ptr(); - let raw_section_ptr = BNAnalysisContextGetSectionByName(self.handle.as_ptr(), name_ptr); - match raw_section_ptr.is_null() { - false => Some(Section::ref_from_raw(raw_section_ptr)), - true => None, - } - } - } - - /// Get all sections containing the given address from the cached section map. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::sections_at`]. - pub fn sections_at(&self, addr: u64) -> Array<Section> { - unsafe { - let mut count = 0; - let sections = BNAnalysisContextGetSectionsAt(self.handle.as_ptr(), addr, &mut count); - Array::new(sections, count, ()) - } - } - - /// Get the start address (the lowest address) from the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryView::start`]. - pub fn start(&self) -> u64 { - unsafe { BNAnalysisContextGetStart(self.handle.as_ptr()) } - } - - /// Get the end address (the highest address) from the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::end`]. - pub fn end(&self) -> u64 { - unsafe { BNAnalysisContextGetEnd(self.handle.as_ptr()) } - } - - /// Get the length of the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewBase::len`]. - pub fn length(&self) -> u64 { - unsafe { BNAnalysisContextGetLength(self.handle.as_ptr()) } - } - - /// Get the next valid offset after the given offset from the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryView::next_valid_offset_after`]. - pub fn next_valid_offset(&self, offset: u64) -> u64 { - unsafe { BNAnalysisContextGetNextValidOffset(self.handle.as_ptr(), offset) } - } - - /// Get the next mapped address after the given address from the cached [`MemoryMap`]. - pub fn next_mapped_address(&self, addr: u64, flags: &SegmentFlags) -> u64 { - unsafe { - BNAnalysisContextGetNextMappedAddress(self.handle.as_ptr(), addr, flags.into_raw()) - } - } - - /// Get the next backed address after the given address from the cached [`MemoryMap`]. - pub fn next_backed_address(&self, addr: u64, flags: &SegmentFlags) -> u64 { - unsafe { - BNAnalysisContextGetNextBackedAddress(self.handle.as_ptr(), addr, flags.into_raw()) - } - } - - /// Get the segment containing the given address from the cached [`MemoryMap`]. - /// - /// NOTE: This is a lock-free alternative to [`BinaryViewExt::segment_at`]. - pub fn segment_at(&self, addr: u64) -> Option<Ref<Segment>> { - unsafe { - let result = BNAnalysisContextGetSegmentAt(self.handle.as_ptr(), addr); - if result.is_null() { - None - } else { - Some(Segment::ref_from_raw(result)) - } - } - } - - /// Get all mapped address ranges from the cached [`MemoryMap`]. - pub fn mapped_address_ranges(&self) -> Array<AddressRange> { - unsafe { - let mut count = 0; - let ranges = BNAnalysisContextGetMappedAddressRanges(self.handle.as_ptr(), &mut count); - Array::new(ranges, count, ()) - } - } - - /// Get all backed address ranges from the cached [`MemoryMap`]. - pub fn backed_address_ranges(&self) -> Array<AddressRange> { - unsafe { - let mut count = 0; - let ranges = BNAnalysisContextGetBackedAddressRanges(self.handle.as_ptr(), &mut count); - Array::new(ranges, count, ()) - } - } } impl ToOwned for AnalysisContext { |
