use std::collections::BTreeMap;
use crate::architecture::CoreIntrinsic;
use crate::rc::Ref;
use crate::types::{ConstantData, SSAVariable, Variable};
use super::operation::*;
use super::MediumLevelILFunction;
#[derive(Clone)]
pub enum MediumLevelILLiftedOperand {
ConstantData(ConstantData),
Intrinsic(CoreIntrinsic),
Expr(MediumLevelILLiftedInstruction),
ExprList(Vec<MediumLevelILLiftedInstruction>),
Float(f64),
Int(u64),
IntList(Vec<u64>),
TargetMap(BTreeMap<u64, u64>),
Var(Variable),
VarList(Vec<Variable>),
VarSsa(SSAVariable),
VarSsaList(Vec<SSAVariable>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct MediumLevelILLiftedInstruction {
pub function: Ref<MediumLevelILFunction>,
pub address: u64,
pub index: usize,
pub size: usize,
pub kind: MediumLevelILLiftedInstructionKind,
}
#[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::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))],
}
}
}