Skip to main content

binaryninja/medium_level_il/
instruction.rs

1use super::lift::*;
2use super::operation::*;
3use super::{MediumLevelILBlock, MediumLevelILFunction};
4use crate::architecture::{CoreIntrinsic, FlagId, IntrinsicId, RegisterId};
5use crate::basic_block::BasicBlock;
6use crate::confidence::Conf;
7use crate::disassembly::InstructionTextToken;
8use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
9use crate::types::Type;
10use crate::variable::{ConstantData, PossibleValueSet, RegisterValue, SSAVariable, Variable};
11use crate::{DataFlowQueryOption, ILBranchDependence};
12use binaryninjacore_sys::*;
13use std::collections::BTreeMap;
14use std::fmt;
15use std::fmt::{Debug, Display, Formatter};
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub struct MediumLevelInstructionIndex(pub usize);
19
20impl MediumLevelInstructionIndex {
21    pub fn next(&self) -> Self {
22        Self(self.0 + 1)
23    }
24}
25
26impl From<usize> for MediumLevelInstructionIndex {
27    fn from(index: usize) -> Self {
28        Self(index)
29    }
30}
31
32impl From<u64> for MediumLevelInstructionIndex {
33    fn from(index: u64) -> Self {
34        Self(index as usize)
35    }
36}
37
38impl Display for MediumLevelInstructionIndex {
39    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
40        f.write_fmt(format_args!("{}", self.0))
41    }
42}
43
44#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
45pub struct MediumLevelExpressionIndex(pub usize);
46
47impl MediumLevelExpressionIndex {
48    pub fn next(&self) -> Self {
49        Self(self.0 + 1)
50    }
51}
52
53impl From<usize> for MediumLevelExpressionIndex {
54    fn from(index: usize) -> Self {
55        Self(index)
56    }
57}
58
59impl From<u64> for MediumLevelExpressionIndex {
60    fn from(index: u64) -> Self {
61        Self(index as usize)
62    }
63}
64
65impl Display for MediumLevelExpressionIndex {
66    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
67        f.write_fmt(format_args!("{}", self.0))
68    }
69}
70
71#[derive(Clone)]
72pub struct MediumLevelILInstruction {
73    pub function: Ref<MediumLevelILFunction>,
74    pub address: u64,
75    pub instr_index: MediumLevelInstructionIndex,
76    pub expr_index: MediumLevelExpressionIndex,
77    pub size: usize,
78    pub kind: MediumLevelILInstructionKind,
79}
80
81impl MediumLevelILInstruction {
82    pub(crate) fn from_instr_index(
83        function: Ref<MediumLevelILFunction>,
84        instr_index: MediumLevelInstructionIndex,
85    ) -> Self {
86        // Get the associated expression index for the top-level instruction.
87        let expr_index_raw =
88            unsafe { BNGetMediumLevelILIndexForInstruction(function.handle, instr_index.0) };
89        Self::new(
90            function,
91            instr_index,
92            MediumLevelExpressionIndex(expr_index_raw),
93        )
94    }
95
96    pub(crate) fn from_expr_index(
97        function: Ref<MediumLevelILFunction>,
98        expr_index: MediumLevelExpressionIndex,
99    ) -> Self {
100        // Get the associated top-level instruction index for the expression.
101        let instr_index_raw =
102            unsafe { BNGetMediumLevelILInstructionForExpr(function.handle, expr_index.0) };
103        Self::new(
104            function,
105            MediumLevelInstructionIndex(instr_index_raw),
106            expr_index,
107        )
108    }
109
110    pub(crate) fn new(
111        function: Ref<MediumLevelILFunction>,
112        instr_index: MediumLevelInstructionIndex,
113        expr_index: MediumLevelExpressionIndex,
114    ) -> Self {
115        // TODO: If op.sourceOperation == BN_INVALID_OPERAND && op.operation == MLIL_NOP return None
116        let op = unsafe { BNGetMediumLevelILByIndex(function.handle, expr_index.0) };
117        use BNMediumLevelILOperation::*;
118        use MediumLevelILInstructionKind as Op;
119        let kind = match op.operation {
120            MLIL_NOP => Op::Nop,
121            MLIL_NORET => Op::Noret,
122            MLIL_BP => Op::Bp,
123            MLIL_UNDEF => Op::Undef,
124            MLIL_ASSERT => Op::Assert(Assert {
125                src: get_var(op.operands[0]),
126                constraint_index: op.operands[1] as usize,
127            }),
128            MLIL_ASSERT_SSA => Op::AssertSsa(AssertSsa {
129                src: get_var_ssa(op.operands[0], op.operands[1] as usize),
130                constraint_index: op.operands[2] as usize,
131            }),
132            MLIL_FORCE_VER => Op::ForceVer(ForceVer {
133                dest: get_var(op.operands[0]),
134                src: get_var(op.operands[1]),
135                reason: unsafe {
136                    std::mem::transmute::<u8, ForceVersionReason>(op.operands[2] as u8)
137                },
138            }),
139            MLIL_FORCE_VER_SSA => Op::ForceVerSsa(ForceVerSsa {
140                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
141                src: get_var_ssa(op.operands[2], op.operands[3] as usize),
142                reason: unsafe {
143                    std::mem::transmute::<u8, ForceVersionReason>(op.operands[4] as u8)
144                },
145            }),
146            MLIL_UNIMPL => Op::Unimpl,
147            MLIL_IF => Op::If(MediumLevelILOperationIf {
148                condition: MediumLevelExpressionIndex::from(op.operands[0]),
149                dest_true: MediumLevelInstructionIndex(op.operands[1] as usize),
150                dest_false: MediumLevelInstructionIndex(op.operands[2] as usize),
151            }),
152            MLIL_FLOAT_CONST => Op::FloatConst(FloatConst {
153                constant: get_float(op.operands[0], op.size),
154            }),
155            MLIL_CONST => Op::Const(Constant {
156                constant: op.operands[0],
157            }),
158            MLIL_CONST_PTR => Op::ConstPtr(Constant {
159                constant: op.operands[0],
160            }),
161            MLIL_IMPORT => Op::Import(Constant {
162                constant: op.operands[0],
163            }),
164            MLIL_EXTERN_PTR => Op::ExternPtr(ExternPtr {
165                constant: op.operands[0],
166                offset: op.operands[1],
167            }),
168            MLIL_CONST_DATA => Op::ConstData(ConstData {
169                constant_data_kind: op.operands[0] as u32,
170                constant_data_value: op.operands[1] as i64,
171                size: op.size,
172            }),
173            MLIL_JUMP => Op::Jump(Jump {
174                dest: MediumLevelExpressionIndex::from(op.operands[0]),
175            }),
176            MLIL_RET_HINT => Op::RetHint(Jump {
177                dest: MediumLevelExpressionIndex::from(op.operands[0]),
178            }),
179            MLIL_STORE_SSA => Op::StoreSsa(StoreSsa {
180                dest: MediumLevelExpressionIndex::from(op.operands[0]),
181                dest_memory: op.operands[1],
182                src_memory: op.operands[2],
183                src: MediumLevelExpressionIndex::from(op.operands[3]),
184            }),
185            MLIL_STORE_STRUCT_SSA => Op::StoreStructSsa(StoreStructSsa {
186                dest: MediumLevelExpressionIndex::from(op.operands[0]),
187                offset: op.operands[1],
188                dest_memory: op.operands[2],
189                src_memory: op.operands[3],
190                src: MediumLevelExpressionIndex::from(op.operands[4]),
191            }),
192            MLIL_STORE_STRUCT => Op::StoreStruct(StoreStruct {
193                dest: MediumLevelExpressionIndex::from(op.operands[0]),
194                offset: op.operands[1],
195                src: MediumLevelExpressionIndex::from(op.operands[2]),
196            }),
197            MLIL_STORE => Op::Store(Store {
198                dest: MediumLevelExpressionIndex::from(op.operands[0]),
199                src: MediumLevelExpressionIndex::from(op.operands[1]),
200            }),
201            MLIL_JUMP_TO => Op::JumpTo(JumpTo {
202                dest: MediumLevelExpressionIndex::from(op.operands[0]),
203                num_operands: op.operands[1] as usize,
204                first_operand: op.operands[2] as usize,
205            }),
206            MLIL_GOTO => Op::Goto(Goto {
207                dest: MediumLevelInstructionIndex(op.operands[0] as usize),
208            }),
209            MLIL_FREE_VAR_SLOT => Op::FreeVarSlot(FreeVarSlot {
210                dest: get_var(op.operands[0]),
211            }),
212            MLIL_SET_VAR_FIELD => Op::SetVarField(SetVarField {
213                dest: get_var(op.operands[0]),
214                offset: op.operands[1],
215                src: MediumLevelExpressionIndex::from(op.operands[2]),
216            }),
217            MLIL_SET_VAR => Op::SetVar(SetVar {
218                dest: get_var(op.operands[0]),
219                src: MediumLevelExpressionIndex::from(op.operands[1]),
220            }),
221            MLIL_FREE_VAR_SLOT_SSA => Op::FreeVarSlotSsa(FreeVarSlotSsa {
222                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
223                prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
224            }),
225            MLIL_SET_VAR_SSA_FIELD => Op::SetVarSsaField(SetVarSsaField {
226                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
227                prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
228                offset: op.operands[3],
229                src: MediumLevelExpressionIndex::from(op.operands[4]),
230            }),
231            MLIL_SET_VAR_ALIASED_FIELD => Op::SetVarAliasedField(SetVarSsaField {
232                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
233                prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
234                offset: op.operands[3],
235                src: MediumLevelExpressionIndex::from(op.operands[4]),
236            }),
237            MLIL_SET_VAR_ALIASED => Op::SetVarAliased(SetVarAliased {
238                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
239                prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
240                src: MediumLevelExpressionIndex::from(op.operands[3]),
241            }),
242            MLIL_SET_VAR_SSA => Op::SetVarSsa(SetVarSsa {
243                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
244                src: MediumLevelExpressionIndex::from(op.operands[2]),
245            }),
246            MLIL_VAR_PHI => Op::VarPhi(VarPhi {
247                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
248                num_operands: op.operands[2] as usize,
249                first_operand: op.operands[3] as usize,
250            }),
251            MLIL_MEM_PHI => Op::MemPhi(MemPhi {
252                dest_memory: op.operands[0],
253                num_operands: op.operands[1] as usize,
254                first_operand: op.operands[2] as usize,
255            }),
256            MLIL_VAR_SPLIT => Op::VarSplit(VarSplit {
257                high: get_var(op.operands[0]),
258                low: get_var(op.operands[1]),
259            }),
260            MLIL_SET_VAR_SPLIT => Op::SetVarSplit(SetVarSplit {
261                high: get_var(op.operands[0]),
262                low: get_var(op.operands[1]),
263                src: MediumLevelExpressionIndex::from(op.operands[2]),
264            }),
265            MLIL_VAR_SPLIT_SSA => Op::VarSplitSsa(VarSplitSsa {
266                high: get_var_ssa(op.operands[0], op.operands[1] as usize),
267                low: get_var_ssa(op.operands[2], op.operands[3] as usize),
268            }),
269            MLIL_SET_VAR_SPLIT_SSA => Op::SetVarSplitSsa(SetVarSplitSsa {
270                high: get_var_ssa(op.operands[0], op.operands[1] as usize),
271                low: get_var_ssa(op.operands[2], op.operands[3] as usize),
272                src: MediumLevelExpressionIndex::from(op.operands[4]),
273            }),
274            MLIL_ADD => Op::Add(BinaryOp {
275                left: MediumLevelExpressionIndex::from(op.operands[0]),
276                right: MediumLevelExpressionIndex::from(op.operands[1]),
277            }),
278            MLIL_SUB => Op::Sub(BinaryOp {
279                left: MediumLevelExpressionIndex::from(op.operands[0]),
280                right: MediumLevelExpressionIndex::from(op.operands[1]),
281            }),
282            MLIL_AND => Op::And(BinaryOp {
283                left: MediumLevelExpressionIndex::from(op.operands[0]),
284                right: MediumLevelExpressionIndex::from(op.operands[1]),
285            }),
286            MLIL_OR => Op::Or(BinaryOp {
287                left: MediumLevelExpressionIndex::from(op.operands[0]),
288                right: MediumLevelExpressionIndex::from(op.operands[1]),
289            }),
290            MLIL_XOR => Op::Xor(BinaryOp {
291                left: MediumLevelExpressionIndex::from(op.operands[0]),
292                right: MediumLevelExpressionIndex::from(op.operands[1]),
293            }),
294            MLIL_LSL => Op::Lsl(BinaryOp {
295                left: MediumLevelExpressionIndex::from(op.operands[0]),
296                right: MediumLevelExpressionIndex::from(op.operands[1]),
297            }),
298            MLIL_LSR => Op::Lsr(BinaryOp {
299                left: MediumLevelExpressionIndex::from(op.operands[0]),
300                right: MediumLevelExpressionIndex::from(op.operands[1]),
301            }),
302            MLIL_ASR => Op::Asr(BinaryOp {
303                left: MediumLevelExpressionIndex::from(op.operands[0]),
304                right: MediumLevelExpressionIndex::from(op.operands[1]),
305            }),
306            MLIL_ROL => Op::Rol(BinaryOp {
307                left: MediumLevelExpressionIndex::from(op.operands[0]),
308                right: MediumLevelExpressionIndex::from(op.operands[1]),
309            }),
310            MLIL_ROR => Op::Ror(BinaryOp {
311                left: MediumLevelExpressionIndex::from(op.operands[0]),
312                right: MediumLevelExpressionIndex::from(op.operands[1]),
313            }),
314            MLIL_MUL => Op::Mul(BinaryOp {
315                left: MediumLevelExpressionIndex::from(op.operands[0]),
316                right: MediumLevelExpressionIndex::from(op.operands[1]),
317            }),
318            MLIL_MULU_DP => Op::MuluDp(BinaryOp {
319                left: MediumLevelExpressionIndex::from(op.operands[0]),
320                right: MediumLevelExpressionIndex::from(op.operands[1]),
321            }),
322            MLIL_MULS_DP => Op::MulsDp(BinaryOp {
323                left: MediumLevelExpressionIndex::from(op.operands[0]),
324                right: MediumLevelExpressionIndex::from(op.operands[1]),
325            }),
326            MLIL_DIVU => Op::Divu(BinaryOp {
327                left: MediumLevelExpressionIndex::from(op.operands[0]),
328                right: MediumLevelExpressionIndex::from(op.operands[1]),
329            }),
330            MLIL_DIVU_DP => Op::DivuDp(BinaryOp {
331                left: MediumLevelExpressionIndex::from(op.operands[0]),
332                right: MediumLevelExpressionIndex::from(op.operands[1]),
333            }),
334            MLIL_DIVS => Op::Divs(BinaryOp {
335                left: MediumLevelExpressionIndex::from(op.operands[0]),
336                right: MediumLevelExpressionIndex::from(op.operands[1]),
337            }),
338            MLIL_DIVS_DP => Op::DivsDp(BinaryOp {
339                left: MediumLevelExpressionIndex::from(op.operands[0]),
340                right: MediumLevelExpressionIndex::from(op.operands[1]),
341            }),
342            MLIL_MODU => Op::Modu(BinaryOp {
343                left: MediumLevelExpressionIndex::from(op.operands[0]),
344                right: MediumLevelExpressionIndex::from(op.operands[1]),
345            }),
346            MLIL_MODU_DP => Op::ModuDp(BinaryOp {
347                left: MediumLevelExpressionIndex::from(op.operands[0]),
348                right: MediumLevelExpressionIndex::from(op.operands[1]),
349            }),
350            MLIL_MODS => Op::Mods(BinaryOp {
351                left: MediumLevelExpressionIndex::from(op.operands[0]),
352                right: MediumLevelExpressionIndex::from(op.operands[1]),
353            }),
354            MLIL_MODS_DP => Op::ModsDp(BinaryOp {
355                left: MediumLevelExpressionIndex::from(op.operands[0]),
356                right: MediumLevelExpressionIndex::from(op.operands[1]),
357            }),
358            MLIL_MINS => Op::MinSigned(BinaryOp {
359                left: MediumLevelExpressionIndex::from(op.operands[0]),
360                right: MediumLevelExpressionIndex::from(op.operands[1]),
361            }),
362            MLIL_MAXS => Op::MaxSigned(BinaryOp {
363                left: MediumLevelExpressionIndex::from(op.operands[0]),
364                right: MediumLevelExpressionIndex::from(op.operands[1]),
365            }),
366            MLIL_MINU => Op::MinUnsigned(BinaryOp {
367                left: MediumLevelExpressionIndex::from(op.operands[0]),
368                right: MediumLevelExpressionIndex::from(op.operands[1]),
369            }),
370            MLIL_MAXU => Op::MaxUnsigned(BinaryOp {
371                left: MediumLevelExpressionIndex::from(op.operands[0]),
372                right: MediumLevelExpressionIndex::from(op.operands[1]),
373            }),
374            MLIL_CMP_E => Op::CmpE(BinaryOp {
375                left: MediumLevelExpressionIndex::from(op.operands[0]),
376                right: MediumLevelExpressionIndex::from(op.operands[1]),
377            }),
378            MLIL_CMP_NE => Op::CmpNe(BinaryOp {
379                left: MediumLevelExpressionIndex::from(op.operands[0]),
380                right: MediumLevelExpressionIndex::from(op.operands[1]),
381            }),
382            MLIL_CMP_SLT => Op::CmpSlt(BinaryOp {
383                left: MediumLevelExpressionIndex::from(op.operands[0]),
384                right: MediumLevelExpressionIndex::from(op.operands[1]),
385            }),
386            MLIL_CMP_ULT => Op::CmpUlt(BinaryOp {
387                left: MediumLevelExpressionIndex::from(op.operands[0]),
388                right: MediumLevelExpressionIndex::from(op.operands[1]),
389            }),
390            MLIL_CMP_SLE => Op::CmpSle(BinaryOp {
391                left: MediumLevelExpressionIndex::from(op.operands[0]),
392                right: MediumLevelExpressionIndex::from(op.operands[1]),
393            }),
394            MLIL_CMP_ULE => Op::CmpUle(BinaryOp {
395                left: MediumLevelExpressionIndex::from(op.operands[0]),
396                right: MediumLevelExpressionIndex::from(op.operands[1]),
397            }),
398            MLIL_CMP_SGE => Op::CmpSge(BinaryOp {
399                left: MediumLevelExpressionIndex::from(op.operands[0]),
400                right: MediumLevelExpressionIndex::from(op.operands[1]),
401            }),
402            MLIL_CMP_UGE => Op::CmpUge(BinaryOp {
403                left: MediumLevelExpressionIndex::from(op.operands[0]),
404                right: MediumLevelExpressionIndex::from(op.operands[1]),
405            }),
406            MLIL_CMP_SGT => Op::CmpSgt(BinaryOp {
407                left: MediumLevelExpressionIndex::from(op.operands[0]),
408                right: MediumLevelExpressionIndex::from(op.operands[1]),
409            }),
410            MLIL_CMP_UGT => Op::CmpUgt(BinaryOp {
411                left: MediumLevelExpressionIndex::from(op.operands[0]),
412                right: MediumLevelExpressionIndex::from(op.operands[1]),
413            }),
414            MLIL_TEST_BIT => Op::TestBit(BinaryOp {
415                left: MediumLevelExpressionIndex::from(op.operands[0]),
416                right: MediumLevelExpressionIndex::from(op.operands[1]),
417            }),
418            MLIL_ADD_OVERFLOW => Op::AddOverflow(BinaryOp {
419                left: MediumLevelExpressionIndex::from(op.operands[0]),
420                right: MediumLevelExpressionIndex::from(op.operands[1]),
421            }),
422            MLIL_FCMP_E => Op::FcmpE(BinaryOp {
423                left: MediumLevelExpressionIndex::from(op.operands[0]),
424                right: MediumLevelExpressionIndex::from(op.operands[1]),
425            }),
426            MLIL_FCMP_NE => Op::FcmpNe(BinaryOp {
427                left: MediumLevelExpressionIndex::from(op.operands[0]),
428                right: MediumLevelExpressionIndex::from(op.operands[1]),
429            }),
430            MLIL_FCMP_LT => Op::FcmpLt(BinaryOp {
431                left: MediumLevelExpressionIndex::from(op.operands[0]),
432                right: MediumLevelExpressionIndex::from(op.operands[1]),
433            }),
434            MLIL_FCMP_LE => Op::FcmpLe(BinaryOp {
435                left: MediumLevelExpressionIndex::from(op.operands[0]),
436                right: MediumLevelExpressionIndex::from(op.operands[1]),
437            }),
438            MLIL_FCMP_GE => Op::FcmpGe(BinaryOp {
439                left: MediumLevelExpressionIndex::from(op.operands[0]),
440                right: MediumLevelExpressionIndex::from(op.operands[1]),
441            }),
442            MLIL_FCMP_GT => Op::FcmpGt(BinaryOp {
443                left: MediumLevelExpressionIndex::from(op.operands[0]),
444                right: MediumLevelExpressionIndex::from(op.operands[1]),
445            }),
446            MLIL_FCMP_O => Op::FcmpO(BinaryOp {
447                left: MediumLevelExpressionIndex::from(op.operands[0]),
448                right: MediumLevelExpressionIndex::from(op.operands[1]),
449            }),
450            MLIL_FCMP_UO => Op::FcmpUo(BinaryOp {
451                left: MediumLevelExpressionIndex::from(op.operands[0]),
452                right: MediumLevelExpressionIndex::from(op.operands[1]),
453            }),
454            MLIL_FADD => Op::Fadd(BinaryOp {
455                left: MediumLevelExpressionIndex::from(op.operands[0]),
456                right: MediumLevelExpressionIndex::from(op.operands[1]),
457            }),
458            MLIL_FSUB => Op::Fsub(BinaryOp {
459                left: MediumLevelExpressionIndex::from(op.operands[0]),
460                right: MediumLevelExpressionIndex::from(op.operands[1]),
461            }),
462            MLIL_FMUL => Op::Fmul(BinaryOp {
463                left: MediumLevelExpressionIndex::from(op.operands[0]),
464                right: MediumLevelExpressionIndex::from(op.operands[1]),
465            }),
466            MLIL_FDIV => Op::Fdiv(BinaryOp {
467                left: MediumLevelExpressionIndex::from(op.operands[0]),
468                right: MediumLevelExpressionIndex::from(op.operands[1]),
469            }),
470            MLIL_ADC => Op::Adc(BinaryOpCarry {
471                left: MediumLevelExpressionIndex::from(op.operands[0]),
472                right: MediumLevelExpressionIndex::from(op.operands[1]),
473                carry: MediumLevelExpressionIndex::from(op.operands[2]),
474            }),
475            MLIL_SBB => Op::Sbb(BinaryOpCarry {
476                left: MediumLevelExpressionIndex::from(op.operands[0]),
477                right: MediumLevelExpressionIndex::from(op.operands[1]),
478                carry: MediumLevelExpressionIndex::from(op.operands[2]),
479            }),
480            MLIL_RLC => Op::Rlc(BinaryOpCarry {
481                left: MediumLevelExpressionIndex::from(op.operands[0]),
482                right: MediumLevelExpressionIndex::from(op.operands[1]),
483                carry: MediumLevelExpressionIndex::from(op.operands[2]),
484            }),
485            MLIL_RRC => Op::Rrc(BinaryOpCarry {
486                left: MediumLevelExpressionIndex::from(op.operands[0]),
487                right: MediumLevelExpressionIndex::from(op.operands[1]),
488                carry: MediumLevelExpressionIndex::from(op.operands[2]),
489            }),
490            MLIL_CALL => Op::Call(Call {
491                num_outputs: op.operands[0] as usize,
492                first_output: op.operands[1] as usize,
493                dest: MediumLevelExpressionIndex::from(op.operands[2]),
494                num_params: op.operands[3] as usize,
495                first_param: op.operands[4] as usize,
496            }),
497            MLIL_CALL_PARAM => Op::CallParam(CallParam {
498                num_params: op.operands[0] as usize,
499                first_param: op.operands[1] as usize,
500            }),
501            MLIL_CALL_OUTPUT_SSA => Op::CallOutputSsa(CallOutputSsa {
502                dest_memory: op.operands[0],
503                num_outputs: op.operands[1] as usize,
504                first_output: op.operands[2] as usize,
505            }),
506            MLIL_CALL_PARAM_SSA => Op::CallParamSsa(CallParamSsa {
507                src_memory: op.operands[0],
508                num_params: op.operands[1] as usize,
509                first_param: op.operands[2] as usize,
510            }),
511            MLIL_TAILCALL => Op::Tailcall(Call {
512                num_outputs: op.operands[0] as usize,
513                first_output: op.operands[1] as usize,
514                dest: MediumLevelExpressionIndex::from(op.operands[2]),
515                num_params: op.operands[3] as usize,
516                first_param: op.operands[4] as usize,
517            }),
518            MLIL_SYSCALL => Op::Syscall(Syscall {
519                num_outputs: op.operands[0] as usize,
520                first_output: op.operands[1] as usize,
521                num_params: op.operands[2] as usize,
522                first_param: op.operands[3] as usize,
523            }),
524            MLIL_INTRINSIC => Op::Intrinsic(Intrinsic {
525                num_outputs: op.operands[0] as usize,
526                first_output: op.operands[1] as usize,
527                intrinsic: op.operands[2] as u32,
528                num_params: op.operands[3] as usize,
529                first_param: op.operands[4] as usize,
530            }),
531            MLIL_INTRINSIC_SSA => Op::IntrinsicSsa(IntrinsicSsa {
532                num_outputs: op.operands[0] as usize,
533                first_output: op.operands[1] as usize,
534                intrinsic: op.operands[2] as u32,
535                num_params: op.operands[3] as usize,
536                first_param: op.operands[4] as usize,
537            }),
538            MLIL_MEMORY_INTRINSIC_SSA => Op::MemoryIntrinsicSsa(MemoryIntrinsicSsa {
539                output: MediumLevelExpressionIndex::from(op.operands[0]),
540                intrinsic: op.operands[1] as u32,
541                num_params: op.operands[2] as usize,
542                first_param: op.operands[3] as usize,
543                src_memory: op.operands[4],
544            }),
545            MLIL_MEMORY_INTRINSIC_OUTPUT_SSA => {
546                Op::MemoryIntrinsicOutputSsa(MemoryIntrinsicOutputSsa {
547                    dest_memory: op.operands[0],
548                    num_outputs: op.operands[1] as usize,
549                    first_output: op.operands[2] as usize,
550                })
551            }
552            MLIL_CALL_SSA => Op::CallSsa(CallSsa {
553                output: MediumLevelExpressionIndex::from(op.operands[0]),
554                dest: MediumLevelExpressionIndex::from(op.operands[1]),
555                num_params: op.operands[2] as usize,
556                first_param: op.operands[3] as usize,
557                src_memory: op.operands[4],
558            }),
559            MLIL_TAILCALL_SSA => Op::TailcallSsa(CallSsa {
560                output: MediumLevelExpressionIndex::from(op.operands[0]),
561                dest: MediumLevelExpressionIndex::from(op.operands[1]),
562                num_params: op.operands[2] as usize,
563                first_param: op.operands[3] as usize,
564                src_memory: op.operands[4],
565            }),
566            MLIL_CALL_UNTYPED_SSA => Op::CallUntypedSsa(CallUntypedSsa {
567                output: MediumLevelExpressionIndex::from(op.operands[0]),
568                dest: MediumLevelExpressionIndex::from(op.operands[1]),
569                params: MediumLevelExpressionIndex::from(op.operands[2]),
570                stack: MediumLevelExpressionIndex::from(op.operands[3]),
571            }),
572            MLIL_TAILCALL_UNTYPED_SSA => Op::TailcallUntypedSsa(CallUntypedSsa {
573                output: MediumLevelExpressionIndex::from(op.operands[0]),
574                dest: MediumLevelExpressionIndex::from(op.operands[1]),
575                params: MediumLevelExpressionIndex::from(op.operands[2]),
576                stack: MediumLevelExpressionIndex::from(op.operands[3]),
577            }),
578            MLIL_SYSCALL_SSA => Op::SyscallSsa(SyscallSsa {
579                output: MediumLevelExpressionIndex::from(op.operands[0]),
580                num_params: op.operands[1] as usize,
581                first_param: op.operands[2] as usize,
582                src_memory: op.operands[3],
583            }),
584            MLIL_SYSCALL_UNTYPED_SSA => Op::SyscallUntypedSsa(SyscallUntypedSsa {
585                output: MediumLevelExpressionIndex::from(op.operands[0]),
586                params: MediumLevelExpressionIndex::from(op.operands[1]),
587                stack: MediumLevelExpressionIndex::from(op.operands[2]),
588            }),
589            MLIL_CALL_UNTYPED => Op::CallUntyped(CallUntyped {
590                num_outputs: op.operands[0] as usize,
591                first_output: op.operands[1] as usize,
592                dest: MediumLevelExpressionIndex::from(op.operands[2]),
593                params: MediumLevelExpressionIndex::from(op.operands[3]),
594                stack: MediumLevelExpressionIndex::from(op.operands[4]),
595            }),
596            MLIL_TAILCALL_UNTYPED => Op::TailcallUntyped(CallUntyped {
597                num_outputs: op.operands[0] as usize,
598                first_output: op.operands[1] as usize,
599                dest: MediumLevelExpressionIndex::from(op.operands[2]),
600                params: MediumLevelExpressionIndex::from(op.operands[3]),
601                stack: MediumLevelExpressionIndex::from(op.operands[4]),
602            }),
603            MLIL_SYSCALL_UNTYPED => Op::SyscallUntyped(SyscallUntyped {
604                num_outputs: op.operands[0] as usize,
605                first_output: op.operands[1] as usize,
606                params: MediumLevelExpressionIndex::from(op.operands[2]),
607                stack: MediumLevelExpressionIndex::from(op.operands[3]),
608            }),
609            MLIL_NEG => Op::Neg(UnaryOp {
610                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
611            }),
612            MLIL_NOT => Op::Not(UnaryOp {
613                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
614            }),
615            MLIL_BSWAP => Op::Bswap(UnaryOp {
616                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
617            }),
618            MLIL_POPCNT => Op::Popcnt(UnaryOp {
619                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
620            }),
621            MLIL_CLZ => Op::Clz(UnaryOp {
622                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
623            }),
624            MLIL_CTZ => Op::Ctz(UnaryOp {
625                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
626            }),
627            MLIL_RBIT => Op::Rbit(UnaryOp {
628                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
629            }),
630            MLIL_CLS => Op::Cls(UnaryOp {
631                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
632            }),
633            MLIL_ABS => Op::Abs(UnaryOp {
634                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
635            }),
636            MLIL_SX => Op::Sx(UnaryOp {
637                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
638            }),
639            MLIL_ZX => Op::Zx(UnaryOp {
640                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
641            }),
642            MLIL_LOW_PART => Op::LowPart(UnaryOp {
643                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
644            }),
645            MLIL_BOOL_TO_INT => Op::BoolToInt(UnaryOp {
646                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
647            }),
648            MLIL_UNIMPL_MEM => Op::UnimplMem(UnaryOp {
649                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
650            }),
651            MLIL_FSQRT => Op::Fsqrt(UnaryOp {
652                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
653            }),
654            MLIL_FNEG => Op::Fneg(UnaryOp {
655                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
656            }),
657            MLIL_FABS => Op::Fabs(UnaryOp {
658                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
659            }),
660            MLIL_FLOAT_TO_INT => Op::FloatToInt(UnaryOp {
661                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
662            }),
663            MLIL_INT_TO_FLOAT => Op::IntToFloat(UnaryOp {
664                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
665            }),
666            MLIL_FLOAT_CONV => Op::FloatConv(UnaryOp {
667                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
668            }),
669            MLIL_ROUND_TO_INT => Op::RoundToInt(UnaryOp {
670                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
671            }),
672            MLIL_FLOOR => Op::Floor(UnaryOp {
673                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
674            }),
675            MLIL_CEIL => Op::Ceil(UnaryOp {
676                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
677            }),
678            MLIL_FTRUNC => Op::Ftrunc(UnaryOp {
679                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
680            }),
681            MLIL_LOAD => Op::Load(UnaryOp {
682                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
683            }),
684            MLIL_LOAD_STRUCT => Op::LoadStruct(LoadStruct {
685                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
686                offset: op.operands[1],
687            }),
688            MLIL_LOAD_STRUCT_SSA => Op::LoadStructSsa(LoadStructSsa {
689                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
690                offset: op.operands[1],
691                src_memory: op.operands[2],
692            }),
693            MLIL_LOAD_SSA => Op::LoadSsa(LoadSsa {
694                src: MediumLevelExpressionIndex::from(op.operands[0]),
695                src_memory: op.operands[1],
696            }),
697            MLIL_RET => Op::Ret(Ret {
698                num_operands: op.operands[0] as usize,
699                first_operand: op.operands[1] as usize,
700            }),
701            MLIL_SEPARATE_PARAM_LIST => Op::SeparateParamList(SeparateParamList {
702                num_params: op.operands[0] as usize,
703                first_param: op.operands[1] as usize,
704            }),
705            MLIL_SHARED_PARAM_SLOT => Op::SharedParamSlot(SharedParamSlot {
706                num_params: op.operands[0] as usize,
707                first_param: op.operands[1] as usize,
708            }),
709            MLIL_VAR => Op::Var(Var {
710                src: get_var(op.operands[0]),
711            }),
712            MLIL_VAR_OUTPUT => Op::VarOutput(VarOutput {
713                dest: get_var(op.operands[0]),
714            }),
715            MLIL_VAR_OUTPUT_FIELD => Op::VarOutputField(VarOutputField {
716                dest: get_var(op.operands[0]),
717                offset: op.operands[1],
718            }),
719            MLIL_STORE_OUTPUT => Op::StoreOutput(StoreOutput {
720                dest: MediumLevelExpressionIndex::from(op.operands[0]),
721            }),
722            MLIL_ADDRESS_OF => Op::AddressOf(Var {
723                src: get_var(op.operands[0]),
724            }),
725            MLIL_PASS_BY_REF => Op::PassByRef(UnaryOp {
726                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
727            }),
728            MLIL_RETURN_BY_REF => Op::ReturnByRef(UnaryOp {
729                src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
730            }),
731            MLIL_VAR_FIELD => Op::VarField(Field {
732                src: get_var(op.operands[0]),
733                offset: op.operands[1],
734            }),
735            MLIL_ADDRESS_OF_FIELD => Op::AddressOfField(Field {
736                src: get_var(op.operands[0]),
737                offset: op.operands[1],
738            }),
739            MLIL_VAR_SSA => Op::VarSsa(VarSsa {
740                src: get_var_ssa(op.operands[0], op.operands[1] as usize),
741            }),
742            MLIL_VAR_ALIASED => Op::VarAliased(VarSsa {
743                src: get_var_ssa(op.operands[0], op.operands[1] as usize),
744            }),
745            MLIL_VAR_SSA_FIELD => Op::VarSsaField(VarSsaField {
746                src: get_var_ssa(op.operands[0], op.operands[1] as usize),
747                offset: op.operands[2],
748            }),
749            MLIL_VAR_ALIASED_FIELD => Op::VarAliasedField(VarSsaField {
750                src: get_var_ssa(op.operands[0], op.operands[1] as usize),
751                offset: op.operands[2],
752            }),
753            MLIL_VAR_OUTPUT_SSA => Op::VarOutputSsa(VarOutputSsa {
754                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
755            }),
756            MLIL_VAR_OUTPUT_SSA_FIELD => Op::VarOutputSsaField(VarOutputSsaField {
757                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
758                prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
759                offset: op.operands[3],
760            }),
761            MLIL_VAR_OUTPUT_ALIASED => Op::VarOutputAliased(VarOutputAliased {
762                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
763                prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
764            }),
765            MLIL_VAR_OUTPUT_ALIASED_FIELD => Op::VarOutputAliasedField(VarOutputAliasedField {
766                dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
767                prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
768                offset: op.operands[3],
769            }),
770            MLIL_TRAP => Op::Trap(Trap {
771                vector: op.operands[0],
772            }),
773            MLIL_BLOCK_TO_EXPAND => Op::BlockToExpand(BlockToExpand {
774                num_operands: op.operands[0] as usize,
775                first_operand: op.operands[1] as usize,
776            }),
777        };
778
779        Self {
780            function,
781            address: op.address,
782            instr_index,
783            expr_index,
784            size: op.size,
785            kind,
786        }
787    }
788
789    fn get_operand_list(&self, operand_idx: usize) -> Vec<u64> {
790        let mut count = 0;
791        let raw_list_ptr = unsafe {
792            BNMediumLevelILGetOperandList(
793                self.function.handle,
794                self.expr_index.0,
795                operand_idx,
796                &mut count,
797            )
798        };
799        assert!(!raw_list_ptr.is_null());
800        let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() };
801        unsafe { BNMediumLevelILFreeOperandList(raw_list_ptr) };
802        list
803    }
804
805    fn get_var_list(&self, operand_idx: usize) -> Vec<Variable> {
806        self.get_operand_list(operand_idx)
807            .into_iter()
808            .map(Variable::from_identifier)
809            .collect()
810    }
811
812    fn get_ssa_var_list(&self, operand_idx: usize) -> Vec<SSAVariable> {
813        self.get_operand_list(operand_idx)
814            .chunks(2)
815            .map(|chunk| (Variable::from_identifier(chunk[0]), chunk[1] as usize))
816            .map(|(var, version)| SSAVariable::new(var, version))
817            .collect()
818    }
819
820    fn get_expr_list(&self, operand_idx: usize) -> Vec<MediumLevelILInstruction> {
821        self.get_operand_list(operand_idx)
822            .into_iter()
823            .map(|val| MediumLevelExpressionIndex(val as usize))
824            .filter_map(|idx| self.function.instruction_from_expr_index(idx))
825            .collect()
826    }
827
828    fn get_target_map(&self, operand_idx: usize) -> BTreeMap<u64, MediumLevelInstructionIndex> {
829        self.get_operand_list(operand_idx)
830            .chunks(2)
831            // TODO: This filter is kinda redundant.
832            .filter_map(|chunk| chunk.get(0..2))
833            .map(|chunk| (chunk[0], MediumLevelInstructionIndex(chunk[1] as usize)))
834            .collect()
835    }
836
837    pub fn lift(&self) -> MediumLevelILLiftedInstruction {
838        use MediumLevelILInstructionKind::*;
839        use MediumLevelILLiftedInstructionKind as Lifted;
840
841        let kind = match self.kind {
842            Nop => Lifted::Nop,
843            Noret => Lifted::Noret,
844            Bp => Lifted::Bp,
845            Undef => Lifted::Undef,
846            Unimpl => Lifted::Unimpl,
847            If(op) => Lifted::If(LiftedIf {
848                condition: self.lift_operand(op.condition),
849                dest_true: op.dest_true,
850                dest_false: op.dest_false,
851            }),
852
853            FloatConst(op) => Lifted::FloatConst(op),
854            Const(op) => Lifted::Const(op),
855            ConstPtr(op) => Lifted::ConstPtr(op),
856            Import(op) => Lifted::Import(op),
857            ExternPtr(op) => Lifted::ExternPtr(op),
858
859            ConstData(op) => Lifted::ConstData(LiftedConstData {
860                constant_data: ConstantData::new(
861                    self.function.function(),
862                    RegisterValue {
863                        // TODO: Replace with a From<u32> for RegisterValueType.
864                        // TODO: We might also want to change the type of `op.constant_data_kind`
865                        // TODO: To RegisterValueType and do the conversion when creating instruction.
866                        state: unsafe {
867                            std::mem::transmute::<u32, BNRegisterValueType>(op.constant_data_kind)
868                        },
869                        value: op.constant_data_value,
870                        offset: 0,
871                        size: op.size,
872                    },
873                ),
874            }),
875            Jump(op) => Lifted::Jump(LiftedJump {
876                dest: self.lift_operand(op.dest),
877            }),
878            RetHint(op) => Lifted::RetHint(LiftedJump {
879                dest: self.lift_operand(op.dest),
880            }),
881            StoreSsa(op) => Lifted::StoreSsa(LiftedStoreSsa {
882                dest: self.lift_operand(op.dest),
883                dest_memory: op.dest_memory,
884                src_memory: op.src_memory,
885                src: self.lift_operand(op.src),
886            }),
887            StoreStructSsa(op) => Lifted::StoreStructSsa(LiftedStoreStructSsa {
888                dest: self.lift_operand(op.dest),
889                offset: op.offset,
890                dest_memory: op.dest_memory,
891                src_memory: op.src_memory,
892                src: self.lift_operand(op.src),
893            }),
894            StoreStruct(op) => Lifted::StoreStruct(LiftedStoreStruct {
895                dest: self.lift_operand(op.dest),
896                offset: op.offset,
897                src: self.lift_operand(op.src),
898            }),
899            Store(op) => Lifted::Store(LiftedStore {
900                dest: self.lift_operand(op.dest),
901                src: self.lift_operand(op.src),
902            }),
903            JumpTo(op) => Lifted::JumpTo(LiftedJumpTo {
904                dest: self.lift_operand(op.dest),
905                targets: self.get_target_map(1),
906            }),
907            Goto(op) => Lifted::Goto(op),
908            FreeVarSlot(op) => Lifted::FreeVarSlot(op),
909            SetVarField(op) => Lifted::SetVarField(LiftedSetVarField {
910                dest: op.dest,
911                offset: op.offset,
912                src: self.lift_operand(op.src),
913            }),
914            SetVar(op) => Lifted::SetVar(LiftedSetVar {
915                dest: op.dest,
916                src: self.lift_operand(op.src),
917            }),
918            FreeVarSlotSsa(op) => Lifted::FreeVarSlotSsa(op),
919            SetVarSsaField(op) => Lifted::SetVarSsaField(LiftedSetVarSsaField {
920                dest: op.dest,
921                prev: op.prev,
922                offset: op.offset,
923                src: self.lift_operand(op.src),
924            }),
925            SetVarAliasedField(op) => Lifted::SetVarAliasedField(LiftedSetVarSsaField {
926                dest: op.dest,
927                prev: op.prev,
928                offset: op.offset,
929                src: self.lift_operand(op.src),
930            }),
931            SetVarAliased(op) => Lifted::SetVarAliased(LiftedSetVarAliased {
932                dest: op.dest,
933                prev: op.prev,
934                src: self.lift_operand(op.src),
935            }),
936            SetVarSsa(op) => Lifted::SetVarSsa(LiftedSetVarSsa {
937                dest: op.dest,
938                src: self.lift_operand(op.src),
939            }),
940            VarPhi(op) => Lifted::VarPhi(LiftedVarPhi {
941                dest: op.dest,
942                src: self.get_ssa_var_list(2),
943            }),
944            MemPhi(op) => Lifted::MemPhi(LiftedMemPhi {
945                dest_memory: op.dest_memory,
946                // TODO: Make a stronger type for this.
947                src_memory: self.get_operand_list(1),
948            }),
949            VarSplit(op) => Lifted::VarSplit(op),
950            SetVarSplit(op) => Lifted::SetVarSplit(LiftedSetVarSplit {
951                high: op.high,
952                low: op.low,
953                src: self.lift_operand(op.src),
954            }),
955            VarSplitSsa(op) => Lifted::VarSplitSsa(op),
956            SetVarSplitSsa(op) => Lifted::SetVarSplitSsa(LiftedSetVarSplitSsa {
957                high: op.high,
958                low: op.low,
959                src: self.lift_operand(op.src),
960            }),
961            Assert(op) => Lifted::Assert(LiftedAssert {
962                src: op.src,
963                constraint: PossibleValueSet::from_owned_core_raw(unsafe {
964                    BNGetCachedMediumLevelILPossibleValueSet(
965                        self.function.handle,
966                        op.constraint_index,
967                    )
968                }),
969            }),
970            ForceVer(op) => Lifted::ForceVer(op),
971            AssertSsa(op) => Lifted::AssertSsa(LiftedAssertSsa {
972                src: op.src,
973                constraint: PossibleValueSet::from_owned_core_raw(unsafe {
974                    BNGetCachedMediumLevelILPossibleValueSet(
975                        self.function.handle,
976                        op.constraint_index,
977                    )
978                }),
979            }),
980            ForceVerSsa(op) => Lifted::ForceVerSsa(op),
981
982            Add(op) => Lifted::Add(self.lift_binary_op(op)),
983            Sub(op) => Lifted::Sub(self.lift_binary_op(op)),
984            And(op) => Lifted::And(self.lift_binary_op(op)),
985            Or(op) => Lifted::Or(self.lift_binary_op(op)),
986            Xor(op) => Lifted::Xor(self.lift_binary_op(op)),
987            Lsl(op) => Lifted::Lsl(self.lift_binary_op(op)),
988            Lsr(op) => Lifted::Lsr(self.lift_binary_op(op)),
989            Asr(op) => Lifted::Asr(self.lift_binary_op(op)),
990            Rol(op) => Lifted::Rol(self.lift_binary_op(op)),
991            Ror(op) => Lifted::Ror(self.lift_binary_op(op)),
992            Mul(op) => Lifted::Mul(self.lift_binary_op(op)),
993            MuluDp(op) => Lifted::MuluDp(self.lift_binary_op(op)),
994            MulsDp(op) => Lifted::MulsDp(self.lift_binary_op(op)),
995            Divu(op) => Lifted::Divu(self.lift_binary_op(op)),
996            DivuDp(op) => Lifted::DivuDp(self.lift_binary_op(op)),
997            Divs(op) => Lifted::Divs(self.lift_binary_op(op)),
998            DivsDp(op) => Lifted::DivsDp(self.lift_binary_op(op)),
999            Modu(op) => Lifted::Modu(self.lift_binary_op(op)),
1000            ModuDp(op) => Lifted::ModuDp(self.lift_binary_op(op)),
1001            Mods(op) => Lifted::Mods(self.lift_binary_op(op)),
1002            ModsDp(op) => Lifted::ModsDp(self.lift_binary_op(op)),
1003            MinSigned(op) => Lifted::MinSigned(self.lift_binary_op(op)),
1004            MaxSigned(op) => Lifted::MaxSigned(self.lift_binary_op(op)),
1005            MinUnsigned(op) => Lifted::MinUnsigned(self.lift_binary_op(op)),
1006            MaxUnsigned(op) => Lifted::MaxUnsigned(self.lift_binary_op(op)),
1007            CmpE(op) => Lifted::CmpE(self.lift_binary_op(op)),
1008            CmpNe(op) => Lifted::CmpNe(self.lift_binary_op(op)),
1009            CmpSlt(op) => Lifted::CmpSlt(self.lift_binary_op(op)),
1010            CmpUlt(op) => Lifted::CmpUlt(self.lift_binary_op(op)),
1011            CmpSle(op) => Lifted::CmpSle(self.lift_binary_op(op)),
1012            CmpUle(op) => Lifted::CmpUle(self.lift_binary_op(op)),
1013            CmpSge(op) => Lifted::CmpSge(self.lift_binary_op(op)),
1014            CmpUge(op) => Lifted::CmpUge(self.lift_binary_op(op)),
1015            CmpSgt(op) => Lifted::CmpSgt(self.lift_binary_op(op)),
1016            CmpUgt(op) => Lifted::CmpUgt(self.lift_binary_op(op)),
1017            TestBit(op) => Lifted::TestBit(self.lift_binary_op(op)),
1018            AddOverflow(op) => Lifted::AddOverflow(self.lift_binary_op(op)),
1019            FcmpE(op) => Lifted::FcmpE(self.lift_binary_op(op)),
1020            FcmpNe(op) => Lifted::FcmpNe(self.lift_binary_op(op)),
1021            FcmpLt(op) => Lifted::FcmpLt(self.lift_binary_op(op)),
1022            FcmpLe(op) => Lifted::FcmpLe(self.lift_binary_op(op)),
1023            FcmpGe(op) => Lifted::FcmpGe(self.lift_binary_op(op)),
1024            FcmpGt(op) => Lifted::FcmpGt(self.lift_binary_op(op)),
1025            FcmpO(op) => Lifted::FcmpO(self.lift_binary_op(op)),
1026            FcmpUo(op) => Lifted::FcmpUo(self.lift_binary_op(op)),
1027            Fadd(op) => Lifted::Fadd(self.lift_binary_op(op)),
1028            Fsub(op) => Lifted::Fsub(self.lift_binary_op(op)),
1029            Fmul(op) => Lifted::Fmul(self.lift_binary_op(op)),
1030            Fdiv(op) => Lifted::Fdiv(self.lift_binary_op(op)),
1031
1032            Adc(op) => Lifted::Adc(self.lift_binary_op_carry(op)),
1033            Sbb(op) => Lifted::Sbb(self.lift_binary_op_carry(op)),
1034            Rlc(op) => Lifted::Rlc(self.lift_binary_op_carry(op)),
1035            Rrc(op) => Lifted::Rrc(self.lift_binary_op_carry(op)),
1036
1037            Call(op) => Lifted::Call(self.lift_call(op)),
1038            CallParam(_op) => Lifted::CallParam(LiftedCallParam {
1039                params: self.get_expr_list(0).iter().map(|i| i.lift()).collect(),
1040            }),
1041            CallOutputSsa(op) => Lifted::CallOutputSsa(LiftedCallOutputSsa {
1042                dest_memory: op.dest_memory,
1043                output: self.get_expr_list(1).iter().map(|i| i.lift()).collect(),
1044            }),
1045            CallParamSsa(op) => Lifted::CallParamSsa(LiftedCallParamSsa {
1046                src_memory: op.src_memory,
1047                params: self.get_expr_list(1).iter().map(|i| i.lift()).collect(),
1048            }),
1049
1050            Tailcall(op) => Lifted::Tailcall(self.lift_call(op)),
1051
1052            Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic {
1053                output: self.get_var_list(0),
1054                intrinsic: CoreIntrinsic::new(
1055                    self.function.function().arch(),
1056                    IntrinsicId(op.intrinsic),
1057                )
1058                .expect("Valid intrinsic"),
1059                params: self
1060                    .get_expr_list(3)
1061                    .iter()
1062                    .map(|expr| expr.lift())
1063                    .collect(),
1064            }),
1065            Syscall(_op) => Lifted::Syscall(LiftedSyscallCall {
1066                output: self
1067                    .get_expr_list(0)
1068                    .iter()
1069                    .map(|expr| expr.lift())
1070                    .collect(),
1071                params: self
1072                    .get_expr_list(2)
1073                    .iter()
1074                    .map(|expr| expr.lift())
1075                    .collect(),
1076            }),
1077            IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa {
1078                output: self.get_ssa_var_list(0),
1079                intrinsic: CoreIntrinsic::new(
1080                    self.function.function().arch(),
1081                    IntrinsicId(op.intrinsic),
1082                )
1083                .expect("Valid intrinsic"),
1084                params: self
1085                    .get_expr_list(3)
1086                    .iter()
1087                    .map(|expr| expr.lift())
1088                    .collect(),
1089            }),
1090            MemoryIntrinsicSsa(op) => Lifted::MemoryIntrinsicSsa(LiftedMemoryIntrinsicSsa {
1091                output: self.lift_operand(op.output),
1092                intrinsic: CoreIntrinsic::new(
1093                    self.function.function().arch(),
1094                    IntrinsicId(op.intrinsic),
1095                )
1096                .expect("Valid intrinsic"),
1097                params: self
1098                    .get_expr_list(2)
1099                    .iter()
1100                    .map(|expr| expr.lift())
1101                    .collect(),
1102                src_memory: op.src_memory,
1103            }),
1104            MemoryIntrinsicOutputSsa(op) => {
1105                Lifted::MemoryIntrinsicOutputSsa(LiftedMemoryIntrinsicOutputSsa {
1106                    dest_memory: op.dest_memory,
1107                    output: self.get_ssa_var_list(1),
1108                })
1109            }
1110
1111            CallSsa(op) => Lifted::CallSsa(self.lift_call_ssa(op)),
1112            TailcallSsa(op) => Lifted::TailcallSsa(self.lift_call_ssa(op)),
1113
1114            CallUntypedSsa(op) => Lifted::CallUntypedSsa(self.lift_call_untyped_ssa(op)),
1115            TailcallUntypedSsa(op) => Lifted::TailcallUntypedSsa(self.lift_call_untyped_ssa(op)),
1116
1117            SyscallSsa(op) => {
1118                let output_instr = self
1119                    .function
1120                    .instruction_from_expr_index(op.output)
1121                    .expect("Valid output expression index");
1122                Lifted::SyscallSsa(LiftedSyscallSsa {
1123                    output: get_call_output_ssa(&output_instr)
1124                        .iter()
1125                        .map(|expr| expr.lift())
1126                        .collect(),
1127                    params: self
1128                        .get_expr_list(1)
1129                        .iter()
1130                        .map(|expr| expr.lift())
1131                        .collect(),
1132                    src_memory: op.src_memory,
1133                })
1134            }
1135            SyscallUntypedSsa(op) => {
1136                let output_instr = self
1137                    .function
1138                    .instruction_from_expr_index(op.output)
1139                    .expect("Valid output expression index");
1140                let params_instr = self
1141                    .function
1142                    .instruction_from_expr_index(op.params)
1143                    .expect("Valid params expression index");
1144                Lifted::SyscallUntypedSsa(LiftedSyscallUntypedSsa {
1145                    output: get_call_output_ssa(&output_instr)
1146                        .iter()
1147                        .map(|expr| expr.lift())
1148                        .collect(),
1149                    params: get_call_params_ssa(&params_instr)
1150                        .iter()
1151                        .map(|param| param.lift())
1152                        .collect(),
1153                    stack: self.lift_operand(op.stack),
1154                })
1155            }
1156
1157            CallUntyped(op) => Lifted::CallUntyped(self.lift_call_untyped(op)),
1158            TailcallUntyped(op) => Lifted::TailcallUntyped(self.lift_call_untyped(op)),
1159            SyscallUntyped(op) => {
1160                let params_instr = self
1161                    .function
1162                    .instruction_from_expr_index(op.params)
1163                    .expect("Valid params expression index");
1164                Lifted::SyscallUntyped(LiftedSyscallUntyped {
1165                    output: self
1166                        .get_expr_list(0)
1167                        .iter()
1168                        .map(|expr| expr.lift())
1169                        .collect(),
1170                    params: get_call_params(&params_instr)
1171                        .iter()
1172                        .map(|param| param.lift())
1173                        .collect(),
1174                    stack: self.lift_operand(op.stack),
1175                })
1176            }
1177
1178            Neg(op) => Lifted::Neg(self.lift_unary_op(op)),
1179            Not(op) => Lifted::Not(self.lift_unary_op(op)),
1180            Bswap(op) => Lifted::Bswap(self.lift_unary_op(op)),
1181            Popcnt(op) => Lifted::Popcnt(self.lift_unary_op(op)),
1182            Clz(op) => Lifted::Clz(self.lift_unary_op(op)),
1183            Ctz(op) => Lifted::Ctz(self.lift_unary_op(op)),
1184            Rbit(op) => Lifted::Rbit(self.lift_unary_op(op)),
1185            Cls(op) => Lifted::Cls(self.lift_unary_op(op)),
1186            Abs(op) => Lifted::Abs(self.lift_unary_op(op)),
1187            Sx(op) => Lifted::Sx(self.lift_unary_op(op)),
1188            Zx(op) => Lifted::Zx(self.lift_unary_op(op)),
1189            LowPart(op) => Lifted::LowPart(self.lift_unary_op(op)),
1190            BoolToInt(op) => Lifted::BoolToInt(self.lift_unary_op(op)),
1191            UnimplMem(op) => Lifted::UnimplMem(self.lift_unary_op(op)),
1192            Fsqrt(op) => Lifted::Fsqrt(self.lift_unary_op(op)),
1193            Fneg(op) => Lifted::Fneg(self.lift_unary_op(op)),
1194            Fabs(op) => Lifted::Fabs(self.lift_unary_op(op)),
1195            FloatToInt(op) => Lifted::FloatToInt(self.lift_unary_op(op)),
1196            IntToFloat(op) => Lifted::IntToFloat(self.lift_unary_op(op)),
1197            FloatConv(op) => Lifted::FloatConv(self.lift_unary_op(op)),
1198            RoundToInt(op) => Lifted::RoundToInt(self.lift_unary_op(op)),
1199            Floor(op) => Lifted::Floor(self.lift_unary_op(op)),
1200            Ceil(op) => Lifted::Ceil(self.lift_unary_op(op)),
1201            Ftrunc(op) => Lifted::Ftrunc(self.lift_unary_op(op)),
1202            Load(op) => Lifted::Load(self.lift_unary_op(op)),
1203
1204            LoadStruct(op) => Lifted::LoadStruct(LiftedLoadStruct {
1205                src: self.lift_operand(op.src),
1206                offset: op.offset,
1207            }),
1208            LoadStructSsa(op) => Lifted::LoadStructSsa(LiftedLoadStructSsa {
1209                src: self.lift_operand(op.src),
1210                offset: op.offset,
1211                src_memory: op.src_memory,
1212            }),
1213            LoadSsa(op) => Lifted::LoadSsa(LiftedLoadSsa {
1214                src: self.lift_operand(op.src),
1215                src_memory: op.src_memory,
1216            }),
1217            Ret(_op) => Lifted::Ret(LiftedRet {
1218                src: self
1219                    .get_expr_list(0)
1220                    .iter()
1221                    .map(|expr| expr.lift())
1222                    .collect(),
1223            }),
1224            SeparateParamList(_op) => Lifted::SeparateParamList(LiftedSeparateParamList {
1225                params: self
1226                    .get_expr_list(0)
1227                    .iter()
1228                    .map(|expr| expr.lift())
1229                    .collect(),
1230            }),
1231            SharedParamSlot(_op) => Lifted::SharedParamSlot(LiftedSharedParamSlot {
1232                params: self
1233                    .get_expr_list(0)
1234                    .iter()
1235                    .map(|expr| expr.lift())
1236                    .collect(),
1237            }),
1238            Var(op) => Lifted::Var(op),
1239            VarOutput(op) => Lifted::VarOutput(op),
1240            VarOutputField(op) => Lifted::VarOutputField(op),
1241            StoreOutput(op) => Lifted::StoreOutput(LiftedStoreOutput {
1242                dest: self.lift_operand(op.dest),
1243            }),
1244            AddressOf(op) => Lifted::AddressOf(op),
1245            PassByRef(op) => Lifted::PassByRef(self.lift_unary_op(op)),
1246            ReturnByRef(op) => Lifted::ReturnByRef(self.lift_unary_op(op)),
1247            VarField(op) => Lifted::VarField(op),
1248            AddressOfField(op) => Lifted::AddressOfField(op),
1249            VarSsa(op) => Lifted::VarSsa(op),
1250            VarAliased(op) => Lifted::VarAliased(op),
1251            VarSsaField(op) => Lifted::VarSsaField(op),
1252            VarAliasedField(op) => Lifted::VarAliasedField(op),
1253            VarOutputSsa(op) => Lifted::VarOutputSsa(op),
1254            VarOutputSsaField(op) => Lifted::VarOutputSsaField(op),
1255            VarOutputAliased(op) => Lifted::VarOutputAliased(op),
1256            VarOutputAliasedField(op) => Lifted::VarOutputAliasedField(op),
1257            Trap(op) => Lifted::Trap(op),
1258            BlockToExpand(_op) => Lifted::BlockToExpand(LiftedBlockToExpand {
1259                exprs: self
1260                    .get_expr_list(0)
1261                    .iter()
1262                    .map(|expr| expr.lift())
1263                    .collect(),
1264            }),
1265        };
1266
1267        MediumLevelILLiftedInstruction {
1268            function: self.function.clone(),
1269            address: self.address,
1270            instr_index: self.instr_index,
1271            expr_index: self.expr_index,
1272            size: self.size,
1273            kind,
1274        }
1275    }
1276
1277    pub fn tokens(&self) -> Array<InstructionTextToken> {
1278        let mut count = 0;
1279        let mut tokens = core::ptr::null_mut();
1280        assert!(unsafe {
1281            BNGetMediumLevelILExprText(
1282                self.function.handle,
1283                self.function.function().arch().handle,
1284                self.expr_index.0,
1285                &mut tokens,
1286                &mut count,
1287                core::ptr::null_mut(),
1288            )
1289        });
1290        unsafe { Array::new(tokens, count, ()) }
1291    }
1292
1293    /// Value of expression if constant or a known value
1294    pub fn value(&self) -> RegisterValue {
1295        unsafe { BNGetMediumLevelILExprValue(self.function.handle, self.expr_index.0) }.into()
1296    }
1297
1298    /// Returns the [`BasicBlock`] containing the given [`MediumLevelILInstruction`].
1299    pub fn basic_block(&self) -> Option<Ref<BasicBlock<MediumLevelILBlock>>> {
1300        // TODO: We might be able to .expect this if we guarantee that self.index is valid.
1301        self.function.basic_block_containing_index(self.instr_index)
1302    }
1303
1304    /// Possible values of expression using path-sensitive static data flow analysis
1305    pub fn possible_values(&self) -> PossibleValueSet {
1306        self.possible_values_with_opts(&[])
1307    }
1308
1309    /// Possible values of expression using path-sensitive static data flow analysis
1310    pub fn possible_values_with_opts(&self, options: &[DataFlowQueryOption]) -> PossibleValueSet {
1311        let value = unsafe {
1312            BNGetMediumLevelILPossibleExprValues(
1313                self.function.handle,
1314                self.expr_index.0,
1315                options.as_ptr() as *mut _,
1316                options.len(),
1317            )
1318        };
1319        PossibleValueSet::from_owned_core_raw(value)
1320    }
1321
1322    pub fn possible_ssa_variable_values(&self, ssa_var: &SSAVariable) -> PossibleValueSet {
1323        self.possible_ssa_variable_values_with_opts(ssa_var, &[])
1324    }
1325
1326    pub fn possible_ssa_variable_values_with_opts(
1327        &self,
1328        ssa_var: &SSAVariable,
1329        options: &[DataFlowQueryOption],
1330    ) -> PossibleValueSet {
1331        let raw_var = BNVariable::from(ssa_var.variable);
1332        let value = unsafe {
1333            BNGetMediumLevelILPossibleSSAVarValues(
1334                self.function.handle,
1335                &raw_var,
1336                ssa_var.version,
1337                self.instr_index.0,
1338                options.as_ptr() as *mut _,
1339                options.len(),
1340            )
1341        };
1342        PossibleValueSet::from_owned_core_raw(value)
1343    }
1344
1345    /// Return the ssa version of a [`Variable`] at the given instruction.
1346    pub fn ssa_variable_version(&self, var: Variable) -> SSAVariable {
1347        let raw_var = BNVariable::from(var);
1348        let version = unsafe {
1349            BNGetMediumLevelILSSAVarVersionAtILInstruction(
1350                self.function.handle,
1351                &raw_var,
1352                self.instr_index.0,
1353            )
1354        };
1355        SSAVariable::new(var, version)
1356    }
1357
1358    /// Return the ssa version of a [`Variable`] after the given instruction.
1359    pub fn ssa_variable_version_after(&self, var: Variable) -> SSAVariable {
1360        let raw_var = BNVariable::from(var);
1361        let version = unsafe {
1362            BNGetMediumLevelILSSAVarVersionAfterILInstruction(
1363                self.function.handle,
1364                &raw_var,
1365                self.instr_index.0,
1366            )
1367        };
1368        SSAVariable::new(var, version)
1369    }
1370
1371    /// Set of branching instructions that must take the true or false path to reach this instruction
1372    pub fn branch_dependencies(&self) -> Array<BranchDependence> {
1373        let mut count = 0;
1374        let deps = unsafe {
1375            BNGetAllMediumLevelILBranchDependence(
1376                self.function.handle,
1377                self.instr_index.0,
1378                &mut count,
1379            )
1380        };
1381        assert!(!deps.is_null());
1382        unsafe { Array::new(deps, count, self.function.clone()) }
1383    }
1384
1385    pub fn branch_dependence_at(
1386        &self,
1387        branch_instruction: MediumLevelILInstruction,
1388    ) -> BranchDependence {
1389        let deps = unsafe {
1390            BNGetMediumLevelILBranchDependence(
1391                self.function.handle,
1392                self.instr_index.0,
1393                branch_instruction.instr_index.0,
1394            )
1395        };
1396        BranchDependence {
1397            instruction: branch_instruction,
1398            dependence: deps,
1399        }
1400    }
1401
1402    /// Version of active memory contents in SSA form for this instruction
1403    pub fn ssa_memory_version(&self) -> usize {
1404        unsafe {
1405            BNGetMediumLevelILSSAMemoryVersionAtILInstruction(
1406                self.function.handle,
1407                self.instr_index.0,
1408            )
1409        }
1410    }
1411
1412    /// Version of active memory contents in SSA form for this instruction
1413    pub fn ssa_memory_version_after(&self) -> usize {
1414        unsafe {
1415            BNGetMediumLevelILSSAMemoryVersionAfterILInstruction(
1416                self.function.handle,
1417                self.instr_index.0,
1418            )
1419        }
1420    }
1421
1422    /// Type of expression
1423    pub fn expr_type(&self) -> Option<Conf<Ref<Type>>> {
1424        let result = unsafe { BNGetMediumLevelILExprType(self.function.handle, self.expr_index.0) };
1425        (!result.type_.is_null()).then(|| Conf::<Ref<Type>>::from_owned_raw(result))
1426    }
1427
1428    /// Set type of expression
1429    ///
1430    /// This API is only meant for workflows or for debugging purposes, since the changes they make are not persistent
1431    /// and get lost after a database save and reload. To make persistent changes to the analysis, one should use other
1432    /// APIs to, for example, change the type of variables. The analysis will then propagate the type of the variable
1433    /// and update the type of related expressions.
1434    pub fn set_expr_type<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) {
1435        let mut ty: BNTypeWithConfidence = Conf::<&Type>::into_raw(ty.into());
1436        unsafe { BNSetMediumLevelILExprType(self.function.handle, self.expr_index.0, &mut ty) }
1437    }
1438
1439    pub fn variable_for_register(&self, reg_id: RegisterId) -> Variable {
1440        let result = unsafe {
1441            BNGetMediumLevelILVariableForRegisterAtInstruction(
1442                self.function.handle,
1443                reg_id.0,
1444                self.instr_index.0,
1445            )
1446        };
1447        Variable::from(result)
1448    }
1449
1450    pub fn variable_for_register_after(&self, reg_id: RegisterId) -> Variable {
1451        let result = unsafe {
1452            BNGetMediumLevelILVariableForRegisterAfterInstruction(
1453                self.function.handle,
1454                reg_id.0,
1455                self.instr_index.0,
1456            )
1457        };
1458        Variable::from(result)
1459    }
1460
1461    pub fn variable_for_flag(&self, flag_id: FlagId) -> Variable {
1462        let result = unsafe {
1463            BNGetMediumLevelILVariableForFlagAtInstruction(
1464                self.function.handle,
1465                flag_id.0,
1466                self.instr_index.0,
1467            )
1468        };
1469        Variable::from(result)
1470    }
1471
1472    pub fn variable_for_flag_after(&self, flag_id: FlagId) -> Variable {
1473        let result = unsafe {
1474            BNGetMediumLevelILVariableForFlagAfterInstruction(
1475                self.function.handle,
1476                flag_id.0,
1477                self.instr_index.0,
1478            )
1479        };
1480        Variable::from(result)
1481    }
1482
1483    pub fn variable_for_stack_location(&self, offset: i64) -> Variable {
1484        let result = unsafe {
1485            BNGetMediumLevelILVariableForStackLocationAtInstruction(
1486                self.function.handle,
1487                offset,
1488                self.instr_index.0,
1489            )
1490        };
1491        Variable::from(result)
1492    }
1493
1494    pub fn variable_for_stack_location_after(&self, offset: i64) -> Variable {
1495        let result = unsafe {
1496            BNGetMediumLevelILVariableForStackLocationAfterInstruction(
1497                self.function.handle,
1498                offset,
1499                self.instr_index.0,
1500            )
1501        };
1502        Variable::from(result)
1503    }
1504
1505    pub fn register_value(&self, reg_id: RegisterId) -> RegisterValue {
1506        unsafe {
1507            BNGetMediumLevelILRegisterValueAtInstruction(
1508                self.function.handle,
1509                reg_id.0,
1510                self.instr_index.0,
1511            )
1512        }
1513        .into()
1514    }
1515
1516    pub fn register_value_after(&self, reg_id: RegisterId) -> RegisterValue {
1517        unsafe {
1518            BNGetMediumLevelILRegisterValueAfterInstruction(
1519                self.function.handle,
1520                reg_id.0,
1521                self.instr_index.0,
1522            )
1523        }
1524        .into()
1525    }
1526
1527    pub fn possible_register_values(&self, reg_id: RegisterId) -> PossibleValueSet {
1528        self.possible_register_values_with_opts(reg_id, &[])
1529    }
1530
1531    pub fn possible_register_values_with_opts(
1532        &self,
1533        reg_id: RegisterId,
1534        options: &[DataFlowQueryOption],
1535    ) -> PossibleValueSet {
1536        let value = unsafe {
1537            BNGetMediumLevelILPossibleRegisterValuesAtInstruction(
1538                self.function.handle,
1539                reg_id.0,
1540                self.instr_index.0,
1541                options.as_ptr() as *mut _,
1542                options.len(),
1543            )
1544        };
1545        PossibleValueSet::from_owned_core_raw(value)
1546    }
1547
1548    pub fn possible_register_values_after(&self, reg_id: RegisterId) -> PossibleValueSet {
1549        self.possible_register_values_after_with_opts(reg_id, &[])
1550    }
1551
1552    pub fn possible_register_values_after_with_opts(
1553        &self,
1554        reg_id: RegisterId,
1555        options: &[DataFlowQueryOption],
1556    ) -> PossibleValueSet {
1557        let value = unsafe {
1558            BNGetMediumLevelILPossibleRegisterValuesAfterInstruction(
1559                self.function.handle,
1560                reg_id.0,
1561                self.instr_index.0,
1562                options.as_ptr() as *mut _,
1563                options.len(),
1564            )
1565        };
1566        PossibleValueSet::from_owned_core_raw(value)
1567    }
1568
1569    pub fn flag_value(&self, flag_id: FlagId) -> RegisterValue {
1570        unsafe {
1571            BNGetMediumLevelILFlagValueAtInstruction(
1572                self.function.handle,
1573                flag_id.0,
1574                self.instr_index.0,
1575            )
1576        }
1577        .into()
1578    }
1579
1580    pub fn flag_value_after(&self, flag_id: FlagId) -> RegisterValue {
1581        unsafe {
1582            BNGetMediumLevelILFlagValueAfterInstruction(
1583                self.function.handle,
1584                flag_id.0,
1585                self.instr_index.0,
1586            )
1587        }
1588        .into()
1589    }
1590
1591    pub fn possible_flag_values(&self, flag_id: FlagId) -> PossibleValueSet {
1592        self.possible_flag_values_with_opts(flag_id, &[])
1593    }
1594
1595    pub fn possible_flag_values_with_opts(
1596        &self,
1597        flag_id: FlagId,
1598        options: &[DataFlowQueryOption],
1599    ) -> PossibleValueSet {
1600        let value = unsafe {
1601            BNGetMediumLevelILPossibleFlagValuesAtInstruction(
1602                self.function.handle,
1603                flag_id.0,
1604                self.instr_index.0,
1605                options.as_ptr() as *mut _,
1606                options.len(),
1607            )
1608        };
1609        PossibleValueSet::from_owned_core_raw(value)
1610    }
1611
1612    pub fn possible_flag_values_after_with_opts(
1613        &self,
1614        flag_id: FlagId,
1615        options: &[DataFlowQueryOption],
1616    ) -> PossibleValueSet {
1617        let value = unsafe {
1618            BNGetMediumLevelILPossibleFlagValuesAfterInstruction(
1619                self.function.handle,
1620                flag_id.0,
1621                self.instr_index.0,
1622                options.as_ptr() as *mut _,
1623                options.len(),
1624            )
1625        };
1626        PossibleValueSet::from_owned_core_raw(value)
1627    }
1628
1629    pub fn stack_contents(&self, offset: i64, size: usize) -> RegisterValue {
1630        unsafe {
1631            BNGetMediumLevelILStackContentsAtInstruction(
1632                self.function.handle,
1633                offset,
1634                size,
1635                self.instr_index.0,
1636            )
1637        }
1638        .into()
1639    }
1640
1641    pub fn stack_contents_after(&self, offset: i64, size: usize) -> RegisterValue {
1642        unsafe {
1643            BNGetMediumLevelILStackContentsAfterInstruction(
1644                self.function.handle,
1645                offset,
1646                size,
1647                self.instr_index.0,
1648            )
1649        }
1650        .into()
1651    }
1652
1653    pub fn possible_stack_contents_with_opts(
1654        &self,
1655        offset: i64,
1656        size: usize,
1657        options: &[DataFlowQueryOption],
1658    ) -> PossibleValueSet {
1659        let value = unsafe {
1660            BNGetMediumLevelILPossibleStackContentsAtInstruction(
1661                self.function.handle,
1662                offset,
1663                size,
1664                self.instr_index.0,
1665                options.as_ptr() as *mut _,
1666                options.len(),
1667            )
1668        };
1669        PossibleValueSet::from_owned_core_raw(value)
1670    }
1671
1672    pub fn possible_stack_contents_after_with_opts(
1673        &self,
1674        offset: i64,
1675        size: usize,
1676        options: &[DataFlowQueryOption],
1677    ) -> PossibleValueSet {
1678        let value = unsafe {
1679            BNGetMediumLevelILPossibleStackContentsAfterInstruction(
1680                self.function.handle,
1681                offset,
1682                size,
1683                self.instr_index.0,
1684                options.as_ptr() as *mut _,
1685                options.len(),
1686            )
1687        };
1688        PossibleValueSet::from_owned_core_raw(value)
1689    }
1690
1691    /// Gets the unique variable for a definition instruction. This unique variable can be passed
1692    /// to [crate::function::Function::split_variable] to split a variable at a definition. The given `var` is the
1693    /// assigned variable to query.
1694    ///
1695    /// * `var` - variable to query
1696    pub fn split_var_for_definition(&self, var: &Variable) -> Variable {
1697        let raw_var = BNVariable::from(var);
1698        let index = unsafe {
1699            BNGetDefaultIndexForMediumLevelILVariableDefinition(
1700                self.function.handle,
1701                &raw_var,
1702                self.instr_index.0,
1703            )
1704        };
1705        Variable::new(var.ty, index, var.storage)
1706    }
1707
1708    fn lift_operand(
1709        &self,
1710        expr_idx: MediumLevelExpressionIndex,
1711    ) -> Box<MediumLevelILLiftedInstruction> {
1712        let operand_instr = self
1713            .function
1714            .instruction_from_expr_index(expr_idx)
1715            .expect("Invalid operand expression index");
1716        Box::new(operand_instr.lift())
1717    }
1718
1719    fn lift_binary_op(&self, op: BinaryOp) -> LiftedBinaryOp {
1720        LiftedBinaryOp {
1721            left: self.lift_operand(op.left),
1722            right: self.lift_operand(op.right),
1723        }
1724    }
1725
1726    fn lift_binary_op_carry(&self, op: BinaryOpCarry) -> LiftedBinaryOpCarry {
1727        LiftedBinaryOpCarry {
1728            left: self.lift_operand(op.left),
1729            right: self.lift_operand(op.right),
1730            carry: self.lift_operand(op.carry),
1731        }
1732    }
1733
1734    fn lift_unary_op(&self, op: UnaryOp) -> LiftedUnaryOp {
1735        LiftedUnaryOp {
1736            src: self.lift_operand(op.src),
1737        }
1738    }
1739
1740    fn lift_call(&self, op: Call) -> LiftedCall {
1741        LiftedCall {
1742            output: self
1743                .get_expr_list(0)
1744                .iter()
1745                .map(|expr| expr.lift())
1746                .collect(),
1747            dest: self.lift_operand(op.dest),
1748            params: self
1749                .get_expr_list(3)
1750                .iter()
1751                .map(|expr| expr.lift())
1752                .collect(),
1753        }
1754    }
1755
1756    fn lift_call_untyped(&self, op: CallUntyped) -> LiftedCallUntyped {
1757        let params_instr = self
1758            .function
1759            .instruction_from_expr_index(op.params)
1760            .expect("Valid params expression index");
1761        LiftedCallUntyped {
1762            output: self
1763                .get_expr_list(0)
1764                .iter()
1765                .map(|expr| expr.lift())
1766                .collect(),
1767            dest: self.lift_operand(op.dest),
1768            params: get_call_params(&params_instr)
1769                .iter()
1770                .map(|expr| expr.lift())
1771                .collect(),
1772            stack: self.lift_operand(op.stack),
1773        }
1774    }
1775
1776    fn lift_call_ssa(&self, op: CallSsa) -> LiftedCallSsa {
1777        let output_instr = self
1778            .function
1779            .instruction_from_expr_index(op.output)
1780            .expect("Valid output expression index");
1781        LiftedCallSsa {
1782            output: get_call_output_ssa(&output_instr)
1783                .iter()
1784                .map(|expr| expr.lift())
1785                .collect(),
1786            dest: self.lift_operand(op.dest),
1787            params: self
1788                .get_expr_list(2)
1789                .iter()
1790                .map(|expr| expr.lift())
1791                .collect(),
1792            src_memory: op.src_memory,
1793        }
1794    }
1795
1796    fn lift_call_untyped_ssa(&self, op: CallUntypedSsa) -> LiftedCallUntypedSsa {
1797        let output_instr = self
1798            .function
1799            .instruction_from_expr_index(op.output)
1800            .expect("Valid output expression index");
1801        let params_instr = self
1802            .function
1803            .instruction_from_expr_index(op.params)
1804            .expect("Valid params expression index");
1805        LiftedCallUntypedSsa {
1806            output: get_call_output_ssa(&output_instr)
1807                .iter()
1808                .map(|expr| expr.lift())
1809                .collect(),
1810            dest: self.lift_operand(op.dest),
1811            params: get_call_params_ssa(&params_instr)
1812                .iter()
1813                .map(|param| param.lift())
1814                .collect(),
1815            stack: self.lift_operand(op.stack),
1816        }
1817    }
1818}
1819
1820impl Debug for MediumLevelILInstruction {
1821    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1822        f.debug_struct("MediumLevelILInstruction")
1823            .field("address", &self.address)
1824            .field("instr_index", &self.instr_index)
1825            .field("expr_index", &self.expr_index)
1826            .field("size", &self.size)
1827            .field("kind", &self.kind)
1828            .finish()
1829    }
1830}
1831
1832impl CoreArrayProvider for MediumLevelILInstruction {
1833    type Raw = usize;
1834    type Context = Ref<MediumLevelILFunction>;
1835    type Wrapped<'a> = Self;
1836}
1837
1838unsafe impl CoreArrayProviderInner for MediumLevelILInstruction {
1839    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
1840        BNFreeILInstructionList(raw)
1841    }
1842
1843    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
1844        context
1845            .instruction_from_index(MediumLevelInstructionIndex(*raw))
1846            .unwrap()
1847    }
1848}
1849
1850#[derive(Debug, Copy, Clone)]
1851pub enum MediumLevelILInstructionKind {
1852    Nop,
1853    Noret,
1854    Bp,
1855    Undef,
1856    Unimpl,
1857    If(MediumLevelILOperationIf),
1858    FloatConst(FloatConst),
1859    Const(Constant),
1860    ConstPtr(Constant),
1861    Import(Constant),
1862    ExternPtr(ExternPtr),
1863    ConstData(ConstData),
1864    Jump(Jump),
1865    RetHint(Jump),
1866    StoreSsa(StoreSsa),
1867    StoreStructSsa(StoreStructSsa),
1868    StoreStruct(StoreStruct),
1869    Store(Store),
1870    JumpTo(JumpTo),
1871    Goto(Goto),
1872    FreeVarSlot(FreeVarSlot),
1873    SetVarField(SetVarField),
1874    SetVar(SetVar),
1875    FreeVarSlotSsa(FreeVarSlotSsa),
1876    SetVarSsaField(SetVarSsaField),
1877    SetVarAliasedField(SetVarSsaField),
1878    SetVarAliased(SetVarAliased),
1879    SetVarSsa(SetVarSsa),
1880    VarPhi(VarPhi),
1881    MemPhi(MemPhi),
1882    VarSplit(VarSplit),
1883    SetVarSplit(SetVarSplit),
1884    Assert(Assert),
1885    ForceVer(ForceVer),
1886    VarSplitSsa(VarSplitSsa),
1887    SetVarSplitSsa(SetVarSplitSsa),
1888    AssertSsa(AssertSsa),
1889    ForceVerSsa(ForceVerSsa),
1890    Add(BinaryOp),
1891    Sub(BinaryOp),
1892    And(BinaryOp),
1893    Or(BinaryOp),
1894    Xor(BinaryOp),
1895    Lsl(BinaryOp),
1896    Lsr(BinaryOp),
1897    Asr(BinaryOp),
1898    Rol(BinaryOp),
1899    Ror(BinaryOp),
1900    Mul(BinaryOp),
1901    MuluDp(BinaryOp),
1902    MulsDp(BinaryOp),
1903    Divu(BinaryOp),
1904    DivuDp(BinaryOp),
1905    Divs(BinaryOp),
1906    DivsDp(BinaryOp),
1907    Modu(BinaryOp),
1908    ModuDp(BinaryOp),
1909    Mods(BinaryOp),
1910    ModsDp(BinaryOp),
1911    MinSigned(BinaryOp),
1912    MaxSigned(BinaryOp),
1913    MinUnsigned(BinaryOp),
1914    MaxUnsigned(BinaryOp),
1915    CmpE(BinaryOp),
1916    CmpNe(BinaryOp),
1917    CmpSlt(BinaryOp),
1918    CmpUlt(BinaryOp),
1919    CmpSle(BinaryOp),
1920    CmpUle(BinaryOp),
1921    CmpSge(BinaryOp),
1922    CmpUge(BinaryOp),
1923    CmpSgt(BinaryOp),
1924    CmpUgt(BinaryOp),
1925    TestBit(BinaryOp),
1926    AddOverflow(BinaryOp),
1927    FcmpE(BinaryOp),
1928    FcmpNe(BinaryOp),
1929    FcmpLt(BinaryOp),
1930    FcmpLe(BinaryOp),
1931    FcmpGe(BinaryOp),
1932    FcmpGt(BinaryOp),
1933    FcmpO(BinaryOp),
1934    FcmpUo(BinaryOp),
1935    Fadd(BinaryOp),
1936    Fsub(BinaryOp),
1937    Fmul(BinaryOp),
1938    Fdiv(BinaryOp),
1939    Adc(BinaryOpCarry),
1940    Sbb(BinaryOpCarry),
1941    Rlc(BinaryOpCarry),
1942    Rrc(BinaryOpCarry),
1943    Call(Call),
1944    CallParam(CallParam),
1945    CallOutputSsa(CallOutputSsa),
1946    CallParamSsa(CallParamSsa),
1947    Tailcall(Call),
1948    Syscall(Syscall),
1949    Intrinsic(Intrinsic),
1950    IntrinsicSsa(IntrinsicSsa),
1951    MemoryIntrinsicSsa(MemoryIntrinsicSsa),
1952    MemoryIntrinsicOutputSsa(MemoryIntrinsicOutputSsa),
1953    CallSsa(CallSsa),
1954    TailcallSsa(CallSsa),
1955    CallUntypedSsa(CallUntypedSsa),
1956    TailcallUntypedSsa(CallUntypedSsa),
1957    SyscallSsa(SyscallSsa),
1958    SyscallUntypedSsa(SyscallUntypedSsa),
1959    CallUntyped(CallUntyped),
1960    TailcallUntyped(CallUntyped),
1961    SyscallUntyped(SyscallUntyped),
1962    SeparateParamList(SeparateParamList),
1963    SharedParamSlot(SharedParamSlot),
1964    VarOutput(VarOutput),
1965    VarOutputField(VarOutputField),
1966    StoreOutput(StoreOutput),
1967    Neg(UnaryOp),
1968    Not(UnaryOp),
1969    Bswap(UnaryOp),
1970    Popcnt(UnaryOp),
1971    Clz(UnaryOp),
1972    Ctz(UnaryOp),
1973    Rbit(UnaryOp),
1974    Cls(UnaryOp),
1975    Abs(UnaryOp),
1976    Sx(UnaryOp),
1977    Zx(UnaryOp),
1978    LowPart(UnaryOp),
1979    BoolToInt(UnaryOp),
1980    UnimplMem(UnaryOp),
1981    Fsqrt(UnaryOp),
1982    Fneg(UnaryOp),
1983    Fabs(UnaryOp),
1984    FloatToInt(UnaryOp),
1985    IntToFloat(UnaryOp),
1986    FloatConv(UnaryOp),
1987    RoundToInt(UnaryOp),
1988    Floor(UnaryOp),
1989    Ceil(UnaryOp),
1990    Ftrunc(UnaryOp),
1991    Load(UnaryOp),
1992    LoadStruct(LoadStruct),
1993    LoadStructSsa(LoadStructSsa),
1994    LoadSsa(LoadSsa),
1995    Ret(Ret),
1996    Var(Var),
1997    AddressOf(Var),
1998    PassByRef(UnaryOp),
1999    ReturnByRef(UnaryOp),
2000    VarField(Field),
2001    AddressOfField(Field),
2002    VarSsa(VarSsa),
2003    VarAliased(VarSsa),
2004    VarSsaField(VarSsaField),
2005    VarAliasedField(VarSsaField),
2006    VarOutputSsa(VarOutputSsa),
2007    VarOutputSsaField(VarOutputSsaField),
2008    VarOutputAliased(VarOutputAliased),
2009    VarOutputAliasedField(VarOutputAliasedField),
2010    Trap(Trap),
2011    BlockToExpand(BlockToExpand),
2012}
2013
2014fn get_float(value: u64, size: usize) -> f64 {
2015    match size {
2016        4 => f32::from_bits(value as u32) as f64,
2017        8 => f64::from_bits(value),
2018        // TODO how to handle this value?
2019        size => todo!("float size {}", size),
2020    }
2021}
2022
2023fn get_var(id: u64) -> Variable {
2024    Variable::from_identifier(id)
2025}
2026
2027fn get_var_ssa(id: u64, version: usize) -> SSAVariable {
2028    SSAVariable::new(get_var(id), version)
2029}
2030
2031fn get_call_params(instr: &MediumLevelILInstruction) -> Vec<MediumLevelILInstruction> {
2032    match instr.kind {
2033        MediumLevelILInstructionKind::CallParam(_op) => instr.get_expr_list(0),
2034        _ => vec![],
2035    }
2036}
2037
2038fn get_call_output_ssa(instr: &MediumLevelILInstruction) -> Vec<MediumLevelILInstruction> {
2039    match instr.kind {
2040        MediumLevelILInstructionKind::CallOutputSsa(_op) => instr.get_expr_list(1),
2041        _ => vec![],
2042    }
2043}
2044
2045fn get_call_params_ssa(instr: &MediumLevelILInstruction) -> Vec<MediumLevelILInstruction> {
2046    match instr.kind {
2047        MediumLevelILInstructionKind::CallParamSsa(_op) => instr.get_expr_list(1),
2048        _ => vec![],
2049    }
2050}
2051
2052/// Conditional branching instruction and an expected conditional result
2053pub struct BranchDependence {
2054    pub instruction: MediumLevelILInstruction,
2055    pub dependence: ILBranchDependence,
2056}
2057
2058impl CoreArrayProvider for BranchDependence {
2059    type Raw = BNILBranchInstructionAndDependence;
2060    type Context = Ref<MediumLevelILFunction>;
2061    type Wrapped<'a> = Self;
2062}
2063
2064unsafe impl CoreArrayProviderInner for BranchDependence {
2065    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
2066        unsafe { BNFreeILBranchDependenceList(raw) };
2067    }
2068
2069    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
2070        Self {
2071            instruction: MediumLevelILInstruction::from_instr_index(
2072                context.clone(),
2073                MediumLevelInstructionIndex(raw.branch),
2074            ),
2075            dependence: raw.dependence,
2076        }
2077    }
2078}