summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/mlil/function.rs207
-rw-r--r--rust/src/mlil/instruction.rs426
-rw-r--r--rust/src/types.rs38
3 files changed, 661 insertions, 10 deletions
diff --git a/rust/src/mlil/function.rs b/rust/src/mlil/function.rs
index 3a3ce5e8..d9e13313 100644
--- a/rust/src/mlil/function.rs
+++ b/rust/src/mlil/function.rs
@@ -5,10 +5,14 @@ use binaryninjacore_sys::*;
use crate::architecture::CoreArchitecture;
use crate::basicblock::BasicBlock;
+use crate::disassembly::DisassemblySettings;
+use crate::flowgraph::FlowGraph;
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 crate::types::{
+ Conf, PossibleValueSet, RegisterValue, SSAVariable, Type, UserVariableValues, Variable,
+};
use super::{MediumLevelILBlock, MediumLevelILInstruction, MediumLevelILLiftedInstruction};
@@ -371,6 +375,207 @@ impl MediumLevelILFunction {
assert!(!refs.is_null());
unsafe { Array::new(refs, count, self.to_owned()) }
}
+
+ /// Current IL Address
+ pub fn current_address(&self) -> u64 {
+ unsafe { BNMediumLevelILGetCurrentAddress(self.handle) }
+ }
+
+ /// Set the current IL Address
+ pub fn set_current_address(&self, value: u64, arch: Option<CoreArchitecture>) {
+ let arch = arch
+ .map(|x| x.0)
+ .unwrap_or_else(|| self.get_function().arch().0);
+ unsafe { BNMediumLevelILSetCurrentAddress(self.handle, arch, value) }
+ }
+
+ /// Returns the BasicBlock at the given MLIL `instruction`.
+ pub fn basic_block_containing(
+ &self,
+ instruction: &MediumLevelILInstruction,
+ ) -> Option<BasicBlock<MediumLevelILBlock>> {
+ let index = instruction.index;
+ let block = unsafe { BNGetMediumLevelILBasicBlockForInstruction(self.handle, index) };
+ (!block.is_null()).then(|| unsafe {
+ BasicBlock::from_raw(
+ block,
+ MediumLevelILBlock {
+ function: self.to_owned(),
+ },
+ )
+ })
+ }
+ /// ends the function and computes the list of basic blocks.
+ pub fn finalize(&self) {
+ unsafe { BNFinalizeMediumLevelILFunction(self.handle) }
+ }
+
+ /// Generate SSA form given the current MLIL
+ ///
+ /// * `analyze_conditionals` - whether or not to analyze conditionals
+ /// * `handle_aliases` - whether or not to handle aliases
+ /// * `known_not_aliases` - optional list of variables known to be not aliased
+ /// * `known_aliases` - optional list of variables known to be aliased
+ pub fn generate_ssa_form(
+ &self,
+ analyze_conditionals: bool,
+ handle_aliases: bool,
+ known_not_aliases: impl IntoIterator<Item = Variable>,
+ known_aliases: impl IntoIterator<Item = Variable>,
+ ) {
+ let mut known_not_aliases: Box<[_]> =
+ known_not_aliases.into_iter().map(|x| x.raw()).collect();
+ let mut known_aliases: Box<[_]> = known_aliases.into_iter().map(|x| x.raw()).collect();
+ let (known_not_aliases_ptr, known_not_aliases_len) = if known_not_aliases.is_empty() {
+ (core::ptr::null_mut(), 0)
+ } else {
+ (known_not_aliases.as_mut_ptr(), known_not_aliases.len())
+ };
+ let (known_aliases_ptr, known_aliases_len) = if known_not_aliases.is_empty() {
+ (core::ptr::null_mut(), 0)
+ } else {
+ (known_aliases.as_mut_ptr(), known_aliases.len())
+ };
+ unsafe {
+ BNGenerateMediumLevelILSSAForm(
+ self.handle,
+ analyze_conditionals,
+ handle_aliases,
+ known_not_aliases_ptr,
+ known_not_aliases_len,
+ known_aliases_ptr,
+ known_aliases_len,
+ )
+ }
+ }
+
+ /// Gets the instruction that contains the given SSA variable's definition.
+ ///
+ /// Since SSA variables can only be defined once, this will return the single instruction where that occurs.
+ /// For SSA variable version 0s, which don't have definitions, this will return None instead.
+ pub fn ssa_variable_definition(&self, var: SSAVariable) -> Option<MediumLevelILInstruction> {
+ let result = unsafe {
+ BNGetMediumLevelILSSAVarDefinition(self.handle, &var.variable.raw(), var.version)
+ };
+ (result < self.instruction_count())
+ .then(|| MediumLevelILInstruction::new(self.to_owned(), result))
+ }
+
+ pub fn ssa_memory_definition(&self, version: usize) -> Option<MediumLevelILInstruction> {
+ let result = unsafe { BNGetMediumLevelILSSAMemoryDefinition(self.handle, version) };
+ (result < self.instruction_count())
+ .then(|| MediumLevelILInstruction::new(self.to_owned(), result))
+ }
+
+ ///Gets all the instructions that use the given SSA variable.
+ pub fn ssa_variable_uses(&self, ssa_var: SSAVariable) -> Array<MediumLevelILInstruction> {
+ let mut count = 0;
+ let uses = unsafe {
+ BNGetMediumLevelILSSAVarUses(
+ self.handle,
+ &ssa_var.variable.raw(),
+ ssa_var.version,
+ &mut count,
+ )
+ };
+ assert!(!uses.is_null());
+ unsafe { Array::new(uses, count, self.to_owned()) }
+ }
+
+ pub fn ssa_memory_uses(&self, version: usize) -> Array<MediumLevelILInstruction> {
+ let mut count = 0;
+ let uses = unsafe { BNGetMediumLevelILSSAMemoryUses(self.handle, version, &mut count) };
+ assert!(!uses.is_null());
+ unsafe { Array::new(uses, count, self.to_owned()) }
+ }
+
+ /// determines if `ssa_var` is live at any point in the function
+ pub fn is_ssa_variable_live(&self, ssa_var: SSAVariable) -> bool {
+ unsafe {
+ BNIsMediumLevelILSSAVarLive(self.handle, &ssa_var.variable.raw(), ssa_var.version)
+ }
+ }
+
+ pub fn variable_definitions(&self, variable: Variable) -> Array<MediumLevelILInstruction> {
+ let mut count = 0;
+ let defs = unsafe {
+ BNGetMediumLevelILVariableDefinitions(self.handle, &variable.raw(), &mut count)
+ };
+ unsafe { Array::new(defs, count, self.to_owned()) }
+ }
+
+ pub fn variable_uses(&self, variable: Variable) -> Array<MediumLevelILInstruction> {
+ let mut count = 0;
+ let uses =
+ unsafe { BNGetMediumLevelILVariableUses(self.handle, &variable.raw(), &mut count) };
+ unsafe { Array::new(uses, count, self.to_owned()) }
+ }
+
+ /// Computes the list of instructions for which `var` is live.
+ /// If `include_last_use` is false, the last use of the variable will not be included in the
+ /// list (this allows for easier computation of overlaps in liveness between two variables).
+ /// If the variable is never used, this function will return an empty list.
+ ///
+ /// `var` - the variable to query
+ /// `include_last_use` - whether to include the last use of the variable in the list of instructions
+ pub fn live_instruction_for_variable(
+ &self,
+ variable: Variable,
+ include_last_user: bool,
+ ) -> Array<MediumLevelILInstruction> {
+ let mut count = 0;
+ let uses = unsafe {
+ BNGetMediumLevelILLiveInstructionsForVariable(
+ self.handle,
+ &variable.raw(),
+ include_last_user,
+ &mut count,
+ )
+ };
+ unsafe { Array::new(uses, count, self.to_owned()) }
+ }
+
+ pub fn ssa_variable_value(&self, ssa_var: SSAVariable) -> RegisterValue {
+ unsafe {
+ BNGetMediumLevelILSSAVarValue(self.handle, &ssa_var.variable.raw(), ssa_var.version)
+ }
+ .into()
+ }
+
+ pub fn create_graph(&self, settings: Option<DisassemblySettings>) -> FlowGraph {
+ let settings = settings.map(|x| x.handle).unwrap_or(core::ptr::null_mut());
+ let graph = unsafe { BNCreateMediumLevelILFunctionGraph(self.handle, settings) };
+ unsafe { FlowGraph::from_raw(graph) }
+ }
+
+ /// This gets just the MLIL variables - you may be interested in the union
+ /// of [MediumLevelIlFunction::aliased_variables] and
+ /// [crate::function::Function::parameter_variables] for all the
+ /// variables used in the function
+ pub fn variables(&self) -> Array<Variable> {
+ let mut count = 0;
+ let uses = unsafe { BNGetMediumLevelILVariables(self.handle, &mut count) };
+ unsafe { Array::new(uses, count, ()) }
+ }
+
+ /// This returns a list of Variables that are taken reference to and used
+ /// elsewhere. You may also wish to consider [MediumLevelIlFunction::variables]
+ /// and [crate::function::Function::parameter_variables]
+ pub fn aliased_variables(&self) -> Array<Variable> {
+ let mut count = 0;
+ let uses = unsafe { BNGetMediumLevelILAliasedVariables(self.handle, &mut count) };
+ unsafe { Array::new(uses, count, ()) }
+ }
+
+ /// This gets just the MLIL SSA variables - you may be interested in the
+ /// union of [MediumLevelIlFunction::aliased_variables] and
+ /// [crate::function::Function::parameter_variables] for all the
+ /// variables used in the function.
+ pub fn ssa_variables(&self) -> Array<Array<SSAVariable>> {
+ let mut count = 0;
+ let vars = unsafe { BNGetMediumLevelILVariables(self.handle, &mut count) };
+ unsafe { Array::new(vars, count, self.to_owned()) }
+ }
}
impl ToOwned for MediumLevelILFunction {
diff --git a/rust/src/mlil/instruction.rs b/rust/src/mlil/instruction.rs
index 00c97cb2..88564cc6 100644
--- a/rust/src/mlil/instruction.rs
+++ b/rust/src/mlil/instruction.rs
@@ -1,12 +1,13 @@
-use binaryninjacore_sys::BNGetDefaultIndexForMediumLevelILVariableDefinition;
-use binaryninjacore_sys::BNGetMediumLevelILByIndex;
-use binaryninjacore_sys::BNMediumLevelILInstruction;
-use binaryninjacore_sys::BNMediumLevelILOperation;
+use binaryninjacore_sys::*;
use crate::architecture::CoreIntrinsic;
+use crate::disassembly::InstructionTextToken;
use crate::operand_iter::OperandIter;
-use crate::rc::Ref;
-use crate::types::{ConstantData, RegisterValue, RegisterValueType, SSAVariable, Variable};
+use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
+use crate::types::{
+ Conf, ConstantData, DataFlowQueryOption, ILBranchDependence, PossibleValueSet,
+ RegisterValue, RegisterValueType, SSAVariable, Type, Variable,
+};
use super::lift::*;
use super::operation::*;
@@ -1033,20 +1034,386 @@ impl MediumLevelILInstruction {
}
}
+ pub fn tokens(&self) -> Array<InstructionTextToken> {
+ let mut count = 0;
+ let mut tokens = core::ptr::null_mut();
+ assert!(unsafe {
+ BNGetMediumLevelILExprText(
+ self.function.handle,
+ self.function.get_function().arch().0,
+ self.index,
+ &mut tokens,
+ &mut count,
+ core::ptr::null_mut(),
+ )
+ });
+ unsafe { Array::new(tokens, count, ()) }
+ }
+
+ /// Value of expression if constant or a known value
+ pub fn value(&self) -> RegisterValue {
+ unsafe { BNGetMediumLevelILExprValue(self.function.handle, self.index) }.into()
+ }
+
+ /// Possible values of expression using path-sensitive static data flow analysis
+ pub fn possible_values(&self, options: Option<&[DataFlowQueryOption]>) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleExprValues(
+ self.function.handle,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
+ pub fn possible_ssa_variable_values(
+ &self,
+ ssa_var: SSAVariable,
+ options: Option<&[DataFlowQueryOption]>,
+ ) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleSSAVarValues(
+ self.function.handle,
+ &ssa_var.variable.raw(),
+ ssa_var.version,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
+ /// return the variable version used at this instruction
+ pub fn ssa_variable_version(&self, var: Variable) -> SSAVariable {
+ let version = unsafe {
+ BNGetMediumLevelILSSAVarVersionAtILInstruction(
+ self.function.handle,
+ &var.raw(),
+ self.index,
+ )
+ };
+ SSAVariable::new(var, version)
+ }
+
+ /// Set of branching instructions that must take the true or false path to reach this instruction
+ pub fn branch_dependence(&self) -> Array<BranchDependence> {
+ let mut count = 0;
+ let deps = unsafe {
+ BNGetAllMediumLevelILBranchDependence(self.function.handle, self.index, &mut count)
+ };
+ assert!(!deps.is_null());
+ unsafe { Array::new(deps, count, self.function.clone()) }
+ }
+
+ pub fn branch_dependence_at(&self, instruction: MediumLevelILInstruction) -> BranchDependence {
+ let deps = unsafe {
+ BNGetMediumLevelILBranchDependence(self.function.handle, self.index, instruction.index)
+ };
+ BranchDependence {
+ instruction,
+ dependence: deps,
+ }
+ }
+
+ /// Version of active memory contents in SSA form for this instruction
+ pub fn ssa_memory_version(&self) -> usize {
+ unsafe {
+ BNGetMediumLevelILSSAMemoryVersionAtILInstruction(self.function.handle, self.index)
+ }
+ }
+
+ /// Type of expression
+ pub fn expr_type(&self) -> Option<Conf<Ref<Type>>> {
+ let result = unsafe { BNGetMediumLevelILExprType(self.function.handle, self.index) };
+ (!result.type_.is_null()).then(|| {
+ Conf::new(
+ unsafe { Type::ref_from_raw(result.type_) },
+ result.confidence,
+ )
+ })
+ }
+
+ /// Set type of expression
+ ///
+ /// This API is only meant for workflows or for debugging purposes, since the changes they make are not persistent
+ /// and get lost after a database save and reload. To make persistent changes to the analysis, one should use other
+ /// APIs to, for example, change the type of variables. The analysis will then propagate the type of the variable
+ /// and update the type of related expressions.
+ pub fn set_expr_type<'a, T: Into<Conf<&'a Type>>>(&self, value: T) {
+ let type_: Conf<&'a Type> = value.into();
+ let mut type_raw: BNTypeWithConfidence = BNTypeWithConfidence {
+ type_: type_.contents.handle,
+ confidence: type_.confidence,
+ };
+ unsafe { BNSetMediumLevelILExprType(self.function.handle, self.index, &mut type_raw) }
+ }
+
+ pub fn variable_for_register(&self, reg_id: u32) -> Variable {
+ let result = unsafe {
+ BNGetMediumLevelILVariableForRegisterAtInstruction(
+ self.function.handle,
+ reg_id,
+ self.index,
+ )
+ };
+ unsafe { Variable::from_raw(result) }
+ }
+
+ pub fn variable_for_flag(&self, flag_id: u32) -> Variable {
+ let result = unsafe {
+ BNGetMediumLevelILVariableForFlagAtInstruction(
+ self.function.handle,
+ flag_id,
+ self.index,
+ )
+ };
+ unsafe { Variable::from_raw(result) }
+ }
+
+ pub fn variable_for_stack_location(&self, offset: i64) -> Variable {
+ let result = unsafe {
+ BNGetMediumLevelILVariableForStackLocationAtInstruction(
+ self.function.handle,
+ offset,
+ self.index,
+ )
+ };
+ unsafe { Variable::from_raw(result) }
+ }
+
+ pub fn register_value(&self, reg_id: u32) -> RegisterValue {
+ unsafe {
+ BNGetMediumLevelILRegisterValueAtInstruction(self.function.handle, reg_id, self.index)
+ }
+ .into()
+ }
+
+ pub fn register_value_after(&self, reg_id: u32) -> RegisterValue {
+ unsafe {
+ BNGetMediumLevelILRegisterValueAfterInstruction(
+ self.function.handle,
+ reg_id,
+ self.index,
+ )
+ }
+ .into()
+ }
+
+ pub fn possible_register_values(
+ &self,
+ reg_id: u32,
+ options: Option<&[DataFlowQueryOption]>,
+ ) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleRegisterValuesAtInstruction(
+ self.function.handle,
+ reg_id,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
+ pub fn possible_register_values_after(
+ &self,
+ reg_id: u32,
+ options: Option<&[DataFlowQueryOption]>,
+ ) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleRegisterValuesAfterInstruction(
+ self.function.handle,
+ reg_id,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
+ pub fn flag_value(&self, flag_id: u32) -> RegisterValue {
+ unsafe {
+ BNGetMediumLevelILFlagValueAtInstruction(self.function.handle, flag_id, self.index)
+ }
+ .into()
+ }
+
+ pub fn flag_value_after(&self, flag_id: u32) -> RegisterValue {
+ unsafe {
+ BNGetMediumLevelILFlagValueAfterInstruction(self.function.handle, flag_id, self.index)
+ }
+ .into()
+ }
+
+ pub fn possible_flag_values(
+ &self,
+ flag_id: u32,
+ options: Option<&[DataFlowQueryOption]>,
+ ) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleFlagValuesAtInstruction(
+ self.function.handle,
+ flag_id,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
+ pub fn possible_flag_values_after(
+ &self,
+ flag_id: u32,
+ options: Option<&[DataFlowQueryOption]>,
+ ) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleFlagValuesAfterInstruction(
+ self.function.handle,
+ flag_id,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
+ pub fn stack_contents(&self, offset: i64, size: usize) -> RegisterValue {
+ unsafe {
+ BNGetMediumLevelILStackContentsAtInstruction(
+ self.function.handle,
+ offset,
+ size,
+ self.index,
+ )
+ }
+ .into()
+ }
+
+ pub fn stack_contents_after(&self, offset: i64, size: usize) -> RegisterValue {
+ unsafe {
+ BNGetMediumLevelILStackContentsAfterInstruction(
+ self.function.handle,
+ offset,
+ size,
+ self.index,
+ )
+ }
+ .into()
+ }
+
+ pub fn possible_stack_contents(
+ &self,
+ offset: i64,
+ size: usize,
+ options: Option<&[DataFlowQueryOption]>,
+ ) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleStackContentsAtInstruction(
+ self.function.handle,
+ offset,
+ size,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
+ pub fn possible_stack_contents_after(
+ &self,
+ offset: i64,
+ size: usize,
+ options: Option<&[DataFlowQueryOption]>,
+ ) -> PossibleValueSet {
+ let options_ptr = options
+ .map(|op| op.as_ptr() as *mut DataFlowQueryOption)
+ .unwrap_or(core::ptr::null_mut());
+ let options_len = options.map(|op| op.len()).unwrap_or(0);
+ let mut value = unsafe {
+ BNGetMediumLevelILPossibleStackContentsAfterInstruction(
+ self.function.handle,
+ offset,
+ size,
+ self.index,
+ options_ptr,
+ options_len,
+ )
+ };
+ let result = unsafe { PossibleValueSet::from_raw(value) };
+ unsafe { BNFreePossibleValueSet(&mut value) }
+ result
+ }
+
/// Gets the unique variable for a definition instruction. This unique variable can be passed
/// to [crate::function::Function::split_variable] to split a variable at a definition. The given `var` is the
/// assigned variable to query.
///
/// * `var` - variable to query
- pub fn get_split_var_for_definition(&self, var: &Variable) -> Variable {
- let new_index = unsafe {
+ pub fn split_var_for_definition(&self, var: Variable) -> Variable {
+ let index = unsafe {
BNGetDefaultIndexForMediumLevelILVariableDefinition(
self.function.handle,
&var.raw(),
self.index,
)
};
- Variable::new(var.t, new_index, var.storage)
+ Variable::new(var.t, index, var.storage)
+ }
+
+ /// alias for [MediumLevelILInstruction::split_var_for_definition]
+ #[inline]
+ pub fn get_split_var_for_definition(&self, var: &Variable) -> Variable {
+ self.split_var_for_definition(*var)
}
fn lift_operand(&self, expr_idx: usize) -> Box<MediumLevelILLiftedInstruction> {
@@ -1122,6 +1489,22 @@ impl MediumLevelILInstruction {
}
}
+impl CoreArrayProvider for MediumLevelILInstruction {
+ type Raw = usize;
+ type Context = Ref<MediumLevelILFunction>;
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for MediumLevelILInstruction {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ BNFreeILInstructionList(raw)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ context.instruction_from_idx(*raw)
+ }
+}
+
fn get_float(value: u64, size: usize) -> f64 {
match size {
4 => f32::from_bits(value as u32) as f64,
@@ -1175,3 +1558,28 @@ fn get_call_params_ssa(
assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA);
OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).exprs()
}
+
+/// Conditional branching instruction and an expected conditional result
+pub struct BranchDependence {
+ pub instruction: MediumLevelILInstruction,
+ pub dependence: ILBranchDependence,
+}
+
+impl CoreArrayProvider for BranchDependence {
+ type Raw = BNILBranchInstructionAndDependence;
+ type Context = Ref<MediumLevelILFunction>;
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for BranchDependence {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ unsafe { BNFreeILBranchDependenceList(raw) };
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Self {
+ instruction: MediumLevelILInstruction::new(context.clone(), raw.branch),
+ dependence: raw.dependence,
+ }
+ }
+}
diff --git a/rust/src/types.rs b/rust/src/types.rs
index 7adc449e..29cdb2d3 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -24,6 +24,7 @@ use crate::{
callingconvention::CallingConvention,
filemetadata::FileMetadata,
function::Function,
+ mlil::MediumLevelILFunction,
rc::*,
string::{raw_to_string, BnStrCompatible, BnString},
symbol::Symbol,
@@ -51,6 +52,8 @@ pub type TypeClass = BNTypeClass;
pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass;
pub type MemberAccess = BNMemberAccess;
pub type MemberScope = BNMemberScope;
+pub type ILBranchDependence = BNILBranchDependence;
+pub type DataFlowQueryOption = BNDataFlowQueryOption;
////////////////
// Confidence
@@ -1442,6 +1445,41 @@ impl SSAVariable {
}
}
+impl CoreArrayProvider for SSAVariable {
+ type Raw = usize;
+ type Context = Variable;
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for SSAVariable {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ BNFreeILInstructionList(raw)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ SSAVariable::new(*context, *raw)
+ }
+}
+
+impl CoreArrayProvider for Array<SSAVariable> {
+ type Raw = BNVariable;
+ type Context = Ref<MediumLevelILFunction>;
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for Array<SSAVariable> {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ BNFreeVariableList(raw)
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ let mut count = 0;
+ let versions =
+ unsafe { BNGetMediumLevelILVariableSSAVersions(context.handle, raw, &mut count) };
+ Array::new(versions, count, Variable::from_raw(*raw))
+ }
+}
+
///////////////
// NamedVariable