use super::operation::*; use super::{HighLevelExpressionIndex, HighLevelILFunction, HighLevelInstructionIndex}; use std::fmt::{Debug, Formatter}; use crate::architecture::CoreIntrinsic; use crate::rc::Ref; use crate::variable::{ConstantData, SSAVariable, Variable}; #[derive(Clone, Debug)] pub enum HighLevelILLiftedOperand { ConstantData(ConstantData), Expr(HighLevelILLiftedInstruction), ExprList(Vec), Float(f64), Int(u64), IntList(Vec), Intrinsic(CoreIntrinsic), Label(GotoLabel), MemberIndex(Option), Var(Variable), VarSsa(SSAVariable), VarSsaList(Vec), } // TODO: UGH, if your gonna call it expr_idx, call the instruction and expression!!!!! // TODO: We dont even need to say instruction in the type! // TODO: IF you want to have an instruction type, there needs to be a separate expression type // TODO: See the lowlevelil module. #[derive(Clone, PartialEq)] pub struct HighLevelILLiftedInstruction { pub function: Ref, pub address: u64, pub instr_index: HighLevelInstructionIndex, pub expr_index: HighLevelExpressionIndex, pub size: usize, pub kind: HighLevelILLiftedInstructionKind, } #[derive(Clone, Debug, PartialEq)] pub enum HighLevelILLiftedInstructionKind { Nop, Break, Continue, Noret, Unreachable, Bp, Undef, Unimpl, Adc(LiftedBinaryOpCarry), Sbb(LiftedBinaryOpCarry), Rlc(LiftedBinaryOpCarry), Rrc(LiftedBinaryOpCarry), 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), Fadd(LiftedBinaryOp), Fsub(LiftedBinaryOp), Fmul(LiftedBinaryOp), Fdiv(LiftedBinaryOp), FcmpE(LiftedBinaryOp), FcmpNe(LiftedBinaryOp), FcmpLt(LiftedBinaryOp), FcmpLe(LiftedBinaryOp), FcmpGe(LiftedBinaryOp), FcmpGt(LiftedBinaryOp), FcmpO(LiftedBinaryOp), FcmpUo(LiftedBinaryOp), ArrayIndex(LiftedArrayIndex), ArrayIndexSsa(LiftedArrayIndexSsa), Assign(LiftedAssign), AssignMemSsa(LiftedAssignMemSsa), AssignUnpack(LiftedAssignUnpack), AssignUnpackMemSsa(LiftedAssignUnpackMemSsa), Block(LiftedBlock), Call(LiftedCall), Tailcall(LiftedCall), CallSsa(LiftedCallSsa), Case(LiftedCase), Const(Const), ConstPtr(Const), Import(Const), ConstData(LiftedConstData), Deref(LiftedUnaryOp), AddressOf(LiftedUnaryOp), PassByRef(LiftedUnaryOp), ReturnByRef(LiftedUnaryOp), Neg(LiftedUnaryOp), Not(LiftedUnaryOp), Bswap(LiftedUnaryOp), Popcnt(LiftedUnaryOp), Clz(LiftedUnaryOp), Ctz(LiftedUnaryOp), Rbit(LiftedUnaryOp), Cls(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), DerefFieldSsa(LiftedDerefFieldSsa), DerefSsa(LiftedDerefSsa), ExternPtr(ExternPtr), FloatConst(FloatConst), For(LiftedForLoop), ForSsa(LiftedForLoopSsa), Goto(LiftedLabel), Label(LiftedLabel), If(LiftedIf), Intrinsic(LiftedIntrinsic), IntrinsicSsa(LiftedIntrinsicSsa), Jump(LiftedJump), MemPhi(LiftedMemPhi), Ret(LiftedRet), Split(LiftedSplit), StructField(LiftedStructField), DerefField(LiftedStructField), Switch(LiftedSwitch), Syscall(LiftedSyscall), SyscallSsa(LiftedSyscallSsa), Trap(Trap), VarDeclare(Var), Var(Var), VarInit(LiftedVarInit), VarInitSsa(LiftedVarInitSsa), VarPhi(LiftedVarPhi), VarSsa(VarSsa), While(LiftedWhile), DoWhile(LiftedWhile), WhileSsa(LiftedWhileSsa), DoWhileSsa(LiftedWhileSsa), } impl HighLevelILLiftedInstruction { pub fn name(&self) -> &'static str { use HighLevelILLiftedInstructionKind::*; match self.kind { Nop => "Nop", Break => "Break", Continue => "Continue", Noret => "Noret", Unreachable => "Unreachable", Bp => "Bp", Undef => "Undef", Unimpl => "Unimpl", Adc(_) => "Adc", Sbb(_) => "Sbb", Rlc(_) => "Rlc", Rrc(_) => "Rrc", 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", Fadd(_) => "Fadd", Fsub(_) => "Fsub", Fmul(_) => "Fmul", Fdiv(_) => "Fdiv", FcmpE(_) => "FcmpE", FcmpNe(_) => "FcmpNe", FcmpLt(_) => "FcmpLt", FcmpLe(_) => "FcmpLe", FcmpGe(_) => "FcmpGe", FcmpGt(_) => "FcmpGt", FcmpO(_) => "FcmpO", FcmpUo(_) => "FcmpUo", ArrayIndex(_) => "ArrayIndex", ArrayIndexSsa(_) => "ArrayIndexSsa", Assign(_) => "Assign", AssignMemSsa(_) => "AssignMemSsa", AssignUnpack(_) => "AssignUnpack", AssignUnpackMemSsa(_) => "AssignUnpackMemSsa", Block(_) => "Block", Call(_) => "Call", Tailcall(_) => "Tailcall", CallSsa(_) => "CallSsa", Case(_) => "Case", Const(_) => "Const", ConstPtr(_) => "ConstPtr", Import(_) => "Import", ConstData(_) => "ConstData", Deref(_) => "Deref", AddressOf(_) => "AddressOf", PassByRef(_) => "PassByRef", ReturnByRef(_) => "ReturnByRef", Neg(_) => "Neg", Not(_) => "Not", Bswap(_) => "Bswap", Popcnt(_) => "Popcnt", Clz(_) => "Clz", Ctz(_) => "Ctz", Rbit(_) => "Rbit", Cls(_) => "Cls", 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", DerefFieldSsa(_) => "DerefFieldSsa", DerefSsa(_) => "DerefSsa", ExternPtr(_) => "ExternPtr", FloatConst(_) => "FloatConst", For(_) => "For", ForSsa(_) => "ForSsa", Goto(_) => "Goto", Label(_) => "Label", If(_) => "If", Intrinsic(_) => "Intrinsic", IntrinsicSsa(_) => "IntrinsicSsa", Jump(_) => "Jump", MemPhi(_) => "MemPhi", Ret(_) => "Ret", Split(_) => "Split", StructField(_) => "StructField", DerefField(_) => "DerefField", Switch(_) => "Switch", Syscall(_) => "Syscall", SyscallSsa(_) => "SyscallSsa", Trap(_) => "Trap", VarDeclare(_) => "VarDeclare", Var(_) => "Var", VarInit(_) => "VarInit", VarInitSsa(_) => "VarInitSsa", VarPhi(_) => "VarPhi", VarSsa(_) => "VarSsa", While(_) => "While", DoWhile(_) => "DoWhile", WhileSsa(_) => "WhileSsa", DoWhileSsa(_) => "DoWhileSsa", } } pub fn operands(&self) -> Vec<(&'static str, HighLevelILLiftedOperand)> { use HighLevelILLiftedInstructionKind::*; use HighLevelILLiftedOperand as Operand; match &self.kind { Nop | Break | Continue | Noret | Unreachable | Bp | Undef | Unimpl => vec![], 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())), ], 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) | Fadd(op) | Fsub(op) | Fmul(op) | Fdiv(op) | FcmpE(op) | FcmpNe(op) | FcmpLt(op) | FcmpLe(op) | FcmpGe(op) | FcmpGt(op) | FcmpO(op) | FcmpUo(op) => vec![ ("left", Operand::Expr(*op.left.clone())), ("right", Operand::Expr(*op.right.clone())), ], ArrayIndex(op) => vec![ ("src", Operand::Expr(*op.src.clone())), ("index", Operand::Expr(*op.index.clone())), ], ArrayIndexSsa(op) => vec![ ("src", Operand::Expr(*op.src.clone())), ("src_memory", Operand::Int(op.src_memory)), ("index", Operand::Expr(*op.index.clone())), ], Assign(op) => vec![ ("dest", Operand::Expr(*op.dest.clone())), ("src", Operand::Expr(*op.src.clone())), ], AssignMemSsa(op) => vec![ ("dest", Operand::Expr(*op.dest.clone())), ("dest_memory", Operand::Int(op.dest_memory)), ("src", Operand::Expr(*op.src.clone())), ("src_memory", Operand::Int(op.src_memory)), ], AssignUnpack(op) => vec![ ("dest", Operand::ExprList(op.dest.clone())), ("src", Operand::Expr(*op.src.clone())), ], AssignUnpackMemSsa(op) => vec![ ("dest", Operand::ExprList(op.dest.clone())), ("dest_memory", Operand::Int(op.dest_memory)), ("src", Operand::Expr(*op.src.clone())), ("src_memory", Operand::Int(op.src_memory)), ], Block(op) => vec![("body", Operand::ExprList(op.body.clone()))], Call(op) | Tailcall(op) => vec![ ("dest", Operand::Expr(*op.dest.clone())), ("params", Operand::ExprList(op.params.clone())), ], CallSsa(op) => vec![ ("dest", Operand::Expr(*op.dest.clone())), ("params", Operand::ExprList(op.params.clone())), ("dest_memory", Operand::Int(op.dest_memory)), ("src_memory", Operand::Int(op.src_memory)), ], Case(op) => vec![ ("values", Operand::ExprList(op.values.clone())), ("body", Operand::Expr(*op.body.clone())), ], Const(op) | ConstPtr(op) | Import(op) => vec![("constant", Operand::Int(op.constant))], ConstData(op) => vec![( "constant_data", Operand::ConstantData(op.constant_data.clone()), )], Deref(op) | AddressOf(op) | PassByRef(op) | ReturnByRef(op) | Neg(op) | Not(op) | Bswap(op) | Popcnt(op) | Clz(op) | Ctz(op) | Rbit(op) | Cls(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) => { vec![("src", Operand::Expr(*op.src.clone()))] } DerefFieldSsa(op) => vec![ ("src", Operand::Expr(*op.src.clone())), ("src_memory", Operand::Int(op.src_memory)), ("offset", Operand::Int(op.offset)), ("member_index", Operand::MemberIndex(op.member_index)), ], DerefSsa(op) => vec![ ("src", Operand::Expr(*op.src.clone())), ("src_memory", Operand::Int(op.src_memory)), ], ExternPtr(op) => vec![ ("constant", Operand::Int(op.constant)), ("offset", Operand::Int(op.offset)), ], FloatConst(op) => vec![("constant", Operand::Float(op.constant))], For(op) => vec![ ("init", Operand::Expr(*op.init.clone())), ("condition", Operand::Expr(*op.condition.clone())), ("update", Operand::Expr(*op.update.clone())), ("body", Operand::Expr(*op.body.clone())), ], ForSsa(op) => vec![ ("init", Operand::Expr(*op.init.clone())), ("condition_phi", Operand::Expr(*op.condition_phi.clone())), ("condition", Operand::Expr(*op.condition.clone())), ("update", Operand::Expr(*op.update.clone())), ("body", Operand::Expr(*op.body.clone())), ], Goto(op) | Label(op) => vec![("target", Operand::Label(op.target.clone()))], If(op) => vec![ ("condition", Operand::Expr(*op.condition.clone())), ("cond_true", Operand::Expr(*op.cond_true.clone())), ("cond_false", Operand::Expr(*op.cond_false.clone())), ], Intrinsic(op) => vec![ ("intrinsic", Operand::Intrinsic(op.intrinsic)), ("params", Operand::ExprList(op.params.clone())), ], IntrinsicSsa(op) => vec![ ("intrinsic", Operand::Intrinsic(op.intrinsic)), ("params", Operand::ExprList(op.params.clone())), ("dest_memory", Operand::Int(op.dest_memory)), ("src_memory", Operand::Int(op.src_memory)), ], Jump(op) => vec![("dest", Operand::Expr(*op.dest.clone()))], MemPhi(op) => vec![ ("dest", Operand::Int(op.dest)), ("src", Operand::IntList(op.src.clone())), ], Ret(op) => vec![("src", Operand::ExprList(op.src.clone()))], Split(op) => vec![ ("high", Operand::Expr(*op.high.clone())), ("low", Operand::Expr(*op.low.clone())), ], StructField(op) | DerefField(op) => vec![ ("src", Operand::Expr(*op.src.clone())), ("offset", Operand::Int(op.offset)), ("member_index", Operand::MemberIndex(op.member_index)), ], Switch(op) => vec![ ("condition", Operand::Expr(*op.condition.clone())), ("default", Operand::Expr(*op.default.clone())), ("cases", Operand::ExprList(op.cases.clone())), ], Syscall(op) => vec![("params", Operand::ExprList(op.params.clone()))], SyscallSsa(op) => vec![ ("params", Operand::ExprList(op.params.clone())), ("dest_memory", Operand::Int(op.dest_memory)), ("src_memory", Operand::Int(op.src_memory)), ], Trap(op) => vec![("vector", Operand::Int(op.vector))], VarDeclare(op) | Var(op) => vec![("var", Operand::Var(op.var))], VarInit(op) => vec![ ("dest", Operand::Var(op.dest)), ("src", Operand::Expr(*op.src.clone())), ], VarInitSsa(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())), ], VarSsa(op) => vec![("var", Operand::VarSsa(op.var))], While(op) | DoWhile(op) => vec![ ("condition", Operand::Expr(*op.condition.clone())), ("body", Operand::Expr(*op.body.clone())), ], WhileSsa(op) | DoWhileSsa(op) => vec![ ("condition_phi", Operand::Expr(*op.condition_phi.clone())), ("condition", Operand::Expr(*op.condition.clone())), ("body", Operand::Expr(*op.body.clone())), ], } } } impl Debug for HighLevelILLiftedInstruction { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("HighLevelILLiftedInstruction") .field("address", &self.address) .field("expr_index", &self.expr_index) .field("size", &self.size) .field("kind", &self.kind) .finish() } }