From 00dc9c659b75c08ca43f5c50885cdcf8d9e3d5e0 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Mon, 12 Oct 2026 17:57:07 -0700 Subject: [PATCH 1/2] Add API struct conversions for ReferenceSource Previously, each method that passed or received a `BNReferenceSource` converted it by hand. --- binaryninjaapi.h | 4 ++ binaryview.cpp | 152 ++++++++++++++++------------------------------- function.cpp | 13 +--- 3 files changed, 57 insertions(+), 112 deletions(-) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index d5e612cfcd..44bbac9fd7 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -5098,6 +5098,10 @@ namespace BinaryNinja { Ref func; Ref arch; uint64_t addr; + + BNReferenceSource ToAPIStruct() const; + static ReferenceSource FromAPIStruct(const BNReferenceSource* source); + static void FreeAPIStruct(BNReferenceSource* source); }; struct TypeFieldReference diff --git a/binaryview.cpp b/binaryview.cpp index 09a1d2e21b..5b3432caf2 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -22,6 +22,7 @@ #include #include #include "binaryninjaapi.h" +#include "ffi.h" using namespace BinaryNinja; using namespace std; @@ -2510,22 +2511,40 @@ vector> BinaryView::GetBasicBlocksStartingAtAddress(uint64_t add } +BNReferenceSource ReferenceSource::ToAPIStruct() const +{ + BNReferenceSource result; + result.func = func ? BNNewFunctionReference(func->m_object) : nullptr; + result.arch = arch ? arch->m_object : nullptr; + result.addr = addr; + return result; +} + + +ReferenceSource ReferenceSource::FromAPIStruct(const BNReferenceSource* source) +{ + ReferenceSource result; + if (source->func) + result.func = new Function(BNNewFunctionReference(source->func)); + if (source->arch) + result.arch = new CoreArchitecture(source->arch); + result.addr = source->addr; + return result; +} + + +void ReferenceSource::FreeAPIStruct(BNReferenceSource* source) +{ + if (source->func) + BNFreeFunction(source->func); +} + + vector BinaryView::GetCodeReferences(uint64_t addr) { size_t count; BNReferenceSource* refs = BNGetCodeReferences(m_object, addr, &count, false, 0); - - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } @@ -2535,18 +2554,7 @@ vector BinaryView::GetCodeReferences(uint64_t addr, uint64_t le { size_t count; BNReferenceSource* refs = BNGetCodeReferencesInRange(m_object, addr, len, &count, false, 0); - - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } @@ -2556,18 +2564,7 @@ vector BinaryView::GetCodeReferencesWithLimit(uint64_t addr, st { size_t count; BNReferenceSource* refs = BNGetCodeReferences(m_object, addr, &count, maxItems.has_value(), maxItems.value_or(0)); - - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } @@ -2579,18 +2576,7 @@ vector BinaryView::GetCodeReferencesInRangeWithLimit( size_t count; BNReferenceSource* refs = BNGetCodeReferencesInRange(m_object, addr, len, &count, maxItems.has_value(), maxItems.value_or(0)); - - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } @@ -2599,8 +2585,9 @@ vector BinaryView::GetCodeReferencesInRangeWithLimit( vector BinaryView::GetCodeReferencesFrom(ReferenceSource src) { size_t count; - BNReferenceSource _src {src.func->m_object, src.arch->m_object, src.addr}; + BNReferenceSource _src = src.ToAPIStruct(); uint64_t* refs = BNGetCodeReferencesFrom(m_object, &_src, &count); + ReferenceSource::FreeAPIStruct(&_src); vector result(refs, &refs[count]); BNFreeAddressList(refs); return result; @@ -2610,8 +2597,9 @@ vector BinaryView::GetCodeReferencesFrom(ReferenceSource src) vector BinaryView::GetCodeReferencesFrom(ReferenceSource src, uint64_t len) { size_t count; - BNReferenceSource _src {src.func->m_object, src.arch->m_object, src.addr}; + BNReferenceSource _src = src.ToAPIStruct(); uint64_t* refs = BNGetCodeReferencesFromInRange(m_object, &_src, len, &count); + ReferenceSource::FreeAPIStruct(&_src); vector result(refs, &refs[count]); BNFreeAddressList(refs); return result; @@ -2713,17 +2701,7 @@ vector BinaryView::GetCodeReferencesForType(const QualifiedName BNGetCodeReferencesForType(m_object, &nameObj, &count, maxItems.has_value(), maxItems.value_or(0)); QualifiedName::FreeAPIStruct(&nameObj); - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } @@ -2860,17 +2838,7 @@ AllTypeReferences BinaryView::GetAllReferencesForType(const QualifiedName& type, QualifiedName::FreeAPIStruct(&nameObj); AllTypeReferences result; - - result.codeRefs.reserve(refs.codeRefCount); - for (size_t i = 0; i < refs.codeRefCount; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs.codeRefs[i].func)); - src.arch = new CoreArchitecture(refs.codeRefs[i].arch); - src.addr = refs.codeRefs[i].addr; - result.codeRefs.push_back(src); - } - + result.codeRefs = ParseAPIStructList(refs.codeRefs, refs.codeRefCount); result.dataRefs = vector(refs.dataRefs, &refs.dataRefs[refs.dataRefCount]); result.typeRefs.reserve(refs.typeRefCount); @@ -2933,8 +2901,9 @@ AllTypeFieldReferences BinaryView::GetAllReferencesForTypeField( vector BinaryView::GetCodeReferencesForTypeFrom(ReferenceSource src) { size_t count; - BNReferenceSource _src {src.func->m_object, src.arch->m_object, src.addr}; + BNReferenceSource _src = src.ToAPIStruct(); BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFrom(m_object, &_src, &count); + ReferenceSource::FreeAPIStruct(&_src); vector result; result.reserve(count); @@ -2955,8 +2924,9 @@ vector BinaryView::GetCodeReferencesForTypeFrom(ReferenceSo vector BinaryView::GetCodeReferencesForTypeFrom(ReferenceSource src, uint64_t len) { size_t count; - BNReferenceSource _src {src.func->m_object, src.arch->m_object, src.addr}; + BNReferenceSource _src = src.ToAPIStruct(); BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFromInRange(m_object, &_src, len, &count); + ReferenceSource::FreeAPIStruct(&_src); vector result; result.reserve(count); @@ -2976,8 +2946,9 @@ vector BinaryView::GetCodeReferencesForTypeFrom(ReferenceSo vector BinaryView::GetCodeReferencesForTypeFieldFrom(ReferenceSource src) { size_t count; - BNReferenceSource _src {src.func->m_object, src.arch->m_object, src.addr}; + BNReferenceSource _src = src.ToAPIStruct(); BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFieldsFrom(m_object, &_src, &count); + ReferenceSource::FreeAPIStruct(&_src); vector result; result.reserve(count); @@ -2998,8 +2969,9 @@ vector BinaryView::GetCodeReferencesForTypeFieldFrom(Refere vector BinaryView::GetCodeReferencesForTypeFieldFrom(ReferenceSource src, uint64_t len) { size_t count; - BNReferenceSource _src {src.func->m_object, src.arch->m_object, src.addr}; + BNReferenceSource _src = src.ToAPIStruct(); BNTypeReferenceSource* refs = BNGetCodeReferencesForTypeFieldsFromInRange(m_object, &_src, len, &count); + ReferenceSource::FreeAPIStruct(&_src); vector result; result.reserve(count); @@ -3218,8 +3190,9 @@ unordered_set BinaryView::GetIncomingRecursiveTypeReferences(cons vector BinaryView::GetCallees(ReferenceSource callSite) { size_t count; - BNReferenceSource src {callSite.func->m_object, callSite.arch->m_object, callSite.addr}; + BNReferenceSource src = callSite.ToAPIStruct(); uint64_t* refs = BNGetCallees(m_object, &src, &count); + ReferenceSource::FreeAPIStruct(&src); vector result(refs, &refs[count]); BNFreeAddressList(refs); return result; @@ -3230,18 +3203,7 @@ vector BinaryView::GetCallers(uint64_t addr) { size_t count; BNReferenceSource* refs = BNGetCallers(m_object, addr, &count); - - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } @@ -4176,17 +4138,7 @@ vector BinaryView::GetDerivedStringCodeReferences( size_t count; BNReferenceSource* refs = BNGetDerivedStringCodeReferences( m_object, &derivedStr, &count, maxItems.has_value(), maxItems.value_or(0)); - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } diff --git a/function.cpp b/function.cpp index d5dd33e839..a061bd2d7a 100644 --- a/function.cpp +++ b/function.cpp @@ -350,18 +350,7 @@ vector Function::GetCallSites() const { size_t count; BNReferenceSource* refs = BNGetFunctionCallSites(m_object, &count); - - vector result; - result.reserve(count); - for (size_t i = 0; i < count; i++) - { - ReferenceSource src; - src.func = new Function(BNNewFunctionReference(refs[i].func)); - src.arch = new CoreArchitecture(refs[i].arch); - src.addr = refs[i].addr; - result.push_back(src); - } - + vector result = ParseAPIStructList(refs, count); BNFreeCodeReferences(refs, count); return result; } From adcdcc73461a0202eb7f5d7ab6cf2fa2aae1db21 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Sat, 10 Oct 2026 10:50:12 -0700 Subject: [PATCH 2/2] Add queries for code and data references into and out of an address range Previously, range queries for references returned only one end of each reference, so a caller could not tell which source in a range made which reference. Now `BinaryView` has `GetIncomingCodeReferences`, `GetIncomingDataReferences`, `GetOutgoingCodeReferences` and `GetOutgoingDataReferences`, which return `CodeXref` and `DataXref` pairs. Python and Rust gain matching methods. --- binaryninjaapi.h | 61 +++++++++++++++++++++ binaryninjacore.h | 24 ++++++++- binaryview.cpp | 80 +++++++++++++++++++++++++++ python/binaryview.py | 116 ++++++++++++++++++++++++++++++++++++++++ rust/src/binary_view.rs | 74 ++++++++++++++++++++++++- rust/src/references.rs | 59 +++++++++++++++++++- 6 files changed, 410 insertions(+), 4 deletions(-) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 44bbac9fd7..fea2ec6f16 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -5104,6 +5104,26 @@ namespace BinaryNinja { static void FreeAPIStruct(BNReferenceSource* source); }; + struct CodeXref + { + ReferenceSource source; + uint64_t target; + + BNCodeXref ToAPIStruct() const; + static CodeXref FromAPIStruct(const BNCodeXref* ref); + static void FreeAPIStruct(BNCodeXref* ref); + }; + + struct DataXref + { + uint64_t source; + uint64_t target; + + BNDataXref ToAPIStruct() const; + static DataXref FromAPIStruct(const BNDataXref* ref); + static void FreeAPIStruct(BNDataXref* ref); + }; + struct TypeFieldReference { Ref func; @@ -6703,6 +6723,47 @@ namespace BinaryNinja { */ std::vector GetDataReferencesFrom(uint64_t addr, uint64_t len); + /*! Get references made by code (instructions) to a range of addresses, each with its source and target + + \param addr Start of the range + \param len Length of the range + \param maxItems Optional maximum number of items to fetch + \return References whose target is in the range + */ + std::vector GetIncomingCodeReferences( + uint64_t addr, uint64_t len, std::optional maxItems = std::nullopt); + + /*! Get references made by data ('DataVariables') to a range of addresses, each with its source and target + + \param addr Start of the range + \param len Length of the range + \param maxItems Optional maximum number of items to fetch + \return References whose target is in the range + */ + std::vector GetIncomingDataReferences( + uint64_t addr, uint64_t len, std::optional maxItems = std::nullopt); + + /*! Get references made by code (instructions) in a range of addresses, each with its source and target + + \param addr Start of the range + \param len Length of the range + \param func Function whose references are returned, or nullptr for every function with code in the range + \param maxItems Optional maximum number of items to fetch + \return References whose source is in the range + */ + std::vector GetOutgoingCodeReferences(uint64_t addr, uint64_t len, Ref func = nullptr, + std::optional maxItems = std::nullopt); + + /*! Get references made by data ('DataVariables') in a range of addresses, each with its source and target + + \param addr Start of the range + \param len Length of the range + \param maxItems Optional maximum number of items to fetch + \return References whose source is in the range + */ + std::vector GetOutgoingDataReferences( + uint64_t addr, uint64_t len, std::optional maxItems = std::nullopt); + /*! Add an auto Data Reference from a virtual address to another virtual address diff --git a/binaryninjacore.h b/binaryninjacore.h index a70f8e941a..206d0ac2d1 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 189 +#define BN_CURRENT_CORE_ABI_VERSION 190 // 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 @@ -2637,6 +2637,18 @@ extern "C" uint64_t addr; } BNReferenceSource; + typedef struct BNCodeXref + { + BNReferenceSource source; + uint64_t target; + } BNCodeXref; + + typedef struct BNDataXref + { + uint64_t source; + uint64_t target; + } BNDataXref; + typedef struct BNTypeFieldReference { BNFunction* func; @@ -6313,6 +6325,16 @@ extern "C" BINARYNINJACOREAPI uint64_t* BNGetDataReferencesFrom(BNBinaryView* view, uint64_t addr, size_t* count); BINARYNINJACOREAPI uint64_t* BNGetDataReferencesFromInRange( BNBinaryView* view, uint64_t addr, uint64_t len, size_t* count); + BINARYNINJACOREAPI BNCodeXref* BNGetIncomingCodeReferences( + BNBinaryView* view, uint64_t addr, uint64_t len, size_t* count, bool limit, size_t maxItems); + BINARYNINJACOREAPI BNDataXref* BNGetIncomingDataReferences( + BNBinaryView* view, uint64_t addr, uint64_t len, size_t* count, bool limit, size_t maxItems); + BINARYNINJACOREAPI BNCodeXref* BNGetOutgoingCodeReferences(BNBinaryView* view, uint64_t addr, uint64_t len, + BNFunction* func, size_t* count, bool limit, size_t maxItems); + BINARYNINJACOREAPI BNDataXref* BNGetOutgoingDataReferences( + BNBinaryView* view, uint64_t addr, uint64_t len, size_t* count, bool limit, size_t maxItems); + BINARYNINJACOREAPI void BNFreeCodeXrefs(BNCodeXref* refs, size_t count); + BINARYNINJACOREAPI void BNFreeDataXrefs(BNDataXref* refs, size_t count); BINARYNINJACOREAPI void BNAddDataReference(BNBinaryView* view, uint64_t fromAddr, uint64_t toAddr); BINARYNINJACOREAPI void BNRemoveDataReference(BNBinaryView* view, uint64_t fromAddr, uint64_t toAddr); BINARYNINJACOREAPI void BNAddUserDataReference(BNBinaryView* view, uint64_t fromAddr, uint64_t toAddr); diff --git a/binaryview.cpp b/binaryview.cpp index 5b3432caf2..8f7b141165 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -2540,6 +2540,41 @@ void ReferenceSource::FreeAPIStruct(BNReferenceSource* source) } +BNCodeXref CodeXref::ToAPIStruct() const +{ + return {source.ToAPIStruct(), target}; +} + + +CodeXref CodeXref::FromAPIStruct(const BNCodeXref* ref) +{ + return {ReferenceSource::FromAPIStruct(&ref->source), ref->target}; +} + + +void CodeXref::FreeAPIStruct(BNCodeXref* ref) +{ + ReferenceSource::FreeAPIStruct(&ref->source); +} + + +BNDataXref DataXref::ToAPIStruct() const +{ + return {source, target}; +} + + +DataXref DataXref::FromAPIStruct(const BNDataXref* ref) +{ + return {ref->source, ref->target}; +} + + +void DataXref::FreeAPIStruct(BNDataXref*) +{ +} + + vector BinaryView::GetCodeReferences(uint64_t addr) { size_t count; @@ -2668,6 +2703,51 @@ vector BinaryView::GetDataReferencesFrom(uint64_t addr, uint64_t len) } +vector BinaryView::GetIncomingCodeReferences(uint64_t addr, uint64_t len, std::optional maxItems) +{ + size_t count; + BNCodeXref* refs = + BNGetIncomingCodeReferences(m_object, addr, len, &count, maxItems.has_value(), maxItems.value_or(0)); + vector result = ParseAPIStructList(refs, count); + BNFreeCodeXrefs(refs, count); + return result; +} + + +vector BinaryView::GetIncomingDataReferences(uint64_t addr, uint64_t len, std::optional maxItems) +{ + size_t count; + BNDataXref* refs = + BNGetIncomingDataReferences(m_object, addr, len, &count, maxItems.has_value(), maxItems.value_or(0)); + vector result = ParseAPIStructList(refs, count); + BNFreeDataXrefs(refs, count); + return result; +} + + +vector BinaryView::GetOutgoingCodeReferences( + uint64_t addr, uint64_t len, Ref func, std::optional maxItems) +{ + size_t count; + BNCodeXref* refs = BNGetOutgoingCodeReferences(m_object, addr, len, func ? func->GetObject() : nullptr, &count, + maxItems.has_value(), maxItems.value_or(0)); + vector result = ParseAPIStructList(refs, count); + BNFreeCodeXrefs(refs, count); + return result; +} + + +vector BinaryView::GetOutgoingDataReferences(uint64_t addr, uint64_t len, std::optional maxItems) +{ + size_t count; + BNDataXref* refs = + BNGetOutgoingDataReferences(m_object, addr, len, &count, maxItems.has_value(), maxItems.value_or(0)); + vector result = ParseAPIStructList(refs, count); + BNFreeDataXrefs(refs, count); + return result; +} + + void BinaryView::AddDataReference(uint64_t fromAddr, uint64_t toAddr) { BNAddDataReference(m_object, fromAddr, toAddr); diff --git a/python/binaryview.py b/python/binaryview.py index ffe1500910..fb023f7385 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -162,6 +162,25 @@ def hlils(self) -> Iterator[highlevelil.HighLevelILInstruction]: for hlil in llil.hlils: yield hlil + +@dataclass(frozen=True) +class CodeXref: + """A reference made by code, from the instruction at ``source`` to the address ``target``.""" + source: ReferenceSource + target: int + + @classmethod + def _from_core_struct(cls, view: 'BinaryView', ref: core.BNCodeXref) -> 'CodeXref': + return CodeXref(ReferenceSource._from_core_struct(view, ref.source), ref.target) + + +@dataclass(frozen=True) +class DataXref: + """A reference made by data, from the address ``source`` to the address ``target``.""" + source: int + target: int + + class NotificationType(IntFlag): NotificationBarrier = 1 << 0 DataWritten = 1 << 1 @@ -6193,6 +6212,28 @@ def get_code_refs(self, addr: int, length: Optional[int] = None, max_items: Opti finally: core.BNFreeCodeReferences(refs, count.value) + def get_incoming_code_refs(self, addr: int, length: int, max_items: Optional[int] = None) -> List[CodeXref]: + """ + ``get_incoming_code_refs`` returns the references made by code to the range ``addr``-``addr``+``length``, + each with its source and target. + This function returns both autoanalysis ("auto") and user-specified ("user") xrefs. + + :param int addr: start of the range to query + :param int length: length of the range to query + :param int max_items: optional maximum number of references to fetch + :return: list of CodeXref + :rtype: list(CodeXref) + """ + count = ctypes.c_ulonglong(0) + has_max_items = max_items is not None + max_items_value = max_items if has_max_items else 0 + refs = core.BNGetIncomingCodeReferences(self.handle, addr, length, count, has_max_items, max_items_value) + assert refs is not None, "core.BNGetIncomingCodeReferences returned None" + try: + return [CodeXref._from_core_struct(self, refs[i]) for i in range(0, count.value)] + finally: + core.BNFreeCodeXrefs(refs, count.value) + def get_code_refs_from( self, addr: int, func: Optional['_function.Function'] = None, arch: Optional['architecture.Architecture'] = None, length: Optional[int] = None @@ -6232,6 +6273,35 @@ def get_code_refs_from( core.BNFreeAddressList(refs) return result + def get_outgoing_code_refs( + self, addr: int, length: int, func: Optional['_function.Function'] = None, max_items: Optional[int] = None + ) -> List[CodeXref]: + """ + ``get_outgoing_code_refs`` returns the references made by code in the range ``addr``-``addr``+``length``, + each with its source and target. If ``func`` is specified, only references made by that function are + returned. Otherwise references made by every function with code in the range are returned. + This function returns both autoanalysis ("auto") and user-specified ("user") xrefs. + + :param int addr: start of the range to query + :param int length: length of the range to query + :param Function func: optional function whose references are returned + :param int max_items: optional maximum number of references to fetch + :return: list of CodeXref + :rtype: list(CodeXref) + """ + count = ctypes.c_ulonglong(0) + has_max_items = max_items is not None + max_items_value = max_items if has_max_items else 0 + func_handle = func.handle if func is not None else None + refs = core.BNGetOutgoingCodeReferences( + self.handle, addr, length, func_handle, count, has_max_items, max_items_value + ) + assert refs is not None, "core.BNGetOutgoingCodeReferences returned None" + try: + return [CodeXref._from_core_struct(self, refs[i]) for i in range(0, count.value)] + finally: + core.BNFreeCodeXrefs(refs, count.value) + def get_data_refs(self, addr: int, length: Optional[int] = None, max_items: Optional[int] = None) -> Generator[int, None, None]: """ ``get_data_refs`` returns a list of virtual addresses of _data_ (not code) which references ``addr``, optionally specifying @@ -6270,6 +6340,29 @@ def get_data_refs(self, addr: int, length: Optional[int] = None, max_items: Opti finally: core.BNFreeDataReferences(refs) + def get_incoming_data_refs(self, addr: int, length: int, max_items: Optional[int] = None) -> List[DataXref]: + """ + ``get_incoming_data_refs`` returns the references made by data to the range ``addr``-``addr``+``length``, + each with its source and target. + This function returns both autoanalysis ("auto") and user-specified ("user") xrefs. To add a user-specified + reference, see :py:func:`add_user_data_ref`. + + :param int addr: start of the range to query + :param int length: length of the range to query + :param int max_items: optional maximum number of references to fetch + :return: list of DataXref + :rtype: list(DataXref) + """ + count = ctypes.c_ulonglong(0) + has_max_items = max_items is not None + max_items_value = max_items if has_max_items else 0 + refs = core.BNGetIncomingDataReferences(self.handle, addr, length, count, has_max_items, max_items_value) + assert refs is not None, "core.BNGetIncomingDataReferences returned None" + try: + return [DataXref(refs[i].source, refs[i].target) for i in range(0, count.value)] + finally: + core.BNFreeDataXrefs(refs, count.value) + def get_data_refs_from(self, addr: int, length: Optional[int] = None) -> Generator[int, None, None]: """ ``get_data_refs_from`` returns a list of virtual addresses referenced by the address ``addr``. Optionally specifying @@ -6302,6 +6395,29 @@ def get_data_refs_from(self, addr: int, length: Optional[int] = None) -> Generat finally: core.BNFreeDataReferences(refs) + def get_outgoing_data_refs(self, addr: int, length: int, max_items: Optional[int] = None) -> List[DataXref]: + """ + ``get_outgoing_data_refs`` returns the references made by data in the range ``addr``-``addr``+``length``, + each with its source and target. + This function returns both autoanalysis ("auto") and user-specified ("user") xrefs. To add a user-specified + reference, see :py:func:`add_user_data_ref`. + + :param int addr: start of the range to query + :param int length: length of the range to query + :param int max_items: optional maximum number of references to fetch + :return: list of DataXref + :rtype: list(DataXref) + """ + count = ctypes.c_ulonglong(0) + has_max_items = max_items is not None + max_items_value = max_items if has_max_items else 0 + refs = core.BNGetOutgoingDataReferences(self.handle, addr, length, count, has_max_items, max_items_value) + assert refs is not None, "core.BNGetOutgoingDataReferences returned None" + try: + return [DataXref(refs[i].source, refs[i].target) for i in range(0, count.value)] + finally: + core.BNFreeDataXrefs(refs, count.value) + def get_code_refs_for_type(self, name: str, max_items: Optional[int] = None) -> Generator[ReferenceSource, None, None]: """ ``get_code_refs_for_type`` returns a Generator[ReferenceSource] objects (xrefs or cross-references) that reference the provided QualifiedName. diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 9a8efcf507..cba02c089d 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -44,7 +44,7 @@ use crate::platform::Platform; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; use crate::rc::*; -use crate::references::{CodeReference, DataReference}; +use crate::references::{CodeReference, CodeXref, DataReference, DataXref}; use crate::relocation::Relocation; use crate::section::{Section, SectionBuilder}; use crate::segment::{Segment, SegmentBuilder}; @@ -2483,6 +2483,22 @@ impl BinaryView { } } + /// Retrieves the references made by code to a given [Range], each with its source and target. + pub fn incoming_code_refs(&self, range: Range) -> Array { + unsafe { + let mut count = 0; + let handle = BNGetIncomingCodeReferences( + self.handle, + range.start, + range.end - range.start, + &mut count, + false, + 0, + ); + Array::new(handle, count, ()) + } + } + /// Retrieves a list of addresses pointed to by a given address. pub fn code_refs_from_addr(&self, addr: u64, func: Option<&Function>) -> Vec { unsafe { @@ -2497,6 +2513,30 @@ impl BinaryView { } } + /// Retrieves the references made by code in a given [Range], each with its source and target. + /// + /// With `func`, only references made by that function are returned. Otherwise references + /// made by every function with code in the range are returned. + pub fn outgoing_code_refs( + &self, + range: Range, + func: Option<&Function>, + ) -> Array { + unsafe { + let mut count = 0; + let handle = BNGetOutgoingCodeReferences( + self.handle, + range.start, + range.end - range.start, + func.map(|f| f.handle).unwrap_or(std::ptr::null_mut()), + &mut count, + false, + 0, + ); + Array::new(handle, count, ()) + } + } + /// Retrieves a list of [DataReference]s pointing to a given address. pub fn data_refs_to_addr(&self, addr: u64) -> Array { unsafe { @@ -2522,6 +2562,22 @@ impl BinaryView { } } + /// Retrieves the references made by data to a given [Range], each with its source and target. + pub fn incoming_data_refs(&self, range: Range) -> Array { + unsafe { + let mut count = 0; + let handle = BNGetIncomingDataReferences( + self.handle, + range.start, + range.end - range.start, + &mut count, + false, + 0, + ); + Array::new(handle, count, ()) + } + } + /// Retrieves a list of [DataReference]s originating from a given address. pub fn data_refs_from_addr(&self, addr: u64) -> Array { unsafe { @@ -2531,6 +2587,22 @@ impl BinaryView { } } + /// Retrieves the references made by data in a given [Range], each with its source and target. + pub fn outgoing_data_refs(&self, range: Range) -> Array { + unsafe { + let mut count = 0; + let handle = BNGetOutgoingDataReferences( + self.handle, + range.start, + range.end - range.start, + &mut count, + false, + 0, + ); + Array::new(handle, count, ()) + } + } + /// Retrieves a list of [CodeReference]s for locations in code that use a given named type. pub fn code_refs_using_type_name>( &self, diff --git a/rust/src/references.rs b/rust/src/references.rs index 52fb671368..6e1957222e 100644 --- a/rust/src/references.rs +++ b/rust/src/references.rs @@ -2,7 +2,10 @@ use crate::architecture::CoreArchitecture; use crate::function::Function; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref}; -use binaryninjacore_sys::{BNFreeCodeReferences, BNFreeDataReferences, BNReferenceSource}; +use binaryninjacore_sys::{ + BNCodeXref, BNDataXref, BNFreeCodeReferences, BNFreeCodeXrefs, BNFreeDataReferences, + BNFreeDataXrefs, BNReferenceSource, +}; /// A struct representing a single code cross-reference. #[derive(Debug)] @@ -19,7 +22,7 @@ impl CodeReference { false => Some(unsafe { Function::from_raw(value.func) }.to_owned()), true => None, }, - arch: match value.func.is_null() { + arch: match value.arch.is_null() { false => Some(unsafe { CoreArchitecture::from_raw(value.arch) }), true => None, }, @@ -110,3 +113,55 @@ unsafe impl CoreArrayProviderInner for DataReference { DataReference { address: *raw } } } + +/// A reference made by code, from the instruction at `source` to the address `target`. +#[derive(Debug)] +pub struct CodeXref { + pub source: CodeReference, + pub target: u64, +} + +impl CoreArrayProvider for CodeXref { + type Raw = BNCodeXref; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for CodeXref { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeCodeXrefs(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + CodeXref { + source: CodeReference::from_raw(&raw.source), + target: raw.target, + } + } +} + +/// A reference made by data, from the address `source` to the address `target`. +#[derive(Debug)] +pub struct DataXref { + pub source: u64, + pub target: u64, +} + +impl CoreArrayProvider for DataXref { + type Raw = BNDataXref; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for DataXref { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeDataXrefs(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + DataXref { + source: raw.source, + target: raw.target, + } + } +}