diff --git a/rust/src/function.rs b/rust/src/function.rs index 795882c52..bd9c9de0d 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -226,13 +226,14 @@ impl Function { /// ```no_run /// # use binaryninja::function::Function; /// # let fun: Function = todo!(); - /// let blocks = fun.basic_block_containing(0x1000); + /// let blocks = fun.basic_block_containing(0x1000, None); /// ``` pub fn basic_block_containing( &self, - arch: &CoreArchitecture, addr: u64, + arch: Option, ) -> Option>> { + let arch = arch.unwrap_or_else(|| self.arch()); unsafe { let block = BNGetFunctionBasicBlockAtAddress(self.handle, arch.0, addr); let context = NativeBlock { _priv: () }; diff --git a/rust/src/mlil/function.rs b/rust/src/mlil/function.rs index 0c3131af1..56d958e50 100644 --- a/rust/src/mlil/function.rs +++ b/rust/src/mlil/function.rs @@ -2,9 +2,12 @@ use core::hash::{Hash, Hasher}; use binaryninjacore_sys::*; +use crate::architecture::CoreArchitecture; use crate::basicblock::BasicBlock; use crate::function::{Function, Location}; -use crate::rc::{Array, Ref, RefCountable}; +use crate::rc::{ + Array, CoreArrayProvider, CoreArrayWrapper, CoreOwnedArrayProvider, Ref, RefCountable, +}; use crate::string::BnStrCompatible; use crate::types::{Conf, PossibleValueSet, Type, UserVariableValues, Variable}; @@ -299,6 +302,76 @@ impl MediumLevelILFunction { ) } } + + /// Returns a list of ILReferenceSource objects (IL xrefs or cross-references) + /// that reference the given variable. The variable is a local variable that can be either on the stack, + /// in a register, or in a flag. + /// This function is related to get_hlil_var_refs(), which returns variable references collected + /// from HLIL. The two can be different in several cases, e.g., multiple variables in MLIL can be merged + /// into a single variable in HLIL. + /// + /// * `var` - Variable for which to query the xref + /// + /// # Example + /// ```no_run + /// # use binaryninja::mlil::MediumLevelILFunction; + /// # use binaryninja::types::Variable; + /// # let mlil_fun: MediumLevelILFunction = todo!(); + /// # let mlil_var: Variable = todo!(); + /// let instr = mlil_fun.var_refs(&mlil_var).get(0).expr(); + /// ``` + pub fn var_refs(&self, var: &Variable) -> Array { + let mut count = 0; + let refs = unsafe { + BNGetMediumLevelILVariableReferences( + self.get_function().handle, + &mut var.raw(), + &mut count, + ) + }; + assert!(!refs.is_null()); + unsafe { Array::new(refs, count, self.to_owned()) } + } + + /// Returns a list of variables referenced by code in the function ``func``, + /// of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from + /// all functions and containing the address will be returned. If no architecture is specified, the + /// architecture of the function will be used. + /// This function is related to get_hlil_var_refs_from(), which returns variable references collected + /// from HLIL. The two can be different in several cases, e.g., multiple variables in MLIL can be merged + /// into a single variable in HLIL. + /// + /// * `addr` - virtual address to query for variable references + /// * `length` - optional length of query + /// * `arch` - optional architecture of query + pub fn var_refs_from( + &self, + addr: u64, + length: Option, + arch: Option, + ) -> Array { + let function = self.get_function(); + let arch = arch.unwrap_or_else(|| function.arch()); + let mut count = 0; + + let refs = if let Some(length) = length { + unsafe { + BNGetMediumLevelILVariableReferencesInRange( + function.handle, + arch.0, + addr, + length, + &mut count, + ) + } + } else { + unsafe { + BNGetMediumLevelILVariableReferencesFrom(function.handle, arch.0, addr, &mut count) + } + }; + assert!(!refs.is_null()); + unsafe { Array::new(refs, count, self.to_owned()) } + } } impl ToOwned for MediumLevelILFunction { @@ -360,3 +433,100 @@ impl DoubleEndedIterator for VariableDefinitions<'_> { impl ExactSizeIterator for VariableDefinitions<'_> {} impl core::iter::FusedIterator for VariableDefinitions<'_> {} + +///////////////////////// +// FunctionGraphType + +pub type FunctionGraphType = binaryninjacore_sys::BNFunctionGraphType; + +///////////////////////// +// ILReferenceSource + +pub struct ILReferenceSource { + mlil: Ref, + _func: Ref, + _arch: CoreArchitecture, + addr: u64, + type_: FunctionGraphType, + expr_id: usize, +} + +impl ILReferenceSource { + unsafe fn from_raw(value: BNILReferenceSource, mlil: Ref) -> Self { + Self { + mlil, + _func: Function::from_raw(value.func), + _arch: CoreArchitecture::from_raw(value.arch), + addr: value.addr, + type_: value.type_, + expr_id: value.exprId, + } + } + pub fn addr(&self) -> u64 { + self.addr + } + pub fn graph_type(&self) -> FunctionGraphType { + self.type_ + } + pub fn expr(&self) -> MediumLevelILInstruction { + self.mlil.instruction_from_idx(self.expr_id) + } +} + +impl CoreArrayProvider for ILReferenceSource { + type Raw = BNILReferenceSource; + type Context = Ref; +} + +unsafe impl CoreOwnedArrayProvider for ILReferenceSource { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeILReferences(raw, count) + } +} + +unsafe impl CoreArrayWrapper for ILReferenceSource { + type Wrapped<'a> = Self; + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::from_raw(*raw, context.to_owned()) + } +} + +///////////////////////// +// VariableReferenceSource + +pub struct VariableReferenceSource { + var: Variable, + source: ILReferenceSource, +} + +impl VariableReferenceSource { + pub fn variable(&self) -> &Variable { + &self.var + } + pub fn source(&self) -> &ILReferenceSource { + &self.source + } +} + +impl CoreArrayProvider for VariableReferenceSource { + type Raw = BNVariableReferenceSource; + type Context = Ref; +} + +unsafe impl CoreOwnedArrayProvider for VariableReferenceSource { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeVariableReferenceSourceList(raw, count) + } +} + +unsafe impl CoreArrayWrapper for VariableReferenceSource { + type Wrapped<'a> = Self; + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + Self { + var: Variable::from_raw(raw.var), + source: ILReferenceSource::from_raw(raw.source, context.to_owned()), + } + } +} diff --git a/rust/src/types.rs b/rust/src/types.rs index 2e3235b71..50f74d1d3 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -3434,7 +3434,6 @@ impl HighlightColor { } } - ///////////////////////// // IntegerDisplayType