From 5fcf6bc59ebc2110d053360d223e6570cdd2272c Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Wed, 7 Feb 2024 11:44:06 -0500 Subject: Refactor MLIL instructions * Turn `MediumLevelILInstruction` into a struct with a `kind` field to indicate the instruction variant, and pull out the `function` and `address` fields from each variant to live in the top-level struct. * Make variant fields public, remove field getter methods and centralize lifting logic to happen all at once. Split tuple fields into individual named fields. * Move the `operands` method to `MediumLevelILLiftedInstruction`, and make it return an owned `Vec` of operands rather than a borrowed iterator. --- rust/src/mlil/lift.rs | 250 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 244 insertions(+), 6 deletions(-) (limited to 'rust/src/mlil/lift.rs') diff --git a/rust/src/mlil/lift.rs b/rust/src/mlil/lift.rs index bf7f16db..0cf669bf 100644 --- a/rust/src/mlil/lift.rs +++ b/rust/src/mlil/lift.rs @@ -1,12 +1,43 @@ +use std::collections::HashMap; + +use crate::rc::Ref; +use crate::types; +use crate::types::ILIntrinsic; +use crate::types::{SSAVariable, Variable}; + use super::operation::*; +use super::MediumLevelILFunction; + +#[derive(Clone)] +pub enum MediumLevelILLiftedOperand { + ConstantData(types::ConstantData), + Intrinsic(ILIntrinsic), + Expr(MediumLevelILLiftedInstruction), + ExprList(Vec), + Float(f64), + Int(u64), + IntList(Vec), + TargetMap(HashMap), + Var(Variable), + VarList(Vec), + VarSsa(SSAVariable), + VarSsaList(Vec), +} #[derive(Clone, Debug, PartialEq)] -pub enum MediumLevelILLiftedInstruction { - Nop(NoArgs), - Noret(NoArgs), - Bp(NoArgs), - Undef(NoArgs), - Unimpl(NoArgs), +pub struct MediumLevelILLiftedInstruction { + pub function: Ref, + pub address: u64, + pub kind: MediumLevelILLiftedInstructionKind, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum MediumLevelILLiftedInstructionKind { + Nop, + Noret, + Bp, + Undef, + Unimpl, If(LiftedIf), FloatConst(FloatConst), Const(Constant), @@ -133,3 +164,210 @@ pub enum MediumLevelILLiftedInstruction { VarAliasedField(VarSsaField), Trap(Trap), } + +impl MediumLevelILLiftedInstruction { + 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::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())), + ], + 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::Int(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))], + } + } +} -- cgit v1.3.1