binaryninja/low_level_il/
lifting.rs

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