Skip to content

Commit f173ccf

Browse files
committed
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
1 parent 331d226 commit f173ccf

File tree

3 files changed

+659
-10
lines changed

3 files changed

+659
-10
lines changed

rust/src/mlil/function.rs

+206-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ use binaryninjacore_sys::*;
55

66
use crate::architecture::CoreArchitecture;
77
use crate::basicblock::BasicBlock;
8+
use crate::disassembly::DisassemblySettings;
9+
use crate::flowgraph::FlowGraph;
810
use crate::function::{Function, Location};
911
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable};
1012
use crate::string::BnStrCompatible;
11-
use crate::types::{Conf, PossibleValueSet, Type, UserVariableValues, Variable};
13+
use crate::types::{
14+
Conf, PossibleValueSet, RegisterValue, SSAVariable, Type, UserVariableValues, Variable,
15+
};
1216

1317
use super::{MediumLevelILBlock, MediumLevelILInstruction, MediumLevelILLiftedInstruction};
1418

@@ -371,6 +375,207 @@ impl MediumLevelILFunction {
371375
assert!(!refs.is_null());
372376
unsafe { Array::new(refs, count, self.to_owned()) }
373377
}
378+
379+
/// Current IL Address
380+
pub fn current_address(&self) -> u64 {
381+
unsafe { BNMediumLevelILGetCurrentAddress(self.handle) }
382+
}
383+
384+
/// Set the current IL Address
385+
pub fn set_current_address(&self, value: u64, arch: Option<CoreArchitecture>) {
386+
let arch = arch
387+
.map(|x| x.0)
388+
.unwrap_or_else(|| self.get_function().arch().0);
389+
unsafe { BNMediumLevelILSetCurrentAddress(self.handle, arch, value) }
390+
}
391+
392+
/// Returns the BasicBlock at the given MLIL `instruction`.
393+
pub fn basic_block_containing(
394+
&self,
395+
instruction: &MediumLevelILInstruction,
396+
) -> Option<BasicBlock<MediumLevelILBlock>> {
397+
let index = instruction.index;
398+
let block = unsafe { BNGetMediumLevelILBasicBlockForInstruction(self.handle, index) };
399+
(!block.is_null()).then(|| unsafe {
400+
BasicBlock::from_raw(
401+
block,
402+
MediumLevelILBlock {
403+
function: self.to_owned(),
404+
},
405+
)
406+
})
407+
}
408+
/// ends the function and computes the list of basic blocks.
409+
pub fn finalize(&self) {
410+
unsafe { BNFinalizeMediumLevelILFunction(self.handle) }
411+
}
412+
413+
/// Generate SSA form given the current MLIL
414+
///
415+
/// * `analyze_conditionals` - whether or not to analyze conditionals
416+
/// * `handle_aliases` - whether or not to handle aliases
417+
/// * `known_not_aliases` - optional list of variables known to be not aliased
418+
/// * `known_aliases` - optional list of variables known to be aliased
419+
pub fn generate_ssa_form(
420+
&self,
421+
analyze_conditionals: bool,
422+
handle_aliases: bool,
423+
known_not_aliases: impl IntoIterator<Item = Variable>,
424+
known_aliases: impl IntoIterator<Item = Variable>,
425+
) {
426+
let mut known_not_aliases: Box<[_]> =
427+
known_not_aliases.into_iter().map(|x| x.raw()).collect();
428+
let mut known_aliases: Box<[_]> = known_aliases.into_iter().map(|x| x.raw()).collect();
429+
let (known_not_aliases_ptr, known_not_aliases_len) = if known_not_aliases.is_empty() {
430+
(core::ptr::null_mut(), 0)
431+
} else {
432+
(known_not_aliases.as_mut_ptr(), known_not_aliases.len())
433+
};
434+
let (known_aliases_ptr, known_aliases_len) = if known_not_aliases.is_empty() {
435+
(core::ptr::null_mut(), 0)
436+
} else {
437+
(known_aliases.as_mut_ptr(), known_aliases.len())
438+
};
439+
unsafe {
440+
BNGenerateMediumLevelILSSAForm(
441+
self.handle,
442+
analyze_conditionals,
443+
handle_aliases,
444+
known_not_aliases_ptr,
445+
known_not_aliases_len,
446+
known_aliases_ptr,
447+
known_aliases_len,
448+
)
449+
}
450+
}
451+
452+
/// Gets the instruction that contains the given SSA variable's definition.
453+
///
454+
/// Since SSA variables can only be defined once, this will return the single instruction where that occurs.
455+
/// For SSA variable version 0s, which don't have definitions, this will return None instead.
456+
pub fn ssa_variable_definition(&self, var: SSAVariable) -> Option<MediumLevelILInstruction> {
457+
let result = unsafe {
458+
BNGetMediumLevelILSSAVarDefinition(self.handle, &var.variable.raw(), var.version)
459+
};
460+
(result < self.instruction_count())
461+
.then(|| MediumLevelILInstruction::new(self.to_owned(), result))
462+
}
463+
464+
pub fn ssa_memory_definition(&self, version: usize) -> Option<MediumLevelILInstruction> {
465+
let result = unsafe { BNGetMediumLevelILSSAMemoryDefinition(self.handle, version) };
466+
(result < self.instruction_count())
467+
.then(|| MediumLevelILInstruction::new(self.to_owned(), result))
468+
}
469+
470+
///Gets all the instructions that use the given SSA variable.
471+
pub fn ssa_variable_uses(&self, ssa_var: SSAVariable) -> Array<MediumLevelILInstruction> {
472+
let mut count = 0;
473+
let uses = unsafe {
474+
BNGetMediumLevelILSSAVarUses(
475+
self.handle,
476+
&ssa_var.variable.raw(),
477+
ssa_var.version,
478+
&mut count,
479+
)
480+
};
481+
assert!(!uses.is_null());
482+
unsafe { Array::new(uses, count, self.to_owned()) }
483+
}
484+
485+
pub fn ssa_memory_uses(&self, version: usize) -> Array<MediumLevelILInstruction> {
486+
let mut count = 0;
487+
let uses = unsafe { BNGetMediumLevelILSSAMemoryUses(self.handle, version, &mut count) };
488+
assert!(!uses.is_null());
489+
unsafe { Array::new(uses, count, self.to_owned()) }
490+
}
491+
492+
/// determines if `ssa_var` is live at any point in the function
493+
pub fn is_ssa_variable_live(&self, ssa_var: SSAVariable) -> bool {
494+
unsafe {
495+
BNIsMediumLevelILSSAVarLive(self.handle, &ssa_var.variable.raw(), ssa_var.version)
496+
}
497+
}
498+
499+
pub fn variable_definitions(&self, variable: Variable) -> Array<MediumLevelILInstruction> {
500+
let mut count = 0;
501+
let defs = unsafe {
502+
BNGetMediumLevelILVariableDefinitions(self.handle, &variable.raw(), &mut count)
503+
};
504+
unsafe { Array::new(defs, count, self.to_owned()) }
505+
}
506+
507+
pub fn variable_uses(&self, variable: Variable) -> Array<MediumLevelILInstruction> {
508+
let mut count = 0;
509+
let uses =
510+
unsafe { BNGetMediumLevelILVariableUses(self.handle, &variable.raw(), &mut count) };
511+
unsafe { Array::new(uses, count, self.to_owned()) }
512+
}
513+
514+
/// Computes the list of instructions for which `var` is live.
515+
/// If `include_last_use` is false, the last use of the variable will not be included in the
516+
/// list (this allows for easier computation of overlaps in liveness between two variables).
517+
/// If the variable is never used, this function will return an empty list.
518+
///
519+
/// `var` - the variable to query
520+
/// `include_last_use` - whether to include the last use of the variable in the list of instructions
521+
pub fn live_instruction_for_variable(
522+
&self,
523+
variable: Variable,
524+
include_last_user: bool,
525+
) -> Array<MediumLevelILInstruction> {
526+
let mut count = 0;
527+
let uses = unsafe {
528+
BNGetMediumLevelILLiveInstructionsForVariable(
529+
self.handle,
530+
&variable.raw(),
531+
include_last_user,
532+
&mut count,
533+
)
534+
};
535+
unsafe { Array::new(uses, count, self.to_owned()) }
536+
}
537+
538+
pub fn ssa_variable_value(&self, ssa_var: SSAVariable) -> RegisterValue {
539+
unsafe {
540+
BNGetMediumLevelILSSAVarValue(self.handle, &ssa_var.variable.raw(), ssa_var.version)
541+
}
542+
.into()
543+
}
544+
545+
pub fn create_graph(&self, settings: Option<DisassemblySettings>) -> FlowGraph {
546+
let settings = settings.map(|x| x.handle).unwrap_or(core::ptr::null_mut());
547+
let graph = unsafe { BNCreateMediumLevelILFunctionGraph(self.handle, settings) };
548+
unsafe { FlowGraph::from_raw(graph) }
549+
}
550+
551+
/// This gets just the MLIL variables - you may be interested in the union
552+
/// of [MediumLevelIlFunction::aliased_variables] and
553+
/// [crate::function::Function::parameter_variables] for all the
554+
/// variables used in the function
555+
pub fn variables(&self) -> Array<Variable> {
556+
let mut count = 0;
557+
let uses = unsafe { BNGetMediumLevelILVariables(self.handle, &mut count) };
558+
unsafe { Array::new(uses, count, ()) }
559+
}
560+
561+
/// This returns a list of Variables that are taken reference to and used
562+
/// elsewhere. You may also wish to consider [MediumLevelIlFunction::variables]
563+
/// and [crate::function::Function::parameter_variables]
564+
pub fn aliased_variables(&self) -> Array<Variable> {
565+
let mut count = 0;
566+
let uses = unsafe { BNGetMediumLevelILAliasedVariables(self.handle, &mut count) };
567+
unsafe { Array::new(uses, count, ()) }
568+
}
569+
570+
/// This gets just the MLIL SSA variables - you may be interested in the
571+
/// union of [MediumLevelIlFunction::aliased_variables] and
572+
/// [crate::function::Function::parameter_variables] for all the
573+
/// variables used in the function.
574+
pub fn ssa_variables(&self) -> Array<Array<SSAVariable>> {
575+
let mut count = 0;
576+
let vars = unsafe { BNGetMediumLevelILVariables(self.handle, &mut count) };
577+
unsafe { Array::new(vars, count, self.to_owned()) }
578+
}
374579
}
375580

376581
impl ToOwned for MediumLevelILFunction {

0 commit comments

Comments
 (0)