use binaryninjacore_sys::BNGetHighLevelILByIndex; use binaryninjacore_sys::BNGetMediumLevelILByIndex; use binaryninjacore_sys::BNHighLevelILOperation; use binaryninjacore_sys::BNMediumLevelILOperation; use crate::hlil::{HighLevelILFunction, HighLevelILInstruction}; use crate::mlil::{MediumLevelILFunction, MediumLevelILInstruction}; use crate::rc::{Ref, RefCountable}; use crate::types::{SSAVariable, Variable}; pub trait ILFunction { type Instruction; fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction; fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5]; } impl ILFunction for MediumLevelILFunction { type Instruction = MediumLevelILInstruction; fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction { self.instruction_from_idx(expr_idx) } fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5] { let node = unsafe { BNGetMediumLevelILByIndex(self.handle, expr_idx) }; assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF); node.operands } } impl ILFunction for HighLevelILFunction { type Instruction = HighLevelILInstruction; fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction { self.instruction_from_idx(expr_idx) } fn operands_from_idx(&self, expr_idx: usize) -> [u64; 5] { let node = unsafe { BNGetHighLevelILByIndex(self.handle, expr_idx, self.full_ast) }; assert_eq!(node.operation, BNHighLevelILOperation::HLIL_UNDEF); node.operands } } pub struct OperandIter { function: Ref, remaining: usize, next_iter_idx: Option, current_iter: OperandIterInner, } impl OperandIter { pub(crate) fn new(function: &F, idx: usize, number: usize) -> Self { // Zero-length lists immediately finish iteration let next_iter_idx = if number > 0 { Some(idx) } else { None }; Self { function: function.to_owned(), remaining: number, next_iter_idx, current_iter: OperandIterInner::empty(), } } pub fn pairs(self) -> OperandPairIter { assert_eq!(self.len() % 2, 0); OperandPairIter(self) } pub fn exprs(self) -> OperandExprIter { OperandExprIter(self) } pub fn vars(self) -> OperandVarIter { OperandVarIter(self) } pub fn ssa_vars(self) -> OperandSSAVarIter { OperandSSAVarIter(self.pairs()) } } impl Iterator for OperandIter { type Item = u64; fn next(&mut self) -> Option { if let Some(item) = self.current_iter.next() { self.remaining -= 1; Some(item) } else { // Will short-circuit and return `None` once iter is exhausted let iter_idx = self.next_iter_idx?; let operands = self.function.operands_from_idx(iter_idx); let next = if self.remaining > 4 { self.next_iter_idx = Some(operands[4] as usize); &operands[..4] } else { self.next_iter_idx = None; &operands[..self.remaining] }; self.current_iter = OperandIterInner::from_slice(next); self.next() } } } impl ExactSizeIterator for OperandIter { fn len(&self) -> usize { self.remaining + self.current_iter.len() } } struct OperandIterInner { arr: [u64; 4], idx: usize, } impl OperandIterInner { fn from_slice(slice: &[u64]) -> Self { assert!(slice.len() <= 4); let idx = 4 - slice.len(); let mut arr = [0; 4]; arr[idx..].copy_from_slice(slice); Self { arr, idx } } fn empty() -> Self { Self { arr: [0; 4], idx: 4, } } } impl Iterator for OperandIterInner { type Item = u64; fn next(&mut self) -> Option { if self.idx < 4 { let val = self.arr[self.idx]; self.idx += 1; Some(val) } else { None } } } impl ExactSizeIterator for OperandIterInner { fn len(&self) -> usize { 4 - self.idx } } pub struct OperandPairIter(OperandIter); impl Iterator for OperandPairIter { type Item = (u64, u64); fn next(&mut self) -> Option { let first = self.0.next()?; let second = self.0.next()?; Some((first, second)) } } impl ExactSizeIterator for OperandPairIter { fn len(&self) -> usize { self.0.len() / 2 } } pub struct OperandExprIter(OperandIter); impl Iterator for OperandExprIter { type Item = F::Instruction; fn next(&mut self) -> Option { self.0 .next() .map(|idx| self.0.function.il_instruction_from_idx(idx as usize)) } } impl ExactSizeIterator for OperandExprIter { fn len(&self) -> usize { self.0.len() } } pub struct OperandVarIter(OperandIter); impl Iterator for OperandVarIter { type Item = Variable; fn next(&mut self) -> Option { self.0.next().map(get_var) } } impl ExactSizeIterator for OperandVarIter { fn len(&self) -> usize { self.0.len() } } pub struct OperandSSAVarIter(OperandPairIter); impl Iterator for OperandSSAVarIter { type Item = SSAVariable; fn next(&mut self) -> Option { self.0 .next() .map(|(id, version)| get_var_ssa(id, version as usize)) } } impl ExactSizeIterator for OperandSSAVarIter { fn len(&self) -> usize { self.0.len() } } pub fn get_var(id: u64) -> Variable { unsafe { Variable::from_identifier(id) } } pub fn get_var_ssa(id: u64, version: usize) -> SSAVariable { SSAVariable::new(get_var(id), version) }