use super::operation::*; use super::{MediumLevelILFunction, MediumLevelInstructionIndex}; use crate::architecture::CoreIntrinsic; use crate::rc::Ref; use crate::variable::{ConstantData, SSAVariable, Variable}; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; #[derive(Clone)] pub enum MediumLevelILLiftedOperand { ConstantData(ConstantData), Intrinsic(CoreIntrinsic), Expr(MediumLevelILLiftedInstruction), ExprList(Vec), Float(f64), Int(u64), IntList(Vec), TargetMap(BTreeMap), Var(Variable), VarList(Vec), VarSsa(SSAVariable), VarSsaList(Vec), InstructionIndex(MediumLevelInstructionIndex), } #[derive(Clone, PartialEq)] pub struct MediumLevelILLiftedInstruction { pub function: Ref, pub address: u64, pub index: MediumLevelInstructionIndex, pub size: usize, pub kind: MediumLevelILLiftedInstructionKind, } impl Debug for MediumLevelILLiftedInstruction { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("MediumLevelILLiftedInstruction") .field("address", &self.address) .field("index", &self.index) .field("size", &self.size) .field("kind", &self.kind) .finish() } } #[derive(Clone, Debug, PartialEq)] pub enum MediumLevelILLiftedInstructionKind { Nop, Noret, Bp, Undef, Unimpl, 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), Goto(Goto), FreeVarSlot(FreeVarSlot), SetVarField(LiftedSetVarField), SetVar(LiftedSetVar), FreeVarSlotSsa(FreeVarSlotSsa), SetVarSsaField(LiftedSetVarSsaField), SetVarAliasedField(LiftedSetVarSsaField), SetVarAliased(LiftedSetVarAliased), SetVarSsa(LiftedSetVarSsa), VarPhi(LiftedVarPhi), MemPhi(LiftedMemPhi), 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), Tailcall(LiftedCall), 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), 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::*; 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::InstructionIndex(op.dest_true)), ("dest_false", Operand::InstructionIndex(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())), ], StoreStruct(op) => vec![ ("dest", Operand::Expr(*op.dest.clone())), ("offset", Operand::Int(op.offset)), ("src", Operand::Expr(*op.src.clone())), ], Store(op) => vec![ ("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::InstructionIndex(op.dest))], FreeVarSlot(op) => vec![("dest", Operand::Var(op.dest))], SetVarField(op) => vec![ ("dest", Operand::Var(op.dest)), ("offset", Operand::Int(op.offset)), ("src", Operand::Expr(*op.src.clone())), ], SetVar(op) => vec![ ("dest", Operand::Var(op.dest)), ("src", Operand::Expr(*op.src.clone())), ], FreeVarSlotSsa(op) => vec![ ("dest", Operand::VarSsa(op.dest)), ("prev", Operand::VarSsa(op.prev)), ], SetVarSsaField(op) | SetVarAliasedField(op) => vec![ ("dest", Operand::VarSsa(op.dest)), ("prev", Operand::VarSsa(op.prev)), ("offset", Operand::Int(op.offset)), ("src", Operand::Expr(*op.src.clone())), ], SetVarAliased(op) => vec![ ("dest", Operand::VarSsa(op.dest)), ("prev", Operand::VarSsa(op.prev)), ("src", Operand::Expr(*op.src.clone())), ], SetVarSsa(op) => vec![ ("dest", Operand::VarSsa(op.dest)), ("src", Operand::Expr(*op.src.clone())), ], VarPhi(op) => vec![ ("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)), ], SetVarSplitSsa(op) => vec![ ("high", Operand::VarSsa(op.high)), ("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)), ("params", Operand::ExprList(op.params.clone())), ], CallSsa(op) | TailcallSsa(op) => vec![ ("output", Operand::VarSsaList(op.output.clone())), ("dest", Operand::Expr(*op.dest.clone())), ("params", Operand::ExprList(op.params.clone())), ("src_memory", Operand::Int(op.src_memory)), ], CallUntypedSsa(op) | TailcallUntypedSsa(op) => vec![ ("output", Operand::VarSsaList(op.output.clone())), ("dest", Operand::Expr(*op.dest.clone())), ("params", Operand::ExprList(op.params.clone())), ("stack", Operand::Expr(*op.stack.clone())), ], SyscallSsa(op) => vec![ ("output", Operand::VarSsaList(op.output.clone())), ("params", Operand::ExprList(op.params.clone())), ("src_memory", Operand::Int(op.src_memory)), ], SyscallUntypedSsa(op) => vec![ ("output", Operand::VarSsaList(op.output.clone())), ("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)), ("src_memory", Operand::Int(op.src_memory)), ], LoadSsa(op) => vec![ ("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))], } } }