binaryninja/low_level_il/
lifting.rs

1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::marker::PhantomData;
16
17use binaryninjacore_sys::{BNAddLowLevelILLabelForAddress, BNLowLevelILOperation};
18use binaryninjacore_sys::{BNLowLevelILLabel, BNRegisterOrConstant};
19
20use super::*;
21use crate::architecture::{Architecture, FlagWriteId, RegisterId};
22use crate::architecture::{CoreRegister, Register as ArchReg};
23use crate::architecture::{
24    Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite, Intrinsic,
25};
26use crate::function::Location;
27
28pub trait LiftableLowLevelIL<'func> {
29    type Result: ExpressionResultType;
30
31    fn lift(
32        il: &'func LowLevelILMutableFunction,
33        expr: Self,
34    ) -> LowLevelILMutableExpression<'func, Self::Result>;
35}
36
37pub trait LiftableLowLevelILWithSize<'func>: LiftableLowLevelIL<'func, Result = ValueExpr> {
38    fn lift_with_size(
39        il: &'func LowLevelILMutableFunction,
40        expr: Self,
41        size: usize,
42    ) -> LowLevelILMutableExpression<'func, ValueExpr>;
43}
44
45#[derive(Copy, Clone)]
46pub enum LowLevelILRegisterOrConstant<R: ArchReg> {
47    Register(usize, LowLevelILRegisterKind<R>),
48    Constant(usize, u64),
49}
50
51impl<R: ArchReg> From<LowLevelILRegisterOrConstant<R>> for BNRegisterOrConstant {
52    fn from(value: LowLevelILRegisterOrConstant<R>) -> Self {
53        match value {
54            LowLevelILRegisterOrConstant::Register(_, r) => Self {
55                constant: false,
56                reg: r.id().0,
57                value: 0,
58            },
59            LowLevelILRegisterOrConstant::Constant(_, value) => Self {
60                constant: true,
61                reg: 0,
62                value,
63            },
64        }
65    }
66}
67
68// TODO flesh way out
69#[derive(Copy, Clone)]
70pub enum LowLevelILFlagWriteOp<R: ArchReg> {
71    SetReg(usize, LowLevelILRegisterOrConstant<R>),
72    SetRegSplit(
73        usize,
74        LowLevelILRegisterOrConstant<R>,
75        LowLevelILRegisterOrConstant<R>,
76    ),
77
78    Sub(
79        usize,
80        LowLevelILRegisterOrConstant<R>,
81        LowLevelILRegisterOrConstant<R>,
82    ),
83    Add(
84        usize,
85        LowLevelILRegisterOrConstant<R>,
86        LowLevelILRegisterOrConstant<R>,
87    ),
88
89    Load(usize, LowLevelILRegisterOrConstant<R>),
90
91    Push(usize, LowLevelILRegisterOrConstant<R>),
92    Neg(usize, LowLevelILRegisterOrConstant<R>),
93    Not(usize, LowLevelILRegisterOrConstant<R>),
94    Sx(usize, LowLevelILRegisterOrConstant<R>),
95    Zx(usize, LowLevelILRegisterOrConstant<R>),
96    LowPart(usize, LowLevelILRegisterOrConstant<R>),
97    BoolToInt(usize, LowLevelILRegisterOrConstant<R>),
98    FloatToInt(usize, LowLevelILRegisterOrConstant<R>),
99
100    Store(
101        usize,
102        LowLevelILRegisterOrConstant<R>,
103        LowLevelILRegisterOrConstant<R>,
104    ),
105
106    And(
107        usize,
108        LowLevelILRegisterOrConstant<R>,
109        LowLevelILRegisterOrConstant<R>,
110    ),
111    Or(
112        usize,
113        LowLevelILRegisterOrConstant<R>,
114        LowLevelILRegisterOrConstant<R>,
115    ),
116    Xor(
117        usize,
118        LowLevelILRegisterOrConstant<R>,
119        LowLevelILRegisterOrConstant<R>,
120    ),
121    Lsl(
122        usize,
123        LowLevelILRegisterOrConstant<R>,
124        LowLevelILRegisterOrConstant<R>,
125    ),
126    Lsr(
127        usize,
128        LowLevelILRegisterOrConstant<R>,
129        LowLevelILRegisterOrConstant<R>,
130    ),
131    Asr(
132        usize,
133        LowLevelILRegisterOrConstant<R>,
134        LowLevelILRegisterOrConstant<R>,
135    ),
136    Rol(
137        usize,
138        LowLevelILRegisterOrConstant<R>,
139        LowLevelILRegisterOrConstant<R>,
140    ),
141    Ror(
142        usize,
143        LowLevelILRegisterOrConstant<R>,
144        LowLevelILRegisterOrConstant<R>,
145    ),
146    Mul(
147        usize,
148        LowLevelILRegisterOrConstant<R>,
149        LowLevelILRegisterOrConstant<R>,
150    ),
151    MuluDp(
152        usize,
153        LowLevelILRegisterOrConstant<R>,
154        LowLevelILRegisterOrConstant<R>,
155    ),
156    MulsDp(
157        usize,
158        LowLevelILRegisterOrConstant<R>,
159        LowLevelILRegisterOrConstant<R>,
160    ),
161    Divu(
162        usize,
163        LowLevelILRegisterOrConstant<R>,
164        LowLevelILRegisterOrConstant<R>,
165    ),
166    Divs(
167        usize,
168        LowLevelILRegisterOrConstant<R>,
169        LowLevelILRegisterOrConstant<R>,
170    ),
171    Modu(
172        usize,
173        LowLevelILRegisterOrConstant<R>,
174        LowLevelILRegisterOrConstant<R>,
175    ),
176    Mods(
177        usize,
178        LowLevelILRegisterOrConstant<R>,
179        LowLevelILRegisterOrConstant<R>,
180    ),
181    DivuDp(
182        usize,
183        LowLevelILRegisterOrConstant<R>,
184        LowLevelILRegisterOrConstant<R>,
185    ),
186    DivsDp(
187        usize,
188        LowLevelILRegisterOrConstant<R>,
189        LowLevelILRegisterOrConstant<R>,
190    ),
191    ModuDp(
192        usize,
193        LowLevelILRegisterOrConstant<R>,
194        LowLevelILRegisterOrConstant<R>,
195    ),
196    ModsDp(
197        usize,
198        LowLevelILRegisterOrConstant<R>,
199        LowLevelILRegisterOrConstant<R>,
200    ),
201
202    TestBit(
203        usize,
204        LowLevelILRegisterOrConstant<R>,
205        LowLevelILRegisterOrConstant<R>,
206    ),
207    AddOverflow(
208        usize,
209        LowLevelILRegisterOrConstant<R>,
210        LowLevelILRegisterOrConstant<R>,
211    ),
212
213    Adc(
214        usize,
215        LowLevelILRegisterOrConstant<R>,
216        LowLevelILRegisterOrConstant<R>,
217        LowLevelILRegisterOrConstant<R>,
218    ),
219    Sbb(
220        usize,
221        LowLevelILRegisterOrConstant<R>,
222        LowLevelILRegisterOrConstant<R>,
223        LowLevelILRegisterOrConstant<R>,
224    ),
225    Rlc(
226        usize,
227        LowLevelILRegisterOrConstant<R>,
228        LowLevelILRegisterOrConstant<R>,
229        LowLevelILRegisterOrConstant<R>,
230    ),
231    Rrc(
232        usize,
233        LowLevelILRegisterOrConstant<R>,
234        LowLevelILRegisterOrConstant<R>,
235        LowLevelILRegisterOrConstant<R>,
236    ),
237
238    Pop(usize),
239    // TODO: floating point stuff, llil comparison ops that set flags, intrinsics
240}
241
242impl<R: ArchReg> LowLevelILFlagWriteOp<R> {
243    pub(crate) fn from_op<A>(
244        arch: &A,
245        size: usize,
246        op: BNLowLevelILOperation,
247        operands: &[BNRegisterOrConstant],
248    ) -> Option<Self>
249    where
250        A: Architecture<Register = R>,
251        R: ArchReg<InfoType = A::RegisterInfo>,
252    {
253        use self::LowLevelILFlagWriteOp::*;
254        use binaryninjacore_sys::BNLowLevelILOperation::*;
255
256        fn build_op<A, R>(
257            arch: &A,
258            size: usize,
259            operand: &BNRegisterOrConstant,
260        ) -> LowLevelILRegisterOrConstant<R>
261        where
262            A: Architecture<Register = R>,
263            R: ArchReg<InfoType = A::RegisterInfo>,
264        {
265            if operand.constant {
266                LowLevelILRegisterOrConstant::Constant(size, operand.value)
267            } else {
268                let raw_id = RegisterId(operand.reg);
269                let il_reg =
270                    LowLevelILRegisterKind::from_raw(arch, raw_id).expect("Bad register ID");
271                LowLevelILRegisterOrConstant::Register(size, il_reg)
272            }
273        }
274
275        macro_rules! op {
276            ($x:ident, $($ops:expr),*) => {
277                ( $x(size, $( build_op(arch, size, &operands[$ops]), )* ) )
278            };
279        }
280
281        Some(match (operands.len(), op) {
282            (1, LLIL_SET_REG) => op!(SetReg, 0),
283            (2, LLIL_SET_REG_SPLIT) => op!(SetRegSplit, 0, 1),
284
285            (2, LLIL_SUB) => op!(Sub, 0, 1),
286            (2, LLIL_ADD) => op!(Add, 0, 1),
287
288            (1, LLIL_LOAD) => op!(Load, 0),
289
290            (1, LLIL_PUSH) => op!(Push, 0),
291            (1, LLIL_NEG) => op!(Neg, 0),
292            (1, LLIL_NOT) => op!(Not, 0),
293            (1, LLIL_SX) => op!(Sx, 0),
294            (1, LLIL_ZX) => op!(Zx, 0),
295            (1, LLIL_LOW_PART) => op!(LowPart, 0),
296            (1, LLIL_BOOL_TO_INT) => op!(BoolToInt, 0),
297            (1, LLIL_FLOAT_TO_INT) => op!(FloatToInt, 0),
298
299            (2, LLIL_STORE) => op!(Store, 0, 1),
300
301            (2, LLIL_AND) => op!(And, 0, 1),
302            (2, LLIL_OR) => op!(Or, 0, 1),
303            (2, LLIL_XOR) => op!(Xor, 0, 1),
304            (2, LLIL_LSL) => op!(Lsl, 0, 1),
305            (2, LLIL_LSR) => op!(Lsr, 0, 1),
306            (2, LLIL_ASR) => op!(Asr, 0, 1),
307            (2, LLIL_ROL) => op!(Rol, 0, 1),
308            (2, LLIL_ROR) => op!(Ror, 0, 1),
309            (2, LLIL_MUL) => op!(Mul, 0, 1),
310            (2, LLIL_MULU_DP) => op!(MuluDp, 0, 1),
311            (2, LLIL_MULS_DP) => op!(MulsDp, 0, 1),
312            (2, LLIL_DIVU) => op!(Divu, 0, 1),
313            (2, LLIL_DIVS) => op!(Divs, 0, 1),
314            (2, LLIL_MODU) => op!(Modu, 0, 1),
315            (2, LLIL_MODS) => op!(Mods, 0, 1),
316            (2, LLIL_DIVU_DP) => op!(DivuDp, 0, 1),
317            (2, LLIL_DIVS_DP) => op!(DivsDp, 0, 1),
318            (2, LLIL_MODU_DP) => op!(ModuDp, 0, 1),
319            (2, LLIL_MODS_DP) => op!(ModsDp, 0, 1),
320
321            (2, LLIL_TEST_BIT) => op!(TestBit, 0, 1),
322            (2, LLIL_ADD_OVERFLOW) => op!(AddOverflow, 0, 1),
323
324            (3, LLIL_ADC) => op!(Adc, 0, 1, 2),
325            (3, LLIL_SBB) => op!(Sbb, 0, 1, 2),
326            (3, LLIL_RLC) => op!(Rlc, 0, 1, 2),
327            (3, LLIL_RRC) => op!(Rrc, 0, 1, 2),
328
329            (0, LLIL_POP) => op!(Pop,),
330
331            _ => return None,
332        })
333    }
334
335    pub(crate) fn size_and_op(&self) -> (usize, BNLowLevelILOperation) {
336        use self::LowLevelILFlagWriteOp::*;
337        use binaryninjacore_sys::BNLowLevelILOperation::*;
338
339        match *self {
340            SetReg(size, ..) => (size, LLIL_SET_REG),
341            SetRegSplit(size, ..) => (size, LLIL_SET_REG_SPLIT),
342
343            Sub(size, ..) => (size, LLIL_SUB),
344            Add(size, ..) => (size, LLIL_ADD),
345
346            Load(size, ..) => (size, LLIL_LOAD),
347
348            Push(size, ..) => (size, LLIL_PUSH),
349            Neg(size, ..) => (size, LLIL_NEG),
350            Not(size, ..) => (size, LLIL_NOT),
351            Sx(size, ..) => (size, LLIL_SX),
352            Zx(size, ..) => (size, LLIL_ZX),
353            LowPart(size, ..) => (size, LLIL_LOW_PART),
354            BoolToInt(size, ..) => (size, LLIL_BOOL_TO_INT),
355            FloatToInt(size, ..) => (size, LLIL_FLOAT_TO_INT),
356
357            Store(size, ..) => (size, LLIL_STORE),
358
359            And(size, ..) => (size, LLIL_AND),
360            Or(size, ..) => (size, LLIL_OR),
361            Xor(size, ..) => (size, LLIL_XOR),
362            Lsl(size, ..) => (size, LLIL_LSL),
363            Lsr(size, ..) => (size, LLIL_LSR),
364            Asr(size, ..) => (size, LLIL_ASR),
365            Rol(size, ..) => (size, LLIL_ROL),
366            Ror(size, ..) => (size, LLIL_ROR),
367            Mul(size, ..) => (size, LLIL_MUL),
368            MuluDp(size, ..) => (size, LLIL_MULU_DP),
369            MulsDp(size, ..) => (size, LLIL_MULS_DP),
370            Divu(size, ..) => (size, LLIL_DIVU),
371            Divs(size, ..) => (size, LLIL_DIVS),
372            Modu(size, ..) => (size, LLIL_MODU),
373            Mods(size, ..) => (size, LLIL_MODS),
374            DivuDp(size, ..) => (size, LLIL_DIVU_DP),
375            DivsDp(size, ..) => (size, LLIL_DIVS_DP),
376            ModuDp(size, ..) => (size, LLIL_MODU_DP),
377            ModsDp(size, ..) => (size, LLIL_MODS_DP),
378
379            TestBit(size, ..) => (size, LLIL_TEST_BIT),
380            AddOverflow(size, ..) => (size, LLIL_ADD_OVERFLOW),
381
382            Adc(size, ..) => (size, LLIL_ADC),
383            Sbb(size, ..) => (size, LLIL_SBB),
384            Rlc(size, ..) => (size, LLIL_RLC),
385            Rrc(size, ..) => (size, LLIL_RRC),
386
387            Pop(size) => (size, LLIL_POP),
388        }
389    }
390
391    pub(crate) fn raw_operands(&self) -> (usize, [BNRegisterOrConstant; 5]) {
392        use self::LowLevelILFlagWriteOp::*;
393
394        let mut operands: [BNRegisterOrConstant; 5] = [BNRegisterOrConstant::default(); 5];
395
396        let count = match *self {
397            Pop(_) => 0,
398
399            SetReg(_, op0)
400            | Load(_, op0)
401            | Push(_, op0)
402            | Neg(_, op0)
403            | Not(_, op0)
404            | Sx(_, op0)
405            | Zx(_, op0)
406            | LowPart(_, op0)
407            | BoolToInt(_, op0)
408            | FloatToInt(_, op0) => {
409                operands[0] = op0.into();
410                1
411            }
412
413            SetRegSplit(_, op0, op1)
414            | Sub(_, op0, op1)
415            | Add(_, op0, op1)
416            | Store(_, op0, op1)
417            | And(_, op0, op1)
418            | Or(_, op0, op1)
419            | Xor(_, op0, op1)
420            | Lsl(_, op0, op1)
421            | Lsr(_, op0, op1)
422            | Asr(_, op0, op1)
423            | Rol(_, op0, op1)
424            | Ror(_, op0, op1)
425            | Mul(_, op0, op1)
426            | MuluDp(_, op0, op1)
427            | MulsDp(_, op0, op1)
428            | Divu(_, op0, op1)
429            | Divs(_, op0, op1)
430            | Modu(_, op0, op1)
431            | Mods(_, op0, op1)
432            | DivuDp(_, op0, op1)
433            | DivsDp(_, op0, op1)
434            | ModuDp(_, op0, op1)
435            | ModsDp(_, op0, op1)
436            | TestBit(_, op0, op1)
437            | AddOverflow(_, op0, op1) => {
438                operands[0] = op0.into();
439                operands[1] = op1.into();
440                2
441            }
442
443            Adc(_, op0, op1, op2)
444            | Sbb(_, op0, op1, op2)
445            | Rlc(_, op0, op1, op2)
446            | Rrc(_, op0, op1, op2) => {
447                operands[0] = op0.into();
448                operands[1] = op1.into();
449                operands[2] = op2.into();
450                3
451            }
452        };
453
454        (count, operands)
455    }
456}
457
458pub fn get_default_flag_write_llil<'func, A>(
459    arch: &A,
460    role: FlagRole,
461    op: LowLevelILFlagWriteOp<A::Register>,
462    il: &'func LowLevelILMutableFunction,
463) -> LowLevelILMutableExpression<'func, ValueExpr>
464where
465    A: 'func + Architecture,
466{
467    let (size, operation) = op.size_and_op();
468    let (count, operands) = op.raw_operands();
469
470    let expr_idx = unsafe {
471        use binaryninjacore_sys::BNGetDefaultArchitectureFlagWriteLowLevelIL;
472        BNGetDefaultArchitectureFlagWriteLowLevelIL(
473            arch.as_ref().handle,
474            operation,
475            size,
476            role,
477            operands.as_ptr() as *mut _,
478            count,
479            il.handle,
480        )
481    };
482
483    LowLevelILExpression::new(il, LowLevelExpressionIndex(expr_idx))
484}
485
486pub fn get_default_flag_cond_llil<'func, A>(
487    arch: &A,
488    cond: FlagCondition,
489    class: Option<A::FlagClass>,
490    il: &'func LowLevelILMutableFunction,
491) -> LowLevelILMutableExpression<'func, ValueExpr>
492where
493    A: 'func + Architecture,
494{
495    use binaryninjacore_sys::BNGetDefaultArchitectureFlagConditionLowLevelIL;
496    let class_id = class.map(|c| c.id().0).unwrap_or(0);
497
498    unsafe {
499        let expr_idx = BNGetDefaultArchitectureFlagConditionLowLevelIL(
500            arch.as_ref().handle,
501            cond,
502            class_id,
503            il.handle,
504        );
505
506        LowLevelILExpression::new(il, LowLevelExpressionIndex(expr_idx))
507    }
508}
509
510macro_rules! prim_int_lifter {
511    ($x:ty) => {
512        impl<'a> LiftableLowLevelIL<'a> for $x {
513            type Result = ValueExpr;
514
515            fn lift(il: &'a LowLevelILMutableFunction, val: Self)
516                -> LowLevelILMutableExpression<'a, Self::Result>
517            {
518                il.const_int(std::mem::size_of::<Self>(), val as i64 as u64)
519            }
520        }
521
522        impl<'a> LiftableLowLevelILWithSize<'a> for $x {
523            fn lift_with_size(il: &'a LowLevelILMutableFunction, val: Self, size: usize)
524                -> LowLevelILMutableExpression<'a, ValueExpr>
525            {
526                let raw = val as i64;
527
528                #[cfg(debug_assertions)]
529                {
530                    let is_safe = match raw.overflowing_shr(size as u32 * 8) {
531                        (_, true) => true,
532                        (res, false) => [-1, 0].contains(&res),
533                    };
534
535                    if !is_safe {
536                        log::error!("il @ {:x} attempted to lift constant 0x{:x} as {} byte expr (won't fit!)",
537                               il.current_address(), val, size);
538                    }
539                }
540
541                il.const_int(size, raw as u64)
542            }
543        }
544    }
545}
546
547prim_int_lifter!(i8);
548prim_int_lifter!(i16);
549prim_int_lifter!(i32);
550prim_int_lifter!(i64);
551
552prim_int_lifter!(u8);
553prim_int_lifter!(u16);
554prim_int_lifter!(u32);
555prim_int_lifter!(u64);
556
557impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILRegisterKind<R>
558where
559    R: LiftableLowLevelIL<'a, Result = ValueExpr> + Into<LowLevelILRegisterKind<R>> + ArchReg,
560{
561    type Result = ValueExpr;
562
563    fn lift(
564        il: &'a LowLevelILMutableFunction,
565        reg: Self,
566    ) -> LowLevelILMutableExpression<'a, Self::Result> {
567        match reg {
568            LowLevelILRegisterKind::Arch(r) => R::lift(il, r),
569            LowLevelILRegisterKind::Temp(t) => il.reg(
570                il.arch().default_integer_size(),
571                LowLevelILRegisterKind::Temp::<R>(t),
572            ),
573        }
574    }
575}
576
577impl<'a, R> LiftableLowLevelILWithSize<'a> for LowLevelILRegisterKind<R>
578where
579    R: LiftableLowLevelILWithSize<'a> + Into<LowLevelILRegisterKind<R>> + ArchReg,
580{
581    fn lift_with_size(
582        il: &'a LowLevelILMutableFunction,
583        reg: Self,
584        size: usize,
585    ) -> LowLevelILMutableExpression<'a, ValueExpr> {
586        match reg {
587            LowLevelILRegisterKind::Arch(r) => R::lift_with_size(il, r, size),
588            LowLevelILRegisterKind::Temp(t) => il.reg(size, LowLevelILRegisterKind::<R>::Temp(t)),
589        }
590    }
591}
592
593impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILRegisterOrConstant<R>
594where
595    R: LiftableLowLevelILWithSize<'a, Result = ValueExpr>
596        + Into<LowLevelILRegisterKind<R>>
597        + ArchReg,
598{
599    type Result = ValueExpr;
600
601    fn lift(
602        il: &'a LowLevelILMutableFunction,
603        reg: Self,
604    ) -> LowLevelILMutableExpression<'a, Self::Result> {
605        match reg {
606            LowLevelILRegisterOrConstant::Register(size, r) => {
607                LowLevelILRegisterKind::<R>::lift_with_size(il, r, size)
608            }
609            LowLevelILRegisterOrConstant::Constant(size, value) => {
610                u64::lift_with_size(il, value, size)
611            }
612        }
613    }
614}
615
616impl<'a, R> LiftableLowLevelILWithSize<'a> for LowLevelILRegisterOrConstant<R>
617where
618    R: LiftableLowLevelILWithSize<'a> + Into<LowLevelILRegisterKind<R>> + ArchReg,
619{
620    fn lift_with_size(
621        il: &'a LowLevelILMutableFunction,
622        reg: Self,
623        size: usize,
624    ) -> LowLevelILMutableExpression<'a, ValueExpr> {
625        // TODO ensure requested size is compatible with size of this constant
626        match reg {
627            LowLevelILRegisterOrConstant::Register(_, r) => {
628                LowLevelILRegisterKind::<R>::lift_with_size(il, r, size)
629            }
630            LowLevelILRegisterOrConstant::Constant(_, value) => {
631                u64::lift_with_size(il, value, size)
632            }
633        }
634    }
635}
636
637impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILExpression<'a, Mutable, NonSSA, R>
638where
639    R: ExpressionResultType,
640{
641    type Result = R;
642
643    fn lift(
644        il: &'a LowLevelILMutableFunction,
645        expr: Self,
646    ) -> LowLevelILMutableExpression<'a, Self::Result> {
647        debug_assert!(expr.function.handle == il.handle);
648        expr
649    }
650}
651
652impl<'a> LiftableLowLevelILWithSize<'a> for LowLevelILExpression<'a, Mutable, NonSSA, ValueExpr> {
653    fn lift_with_size(
654        il: &'a LowLevelILMutableFunction,
655        expr: Self,
656        _size: usize,
657    ) -> LowLevelILMutableExpression<'a, Self::Result> {
658        #[cfg(debug_assertions)]
659        {
660            use crate::low_level_il::ExpressionHandler;
661            if let Some(expr_size) = expr.kind().size() {
662                if expr_size != _size {
663                    log::warn!(
664                        "il @ {:x} attempted to lift {} byte expression as {} bytes",
665                        il.current_address(),
666                        expr_size,
667                        _size
668                    );
669                }
670            }
671        }
672
673        LiftableLowLevelIL::lift(il, expr)
674    }
675}
676
677impl<R> LowLevelILExpression<'_, Mutable, NonSSA, R>
678where
679    R: ExpressionResultType,
680{
681    pub fn with_source_operand(self, op: u32) -> Self {
682        use binaryninjacore_sys::BNLowLevelILSetExprSourceOperand;
683        unsafe { BNLowLevelILSetExprSourceOperand(self.function.handle, self.index.0, op) }
684        self
685    }
686
687    pub fn append(self) {
688        self.function.add_instruction(self);
689    }
690}
691
692pub struct ExpressionBuilder<'func, R>
693where
694    R: ExpressionResultType,
695{
696    function: &'func LowLevelILFunction<Mutable, NonSSA>,
697    op: BNLowLevelILOperation,
698    size: usize,
699    flag_write: FlagWriteId,
700    op1: u64,
701    op2: u64,
702    op3: u64,
703    op4: u64,
704    _ty: PhantomData<R>,
705}
706
707impl<'a, R> ExpressionBuilder<'a, R>
708where
709    R: ExpressionResultType,
710{
711    pub fn from_expr(expr: LowLevelILExpression<'a, Mutable, NonSSA, R>) -> Self {
712        use binaryninjacore_sys::BNGetLowLevelILByIndex;
713
714        let instr = unsafe { BNGetLowLevelILByIndex(expr.function.handle, expr.index.0) };
715
716        ExpressionBuilder {
717            function: expr.function,
718            op: instr.operation,
719            size: instr.size,
720            flag_write: FlagWriteId(instr.flags),
721            op1: instr.operands[0],
722            op2: instr.operands[1],
723            op3: instr.operands[2],
724            op4: instr.operands[3],
725            _ty: PhantomData,
726        }
727    }
728
729    pub fn with_flag_write(mut self, flag_write: impl FlagWrite) -> Self {
730        // TODO verify valid id
731        self.flag_write = flag_write.id();
732        self
733    }
734
735    pub fn build(self) -> LowLevelILExpression<'a, Mutable, NonSSA, R> {
736        use binaryninjacore_sys::BNLowLevelILAddExpr;
737
738        let expr_idx = unsafe {
739            BNLowLevelILAddExpr(
740                self.function.handle,
741                self.op,
742                self.size,
743                self.flag_write.0,
744                self.op1,
745                self.op2,
746                self.op3,
747                self.op4,
748            )
749        };
750
751        LowLevelILExpression::new(self.function, LowLevelExpressionIndex(expr_idx))
752    }
753
754    pub fn with_source_operand(self, op: u32) -> LowLevelILExpression<'a, Mutable, NonSSA, R> {
755        self.build().with_source_operand(op)
756    }
757
758    pub fn append(self) {
759        let expr = self.build();
760        expr.function.add_instruction(expr);
761    }
762}
763
764impl<'a, R> LiftableLowLevelIL<'a> for ExpressionBuilder<'a, R>
765where
766    R: ExpressionResultType,
767{
768    type Result = R;
769
770    fn lift(
771        il: &'a LowLevelILMutableFunction,
772        expr: Self,
773    ) -> LowLevelILMutableExpression<'a, Self::Result> {
774        debug_assert!(expr.function.handle == il.handle);
775
776        expr.build()
777    }
778}
779
780impl<'a> LiftableLowLevelILWithSize<'a> for ExpressionBuilder<'a, ValueExpr> {
781    fn lift_with_size(
782        il: &'a LowLevelILMutableFunction,
783        expr: Self,
784        _size: usize,
785    ) -> LowLevelILMutableExpression<'a, ValueExpr> {
786        #[cfg(debug_assertions)]
787        {
788            use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_UNIMPL, LLIL_UNIMPL_MEM};
789
790            if expr.size != _size && ![LLIL_UNIMPL, LLIL_UNIMPL_MEM].contains(&expr.op) {
791                log::warn!(
792                    "il @ {:x} attempted to lift {} byte expression builder as {} bytes",
793                    il.current_address(),
794                    expr.size,
795                    _size
796                );
797            }
798        }
799
800        LiftableLowLevelIL::lift(il, expr)
801    }
802}
803
804macro_rules! no_arg_lifter {
805    ($name:ident, $op:ident, $result:ty) => {
806        pub fn $name(&self) -> LowLevelILExpression<'_, Mutable, NonSSA, $result> {
807            use binaryninjacore_sys::BNLowLevelILAddExpr;
808            use binaryninjacore_sys::BNLowLevelILOperation::$op;
809
810            let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, $op, 0, 0, 0, 0, 0, 0) };
811
812            LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
813        }
814    };
815}
816
817macro_rules! sized_no_arg_lifter {
818    ($name:ident, $op:ident, $result:ty) => {
819        pub fn $name(&self, size: usize) -> ExpressionBuilder<'_, $result> {
820            use binaryninjacore_sys::BNLowLevelILOperation::$op;
821
822            ExpressionBuilder {
823                function: self,
824                op: $op,
825                size,
826                flag_write: FlagWriteId(0),
827                op1: 0,
828                op2: 0,
829                op3: 0,
830                op4: 0,
831                _ty: PhantomData,
832            }
833        }
834    };
835}
836
837macro_rules! unsized_unary_op_lifter {
838    ($name:ident, $op:ident, $result:ty) => {
839        pub fn $name<'a, E>(&'a self, expr: E) -> LowLevelILExpression<'a, Mutable, NonSSA, $result>
840        where
841            E: LiftableLowLevelIL<'a, Result = ValueExpr>,
842        {
843            use binaryninjacore_sys::BNLowLevelILAddExpr;
844            use binaryninjacore_sys::BNLowLevelILOperation::$op;
845
846            let expr = E::lift(self, expr);
847
848            let expr_idx = unsafe {
849                BNLowLevelILAddExpr(self.handle, $op, 0, 0, expr.index.0 as u64, 0, 0, 0)
850            };
851
852            LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
853        }
854    };
855}
856
857macro_rules! sized_unary_op_lifter {
858    ($name:ident, $op:ident, $result:ty) => {
859        pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, $result>
860        where
861            E: LiftableLowLevelILWithSize<'a>,
862        {
863            use binaryninjacore_sys::BNLowLevelILOperation::$op;
864
865            let expr = E::lift_with_size(self, expr, size);
866
867            ExpressionBuilder {
868                function: self,
869                op: $op,
870                size,
871                flag_write: FlagWriteId(0),
872                op1: expr.index.0 as u64,
873                op2: 0,
874                op3: 0,
875                op4: 0,
876                _ty: PhantomData,
877            }
878        }
879    };
880}
881
882macro_rules! size_changing_unary_op_lifter {
883    ($name:ident, $op:ident, $result:ty) => {
884        pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, $result>
885        where
886            E: LiftableLowLevelILWithSize<'a>,
887        {
888            use binaryninjacore_sys::BNLowLevelILOperation::$op;
889
890            let expr = E::lift(self, expr);
891
892            ExpressionBuilder {
893                function: self,
894                op: $op,
895                size,
896                flag_write: FlagWriteId(0),
897                op1: expr.index.0 as u64,
898                op2: 0,
899                op3: 0,
900                op4: 0,
901                _ty: PhantomData,
902            }
903        }
904    };
905}
906
907macro_rules! binary_op_lifter {
908    ($name:ident, $op:ident) => {
909        pub fn $name<'a, L, R>(
910            &'a self,
911            size: usize,
912            left: L,
913            right: R,
914        ) -> ExpressionBuilder<'a, ValueExpr>
915        where
916            L: LiftableLowLevelILWithSize<'a>,
917            R: LiftableLowLevelILWithSize<'a>,
918        {
919            use binaryninjacore_sys::BNLowLevelILOperation::$op;
920
921            let left = L::lift_with_size(self, left, size);
922            let right = R::lift_with_size(self, right, size);
923
924            ExpressionBuilder {
925                function: self,
926                op: $op,
927                size,
928                flag_write: FlagWriteId(0),
929                op1: left.index.0 as u64,
930                op2: right.index.0 as u64,
931                op3: 0,
932                op4: 0,
933                _ty: PhantomData,
934            }
935        }
936    };
937}
938
939macro_rules! binary_op_carry_lifter {
940    ($name:ident, $op:ident) => {
941        pub fn $name<'a, L, R, C>(
942            &'a self,
943            size: usize,
944            left: L,
945            right: R,
946            carry: C,
947        ) -> ExpressionBuilder<'a, ValueExpr>
948        where
949            L: LiftableLowLevelILWithSize<'a>,
950            R: LiftableLowLevelILWithSize<'a>,
951            C: LiftableLowLevelILWithSize<'a>,
952        {
953            use binaryninjacore_sys::BNLowLevelILOperation::$op;
954
955            let left = L::lift_with_size(self, left, size);
956            let right = R::lift_with_size(self, right, size);
957            let carry = C::lift_with_size(self, carry, 0);
958
959            ExpressionBuilder {
960                function: self,
961                op: $op,
962                size,
963                flag_write: FlagWriteId(0),
964                op1: left.index.0 as u64,
965                op2: right.index.0 as u64,
966                op3: carry.index.0 as u64,
967                op4: 0,
968                _ty: PhantomData,
969            }
970        }
971    };
972}
973
974impl LowLevelILMutableFunction {
975    pub const NO_INPUTS: [ExpressionBuilder<'static, ValueExpr>; 0] = [];
976    pub const NO_OUTPUTS: [LowLevelILRegisterKind<CoreRegister>; 0] = [];
977
978    pub fn expression<'a, E: LiftableLowLevelIL<'a>>(
979        &'a self,
980        expr: E,
981    ) -> LowLevelILExpression<'a, Mutable, NonSSA, E::Result> {
982        E::lift(self, expr)
983    }
984
985    pub fn add_instruction<'a, E: LiftableLowLevelIL<'a>>(&'a self, expr: E) {
986        let expr = self.expression(expr);
987
988        unsafe {
989            use binaryninjacore_sys::BNLowLevelILAddInstruction;
990            BNLowLevelILAddInstruction(self.handle, expr.index.0);
991        }
992    }
993
994    pub unsafe fn replace_expression<'a, E: LiftableLowLevelIL<'a>>(
995        &'a self,
996        replaced_expr_index: LowLevelExpressionIndex,
997        replacement: E,
998    ) -> bool {
999        use binaryninjacore_sys::BNReplaceLowLevelILExpr;
1000        if replaced_expr_index.0 >= self.expression_count() {
1001            // Invalid expression index, cant replace expression.
1002            return false;
1003        }
1004        let expr = self.expression(replacement);
1005        BNReplaceLowLevelILExpr(self.handle, replaced_expr_index.0, expr.index.0);
1006        true
1007    }
1008
1009    pub fn const_int(&self, size: usize, val: u64) -> LowLevelILMutableExpression<'_, ValueExpr> {
1010        use binaryninjacore_sys::BNLowLevelILAddExpr;
1011        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST;
1012
1013        let expr_idx =
1014            unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST, size, 0, val, 0, 0, 0) };
1015
1016        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1017    }
1018
1019    pub fn const_ptr_sized(
1020        &self,
1021        size: usize,
1022        val: u64,
1023    ) -> LowLevelILMutableExpression<'_, ValueExpr> {
1024        use binaryninjacore_sys::BNLowLevelILAddExpr;
1025        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST_PTR;
1026
1027        let expr_idx =
1028            unsafe { BNLowLevelILAddExpr(self.handle, LLIL_CONST_PTR, size, 0, val, 0, 0, 0) };
1029
1030        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1031    }
1032
1033    pub fn const_ptr(&self, val: u64) -> LowLevelILMutableExpression<'_, ValueExpr> {
1034        self.const_ptr_sized(self.arch().address_size(), val)
1035    }
1036
1037    pub fn trap(&self, val: u64) -> LowLevelILExpression<'_, Mutable, NonSSA, VoidExpr> {
1038        use binaryninjacore_sys::BNLowLevelILAddExpr;
1039        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_TRAP;
1040
1041        let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_TRAP, 0, 0, val, 0, 0, 0) };
1042
1043        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1044    }
1045
1046    no_arg_lifter!(unimplemented, LLIL_UNIMPL, ValueExpr);
1047    no_arg_lifter!(undefined, LLIL_UNDEF, ValueExpr);
1048    no_arg_lifter!(nop, LLIL_NOP, VoidExpr);
1049
1050    no_arg_lifter!(no_ret, LLIL_NORET, VoidExpr);
1051    no_arg_lifter!(syscall, LLIL_SYSCALL, VoidExpr);
1052    no_arg_lifter!(bp, LLIL_BP, VoidExpr);
1053
1054    unsized_unary_op_lifter!(call, LLIL_CALL, VoidExpr);
1055    unsized_unary_op_lifter!(tailcall, LLIL_TAILCALL, VoidExpr);
1056    unsized_unary_op_lifter!(ret, LLIL_RET, VoidExpr);
1057    unsized_unary_op_lifter!(jump, LLIL_JUMP, VoidExpr);
1058    // TODO: LLIL_JUMP_TO
1059
1060    pub fn if_expr<'a: 'b, 'b, C>(
1061        &'a self,
1062        cond: C,
1063        true_label: &'b mut LowLevelILLabel,
1064        false_label: &'b mut LowLevelILLabel,
1065    ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr>
1066    where
1067        C: LiftableLowLevelIL<'b, Result = ValueExpr>,
1068    {
1069        use binaryninjacore_sys::BNLowLevelILIf;
1070
1071        let cond = C::lift(self, cond);
1072
1073        let mut raw_true_label = BNLowLevelILLabel::from(*true_label);
1074        let mut raw_false_label = BNLowLevelILLabel::from(*false_label);
1075        let expr_idx = unsafe {
1076            BNLowLevelILIf(
1077                self.handle,
1078                cond.index.0 as u64,
1079                &mut raw_true_label,
1080                &mut raw_false_label,
1081            )
1082        };
1083
1084        // Update the labels after they have been resolved.
1085        let mut new_true_label = LowLevelILLabel::from(raw_true_label);
1086        let mut new_false_label = LowLevelILLabel::from(raw_false_label);
1087        if let Some(location) = true_label.location {
1088            new_true_label.location = Some(location);
1089            self.update_label_map_for_label(&new_true_label);
1090        }
1091        if let Some(location) = false_label.location {
1092            new_false_label.location = Some(location);
1093            self.update_label_map_for_label(&new_false_label);
1094        }
1095        *true_label = new_true_label;
1096        *false_label = new_false_label;
1097
1098        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1099    }
1100
1101    // TODO: Wtf are these lifetimes??
1102    pub fn goto<'a: 'b, 'b>(
1103        &'a self,
1104        label: &'b mut LowLevelILLabel,
1105    ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> {
1106        use binaryninjacore_sys::BNLowLevelILGoto;
1107
1108        let mut raw_label = BNLowLevelILLabel::from(*label);
1109        let expr_idx = unsafe { BNLowLevelILGoto(self.handle, &mut raw_label) };
1110
1111        // Update the labels after they have been resolved.
1112        let mut new_label = LowLevelILLabel::from(raw_label);
1113        if let Some(location) = label.location {
1114            new_label.location = Some(location);
1115            self.update_label_map_for_label(&new_label);
1116        }
1117        *label = new_label;
1118
1119        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1120    }
1121
1122    pub fn reg<R: ArchReg, LR: Into<LowLevelILRegisterKind<R>>>(
1123        &self,
1124        size: usize,
1125        reg: LR,
1126    ) -> LowLevelILMutableExpression<'_, ValueExpr> {
1127        use binaryninjacore_sys::BNLowLevelILAddExpr;
1128        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG;
1129
1130        // TODO verify valid id
1131        let reg = reg.into().id();
1132
1133        let expr_idx =
1134            unsafe { BNLowLevelILAddExpr(self.handle, LLIL_REG, size, 0, reg.0 as u64, 0, 0, 0) };
1135
1136        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1137    }
1138
1139    pub fn reg_split<R: ArchReg, LR: Into<LowLevelILRegisterKind<R>>>(
1140        &self,
1141        size: usize,
1142        hi_reg: LR,
1143        lo_reg: LR,
1144    ) -> LowLevelILMutableExpression<'_, ValueExpr> {
1145        use binaryninjacore_sys::BNLowLevelILAddExpr;
1146        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG_SPLIT;
1147
1148        // TODO verify valid id
1149        let hi_reg = hi_reg.into().id();
1150        let lo_reg = lo_reg.into().id();
1151
1152        let expr_idx = unsafe {
1153            BNLowLevelILAddExpr(
1154                self.handle,
1155                LLIL_REG_SPLIT,
1156                size,
1157                0,
1158                hi_reg.0 as u64,
1159                lo_reg.0 as u64,
1160                0,
1161                0,
1162            )
1163        };
1164
1165        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1166    }
1167
1168    pub fn set_reg<'a, R, LR, E>(
1169        &'a self,
1170        size: usize,
1171        dest_reg: LR,
1172        expr: E,
1173    ) -> ExpressionBuilder<'a, VoidExpr>
1174    where
1175        R: ArchReg,
1176        LR: Into<LowLevelILRegisterKind<R>>,
1177        E: LiftableLowLevelILWithSize<'a>,
1178    {
1179        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG;
1180
1181        // TODO verify valid id
1182        let dest_reg = dest_reg.into().id();
1183
1184        let expr = E::lift_with_size(self, expr, size);
1185
1186        ExpressionBuilder {
1187            function: self,
1188            op: LLIL_SET_REG,
1189            size,
1190            // TODO: Make these optional?
1191            flag_write: FlagWriteId(0),
1192            op1: dest_reg.0 as u64,
1193            op2: expr.index.0 as u64,
1194            op3: 0,
1195            op4: 0,
1196            _ty: PhantomData,
1197        }
1198    }
1199
1200    pub fn set_reg_split<'a, R, LR, E>(
1201        &'a self,
1202        size: usize,
1203        hi_reg: LR,
1204        lo_reg: LR,
1205        expr: E,
1206    ) -> ExpressionBuilder<'a, VoidExpr>
1207    where
1208        R: ArchReg,
1209        LR: Into<LowLevelILRegisterKind<R>>,
1210        E: LiftableLowLevelILWithSize<'a>,
1211    {
1212        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG_SPLIT;
1213
1214        // TODO verify valid id
1215        let hi_reg = hi_reg.into().id();
1216        let lo_reg = lo_reg.into().id();
1217
1218        let expr = E::lift_with_size(self, expr, size);
1219
1220        ExpressionBuilder {
1221            function: self,
1222            op: LLIL_SET_REG_SPLIT,
1223            size,
1224            flag_write: FlagWriteId(0),
1225            op1: hi_reg.0 as u64,
1226            op2: lo_reg.0 as u64,
1227            op3: expr.index.0 as u64,
1228            op4: 0,
1229            _ty: PhantomData,
1230        }
1231    }
1232
1233    pub fn flag(&self, flag: impl Flag) -> LowLevelILMutableExpression<'_, ValueExpr> {
1234        use binaryninjacore_sys::BNLowLevelILAddExpr;
1235        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG;
1236
1237        // TODO verify valid id
1238        let expr_idx = unsafe {
1239            BNLowLevelILAddExpr(self.handle, LLIL_FLAG, 0, 0, flag.id().0 as u64, 0, 0, 0)
1240        };
1241
1242        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1243    }
1244
1245    pub fn flag_cond(&self, cond: FlagCondition) -> LowLevelILMutableExpression<'_, ValueExpr> {
1246        use binaryninjacore_sys::BNLowLevelILAddExpr;
1247        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_COND;
1248
1249        // TODO verify valid id
1250        let expr_idx =
1251            unsafe { BNLowLevelILAddExpr(self.handle, LLIL_FLAG_COND, 0, 0, cond as u64, 0, 0, 0) };
1252
1253        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1254    }
1255
1256    pub fn flag_group(&self, group: impl FlagGroup) -> LowLevelILMutableExpression<'_, ValueExpr> {
1257        use binaryninjacore_sys::BNLowLevelILAddExpr;
1258        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_GROUP;
1259
1260        // TODO verify valid id
1261        let expr_idx = unsafe {
1262            BNLowLevelILAddExpr(
1263                self.handle,
1264                LLIL_FLAG_GROUP,
1265                0,
1266                0,
1267                group.id().0 as u64,
1268                0,
1269                0,
1270                0,
1271            )
1272        };
1273
1274        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1275    }
1276
1277    pub fn set_flag<'a, E>(
1278        &'a self,
1279        dest_flag: impl Flag,
1280        expr: E,
1281    ) -> ExpressionBuilder<'a, VoidExpr>
1282    where
1283        E: LiftableLowLevelILWithSize<'a>,
1284    {
1285        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_FLAG;
1286
1287        // TODO verify valid id
1288
1289        let expr = E::lift_with_size(self, expr, 0);
1290
1291        ExpressionBuilder {
1292            function: self,
1293            op: LLIL_SET_FLAG,
1294            size: 0,
1295            flag_write: FlagWriteId(0),
1296            op1: dest_flag.id().0 as u64,
1297            op2: expr.index.0 as u64,
1298            op3: 0,
1299            op4: 0,
1300            _ty: PhantomData,
1301        }
1302    }
1303
1304    /*
1305     * TODO
1306    FlagBit(usize, Flag<A>, u64),
1307    */
1308
1309    pub fn load<'a, E>(&'a self, size: usize, source_mem: E) -> ExpressionBuilder<'a, ValueExpr>
1310    where
1311        E: LiftableLowLevelIL<'a, Result = ValueExpr>,
1312    {
1313        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_LOAD;
1314
1315        let expr = E::lift(self, source_mem);
1316
1317        ExpressionBuilder {
1318            function: self,
1319            op: LLIL_LOAD,
1320            size,
1321            flag_write: FlagWriteId(0),
1322            op1: expr.index.0 as u64,
1323            op2: 0,
1324            op3: 0,
1325            op4: 0,
1326            _ty: PhantomData,
1327        }
1328    }
1329
1330    pub fn store<'a, D, V>(
1331        &'a self,
1332        size: usize,
1333        dest_mem: D,
1334        value: V,
1335    ) -> ExpressionBuilder<'a, VoidExpr>
1336    where
1337        D: LiftableLowLevelIL<'a, Result = ValueExpr>,
1338        V: LiftableLowLevelILWithSize<'a>,
1339    {
1340        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_STORE;
1341
1342        let dest_mem = D::lift(self, dest_mem);
1343        let value = V::lift_with_size(self, value, size);
1344
1345        ExpressionBuilder {
1346            function: self,
1347            op: LLIL_STORE,
1348            size,
1349            flag_write: FlagWriteId(0),
1350            op1: dest_mem.index.0 as u64,
1351            op2: value.index.0 as u64,
1352            op3: 0,
1353            op4: 0,
1354            _ty: PhantomData,
1355        }
1356    }
1357
1358    // TODO: Reposition arguments.
1359    pub fn intrinsic<'a, R, O, P>(
1360        &'a self,
1361        outputs: impl IntoIterator<Item = O>,
1362        intrinsic: impl Intrinsic,
1363        inputs: impl IntoIterator<Item = P>,
1364    ) -> ExpressionBuilder<'a, VoidExpr>
1365    where
1366        R: ArchReg,
1367        O: Into<LowLevelILRegisterKind<R>>,
1368        P: LiftableLowLevelIL<'a, Result = ValueExpr>,
1369    {
1370        use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_CALL_PARAM, LLIL_INTRINSIC};
1371        use binaryninjacore_sys::{BNLowLevelILAddExpr, BNLowLevelILAddOperandList};
1372
1373        let mut outputs: Vec<u64> = outputs
1374            .into_iter()
1375            .map(|output| output.into().id().0 as u64)
1376            .collect();
1377        let output_expr_idx =
1378            unsafe { BNLowLevelILAddOperandList(self.handle, outputs.as_mut_ptr(), outputs.len()) };
1379
1380        let mut inputs: Vec<u64> = inputs
1381            .into_iter()
1382            .map(|input| {
1383                let input = P::lift(self, input);
1384                input.index.0 as u64
1385            })
1386            .collect();
1387        let input_list_expr_idx =
1388            unsafe { BNLowLevelILAddOperandList(self.handle, inputs.as_mut_ptr(), inputs.len()) };
1389        let input_expr_idx = unsafe {
1390            BNLowLevelILAddExpr(
1391                self.handle,
1392                LLIL_CALL_PARAM,
1393                0,
1394                0,
1395                inputs.len() as u64,
1396                input_list_expr_idx as u64,
1397                0,
1398                0,
1399            )
1400        };
1401
1402        ExpressionBuilder {
1403            function: self,
1404            op: LLIL_INTRINSIC,
1405            size: 0,
1406            flag_write: FlagWriteId(0),
1407            op1: outputs.len() as u64,
1408            op2: output_expr_idx as u64,
1409            op3: intrinsic.id().0 as u64,
1410            op4: input_expr_idx as u64,
1411            _ty: PhantomData,
1412        }
1413    }
1414
1415    sized_unary_op_lifter!(push, LLIL_PUSH, VoidExpr);
1416    sized_no_arg_lifter!(pop, LLIL_POP, ValueExpr);
1417
1418    size_changing_unary_op_lifter!(unimplemented_mem, LLIL_UNIMPL_MEM, ValueExpr);
1419
1420    sized_unary_op_lifter!(neg, LLIL_NEG, ValueExpr);
1421    sized_unary_op_lifter!(not, LLIL_NOT, ValueExpr);
1422
1423    size_changing_unary_op_lifter!(sx, LLIL_SX, ValueExpr);
1424    size_changing_unary_op_lifter!(zx, LLIL_ZX, ValueExpr);
1425    size_changing_unary_op_lifter!(low_part, LLIL_LOW_PART, ValueExpr);
1426
1427    binary_op_lifter!(add, LLIL_ADD);
1428    binary_op_lifter!(add_overflow, LLIL_ADD_OVERFLOW);
1429    binary_op_lifter!(sub, LLIL_SUB);
1430    binary_op_lifter!(and, LLIL_AND);
1431    binary_op_lifter!(or, LLIL_OR);
1432    binary_op_lifter!(xor, LLIL_XOR);
1433    binary_op_lifter!(lsl, LLIL_LSL);
1434    binary_op_lifter!(lsr, LLIL_LSR);
1435    binary_op_lifter!(asr, LLIL_ASR);
1436
1437    binary_op_lifter!(rol, LLIL_ROL);
1438    binary_op_lifter!(rlc, LLIL_RLC);
1439    binary_op_lifter!(ror, LLIL_ROR);
1440    binary_op_lifter!(rrc, LLIL_RRC);
1441    binary_op_lifter!(mul, LLIL_MUL);
1442    binary_op_lifter!(muls_dp, LLIL_MULS_DP);
1443    binary_op_lifter!(mulu_dp, LLIL_MULU_DP);
1444    binary_op_lifter!(divs, LLIL_DIVS);
1445    binary_op_lifter!(divu, LLIL_DIVU);
1446    binary_op_lifter!(mods, LLIL_MODS);
1447    binary_op_lifter!(modu, LLIL_MODU);
1448
1449    binary_op_carry_lifter!(adc, LLIL_ADC);
1450    binary_op_carry_lifter!(sbb, LLIL_SBB);
1451
1452    /*
1453    DivsDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1454    DivuDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1455    ModsDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1456    ModuDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1457    */
1458
1459    // FlagCond(u32), // TODO
1460
1461    binary_op_lifter!(cmp_e, LLIL_CMP_E);
1462    binary_op_lifter!(cmp_ne, LLIL_CMP_NE);
1463    binary_op_lifter!(cmp_slt, LLIL_CMP_SLT);
1464    binary_op_lifter!(cmp_ult, LLIL_CMP_ULT);
1465    binary_op_lifter!(cmp_sle, LLIL_CMP_SLE);
1466    binary_op_lifter!(cmp_ule, LLIL_CMP_ULE);
1467    binary_op_lifter!(cmp_sge, LLIL_CMP_SGE);
1468    binary_op_lifter!(cmp_uge, LLIL_CMP_UGE);
1469    binary_op_lifter!(cmp_sgt, LLIL_CMP_SGT);
1470    binary_op_lifter!(cmp_ugt, LLIL_CMP_UGT);
1471    binary_op_lifter!(test_bit, LLIL_TEST_BIT);
1472
1473    // TODO no flags
1474    size_changing_unary_op_lifter!(bool_to_int, LLIL_BOOL_TO_INT, ValueExpr);
1475
1476    binary_op_lifter!(fadd, LLIL_FADD);
1477    binary_op_lifter!(fsub, LLIL_FSUB);
1478    binary_op_lifter!(fmul, LLIL_FMUL);
1479    binary_op_lifter!(fdiv, LLIL_FDIV);
1480    sized_unary_op_lifter!(fsqrt, LLIL_FSQRT, ValueExpr);
1481    sized_unary_op_lifter!(fneg, LLIL_FNEG, ValueExpr);
1482    sized_unary_op_lifter!(fabs, LLIL_FABS, ValueExpr);
1483    sized_unary_op_lifter!(float_to_int, LLIL_FLOAT_TO_INT, ValueExpr);
1484    sized_unary_op_lifter!(int_to_float, LLIL_INT_TO_FLOAT, ValueExpr);
1485    sized_unary_op_lifter!(float_conv, LLIL_FLOAT_CONV, ValueExpr);
1486    sized_unary_op_lifter!(round_to_int, LLIL_ROUND_TO_INT, ValueExpr);
1487    sized_unary_op_lifter!(floor, LLIL_FLOOR, ValueExpr);
1488    sized_unary_op_lifter!(ceil, LLIL_CEIL, ValueExpr);
1489    sized_unary_op_lifter!(ftrunc, LLIL_FTRUNC, ValueExpr);
1490    binary_op_lifter!(fcmp_e, LLIL_FCMP_E);
1491    binary_op_lifter!(fcmp_ne, LLIL_FCMP_NE);
1492    binary_op_lifter!(fcmp_lt, LLIL_FCMP_LT);
1493    binary_op_lifter!(fcmp_le, LLIL_FCMP_LE);
1494    binary_op_lifter!(fcmp_ge, LLIL_FCMP_GE);
1495    binary_op_lifter!(fcmp_gt, LLIL_FCMP_GT);
1496    binary_op_lifter!(fcmp_o, LLIL_FCMP_O);
1497    binary_op_lifter!(fcmp_uo, LLIL_FCMP_UO);
1498
1499    pub fn current_address(&self) -> u64 {
1500        use binaryninjacore_sys::BNLowLevelILGetCurrentAddress;
1501        unsafe { BNLowLevelILGetCurrentAddress(self.handle) }
1502    }
1503
1504    pub fn set_current_address<L: Into<Location>>(&self, loc: L) {
1505        use binaryninjacore_sys::BNLowLevelILSetCurrentAddress;
1506
1507        let loc: Location = loc.into();
1508        let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref());
1509
1510        unsafe {
1511            BNLowLevelILSetCurrentAddress(self.handle, arch.handle, loc.addr);
1512        }
1513    }
1514
1515    pub fn label_for_address<L: Into<Location>>(&self, loc: L) -> Option<LowLevelILLabel> {
1516        use binaryninjacore_sys::BNGetLowLevelILLabelForAddress;
1517
1518        let loc: Location = loc.into();
1519        let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref());
1520        let raw_label =
1521            unsafe { BNGetLowLevelILLabelForAddress(self.handle, arch.handle, loc.addr) };
1522        match raw_label.is_null() {
1523            false => {
1524                let mut label = unsafe { LowLevelILLabel::from(*raw_label) };
1525                // Set the location so that calls to [Self::update_label_map_for_label] will update the label map.
1526                label.location = Some(loc);
1527                Some(label)
1528            }
1529            true => None,
1530        }
1531    }
1532
1533    /// Call this after updating the label through an il operation or via [`Self::mark_label`].
1534    fn update_label_map_for_label(&self, label: &LowLevelILLabel) {
1535        use binaryninjacore_sys::BNGetLowLevelILLabelForAddress;
1536
1537        // Only need to update the label if there is an associated address.
1538        if let Some(loc) = label.location {
1539            let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref());
1540            // Add the label into the label map
1541            unsafe { BNAddLowLevelILLabelForAddress(self.handle, arch.handle, loc.addr) };
1542            // Retrieve a pointer to the label in the map
1543            let raw_label =
1544                unsafe { BNGetLowLevelILLabelForAddress(self.handle, arch.handle, loc.addr) };
1545            // We should always have a valid label here
1546            assert!(!raw_label.is_null(), "Failed to add label for address!");
1547            // Update the label in the map with `label`
1548            unsafe { *raw_label = label.into() };
1549        }
1550    }
1551
1552    pub fn mark_label(&self, label: &mut LowLevelILLabel) {
1553        use binaryninjacore_sys::BNLowLevelILMarkLabel;
1554
1555        let mut raw_label = BNLowLevelILLabel::from(*label);
1556        unsafe { BNLowLevelILMarkLabel(self.handle, &mut raw_label) };
1557        let mut new_label = LowLevelILLabel::from(raw_label);
1558        if let Some(location) = label.location {
1559            new_label.location = Some(location);
1560            self.update_label_map_for_label(&new_label);
1561        }
1562        *label = new_label;
1563    }
1564}
1565
1566#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1567pub struct LowLevelILLabel {
1568    /// Used to update the label map if the label is associated with a location.
1569    pub location: Option<Location>,
1570    pub resolved: bool,
1571    // TODO: This expr_ref is not actually a valid one sometimes...
1572    // TODO: We should make these non public and only accessible if resolved is true.
1573    pub expr_ref: LowLevelExpressionIndex,
1574    // TODO: If this is 7 this label is not valid.
1575    pub operand: usize,
1576}
1577
1578impl LowLevelILLabel {
1579    pub fn new() -> Self {
1580        use binaryninjacore_sys::BNLowLevelILInitLabel;
1581
1582        let mut raw_label = BNLowLevelILLabel::default();
1583        unsafe { BNLowLevelILInitLabel(&mut raw_label) };
1584        raw_label.into()
1585    }
1586}
1587
1588impl From<BNLowLevelILLabel> for LowLevelILLabel {
1589    fn from(value: BNLowLevelILLabel) -> Self {
1590        Self {
1591            location: None,
1592            resolved: value.resolved,
1593            expr_ref: LowLevelExpressionIndex(value.ref_),
1594            operand: value.operand,
1595        }
1596    }
1597}
1598
1599impl From<LowLevelILLabel> for BNLowLevelILLabel {
1600    fn from(value: LowLevelILLabel) -> Self {
1601        Self {
1602            resolved: value.resolved,
1603            ref_: value.expr_ref.0,
1604            operand: value.operand,
1605        }
1606    }
1607}
1608
1609impl From<&LowLevelILLabel> for BNLowLevelILLabel {
1610    fn from(value: &LowLevelILLabel) -> Self {
1611        Self::from(*value)
1612    }
1613}
1614
1615impl Default for LowLevelILLabel {
1616    fn default() -> Self {
1617        Self::new()
1618    }
1619}