use binaryninjacore_sys::*;
use crate::architecture::CoreIntrinsic;
use crate::disassembly::InstructionTextToken;
use crate::operand_iter::OperandIter;
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
use crate::types::{
Conf, ConstantData, DataFlowQueryOption, ILBranchDependence, PossibleValueSet,
RegisterValue, RegisterValueType, SSAVariable, Type, Variable,
};
use super::lift::*;
use super::operation::*;
use super::MediumLevelILFunction;
#[derive(Clone)]
pub struct MediumLevelILInstruction {
pub function: Ref<MediumLevelILFunction>,
pub address: u64,
pub index: usize,
pub size: usize,
pub kind: MediumLevelILInstructionKind,
}
#[derive(Copy, Clone)]
pub enum MediumLevelILInstructionKind {
Nop,
Noret,
Bp,
Undef,
Unimpl,
If(MediumLevelILOperationIf),
FloatConst(FloatConst),
Const(Constant),
ConstPtr(Constant),
Import(Constant),
ExternPtr(ExternPtr),
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),
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),
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),
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),
Load(UnaryOp),
LoadStruct(LoadStruct),
LoadStructSsa(LoadStructSsa),
LoadSsa(LoadSsa),
Ret(Ret),
Var(Var),
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>(),
self.address,
)
}
}
impl MediumLevelILInstruction {
pub(crate) fn new(function: Ref<MediumLevelILFunction>, index: usize) -> Self {
let op = unsafe { BNGetMediumLevelILByIndex(function.handle, index) };
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 {
dest: op.operands[0] as usize,
offset: op.operands[1],
src: op.operands[2] as usize,
}),
MLIL_STORE => Op::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 {
dest: get_var(op.operands[0]),
}),
MLIL_SET_VAR_FIELD => Op::SetVarField(SetVarField {
dest: get_var(op.operands[0]),
offset: op.operands[1],
src: op.operands[2] as usize,
}),
MLIL_SET_VAR => Op::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 {
high: get_var(op.operands[0]),
low: get_var(op.operands[1]),
}),
MLIL_SET_VAR_SPLIT => Op::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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
src: op.operands[0] as usize,
}),
MLIL_FLOOR => Op::Floor(UnaryOp {
src: op.operands[0] as usize,
}),
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],
}),
MLIL_CALL_OUTPUT
| MLIL_CALL_PARAM
| MLIL_CALL_PARAM_SSA
| MLIL_CALL_OUTPUT_SSA
| MLIL_MEMORY_INTRINSIC_OUTPUT_SSA
| MLIL_MEMORY_INTRINSIC_SSA => {
unreachable!()
}
};
Self {
function,
address: op.address,
index,
size: op.size,
kind,
}
}
pub fn lift(&self) -> MediumLevelILLiftedInstruction {
use MediumLevelILInstructionKind::*;
use MediumLevelILLiftedInstructionKind as Lifted;
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,
}),
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),
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,
},
),
}),
Jump(op) => Lifted::Jump(LiftedJump {
dest: self.lift_operand(op.dest),
}),
RetHint(op) => Lifted::RetHint(LiftedJump {
dest: self.lift_operand(op.dest),
}),
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),
}),
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),
}),
StoreStruct(op) => Lifted::StoreStruct(LiftedStoreStruct {
dest: self.lift_operand(op.dest),
offset: op.offset,
src: self.lift_operand(op.src),
}),
Store(op) => Lifted::Store(LiftedStore {
dest: self.lift_operand(op.dest),
src: self.lift_operand(op.src),
}),
JumpTo(op) => Lifted::JumpTo(LiftedJumpTo {
dest: self.lift_operand(op.dest),
targets: OperandIter::new(&*self.function, op.first_operand, op.num_operands)
.pairs()
.collect(),
}),
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),
}),
SetVar(op) => Lifted::SetVar(LiftedSetVar {
dest: op.dest,
src: self.lift_operand(op.src),
}),
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),
}),
SetVarAliasedField(op) => Lifted::SetVarAliasedField(LiftedSetVarSsaField {
dest: op.dest,
prev: op.prev,
offset: op.offset,
src: self.lift_operand(op.src),
}),
SetVarAliased(op) => Lifted::SetVarAliased(LiftedSetVarAliased {
dest: op.dest,
prev: op.prev,
src: self.lift_operand(op.src),
}),
SetVarSsa(op) => Lifted::SetVarSsa(LiftedSetVarSsa {
dest: op.dest,
src: self.lift_operand(op.src),
}),
VarPhi(op) => Lifted::VarPhi(LiftedVarPhi {
dest: op.dest,
src: OperandIter::new(&*self.function, op.first_operand, op.num_operands)
.ssa_vars()
.collect(),
}),
MemPhi(op) => Lifted::MemPhi(LiftedMemPhi {
dest_memory: op.dest_memory,
src_memory: OperandIter::new(&*self.function, op.first_operand, op.num_operands)
.collect(),
}),
VarSplit(op) => Lifted::VarSplit(op),
SetVarSplit(op) => Lifted::SetVarSplit(LiftedSetVarSplit {
high: op.high,
low: op.low,
src: self.lift_operand(op.src),
}),
VarSplitSsa(op) => Lifted::VarSplitSsa(op),
SetVarSplitSsa(op) => Lifted::SetVarSplitSsa(LiftedSetVarSplitSsa {
high: op.high,
low: op.low,
src: self.lift_operand(op.src),
}),
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: CoreIntrinsic(self.function.get_function().arch().0, op.intrinsic),
params: OperandIter::new(&*self.function, op.first_param, op.num_params)
.exprs()
.map(|expr| expr.lift())
.collect(),
}),
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(),
}),
IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa {
output: OperandIter::new(&*self.function, op.first_output, op.num_outputs)
.ssa_vars()
.collect(),
intrinsic: CoreIntrinsic(self.function.get_function().arch().0, op.intrinsic),
params: OperandIter::new(&*self.function, op.first_param, op.num_params)
.exprs()
.map(|expr| expr.lift())
.collect(),
}),
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,
}),
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),
}),
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),
}),
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)),
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),
};
MediumLevelILLiftedInstruction {
function: self.function.clone(),
address: self.address,
index: self.index,
size: self.size,
kind,
}
}
pub fn tokens(&self) -> Array<InstructionTextToken> {
let mut count = 0;
let mut tokens = core::ptr::null_mut();
assert!(unsafe {
BNGetMediumLevelILExprText(
self.function.handle,
self.function.get_function().arch().0,
self.index,
&mut tokens,
&mut count,
core::ptr::null_mut(),
)
});
unsafe { Array::new(tokens, count, ()) }
}
pub fn value(&self) -> RegisterValue {
unsafe { BNGetMediumLevelILExprValue(self.function.handle, self.index) }.into()
}
pub fn possible_values(&self, options: Option<&[DataFlowQueryOption]>) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleExprValues(
self.function.handle,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn possible_ssa_variable_values(
&self,
ssa_var: SSAVariable,
options: Option<&[DataFlowQueryOption]>,
) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleSSAVarValues(
self.function.handle,
&ssa_var.variable.raw(),
ssa_var.version,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn ssa_variable_version(&self, var: Variable) -> SSAVariable {
let version = unsafe {
BNGetMediumLevelILSSAVarVersionAtILInstruction(
self.function.handle,
&var.raw(),
self.index,
)
};
SSAVariable::new(var, version)
}
pub fn branch_dependence(&self) -> Array<BranchDependence> {
let mut count = 0;
let deps = unsafe {
BNGetAllMediumLevelILBranchDependence(self.function.handle, self.index, &mut count)
};
assert!(!deps.is_null());
unsafe { Array::new(deps, count, self.function.clone()) }
}
pub fn branch_dependence_at(&self, instruction: MediumLevelILInstruction) -> BranchDependence {
let deps = unsafe {
BNGetMediumLevelILBranchDependence(self.function.handle, self.index, instruction.index)
};
BranchDependence {
instruction,
dependence: deps,
}
}
pub fn ssa_memory_version(&self) -> usize {
unsafe {
BNGetMediumLevelILSSAMemoryVersionAtILInstruction(self.function.handle, self.index)
}
}
pub fn expr_type(&self) -> Option<Conf<Ref<Type>>> {
let result = unsafe { BNGetMediumLevelILExprType(self.function.handle, self.index) };
(!result.type_.is_null()).then(|| {
Conf::new(
unsafe { Type::ref_from_raw(result.type_) },
result.confidence,
)
})
}
pub fn set_expr_type<'a, T: Into<Conf<&'a Type>>>(&self, value: T) {
let type_: Conf<&'a Type> = value.into();
let mut type_raw: BNTypeWithConfidence = BNTypeWithConfidence {
type_: type_.contents.handle,
confidence: type_.confidence,
};
unsafe { BNSetMediumLevelILExprType(self.function.handle, self.index, &mut type_raw) }
}
pub fn variable_for_register(&self, reg_id: u32) -> Variable {
let result = unsafe {
BNGetMediumLevelILVariableForRegisterAtInstruction(
self.function.handle,
reg_id,
self.index,
)
};
unsafe { Variable::from_raw(result) }
}
pub fn variable_for_flag(&self, flag_id: u32) -> Variable {
let result = unsafe {
BNGetMediumLevelILVariableForFlagAtInstruction(
self.function.handle,
flag_id,
self.index,
)
};
unsafe { Variable::from_raw(result) }
}
pub fn variable_for_stack_location(&self, offset: i64) -> Variable {
let result = unsafe {
BNGetMediumLevelILVariableForStackLocationAtInstruction(
self.function.handle,
offset,
self.index,
)
};
unsafe { Variable::from_raw(result) }
}
pub fn register_value(&self, reg_id: u32) -> RegisterValue {
unsafe {
BNGetMediumLevelILRegisterValueAtInstruction(self.function.handle, reg_id, self.index)
}
.into()
}
pub fn register_value_after(&self, reg_id: u32) -> RegisterValue {
unsafe {
BNGetMediumLevelILRegisterValueAfterInstruction(
self.function.handle,
reg_id,
self.index,
)
}
.into()
}
pub fn possible_register_values(
&self,
reg_id: u32,
options: Option<&[DataFlowQueryOption]>,
) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleRegisterValuesAtInstruction(
self.function.handle,
reg_id,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn possible_register_values_after(
&self,
reg_id: u32,
options: Option<&[DataFlowQueryOption]>,
) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleRegisterValuesAfterInstruction(
self.function.handle,
reg_id,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn flag_value(&self, flag_id: u32) -> RegisterValue {
unsafe {
BNGetMediumLevelILFlagValueAtInstruction(self.function.handle, flag_id, self.index)
}
.into()
}
pub fn flag_value_after(&self, flag_id: u32) -> RegisterValue {
unsafe {
BNGetMediumLevelILFlagValueAfterInstruction(self.function.handle, flag_id, self.index)
}
.into()
}
pub fn possible_flag_values(
&self,
flag_id: u32,
options: Option<&[DataFlowQueryOption]>,
) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleFlagValuesAtInstruction(
self.function.handle,
flag_id,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn possible_flag_values_after(
&self,
flag_id: u32,
options: Option<&[DataFlowQueryOption]>,
) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleFlagValuesAfterInstruction(
self.function.handle,
flag_id,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn stack_contents(&self, offset: i64, size: usize) -> RegisterValue {
unsafe {
BNGetMediumLevelILStackContentsAtInstruction(
self.function.handle,
offset,
size,
self.index,
)
}
.into()
}
pub fn stack_contents_after(&self, offset: i64, size: usize) -> RegisterValue {
unsafe {
BNGetMediumLevelILStackContentsAfterInstruction(
self.function.handle,
offset,
size,
self.index,
)
}
.into()
}
pub fn possible_stack_contents(
&self,
offset: i64,
size: usize,
options: Option<&[DataFlowQueryOption]>,
) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleStackContentsAtInstruction(
self.function.handle,
offset,
size,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn possible_stack_contents_after(
&self,
offset: i64,
size: usize,
options: Option<&[DataFlowQueryOption]>,
) -> PossibleValueSet {
let options_ptr = options
.map(|op| op.as_ptr() as *mut DataFlowQueryOption)
.unwrap_or(core::ptr::null_mut());
let options_len = options.map(|op| op.len()).unwrap_or(0);
let mut value = unsafe {
BNGetMediumLevelILPossibleStackContentsAfterInstruction(
self.function.handle,
offset,
size,
self.index,
options_ptr,
options_len,
)
};
let result = unsafe { PossibleValueSet::from_raw(value) };
unsafe { BNFreePossibleValueSet(&mut value) }
result
}
pub fn split_var_for_definition(&self, var: Variable) -> Variable {
let index = unsafe {
BNGetDefaultIndexForMediumLevelILVariableDefinition(
self.function.handle,
&var.raw(),
self.index,
)
};
Variable::new(var.t, index, var.storage)
}
#[inline]
pub fn get_split_var_for_definition(&self, var: &Variable) -> Variable {
self.split_var_for_definition(*var)
}
fn lift_operand(&self, expr_idx: usize) -> Box<MediumLevelILLiftedInstruction> {
Box::new(self.function.lifted_instruction_from_idx(expr_idx))
}
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),
}
}
fn lift_unary_op(&self, op: UnaryOp) -> LiftedUnaryOp {
LiftedUnaryOp {
src: self.lift_operand(op.src),
}
}
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(),
}
}
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),
}
}
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,
}
}
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),
}
}
}
impl CoreArrayProvider for MediumLevelILInstruction {
type Raw = usize;
type Context = Ref<MediumLevelILFunction>;
type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for MediumLevelILInstruction {
unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
BNFreeILInstructionList(raw)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
context.instruction_from_idx(*raw)
}
}
fn get_float(value: u64, size: usize) -> f64 {
match size {
4 => f32::from_bits(value as u32) as f64,
8 => f64::from_bits(value),
size => todo!("float size {}", size),
}
}
fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction {
unsafe { BNGetMediumLevelILByIndex(function.handle, idx) }
}
fn get_var(id: u64) -> Variable {
unsafe { Variable::from_identifier(id) }
}
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<Item = Variable> {
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<Item = MediumLevelILInstruction> {
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<Item = SSAVariable> {
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<Item = MediumLevelILInstruction> {
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()
}
pub struct BranchDependence {
pub instruction: MediumLevelILInstruction,
pub dependence: ILBranchDependence,
}
impl CoreArrayProvider for BranchDependence {
type Raw = BNILBranchInstructionAndDependence;
type Context = Ref<MediumLevelILFunction>;
type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for BranchDependence {
unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
unsafe { BNFreeILBranchDependenceList(raw) };
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
Self {
instruction: MediumLevelILInstruction::new(context.clone(), raw.branch),
dependence: raw.dependence,
}
}
}