diff --git a/rust/Cargo.lock b/rust/Cargo.lock index e45d2da2d..c8fdddbb8 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -105,6 +105,7 @@ dependencies = [ "libc", "log", "rayon", + "strum", ] [[package]] @@ -830,6 +831,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" + [[package]] name = "ruzstd" version = "0.5.0" @@ -916,6 +923,28 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.52", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b827b9bb5..9b6a3380a 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -13,6 +13,7 @@ log = "0.4" libc = "0.2" rayon = { version = "1.8", optional = true } binaryninjacore-sys = { path = "binaryninjacore-sys" } +strum = { version = "0.26.2", features = ["derive"] } [patch.crates-io] # Patched pdb crate to implement some extra structures diff --git a/rust/examples/mlil_visitor/src/main.rs b/rust/examples/mlil_visitor/src/main.rs index c38d59f48..2bad20dca 100644 --- a/rust/examples/mlil_visitor/src/main.rs +++ b/rust/examples/mlil_visitor/src/main.rs @@ -1,26 +1,26 @@ use std::env; use binaryninja::binaryview::BinaryViewExt; -use binaryninja::mlil::MediumLevelILLiftedOperand; -use binaryninja::mlil::{MediumLevelILFunction, MediumLevelILLiftedInstruction}; +use binaryninja::mlil; +use binaryninja::mlil::{MediumLevelILLiftedOperand, MediumLevelILFunction, MediumLevelILLiftedInstruction}; use binaryninja::types::Variable; fn print_indent(indent: usize) { print!("{:(operation: &MediumLevelILLiftedInstruction) { print!("{}", operation.name()); } -fn print_variable(func: &MediumLevelILFunction, var: &Variable) { +fn print_variable(func: &MediumLevelILFunction, var: &Variable) { print!("{}", func.get_function().get_variable_name(var)); } -fn print_il_expr(instr: &MediumLevelILLiftedInstruction, mut indent: usize) { +fn print_il_expr(instr: &MediumLevelILLiftedInstruction, mut indent: usize) { print_indent(indent); print_operation(instr); - println!(""); + println!(); indent += 1; diff --git a/rust/src/function.rs b/rust/src/function.rs index 74e05ea55..65ff0f01e 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -251,7 +251,7 @@ impl Function { } } - pub fn medium_level_il(&self) -> Result, ()> { + pub fn medium_level_il(&self) -> Result>, ()> { unsafe { let mlil = BNGetFunctionMediumLevelIL(self.handle); diff --git a/rust/src/functionrecognizer.rs b/rust/src/functionrecognizer.rs index c63edcab0..7f4f61be8 100644 --- a/rust/src/functionrecognizer.rs +++ b/rust/src/functionrecognizer.rs @@ -15,11 +15,11 @@ pub trait FunctionRecognizer { false } - fn recognize_medium_level_il( + fn recognize_medium_level_il( &self, _bv: &BinaryView, _func: &Function, - _mlil: &mlil::MediumLevelILFunction, + _mlil: &mlil::MediumLevelILFunction, ) -> bool { false } @@ -70,7 +70,7 @@ where let custom_handler = unsafe { &*(ctxt as *mut R) }; let bv = unsafe { BinaryView::from_raw(BNNewViewReference(bv)) }; let func = unsafe { Function::from_raw(BNNewFunctionReference(func)) }; - let mlil = unsafe { mlil::MediumLevelILFunction::ref_from_raw(mlil) }; + let mlil = unsafe { mlil::MediumLevelILFunction::::ref_from_raw(mlil) }; custom_handler.recognize_medium_level_il(bv.as_ref(), func.as_ref(), &mlil) } diff --git a/rust/src/mlil/block.rs b/rust/src/mlil/block.rs index 015c7ba4e..73971266a 100644 --- a/rust/src/mlil/block.rs +++ b/rust/src/mlil/block.rs @@ -5,15 +5,15 @@ use binaryninjacore_sys::BNGetMediumLevelILIndexForInstruction; use crate::basicblock::{BasicBlock, BlockContext}; use crate::rc::Ref; -use super::{MediumLevelILFunction, MediumLevelILInstruction}; +use super::{Form, MediumLevelILFunction, MediumLevelILInstruction}; -pub struct MediumLevelILBlockIter { - function: Ref, +pub struct MediumLevelILBlockIter { + function: Ref>, range: Range, } -impl Iterator for MediumLevelILBlockIter { - type Item = MediumLevelILInstruction; +impl Iterator for MediumLevelILBlockIter { + type Item = MediumLevelILInstruction; fn next(&mut self) -> Option { self.range @@ -25,28 +25,28 @@ impl Iterator for MediumLevelILBlockIter { } } -pub struct MediumLevelILBlock { - pub(crate) function: Ref, +pub struct MediumLevelILBlock { + pub(crate) function: Ref>, } -impl core::fmt::Debug for MediumLevelILBlock { +impl core::fmt::Debug for MediumLevelILBlock { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "mlil_bb {:?}", self.function) } } -impl BlockContext for MediumLevelILBlock { - type Iter = MediumLevelILBlockIter; - type Instruction = MediumLevelILInstruction; +impl BlockContext for MediumLevelILBlock { + type Iter = MediumLevelILBlockIter; + type Instruction = MediumLevelILInstruction; - fn start(&self, block: &BasicBlock) -> MediumLevelILInstruction { + fn start(&self, block: &BasicBlock) -> MediumLevelILInstruction { let expr_idx = unsafe { BNGetMediumLevelILIndexForInstruction(self.function.handle, block.raw_start() as usize) }; MediumLevelILInstruction::new(self.function.to_owned(), expr_idx) } - fn iter(&self, block: &BasicBlock) -> MediumLevelILBlockIter { + fn iter(&self, block: &BasicBlock) -> MediumLevelILBlockIter { MediumLevelILBlockIter { function: self.function.to_owned(), range: block.raw_start()..block.raw_end(), @@ -54,7 +54,7 @@ impl BlockContext for MediumLevelILBlock { } } -impl Clone for MediumLevelILBlock { +impl Clone for MediumLevelILBlock { fn clone(&self) -> Self { MediumLevelILBlock { function: self.function.to_owned(), diff --git a/rust/src/mlil/function.rs b/rust/src/mlil/function.rs index 0b662578c..80ae14196 100644 --- a/rust/src/mlil/function.rs +++ b/rust/src/mlil/function.rs @@ -15,36 +15,56 @@ use crate::function::Function; use crate::function::Location; use crate::rc::{Array, Ref, RefCountable}; -use super::{MediumLevelILBlock, MediumLevelILInstruction, MediumLevelILLiftedInstruction}; +use super::{ + Form, MediumLevelILBlock, MediumLevelILInstruction, MediumLevelILLiftedInstruction, NonSSA, SSA, +}; -pub struct MediumLevelILFunction { +pub struct MediumLevelILFunction { pub(crate) handle: *mut BNMediumLevelILFunction, + _form: std::marker::PhantomData, } -unsafe impl Send for MediumLevelILFunction {} -unsafe impl Sync for MediumLevelILFunction {} +unsafe impl Send for MediumLevelILFunction {} +unsafe impl Sync for MediumLevelILFunction {} -impl Eq for MediumLevelILFunction {} -impl PartialEq for MediumLevelILFunction { +impl Eq for MediumLevelILFunction {} +impl PartialEq for MediumLevelILFunction { fn eq(&self, rhs: &Self) -> bool { self.get_function().eq(&rhs.get_function()) } } -impl Hash for MediumLevelILFunction { +impl Hash for MediumLevelILFunction { fn hash(&self, state: &mut H) { self.get_function().hash(state) } } -impl MediumLevelILFunction { +impl MediumLevelILFunction { pub(crate) unsafe fn ref_from_raw(handle: *mut BNMediumLevelILFunction) -> Ref { debug_assert!(!handle.is_null()); - Self { handle }.to_owned() + Self { + handle, + _form: std::marker::PhantomData, + } + .to_owned() + } + + pub fn instruction_count(&self) -> usize { + unsafe { BNGetMediumLevelILInstructionCount(self.handle) } } - pub fn instruction_at>(&self, loc: L) -> Option { + pub fn get_function(&self) -> Ref { + unsafe { + let func = BNGetMediumLevelILOwnerFunction(self.handle); + Function::from_raw(func) + } + } +} + +impl MediumLevelILFunction { + pub fn instruction_at>(&self, loc: L) -> Option> { let loc: Location = loc.into(); let arch_handle = loc.arch.unwrap(); @@ -58,15 +78,21 @@ impl MediumLevelILFunction { } } - pub fn instruction_from_idx(&self, expr_idx: usize) -> MediumLevelILInstruction { + pub fn instruction_from_idx(&self, expr_idx: usize) -> MediumLevelILInstruction { MediumLevelILInstruction::new(self.to_owned(), expr_idx) } - pub fn lifted_instruction_from_idx(&self, expr_idx: usize) -> MediumLevelILLiftedInstruction { + pub fn lifted_instruction_from_idx( + &self, + expr_idx: usize, + ) -> MediumLevelILLiftedInstruction { self.instruction_from_idx(expr_idx).lift() } - pub fn instruction_from_instruction_idx(&self, instr_idx: usize) -> MediumLevelILInstruction { + pub fn instruction_from_instruction_idx( + &self, + instr_idx: usize, + ) -> MediumLevelILInstruction { MediumLevelILInstruction::new(self.to_owned(), unsafe { BNGetMediumLevelILIndexForInstruction(self.handle, instr_idx) }) @@ -75,28 +101,11 @@ impl MediumLevelILFunction { pub fn lifted_instruction_from_instruction_idx( &self, instr_idx: usize, - ) -> MediumLevelILLiftedInstruction { + ) -> MediumLevelILLiftedInstruction { self.instruction_from_instruction_idx(instr_idx).lift() } - pub fn instruction_count(&self) -> usize { - unsafe { BNGetMediumLevelILInstructionCount(self.handle) } - } - - pub fn ssa_form(&self) -> MediumLevelILFunction { - let ssa = unsafe { BNGetMediumLevelILSSAForm(self.handle) }; - assert!(!ssa.is_null()); - MediumLevelILFunction { handle: ssa } - } - - pub fn get_function(&self) -> Ref { - unsafe { - let func = BNGetMediumLevelILOwnerFunction(self.handle); - Function::from_raw(func) - } - } - - pub fn basic_blocks(&self) -> Array> { + pub fn basic_blocks(&self) -> Array>> { let mut count = 0; let blocks = unsafe { BNGetMediumLevelILBasicBlockList(self.handle, &mut count) }; let context = MediumLevelILBlock { @@ -107,7 +116,18 @@ impl MediumLevelILFunction { } } -impl ToOwned for MediumLevelILFunction { +impl MediumLevelILFunction { + pub fn ssa_form(&self) -> MediumLevelILFunction { + let ssa = unsafe { BNGetMediumLevelILSSAForm(self.handle) }; + assert!(!ssa.is_null()); + MediumLevelILFunction { + handle: ssa, + _form: std::marker::PhantomData, + } + } +} + +impl ToOwned for MediumLevelILFunction { type Owned = Ref; fn to_owned(&self) -> Self::Owned { @@ -115,10 +135,11 @@ impl ToOwned for MediumLevelILFunction { } } -unsafe impl RefCountable for MediumLevelILFunction { +unsafe impl RefCountable for MediumLevelILFunction { unsafe fn inc_ref(handle: &Self) -> Ref { Ref::new(Self { handle: BNNewMediumLevelILFunctionReference(handle.handle), + _form: std::marker::PhantomData, }) } @@ -127,7 +148,7 @@ unsafe impl RefCountable for MediumLevelILFunction { } } -impl core::fmt::Debug for MediumLevelILFunction { +impl core::fmt::Debug for MediumLevelILFunction { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "", self.handle) } diff --git a/rust/src/mlil/instruction.rs b/rust/src/mlil/instruction.rs index bd2cc7171..468053c22 100644 --- a/rust/src/mlil/instruction.rs +++ b/rust/src/mlil/instruction.rs @@ -5,25 +5,363 @@ use binaryninjacore_sys::BNMediumLevelILOperation; use crate::operand_iter::OperandIter; use crate::rc::Ref; -use crate::types::{ - ConstantData, ILIntrinsic, RegisterValue, RegisterValueType, SSAVariable, Variable, -}; +use crate::types::{SSAVariable, Variable}; use super::lift::*; use super::operation::*; -use super::MediumLevelILFunction; +use super::{ + Form, InstructionLiftedTrait, InstructionTrait, InstructionTraitFromRaw, MediumLevelILFunction, + Sealed, +}; + +use strum::IntoStaticStr; #[derive(Clone)] -pub struct MediumLevelILInstruction { - pub function: Ref, +pub struct MediumLevelILInstruction { + pub function: Ref>, pub address: u64, pub index: usize, pub size: usize, - pub kind: MediumLevelILInstructionKind, + pub kind: I::Instruction, +} + +macro_rules! construct_common { + ($form:ident) => { + fn from_common_operation(op: BNMediumLevelILInstruction) -> Option { + use crate::mlil::operation::*; + use BNMediumLevelILOperation::*; + Some(match op.operation { + MLIL_NOP => Self::Nop, + MLIL_NORET => Self::Noret, + MLIL_BP => Self::Bp, + MLIL_UNDEF => Self::Undef, + MLIL_UNIMPL => Self::Unimpl, + MLIL_IF => Self::If(MediumLevelILOperationIf { + condition: op.operands[0] as usize, + dest_true: op.operands[1], + dest_false: op.operands[2], + }), + MLIL_FLOAT_CONST => Self::FloatConst(FloatConst { + constant: get_float(op.operands[0], op.size), + }), + MLIL_CONST => Self::Const(Constant { + constant: op.operands[0], + }), + MLIL_CONST_PTR => Self::ConstPtr(Constant { + constant: op.operands[0], + }), + MLIL_IMPORT => Self::Import(Constant { + constant: op.operands[0], + }), + MLIL_EXTERN_PTR => Self::ExternPtr(ExternPtr { + constant: op.operands[0], + offset: op.operands[1], + }), + MLIL_CONST_DATA => Self::ConstData(ConstData { + constant_data_kind: op.operands[0] as u32, + constant_data_value: op.operands[1] as i64, + size: op.size, + }), + MLIL_JUMP => Self::Jump(Jump { + dest: op.operands[0] as usize, + }), + MLIL_RET_HINT => Self::RetHint(Jump { + dest: op.operands[0] as usize, + }), + MLIL_JUMP_TO => Self::JumpTo(JumpTo { + dest: op.operands[0] as usize, + num_operands: op.operands[1] as usize, + first_operand: op.operands[2] as usize, + }), + MLIL_GOTO => Self::Goto(Goto { + dest: op.operands[0], + }), + MLIL_MEM_PHI => Self::MemPhi(MemPhi { + dest_memory: op.operands[0], + num_operands: op.operands[1] as usize, + first_operand: op.operands[2] as usize, + }), + MLIL_ADD => Self::Add(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_SUB => Self::Sub(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_AND => Self::And(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_OR => Self::Or(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_XOR => Self::Xor(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_LSL => Self::Lsl(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_LSR => Self::Lsr(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ASR => Self::Asr(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ROL => Self::Rol(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ROR => Self::Ror(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MUL => Self::Mul(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MULU_DP => Self::MuluDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MULS_DP => Self::MulsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVU => Self::Divu(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVU_DP => Self::DivuDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVS => Self::Divs(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_DIVS_DP => Self::DivsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODU => Self::Modu(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODU_DP => Self::ModuDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODS => Self::Mods(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_MODS_DP => Self::ModsDp(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_E => Self::CmpE(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_NE => Self::CmpNe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SLT => Self::CmpSlt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_ULT => Self::CmpUlt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SLE => Self::CmpSle(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_ULE => Self::CmpUle(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SGE => Self::CmpSge(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_UGE => Self::CmpUge(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_SGT => Self::CmpSgt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_CMP_UGT => Self::CmpUgt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_TEST_BIT => Self::TestBit(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ADD_OVERFLOW => Self::AddOverflow(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_E => Self::FcmpE(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_NE => Self::FcmpNe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_LT => Self::FcmpLt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_LE => Self::FcmpLe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_GE => Self::FcmpGe(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_GT => Self::FcmpGt(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_O => Self::FcmpO(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FCMP_UO => Self::FcmpUo(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FADD => Self::Fadd(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FSUB => Self::Fsub(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FMUL => Self::Fmul(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_FDIV => Self::Fdiv(BinaryOp { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + }), + MLIL_ADC => Self::Adc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_SBB => Self::Sbb(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_RLC => Self::Rlc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_RRC => Self::Rrc(BinaryOpCarry { + left: op.operands[0] as usize, + right: op.operands[1] as usize, + carry: op.operands[2] as usize, + }), + MLIL_NEG => Self::Neg(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_NOT => Self::Not(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_SX => Self::Sx(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_ZX => Self::Zx(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_LOW_PART => Self::LowPart(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_BOOL_TO_INT => Self::BoolToInt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_UNIMPL_MEM => Self::UnimplMem(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FSQRT => Self::Fsqrt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FNEG => Self::Fneg(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FABS => Self::Fabs(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FLOAT_TO_INT => Self::FloatToInt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_INT_TO_FLOAT => Self::IntToFloat(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FLOAT_CONV => Self::FloatConv(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_ROUND_TO_INT => Self::RoundToInt(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FLOOR => Self::Floor(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_CEIL => Self::Ceil(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_FTRUNC => Self::Ftrunc(UnaryOp { + src: op.operands[0] as usize, + }), + MLIL_RET => Self::Ret(Ret { + num_operands: op.operands[0] as usize, + first_operand: op.operands[1] as usize, + }), + MLIL_SEPARATE_PARAM_LIST => Self::SeparateParamList(SeparateParamList { + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, + }), + MLIL_SHARED_PARAM_SLOT => Self::SharedParamSlot(SharedParamSlot { + num_params: op.operands[0] as usize, + first_param: op.operands[1] as usize, + }), + MLIL_ADDRESS_OF => Self::AddressOf(Var { + src: get_var(op.operands[0]), + }), + MLIL_ADDRESS_OF_FIELD => Self::AddressOfField(Field { + src: get_var(op.operands[0]), + offset: op.operands[1], + }), + MLIL_TRAP => Self::Trap(Trap { + vector: op.operands[0], + }), + _ => return None, + }) + } + }; } -#[derive(Copy, Clone)] -pub enum MediumLevelILInstructionKind { +#[derive(Debug, Copy, Clone, IntoStaticStr)] +pub enum MediumLevelILInstructionKindNonSSA { Nop, Noret, Bp, @@ -38,26 +376,8 @@ pub enum MediumLevelILInstructionKind { ConstData(ConstData), Jump(Jump), RetHint(Jump), - StoreSsa(StoreSsa), - StoreStructSsa(StoreStructSsa), - StoreStruct(StoreStruct), - Store(Store), JumpTo(JumpTo), Goto(Goto), - FreeVarSlot(FreeVarSlot), - SetVarField(SetVarField), - SetVar(SetVar), - FreeVarSlotSsa(FreeVarSlotSsa), - SetVarSsaField(SetVarSsaField), - SetVarAliasedField(SetVarSsaField), - SetVarAliased(SetVarAliased), - SetVarSsa(SetVarSsa), - VarPhi(VarPhi), - MemPhi(MemPhi), - VarSplit(VarSplit), - SetVarSplit(SetVarSplit), - VarSplitSsa(VarSplitSsa), - SetVarSplitSsa(SetVarSplitSsa), Add(BinaryOp), Sub(BinaryOp), And(BinaryOp), @@ -107,22 +427,6 @@ pub enum MediumLevelILInstructionKind { Sbb(BinaryOpCarry), Rlc(BinaryOpCarry), Rrc(BinaryOpCarry), - Call(Call), - Tailcall(Call), - Syscall(Syscall), - Intrinsic(Intrinsic), - IntrinsicSsa(IntrinsicSsa), - CallSsa(CallSsa), - TailcallSsa(CallSsa), - CallUntypedSsa(CallUntypedSsa), - TailcallUntypedSsa(CallUntypedSsa), - SyscallSsa(SyscallSsa), - SyscallUntypedSsa(SyscallUntypedSsa), - CallUntyped(CallUntyped), - TailcallUntyped(CallUntyped), - SyscallUntyped(SyscallUntyped), - SeparateParamList(SeparateParamList), - SharedParamSlot(SharedParamSlot), Neg(UnaryOp), Not(UnaryOp), Sx(UnaryOp), @@ -140,974 +444,506 @@ pub enum MediumLevelILInstructionKind { Floor(UnaryOp), Ceil(UnaryOp), Ftrunc(UnaryOp), - Load(UnaryOp), - LoadStruct(LoadStruct), - LoadStructSsa(LoadStructSsa), - LoadSsa(LoadSsa), Ret(Ret), - Var(Var), + + MemPhi(MemPhi), + SeparateParamList(SeparateParamList), + SharedParamSlot(SharedParamSlot), + AddressOf(Var), - VarField(Field), AddressOfField(Field), - VarSsa(VarSsa), - VarAliased(VarSsa), - VarSsaField(VarSsaField), - VarAliasedField(VarSsaField), Trap(Trap), -} -impl core::fmt::Debug for MediumLevelILInstruction { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!( - f, - "<{} at 0x{:08}>", - core::any::type_name::(), - self.address, - ) - } + Var(Var), + VarField(Field), + Store(Store), + StoreStruct(StoreStruct), + SetVar(SetVar), + SetVarField(SetVarField), + FreeVarSlot(FreeVarSlot), + VarSplit(VarSplit), + SetVarSplit(SetVarSplit), + Call(Call), + CallUntyped(CallUntyped), + Tailcall(Call), + Syscall(Syscall), + SyscallUntyped(SyscallUntyped), + Intrinsic(Intrinsic), + TailcallUntyped(CallUntyped), + Load(UnaryOp), + LoadStruct(LoadStruct), } -impl MediumLevelILInstruction { - pub(crate) fn new(function: Ref, index: usize) -> Self { - let op = unsafe { BNGetMediumLevelILByIndex(function.handle, index) }; +impl Sealed for MediumLevelILInstructionKindNonSSA {} +impl MediumLevelILInstructionKindNonSSA { + construct_common!(NonSSA); +} +impl MediumLevelILInstructionKindNonSSA { + fn from_this_operation(op: BNMediumLevelILInstruction) -> Option { + use crate::mlil::operation::*; use BNMediumLevelILOperation::*; - use MediumLevelILInstructionKind as Op; - let kind = match op.operation { - MLIL_NOP => Op::Nop, - MLIL_NORET => Op::Noret, - MLIL_BP => Op::Bp, - MLIL_UNDEF => Op::Undef, - MLIL_UNIMPL => Op::Unimpl, - MLIL_IF => Op::If(MediumLevelILOperationIf { - condition: op.operands[0] as usize, - dest_true: op.operands[1], - dest_false: op.operands[2], - }), - MLIL_FLOAT_CONST => Op::FloatConst(FloatConst { - constant: get_float(op.operands[0], op.size), - }), - MLIL_CONST => Op::Const(Constant { - constant: op.operands[0], - }), - MLIL_CONST_PTR => Op::ConstPtr(Constant { - constant: op.operands[0], - }), - MLIL_IMPORT => Op::Import(Constant { - constant: op.operands[0], - }), - MLIL_EXTERN_PTR => Op::ExternPtr(ExternPtr { - constant: op.operands[0], - offset: op.operands[1], - }), - MLIL_CONST_DATA => Op::ConstData(ConstData { - constant_data_kind: op.operands[0] as u32, - constant_data_value: op.operands[1] as i64, - size: op.size, - }), - MLIL_JUMP => Op::Jump(Jump { - dest: op.operands[0] as usize, - }), - MLIL_RET_HINT => Op::RetHint(Jump { - dest: op.operands[0] as usize, - }), - MLIL_STORE_SSA => Op::StoreSsa(StoreSsa { - dest: op.operands[0] as usize, - dest_memory: op.operands[1], - src_memory: op.operands[2], - src: op.operands[3] as usize, - }), - MLIL_STORE_STRUCT_SSA => Op::StoreStructSsa(StoreStructSsa { - dest: op.operands[0] as usize, - offset: op.operands[1], - dest_memory: op.operands[2], - src_memory: op.operands[3], - src: op.operands[4] as usize, - }), - MLIL_STORE_STRUCT => Op::StoreStruct(StoreStruct { + Some(match op.operation { + MLIL_STORE_STRUCT => Self::StoreStruct(StoreStruct { dest: op.operands[0] as usize, offset: op.operands[1], src: op.operands[2] as usize, }), - MLIL_STORE => Op::Store(Store { + MLIL_STORE => Self::Store(Store { dest: op.operands[0] as usize, src: op.operands[1] as usize, }), - MLIL_JUMP_TO => Op::JumpTo(JumpTo { - dest: op.operands[0] as usize, - num_operands: op.operands[1] as usize, - first_operand: op.operands[2] as usize, - }), - MLIL_GOTO => Op::Goto(Goto { - dest: op.operands[0], - }), - MLIL_FREE_VAR_SLOT => Op::FreeVarSlot(FreeVarSlot { + MLIL_FREE_VAR_SLOT => Self::FreeVarSlot(FreeVarSlot { dest: get_var(op.operands[0]), }), - MLIL_SET_VAR_FIELD => Op::SetVarField(SetVarField { + MLIL_SET_VAR_FIELD => Self::SetVarField(SetVarField { dest: get_var(op.operands[0]), offset: op.operands[1], src: op.operands[2] as usize, }), - MLIL_SET_VAR => Op::SetVar(SetVar { + MLIL_SET_VAR => Self::SetVar(SetVar { dest: get_var(op.operands[0]), src: op.operands[1] as usize, }), - MLIL_FREE_VAR_SLOT_SSA => Op::FreeVarSlotSsa(FreeVarSlotSsa { - dest: get_var_ssa(op.operands[0], op.operands[1] as usize), - prev: get_var_ssa(op.operands[0], op.operands[2] as usize), - }), - MLIL_SET_VAR_SSA_FIELD => Op::SetVarSsaField(SetVarSsaField { - dest: get_var_ssa(op.operands[0], op.operands[1] as usize), - prev: get_var_ssa(op.operands[0], op.operands[2] as usize), - offset: op.operands[3], - src: op.operands[4] as usize, - }), - MLIL_SET_VAR_ALIASED_FIELD => Op::SetVarAliasedField(SetVarSsaField { - dest: get_var_ssa(op.operands[0], op.operands[1] as usize), - prev: get_var_ssa(op.operands[0], op.operands[2] as usize), - offset: op.operands[3], - src: op.operands[4] as usize, - }), - MLIL_SET_VAR_ALIASED => Op::SetVarAliased(SetVarAliased { - dest: get_var_ssa(op.operands[0], op.operands[1] as usize), - prev: get_var_ssa(op.operands[0], op.operands[2] as usize), - src: op.operands[3] as usize, - }), - MLIL_SET_VAR_SSA => Op::SetVarSsa(SetVarSsa { - dest: get_var_ssa(op.operands[0], op.operands[1] as usize), - src: op.operands[2] as usize, - }), - MLIL_VAR_PHI => Op::VarPhi(VarPhi { - dest: get_var_ssa(op.operands[0], op.operands[1] as usize), - num_operands: op.operands[2] as usize, - first_operand: op.operands[3] as usize, - }), - MLIL_MEM_PHI => Op::MemPhi(MemPhi { - dest_memory: op.operands[0], - num_operands: op.operands[1] as usize, - first_operand: op.operands[2] as usize, - }), - MLIL_VAR_SPLIT => Op::VarSplit(VarSplit { + MLIL_VAR_SPLIT => Self::VarSplit(VarSplit { high: get_var(op.operands[0]), low: get_var(op.operands[1]), }), - MLIL_SET_VAR_SPLIT => Op::SetVarSplit(SetVarSplit { + MLIL_SET_VAR_SPLIT => Self::SetVarSplit(SetVarSplit { high: get_var(op.operands[0]), low: get_var(op.operands[1]), src: op.operands[2] as usize, }), - MLIL_VAR_SPLIT_SSA => Op::VarSplitSsa(VarSplitSsa { - high: get_var_ssa(op.operands[0], op.operands[1] as usize), - low: get_var_ssa(op.operands[2], op.operands[3] as usize), - }), - MLIL_SET_VAR_SPLIT_SSA => Op::SetVarSplitSsa(SetVarSplitSsa { - high: get_var_ssa(op.operands[0], op.operands[1] as usize), - low: get_var_ssa(op.operands[2], op.operands[3] as usize), - src: op.operands[4] as usize, - }), - MLIL_ADD => Op::Add(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_SUB => Op::Sub(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_AND => Op::And(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_OR => Op::Or(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_XOR => Op::Xor(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_LSL => Op::Lsl(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_LSR => Op::Lsr(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_ASR => Op::Asr(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_ROL => Op::Rol(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_ROR => Op::Ror(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_MUL => Op::Mul(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_MULU_DP => Op::MuluDp(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_MULS_DP => Op::MulsDp(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_DIVU => Op::Divu(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_DIVU_DP => Op::DivuDp(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_DIVS => Op::Divs(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_DIVS_DP => Op::DivsDp(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_MODU => Op::Modu(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_MODU_DP => Op::ModuDp(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_MODS => Op::Mods(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_MODS_DP => Op::ModsDp(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_E => Op::CmpE(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_NE => Op::CmpNe(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_SLT => Op::CmpSlt(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_ULT => Op::CmpUlt(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_SLE => Op::CmpSle(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_ULE => Op::CmpUle(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_SGE => Op::CmpSge(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_UGE => Op::CmpUge(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_SGT => Op::CmpSgt(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_CMP_UGT => Op::CmpUgt(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_TEST_BIT => Op::TestBit(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_ADD_OVERFLOW => Op::AddOverflow(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_E => Op::FcmpE(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_NE => Op::FcmpNe(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_LT => Op::FcmpLt(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_LE => Op::FcmpLe(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_GE => Op::FcmpGe(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_GT => Op::FcmpGt(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_O => Op::FcmpO(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FCMP_UO => Op::FcmpUo(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FADD => Op::Fadd(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FSUB => Op::Fsub(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FMUL => Op::Fmul(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_FDIV => Op::Fdiv(BinaryOp { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - }), - MLIL_ADC => Op::Adc(BinaryOpCarry { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - carry: op.operands[2] as usize, - }), - MLIL_SBB => Op::Sbb(BinaryOpCarry { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - carry: op.operands[2] as usize, - }), - MLIL_RLC => Op::Rlc(BinaryOpCarry { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - carry: op.operands[2] as usize, - }), - MLIL_RRC => Op::Rrc(BinaryOpCarry { - left: op.operands[0] as usize, - right: op.operands[1] as usize, - carry: op.operands[2] as usize, - }), - MLIL_CALL => Op::Call(Call { + MLIL_CALL => Self::Call(Call { num_outputs: op.operands[0] as usize, first_output: op.operands[1] as usize, dest: op.operands[2] as usize, num_params: op.operands[3] as usize, first_param: op.operands[4] as usize, }), - MLIL_TAILCALL => Op::Tailcall(Call { + MLIL_TAILCALL => Self::Tailcall(Call { num_outputs: op.operands[0] as usize, first_output: op.operands[1] as usize, dest: op.operands[2] as usize, num_params: op.operands[3] as usize, first_param: op.operands[4] as usize, }), - MLIL_SYSCALL => Op::Syscall(Syscall { + MLIL_SYSCALL => Self::Syscall(Syscall { num_outputs: op.operands[0] as usize, first_output: op.operands[1] as usize, num_params: op.operands[2] as usize, first_param: op.operands[3] as usize, }), - MLIL_INTRINSIC => Op::Intrinsic(Intrinsic { - num_outputs: op.operands[0] as usize, - first_output: op.operands[1] as usize, - intrinsic: op.operands[2] as u32, - num_params: op.operands[3] as usize, - first_param: op.operands[4] as usize, - }), - MLIL_INTRINSIC_SSA => Op::IntrinsicSsa(IntrinsicSsa { + MLIL_INTRINSIC => Self::Intrinsic(Intrinsic { num_outputs: op.operands[0] as usize, first_output: op.operands[1] as usize, intrinsic: op.operands[2] as u32, num_params: op.operands[3] as usize, first_param: op.operands[4] as usize, }), - MLIL_CALL_SSA => Op::CallSsa(CallSsa { - output: op.operands[0] as usize, - dest: op.operands[1] as usize, - num_params: op.operands[2] as usize, - first_param: op.operands[3] as usize, - src_memory: op.operands[4], - }), - MLIL_TAILCALL_SSA => Op::TailcallSsa(CallSsa { - output: op.operands[0] as usize, - dest: op.operands[1] as usize, - num_params: op.operands[2] as usize, - first_param: op.operands[3] as usize, - src_memory: op.operands[4], - }), - MLIL_CALL_UNTYPED_SSA => Op::CallUntypedSsa(CallUntypedSsa { - output: op.operands[0] as usize, - dest: op.operands[1] as usize, - params: op.operands[2] as usize, - stack: op.operands[3] as usize, - }), - MLIL_TAILCALL_UNTYPED_SSA => Op::TailcallUntypedSsa(CallUntypedSsa { - output: op.operands[0] as usize, - dest: op.operands[1] as usize, - params: op.operands[2] as usize, - stack: op.operands[3] as usize, - }), - MLIL_SYSCALL_SSA => Op::SyscallSsa(SyscallSsa { - output: op.operands[0] as usize, - num_params: op.operands[1] as usize, - first_param: op.operands[2] as usize, - src_memory: op.operands[3], - }), - MLIL_SYSCALL_UNTYPED_SSA => Op::SyscallUntypedSsa(SyscallUntypedSsa { - output: op.operands[0] as usize, - params: op.operands[1] as usize, - stack: op.operands[2] as usize, - }), - MLIL_CALL_UNTYPED => Op::CallUntyped(CallUntyped { + MLIL_CALL_UNTYPED => Self::CallUntyped(CallUntyped { output: op.operands[0] as usize, dest: op.operands[1] as usize, params: op.operands[2] as usize, stack: op.operands[3] as usize, }), - MLIL_TAILCALL_UNTYPED => Op::TailcallUntyped(CallUntyped { + MLIL_TAILCALL_UNTYPED => Self::TailcallUntyped(CallUntyped { output: op.operands[0] as usize, dest: op.operands[1] as usize, params: op.operands[2] as usize, stack: op.operands[3] as usize, }), - MLIL_SYSCALL_UNTYPED => Op::SyscallUntyped(SyscallUntyped { + MLIL_SYSCALL_UNTYPED => Self::SyscallUntyped(SyscallUntyped { output: op.operands[0] as usize, params: op.operands[1] as usize, stack: op.operands[2] as usize, }), - MLIL_NEG => Op::Neg(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_NOT => Op::Not(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_SX => Op::Sx(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_ZX => Op::Zx(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_LOW_PART => Op::LowPart(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_BOOL_TO_INT => Op::BoolToInt(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_UNIMPL_MEM => Op::UnimplMem(UnaryOp { + MLIL_LOAD => Self::Load(UnaryOp { src: op.operands[0] as usize, }), - MLIL_FSQRT => Op::Fsqrt(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_FNEG => Op::Fneg(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_FABS => Op::Fabs(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_FLOAT_TO_INT => Op::FloatToInt(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_INT_TO_FLOAT => Op::IntToFloat(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_FLOAT_CONV => Op::FloatConv(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_ROUND_TO_INT => Op::RoundToInt(UnaryOp { + MLIL_LOAD_STRUCT => Self::LoadStruct(LoadStruct { src: op.operands[0] as usize, + offset: op.operands[1], }), - MLIL_FLOOR => Op::Floor(UnaryOp { - src: op.operands[0] as usize, + MLIL_VAR_FIELD => Self::VarField(Field { + src: get_var(op.operands[0]), + offset: op.operands[1], }), - MLIL_CEIL => Op::Ceil(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_FTRUNC => Op::Ftrunc(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_LOAD => Op::Load(UnaryOp { - src: op.operands[0] as usize, - }), - MLIL_LOAD_STRUCT => Op::LoadStruct(LoadStruct { - src: op.operands[0] as usize, - offset: op.operands[1], - }), - MLIL_LOAD_STRUCT_SSA => Op::LoadStructSsa(LoadStructSsa { - src: op.operands[0] as usize, - offset: op.operands[1], - src_memory: op.operands[2], - }), - MLIL_LOAD_SSA => Op::LoadSsa(LoadSsa { - src: op.operands[0] as usize, - src_memory: op.operands[1], - }), - MLIL_RET => Op::Ret(Ret { - num_operands: op.operands[0] as usize, - first_operand: op.operands[1] as usize, - }), - MLIL_SEPARATE_PARAM_LIST => Op::SeparateParamList(SeparateParamList { - num_params: op.operands[0] as usize, - first_param: op.operands[1] as usize, - }), - MLIL_SHARED_PARAM_SLOT => Op::SharedParamSlot(SharedParamSlot { - num_params: op.operands[0] as usize, - first_param: op.operands[1] as usize, - }), - MLIL_VAR => Op::Var(Var { - src: get_var(op.operands[0]), - }), - MLIL_ADDRESS_OF => Op::AddressOf(Var { - src: get_var(op.operands[0]), - }), - MLIL_VAR_FIELD => Op::VarField(Field { - src: get_var(op.operands[0]), - offset: op.operands[1], - }), - MLIL_ADDRESS_OF_FIELD => Op::AddressOfField(Field { - src: get_var(op.operands[0]), - offset: op.operands[1], - }), - MLIL_VAR_SSA => Op::VarSsa(VarSsa { - src: get_var_ssa(op.operands[0], op.operands[1] as usize), - }), - MLIL_VAR_ALIASED => Op::VarAliased(VarSsa { - src: get_var_ssa(op.operands[0], op.operands[1] as usize), - }), - MLIL_VAR_SSA_FIELD => Op::VarSsaField(VarSsaField { - src: get_var_ssa(op.operands[0], op.operands[1] as usize), - offset: op.operands[2], - }), - MLIL_VAR_ALIASED_FIELD => Op::VarAliasedField(VarSsaField { - src: get_var_ssa(op.operands[0], op.operands[1] as usize), - offset: op.operands[2], - }), - MLIL_TRAP => Op::Trap(Trap { - vector: op.operands[0], - }), - // translated directly into a list for Expression or Variables - // TODO MLIL_MEMORY_INTRINSIC_SSA needs to be handled properly - MLIL_CALL_OUTPUT - | MLIL_CALL_PARAM - | MLIL_CALL_PARAM_SSA - | MLIL_CALL_OUTPUT_SSA - | MLIL_MEMORY_INTRINSIC_OUTPUT_SSA - | MLIL_MEMORY_INTRINSIC_SSA => { - unreachable!() - } - }; + _ => return None, + }) + } +} - Self { - function, - address: op.address, - index, - size: op.size, - kind, - } +impl InstructionTraitFromRaw for MediumLevelILInstructionKindNonSSA { + fn from_operation(op: BNMediumLevelILInstruction) -> Option { + Self::from_common_operation(op).or_else(|| Self::from_this_operation(op)) } +} - pub fn lift(&self) -> MediumLevelILLiftedInstruction { - use MediumLevelILInstructionKind::*; - use MediumLevelILLiftedInstructionKind as Lifted; +impl InstructionTrait for MediumLevelILInstructionKindNonSSA { + fn name(&self) -> &'static str { + self.into() + } +} - let kind = match self.kind { - Nop => Lifted::Nop, - Noret => Lifted::Noret, - Bp => Lifted::Bp, - Undef => Lifted::Undef, - Unimpl => Lifted::Unimpl, - If(op) => Lifted::If(LiftedIf { - condition: self.lift_operand(op.condition), - dest_true: op.dest_true, - dest_false: op.dest_false, - }), +#[derive(Debug, Copy, Clone, IntoStaticStr)] +pub enum MediumLevelILInstructionKindSSA { + Nop, + Noret, + Bp, + Undef, + Unimpl, + If(MediumLevelILOperationIf), + FloatConst(FloatConst), + Const(Constant), + ConstPtr(Constant), + Import(Constant), + ExternPtr(ExternPtr), + ConstData(ConstData), + Jump(Jump), + RetHint(Jump), + JumpTo(JumpTo), + Goto(Goto), + Add(BinaryOp), + Sub(BinaryOp), + And(BinaryOp), + Or(BinaryOp), + Xor(BinaryOp), + Lsl(BinaryOp), + Lsr(BinaryOp), + Asr(BinaryOp), + Rol(BinaryOp), + Ror(BinaryOp), + Mul(BinaryOp), + MuluDp(BinaryOp), + MulsDp(BinaryOp), + Divu(BinaryOp), + DivuDp(BinaryOp), + Divs(BinaryOp), + DivsDp(BinaryOp), + Modu(BinaryOp), + ModuDp(BinaryOp), + Mods(BinaryOp), + ModsDp(BinaryOp), + CmpE(BinaryOp), + CmpNe(BinaryOp), + CmpSlt(BinaryOp), + CmpUlt(BinaryOp), + CmpSle(BinaryOp), + CmpUle(BinaryOp), + CmpSge(BinaryOp), + CmpUge(BinaryOp), + CmpSgt(BinaryOp), + CmpUgt(BinaryOp), + TestBit(BinaryOp), + AddOverflow(BinaryOp), + FcmpE(BinaryOp), + FcmpNe(BinaryOp), + FcmpLt(BinaryOp), + FcmpLe(BinaryOp), + FcmpGe(BinaryOp), + FcmpGt(BinaryOp), + FcmpO(BinaryOp), + FcmpUo(BinaryOp), + Fadd(BinaryOp), + Fsub(BinaryOp), + Fmul(BinaryOp), + Fdiv(BinaryOp), + Adc(BinaryOpCarry), + Sbb(BinaryOpCarry), + Rlc(BinaryOpCarry), + Rrc(BinaryOpCarry), + Neg(UnaryOp), + Not(UnaryOp), + Sx(UnaryOp), + Zx(UnaryOp), + LowPart(UnaryOp), + BoolToInt(UnaryOp), + UnimplMem(UnaryOp), + Fsqrt(UnaryOp), + Fneg(UnaryOp), + Fabs(UnaryOp), + FloatToInt(UnaryOp), + IntToFloat(UnaryOp), + FloatConv(UnaryOp), + RoundToInt(UnaryOp), + Floor(UnaryOp), + Ceil(UnaryOp), + Ftrunc(UnaryOp), + Ret(Ret), - FloatConst(op) => Lifted::FloatConst(op), - Const(op) => Lifted::Const(op), - ConstPtr(op) => Lifted::ConstPtr(op), - Import(op) => Lifted::Import(op), - ExternPtr(op) => Lifted::ExternPtr(op), + MemPhi(MemPhi), + SeparateParamList(SeparateParamList), + SharedParamSlot(SharedParamSlot), + + AddressOf(Var), + AddressOfField(Field), + Trap(Trap), - ConstData(op) => Lifted::ConstData(LiftedConstData { - constant_data: ConstantData::new( - self.function.get_function(), - RegisterValue { - state: RegisterValueType::from_raw_value(op.constant_data_kind).unwrap(), - value: op.constant_data_value, - offset: 0, - size: op.size, - }, - ), + VarSsa(VarSsa), + VarSsaField(VarSsaField), + StoreSsa(StoreSsa), + StoreStructSsa(StoreStructSsa), + SetVarSsa(SetVarSsa), + SetVarSsaField(SetVarSsaField), + FreeVarSlotSsa(FreeVarSlotSsa), + VarSplitSsa(VarSplitSsa), + SetVarSplitSsa(SetVarSplitSsa), + CallSsa(CallSsa), + CallUntypedSsa(CallUntypedSsa), + TailcallSsa(CallSsa), + SyscallSsa(SyscallSsa), + SyscallUntypedSsa(SyscallUntypedSsa), + IntrinsicSsa(IntrinsicSsa), + TailcallUntypedSsa(CallUntypedSsa), + LoadSsa(LoadSsa), + LoadStructSsa(LoadStructSsa), + + SetVarAliased(SetVarAliased), + SetVarAliasedField(SetVarSsaField), + VarPhi(VarPhi), + VarAliased(VarSsa), + VarAliasedField(VarSsaField), +} + +impl Sealed for MediumLevelILInstructionKindSSA {} +impl MediumLevelILInstructionKindSSA { + construct_common!(SSA); + fn from_this_operation(op: BNMediumLevelILInstruction) -> Option { + use crate::mlil::operation::*; + use BNMediumLevelILOperation::*; + Some(match op.operation { + MLIL_STORE_SSA => Self::StoreSsa(StoreSsa { + dest: op.operands[0] as usize, + dest_memory: op.operands[1], + src_memory: op.operands[2], + src: op.operands[3] as usize, }), - Jump(op) => Lifted::Jump(LiftedJump { - dest: self.lift_operand(op.dest), + MLIL_STORE_STRUCT_SSA => Self::StoreStructSsa(StoreStructSsa { + dest: op.operands[0] as usize, + offset: op.operands[1], + dest_memory: op.operands[2], + src_memory: op.operands[3], + src: op.operands[4] as usize, }), - RetHint(op) => Lifted::RetHint(LiftedJump { - dest: self.lift_operand(op.dest), + MLIL_FREE_VAR_SLOT_SSA => Self::FreeVarSlotSsa(FreeVarSlotSsa { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), }), - StoreSsa(op) => Lifted::StoreSsa(LiftedStoreSsa { - dest: self.lift_operand(op.dest), - dest_memory: op.dest_memory, - src_memory: op.src_memory, - src: self.lift_operand(op.src), + MLIL_SET_VAR_SSA_FIELD => Self::SetVarSsaField(SetVarSsaField { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), + offset: op.operands[3], + src: op.operands[4] as usize, }), - StoreStructSsa(op) => Lifted::StoreStructSsa(LiftedStoreStructSsa { - dest: self.lift_operand(op.dest), - offset: op.offset, - dest_memory: op.dest_memory, - src_memory: op.src_memory, - src: self.lift_operand(op.src), + MLIL_SET_VAR_ALIASED_FIELD => Self::SetVarAliasedField(SetVarSsaField { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), + offset: op.operands[3], + src: op.operands[4] as usize, }), - StoreStruct(op) => Lifted::StoreStruct(LiftedStoreStruct { - dest: self.lift_operand(op.dest), - offset: op.offset, - src: self.lift_operand(op.src), + MLIL_SET_VAR_ALIASED => Self::SetVarAliased(SetVarAliased { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + prev: get_var_ssa(op.operands[0], op.operands[2] as usize), + src: op.operands[3] as usize, }), - Store(op) => Lifted::Store(LiftedStore { - dest: self.lift_operand(op.dest), - src: self.lift_operand(op.src), + MLIL_SET_VAR_SSA => Self::SetVarSsa(SetVarSsa { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + src: op.operands[2] as usize, }), - JumpTo(op) => Lifted::JumpTo(LiftedJumpTo { - dest: self.lift_operand(op.dest), - targets: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .pairs() - .collect(), + MLIL_VAR_PHI => Self::VarPhi(VarPhi { + dest: get_var_ssa(op.operands[0], op.operands[1] as usize), + num_operands: op.operands[2] as usize, + first_operand: op.operands[3] as usize, }), - Goto(op) => Lifted::Goto(op), - FreeVarSlot(op) => Lifted::FreeVarSlot(op), - SetVarField(op) => Lifted::SetVarField(LiftedSetVarField { - dest: op.dest, - offset: op.offset, - src: self.lift_operand(op.src), + MLIL_VAR_SPLIT_SSA => Self::VarSplitSsa(VarSplitSsa { + high: get_var_ssa(op.operands[0], op.operands[1] as usize), + low: get_var_ssa(op.operands[2], op.operands[3] as usize), }), - SetVar(op) => Lifted::SetVar(LiftedSetVar { - dest: op.dest, - src: self.lift_operand(op.src), + MLIL_SET_VAR_SPLIT_SSA => Self::SetVarSplitSsa(SetVarSplitSsa { + high: get_var_ssa(op.operands[0], op.operands[1] as usize), + low: get_var_ssa(op.operands[2], op.operands[3] as usize), + src: op.operands[4] as usize, }), - FreeVarSlotSsa(op) => Lifted::FreeVarSlotSsa(op), - SetVarSsaField(op) => Lifted::SetVarSsaField(LiftedSetVarSsaField { - dest: op.dest, - prev: op.prev, - offset: op.offset, - src: self.lift_operand(op.src), + MLIL_INTRINSIC_SSA => Self::IntrinsicSsa(IntrinsicSsa { + num_outputs: op.operands[0] as usize, + first_output: op.operands[1] as usize, + intrinsic: op.operands[2] as u32, + num_params: op.operands[3] as usize, + first_param: op.operands[4] as usize, }), - SetVarAliasedField(op) => Lifted::SetVarAliasedField(LiftedSetVarSsaField { - dest: op.dest, - prev: op.prev, - offset: op.offset, - src: self.lift_operand(op.src), + MLIL_CALL_SSA => Self::CallSsa(CallSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + num_params: op.operands[2] as usize, + first_param: op.operands[3] as usize, + src_memory: op.operands[4], }), - SetVarAliased(op) => Lifted::SetVarAliased(LiftedSetVarAliased { - dest: op.dest, - prev: op.prev, - src: self.lift_operand(op.src), + MLIL_TAILCALL_SSA => Self::TailcallSsa(CallSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + num_params: op.operands[2] as usize, + first_param: op.operands[3] as usize, + src_memory: op.operands[4], }), - SetVarSsa(op) => Lifted::SetVarSsa(LiftedSetVarSsa { - dest: op.dest, - src: self.lift_operand(op.src), + MLIL_CALL_UNTYPED_SSA => Self::CallUntypedSsa(CallUntypedSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + params: op.operands[2] as usize, + stack: op.operands[3] as usize, }), - VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { - dest: op.dest, - src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .ssa_vars() - .collect(), + MLIL_TAILCALL_UNTYPED_SSA => Self::TailcallUntypedSsa(CallUntypedSsa { + output: op.operands[0] as usize, + dest: op.operands[1] as usize, + params: op.operands[2] as usize, + stack: op.operands[3] as usize, }), - MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { - dest_memory: op.dest_memory, - src_memory: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .collect(), + MLIL_SYSCALL_SSA => Self::SyscallSsa(SyscallSsa { + output: op.operands[0] as usize, + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + src_memory: op.operands[3], }), - VarSplit(op) => Lifted::VarSplit(op), - SetVarSplit(op) => Lifted::SetVarSplit(LiftedSetVarSplit { - high: op.high, - low: op.low, - src: self.lift_operand(op.src), + MLIL_SYSCALL_UNTYPED_SSA => Self::SyscallUntypedSsa(SyscallUntypedSsa { + output: op.operands[0] as usize, + params: op.operands[1] as usize, + stack: op.operands[2] as usize, }), - VarSplitSsa(op) => Lifted::VarSplitSsa(op), - SetVarSplitSsa(op) => Lifted::SetVarSplitSsa(LiftedSetVarSplitSsa { - high: op.high, - low: op.low, - src: self.lift_operand(op.src), + MLIL_LOAD_STRUCT_SSA => Self::LoadStructSsa(LoadStructSsa { + src: op.operands[0] as usize, + offset: op.operands[1], + src_memory: op.operands[2], }), - - Add(op) => Lifted::Add(self.lift_binary_op(op)), - Sub(op) => Lifted::Sub(self.lift_binary_op(op)), - And(op) => Lifted::And(self.lift_binary_op(op)), - Or(op) => Lifted::Or(self.lift_binary_op(op)), - Xor(op) => Lifted::Xor(self.lift_binary_op(op)), - Lsl(op) => Lifted::Lsl(self.lift_binary_op(op)), - Lsr(op) => Lifted::Lsr(self.lift_binary_op(op)), - Asr(op) => Lifted::Asr(self.lift_binary_op(op)), - Rol(op) => Lifted::Rol(self.lift_binary_op(op)), - Ror(op) => Lifted::Ror(self.lift_binary_op(op)), - Mul(op) => Lifted::Mul(self.lift_binary_op(op)), - MuluDp(op) => Lifted::MuluDp(self.lift_binary_op(op)), - MulsDp(op) => Lifted::MulsDp(self.lift_binary_op(op)), - Divu(op) => Lifted::Divu(self.lift_binary_op(op)), - DivuDp(op) => Lifted::DivuDp(self.lift_binary_op(op)), - Divs(op) => Lifted::Divs(self.lift_binary_op(op)), - DivsDp(op) => Lifted::DivsDp(self.lift_binary_op(op)), - Modu(op) => Lifted::Modu(self.lift_binary_op(op)), - ModuDp(op) => Lifted::ModuDp(self.lift_binary_op(op)), - Mods(op) => Lifted::Mods(self.lift_binary_op(op)), - ModsDp(op) => Lifted::ModsDp(self.lift_binary_op(op)), - CmpE(op) => Lifted::CmpE(self.lift_binary_op(op)), - CmpNe(op) => Lifted::CmpNe(self.lift_binary_op(op)), - CmpSlt(op) => Lifted::CmpSlt(self.lift_binary_op(op)), - CmpUlt(op) => Lifted::CmpUlt(self.lift_binary_op(op)), - CmpSle(op) => Lifted::CmpSle(self.lift_binary_op(op)), - CmpUle(op) => Lifted::CmpUle(self.lift_binary_op(op)), - CmpSge(op) => Lifted::CmpSge(self.lift_binary_op(op)), - CmpUge(op) => Lifted::CmpUge(self.lift_binary_op(op)), - CmpSgt(op) => Lifted::CmpSgt(self.lift_binary_op(op)), - CmpUgt(op) => Lifted::CmpUgt(self.lift_binary_op(op)), - TestBit(op) => Lifted::TestBit(self.lift_binary_op(op)), - AddOverflow(op) => Lifted::AddOverflow(self.lift_binary_op(op)), - FcmpE(op) => Lifted::FcmpE(self.lift_binary_op(op)), - FcmpNe(op) => Lifted::FcmpNe(self.lift_binary_op(op)), - FcmpLt(op) => Lifted::FcmpLt(self.lift_binary_op(op)), - FcmpLe(op) => Lifted::FcmpLe(self.lift_binary_op(op)), - FcmpGe(op) => Lifted::FcmpGe(self.lift_binary_op(op)), - FcmpGt(op) => Lifted::FcmpGt(self.lift_binary_op(op)), - FcmpO(op) => Lifted::FcmpO(self.lift_binary_op(op)), - FcmpUo(op) => Lifted::FcmpUo(self.lift_binary_op(op)), - Fadd(op) => Lifted::Fadd(self.lift_binary_op(op)), - Fsub(op) => Lifted::Fsub(self.lift_binary_op(op)), - Fmul(op) => Lifted::Fmul(self.lift_binary_op(op)), - Fdiv(op) => Lifted::Fdiv(self.lift_binary_op(op)), - - Adc(op) => Lifted::Adc(self.lift_binary_op_carry(op)), - Sbb(op) => Lifted::Sbb(self.lift_binary_op_carry(op)), - Rlc(op) => Lifted::Rlc(self.lift_binary_op_carry(op)), - Rrc(op) => Lifted::Rrc(self.lift_binary_op_carry(op)), - - Call(op) => Lifted::Call(self.lift_call(op)), - 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(), - intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() - .map(|expr| expr.lift()) - .collect(), + MLIL_LOAD_SSA => Self::LoadSsa(LoadSsa { + src: op.operands[0] as usize, + src_memory: op.operands[1], }), - 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() - .map(|expr| expr.lift()) - .collect(), + MLIL_VAR_SSA => Self::VarSsa(VarSsa { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), }), - IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .ssa_vars() - .collect(), - intrinsic: ILIntrinsic::new(self.function.get_function().arch(), op.intrinsic), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() - .map(|expr| expr.lift()) - .collect(), + MLIL_VAR_ALIASED => Self::VarAliased(VarSsa { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), }), - - CallSsa(op) => Lifted::CallSsa(self.lift_call_ssa(op)), - TailcallSsa(op) => Lifted::TailcallSsa(self.lift_call_ssa(op)), - - CallUntypedSsa(op) => Lifted::CallUntypedSsa(self.lift_call_untyped_ssa(op)), - 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() - .map(|expr| expr.lift()) - .collect(), - src_memory: op.src_memory, + MLIL_VAR_SSA_FIELD => Self::VarSsaField(VarSsaField { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), + offset: op.operands[2], }), - 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(), - stack: self.lift_operand(op.stack), + MLIL_VAR_ALIASED_FIELD => Self::VarAliasedField(VarSsaField { + src: get_var_ssa(op.operands[0], op.operands[1] as usize), + offset: op.operands[2], }), + _ => return None, + }) + } +} +impl InstructionTraitFromRaw for MediumLevelILInstructionKindSSA { + fn from_operation(op: BNMediumLevelILInstruction) -> Option { + Self::from_common_operation(op).or_else(|| Self::from_this_operation(op)) + } +} - 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(), - stack: self.lift_operand(op.stack), - }), +impl InstructionTrait for MediumLevelILInstructionKindSSA { + fn name(&self) -> &'static str { + self.into() + } +} - Neg(op) => Lifted::Neg(self.lift_unary_op(op)), - Not(op) => Lifted::Not(self.lift_unary_op(op)), - Sx(op) => Lifted::Sx(self.lift_unary_op(op)), - Zx(op) => Lifted::Zx(self.lift_unary_op(op)), - LowPart(op) => Lifted::LowPart(self.lift_unary_op(op)), - BoolToInt(op) => Lifted::BoolToInt(self.lift_unary_op(op)), - UnimplMem(op) => Lifted::UnimplMem(self.lift_unary_op(op)), - Fsqrt(op) => Lifted::Fsqrt(self.lift_unary_op(op)), - Fneg(op) => Lifted::Fneg(self.lift_unary_op(op)), - Fabs(op) => Lifted::Fabs(self.lift_unary_op(op)), - FloatToInt(op) => Lifted::FloatToInt(self.lift_unary_op(op)), - IntToFloat(op) => Lifted::IntToFloat(self.lift_unary_op(op)), - FloatConv(op) => Lifted::FloatConv(self.lift_unary_op(op)), - RoundToInt(op) => Lifted::RoundToInt(self.lift_unary_op(op)), - Floor(op) => Lifted::Floor(self.lift_unary_op(op)), - Ceil(op) => Lifted::Ceil(self.lift_unary_op(op)), - Ftrunc(op) => Lifted::Ftrunc(self.lift_unary_op(op)), - Load(op) => Lifted::Load(self.lift_unary_op(op)), +impl core::fmt::Debug for MediumLevelILInstruction { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!( + f, + "<{} at 0x{:08}>", + core::any::type_name::(), + self.address, + ) + } +} - LoadStruct(op) => Lifted::LoadStruct(LiftedLoadStruct { - src: self.lift_operand(op.src), - offset: op.offset, - }), - LoadStructSsa(op) => Lifted::LoadStructSsa(LiftedLoadStructSsa { - src: self.lift_operand(op.src), - offset: op.offset, - src_memory: op.src_memory, - }), - LoadSsa(op) => Lifted::LoadSsa(LiftedLoadSsa { - 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() - .map(|expr| expr.lift()) - .collect(), - }), - SeparateParamList(op) => Lifted::SeparateParamList(LiftedSeparateParamList { - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() - .map(|expr| expr.lift()) - .collect(), - }), - SharedParamSlot(op) => Lifted::SharedParamSlot(LiftedSharedParamSlot { - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() - .map(|expr| expr.lift()) - .collect(), - }), - Var(op) => Lifted::Var(op), - AddressOf(op) => Lifted::AddressOf(op), - VarField(op) => Lifted::VarField(op), - AddressOfField(op) => Lifted::AddressOfField(op), - VarSsa(op) => Lifted::VarSsa(op), - VarAliased(op) => Lifted::VarAliased(op), - VarSsaField(op) => Lifted::VarSsaField(op), - VarAliasedField(op) => Lifted::VarAliasedField(op), - Trap(op) => Lifted::Trap(op), - }; +impl MediumLevelILInstruction { + pub(crate) fn new(function: Ref>, index: usize) -> Self { + let op = unsafe { BNGetMediumLevelILByIndex(function.handle, index) }; + let kind = + ::from_operation(op).expect("Invalid Medium Level IL Instruction"); + Self { + function, + address: op.address, + index, + size: op.size, + kind, + } + } + pub fn lift(&self) -> MediumLevelILLiftedInstruction { MediumLevelILLiftedInstruction { function: self.function.clone(), address: self.address, index: self.index, size: self.size, - kind, + kind: ::from_instruction(self), } } - - fn lift_operand(&self, expr_idx: usize) -> Box { - Box::new(self.function.lifted_instruction_from_idx(expr_idx)) + pub fn name(&self) -> &'static str { + self.kind.name() } - - fn lift_binary_op(&self, op: BinaryOp) -> LiftedBinaryOp { - LiftedBinaryOp { - left: self.lift_operand(op.left), - right: self.lift_operand(op.right), - } - } - - fn lift_binary_op_carry(&self, op: BinaryOpCarry) -> LiftedBinaryOpCarry { - LiftedBinaryOpCarry { - left: self.lift_operand(op.left), - right: self.lift_operand(op.right), - carry: self.lift_operand(op.carry), - } + pub(crate) fn lift_operand(&self, expr_idx: usize) -> Box> { + Box::new(self.function.lifted_instruction_from_idx(expr_idx)) } - fn lift_unary_op(&self, op: UnaryOp) -> LiftedUnaryOp { - LiftedUnaryOp { - src: self.lift_operand(op.src), - } + pub(crate) fn get_call_output(&self, idx: usize) -> impl Iterator { + let op = self.get_raw_operation(idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT); + OperandIter::new( + self.function.as_ref(), + op.operands[1] as usize, + op.operands[0] as usize, + ) + .vars() } - fn lift_call(&self, op: Call) -> LiftedCall { - LiftedCall { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .vars() - .collect(), - dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() - .map(|expr| expr.lift()) - .collect(), - } + pub(crate) fn get_call_params( + &self, + idx: usize, + ) -> impl Iterator> { + let op = self.get_raw_operation(idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM); + OperandIter::new( + self.function.as_ref(), + op.operands[1] as usize, + op.operands[0] as usize, + ) + .exprs() } - fn lift_call_untyped(&self, op: CallUntyped) -> LiftedCallUntyped { - LiftedCallUntyped { - output: get_call_output(&self.function, op.output).collect(), - dest: self.lift_operand(op.dest), - params: get_call_params(&self.function, op.params) - .map(|expr| expr.lift()) - .collect(), - stack: self.lift_operand(op.stack), - } + pub(crate) fn get_call_output_ssa(&self, idx: usize) -> impl Iterator { + let op = self.get_raw_operation(idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA); + OperandIter::new( + self.function.as_ref(), + op.operands[2] as usize, + op.operands[1] as usize, + ) + .ssa_vars() } - fn lift_call_ssa(&self, op: CallSsa) -> LiftedCallSsa { - LiftedCallSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), - dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() - .map(|expr| expr.lift()) - .collect(), - src_memory: op.src_memory, - } + pub(crate) fn get_call_params_ssa( + &self, + idx: usize, + ) -> impl Iterator> { + let op = self.get_raw_operation(idx); + assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA); + OperandIter::new( + self.function.as_ref(), + op.operands[2] as usize, + op.operands[1] as usize, + ) + .exprs() } - fn lift_call_untyped_ssa(&self, op: CallUntypedSsa) -> LiftedCallUntypedSsa { - LiftedCallUntypedSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), - dest: self.lift_operand(op.dest), - params: get_call_params_ssa(&self.function, op.params) - .map(|param| param.lift()) - .collect(), - stack: self.lift_operand(op.stack), - } + pub(crate) fn get_raw_operation(&self, idx: usize) -> BNMediumLevelILInstruction { + unsafe { BNGetMediumLevelILByIndex(self.function.handle, idx) } } } -fn get_float(value: u64, size: usize) -> f64 { +pub(crate) fn get_float(value: u64, size: usize) -> f64 { match size { 4 => f32::from_bits(value as u32) as f64, 8 => f64::from_bits(value), @@ -1116,47 +952,10 @@ 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 { +pub(crate) fn get_var(id: u64) -> Variable { unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) } } -fn get_var_ssa(id: u64, version: usize) -> SSAVariable { +pub(crate) 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 { - 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_params( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator { - 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_output_ssa( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator { - 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_params_ssa( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator { - 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() -} diff --git a/rust/src/mlil/lift.rs b/rust/src/mlil/lift.rs index e8548b064..b3b60323c 100644 --- a/rust/src/mlil/lift.rs +++ b/rust/src/mlil/lift.rs @@ -1,17 +1,26 @@ use std::collections::BTreeMap; +use crate::mlil::MediumLevelILInstructionKindSSA; +use crate::operand_iter::OperandIter; use crate::rc::Ref; -use crate::types::{ConstantData, ILIntrinsic, SSAVariable, Variable}; +use crate::types::{ + ConstantData, ILIntrinsic, RegisterValue, RegisterValueType, SSAVariable, Variable, +}; use super::operation::*; -use super::MediumLevelILFunction; +use super::{ + Form, InstructionLiftedTrait, MediumLevelILFunction, MediumLevelILInstruction, + MediumLevelILInstructionKindNonSSA, NonSSA, Sealed, SSA, +}; -#[derive(Clone)] -pub enum MediumLevelILLiftedOperand { +use strum::IntoStaticStr; + +#[derive(Clone, Debug, IntoStaticStr)] +pub enum MediumLevelILLiftedOperand { ConstantData(ConstantData), Intrinsic(ILIntrinsic), - Expr(MediumLevelILLiftedInstruction), - ExprList(Vec), + Expr(MediumLevelILLiftedInstruction), + ExprList(Vec>), Float(f64), Int(u64), IntList(Vec), @@ -22,320 +31,367 @@ pub enum MediumLevelILLiftedOperand { VarSsaList(Vec), } -#[derive(Clone, Debug, PartialEq)] -pub struct MediumLevelILLiftedInstruction { - pub function: Ref, +#[derive(Clone, Debug)] +pub struct MediumLevelILLiftedInstruction { + pub function: Ref>, pub address: u64, pub index: usize, pub size: usize, - pub kind: MediumLevelILLiftedInstructionKind, + pub kind: I::InstructionLifted, +} + +macro_rules! construct_common { + ($form:ident, $instruction:ident, $lifted:ident) => { + fn common_operands( + &self, + ) -> Option)>> { + use MediumLevelILLiftedOperand as Operand; + Some(match self { + Self::Nop | Self::Noret | Self::Bp | Self::Undef | Self::Unimpl => vec![], + Self::If(op) => vec![ + ("condition", Operand::Expr(*op.condition.clone())), + ("dest_true", Operand::Int(op.dest_true)), + ("dest_false", Operand::Int(op.dest_false)), + ], + Self::FloatConst(op) => vec![("constant", Operand::Float(op.constant))], + Self::Const(op) | Self::ConstPtr(op) | Self::Import(op) => { + vec![("constant", Operand::Int(op.constant))] + } + Self::ExternPtr(op) => vec![ + ("constant", Operand::Int(op.constant)), + ("offset", Operand::Int(op.offset)), + ], + Self::ConstData(op) => vec![( + "constant_data", + Operand::ConstantData(op.constant_data.clone()), + )], + Self::Jump(op) | Self::RetHint(op) => { + vec![("dest", Operand::Expr(*op.dest.clone()))] + } + Self::JumpTo(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("targets", Operand::TargetMap(op.targets.clone())), + ], + Self::Goto(op) => vec![("dest", Operand::Int(op.dest))], + Self::MemPhi(op) => vec![ + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::IntList(op.src_memory.clone())), + ], + Self::Add(op) + | Self::Sub(op) + | Self::And(op) + | Self::Or(op) + | Self::Xor(op) + | Self::Lsl(op) + | Self::Lsr(op) + | Self::Asr(op) + | Self::Rol(op) + | Self::Ror(op) + | Self::Mul(op) + | Self::MuluDp(op) + | Self::MulsDp(op) + | Self::Divu(op) + | Self::DivuDp(op) + | Self::Divs(op) + | Self::DivsDp(op) + | Self::Modu(op) + | Self::ModuDp(op) + | Self::Mods(op) + | Self::ModsDp(op) + | Self::CmpE(op) + | Self::CmpNe(op) + | Self::CmpSlt(op) + | Self::CmpUlt(op) + | Self::CmpSle(op) + | Self::CmpUle(op) + | Self::CmpSge(op) + | Self::CmpUge(op) + | Self::CmpSgt(op) + | Self::CmpUgt(op) + | Self::TestBit(op) + | Self::AddOverflow(op) + | Self::FcmpE(op) + | Self::FcmpNe(op) + | Self::FcmpLt(op) + | Self::FcmpLe(op) + | Self::FcmpGe(op) + | Self::FcmpGt(op) + | Self::FcmpO(op) + | Self::FcmpUo(op) + | Self::Fadd(op) + | Self::Fsub(op) + | Self::Fmul(op) + | Self::Fdiv(op) => vec![ + ("left", Operand::Expr(*op.left.clone())), + ("right", Operand::Expr(*op.right.clone())), + ], + Self::Adc(op) | Self::Sbb(op) | Self::Rlc(op) | Self::Rrc(op) => vec![ + ("left", Operand::Expr(*op.left.clone())), + ("right", Operand::Expr(*op.right.clone())), + ("carry", Operand::Expr(*op.carry.clone())), + ], + Self::Neg(op) + | Self::Not(op) + | Self::Sx(op) + | Self::Zx(op) + | Self::LowPart(op) + | Self::BoolToInt(op) + | Self::UnimplMem(op) + | Self::Fsqrt(op) + | Self::Fneg(op) + | Self::Fabs(op) + | Self::FloatToInt(op) + | Self::IntToFloat(op) + | Self::FloatConv(op) + | Self::RoundToInt(op) + | Self::Floor(op) + | Self::Ceil(op) + | Self::Ftrunc(op) => { + vec![("src", Operand::Expr(*op.src.clone()))] + } + Self::Ret(op) => vec![("src", Operand::ExprList(op.src.clone()))], + Self::SeparateParamList(op) => { + vec![("params", Operand::ExprList(op.params.clone()))] + } + Self::SharedParamSlot(op) => vec![("params", Operand::ExprList(op.params.clone()))], + Self::AddressOf(op) => vec![("src", Operand::Var(op.src))], + Self::AddressOfField(op) => vec![ + ("src", Operand::Var(op.src)), + ("offset", Operand::Int(op.offset)), + ], + Self::Trap(op) => vec![("vector", Operand::Int(op.vector))], + + _ => return None, + }) + } + + fn common_from_instruction(inst: &MediumLevelILInstruction<$form>) -> Option { + use $instruction as UnLifted; + use $lifted as Lifted; + Some(match &inst.kind { + UnLifted::Nop => Lifted::Nop, + UnLifted::Noret => Lifted::Noret, + UnLifted::Bp => Lifted::Bp, + UnLifted::Undef => Lifted::Undef, + UnLifted::Unimpl => Lifted::Unimpl, + UnLifted::If(op) => Lifted::If(op.lift(inst)), + UnLifted::FloatConst(op) => Lifted::FloatConst(*op), + UnLifted::Const(op) => Lifted::Const(*op), + UnLifted::ConstPtr(op) => Lifted::ConstPtr(*op), + UnLifted::Import(op) => Lifted::Import(*op), + UnLifted::ExternPtr(op) => Lifted::ExternPtr(*op), + UnLifted::ConstData(op) => Lifted::ConstData(op.lift(inst)), + UnLifted::Jump(op) => Lifted::Jump(op.lift(inst)), + UnLifted::RetHint(op) => Lifted::RetHint(op.lift(inst)), + UnLifted::JumpTo(op) => Lifted::JumpTo(op.lift(inst)), + UnLifted::Goto(op) => Lifted::Goto(*op), + UnLifted::Add(op) => Lifted::Add(op.lift(inst)), + UnLifted::Sub(op) => Lifted::Sub(op.lift(inst)), + UnLifted::And(op) => Lifted::And(op.lift(inst)), + UnLifted::Or(op) => Lifted::Or(op.lift(inst)), + UnLifted::Xor(op) => Lifted::Xor(op.lift(inst)), + UnLifted::Lsl(op) => Lifted::Lsl(op.lift(inst)), + UnLifted::Lsr(op) => Lifted::Lsr(op.lift(inst)), + UnLifted::Asr(op) => Lifted::Asr(op.lift(inst)), + UnLifted::Rol(op) => Lifted::Rol(op.lift(inst)), + UnLifted::Ror(op) => Lifted::Ror(op.lift(inst)), + UnLifted::Mul(op) => Lifted::Mul(op.lift(inst)), + UnLifted::MuluDp(op) => Lifted::MuluDp(op.lift(inst)), + UnLifted::MulsDp(op) => Lifted::MulsDp(op.lift(inst)), + UnLifted::Divu(op) => Lifted::Divu(op.lift(inst)), + UnLifted::DivuDp(op) => Lifted::DivuDp(op.lift(inst)), + UnLifted::Divs(op) => Lifted::Divs(op.lift(inst)), + UnLifted::DivsDp(op) => Lifted::DivsDp(op.lift(inst)), + UnLifted::Modu(op) => Lifted::Modu(op.lift(inst)), + UnLifted::ModuDp(op) => Lifted::ModuDp(op.lift(inst)), + UnLifted::Mods(op) => Lifted::Mods(op.lift(inst)), + UnLifted::ModsDp(op) => Lifted::ModsDp(op.lift(inst)), + UnLifted::CmpE(op) => Lifted::CmpE(op.lift(inst)), + UnLifted::CmpNe(op) => Lifted::CmpNe(op.lift(inst)), + UnLifted::CmpSlt(op) => Lifted::CmpSlt(op.lift(inst)), + UnLifted::CmpUlt(op) => Lifted::CmpUlt(op.lift(inst)), + UnLifted::CmpSle(op) => Lifted::CmpSle(op.lift(inst)), + UnLifted::CmpUle(op) => Lifted::CmpUle(op.lift(inst)), + UnLifted::CmpSge(op) => Lifted::CmpSge(op.lift(inst)), + UnLifted::CmpUge(op) => Lifted::CmpUge(op.lift(inst)), + UnLifted::CmpSgt(op) => Lifted::CmpSgt(op.lift(inst)), + UnLifted::CmpUgt(op) => Lifted::CmpUgt(op.lift(inst)), + UnLifted::TestBit(op) => Lifted::TestBit(op.lift(inst)), + UnLifted::AddOverflow(op) => Lifted::AddOverflow(op.lift(inst)), + UnLifted::FcmpE(op) => Lifted::FcmpE(op.lift(inst)), + UnLifted::FcmpNe(op) => Lifted::FcmpNe(op.lift(inst)), + UnLifted::FcmpLt(op) => Lifted::FcmpLt(op.lift(inst)), + UnLifted::FcmpLe(op) => Lifted::FcmpLe(op.lift(inst)), + UnLifted::FcmpGe(op) => Lifted::FcmpGe(op.lift(inst)), + UnLifted::FcmpGt(op) => Lifted::FcmpGt(op.lift(inst)), + UnLifted::FcmpO(op) => Lifted::FcmpO(op.lift(inst)), + UnLifted::FcmpUo(op) => Lifted::FcmpUo(op.lift(inst)), + UnLifted::Fadd(op) => Lifted::Fadd(op.lift(inst)), + UnLifted::Fsub(op) => Lifted::Fsub(op.lift(inst)), + UnLifted::Fmul(op) => Lifted::Fmul(op.lift(inst)), + UnLifted::Fdiv(op) => Lifted::Fdiv(op.lift(inst)), + UnLifted::Adc(op) => Lifted::Adc(op.lift(inst)), + UnLifted::Sbb(op) => Lifted::Sbb(op.lift(inst)), + UnLifted::Rlc(op) => Lifted::Rlc(op.lift(inst)), + UnLifted::Rrc(op) => Lifted::Rrc(op.lift(inst)), + UnLifted::Neg(op) => Lifted::Neg(op.lift(inst)), + UnLifted::Not(op) => Lifted::Not(op.lift(inst)), + UnLifted::Sx(op) => Lifted::Sx(op.lift(inst)), + UnLifted::Zx(op) => Lifted::Zx(op.lift(inst)), + UnLifted::LowPart(op) => Lifted::LowPart(op.lift(inst)), + UnLifted::BoolToInt(op) => Lifted::BoolToInt(op.lift(inst)), + UnLifted::UnimplMem(op) => Lifted::UnimplMem(op.lift(inst)), + UnLifted::Fsqrt(op) => Lifted::Fsqrt(op.lift(inst)), + UnLifted::Fneg(op) => Lifted::Fneg(op.lift(inst)), + UnLifted::Fabs(op) => Lifted::Fabs(op.lift(inst)), + UnLifted::FloatToInt(op) => Lifted::FloatToInt(op.lift(inst)), + UnLifted::IntToFloat(op) => Lifted::IntToFloat(op.lift(inst)), + UnLifted::FloatConv(op) => Lifted::FloatConv(op.lift(inst)), + UnLifted::RoundToInt(op) => Lifted::RoundToInt(op.lift(inst)), + UnLifted::Floor(op) => Lifted::Floor(op.lift(inst)), + UnLifted::Ceil(op) => Lifted::Ceil(op.lift(inst)), + UnLifted::Ftrunc(op) => Lifted::Ftrunc(op.lift(inst)), + UnLifted::Ret(op) => Lifted::Ret(op.lift(inst)), + + UnLifted::MemPhi(op) => Lifted::MemPhi(op.lift(inst)), + UnLifted::SeparateParamList(op) => Lifted::SeparateParamList(op.lift(inst)), + UnLifted::SharedParamSlot(op) => Lifted::SharedParamSlot(op.lift(inst)), + + UnLifted::AddressOf(op) => Lifted::AddressOf(*op), + UnLifted::AddressOfField(op) => Lifted::AddressOfField(*op), + UnLifted::Trap(op) => Lifted::Trap(*op), + + _ => return None, + }) + } + }; } -#[derive(Clone, Debug, PartialEq)] -pub enum MediumLevelILLiftedInstructionKind { +#[derive(Clone, Debug, IntoStaticStr)] +pub enum MediumLevelILLiftedInstructionKindNonSSA { Nop, Noret, Bp, Undef, Unimpl, - If(LiftedIf), + If(LiftedIf), FloatConst(FloatConst), Const(Constant), ConstPtr(Constant), Import(Constant), ExternPtr(ExternPtr), ConstData(LiftedConstData), - Jump(LiftedJump), - RetHint(LiftedJump), - StoreSsa(LiftedStoreSsa), - StoreStructSsa(LiftedStoreStructSsa), - StoreStruct(LiftedStoreStruct), - Store(LiftedStore), - JumpTo(LiftedJumpTo), + Jump(LiftedJump), + RetHint(LiftedJump), + JumpTo(LiftedJumpTo), Goto(Goto), - FreeVarSlot(FreeVarSlot), - SetVarField(LiftedSetVarField), - SetVar(LiftedSetVar), - FreeVarSlotSsa(FreeVarSlotSsa), - SetVarSsaField(LiftedSetVarSsaField), - SetVarAliasedField(LiftedSetVarSsaField), - SetVarAliased(LiftedSetVarAliased), - SetVarSsa(LiftedSetVarSsa), - VarPhi(LiftedVarPhi), + Add(LiftedBinaryOp), + Sub(LiftedBinaryOp), + And(LiftedBinaryOp), + Or(LiftedBinaryOp), + Xor(LiftedBinaryOp), + Lsl(LiftedBinaryOp), + Lsr(LiftedBinaryOp), + Asr(LiftedBinaryOp), + Rol(LiftedBinaryOp), + Ror(LiftedBinaryOp), + Mul(LiftedBinaryOp), + MuluDp(LiftedBinaryOp), + MulsDp(LiftedBinaryOp), + Divu(LiftedBinaryOp), + DivuDp(LiftedBinaryOp), + Divs(LiftedBinaryOp), + DivsDp(LiftedBinaryOp), + Modu(LiftedBinaryOp), + ModuDp(LiftedBinaryOp), + Mods(LiftedBinaryOp), + ModsDp(LiftedBinaryOp), + CmpE(LiftedBinaryOp), + CmpNe(LiftedBinaryOp), + CmpSlt(LiftedBinaryOp), + CmpUlt(LiftedBinaryOp), + CmpSle(LiftedBinaryOp), + CmpUle(LiftedBinaryOp), + CmpSge(LiftedBinaryOp), + CmpUge(LiftedBinaryOp), + CmpSgt(LiftedBinaryOp), + CmpUgt(LiftedBinaryOp), + TestBit(LiftedBinaryOp), + AddOverflow(LiftedBinaryOp), + FcmpE(LiftedBinaryOp), + FcmpNe(LiftedBinaryOp), + FcmpLt(LiftedBinaryOp), + FcmpLe(LiftedBinaryOp), + FcmpGe(LiftedBinaryOp), + FcmpGt(LiftedBinaryOp), + FcmpO(LiftedBinaryOp), + FcmpUo(LiftedBinaryOp), + Fadd(LiftedBinaryOp), + Fsub(LiftedBinaryOp), + Fmul(LiftedBinaryOp), + Fdiv(LiftedBinaryOp), + Adc(LiftedBinaryOpCarry), + Sbb(LiftedBinaryOpCarry), + Rlc(LiftedBinaryOpCarry), + Rrc(LiftedBinaryOpCarry), + Neg(LiftedUnaryOp), + Not(LiftedUnaryOp), + Sx(LiftedUnaryOp), + Zx(LiftedUnaryOp), + LowPart(LiftedUnaryOp), + BoolToInt(LiftedUnaryOp), + UnimplMem(LiftedUnaryOp), + Fsqrt(LiftedUnaryOp), + Fneg(LiftedUnaryOp), + Fabs(LiftedUnaryOp), + FloatToInt(LiftedUnaryOp), + IntToFloat(LiftedUnaryOp), + FloatConv(LiftedUnaryOp), + RoundToInt(LiftedUnaryOp), + Floor(LiftedUnaryOp), + Ceil(LiftedUnaryOp), + Ftrunc(LiftedUnaryOp), + Ret(LiftedRet), + MemPhi(LiftedMemPhi), + SeparateParamList(LiftedSeparateParamList), + SharedParamSlot(LiftedSharedParamSlot), + + AddressOf(Var), + AddressOfField(Field), + Trap(Trap), + + Var(Var), + VarField(Field), + Store(LiftedStore), + StoreStruct(LiftedStoreStruct), + SetVar(LiftedSetVar), + SetVarField(LiftedSetVarField), + FreeVarSlot(FreeVarSlot), VarSplit(VarSplit), SetVarSplit(LiftedSetVarSplit), - VarSplitSsa(VarSplitSsa), - SetVarSplitSsa(LiftedSetVarSplitSsa), - Add(LiftedBinaryOp), - Sub(LiftedBinaryOp), - And(LiftedBinaryOp), - Or(LiftedBinaryOp), - Xor(LiftedBinaryOp), - Lsl(LiftedBinaryOp), - Lsr(LiftedBinaryOp), - Asr(LiftedBinaryOp), - Rol(LiftedBinaryOp), - Ror(LiftedBinaryOp), - Mul(LiftedBinaryOp), - MuluDp(LiftedBinaryOp), - MulsDp(LiftedBinaryOp), - Divu(LiftedBinaryOp), - DivuDp(LiftedBinaryOp), - Divs(LiftedBinaryOp), - DivsDp(LiftedBinaryOp), - Modu(LiftedBinaryOp), - ModuDp(LiftedBinaryOp), - Mods(LiftedBinaryOp), - ModsDp(LiftedBinaryOp), - CmpE(LiftedBinaryOp), - CmpNe(LiftedBinaryOp), - CmpSlt(LiftedBinaryOp), - CmpUlt(LiftedBinaryOp), - CmpSle(LiftedBinaryOp), - CmpUle(LiftedBinaryOp), - CmpSge(LiftedBinaryOp), - CmpUge(LiftedBinaryOp), - CmpSgt(LiftedBinaryOp), - CmpUgt(LiftedBinaryOp), - TestBit(LiftedBinaryOp), - AddOverflow(LiftedBinaryOp), - FcmpE(LiftedBinaryOp), - FcmpNe(LiftedBinaryOp), - FcmpLt(LiftedBinaryOp), - FcmpLe(LiftedBinaryOp), - FcmpGe(LiftedBinaryOp), - FcmpGt(LiftedBinaryOp), - FcmpO(LiftedBinaryOp), - FcmpUo(LiftedBinaryOp), - Fadd(LiftedBinaryOp), - Fsub(LiftedBinaryOp), - Fmul(LiftedBinaryOp), - Fdiv(LiftedBinaryOp), - Adc(LiftedBinaryOpCarry), - Sbb(LiftedBinaryOpCarry), - Rlc(LiftedBinaryOpCarry), - Rrc(LiftedBinaryOpCarry), Call(LiftedCall), + CallUntyped(LiftedCallUntyped), Tailcall(LiftedCall), + Syscall(LiftedSyscall), + SyscallUntyped(LiftedSyscallUntyped), Intrinsic(LiftedIntrinsic), - Syscall(LiftedSyscallCall), - IntrinsicSsa(LiftedIntrinsicSsa), - CallSsa(LiftedCallSsa), - TailcallSsa(LiftedCallSsa), - CallUntypedSsa(LiftedCallUntypedSsa), - TailcallUntypedSsa(LiftedCallUntypedSsa), - SyscallSsa(LiftedSyscallSsa), - SyscallUntypedSsa(LiftedSyscallUntypedSsa), - CallUntyped(LiftedCallUntyped), TailcallUntyped(LiftedCallUntyped), - SyscallUntyped(LiftedSyscallUntyped), - SeparateParamList(LiftedSeparateParamList), - SharedParamSlot(LiftedSharedParamSlot), - Neg(LiftedUnaryOp), - Not(LiftedUnaryOp), - Sx(LiftedUnaryOp), - Zx(LiftedUnaryOp), - LowPart(LiftedUnaryOp), - BoolToInt(LiftedUnaryOp), - UnimplMem(LiftedUnaryOp), - Fsqrt(LiftedUnaryOp), - Fneg(LiftedUnaryOp), - Fabs(LiftedUnaryOp), - FloatToInt(LiftedUnaryOp), - IntToFloat(LiftedUnaryOp), - FloatConv(LiftedUnaryOp), - RoundToInt(LiftedUnaryOp), - Floor(LiftedUnaryOp), - Ceil(LiftedUnaryOp), - Ftrunc(LiftedUnaryOp), - Load(LiftedUnaryOp), + Load(LiftedUnaryOp), LoadStruct(LiftedLoadStruct), - LoadStructSsa(LiftedLoadStructSsa), - LoadSsa(LiftedLoadSsa), - Ret(LiftedRet), - Var(Var), - AddressOf(Var), - VarField(Field), - AddressOfField(Field), - VarSsa(VarSsa), - VarAliased(VarSsa), - VarSsaField(VarSsaField), - VarAliasedField(VarSsaField), - Trap(Trap), } -impl MediumLevelILLiftedInstruction { - pub fn name(&self) -> &'static str { - use MediumLevelILLiftedInstructionKind::*; - match self.kind { - Nop => "Nop", - Noret => "Noret", - Bp => "Bp", - Undef => "Undef", - Unimpl => "Unimpl", - If(_) => "If", - FloatConst(_) => "FloatConst", - Const(_) => "Const", - ConstPtr(_) => "ConstPtr", - Import(_) => "Import", - ExternPtr(_) => "ExternPtr", - ConstData(_) => "ConstData", - Jump(_) => "Jump", - RetHint(_) => "RetHint", - StoreSsa(_) => "StoreSsa", - StoreStructSsa(_) => "StoreStructSsa", - StoreStruct(_) => "StoreStruct", - Store(_) => "Store", - JumpTo(_) => "JumpTo", - Goto(_) => "Goto", - FreeVarSlot(_) => "FreeVarSlot", - SetVarField(_) => "SetVarField", - SetVar(_) => "SetVar", - FreeVarSlotSsa(_) => "FreeVarSlotSsa", - SetVarSsaField(_) => "SetVarSsaField", - SetVarAliasedField(_) => "SetVarAliasedField", - SetVarAliased(_) => "SetVarAliased", - SetVarSsa(_) => "SetVarSsa", - VarPhi(_) => "VarPhi", - MemPhi(_) => "MemPhi", - VarSplit(_) => "VarSplit", - SetVarSplit(_) => "SetVarSplit", - VarSplitSsa(_) => "VarSplitSsa", - SetVarSplitSsa(_) => "SetVarSplitSsa", - Add(_) => "Add", - Sub(_) => "Sub", - And(_) => "And", - Or(_) => "Or", - Xor(_) => "Xor", - Lsl(_) => "Lsl", - Lsr(_) => "Lsr", - Asr(_) => "Asr", - Rol(_) => "Rol", - Ror(_) => "Ror", - Mul(_) => "Mul", - MuluDp(_) => "MuluDp", - MulsDp(_) => "MulsDp", - Divu(_) => "Divu", - DivuDp(_) => "DivuDp", - Divs(_) => "Divs", - DivsDp(_) => "DivsDp", - Modu(_) => "Modu", - ModuDp(_) => "ModuDp", - Mods(_) => "Mods", - ModsDp(_) => "ModsDp", - CmpE(_) => "CmpE", - CmpNe(_) => "CmpNe", - CmpSlt(_) => "CmpSlt", - CmpUlt(_) => "CmpUlt", - CmpSle(_) => "CmpSle", - CmpUle(_) => "CmpUle", - CmpSge(_) => "CmpSge", - CmpUge(_) => "CmpUge", - CmpSgt(_) => "CmpSgt", - CmpUgt(_) => "CmpUgt", - TestBit(_) => "TestBit", - AddOverflow(_) => "AddOverflow", - FcmpE(_) => "FcmpE", - FcmpNe(_) => "FcmpNe", - FcmpLt(_) => "FcmpLt", - FcmpLe(_) => "FcmpLe", - FcmpGe(_) => "FcmpGe", - FcmpGt(_) => "FcmpGt", - FcmpO(_) => "FcmpO", - FcmpUo(_) => "FcmpUo", - Fadd(_) => "Fadd", - Fsub(_) => "Fsub", - Fmul(_) => "Fmul", - Fdiv(_) => "Fdiv", - Adc(_) => "Adc", - Sbb(_) => "Sbb", - Rlc(_) => "Rlc", - Rrc(_) => "Rrc", - Call(_) => "Call", - Tailcall(_) => "Tailcall", - Syscall(_) => "Syscall", - Intrinsic(_) => "Intrinsic", - IntrinsicSsa(_) => "IntrinsicSsa", - CallSsa(_) => "CallSsa", - TailcallSsa(_) => "TailcallSsa", - CallUntypedSsa(_) => "CallUntypedSsa", - TailcallUntypedSsa(_) => "TailcallUntypedSsa", - SyscallSsa(_) => "SyscallSsa", - SyscallUntypedSsa(_) => "SyscallUntypedSsa", - CallUntyped(_) => "CallUntyped", - TailcallUntyped(_) => "TailcallUntyped", - SyscallUntyped(_) => "SyscallUntyped", - SeparateParamList(_) => "SeparateParamList", - SharedParamSlot(_) => "SharedParamSlot", - Neg(_) => "Neg", - Not(_) => "Not", - Sx(_) => "Sx", - Zx(_) => "Zx", - LowPart(_) => "LowPart", - BoolToInt(_) => "BoolToInt", - UnimplMem(_) => "UnimplMem", - Fsqrt(_) => "Fsqrt", - Fneg(_) => "Fneg", - Fabs(_) => "Fabs", - FloatToInt(_) => "FloatToInt", - IntToFloat(_) => "IntToFloat", - FloatConv(_) => "FloatConv", - RoundToInt(_) => "RoundToInt", - Floor(_) => "Floor", - Ceil(_) => "Ceil", - Ftrunc(_) => "Ftrunc", - Load(_) => "Load", - LoadStruct(_) => "LoadStruct", - LoadStructSsa(_) => "LoadStructSsa", - LoadSsa(_) => "LoadSsa", - Ret(_) => "Ret", - Var(_) => "Var", - AddressOf(_) => "AddressOf", - VarField(_) => "VarField", - AddressOfField(_) => "AddressOfField", - VarSsa(_) => "VarSsa", - VarAliased(_) => "VarAliased", - VarSsaField(_) => "VarSsaField", - VarAliasedField(_) => "VarAliasedField", - Trap(_) => "Trap", - } - } - - pub fn operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)> { - use MediumLevelILLiftedInstructionKind::*; +impl Sealed for MediumLevelILLiftedInstructionKindNonSSA {} +impl MediumLevelILLiftedInstructionKindNonSSA { + construct_common!( + NonSSA, + MediumLevelILInstructionKindNonSSA, + MediumLevelILLiftedInstructionKindNonSSA + ); + fn this_operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)> { + use MediumLevelILLiftedInstructionKindNonSSA::*; use MediumLevelILLiftedOperand as Operand; - match &self.kind { - Nop | Noret | Bp | Undef | Unimpl => vec![], - If(op) => vec![ - ("condition", Operand::Expr(*op.condition.clone())), - ("dest_true", Operand::Int(op.dest_true)), - ("dest_false", Operand::Int(op.dest_false)), - ], - FloatConst(op) => vec![("constant", Operand::Float(op.constant))], - Const(op) | ConstPtr(op) | Import(op) => vec![("constant", Operand::Int(op.constant))], - ExternPtr(op) => vec![ - ("constant", Operand::Int(op.constant)), - ("offset", Operand::Int(op.offset)), - ], - ConstData(op) => vec![( - "constant_data", - Operand::ConstantData(op.constant_data.clone()), - )], - Jump(op) | RetHint(op) => vec![("dest", Operand::Expr(*op.dest.clone()))], - StoreSsa(op) => vec![ - ("dest", Operand::Expr(*op.dest.clone())), - ("dest_memory", Operand::Int(op.dest_memory)), - ("src_memory", Operand::Int(op.src_memory)), - ("src", Operand::Expr(*op.src.clone())), - ], - StoreStructSsa(op) => vec![ - ("dest", Operand::Expr(*op.dest.clone())), - ("offset", Operand::Int(op.offset)), - ("dest_memory", Operand::Int(op.dest_memory)), - ("src_memory", Operand::Int(op.src_memory)), - ("src", Operand::Expr(*op.src.clone())), - ], + match self { StoreStruct(op) => vec![ ("dest", Operand::Expr(*op.dest.clone())), ("offset", Operand::Int(op.offset)), @@ -345,11 +401,6 @@ impl MediumLevelILLiftedInstruction { ("dest", Operand::Expr(*op.dest.clone())), ("src", Operand::Expr(*op.src.clone())), ], - JumpTo(op) => vec![ - ("dest", Operand::Expr(*op.dest.clone())), - ("targets", Operand::TargetMap(op.targets.clone())), - ], - Goto(op) => vec![("dest", Operand::Int(op.dest))], FreeVarSlot(op) => vec![("dest", Operand::Var(op.dest))], SetVarField(op) => vec![ ("dest", Operand::Var(op.dest)), @@ -360,6 +411,239 @@ impl MediumLevelILLiftedInstruction { ("dest", Operand::Var(op.dest)), ("src", Operand::Expr(*op.src.clone())), ], + VarSplit(op) => vec![ + ("high", Operand::Var(op.high)), + ("low", Operand::Var(op.low)), + ], + SetVarSplit(op) => vec![ + ("high", Operand::Var(op.high)), + ("low", Operand::Var(op.low)), + ("src", Operand::Expr(*op.src.clone())), + ], + Call(op) | Tailcall(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ], + Syscall(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("params", Operand::ExprList(op.params.clone())), + ], + Intrinsic(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("intrinsic", Operand::Intrinsic(op.intrinsic)), + ("params", Operand::ExprList(op.params.clone())), + ], + CallUntyped(op) | TailcallUntyped(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("dest", Operand::Expr(*op.dest.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("stack", Operand::Expr(*op.stack.clone())), + ], + SyscallUntyped(op) => vec![ + ("output", Operand::VarList(op.output.clone())), + ("params", Operand::ExprList(op.params.clone())), + ("stack", Operand::Expr(*op.stack.clone())), + ], + Load(op) => vec![("src", Operand::Expr(*op.src.clone()))], + LoadStruct(op) => vec![ + ("src", Operand::Expr(*op.src.clone())), + ("offset", Operand::Int(op.offset)), + ], + Var(op) => vec![("src", Operand::Var(op.src))], + VarField(op) => vec![ + ("src", Operand::Var(op.src)), + ("offset", Operand::Int(op.offset)), + ], + _ => unreachable!(), + } + } + fn this_from_instruction(inst: &MediumLevelILInstruction) -> Self { + use MediumLevelILInstructionKindNonSSA::*; + use MediumLevelILLiftedInstructionKindNonSSA as Lifted; + match &inst.kind { + Var(op) => Lifted::Var(*op), + VarField(op) => Lifted::VarField(*op), + Store(op) => Lifted::Store(op.lift(inst)), + StoreStruct(op) => Lifted::StoreStruct(op.lift(inst)), + SetVar(op) => Lifted::SetVar(op.lift(inst)), + SetVarField(op) => Lifted::SetVarField(op.lift(inst)), + FreeVarSlot(op) => Lifted::FreeVarSlot(*op), + VarSplit(op) => Lifted::VarSplit(*op), + SetVarSplit(op) => Lifted::SetVarSplit(op.lift(inst)), + Call(op) => Lifted::Call(op.lift(inst)), + CallUntyped(op) => Lifted::CallUntyped(op.lift(inst)), + Tailcall(op) => Lifted::Tailcall(op.lift(inst)), + Syscall(op) => Lifted::Syscall(op.lift(inst)), + SyscallUntyped(op) => Lifted::SyscallUntyped(op.lift(inst)), + Intrinsic(op) => Lifted::Intrinsic(op.lift(inst)), + TailcallUntyped(op) => Lifted::TailcallUntyped(op.lift(inst)), + Load(op) => Lifted::Load(op.lift(inst)), + LoadStruct(op) => Lifted::LoadStruct(op.lift(inst)), + _ => unreachable!(), + } + } +} + +impl InstructionLiftedTrait for MediumLevelILLiftedInstructionKindNonSSA { + fn name(&self) -> &'static str { + self.into() + } + + fn from_instruction(inst: &MediumLevelILInstruction) -> Self { + Self::common_from_instruction(inst).unwrap_or_else(|| Self::this_from_instruction(inst)) + } + + fn operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)> { + self.common_operands() + .unwrap_or_else(|| self.this_operands()) + } +} + +#[derive(Clone, Debug, IntoStaticStr)] +pub enum MediumLevelILLiftedInstructionKindSSA { + Nop, + Noret, + Bp, + Undef, + Unimpl, + If(LiftedIf), + FloatConst(FloatConst), + Const(Constant), + ConstPtr(Constant), + Import(Constant), + ExternPtr(ExternPtr), + ConstData(LiftedConstData), + Jump(LiftedJump), + RetHint(LiftedJump), + JumpTo(LiftedJumpTo), + Goto(Goto), + Add(LiftedBinaryOp), + Sub(LiftedBinaryOp), + And(LiftedBinaryOp), + Or(LiftedBinaryOp), + Xor(LiftedBinaryOp), + Lsl(LiftedBinaryOp), + Lsr(LiftedBinaryOp), + Asr(LiftedBinaryOp), + Rol(LiftedBinaryOp), + Ror(LiftedBinaryOp), + Mul(LiftedBinaryOp), + MuluDp(LiftedBinaryOp), + MulsDp(LiftedBinaryOp), + Divu(LiftedBinaryOp), + DivuDp(LiftedBinaryOp), + Divs(LiftedBinaryOp), + DivsDp(LiftedBinaryOp), + Modu(LiftedBinaryOp), + ModuDp(LiftedBinaryOp), + Mods(LiftedBinaryOp), + ModsDp(LiftedBinaryOp), + CmpE(LiftedBinaryOp), + CmpNe(LiftedBinaryOp), + CmpSlt(LiftedBinaryOp), + CmpUlt(LiftedBinaryOp), + CmpSle(LiftedBinaryOp), + CmpUle(LiftedBinaryOp), + CmpSge(LiftedBinaryOp), + CmpUge(LiftedBinaryOp), + CmpSgt(LiftedBinaryOp), + CmpUgt(LiftedBinaryOp), + TestBit(LiftedBinaryOp), + AddOverflow(LiftedBinaryOp), + FcmpE(LiftedBinaryOp), + FcmpNe(LiftedBinaryOp), + FcmpLt(LiftedBinaryOp), + FcmpLe(LiftedBinaryOp), + FcmpGe(LiftedBinaryOp), + FcmpGt(LiftedBinaryOp), + FcmpO(LiftedBinaryOp), + FcmpUo(LiftedBinaryOp), + Fadd(LiftedBinaryOp), + Fsub(LiftedBinaryOp), + Fmul(LiftedBinaryOp), + Fdiv(LiftedBinaryOp), + Adc(LiftedBinaryOpCarry), + Sbb(LiftedBinaryOpCarry), + Rlc(LiftedBinaryOpCarry), + Rrc(LiftedBinaryOpCarry), + Neg(LiftedUnaryOp), + Not(LiftedUnaryOp), + Sx(LiftedUnaryOp), + Zx(LiftedUnaryOp), + LowPart(LiftedUnaryOp), + BoolToInt(LiftedUnaryOp), + UnimplMem(LiftedUnaryOp), + Fsqrt(LiftedUnaryOp), + Fneg(LiftedUnaryOp), + Fabs(LiftedUnaryOp), + FloatToInt(LiftedUnaryOp), + IntToFloat(LiftedUnaryOp), + FloatConv(LiftedUnaryOp), + RoundToInt(LiftedUnaryOp), + Floor(LiftedUnaryOp), + Ceil(LiftedUnaryOp), + Ftrunc(LiftedUnaryOp), + Ret(LiftedRet), + + MemPhi(LiftedMemPhi), + SeparateParamList(LiftedSeparateParamList), + SharedParamSlot(LiftedSharedParamSlot), + + AddressOf(Var), + AddressOfField(Field), + Trap(Trap), + + VarSsa(VarSsa), + VarSsaField(VarSsaField), + StoreSsa(LiftedStoreSsa), + StoreStructSsa(LiftedStoreStructSsa), + SetVarSsa(LiftedSetVarSsa), + SetVarSsaField(LiftedSetVarSsaField), + FreeVarSlotSsa(FreeVarSlotSsa), + VarSplitSsa(VarSplitSsa), + SetVarSplitSsa(LiftedSetVarSplitSsa), + CallSsa(LiftedCallSsa), + CallUntypedSsa(LiftedCallUntypedSsa), + TailcallSsa(LiftedCallSsa), + SyscallSsa(LiftedSyscallSsa), + SyscallUntypedSsa(LiftedSyscallUntypedSsa), + IntrinsicSsa(LiftedIntrinsicSsa), + TailcallUntypedSsa(LiftedCallUntypedSsa), + LoadSsa(LiftedLoadSsa), + LoadStructSsa(LiftedLoadStructSsa), + + SetVarAliased(LiftedSetVarAliased), + SetVarAliasedField(LiftedSetVarSsaField), + VarPhi(LiftedVarPhi), + VarAliased(VarSsa), + VarAliasedField(VarSsaField), +} + +impl Sealed for MediumLevelILLiftedInstructionKindSSA {} +impl MediumLevelILLiftedInstructionKindSSA { + construct_common!( + SSA, + MediumLevelILInstructionKindSSA, + MediumLevelILLiftedInstructionKindSSA + ); + fn this_operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)> { + use MediumLevelILLiftedInstructionKindSSA::*; + use MediumLevelILLiftedOperand as Operand; + match self { + StoreSsa(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::Int(op.src_memory)), + ("src", Operand::Expr(*op.src.clone())), + ], + StoreStructSsa(op) => vec![ + ("dest", Operand::Expr(*op.dest.clone())), + ("offset", Operand::Int(op.offset)), + ("dest_memory", Operand::Int(op.dest_memory)), + ("src_memory", Operand::Int(op.src_memory)), + ("src", Operand::Expr(*op.src.clone())), + ], FreeVarSlotSsa(op) => vec![ ("dest", Operand::VarSsa(op.dest)), ("prev", Operand::VarSsa(op.prev)), @@ -383,19 +667,6 @@ impl MediumLevelILLiftedInstruction { ("dest", Operand::VarSsa(op.dest)), ("src", Operand::VarSsaList(op.src.clone())), ], - MemPhi(op) => vec![ - ("dest_memory", Operand::Int(op.dest_memory)), - ("src_memory", Operand::IntList(op.src_memory.clone())), - ], - VarSplit(op) => vec![ - ("high", Operand::Var(op.high)), - ("low", Operand::Var(op.low)), - ], - SetVarSplit(op) => vec![ - ("high", Operand::Var(op.high)), - ("low", Operand::Var(op.low)), - ("src", Operand::Expr(*op.src.clone())), - ], VarSplitSsa(op) => vec![ ("high", Operand::VarSsa(op.high)), ("low", Operand::VarSsa(op.low)), @@ -405,35 +676,6 @@ impl MediumLevelILLiftedInstruction { ("low", Operand::VarSsa(op.low)), ("src", Operand::Expr(*op.src.clone())), ], - Add(op) | Sub(op) | And(op) | Or(op) | Xor(op) | Lsl(op) | Lsr(op) | Asr(op) - | Rol(op) | Ror(op) | Mul(op) | MuluDp(op) | MulsDp(op) | Divu(op) | DivuDp(op) - | Divs(op) | DivsDp(op) | Modu(op) | ModuDp(op) | Mods(op) | ModsDp(op) | CmpE(op) - | CmpNe(op) | CmpSlt(op) | CmpUlt(op) | CmpSle(op) | CmpUle(op) | CmpSge(op) - | CmpUge(op) | CmpSgt(op) | CmpUgt(op) | TestBit(op) | AddOverflow(op) | FcmpE(op) - | FcmpNe(op) | FcmpLt(op) | FcmpLe(op) | FcmpGe(op) | FcmpGt(op) | FcmpO(op) - | FcmpUo(op) | Fadd(op) | Fsub(op) | Fmul(op) | Fdiv(op) => vec![ - ("left", Operand::Expr(*op.left.clone())), - ("right", Operand::Expr(*op.right.clone())), - ], - Adc(op) | Sbb(op) | Rlc(op) | Rrc(op) => vec![ - ("left", Operand::Expr(*op.left.clone())), - ("right", Operand::Expr(*op.right.clone())), - ("carry", Operand::Expr(*op.carry.clone())), - ], - Call(op) | Tailcall(op) => vec![ - ("output", Operand::VarList(op.output.clone())), - ("dest", Operand::Expr(*op.dest.clone())), - ("params", Operand::ExprList(op.params.clone())), - ], - Syscall(op) => vec![ - ("output", Operand::VarList(op.output.clone())), - ("params", Operand::ExprList(op.params.clone())), - ], - Intrinsic(op) => vec![ - ("output", Operand::VarList(op.output.clone())), - ("intrinsic", Operand::Intrinsic(op.intrinsic)), - ("params", Operand::ExprList(op.params.clone())), - ], IntrinsicSsa(op) => vec![ ("output", Operand::VarSsaList(op.output.clone())), ("intrinsic", Operand::Intrinsic(op.intrinsic)), @@ -461,26 +703,6 @@ impl MediumLevelILLiftedInstruction { ("params", Operand::ExprList(op.params.clone())), ("stack", Operand::Expr(*op.stack.clone())), ], - CallUntyped(op) | TailcallUntyped(op) => vec![ - ("output", Operand::VarList(op.output.clone())), - ("dest", Operand::Expr(*op.dest.clone())), - ("params", Operand::ExprList(op.params.clone())), - ("stack", Operand::Expr(*op.stack.clone())), - ], - SyscallUntyped(op) => vec![ - ("output", Operand::VarList(op.output.clone())), - ("params", Operand::ExprList(op.params.clone())), - ("stack", Operand::Expr(*op.stack.clone())), - ], - Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op) | BoolToInt(op) | UnimplMem(op) - | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op) | IntToFloat(op) | FloatConv(op) - | RoundToInt(op) | Floor(op) | Ceil(op) | Ftrunc(op) | Load(op) => { - vec![("src", Operand::Expr(*op.src.clone()))] - } - LoadStruct(op) => vec![ - ("src", Operand::Expr(*op.src.clone())), - ("offset", Operand::Int(op.offset)), - ], LoadStructSsa(op) => vec![ ("src", Operand::Expr(*op.src.clone())), ("offset", Operand::Int(op.offset)), @@ -490,20 +712,441 @@ impl MediumLevelILLiftedInstruction { ("src", Operand::Expr(*op.src.clone())), ("src_memory", Operand::Int(op.src_memory)), ], - Ret(op) => vec![("src", Operand::ExprList(op.src.clone()))], - SeparateParamList(op) => vec![("params", Operand::ExprList(op.params.clone()))], - SharedParamSlot(op) => vec![("params", Operand::ExprList(op.params.clone()))], - Var(op) | AddressOf(op) => vec![("src", Operand::Var(op.src))], - VarField(op) | AddressOfField(op) => vec![ - ("src", Operand::Var(op.src)), - ("offset", Operand::Int(op.offset)), - ], VarSsa(op) | VarAliased(op) => vec![("src", Operand::VarSsa(op.src))], VarSsaField(op) | VarAliasedField(op) => vec![ ("src", Operand::VarSsa(op.src)), ("offset", Operand::Int(op.offset)), ], - Trap(op) => vec![("vector", Operand::Int(op.vector))], + _ => unreachable!(), + } + } + fn this_from_instruction(inst: &MediumLevelILInstruction) -> Self { + use MediumLevelILInstructionKindSSA::*; + use MediumLevelILLiftedInstructionKindSSA as Lifted; + match &inst.kind { + VarSsa(op) => Lifted::VarSsa(*op), + VarSsaField(op) => Lifted::VarSsaField(*op), + StoreSsa(op) => Lifted::StoreSsa(op.lift(inst)), + StoreStructSsa(op) => Lifted::StoreStructSsa(op.lift(inst)), + SetVarSsa(op) => Lifted::SetVarSsa(op.lift(inst)), + SetVarSsaField(op) => Lifted::SetVarSsaField(op.lift(inst)), + FreeVarSlotSsa(op) => Lifted::FreeVarSlotSsa(*op), + VarSplitSsa(op) => Lifted::VarSplitSsa(*op), + SetVarSplitSsa(op) => Lifted::SetVarSplitSsa(op.lift(inst)), + CallSsa(op) => Lifted::CallSsa(op.lift(inst)), + CallUntypedSsa(op) => Lifted::CallUntypedSsa(op.lift(inst)), + TailcallSsa(op) => Lifted::TailcallSsa(op.lift(inst)), + SyscallSsa(op) => Lifted::SyscallSsa(op.lift(inst)), + SyscallUntypedSsa(op) => Lifted::SyscallUntypedSsa(op.lift(inst)), + IntrinsicSsa(op) => Lifted::IntrinsicSsa(op.lift(inst)), + TailcallUntypedSsa(op) => Lifted::TailcallUntypedSsa(op.lift(inst)), + LoadSsa(op) => Lifted::LoadSsa(op.lift(inst)), + LoadStructSsa(op) => Lifted::LoadStructSsa(op.lift(inst)), + + SetVarAliased(op) => Lifted::SetVarAliased(op.lift(inst)), + SetVarAliasedField(op) => Lifted::SetVarAliasedField(op.lift(inst)), + VarPhi(op) => Lifted::VarPhi(op.lift(inst)), + VarAliased(op) => Lifted::VarAliased(*op), + VarAliasedField(op) => Lifted::VarAliasedField(*op), + _ => unreachable!(), + } + } +} + +impl InstructionLiftedTrait for MediumLevelILLiftedInstructionKindSSA { + fn name(&self) -> &'static str { + self.into() + } + + fn from_instruction(inst: &MediumLevelILInstruction) -> Self { + Self::common_from_instruction(inst).unwrap_or_else(|| Self::this_from_instruction(inst)) + } + + fn operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)> { + self.common_operands() + .unwrap_or_else(|| self.this_operands()) + } +} + +impl MediumLevelILLiftedInstruction { + pub fn name(&self) -> &'static str { + self.kind.name() + } + pub fn operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)> { + self.kind.operands() + } +} + +impl MediumLevelILOperationIf { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedIf { + LiftedIf { + condition: inst.lift_operand(self.condition), + dest_true: self.dest_true, + dest_false: self.dest_false, + } + } +} +impl ConstData { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedConstData { + LiftedConstData { + constant_data: ConstantData::new( + inst.function.get_function(), + RegisterValue { + state: RegisterValueType::from_raw_value(self.constant_data_kind).unwrap(), + value: self.constant_data_value, + offset: 0, + size: self.size, + }, + ), + } + } +} +impl Jump { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedJump { + LiftedJump { + dest: inst.lift_operand(self.dest), + } + } +} +impl JumpTo { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedJumpTo { + LiftedJumpTo { + dest: inst.lift_operand(self.dest), + targets: OperandIter::new(&*inst.function, self.first_operand, self.num_operands) + .pairs() + .collect(), + } + } +} +impl StoreSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedStoreSsa { + LiftedStoreSsa { + dest: inst.lift_operand(self.dest), + dest_memory: self.dest_memory, + src_memory: self.src_memory, + src: inst.lift_operand(self.src), + } + } +} + +impl StoreStructSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedStoreStructSsa { + LiftedStoreStructSsa { + dest: inst.lift_operand(self.dest), + offset: self.offset, + dest_memory: self.dest_memory, + src_memory: self.src_memory, + src: inst.lift_operand(self.src), + } + } +} +impl StoreStruct { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedStoreStruct { + LiftedStoreStruct { + dest: inst.lift_operand(self.dest), + offset: self.offset, + src: inst.lift_operand(self.src), + } + } +} +impl Store { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedStore { + LiftedStore { + dest: inst.lift_operand(self.dest), + src: inst.lift_operand(self.src), + } + } +} +impl SetVarField { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSetVarField { + LiftedSetVarField { + dest: self.dest, + offset: self.offset, + src: inst.lift_operand(self.src), + } + } +} +impl SetVar { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSetVar { + LiftedSetVar { + dest: self.dest, + src: inst.lift_operand(self.src), + } + } +} +impl SetVarSsaField { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSetVarSsaField { + LiftedSetVarSsaField { + dest: self.dest, + prev: self.prev, + offset: self.offset, + src: inst.lift_operand(self.src), + } + } +} +impl SetVarAliased { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSetVarAliased { + LiftedSetVarAliased { + dest: self.dest, + prev: self.prev, + src: inst.lift_operand(self.src), + } + } +} +impl SetVarSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSetVarSsa { + LiftedSetVarSsa { + dest: self.dest, + src: inst.lift_operand(self.src), + } + } +} +impl VarPhi { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedVarPhi { + LiftedVarPhi { + dest: self.dest, + src: OperandIter::new(&*inst.function, self.first_operand, self.num_operands) + .ssa_vars() + .collect(), + } + } +} +impl MemPhi { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedMemPhi { + LiftedMemPhi { + dest_memory: self.dest_memory, + src_memory: OperandIter::new(&*inst.function, self.first_operand, self.num_operands) + .collect(), + } + } +} +impl SetVarSplit { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSetVarSplit { + LiftedSetVarSplit { + high: self.high, + low: self.low, + src: inst.lift_operand(self.src), + } + } +} +impl SetVarSplitSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSetVarSplitSsa { + LiftedSetVarSplitSsa { + high: self.high, + low: self.low, + src: inst.lift_operand(self.src), + } + } +} +impl UnaryOp { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedUnaryOp { + LiftedUnaryOp { + src: inst.lift_operand(self.src), + } + } +} +impl BinaryOp { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedBinaryOp { + LiftedBinaryOp { + left: inst.lift_operand(self.left), + right: inst.lift_operand(self.right), + } + } +} +impl BinaryOpCarry { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedBinaryOpCarry { + LiftedBinaryOpCarry { + left: inst.lift_operand(self.left), + right: inst.lift_operand(self.right), + carry: inst.lift_operand(self.carry), + } + } +} +impl Call { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedCall { + LiftedCall { + output: OperandIter::new(&*inst.function, self.first_output, self.num_outputs) + .vars() + .collect(), + dest: inst.lift_operand(self.dest), + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } +} +impl CallSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedCallSsa { + LiftedCallSsa { + output: inst.get_call_output_ssa(self.output).collect(), + dest: inst.lift_operand(self.dest), + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + src_memory: self.src_memory, + } + } +} +impl CallUntyped { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedCallUntyped { + LiftedCallUntyped { + output: inst.get_call_output(self.output).collect(), + dest: inst.lift_operand(self.dest), + params: inst + .get_call_params(self.params) + .map(|expr| expr.lift()) + .collect(), + stack: inst.lift_operand(self.stack), + } + } +} +impl CallUntypedSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedCallUntypedSsa { + LiftedCallUntypedSsa { + output: inst.get_call_output_ssa(self.output).collect(), + dest: inst.lift_operand(self.dest), + params: inst + .get_call_params_ssa(self.params) + .map(|param| param.lift()) + .collect(), + stack: inst.lift_operand(self.stack), + } + } +} +impl Intrinsic { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedIntrinsic { + LiftedIntrinsic { + output: OperandIter::new(&*inst.function, self.first_output, self.num_outputs) + .vars() + .collect(), + intrinsic: ILIntrinsic::new(inst.function.get_function().arch(), self.intrinsic), + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } +} +impl Syscall { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSyscall { + LiftedSyscall { + output: OperandIter::new(&*inst.function, self.first_output, self.num_outputs) + .vars() + .collect(), + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } +} +impl IntrinsicSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedIntrinsicSsa { + LiftedIntrinsicSsa { + output: OperandIter::new(&*inst.function, self.first_output, self.num_outputs) + .ssa_vars() + .collect(), + intrinsic: ILIntrinsic::new(inst.function.get_function().arch(), self.intrinsic), + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } +} + +impl SyscallSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSyscallSsa { + LiftedSyscallSsa { + output: inst.get_call_output_ssa(self.output).collect(), + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + src_memory: self.src_memory, + } + } +} +impl SyscallUntypedSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSyscallUntypedSsa { + LiftedSyscallUntypedSsa { + output: inst.get_call_output_ssa(self.output).collect(), + params: inst + .get_call_params_ssa(self.params) + .map(|param| param.lift()) + .collect(), + stack: inst.lift_operand(self.stack), + } + } +} + +impl SyscallUntyped { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSyscallUntyped { + LiftedSyscallUntyped { + output: inst.get_call_output(self.output).collect(), + params: inst + .get_call_params(self.params) + .map(|param| param.lift()) + .collect(), + stack: inst.lift_operand(self.stack), + } + } +} + +impl LoadStruct { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedLoadStruct { + LiftedLoadStruct { + src: inst.lift_operand(self.src), + offset: self.offset, + } + } +} +impl LoadStructSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedLoadStructSsa { + LiftedLoadStructSsa { + src: inst.lift_operand(self.src), + offset: self.offset, + src_memory: self.src_memory, + } + } +} +impl LoadSsa { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedLoadSsa { + LiftedLoadSsa { + src: inst.lift_operand(self.src), + src_memory: self.src_memory, + } + } +} +impl Ret { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedRet { + LiftedRet { + src: OperandIter::new(&*inst.function, self.first_operand, self.num_operands) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } +} +impl SeparateParamList { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSeparateParamList { + LiftedSeparateParamList { + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), + } + } +} +impl SharedParamSlot { + pub fn lift(&self, inst: &MediumLevelILInstruction) -> LiftedSharedParamSlot { + LiftedSharedParamSlot { + params: OperandIter::new(&*inst.function, self.first_param, self.num_params) + .exprs() + .map(|expr| expr.lift()) + .collect(), } } } diff --git a/rust/src/mlil/mod.rs b/rust/src/mlil/mod.rs index 8a9103acf..10fb4bab5 100644 --- a/rust/src/mlil/mod.rs +++ b/rust/src/mlil/mod.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + mod block; mod function; mod instruction; @@ -8,3 +10,49 @@ pub use self::block::*; pub use self::function::*; pub use self::instruction::*; pub use self::lift::*; + +use binaryninjacore_sys::BNMediumLevelILInstruction; + +// don't allow the user to implement those traits for custom types +trait Sealed {} + +#[allow(private_bounds)] +pub trait InstructionTrait: Sealed + Sized + Clone + Debug + InstructionTraitFromRaw { + fn name(&self) -> &'static str; +} + +// don't allow the user to call this function directly +trait InstructionTraitFromRaw: Sized { + fn from_operation(op: BNMediumLevelILInstruction) -> Option; +} + +#[allow(private_bounds)] +pub trait InstructionLiftedTrait: Sealed + Sized + Clone + Debug { + fn name(&self) -> &'static str; + fn from_instruction(inst: &MediumLevelILInstruction) -> Self; + fn operands(&self) -> Vec<(&'static str, MediumLevelILLiftedOperand)>; +} + +#[allow(private_bounds)] +pub trait Form: Sealed + Sized + Clone + std::fmt::Debug { + type Instruction: InstructionTrait; + type InstructionLifted: InstructionLiftedTrait; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SSA; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NonSSA; + +impl Sealed for SSA {} +impl Sealed for NonSSA {} + +impl Form for NonSSA { + type Instruction = MediumLevelILInstructionKindNonSSA; + type InstructionLifted = MediumLevelILLiftedInstructionKindNonSSA; +} + +impl Form for SSA { + type Instruction = MediumLevelILInstructionKindSSA; + type InstructionLifted = MediumLevelILLiftedInstructionKindSSA; +} diff --git a/rust/src/mlil/operation.rs b/rust/src/mlil/operation.rs index 822688a61..7591fdb1f 100644 --- a/rust/src/mlil/operation.rs +++ b/rust/src/mlil/operation.rs @@ -2,81 +2,81 @@ use std::collections::BTreeMap; use crate::types::{ConstantData, ILIntrinsic, SSAVariable, Variable}; -use super::MediumLevelILLiftedInstruction; +use super::{Form, MediumLevelILLiftedInstruction, NonSSA, SSA}; // IF -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct MediumLevelILOperationIf { pub condition: usize, pub dest_true: u64, pub dest_false: u64, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedIf { - pub condition: Box, +#[derive(Debug, Clone)] +pub struct LiftedIf { + pub condition: Box>, pub dest_true: u64, pub dest_false: u64, } // FLOAT_CONST -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Debug, Copy, Clone)] pub struct FloatConst { pub constant: f64, } // CONST, CONST_PTR, IMPORT -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Constant { pub constant: u64, } // EXTERN_PTR -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ExternPtr { pub constant: u64, pub offset: u64, } // CONST_DATA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct ConstData { pub constant_data_kind: u32, pub constant_data_value: i64, pub size: usize, } -#[derive(Clone, Debug, Hash, PartialEq)] +#[derive(Debug, Clone, Hash)] pub struct LiftedConstData { pub constant_data: ConstantData, } // JUMP, RET_HINT -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct Jump { pub dest: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedJump { - pub dest: Box, +#[derive(Debug, Clone)] +pub struct LiftedJump { + pub dest: Box>, } // STORE_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct StoreSsa { pub dest: usize, pub dest_memory: u64, pub src_memory: u64, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedStoreSsa { - pub dest: Box, + pub dest: Box>, pub dest_memory: u64, pub src_memory: u64, - pub src: Box, + pub src: Box>, } // STORE_STRUCT_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct StoreStructSsa { pub dest: usize, pub offset: u64, @@ -84,237 +84,237 @@ pub struct StoreStructSsa { pub src_memory: u64, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedStoreStructSsa { - pub dest: Box, + pub dest: Box>, pub offset: u64, pub dest_memory: u64, pub src_memory: u64, - pub src: Box, + pub src: Box>, } // STORE_STRUCT -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct StoreStruct { pub dest: usize, pub offset: u64, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedStoreStruct { - pub dest: Box, + pub dest: Box>, pub offset: u64, - pub src: Box, + pub src: Box>, } // STORE -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct Store { pub dest: usize, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedStore { - pub dest: Box, - pub src: Box, + pub dest: Box>, + pub src: Box>, } // JUMP_TO -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct JumpTo { pub dest: usize, pub first_operand: usize, pub num_operands: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedJumpTo { - pub dest: Box, +#[derive(Debug, Clone)] +pub struct LiftedJumpTo { + pub dest: Box>, pub targets: BTreeMap, } // GOTO -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Goto { pub dest: u64, } // FREE_VAR_SLOT -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct FreeVarSlot { pub dest: Variable, } // SET_VAR_FIELD -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SetVarField { pub dest: Variable, pub offset: u64, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSetVarField { pub dest: Variable, pub offset: u64, - pub src: Box, + pub src: Box>, } // SET_VAR -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SetVar { pub dest: Variable, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSetVar { pub dest: Variable, - pub src: Box, + pub src: Box>, } // FREE_VAR_SLOT_SSA -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct FreeVarSlotSsa { pub dest: SSAVariable, pub prev: SSAVariable, } // SET_VAR_SSA_FIELD, SET_VAR_ALIASED_FIELD -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SetVarSsaField { pub dest: SSAVariable, pub prev: SSAVariable, pub offset: u64, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSetVarSsaField { pub dest: SSAVariable, pub prev: SSAVariable, pub offset: u64, - pub src: Box, + pub src: Box>, } // SET_VAR_ALIASED -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SetVarAliased { pub dest: SSAVariable, pub prev: SSAVariable, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSetVarAliased { pub dest: SSAVariable, pub prev: SSAVariable, - pub src: Box, + pub src: Box>, } // SET_VAR_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SetVarSsa { pub dest: SSAVariable, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSetVarSsa { pub dest: SSAVariable, - pub src: Box, + pub src: Box>, } // VAR_PHI -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct VarPhi { pub dest: SSAVariable, pub first_operand: usize, pub num_operands: usize, } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct LiftedVarPhi { pub dest: SSAVariable, pub src: Vec, } // MEM_PHI -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct MemPhi { pub dest_memory: u64, pub first_operand: usize, pub num_operands: usize, } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct LiftedMemPhi { pub dest_memory: u64, pub src_memory: Vec, } // VAR_SPLIT -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct VarSplit { pub high: Variable, pub low: Variable, } // SET_VAR_SPLIT -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SetVarSplit { pub high: Variable, pub low: Variable, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSetVarSplit { pub high: Variable, pub low: Variable, - pub src: Box, + pub src: Box>, } // VAR_SPLIT_SSA -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct VarSplitSsa { pub high: SSAVariable, pub low: SSAVariable, } // SET_VAR_SPLIT_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SetVarSplitSsa { pub high: SSAVariable, pub low: SSAVariable, pub src: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSetVarSplitSsa { pub high: SSAVariable, pub low: SSAVariable, - pub src: Box, + pub src: Box>, } // ADD, SUB, AND, OR, XOR, LSL, LSR, ASR, ROL, ROR, MUL, MULU_DP, MULS_DP, DIVU, DIVU_DP, DIVS, DIVS_DP, MODU, MODU_DP, MODS, MODS_DP, CMP_E, CMP_NE, CMP_SLT, CMP_ULT, CMP_SLE, CMP_ULE, CMP_SGE, CMP_UGE, CMP_SGT, CMP_UGT, TEST_BIT, ADD_OVERFLOW, FCMP_E, FCMP_NE, FCMP_LT, FCMP_LE, FCMP_GE, FCMP_GT, FCMP_O, FCMP_UO, FADD, FSUB, FMUL, FDIV -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct BinaryOp { pub left: usize, pub right: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedBinaryOp { - pub left: Box, - pub right: Box, +#[derive(Debug, Clone)] +pub struct LiftedBinaryOp { + pub left: Box>, + pub right: Box>, } // ADC, SBB, RLC, RRC -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct BinaryOpCarry { pub left: usize, pub right: usize, pub carry: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedBinaryOpCarry { - pub left: Box, - pub right: Box, - pub carry: Box, +#[derive(Debug, Clone)] +pub struct LiftedBinaryOpCarry { + pub left: Box>, + pub right: Box>, + pub carry: Box>, } // CALL, TAILCALL -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct Call { pub first_output: usize, pub num_outputs: usize, @@ -322,29 +322,29 @@ pub struct Call { pub first_param: usize, pub num_params: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedCall { pub output: Vec, - pub dest: Box, - pub params: Vec, + pub dest: Box>, + pub params: Vec>, } // SYSCALL -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct Syscall { pub first_output: usize, pub num_outputs: usize, pub first_param: usize, pub num_params: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedSyscallCall { +#[derive(Debug, Clone)] +pub struct LiftedSyscall { pub output: Vec, - pub params: Vec, + pub params: Vec>, } // INTRINSIC -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct Intrinsic { pub first_output: usize, pub num_outputs: usize, @@ -352,15 +352,15 @@ pub struct Intrinsic { pub first_param: usize, pub num_params: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedIntrinsic { pub output: Vec, pub intrinsic: ILIntrinsic, - pub params: Vec, + pub params: Vec>, } // INTRINSIC_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct IntrinsicSsa { pub first_output: usize, pub num_outputs: usize, @@ -368,15 +368,15 @@ pub struct IntrinsicSsa { pub first_param: usize, pub num_params: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedIntrinsicSsa { pub output: Vec, pub intrinsic: ILIntrinsic, - pub params: Vec, + pub params: Vec>, } // CALL_SSA, TAILCALL_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct CallSsa { pub output: usize, pub dest: usize, @@ -384,198 +384,198 @@ pub struct CallSsa { pub num_params: usize, pub src_memory: u64, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedCallSsa { pub output: Vec, - pub dest: Box, - pub params: Vec, + pub dest: Box>, + pub params: Vec>, pub src_memory: u64, } // CALL_UNTYPED_SSA, TAILCALL_UNTYPED_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct CallUntypedSsa { pub output: usize, pub dest: usize, pub params: usize, pub stack: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedCallUntypedSsa { pub output: Vec, - pub dest: Box, - pub params: Vec, - pub stack: Box, + pub dest: Box>, + pub params: Vec>, + pub stack: Box>, } // SYSCALL_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SyscallSsa { pub output: usize, pub first_param: usize, pub num_params: usize, pub src_memory: u64, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSyscallSsa { pub output: Vec, - pub params: Vec, + pub params: Vec>, pub src_memory: u64, } // SYSCALL_UNTYPED_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SyscallUntypedSsa { pub output: usize, pub params: usize, pub stack: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSyscallUntypedSsa { pub output: Vec, - pub params: Vec, - pub stack: Box, + pub params: Vec>, + pub stack: Box>, } // CALL_UNTYPED, TAILCALL_UNTYPED -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct CallUntyped { pub output: usize, pub dest: usize, pub params: usize, pub stack: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedCallUntyped { pub output: Vec, - pub dest: Box, - pub params: Vec, - pub stack: Box, + pub dest: Box>, + pub params: Vec>, + pub stack: Box>, } // SYSCALL_UNTYPED -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SyscallUntyped { pub output: usize, pub params: usize, pub stack: usize, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedSyscallUntyped { pub output: Vec, - pub params: Vec, - pub stack: Box, + pub params: Vec>, + pub stack: Box>, } // NEG, NOT, SX, ZX, LOW_PART, BOOL_TO_INT, UNIMPL_MEM, FSQRT, FNEG, FABS, FLOAT_TO_INT, INT_TO_FLOAT, FLOAT_CONV, ROUND_TO_INT, FLOOR, CEIL, FTRUNC, LOAD -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct UnaryOp { pub src: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedUnaryOp { - pub src: Box, +#[derive(Debug, Clone)] +pub struct LiftedUnaryOp { + pub src: Box>, } // LOAD_STRUCT -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct LoadStruct { pub src: usize, pub offset: u64, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedLoadStruct { - pub src: Box, + pub src: Box>, pub offset: u64, } // LOAD_STRUCT_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct LoadStructSsa { pub src: usize, pub offset: u64, pub src_memory: u64, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedLoadStructSsa { - pub src: Box, + pub src: Box>, pub offset: u64, pub src_memory: u64, } // LOAD_SSA -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct LoadSsa { pub src: usize, pub src_memory: u64, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone)] pub struct LiftedLoadSsa { - pub src: Box, + pub src: Box>, pub src_memory: u64, } // RET -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct Ret { pub first_operand: usize, pub num_operands: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedRet { - pub src: Vec, +#[derive(Debug, Clone)] +pub struct LiftedRet { + pub src: Vec>, } // SEPARATE_PARAM_LIST -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SeparateParamList { pub first_param: usize, pub num_params: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedSeparateParamList { - pub params: Vec, +#[derive(Debug, Clone)] +pub struct LiftedSeparateParamList { + pub params: Vec>, } // SHARED_PARAM_SLOT -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct SharedParamSlot { pub first_param: usize, pub num_params: usize, } -#[derive(Clone, Debug, PartialEq)] -pub struct LiftedSharedParamSlot { - pub params: Vec, +#[derive(Debug, Clone)] +pub struct LiftedSharedParamSlot { + pub params: Vec>, } // VAR, ADDRESS_OF -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Var { pub src: Variable, } // VAR_FIELD, ADDRESS_OF_FIELD -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Field { pub src: Variable, pub offset: u64, } // VAR_SSA, VAR_ALIASED -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct VarSsa { pub src: SSAVariable, } // VAR_SSA_FIELD, VAR_ALIASED_FIELD -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct VarSsaField { pub src: SSAVariable, pub offset: u64, } // TRAP -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Trap { pub vector: u64, } diff --git a/rust/src/operand_iter.rs b/rust/src/operand_iter.rs index 5f0fbd8ec..a77c885fb 100644 --- a/rust/src/operand_iter.rs +++ b/rust/src/operand_iter.rs @@ -5,19 +5,20 @@ use binaryninjacore_sys::BNHighLevelILOperation; use binaryninjacore_sys::BNMediumLevelILOperation; use crate::hlil::{HighLevelILFunction, HighLevelILInstruction}; +use crate::mlil; use crate::mlil::{MediumLevelILFunction, MediumLevelILInstruction}; use crate::rc::{Ref, RefCountable}; use crate::types::{SSAVariable, Variable}; pub trait ILFunction { - type Instruction; + type Instruction: Sized; 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; +impl ILFunction for MediumLevelILFunction { + type Instruction = MediumLevelILInstruction; fn il_instruction_from_idx(&self, expr_idx: usize) -> Self::Instruction { self.instruction_from_idx(expr_idx)