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