summaryrefslogtreecommitdiff
path: root/rust/src/mlil/function.rs
diff options
context:
space:
mode:
authorRubens Brandao <git@rubens.io>2024-05-07 09:52:19 -0300
committerKyle Martin <krm504@nyu.edu>2024-05-20 15:43:59 -0400
commit27bc08fa90d4381b4fd5d896dda991824504b0fd (patch)
tree842d477d932439765e94783f65f46dc66afd661c /rust/src/mlil/function.rs
parent82dd5d4b6fb97f4754d80aefe514d74b61c79054 (diff)
Implement python Function methods to rust
Squashed: add Function::add_tag method add Function::{add_user_code_ref,remove_user_code_ref} methods add Function::{add_user_type_field_ref, remove_user_type_field_ref} methods add Function::{add_user_type_ref, remove_user_type_ref} methods add Function::apply_auto_discovered_type add Function/MediumLevelILFunction user_var_values and related functions simplify UserVariableValues::values_from_variable cargo fmt fix fix doc and QualifiedName params fix MediumLevelILFunction::is_var_user_defined parameter Remove unecessary Safety comment add Function::{create_auto_stack_var,delete_auto_stack_var} methods add MediumLevelILFunction::create_auto_var method move Function::{create_auto_stack_var,delete_auto_stack_var} methods to MediumLevelILFunction add MediumLevelILFunction::{create_user_stack_var,delete_user_stack_var} methods add Function::block_annotations method add Function::{call_stack_adjustment, call_type_adjustment} method add Function::{constant_data, constants_referenced_by, constants_referenced_by_address_if_available} methods add Function::function_tags method add Function::{indirect_branches, indirect_branches_at} methods add Function::instr_highlight method add Function::instruction_containing_address method add Function::{int_display_type,int_enum_display_typeid,int_display_type_and_typeid} methods add MediumLevelILFunction::{var_refs, var_refs_from} methods add Function::{parameter_at, parameter_at_low_level_il_instruction} methods rebase GAT changes add Function::{reg_value_at, reg_value_after, reg_value_at_exit} methods Add alpha to HighlightColor::NoHighlightColor add Function::{regs_read_by, regs_written_by} methods add Function::{stack_contents_at, stack_contents_after} methods add Function::{stack_vars_referenced_by, stack_vars_referenced_by_address_if_available} methods add Function::{tags_at, tags_at_range} methods add Function::type_tokens method add Function::variables method add Function::{is_call_instruction, is_var_user_defined} methods add Function::{mark_updates_required, mark_caller_updates_required, mark_recent_use} methods add Function::{merge_vars, unmerge_vars, split_var, unsplit_var} methods add Function::reanalyze method add Function::request_debug_report method add Function::remove_tag method add Function::remove_tags_of_type method add Function::analysis_performance_info method add Function::call_sites method add Function::caller_sites method add Function::{calling_convention, set_calling_convention} methods add Function::{can_return, set_can_return} methods add Function::comments method add Function::{clobbered_regs, set_clobbered_regs} methods add Function::{has_explicitly_defined_type, has_user_annotations, has_user_type, has_variable_arguments} methods fix Function::set_can_return_user function add Function::{high_level_il_if_available, medium_level_il_if_available, low_level_il_if_available, lifted_il_if_available} methods add Function::{global_pointer_value, has_unresolved_indirect_branches} methods add Function::lowest_address method add Function::{inline_during_analysis, set_auto_inline_during_analysis, set_user_inline_during_analysis} methods add Function::{is_pure, is_too_large, is_update_needed} methods add Function::{provenance, stack_adjustment, set_user_stack_adjustment, set_auto_stack_adjustment} methods add Function::{set_user_pure, set_auto_pure} methods add Function::set_auto_type method add Function::{return_regs, set_return_regs} methods add Function::{set_auto_return_type, set_user_return_type} methods add Function::unresolved_stack_adjustment_graph method add Function::create_graph method add Function::tags method add Function::split_variables method add Function::{reg_stack_adjustments, set_reg_stack_adjustments} methods add Function::{mapped_medium_level_il, merged_variables} methods add Function::{set_auto_instr_highlight, set_user_instr_highlight} methods add stack_adjustments methods add Function::set_user_call_stack_adjustment add Function::set_auto_call_stack_adjustment add Function::call_type_adjustment add Function::set_user_call_type_adjustment add Function::set_auto_call_type_adjustment add Function::call_reg_stack_adjustment add Function::set_user_call_reg_stack_adjustment add Function::set_auto_call_reg_stack_adjustment add Function::call_reg_stack_adjustment_for_reg_stack add Function::set_user_call_reg_stack_adjustment_for_reg_stack add Function::set_auto_call_reg_stack_adjustment_for_reg_stack add Function::set_user_reg_stack_adjustments add Function::set_auto_reg_stack_adjustments add Function::set_auto_reg_stack_adjustments add Function::set_auto_calling_convention method add Function::set_auto_can_return method add Function::{set_user_has_variable_arguments, set_auto_has_variable_arguments} methods add Function::{set_user_indirect_branches, set_auto_indirect_branches} methods add Function::set_int_display_type method add Function::{set_user_parameter_variables, set_auto_parameter_variables} methods fix documentation add Function::unresolved_indirect_branches method add Function::mapped_medium_level_il_if_available method change methods `Function::{set_user_type, set_auto_type}` to receive `&Type` merge RegisterList and RegisterSet into CoreRegister impl fix function names fix function names fix documentation syntax fix documentation syntax fix Function documentation by adding MediumLevelILInstruction::get_split_var_for_definition fix documentation links rename `VariableDefinitions` to `MediumLevelILInstructionList` fix `PossibleValueSet` switched `NotInSetOfValues` and `ReturnAddressValue`
Diffstat (limited to 'rust/src/mlil/function.rs')
-rw-r--r--rust/src/mlil/function.rs411
1 files changed, 399 insertions, 12 deletions
diff --git a/rust/src/mlil/function.rs b/rust/src/mlil/function.rs
index 0b662578..e0856b93 100644
--- a/rust/src/mlil/function.rs
+++ b/rust/src/mlil/function.rs
@@ -1,19 +1,13 @@
use core::hash::{Hash, Hasher};
-use binaryninjacore_sys::BNFreeMediumLevelILFunction;
-use binaryninjacore_sys::BNGetMediumLevelILBasicBlockList;
-use binaryninjacore_sys::BNGetMediumLevelILIndexForInstruction;
-use binaryninjacore_sys::BNGetMediumLevelILInstructionCount;
-use binaryninjacore_sys::BNGetMediumLevelILOwnerFunction;
-use binaryninjacore_sys::BNGetMediumLevelILSSAForm;
-use binaryninjacore_sys::BNMediumLevelILFunction;
-use binaryninjacore_sys::BNMediumLevelILGetInstructionStart;
-use binaryninjacore_sys::BNNewMediumLevelILFunctionReference;
+use binaryninjacore_sys::*;
+use crate::architecture::CoreArchitecture;
use crate::basicblock::BasicBlock;
-use crate::function::Function;
-use crate::function::Location;
-use crate::rc::{Array, Ref, RefCountable};
+use crate::function::{Function, Location};
+use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable};
+use crate::string::BnStrCompatible;
+use crate::types::{Conf, PossibleValueSet, Type, UserVariableValues, Variable};
use super::{MediumLevelILBlock, MediumLevelILInstruction, MediumLevelILLiftedInstruction};
@@ -105,6 +99,277 @@ impl MediumLevelILFunction {
unsafe { Array::new(blocks, count, context) }
}
+
+ pub fn get_var_definitions<'a>(&'a self, var: &Variable) -> MediumLevelILInstructionList<'a> {
+ let mut count = 0;
+ let raw_instrs =
+ unsafe { BNGetMediumLevelILVariableDefinitions(self.handle, &var.raw(), &mut count) };
+ assert!(!raw_instrs.is_null());
+ let instrs = unsafe { core::slice::from_raw_parts(raw_instrs, count) };
+ MediumLevelILInstructionList {
+ mlil: self,
+ ptr: raw_instrs,
+ instr_idxs: instrs.iter(),
+ }
+ }
+
+ pub fn create_user_stack_var<'a, S: BnStrCompatible, C: Into<Conf<&'a Type>>>(
+ self,
+ offset: i64,
+ var_type: C,
+ name: S,
+ ) {
+ let var_type = var_type.into();
+ let mut raw_var_type: BNTypeWithConfidence = var_type.into();
+ let name = name.into_bytes_with_nul();
+ unsafe {
+ BNCreateUserStackVariable(
+ self.get_function().handle,
+ offset,
+ &mut raw_var_type,
+ name.as_ref().as_ptr() as *const i8,
+ )
+ }
+ }
+
+ pub fn delete_user_stack_var(self, offset: i64) {
+ unsafe { BNDeleteUserStackVariable(self.get_function().handle, offset) }
+ }
+
+ pub fn create_user_var<'a, S: BnStrCompatible, C: Into<Conf<&'a Type>>>(
+ &self,
+ var: &Variable,
+ var_type: C,
+ name: S,
+ ignore_disjoint_uses: bool,
+ ) {
+ let var_type = var_type.into();
+ let raw_var_type: BNTypeWithConfidence = var_type.into();
+ let name = name.into_bytes_with_nul();
+ unsafe {
+ BNCreateUserVariable(
+ self.get_function().handle,
+ &var.raw(),
+ &raw_var_type as *const _ as *mut _,
+ name.as_ref().as_ptr() as *const _,
+ ignore_disjoint_uses,
+ )
+ }
+ }
+
+ pub fn delete_user_var(&self, var: &Variable) {
+ unsafe { BNDeleteUserVariable(self.get_function().handle, &var.raw()) }
+ }
+
+ pub fn is_var_user_defined(&self, var: &Variable) -> bool {
+ unsafe { BNIsVariableUserDefined(self.get_function().handle, &var.raw()) }
+ }
+
+ /// Allows the user to specify a PossibleValueSet value for an MLIL
+ /// variable at its definition site.
+ ///
+ /// .. warning:: Setting the variable value, triggers a reanalysis of the
+ /// function and allows the dataflow to compute and propagate values which
+ /// depend on the current variable. This implies that branch conditions
+ /// whose values can be determined statically will be computed, leading to
+ /// potential branch elimination at the HLIL layer.
+ ///
+ /// * `var` - Variable for which the value is to be set
+ /// * `addr` - Address of the definition site of the variable
+ /// * `value` - Informed value of the variable
+ ///
+ /// # Example
+ /// ```no_run
+ /// # use binaryninja::mlil::MediumLevelILFunction;
+ /// # use binaryninja::types::PossibleValueSet;
+ /// # let mlil_fun: MediumLevelILFunction = todo!();
+ /// let (mlil_var, arch_addr, _val) = mlil_fun.user_var_values().all().next().unwrap();
+ /// let def_address = arch_addr.address;
+ /// let var_value = PossibleValueSet::ConstantValue{value: 5};
+ /// mlil_fun.set_user_var_value(&mlil_var, def_address, var_value).unwrap();
+ /// ```
+ pub fn set_user_var_value(
+ &self,
+ var: &Variable,
+ addr: u64,
+ value: PossibleValueSet,
+ ) -> Result<(), ()> {
+ let Some(_def_site) = self
+ .get_var_definitions(var)
+ .find(|def| def.address == addr)
+ else {
+ // Error "No definition for Variable found at given address"
+ return Err(());
+ };
+ let function = self.get_function();
+ let def_site = BNArchitectureAndAddress {
+ arch: function.arch().0,
+ address: addr,
+ };
+ let value = value.into_raw();
+
+ unsafe { BNSetUserVariableValue(function.handle, &var.raw(), &def_site, value.as_ffi()) }
+ Ok(())
+ }
+
+ /// Clears a previously defined user variable value.
+ ///
+ /// * `var` - Variable for which the value was informed
+ /// * `def_addr` - Address of the definition site of the variable
+ pub fn clear_user_var_value(&self, var: &Variable, addr: u64) -> Result<(), ()> {
+ let Some(_var_def) = self
+ .get_var_definitions(var)
+ .find(|site| site.address == addr)
+ else {
+ //error "Could not get definition for Variable"
+ return Err(());
+ };
+
+ let function = self.get_function();
+ let def_site = BNArchitectureAndAddress {
+ arch: function.arch().0,
+ address: addr,
+ };
+
+ unsafe { BNClearUserVariableValue(function.handle, &var.raw(), &def_site) };
+ Ok(())
+ }
+
+ /// Returns a map of current defined user variable values.
+ /// Returns a Map of user current defined user variable values and their definition sites.
+ pub fn user_var_values(&self) -> UserVariableValues {
+ let mut count = 0;
+ let function = self.get_function();
+ let var_values = unsafe { BNGetAllUserVariableValues(function.handle, &mut count) };
+ assert!(!var_values.is_null());
+ UserVariableValues {
+ vars: core::ptr::slice_from_raw_parts(var_values, count),
+ }
+ }
+
+ /// Clear all user defined variable values.
+ pub fn clear_user_var_values(&self) -> Result<(), ()> {
+ for (var, arch_and_addr, _value) in self.user_var_values().all() {
+ self.clear_user_var_value(&var, arch_and_addr.address)?;
+ }
+ Ok(())
+ }
+
+ pub fn create_auto_stack_var<'a, T: Into<Conf<&'a Type>>, S: BnStrCompatible>(
+ &self,
+ offset: i64,
+ var_type: T,
+ name: S,
+ ) {
+ let var_type: Conf<&Type> = var_type.into();
+ let mut var_type = var_type.into();
+ let name = name.into_bytes_with_nul();
+ let name_c_str = name.as_ref();
+ unsafe {
+ BNCreateAutoStackVariable(
+ self.get_function().handle,
+ offset,
+ &mut var_type,
+ name_c_str.as_ptr() as *const i8,
+ )
+ }
+ }
+
+ pub fn delete_auto_stack_var(&self, offset: i64) {
+ unsafe { BNDeleteAutoStackVariable(self.get_function().handle, offset) }
+ }
+
+ pub fn create_auto_var<'a, S: BnStrCompatible, C: Into<Conf<&'a Type>>>(
+ &self,
+ var: &Variable,
+ var_type: C,
+ name: S,
+ ignore_disjoint_uses: bool,
+ ) {
+ let var_type: Conf<&Type> = var_type.into();
+ let mut var_type = var_type.into();
+ let name = name.into_bytes_with_nul();
+ let name_c_str = name.as_ref();
+ unsafe {
+ BNCreateAutoVariable(
+ self.get_function().handle,
+ &var.raw(),
+ &mut var_type,
+ name_c_str.as_ptr() as *const i8,
+ ignore_disjoint_uses,
+ )
+ }
+ }
+
+ /// 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<ILReferenceSource> {
+ 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<u64>,
+ arch: Option<CoreArchitecture>,
+ ) -> Array<VariableReferenceSource> {
+ 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 {
@@ -132,3 +397,125 @@ impl core::fmt::Debug for MediumLevelILFunction {
write!(f, "<mlil func handle {:p}>", self.handle)
}
}
+
+#[derive(Clone, Debug)]
+pub struct MediumLevelILInstructionList<'a> {
+ mlil: &'a MediumLevelILFunction,
+ ptr: *mut usize,
+ instr_idxs: core::slice::Iter<'a, usize>,
+}
+
+impl Drop for MediumLevelILInstructionList<'_> {
+ fn drop(&mut self) {
+ unsafe { BNFreeILInstructionList(self.ptr) };
+ }
+}
+
+impl Iterator for MediumLevelILInstructionList<'_> {
+ type Item = MediumLevelILInstruction;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.instr_idxs
+ .next()
+ .map(|i| self.mlil.instruction_from_instruction_idx(*i))
+ }
+}
+
+impl DoubleEndedIterator for MediumLevelILInstructionList<'_> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.instr_idxs
+ .next_back()
+ .map(|i| self.mlil.instruction_from_instruction_idx(*i))
+ }
+}
+
+impl ExactSizeIterator for MediumLevelILInstructionList<'_> {}
+impl core::iter::FusedIterator for MediumLevelILInstructionList<'_> {}
+
+/////////////////////////
+// FunctionGraphType
+
+pub type FunctionGraphType = binaryninjacore_sys::BNFunctionGraphType;
+
+/////////////////////////
+// ILReferenceSource
+
+pub struct ILReferenceSource {
+ mlil: Ref<MediumLevelILFunction>,
+ _func: Ref<Function>,
+ _arch: CoreArchitecture,
+ addr: u64,
+ type_: FunctionGraphType,
+ expr_id: usize,
+}
+
+impl ILReferenceSource {
+ unsafe fn from_raw(value: BNILReferenceSource, mlil: Ref<MediumLevelILFunction>) -> 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<MediumLevelILFunction>;
+ type Wrapped<'a> = Self;
+}
+unsafe impl CoreArrayProviderInner for ILReferenceSource {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeILReferences(raw, count)
+ }
+ 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<MediumLevelILFunction>;
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for VariableReferenceSource {
+ unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
+ BNFreeVariableReferenceSourceList(raw, count)
+ }
+ 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()),
+ }
+ }
+}