diff options
| author | Mason Reed <mason@vector35.com> | 2025-05-11 21:00:24 -0400 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2025-05-12 17:45:24 -0400 |
| commit | e2fac46543527d27eab2fc77cf19a4f715438857 (patch) | |
| tree | 00a7bf0d381781c049658c104f295830fda448cd /rust/src | |
| parent | 5dce2937456a59b951ebba720b1077d1e2e7e836 (diff) | |
[Rust] Simplify operand list retrieval for MLIL and HLIL
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/high_level_il/instruction.rs | 127 | ||||
| -rw-r--r-- | rust/src/lib.rs | 1 | ||||
| -rw-r--r-- | rust/src/medium_level_il/instruction.rs | 269 | ||||
| -rw-r--r-- | rust/src/operand_iter.rs | 237 |
4 files changed, 273 insertions, 361 deletions
diff --git a/rust/src/high_level_il/instruction.rs b/rust/src/high_level_il/instruction.rs index 00900de7..67225eea 100644 --- a/rust/src/high_level_il/instruction.rs +++ b/rust/src/high_level_il/instruction.rs @@ -7,7 +7,6 @@ use super::{HighLevelILFunction, HighLevelILLiftedInstruction, HighLevelILLifted use crate::architecture::{CoreIntrinsic, IntrinsicId}; use crate::confidence::Conf; use crate::disassembly::DisassemblyTextLine; -use crate::operand_iter::OperandIter; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; use crate::types::Type; use crate::variable::{ConstantData, RegisterValue, SSAVariable, Variable}; @@ -552,6 +551,38 @@ impl HighLevelILInstruction { } } + fn get_operand_list(&self, operand_idx: usize) -> Vec<u64> { + let mut count = 0; + let raw_list_ptr = unsafe { + BNHighLevelILGetOperandList( + self.function.handle, + self.expr_index.0, + operand_idx, + &mut count, + ) + }; + assert!(!raw_list_ptr.is_null()); + let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() }; + unsafe { BNHighLevelILFreeOperandList(raw_list_ptr) }; + list + } + + fn get_ssa_var_list(&self, operand_idx: usize) -> Vec<SSAVariable> { + self.get_operand_list(operand_idx) + .chunks(2) + .map(|chunk| (Variable::from_identifier(chunk[0]), chunk[1] as usize)) + .map(|(var, version)| SSAVariable::new(var, version)) + .collect() + } + + fn get_expr_list(&self, operand_idx: usize) -> Vec<HighLevelILInstruction> { + self.get_operand_list(operand_idx) + .into_iter() + .map(|val| HighLevelInstructionIndex(val as usize)) + .filter_map(|idx| self.function.instruction_from_expr_index(idx)) + .collect() + } + pub fn lift(&self) -> HighLevelILLiftedInstruction { use HighLevelILInstructionKind::*; use HighLevelILLiftedInstructionKind as Lifted; @@ -630,7 +661,11 @@ impl HighLevelILInstruction { src: self.lift_operand(op.src), }), AssignUnpack(op) => Lifted::AssignUnpack(LiftedAssignUnpack { - dest: self.lift_instruction_list(op.first_dest, op.num_dests), + dest: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), src: self.lift_operand(op.src), }), AssignMemSsa(op) => Lifted::AssignMemSsa(LiftedAssignMemSsa { @@ -640,26 +675,42 @@ impl HighLevelILInstruction { src_memory: op.src_memory, }), AssignUnpackMemSsa(op) => Lifted::AssignUnpackMemSsa(LiftedAssignUnpackMemSsa { - dest: self.lift_instruction_list(op.first_dest, op.num_dests), + dest: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src: self.lift_operand(op.src), src_memory: op.src_memory, }), - Block(op) => Lifted::Block(LiftedBlock { - body: self.lift_instruction_list(op.first_param, op.num_params), + Block(_op) => Lifted::Block(LiftedBlock { + body: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), }), Call(op) => Lifted::Call(self.lift_call(op)), Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), CallSsa(op) => Lifted::CallSsa(LiftedCallSsa { dest: self.lift_operand(op.dest), - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(1) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src_memory: op.src_memory, }), Case(op) => Lifted::Case(LiftedCase { - values: self.lift_instruction_list(op.first_value, op.num_values), + values: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), body: self.lift_operand(op.body), }), Const(op) => Lifted::Const(op), @@ -740,7 +791,11 @@ impl HighLevelILInstruction { IntrinsicId(op.intrinsic), ) .expect("Invalid intrinsic"), - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(1) + .iter() + .map(|expr| expr.lift()) + .collect(), }), IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { intrinsic: CoreIntrinsic::new( @@ -748,7 +803,11 @@ impl HighLevelILInstruction { IntrinsicId(op.intrinsic), ) .expect("Invalid intrinsic"), - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(1) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src_memory: op.src_memory, }), @@ -757,10 +816,14 @@ impl HighLevelILInstruction { }), MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { dest: op.dest, - src: OperandIter::new(&*self.function, op.first_src, op.num_srcs).collect(), + src: self.get_operand_list(1), }), - Ret(op) => Lifted::Ret(LiftedRet { - src: self.lift_instruction_list(op.first_src, op.num_srcs), + Ret(_op) => Lifted::Ret(LiftedRet { + src: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), }), Split(op) => Lifted::Split(LiftedSplit { high: self.lift_operand(op.high), @@ -771,13 +834,25 @@ impl HighLevelILInstruction { Switch(op) => Lifted::Switch(LiftedSwitch { condition: self.lift_operand(op.condition), default: self.lift_operand(op.default), - cases: self.lift_instruction_list(op.first_case, op.num_cases), + cases: self + .get_expr_list(2) + .iter() + .map(|expr| expr.lift()) + .collect(), }), - Syscall(op) => Lifted::Syscall(LiftedSyscall { - params: self.lift_instruction_list(op.first_param, op.num_params), + Syscall(_op) => Lifted::Syscall(LiftedSyscall { + params: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), }), SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa { - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src_memory: op.src_memory, }), @@ -794,9 +869,7 @@ impl HighLevelILInstruction { }), VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { dest: op.dest, - src: OperandIter::new(&*self.function, op.first_src, op.num_srcs) - .ssa_vars() - .collect(), + src: self.get_ssa_var_list(2), }), VarSsa(op) => Lifted::VarSsa(op), @@ -907,8 +980,9 @@ impl HighLevelILInstruction { fn lift_call(&self, op: Call) -> LiftedCall { LiftedCall { dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(1) + .iter() .map(|expr| expr.lift()) .collect(), } @@ -936,17 +1010,6 @@ impl HighLevelILInstruction { member_index: op.member_index, } } - - fn lift_instruction_list( - &self, - first_instruction: usize, - num_instructions: usize, - ) -> Vec<HighLevelILLiftedInstruction> { - OperandIter::new(&*self.function, first_instruction, num_instructions) - .exprs() - .map(|expr| expr.lift()) - .collect() - } } impl CoreArrayProvider for HighLevelILInstruction { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 80baae43..05c01077 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -26,7 +26,6 @@ #[macro_use] mod ffi; -mod operand_iter; pub mod architecture; pub mod background_task; diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs index b043788d..065e28f1 100644 --- a/rust/src/medium_level_il/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -621,6 +621,54 @@ impl MediumLevelILInstruction { } } + fn get_operand_list(&self, operand_idx: usize) -> Vec<u64> { + let mut count = 0; + let raw_list_ptr = unsafe { + BNMediumLevelILGetOperandList( + self.function.handle, + self.expr_index.0, + operand_idx, + &mut count, + ) + }; + assert!(!raw_list_ptr.is_null()); + let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() }; + unsafe { BNMediumLevelILFreeOperandList(raw_list_ptr) }; + list + } + + fn get_var_list(&self, operand_idx: usize) -> Vec<Variable> { + self.get_operand_list(operand_idx) + .into_iter() + .map(Variable::from_identifier) + .collect() + } + + fn get_ssa_var_list(&self, operand_idx: usize) -> Vec<SSAVariable> { + self.get_operand_list(operand_idx) + .chunks(2) + .map(|chunk| (Variable::from_identifier(chunk[0]), chunk[1] as usize)) + .map(|(var, version)| SSAVariable::new(var, version)) + .collect() + } + + fn get_expr_list(&self, operand_idx: usize) -> Vec<MediumLevelILInstruction> { + self.get_operand_list(operand_idx) + .into_iter() + .map(|val| MediumLevelInstructionIndex(val as usize)) + .filter_map(|idx| self.function.instruction_from_expr_index(idx)) + .collect() + } + + fn get_target_map(&self, operand_idx: usize) -> BTreeMap<u64, MediumLevelInstructionIndex> { + self.get_operand_list(operand_idx) + .chunks(2) + // TODO: This filter is kinda redundant. + .filter_map(|chunk| chunk.get(0..2)) + .map(|chunk| (chunk[0], MediumLevelInstructionIndex(chunk[1] as usize))) + .collect() + } + pub fn lift(&self) -> MediumLevelILLiftedInstruction { use MediumLevelILInstructionKind::*; use MediumLevelILLiftedInstructionKind as Lifted; @@ -690,12 +738,7 @@ impl MediumLevelILInstruction { }), JumpTo(op) => Lifted::JumpTo(LiftedJumpTo { dest: self.lift_operand(op.dest), - targets: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .pairs() - .map(|(addr, instr_idx)| { - (addr, MediumLevelInstructionIndex(instr_idx as usize)) - }) - .collect(), + targets: self.get_target_map(1), }), Goto(op) => Lifted::Goto(op), FreeVarSlot(op) => Lifted::FreeVarSlot(op), @@ -732,14 +775,12 @@ impl MediumLevelILInstruction { }), VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { dest: op.dest, - src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .ssa_vars() - .collect(), + src: self.get_ssa_var_list(2), }), MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { dest_memory: op.dest_memory, - src_memory: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .collect(), + // TODO: Make a stronger type for this. + src_memory: self.get_operand_list(0), }), VarSplit(op) => Lifted::VarSplit(op), SetVarSplit(op) => Lifted::SetVarSplit(LiftedSetVarSplit { @@ -809,42 +850,59 @@ impl MediumLevelILInstruction { Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .vars() - .collect(), + output: self.get_var_list(0), intrinsic: CoreIntrinsic::new( self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Valid intrinsic"), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(3) + .iter() .map(|expr| expr.lift()) .collect(), }), - Syscall(op) => Lifted::Syscall(LiftedSyscallCall { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .vars() - .collect(), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + Syscall(_op) => Lifted::Syscall(LiftedSyscallCall { + output: self.get_var_list(0), + params: self + .get_expr_list(2) + .iter() .map(|expr| expr.lift()) .collect(), }), IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .ssa_vars() + output: self.get_ssa_var_list(0), + intrinsic: CoreIntrinsic::new( + self.function.function().arch(), + IntrinsicId(op.intrinsic), + ) + .expect("Valid intrinsic"), + params: self + .get_expr_list(3) + .iter() + .map(|expr| expr.lift()) .collect(), + }), + MemoryIntrinsicSsa(op) => Lifted::MemoryIntrinsicSsa(LiftedMemoryIntrinsicSsa { + output: self.lift_operand(op.output), intrinsic: CoreIntrinsic::new( self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Valid intrinsic"), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(3) + .iter() .map(|expr| expr.lift()) .collect(), + src_memory: op.src_memory, }), + MemoryIntrinsicOutputSsa(op) => { + Lifted::MemoryIntrinsicOutputSsa(LiftedMemoryIntrinsicOutputSsa { + dest_memory: op.dest_memory, + output: self.get_ssa_var_list(1), + }) + } CallSsa(op) => Lifted::CallSsa(self.lift_call_ssa(op)), TailcallSsa(op) => Lifted::TailcallSsa(self.lift_call_ssa(op)), @@ -853,28 +911,46 @@ impl MediumLevelILInstruction { TailcallUntypedSsa(op) => Lifted::TailcallUntypedSsa(self.lift_call_untyped_ssa(op)), SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), + params: self + .get_expr_list(1) + .iter() .map(|expr| expr.lift()) .collect(), src_memory: op.src_memory, }), SyscallUntypedSsa(op) => Lifted::SyscallUntypedSsa(LiftedSyscallUntypedSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), - params: get_call_params_ssa(&self.function, op.params) - .map(|param| param.lift()) - .collect(), + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), + params: get_call_params_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|param| param.lift()) + .collect(), stack: self.lift_operand(op.stack), }), CallUntyped(op) => Lifted::CallUntyped(self.lift_call_untyped(op)), TailcallUntyped(op) => Lifted::TailcallUntyped(self.lift_call_untyped(op)), SyscallUntyped(op) => Lifted::SyscallUntyped(LiftedSyscallUntyped { - output: get_call_output(&self.function, op.output).collect(), - params: get_call_params(&self.function, op.params) - .map(|param| param.lift()) - .collect(), + output: get_call_output(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), + params: get_call_params(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|param| param.lift()) + .collect(), stack: self.lift_operand(op.stack), }), @@ -910,21 +986,24 @@ impl MediumLevelILInstruction { src: self.lift_operand(op.src), src_memory: op.src_memory, }), - Ret(op) => Lifted::Ret(LiftedRet { - src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .exprs() + Ret(_op) => Lifted::Ret(LiftedRet { + src: self + .get_expr_list(0) + .iter() .map(|expr| expr.lift()) .collect(), }), - SeparateParamList(op) => Lifted::SeparateParamList(LiftedSeparateParamList { - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + SeparateParamList(_op) => Lifted::SeparateParamList(LiftedSeparateParamList { + params: self + .get_expr_list(0) + .iter() .map(|expr| expr.lift()) .collect(), }), - SharedParamSlot(op) => Lifted::SharedParamSlot(LiftedSharedParamSlot { - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + SharedParamSlot(_op) => Lifted::SharedParamSlot(LiftedSharedParamSlot { + params: self + .get_expr_list(0) + .iter() .map(|expr| expr.lift()) .collect(), }), @@ -1413,12 +1492,11 @@ impl MediumLevelILInstruction { fn lift_call(&self, op: Call) -> LiftedCall { LiftedCall { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .vars() - .collect(), + output: self.get_var_list(0), dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(3) + .iter() .map(|expr| expr.lift()) .collect(), } @@ -1426,21 +1504,32 @@ impl MediumLevelILInstruction { fn lift_call_untyped(&self, op: CallUntyped) -> LiftedCallUntyped { LiftedCallUntyped { - output: get_call_output(&self.function, op.output).collect(), + output: get_call_output(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), dest: self.lift_operand(op.dest), - params: get_call_params(&self.function, op.params) - .map(|expr| expr.lift()) - .collect(), + params: get_call_params(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|expr| expr.lift()) + .collect(), stack: self.lift_operand(op.stack), } } fn lift_call_ssa(&self, op: CallSsa) -> LiftedCallSsa { LiftedCallSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(2) + .iter() .map(|expr| expr.lift()) .collect(), src_memory: op.src_memory, @@ -1449,11 +1538,18 @@ impl MediumLevelILInstruction { fn lift_call_untyped_ssa(&self, op: CallUntypedSsa) -> LiftedCallUntypedSsa { LiftedCallUntypedSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), dest: self.lift_operand(op.dest), - params: get_call_params_ssa(&self.function, op.params) - .map(|param| param.lift()) - .collect(), + params: get_call_params_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|param| param.lift()) + .collect(), stack: self.lift_operand(op.stack), } } @@ -1636,10 +1732,6 @@ fn get_float(value: u64, size: usize) -> f64 { } } -fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction { - unsafe { BNGetMediumLevelILByIndex(function.handle, idx) } -} - fn get_var(id: u64) -> Variable { Variable::from_identifier(id) } @@ -1648,37 +1740,32 @@ fn get_var_ssa(id: u64, version: usize) -> SSAVariable { SSAVariable::new(get_var(id), version) } -fn get_call_output(function: &MediumLevelILFunction, idx: usize) -> impl Iterator<Item = Variable> { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT); - OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).vars() +fn get_call_output(instr: &MediumLevelILInstruction) -> Vec<Variable> { + match instr.kind { + MediumLevelILInstructionKind::CallOutput(_op) => instr.get_var_list(0), + _ => vec![], + } } -fn get_call_params( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator<Item = MediumLevelILInstruction> { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM); - OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).exprs() +fn get_call_params(instr: &MediumLevelILInstruction) -> Vec<MediumLevelILInstruction> { + match instr.kind { + MediumLevelILInstructionKind::CallParam(_op) => instr.get_expr_list(0), + _ => vec![], + } } -fn get_call_output_ssa( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator<Item = SSAVariable> { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA); - OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).ssa_vars() +fn get_call_output_ssa(instr: &MediumLevelILInstruction) -> Vec<SSAVariable> { + match instr.kind { + MediumLevelILInstructionKind::CallOutputSsa(_op) => instr.get_ssa_var_list(1), + _ => vec![], + } } -fn get_call_params_ssa( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator<Item = MediumLevelILInstruction> { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA); - OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).exprs() +fn get_call_params_ssa(instr: &MediumLevelILInstruction) -> Vec<MediumLevelILInstruction> { + match instr.kind { + MediumLevelILInstructionKind::CallParamSsa(_op) => instr.get_expr_list(1), + _ => vec![], + } } /// Conditional branching instruction and an expected conditional result diff --git a/rust/src/operand_iter.rs b/rust/src/operand_iter.rs deleted file mode 100644 index fcbf5fad..00000000 --- a/rust/src/operand_iter.rs +++ /dev/null @@ -1,237 +0,0 @@ -use binaryninjacore_sys::BNGetHighLevelILByIndex; -use binaryninjacore_sys::BNGetMediumLevelILByIndex; -use binaryninjacore_sys::BNHighLevelILOperation; -use binaryninjacore_sys::BNMediumLevelILOperation; - -use crate::high_level_il::{ - HighLevelILFunction, HighLevelILInstruction, HighLevelInstructionIndex, -}; -use crate::medium_level_il::{ - MediumLevelILFunction, MediumLevelILInstruction, MediumLevelInstructionIndex, -}; -use crate::rc::{Ref, RefCountable}; -use crate::variable::{SSAVariable, Variable}; - -// TODO: This code needs to go away IMO, we have the facilities to do this for each IL already! - -pub trait ILFunction { - type Instruction; - type InstructionIndex: From<u64>; - - // TODO Actually this is il expression from index! - fn il_instruction_from_index(&self, instr_index: Self::InstructionIndex) -> Self::Instruction; - fn operands_from_index(&self, instr_index: Self::InstructionIndex) -> [u64; 5]; -} - -impl ILFunction for MediumLevelILFunction { - type Instruction = MediumLevelILInstruction; - type InstructionIndex = MediumLevelInstructionIndex; - - fn il_instruction_from_index(&self, instr_index: Self::InstructionIndex) -> Self::Instruction { - self.instruction_from_expr_index(instr_index).unwrap() - } - - fn operands_from_index(&self, instr_index: Self::InstructionIndex) -> [u64; 5] { - // TODO: WTF?!?!?! - let node = unsafe { BNGetMediumLevelILByIndex(self.handle, instr_index.0) }; - assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF); - node.operands - } -} - -impl ILFunction for HighLevelILFunction { - type Instruction = HighLevelILInstruction; - type InstructionIndex = HighLevelInstructionIndex; - - fn il_instruction_from_index(&self, instr_index: Self::InstructionIndex) -> Self::Instruction { - self.instruction_from_expr_index(instr_index).unwrap() - } - - fn operands_from_index(&self, instr_index: Self::InstructionIndex) -> [u64; 5] { - let node = unsafe { BNGetHighLevelILByIndex(self.handle, instr_index.0, self.full_ast) }; - assert_eq!(node.operation, BNHighLevelILOperation::HLIL_UNDEF); - node.operands - } -} - -pub struct OperandIter<F: ILFunction + RefCountable> { - function: Ref<F>, - remaining: usize, - next_iter_idx: Option<usize>, - current_iter: OperandIterInner, -} - -impl<F: ILFunction + RefCountable> OperandIter<F> { - 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<F> { - assert_eq!(self.len() % 2, 0); - OperandPairIter(self) - } - - pub fn exprs(self) -> OperandExprIter<F> { - OperandExprIter(self) - } - - pub fn vars(self) -> OperandVarIter<F> { - OperandVarIter(self) - } - - pub fn ssa_vars(self) -> OperandSSAVarIter<F> { - OperandSSAVarIter(self.pairs()) - } -} - -impl<F: ILFunction + RefCountable> Iterator for OperandIter<F> { - type Item = u64; - - fn next(&mut self) -> Option<Self::Item> { - 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 iter_idx = F::InstructionIndex::from(iter_idx as u64); - let operands = self.function.operands_from_index(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<F: ILFunction + RefCountable> ExactSizeIterator for OperandIter<F> { - 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<Self::Item> { - 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<F: ILFunction + RefCountable>(OperandIter<F>); - -impl<F: ILFunction + RefCountable> Iterator for OperandPairIter<F> { - type Item = (u64, u64); - - fn next(&mut self) -> Option<Self::Item> { - let first = self.0.next()?; - let second = self.0.next()?; - Some((first, second)) - } -} -impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandPairIter<F> { - fn len(&self) -> usize { - self.0.len() / 2 - } -} - -pub struct OperandExprIter<F: ILFunction + RefCountable>(OperandIter<F>); - -impl<F: ILFunction + RefCountable> Iterator for OperandExprIter<F> { - type Item = F::Instruction; - - fn next(&mut self) -> Option<Self::Item> { - self.0 - .next() - .map(F::InstructionIndex::from) - .map(|idx| self.0.function.il_instruction_from_index(idx)) - } -} - -impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandExprIter<F> { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandVarIter<F: ILFunction + RefCountable>(OperandIter<F>); - -impl<F: ILFunction + RefCountable> Iterator for OperandVarIter<F> { - type Item = Variable; - - fn next(&mut self) -> Option<Self::Item> { - self.0.next().map(Variable::from_identifier) - } -} -impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandVarIter<F> { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandSSAVarIter<F: ILFunction + RefCountable>(OperandPairIter<F>); - -impl<F: ILFunction + RefCountable> Iterator for OperandSSAVarIter<F> { - type Item = SSAVariable; - - fn next(&mut self) -> Option<Self::Item> { - self.0.next().map(|(id, version)| { - let var = Variable::from_identifier(id); - SSAVariable::new(var, version as _) - }) - } -} - -impl<F: ILFunction + RefCountable> ExactSizeIterator for OperandSSAVarIter<F> { - fn len(&self) -> usize { - self.0.len() - } -} |
