summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Potchik <brian@vector35.com>2025-11-24 15:35:58 -0500
committerBrian Potchik <brian@vector35.com>2025-11-24 15:35:58 -0500
commitb4d77d5b44dd322042f90b5a4a4da9075d05b644 (patch)
tree9d13e5ae7c4c2f62ffd67ba79bfb8cc42b1566cc
parentd3d4d43d223da5cd84b48a129b54acc39612c986 (diff)
Add AnalysisContext FFI for SectionMap queries.
-rw-r--r--binaryninjaapi.h9
-rw-r--r--binaryninjacore.h9
-rw-r--r--python/workflow.py77
-rw-r--r--rust/src/workflow.rs66
-rw-r--r--workflow.cpp59
5 files changed, 219 insertions, 1 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 37bbd235..6f84250c 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -11483,6 +11483,15 @@ namespace BinaryNinja {
Ref<Segment> GetSegmentAt(uint64_t addr);
std::vector<BNAddressRange> GetMappedAddressRanges();
std::vector<BNAddressRange> GetBackedAddressRanges();
+
+ // Section map access - lock-free access to cached SectionMap
+ bool IsOffsetCodeSemantics(uint64_t offset);
+ bool IsOffsetExternSemantics(uint64_t offset);
+ bool IsOffsetWritableSemantics(uint64_t offset);
+ bool IsOffsetReadOnlySemantics(uint64_t offset);
+ std::vector<Ref<Section>> GetSections();
+ Ref<Section> GetSectionByName(const std::string& name);
+ std::vector<Ref<Section>> GetSectionsAt(uint64_t addr);
};
// Explicit template specialization declarations for AnalysisContext::GetSetting<T>
diff --git a/binaryninjacore.h b/binaryninjacore.h
index b7b33715..a86fd5d3 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 149
+#define BN_CURRENT_CORE_ABI_VERSION 150
// 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
@@ -5945,6 +5945,13 @@ extern "C"
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 bool BNAnalysisContextIsOffsetCodeSemantics(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetExternSemantics(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetWritableSemantics(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI bool BNAnalysisContextIsOffsetReadOnlySemantics(BNAnalysisContext* analysisContext, uint64_t offset);
+ BINARYNINJACOREAPI BNSection** BNAnalysisContextGetSections(BNAnalysisContext* analysisContext, size_t* count);
+ BINARYNINJACOREAPI BNSection* BNAnalysisContextGetSectionByName(BNAnalysisContext* analysisContext, const char* name);
+ BINARYNINJACOREAPI BNSection** BNAnalysisContextGetSectionsAt(BNAnalysisContext* analysisContext, uint64_t addr, size_t* count);
BINARYNINJACOREAPI uint64_t BNAnalysisContextGetStart(BNAnalysisContext* analysisContext);
BINARYNINJACOREAPI uint64_t BNAnalysisContextGetEnd(BNAnalysisContext* analysisContext);
BINARYNINJACOREAPI uint64_t BNAnalysisContextGetLength(BNAnalysisContext* analysisContext);
diff --git a/python/workflow.py b/python/workflow.py
index ed6bc876..61827b55 100644
--- a/python/workflow.py
+++ b/python/workflow.py
@@ -293,6 +293,83 @@ class AnalysisContext:
"""
return core.BNAnalysisContextIsOffsetBackedByFile(self.handle, offset)
+ def is_offset_code_semantics(self, offset: int) -> bool:
+ """
+ Check if an offset has code semantics in the cached section map.
+
+ :param offset: Offset to check
+ :return: True if offset has code semantics
+ """
+ return core.BNAnalysisContextIsOffsetCodeSemantics(self.handle, offset)
+
+ def is_offset_extern_semantics(self, offset: int) -> bool:
+ """
+ Check if an offset has external semantics in the cached section map.
+
+ :param offset: Offset to check
+ :return: True if offset has external semantics
+ """
+ return core.BNAnalysisContextIsOffsetExternSemantics(self.handle, offset)
+
+ def is_offset_writable_semantics(self, offset: int) -> bool:
+ """
+ Check if an offset has writable semantics in the cached section map.
+
+ :param offset: Offset to check
+ :return: True if offset has writable semantics
+ """
+ return core.BNAnalysisContextIsOffsetWritableSemantics(self.handle, offset)
+
+ def is_offset_readonly_semantics(self, offset: int) -> bool:
+ """
+ Check if an offset has read-only semantics in the cached section map.
+
+ :param offset: Offset to check
+ :return: True if offset has read-only semantics
+ """
+ return core.BNAnalysisContextIsOffsetReadOnlySemantics(self.handle, offset)
+
+ def get_sections(self) -> List['binaryninja.binaryview.Section']:
+ """
+ Get all sections from the cached section map.
+
+ :return: List of all sections
+ """
+ count = ctypes.c_ulonglong()
+ sections = core.BNAnalysisContextGetSections(self.handle, count)
+ result = []
+ for i in range(count.value):
+ result.append(binaryninja.binaryview.Section(core.BNNewSectionReference(sections[i])))
+ core.BNFreeSectionList(sections, count.value)
+ return result
+
+ def get_section_by_name(self, name: str) -> Optional['binaryninja.binaryview.Section']:
+ """
+ Get a section by name from the cached section map.
+
+ :param name: Section name
+ :return: Section with the given name, or None if not found
+ """
+ section = core.BNAnalysisContextGetSectionByName(self.handle, name)
+ if not section:
+ return None
+ return binaryninja.binaryview.Section(section)
+
+ def get_sections_at(self, addr: int) -> List['binaryninja.binaryview.Section']:
+ """
+ Get all sections containing the given address from the cached section map.
+
+ :param addr: Address to query
+ :return: List of sections containing the address
+ """
+ count = ctypes.c_ulonglong()
+ sections = core.BNAnalysisContextGetSectionsAt(self.handle, addr, count)
+ result = []
+ for i in range(count.value):
+ result.append(binaryninja.binaryview.Section(core.BNNewSectionReference(sections[i])))
+ core.BNFreeSectionList(sections, count.value)
+ return result
+
def get_start(self) -> int:
"""
Get the start address from the cached memory map.
diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs
index adc8d4ba..a3de4221 100644
--- a/rust/src/workflow.rs
+++ b/rust/src/workflow.rs
@@ -12,6 +12,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::section::Section;
use crate::segment::{Segment, SegmentFlags};
use crate::string::{BnString, IntoCStr};
use std::ffi::c_char;
@@ -215,6 +216,71 @@ impl AnalysisContext {
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 [`BinaryView::is_offset_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 [`BinaryView::is_offset_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 [`BinaryView::is_offset_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 [`BinaryView::is_offset_readonly_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 [`BinaryView::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 [`BinaryView::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 [`BinaryView::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`].
diff --git a/workflow.cpp b/workflow.cpp
index d4981c1a..5be636d2 100644
--- a/workflow.cpp
+++ b/workflow.cpp
@@ -235,6 +235,65 @@ bool AnalysisContext::IsOffsetBackedByFile(uint64_t offset)
}
+bool AnalysisContext::IsOffsetCodeSemantics(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetCodeSemantics(m_object, offset);
+}
+
+
+bool AnalysisContext::IsOffsetExternSemantics(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetExternSemantics(m_object, offset);
+}
+
+
+bool AnalysisContext::IsOffsetWritableSemantics(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetWritableSemantics(m_object, offset);
+}
+
+
+bool AnalysisContext::IsOffsetReadOnlySemantics(uint64_t offset)
+{
+ return BNAnalysisContextIsOffsetReadOnlySemantics(m_object, offset);
+}
+
+
+vector<Ref<Section>> AnalysisContext::GetSections()
+{
+ size_t count;
+ BNSection** sections = BNAnalysisContextGetSections(m_object, &count);
+ vector<Ref<Section>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.push_back(new Section(BNNewSectionReference(sections[i])));
+ BNFreeSectionList(sections, count);
+ return result;
+}
+
+
+Ref<Section> AnalysisContext::GetSectionByName(const string& name)
+{
+ BNSection* section = BNAnalysisContextGetSectionByName(m_object, name.c_str());
+ if (!section)
+ return nullptr;
+ return new Section(section);
+}
+
+
+vector<Ref<Section>> AnalysisContext::GetSectionsAt(uint64_t addr)
+{
+ size_t count;
+ BNSection** sections = BNAnalysisContextGetSectionsAt(m_object, addr, &count);
+ vector<Ref<Section>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.push_back(new Section(BNNewSectionReference(sections[i])));
+ BNFreeSectionList(sections, count);
+ return result;
+}
+
+
uint64_t AnalysisContext::GetStart()
{
return BNAnalysisContextGetStart(m_object);