summaryrefslogtreecommitdiff
path: root/rust/src/mlil/function.rs
diff options
context:
space:
mode:
authorRubens Brandao <git@rubens.io>2024-05-21 13:25:03 -0300
committerKyle Martin <krm504@nyu.edu>2024-05-28 19:26:10 -0400
commit9ca13512527ca62effce85bfcd9c41b8ed9cb86c (patch)
tree9c2d2a68bf8ab2d24b670977c34a93362a2415b4 /rust/src/mlil/function.rs
parent2c69eb22efddebde1027ba6cc62b446b052a35b6 (diff)
Implement python MLIL related functions
add `MediumLevelILInstruction::tokens` add `MediumLevelILInstruction::value` add `MediumLevelILInstruction::possible_values` add `MediumLevelILInstruction::branch_dependence` add `MediumLevelILInstruction::ssa_memory_version` add `MediumLevelILInstruction::expr_type` add `MediumLevelILInstruction::possible_values_with_options` add `MediumLevelILInstruction::possible_ssa_variable_values` add `MediumLevelILInstruction::ssa_variable_version` add `MediumLevelILInstruction::variable_for_register` add `MediumLevelILInstruction::variable_for_flag` add `MediumLevelILInstruction::variable_for_stack_location` add `MediumLevelILInstruction::register_value` add `MediumLevelILInstruction::register_value_after` add `MediumLevelILInstruction::possible_register_values` add `MediumLevelILInstruction::possible_register_values_after` add `MediumLevelILInstruction::flag_value` add `MediumLevelILInstruction::flag_value_after` add `MediumLevelILInstruction::possible_flag_values` add `MediumLevelILInstruction::possible_flag_values_after` add `MediumLevelILInstruction::stack_contents` add `MediumLevelILInstruction::stack_contents_after` add `MediumLevelILInstruction::possible_stack_contents` add `MediumLevelILInstruction::possible_stack_contents_after` add `MediumLevelILInstruction::branch_dependence_at` add `MediumLevelILInstruction::split_var_for_definition` move functions add `MediumLevelILFunction::current_address` add `MediumLevelILFunction::set_current_address` add `MediumLevelILFunction::basic_block_containing` add `MediumLevelILFunction::finalize` add `MediumLevelILFunction::generate_ssa_form` add `MediumLevelILFunction::ssa_variable_definition` add `MediumLevelILFunction::ssa_memory_definition` add `MediumLevelILFunction::ssa_variable_uses` add `MediumLevelILFunction::ssa_memory_uses` add `MediumLevelILFunction::is_ssa_variable_live` add `MediumLevelILFunction::variable_definitions` add `MediumLevelILFunction::variable_uses` add `MediumLevelILFunction::live_instruction_for_variable` add `MediumLevelILFunction::ssa_variable_value` add `MediumLevelILFunction::create_graph` add `MediumLevelILFunction::variables` add `MediumLevelILFunction::aliased_variables` add `MediumLevelILFunction::ssa_variables` add `MediumLevelILInstruction::set_expr_type` fix `MediumLevelILInstruction::generate_ssa_form` redundant type
Diffstat (limited to 'rust/src/mlil/function.rs')
-rw-r--r--rust/src/mlil/function.rs207
1 files changed, 206 insertions, 1 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 {