summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2026-02-22 17:08:21 -0800
committerMason Reed <35282038+emesare@users.noreply.github.com>2026-02-23 00:09:44 -0800
commitb18bdad6c94a8e234108d531f0c480c7104abebe (patch)
treeb0edb86cfae52c37635ef0b5cac491220bc3ef24 /rust/src
parentdbd54d67a6d523f64615f653d82d8224cd09870a (diff)
[Rust] Misc documentation and cleanup
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/binary_view.rs107
-rw-r--r--rust/src/custom_binary_view.rs18
-rw-r--r--rust/src/file_metadata.rs172
-rw-r--r--rust/src/main_thread.rs8
-rw-r--r--rust/src/types/printer.rs1
-rw-r--r--rust/src/workflow.rs227
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 {