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