diff options
| author | Mason Reed <mason@vector35.com> | 2025-11-23 17:58:37 -0500 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2025-11-23 18:18:08 -0500 |
| commit | cd6747223935581ae422a9825a389d89f329b5fd (patch) | |
| tree | 02ad7e5afc5a97f97670deb0dac9b047a1b351d7 /rust | |
| parent | 979ba310a3489eddb5403fcdcf596e8fca4e1569 (diff) | |
[Rust] Clarify and expand on the current set of queryable offset properties
Now that we have more duplicate API's we need to clarify and cross link between them to help alleviate the confusion for readers.
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/src/binary_view.rs | 87 | ||||
| -rw-r--r-- | rust/src/function.rs | 42 | ||||
| -rw-r--r-- | rust/src/workflow.rs | 104 |
3 files changed, 146 insertions, 87 deletions
diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 593c1c4b..4fb07ded 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -23,6 +23,10 @@ use binaryninjacore_sys::*; +// Used for documentation +#[allow(unused)] +pub use crate::workflow::AnalysisContext; + use crate::architecture::{Architecture, CoreArchitecture}; use crate::base_detection::BaseAddressDetection; use crate::basic_block::BasicBlock; @@ -447,14 +451,29 @@ pub trait BinaryViewExt: BinaryViewBase { } } + /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the + /// offset has code semantics. fn offset_has_code_semantics(&self, offset: u64) -> bool { unsafe { BNIsOffsetCodeSemantics(self.as_ref().handle, offset) } } + /// Check if the offset is within a [`Section`] with [`crate::section::Semantics::External`]. + fn offset_has_extern_semantics(&self, offset: u64) -> bool { + unsafe { BNIsOffsetExternSemantics(self.as_ref().handle, offset) } + } + + /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the + /// offset has writable semantics. fn offset_has_writable_semantics(&self, offset: u64) -> bool { unsafe { BNIsOffsetWritableSemantics(self.as_ref().handle, offset) } } + /// Consults the [`Section`]'s current [`crate::section::Semantics`] to determine if the + /// offset has read only semantics. + fn offset_has_read_only_semantics(&self, offset: u64) -> bool { + unsafe { BNIsOffsetExternSemantics(self.as_ref().handle, offset) } + } + fn image_base(&self) -> u64 { unsafe { BNGetImageBase(self.as_ref().handle) } } @@ -467,6 +486,9 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNSetOriginalImageBase(self.as_ref().handle, image_base) } } + /// 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) } } @@ -2371,26 +2393,45 @@ 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) } } @@ -2399,10 +2440,16 @@ 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) } } @@ -2582,3 +2629,43 @@ unsafe impl CoreArrayProviderInner for StringReference { Self::from(*raw) } } + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct AddressRange { + pub start: u64, + pub end: u64, +} + +impl From<BNAddressRange> for AddressRange { + fn from(raw: BNAddressRange) -> Self { + Self { + start: raw.start, + end: raw.end, + } + } +} + +impl From<AddressRange> for BNAddressRange { + fn from(raw: AddressRange) -> Self { + Self { + start: raw.start, + end: raw.end, + } + } +} + +impl CoreArrayProvider for AddressRange { + type Raw = BNAddressRange; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for AddressRange { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeAddressRanges(raw); + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::from(*raw) + } +} diff --git a/rust/src/function.rs b/rust/src/function.rs index c0e00bd1..80de8e6d 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -38,6 +38,7 @@ pub use binaryninjacore_sys::BNFunctionUpdateType as FunctionUpdateType; pub use binaryninjacore_sys::BNHighlightStandardColor as HighlightStandardColor; use crate::architecture::RegisterId; +use crate::binary_view::AddressRange; use crate::confidence::Conf; use crate::high_level_il::HighLevelILFunction; use crate::language_representation::CoreLanguageRepresentationFunction; @@ -373,7 +374,6 @@ impl Function { unsafe { let mut count = 0; let addresses = BNGetFunctionAddressRanges(self.handle, &mut count); - Array::new(addresses, count, ()) } } @@ -2684,46 +2684,6 @@ impl PartialEq for Function { } } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct AddressRange { - pub start: u64, - pub end: u64, -} - -impl From<BNAddressRange> for AddressRange { - fn from(raw: BNAddressRange) -> Self { - Self { - start: raw.start, - end: raw.end, - } - } -} - -impl From<AddressRange> for BNAddressRange { - fn from(raw: AddressRange) -> Self { - Self { - start: raw.start, - end: raw.end, - } - } -} - -impl CoreArrayProvider for AddressRange { - type Raw = BNAddressRange; - type Context = (); - type Wrapped<'a> = Self; -} - -unsafe impl CoreArrayProviderInner for AddressRange { - unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { - BNFreeAddressRanges(raw); - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::from(*raw) - } -} - #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct PerformanceInfo { pub name: String, diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index 2fd02e09..adc8d4ba 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -1,14 +1,18 @@ use binaryninjacore_sys::*; +// Needed for documentation. +#[allow(unused)] +use crate::binary_view::{memory_map::MemoryMap, BinaryViewBase, BinaryViewExt}; + use crate::basic_block::BasicBlock; -use crate::binary_view::BinaryView; +use crate::binary_view::{AddressRange, 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::segment::Segment; +use crate::segment::{Segment, SegmentFlags}; use crate::string::{BnString, IntoCStr}; use std::ffi::c_char; use std::ptr; @@ -176,65 +180,87 @@ impl AnalysisContext { } } - // Memory map access - lock-free access to cached MemoryMap - - /// Check if an offset is mapped in the cached memory map - pub fn is_valid_offset(&self, offset: u64) -> bool { + /// 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 memory map + /// 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 memory map + /// 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 memory map + /// 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 memory map + /// 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) } } - /// Get the start address from the cached memory map - pub fn get_start(&self) -> u64 { + /// 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 from the cached memory map - pub fn get_end(&self) -> u64 { + /// Get the end address (the highest address) from the cached [`MemoryMap`]. + /// + /// NOTE: This is a lock-free alternative to [`BinaryViewBase::end`]. + pub fn end(&self) -> u64 { unsafe { BNAnalysisContextGetEnd(self.handle.as_ptr()) } } - /// Get the length of the cached memory map - pub fn get_length(&self) -> u64 { + /// 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 memory map - pub fn get_next_valid_offset(&self, offset: u64) -> u64 { + /// 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 memory map - pub fn get_next_mapped_address(&self, addr: u64, flags: u32) -> u64 { - unsafe { BNAnalysisContextGetNextMappedAddress(self.handle.as_ptr(), addr, flags) } + /// 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 memory map - pub fn get_next_backed_address(&self, addr: u64, flags: u32) -> u64 { - unsafe { BNAnalysisContextGetNextBackedAddress(self.handle.as_ptr(), addr, flags) } + /// 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 memory map - pub fn get_segment_at(&self, addr: u64) -> Option<Ref<Segment>> { + /// Get the segment containing the given address from the cached [`MemoryMap`]. + /// + /// NOTE: This is a lock-free alternative to [`BinaryView::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() { @@ -245,35 +271,21 @@ impl AnalysisContext { } } - /// Get all mapped address ranges from the cached memory map - pub fn get_mapped_address_ranges(&self) -> Vec<(u64, u64)> { + /// 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); - let result = (0..count) - .map(|i| { - let range = *ranges.add(i); - (range.start, range.end) - }) - .collect(); - BNFreeAddressRanges(ranges); - result + Array::new(ranges, count, ()) } } - /// Get all backed address ranges from the cached memory map - pub fn get_backed_address_ranges(&self) -> Vec<(u64, u64)> { + /// 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); - let result = (0..count) - .map(|i| { - let range = *ranges.add(i); - (range.start, range.end) - }) - .collect(); - BNFreeAddressRanges(ranges); - result + Array::new(ranges, count, ()) } } } |
