summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h76
-rw-r--r--binaryninjacore.h26
-rw-r--r--python/binaryview.py34
-rw-r--r--python/workflow.py198
-rw-r--r--rust/src/binary_view/memory_map.rs28
-rw-r--r--rust/src/workflow.rs147
-rw-r--r--workflow.cpp154
7 files changed, 659 insertions, 4 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index fa8ec3e4..ea5c9feb 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -8129,6 +8129,22 @@ namespace BinaryNinja {
std::optional<std::pair<std::string, BNStringType>> StringifyUnicodeData(Architecture* arch, const DataBuffer& buffer, bool nullTerminates = true, bool allowShortStrings = false);
};
+ /*! MemoryMap provides access to the system-level memory map describing how a BinaryView is loaded into memory.
+
+ \note Architecture: This API-side MemoryMap class is a proxy that accesses the BinaryView's current
+ MemoryMap state through the core API. The proxy provides a simple mutable interface: when you call
+ modification operations (AddMemoryRegion, RemoveMemoryRegion, etc.), the proxy automatically accesses
+ the updated MemoryMap. Internally, the core uses immutable copy-on-write data structures, but the proxy
+ abstracts this away.
+
+ When you access a BinaryView's MemoryMap, you always see the current state. For lock-free access during
+ analysis, AnalysisContext provides memory layout query methods (IsValidOffset, IsOffsetReadable, GetStart,
+ GetLength, etc.) that operate on an immutable snapshot of the MemoryMap cached when the analysis was initiated.
+
+ 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.
+ */
class MemoryMap
{
BNBinaryView* m_object;
@@ -8142,6 +8158,22 @@ namespace BinaryNinja {
BNSetLogicalMemoryMapEnabled(m_object, enabled);
}
+ /*! Returns true if this MemoryMap represents a parsed BinaryView with real segments.
+
+ This is determined by whether the BinaryView has a parent view - parsed views
+ (ELF, PE, Mach-O, etc.) have a parent Raw view, while Raw views have no parent.
+
+ Returns true for parsed BinaryViews (ELF, PE, Mach-O, etc.) with segments from
+ binary format parsing. Returns false for Raw BinaryViews (flat file view with
+ synthetic MemoryMap) or views that failed to parse segments.
+
+ Use this to gate features that require parsed binary structure (sections, imports,
+ relocations, etc.). For basic analysis queries (GetStart, IsOffsetReadable,
+ GetLength, etc.), use the MemoryMap directly regardless of activation state - all
+ BinaryViews have a usable MemoryMap.
+
+ \return True if this is an activated (parsed) memory map, false otherwise
+ */
bool IsActivated()
{
return BNIsMemoryMapActivated(m_object);
@@ -11420,8 +11452,52 @@ namespace BinaryNinja {
request.Accept(writer);
return Inform(buffer.GetString());
}
+
+ // Settings cache access - lock-free access to cached settings
+ /*! Get a setting value from the cached settings
+
+ \code{.cpp}
+ bool enabled = analysisContext->GetSetting<bool>("analysis.conservative");
+ \endcode
+
+ \tparam T type for the value you are retrieving
+ \param key Key for the setting
+ \return Value for the setting, with type T
+ */
+ template <typename T>
+ T GetSetting(const std::string& key);
+
+ // Memory map access - lock-free access to cached MemoryMap
+ bool IsValidOffset(uint64_t offset);
+ bool IsOffsetReadable(uint64_t offset);
+ bool IsOffsetWritable(uint64_t offset);
+ bool IsOffsetExecutable(uint64_t offset);
+ bool IsOffsetBackedByFile(uint64_t offset);
+ uint64_t GetStart();
+ uint64_t GetEnd();
+ uint64_t GetLength();
+ uint64_t GetNextValidOffset(uint64_t offset);
+ uint64_t GetNextMappedAddress(uint64_t addr, uint32_t flags = 0);
+ uint64_t GetNextBackedAddress(uint64_t addr, uint32_t flags = 0);
+ Ref<Segment> GetSegmentAt(uint64_t addr);
+ std::vector<BNAddressRange> GetMappedAddressRanges();
+ std::vector<BNAddressRange> GetBackedAddressRanges();
};
+ // Explicit template specialization declarations for AnalysisContext::GetSetting<T>
+ template <>
+ bool AnalysisContext::GetSetting<bool>(const std::string& key);
+ template <>
+ double AnalysisContext::GetSetting<double>(const std::string& key);
+ template <>
+ int64_t AnalysisContext::GetSetting<int64_t>(const std::string& key);
+ template <>
+ uint64_t AnalysisContext::GetSetting<uint64_t>(const std::string& key);
+ template <>
+ std::string AnalysisContext::GetSetting<std::string>(const std::string& key);
+ template <>
+ std::vector<std::string> AnalysisContext::GetSetting<std::vector<std::string>>(const std::string& key);
+
/*!
\ingroup workflow
*/
diff --git a/binaryninjacore.h b/binaryninjacore.h
index b0248d52..763dce0e 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -37,7 +37,7 @@
// Current ABI version for linking to the core. This is incremented any time
// there are changes to the API that affect linking, including new functions,
// new types, or modifications to existing functions or types.
-#define BN_CURRENT_CORE_ABI_VERSION 147
+#define BN_CURRENT_CORE_ABI_VERSION 148
// Minimum ABI version that is supported for loading of plugins. Plugins that
// are linked to an ABI version less than this will not be able to load and
@@ -5930,6 +5930,30 @@ extern "C"
BNAnalysisContext* analysisContext, BNHighLevelILFunction* highLevelIL);
BINARYNINJACOREAPI bool BNAnalysisContextInform(BNAnalysisContext* analysisContext, const char* request);
+ // Settings cache access
+ BINARYNINJACOREAPI bool BNAnalysisContextGetSettingBool(BNAnalysisContext* analysisContext, const char* key);
+ BINARYNINJACOREAPI double BNAnalysisContextGetSettingDouble(BNAnalysisContext* analysisContext, const char* key);
+ BINARYNINJACOREAPI int64_t BNAnalysisContextGetSettingInt64(BNAnalysisContext* analysisContext, const char* key);
+ BINARYNINJACOREAPI uint64_t BNAnalysisContextGetSettingUInt64(BNAnalysisContext* analysisContext, const char* key);
+ BINARYNINJACOREAPI char* BNAnalysisContextGetSettingString(BNAnalysisContext* analysisContext, const char* key);
+ BINARYNINJACOREAPI char** BNAnalysisContextGetSettingStringList(BNAnalysisContext* analysisContext, const char* key, size_t* count);
+
+ // Memory map access
+ BINARYNINJACOREAPI bool BNAnalysisContextIsValidOffset(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetReadable(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetWritable(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetExecutable(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetBackedByFile(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI uint64_t BNAnalysisContextGetStart(BNAnalysisContext* analysisContext);
+ BINARYNINJACOREAPI uint64_t BNAnalysisContextGetEnd(BNAnalysisContext* analysisContext);
+ BINARYNINJACOREAPI uint64_t BNAnalysisContextGetLength(BNAnalysisContext* analysisContext);
+ BINARYNINJACOREAPI uint64_t BNAnalysisContextGetNextValidOffset(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI uint64_t BNAnalysisContextGetNextMappedAddress(BNAnalysisContext* analysisContext, uint64_t addr, uint32_t flags);
+ BINARYNINJACOREAPI uint64_t BNAnalysisContextGetNextBackedAddress(BNAnalysisContext* analysisContext, uint64_t addr, uint32_t flags);
+ BINARYNINJACOREAPI BNSegment* BNAnalysisContextGetSegmentAt(BNAnalysisContext* analysisContext, uint64_t addr);
+ BINARYNINJACOREAPI BNAddressRange* BNAnalysisContextGetMappedAddressRanges(BNAnalysisContext* analysisContext, size_t* count);
+ BINARYNINJACOREAPI BNAddressRange* BNAnalysisContextGetBackedAddressRanges(BNAnalysisContext* analysisContext, size_t* count);
+
// Activity
BINARYNINJACOREAPI BNActivity* BNCreateActivity(const char* configuration, void* ctxt, void (*action)(void*, BNAnalysisContext*));
BINARYNINJACOREAPI BNActivity* BNCreateActivityWithEligibility(const char* configuration, void* ctxt, void (*action)(void*, BNAnalysisContext*), bool (*eligibilityHandler)(void*, BNActivity*, BNAnalysisContext*));
diff --git a/python/binaryview.py b/python/binaryview.py
index d0d20405..4170302b 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -2457,8 +2457,19 @@ class AdvancedILFunctionList:
class MemoryMap:
r"""
- The MemoryMap object describes a system-level memory map into which a BinaryView is loaded. Each BinaryView
- exposes its portion of the MemoryMap through the Segments defined within that view.
+ The MemoryMap object provides access to the system-level memory map describing how a BinaryView is loaded
+ into memory. Each BinaryView exposes its portion of the MemoryMap through the Segments defined within that view.
+
+ **Architecture Note:** This Python MemoryMap object is a proxy that accesses the BinaryView's current
+ MemoryMap state through the FFI boundary. The proxy provides a simple mutable interface: when you call
+ modification operations (``add_memory_region``, ``remove_memory_region``, etc.), the proxy automatically
+ accesses the updated MemoryMap. Internally, the core uses immutable copy-on-write data structures, but
+ the proxy abstracts this away.
+
+ When you access ``view.memory_map``, you always see the current state. For lock-free access during analysis,
+ AnalysisContext provides memory layout query methods (``is_valid_offset()``, ``is_offset_readable()``,
+ ``get_start()``, ``get_length()``, etc.) that operate on an immutable snapshot of the MemoryMap cached when
+ the analysis was initiated.
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
@@ -2615,7 +2626,24 @@ class MemoryMap:
@property
def is_activated(self):
- """Whether the memory map is activated for the associated view."""
+ """
+ Whether the memory map is activated for the associated view.
+
+ Returns ``True`` if this MemoryMap represents a parsed BinaryView with real segments
+ (ELF, PE, Mach-O, etc.). Returns ``False`` for Raw BinaryViews or views that failed
+ to parse segments.
+
+ This is determined by whether the BinaryView has a parent view - parsed views have a
+ parent Raw view, while Raw views have no parent.
+
+ Use this to gate features that require parsed binary structure (sections, imports,
+ relocations, etc.). For basic analysis queries (start, length, is_offset_readable, etc.),
+ use the MemoryMap directly regardless of activation state - all BinaryViews have a
+ usable MemoryMap.
+
+ :return: True if this is an activated (parsed) memory map, False otherwise
+ :rtype: bool
+ """
return core.BNIsMemoryMapActivated(self.handle)
def add_memory_region(self, name: str, start: int, source: Optional[Union['os.PathLike', str, bytes, bytearray, 'BinaryView', 'databuffer.DataBuffer', 'fileaccessor.FileAccessor']] = None, flags: SegmentFlag = 0, fill: int = 0, length: Optional[int] = None) -> bool:
diff --git a/python/workflow.py b/python/workflow.py
index 6f3b2dd8..ed6bc876 100644
--- a/python/workflow.py
+++ b/python/workflow.py
@@ -188,6 +188,204 @@ class AnalysisContext:
def inform(self, request: str) -> bool:
return core.BNAnalysisContextInform(self.handle, request)
+ def get_setting_bool(self, key: str) -> bool:
+ """
+ Get a boolean setting from the cached settings.
+
+ :param key: Setting key
+ :return: Boolean setting value
+ """
+ return core.BNAnalysisContextGetSettingBool(self.handle, key)
+
+ def get_setting_double(self, key: str) -> float:
+ """
+ Get a double setting from the cached settings.
+
+ :param key: Setting key
+ :return: Double setting value
+ """
+ return core.BNAnalysisContextGetSettingDouble(self.handle, key)
+
+ def get_setting_int64(self, key: str) -> int:
+ """
+ Get a 64-bit signed integer setting from the cached settings.
+
+ :param key: Setting key
+ :return: Int64 setting value
+ """
+ return core.BNAnalysisContextGetSettingInt64(self.handle, key)
+
+ def get_setting_uint64(self, key: str) -> int:
+ """
+ Get a 64-bit unsigned integer setting from the cached settings.
+
+ :param key: Setting key
+ :return: UInt64 setting value
+ """
+ return core.BNAnalysisContextGetSettingUInt64(self.handle, key)
+
+ def get_setting_string(self, key: str) -> str:
+ """
+ Get a string setting from the cached settings.
+
+ :param key: Setting key
+ :return: String setting value
+ """
+ return core.BNAnalysisContextGetSettingString(self.handle, key)
+
+ def get_setting_string_list(self, key: str) -> List[str]:
+ """
+ Get a string list setting from the cached settings.
+
+ :param key: Setting key
+ :return: List of strings
+ """
+ count = ctypes.c_size_t()
+ result = core.BNAnalysisContextGetSettingStringList(self.handle, key, ctypes.byref(count))
+ out_list = []
+ for i in range(count.value):
+ out_list.append(result[i].decode('utf-8'))
+ core.BNFreeStringList(result, count.value)
+ return out_list
+
+ def is_valid_offset(self, offset: int) -> bool:
+ """
+ Check if an offset is mapped in the cached memory map.
+
+ :param offset: Offset to check
+ :return: True if offset is mapped
+ """
+ return core.BNAnalysisContextIsValidOffset(self.handle, offset)
+
+ def is_offset_readable(self, offset: int) -> bool:
+ """
+ Check if an offset is readable in the cached memory map.
+
+ :param offset: Offset to check
+ :return: True if offset is readable
+ """
+ return core.BNAnalysisContextIsOffsetReadable(self.handle, offset)
+
+ def is_offset_writable(self, offset: int) -> bool:
+ """
+ Check if an offset is writable in the cached memory map.
+
+ :param offset: Offset to check
+ :return: True if offset is writable
+ """
+ return core.BNAnalysisContextIsOffsetWritable(self.handle, offset)
+
+ def is_offset_executable(self, offset: int) -> bool:
+ """
+ Check if an offset is executable in the cached memory map.
+
+ :param offset: Offset to check
+ :return: True if offset is executable
+ """
+ return core.BNAnalysisContextIsOffsetExecutable(self.handle, offset)
+
+ def is_offset_backed_by_file(self, offset: int) -> bool:
+ """
+ Check if an offset is backed by the file in the cached memory map.
+
+ :param offset: Offset to check
+ :return: True if offset is backed by file
+ """
+ return core.BNAnalysisContextIsOffsetBackedByFile(self.handle, offset)
+
+ def get_start(self) -> int:
+ """
+ Get the start address from the cached memory map.
+
+ :return: Start address
+ """
+ return core.BNAnalysisContextGetStart(self.handle)
+
+ def get_end(self) -> int:
+ """
+ Get the end address from the cached memory map.
+
+ :return: End address
+ """
+ return core.BNAnalysisContextGetEnd(self.handle)
+
+ def get_length(self) -> int:
+ """
+ Get the length of the cached memory map.
+
+ :return: Length
+ """
+ return core.BNAnalysisContextGetLength(self.handle)
+
+ def get_next_valid_offset(self, offset: int) -> int:
+ """
+ Get the next valid offset after the given offset from the cached memory map.
+
+ :param offset: Starting offset
+ :return: Next valid offset
+ """
+ return core.BNAnalysisContextGetNextValidOffset(self.handle, offset)
+
+ def get_next_mapped_address(self, addr: int, flags: int = 0) -> int:
+ """
+ Get the next mapped address after the given address from the cached memory map.
+
+ :param addr: Starting address
+ :param flags: Optional flags to filter by
+ :return: Next mapped address
+ """
+ return core.BNAnalysisContextGetNextMappedAddress(self.handle, addr, flags)
+
+ def get_next_backed_address(self, addr: int, flags: int = 0) -> int:
+ """
+ Get the next backed address after the given address from the cached memory map.
+
+ :param addr: Starting address
+ :param flags: Optional flags to filter by
+ :return: Next backed address
+ """
+ return core.BNAnalysisContextGetNextBackedAddress(self.handle, addr, flags)
+
+ def get_segment_at(self, addr: int) -> Optional['binaryview.Segment']:
+ """
+ Get the segment containing the given address from the cached memory map.
+
+ :param addr: Address to query
+ :return: Segment containing the address, or None
+ """
+ segment = core.BNAnalysisContextGetSegmentAt(self.handle, addr)
+ if not segment:
+ return None
+ return binaryview.Segment(segment)
+
+ def get_mapped_address_ranges(self) -> List[tuple]:
+ """
+ Get all mapped address ranges from the cached memory map.
+
+ :return: List of (start, end) tuples
+ """
+ count = ctypes.c_size_t()
+ ranges = core.BNAnalysisContextGetMappedAddressRanges(self.handle, ctypes.byref(count))
+ result = []
+ for i in range(count.value):
+ result.append((ranges[i].start, ranges[i].end))
+ core.BNFreeAddressRanges(ranges)
+ return result
+
+ def get_backed_address_ranges(self) -> List[tuple]:
+ """
+ Get all backed address ranges from the cached memory map.
+
+ :return: List of (start, end) tuples
+ """
+ count = ctypes.c_size_t()
+ ranges = core.BNAnalysisContextGetBackedAddressRanges(self.handle, ctypes.byref(count))
+ result = []
+ for i in range(count.value):
+ result.append((ranges[i].start, ranges[i].end))
+ core.BNFreeAddressRanges(ranges)
+ return result
+
class Activity(object):
"""
diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs
index 914c3aee..bb7902b9 100644
--- a/rust/src/binary_view/memory_map.rs
+++ b/rust/src/binary_view/memory_map.rs
@@ -6,6 +6,22 @@ use crate::segment::SegmentFlags;
use crate::string::{BnString, IntoCStr};
use binaryninjacore_sys::*;
+/// MemoryMap provides access to the system-level memory map describing how a BinaryView is loaded into memory.
+///
+/// # Architecture Note
+///
+/// This Rust `MemoryMap` struct is a proxy that accesses the BinaryView's current MemoryMap state through
+/// the FFI boundary. The proxy provides a simple mutable interface: when you call modification operations
+/// (add_memory_region, remove_memory_region, etc.), the proxy automatically accesses the updated MemoryMap.
+/// Internally, the core uses immutable copy-on-write data structures, but the proxy abstracts this away.
+///
+/// When you access a BinaryView's MemoryMap, you always see the current state. For lock-free access during
+/// analysis, AnalysisContext provides memory layout query methods (is_valid_offset, is_offset_readable, get_start,
+/// get_length, etc.) that operate on an immutable snapshot of the MemoryMap cached when the analysis was initiated.
+///
+/// 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.
#[derive(PartialEq, Eq, Hash)]
pub struct MemoryMap {
view: Ref<BinaryView>,
@@ -41,6 +57,18 @@ impl MemoryMap {
}
/// Whether the memory map is activated for the associated view.
+ ///
+ /// Returns `true` if this MemoryMap represents a parsed BinaryView with real segments
+ /// (ELF, PE, Mach-O, etc.). Returns `false` for Raw BinaryViews or views that failed
+ /// to parse segments.
+ ///
+ /// This is determined by whether the BinaryView has a parent view - parsed views have a
+ /// parent Raw view, while Raw views have no parent.
+ ///
+ /// Use this to gate features that require parsed binary structure (sections, imports,
+ /// relocations, etc.). For basic analysis queries (start, length, is_offset_readable, etc.),
+ /// use the MemoryMap directly regardless of activation state - all BinaryViews have a
+ /// usable MemoryMap.
pub fn is_activated(&self) -> bool {
unsafe { BNIsMemoryMapActivated(self.view.handle) }
}
diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs
index 49c5760e..618a290c 100644
--- a/rust/src/workflow.rs
+++ b/rust/src/workflow.rs
@@ -8,6 +8,7 @@ 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::string::{BnString, IntoCStr};
use std::ffi::c_char;
use std::ptr;
@@ -125,6 +126,152 @@ 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, ())
+ }
+ }
+
+ // 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 {
+ unsafe { BNAnalysisContextIsValidOffset(self.handle.as_ptr(), offset) }
+ }
+
+ /// Check if an offset is readable in the cached memory map
+ 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
+ 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
+ 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
+ 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 {
+ unsafe { BNAnalysisContextGetStart(self.handle.as_ptr()) }
+ }
+
+ /// Get the end address from the cached memory map
+ pub fn get_end(&self) -> u64 {
+ unsafe { BNAnalysisContextGetEnd(self.handle.as_ptr()) }
+ }
+
+ /// Get the length of the cached memory map
+ pub fn get_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 {
+ 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 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 segment containing the given address from the cached memory map
+ pub fn get_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 memory map
+ pub fn get_mapped_address_ranges(&self) -> Vec<(u64, u64)> {
+ 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
+ }
+ }
+
+ /// Get all backed address ranges from the cached memory map
+ pub fn get_backed_address_ranges(&self) -> Vec<(u64, u64)> {
+ 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
+ }
+ }
}
impl ToOwned for AnalysisContext {
diff --git a/workflow.cpp b/workflow.cpp
index 3b0366db..d4981c1a 100644
--- a/workflow.cpp
+++ b/workflow.cpp
@@ -152,6 +152,160 @@ bool AnalysisContext::Inform(const string& request)
}
+// Template specializations for GetSetting<T>
+template<>
+bool AnalysisContext::GetSetting<bool>(const string& key)
+{
+ return BNAnalysisContextGetSettingBool(m_object, key.c_str());
+}
+
+
+template<>
+double AnalysisContext::GetSetting<double>(const string& key)
+{
+ return BNAnalysisContextGetSettingDouble(m_object, key.c_str());
+}
+
+
+template<>
+int64_t AnalysisContext::GetSetting<int64_t>(const string& key)
+{
+ return BNAnalysisContextGetSettingInt64(m_object, key.c_str());
+}
+
+
+template<>
+uint64_t AnalysisContext::GetSetting<uint64_t>(const string& key)
+{
+ return BNAnalysisContextGetSettingUInt64(m_object, key.c_str());
+}
+
+
+template<>
+string AnalysisContext::GetSetting<string>(const string& key)
+{
+ char* str = BNAnalysisContextGetSettingString(m_object, key.c_str());
+ string result = str;
+ BNFreeString(str);
+ return result;
+}
+
+
+template<>
+vector<string> AnalysisContext::GetSetting<vector<string>>(const string& key)
+{
+ size_t count = 0;
+ char** list = BNAnalysisContextGetSettingStringList(m_object, key.c_str(), &count);
+ vector<string> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.push_back(list[i]);
+ BNFreeStringList(list, count);
+ return result;
+}
+
+
+bool AnalysisContext::IsValidOffset(uint64_t offset)
+{
+ return BNAnalysisContextIsValidOffset(m_object, offset);
+}
+
+
+bool AnalysisContext::IsOffsetReadable(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetReadable(m_object, offset);
+}
+
+
+bool AnalysisContext::IsOffsetWritable(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetWritable(m_object, offset);
+}
+
+
+bool AnalysisContext::IsOffsetExecutable(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetExecutable(m_object, offset);
+}
+
+
+bool AnalysisContext::IsOffsetBackedByFile(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetBackedByFile(m_object, offset);
+}
+
+
+uint64_t AnalysisContext::GetStart()
+{
+ return BNAnalysisContextGetStart(m_object);
+}
+
+
+uint64_t AnalysisContext::GetEnd()
+{
+ return BNAnalysisContextGetEnd(m_object);
+}
+
+
+uint64_t AnalysisContext::GetLength()
+{
+ return BNAnalysisContextGetLength(m_object);
+}
+
+
+uint64_t AnalysisContext::GetNextValidOffset(uint64_t offset)
+{
+ return BNAnalysisContextGetNextValidOffset(m_object, offset);
+}
+
+
+uint64_t AnalysisContext::GetNextMappedAddress(uint64_t addr, uint32_t flags)
+{
+ return BNAnalysisContextGetNextMappedAddress(m_object, addr, flags);
+}
+
+
+uint64_t AnalysisContext::GetNextBackedAddress(uint64_t addr, uint32_t flags)
+{
+ return BNAnalysisContextGetNextBackedAddress(m_object, addr, flags);
+}
+
+
+Ref<Segment> AnalysisContext::GetSegmentAt(uint64_t addr)
+{
+ BNSegment* segment = BNAnalysisContextGetSegmentAt(m_object, addr);
+ if (!segment)
+ return nullptr;
+ return new Segment(segment);
+}
+
+
+vector<BNAddressRange> AnalysisContext::GetMappedAddressRanges()
+{
+ size_t count = 0;
+ BNAddressRange* ranges = BNAnalysisContextGetMappedAddressRanges(m_object, &count);
+ vector<BNAddressRange> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.push_back(ranges[i]);
+ BNFreeAddressRanges(ranges);
+ return result;
+}
+
+
+vector<BNAddressRange> AnalysisContext::GetBackedAddressRanges()
+{
+ size_t count = 0;
+ BNAddressRange* ranges = BNAnalysisContextGetBackedAddressRanges(m_object, &count);
+ vector<BNAddressRange> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.push_back(ranges[i]);
+ BNFreeAddressRanges(ranges);
+ return result;
+}
+
+
bool WorkflowMachine::PostRequest(const std::string& command)
{
rapidjson::Document request(rapidjson::kObjectType);