summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
authorBrian Potchik <brian@vector35.com>2026-03-11 12:12:36 -0400
committerBrian Potchik <brian@vector35.com>2026-03-11 12:12:36 -0400
commit6b57ef1d2c82d263655364588546e6211b0a99a8 (patch)
tree83593089f530368b6d83905fc32858f8251904dc /rust/src
parentb8fdf800de345f93b2e68713d14bac425a62feb3 (diff)
Enhance MemoryMap bindings and add support to re-enable disabled regions in the UI.
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/binary_view.rs2
-rw-r--r--rust/src/binary_view/memory_map.rs205
2 files changed, 203 insertions, 4 deletions
diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs
index 93819098..bd26dad3 100644
--- a/rust/src/binary_view.rs
+++ b/rust/src/binary_view.rs
@@ -68,7 +68,7 @@ pub mod reader;
pub mod search;
pub mod writer;
-pub use memory_map::MemoryMap;
+pub use memory_map::{MemoryMap, MemoryRegionInfo, ResolvedRange};
pub use reader::BinaryReader;
pub use writer::BinaryWriter;
diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs
index bb7902b9..44bb58c6 100644
--- a/rust/src/binary_view/memory_map.rs
+++ b/rust/src/binary_view/memory_map.rs
@@ -3,10 +3,101 @@ use crate::data_buffer::DataBuffer;
use crate::file_accessor::{Accessor, FileAccessor};
use crate::rc::Ref;
use crate::segment::SegmentFlags;
-use crate::string::{BnString, IntoCStr};
+use crate::string::{raw_to_string, BnString, IntoCStr};
use binaryninjacore_sys::*;
-/// MemoryMap provides access to the system-level memory map describing how a BinaryView is loaded into memory.
+/// Snapshot of a memory region's properties at the time of query.
+///
+/// This is a value type — modifying the memory map will not update existing
+/// `MemoryRegionInfo` instances. To mutate a region, use the corresponding
+/// [`MemoryMap`] methods.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemoryRegionInfo {
+ pub name: String,
+ pub display_name: String,
+ pub start: u64,
+ pub length: u64,
+ pub flags: SegmentFlags,
+ pub enabled: bool,
+ pub rebaseable: bool,
+ pub fill: u8,
+ pub has_target: bool,
+ pub absolute_address_mode: bool,
+ pub local: bool,
+}
+
+impl MemoryRegionInfo {
+ pub fn end(&self) -> u64 {
+ self.start + self.length
+ }
+
+ fn from_raw(region: &BNMemoryRegionInfo) -> Self {
+ Self {
+ name: raw_to_string(region.name).unwrap_or_default(),
+ display_name: raw_to_string(region.displayName).unwrap_or_default(),
+ start: region.start,
+ length: region.length,
+ flags: SegmentFlags::from_raw(region.flags),
+ enabled: region.enabled,
+ rebaseable: region.rebaseable,
+ fill: region.fill,
+ has_target: region.hasTarget,
+ absolute_address_mode: region.absoluteAddressMode,
+ local: region.local,
+ }
+ }
+}
+
+/// A resolved, non-overlapping address range in the memory map.
+///
+/// Each range contains an ordered list of memory regions that overlap at this
+/// interval. The first region is the active (highest priority) one.
+///
+/// This is a snapshot value — it is not updated by later mutations to the
+/// memory map.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ResolvedRange {
+ pub start: u64,
+ pub length: u64,
+ pub regions: Vec<MemoryRegionInfo>,
+}
+
+impl ResolvedRange {
+ pub fn end(&self) -> u64 {
+ self.start + self.length
+ }
+
+ /// The highest-priority region at this range.
+ pub fn active_region(&self) -> Option<&MemoryRegionInfo> {
+ self.regions.first()
+ }
+
+ /// Name of the active region, or `None` if empty.
+ pub fn name(&self) -> Option<&str> {
+ self.active_region().map(|r| r.name.as_str())
+ }
+
+ /// Flags of the active (highest-priority) region.
+ pub fn flags(&self) -> SegmentFlags {
+ self.active_region()
+ .map(|r| r.flags)
+ .unwrap_or(SegmentFlags::from_raw(0))
+ }
+}
+
+/// Live proxy to the memory map of a [`BinaryView`].
+///
+/// A `MemoryMap` describes how a [`BinaryView`] is loaded into memory. It
+/// contains *regions* — raw, possibly overlapping memory definitions — and
+/// exposes *resolved ranges* — a computed, disjoint view of the address space
+/// produced by splitting overlapping regions. The most recently added region
+/// takes precedence when regions overlap. Mutation is always by region name.
+///
+/// - [`regions()`](Self::regions) returns configured memory regions, including
+/// disabled ones.
+/// - [`ranges()`](Self::ranges) returns resolved, non-overlapping address
+/// ranges — the computed active view.
+/// - Both return snapshot values that are not updated after later mutations.
///
/// # Architecture Note
///
@@ -22,6 +113,13 @@ use binaryninjacore_sys::*;
/// A MemoryMap can contain multiple, arbitrarily overlapping memory regions. When modified, address space
/// segmentation is automatically managed. If multiple regions overlap, the most recently added region takes
/// precedence by default.
+///
+/// All MemoryMap APIs support undo and redo operations. During BinaryView::Init, these APIs should be used
+/// conditionally:
+///
+/// * Initial load: Use the MemoryMap APIs to define the memory regions that compose the system.
+/// * Database load: Do not use the MemoryMap APIs, as the regions are already persisted and will be restored
+/// automatically.
#[derive(PartialEq, Eq, Hash)]
pub struct MemoryMap {
view: Ref<BinaryView>,
@@ -32,7 +130,106 @@ impl MemoryMap {
Self { view }
}
- // TODO: There does not seem to be a way to enumerate memory regions.
+ /// Returns a snapshot of all configured memory regions, including disabled ones.
+ pub fn regions(&self) -> Vec<MemoryRegionInfo> {
+ let mut count: usize = 0;
+ let regions_raw = unsafe { BNGetMemoryRegions(self.view.handle, &mut count) };
+ if regions_raw.is_null() {
+ return Vec::new();
+ }
+ let mut result = Vec::with_capacity(count);
+ for i in 0..count {
+ let region = unsafe { &*regions_raw.add(i) };
+ result.push(MemoryRegionInfo::from_raw(region));
+ }
+ unsafe { BNFreeMemoryRegions(regions_raw, count) };
+ result
+ }
+
+ /// Returns a snapshot of the resolved, non-overlapping address ranges.
+ ///
+ /// Each range contains an ordered list of memory regions, with the first
+ /// being the active (highest priority) region at that interval.
+ pub fn ranges(&self) -> Vec<ResolvedRange> {
+ let mut count: usize = 0;
+ let ranges_raw = unsafe { BNGetResolvedMemoryRanges(self.view.handle, &mut count) };
+ if ranges_raw.is_null() {
+ return Vec::new();
+ }
+ let mut result = Vec::with_capacity(count);
+ for i in 0..count {
+ let range = unsafe { &*ranges_raw.add(i) };
+ let mut regions = Vec::with_capacity(range.regionCount);
+ for j in 0..range.regionCount {
+ let region = unsafe { &*range.regions.add(j) };
+ regions.push(MemoryRegionInfo::from_raw(region));
+ }
+ result.push(ResolvedRange {
+ start: range.start,
+ length: range.length,
+ regions,
+ });
+ }
+ unsafe { BNFreeResolvedMemoryRanges(ranges_raw, count) };
+ result
+ }
+
+ /// Look up a configured memory region by name.
+ ///
+ /// Returns a snapshot of the region's properties, or `None` if no region
+ /// with the given name exists.
+ pub fn get_region(&self, name: &str) -> Option<MemoryRegionInfo> {
+ let name_raw = name.to_cstr();
+ let mut result: BNMemoryRegionInfo = unsafe { std::mem::zeroed() };
+ let found = unsafe {
+ BNGetMemoryRegionInfo(self.view.handle, name_raw.as_ptr(), &mut result)
+ };
+ if !found {
+ return None;
+ }
+ let info = MemoryRegionInfo::from_raw(&result);
+ unsafe { BNFreeMemoryRegionInfo(&mut result) };
+ Some(info)
+ }
+
+ /// Return the active region snapshot covering `addr`, or `None` if no
+ /// enabled region covers the address.
+ pub fn get_active_region_at(&self, addr: u64) -> Option<MemoryRegionInfo> {
+ let mut result: BNMemoryRegionInfo = unsafe { std::mem::zeroed() };
+ let found = unsafe {
+ BNGetActiveMemoryRegionInfoAt(self.view.handle, addr, &mut result)
+ };
+ if !found {
+ return None;
+ }
+ let info = MemoryRegionInfo::from_raw(&result);
+ unsafe { BNFreeMemoryRegionInfo(&mut result) };
+ Some(info)
+ }
+
+ /// Return the resolved range snapshot covering `addr`, or `None` if no
+ /// range covers the address.
+ pub fn get_resolved_range_at(&self, addr: u64) -> Option<ResolvedRange> {
+ let mut result: BNResolvedMemoryRange = unsafe { std::mem::zeroed() };
+ let found = unsafe {
+ BNGetResolvedMemoryRangeAt(self.view.handle, addr, &mut result)
+ };
+ if !found {
+ return None;
+ }
+ let mut regions = Vec::with_capacity(result.regionCount);
+ for j in 0..result.regionCount {
+ let region = unsafe { &*result.regions.add(j) };
+ regions.push(MemoryRegionInfo::from_raw(region));
+ }
+ let resolved = ResolvedRange {
+ start: result.start,
+ length: result.length,
+ regions,
+ };
+ unsafe { BNFreeResolvedMemoryRange(&mut result) };
+ Some(resolved)
+ }
/// JSON string representation of the base [`MemoryMap`], consisting of unresolved auto and user segments.
pub fn base_description(&self) -> String {
@@ -169,6 +366,8 @@ impl MemoryMap {
unsafe { BNRemoveMemoryRegion(self.view.handle, name_raw.as_ptr()) }
}
+ /// Return the name of the active region at `addr`, or an empty string if
+ /// no region covers the address.
pub fn active_memory_region_at(&self, addr: u64) -> String {
unsafe {
let name_raw = BNGetActiveMemoryRegionAt(self.view.handle, addr);