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
1111    pub fn unknown(&self) -> LowLevelILExpression<'_, Mutable, NonSSA, ValueExpr> {
1112        use binaryninjacore_sys::BNLowLevelILAddExpr;
1113        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_UNIMPL;
1114
1115        let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_UNIMPL, 0, 0, 1, 0, 0, 0) };
1116
1117        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1118    }
1119    no_arg_lifter!(undefined, LLIL_UNDEF, ValueExpr);
1120    no_arg_lifter!(nop, LLIL_NOP, VoidExpr);
1121
1122    no_arg_lifter!(no_ret, LLIL_NORET, VoidExpr);
1123    no_arg_lifter!(syscall, LLIL_SYSCALL, VoidExpr);
1124    no_arg_lifter!(bp, LLIL_BP, VoidExpr);
1125
1126    unsized_unary_op_lifter!(call, LLIL_CALL, VoidExpr);
1127    unsized_unary_op_lifter!(tailcall, LLIL_TAILCALL, VoidExpr);
1128    unsized_unary_op_lifter!(ret, LLIL_RET, VoidExpr);
1129    unsized_unary_op_lifter!(jump, LLIL_JUMP, VoidExpr);
1130    // TODO: LLIL_JUMP_TO
1131
1132    pub fn if_expr<'a: 'b, 'b, C>(
1133        &'a self,
1134        cond: C,
1135        true_label: &'b mut LowLevelILLabel,
1136        false_label: &'b mut LowLevelILLabel,
1137    ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr>
1138    where
1139        C: LiftableLowLevelIL<'b, Result = ValueExpr>,
1140    {
1141        use binaryninjacore_sys::BNLowLevelILIf;
1142
1143        let cond = C::lift(self, cond);
1144
1145        let mut raw_true_label = BNLowLevelILLabel::from(*true_label);
1146        let mut raw_false_label = BNLowLevelILLabel::from(*false_label);
1147        let expr_idx = unsafe {
1148            BNLowLevelILIf(
1149                self.handle,
1150                cond.index.0 as u64,
1151                &mut raw_true_label,
1152                &mut raw_false_label,
1153            )
1154        };
1155
1156        // Update the labels after they have been resolved.
1157        let mut new_true_label = LowLevelILLabel::from(raw_true_label);
1158        let mut new_false_label = LowLevelILLabel::from(raw_false_label);
1159        if let Some(location) = true_label.location {
1160            new_true_label.location = Some(location);
1161            self.update_label_map_for_label(&new_true_label);
1162        }
1163        if let Some(location) = false_label.location {
1164            new_false_label.location = Some(location);
1165            self.update_label_map_for_label(&new_false_label);
1166        }
1167        *true_label = new_true_label;
1168        *false_label = new_false_label;
1169
1170        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1171    }
1172
1173    // TODO: Wtf are these lifetimes??
1174    pub fn goto<'a: 'b, 'b>(
1175        &'a self,
1176        label: &'b mut LowLevelILLabel,
1177    ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> {
1178        use binaryninjacore_sys::BNLowLevelILGoto;
1179
1180        let mut raw_label = BNLowLevelILLabel::from(*label);
1181        let expr_idx = unsafe { BNLowLevelILGoto(self.handle, &mut raw_label) };
1182
1183        // Update the labels after they have been resolved.
1184        let mut new_label = LowLevelILLabel::from(raw_label);
1185        if let Some(location) = label.location {
1186            new_label.location = Some(location);
1187            self.update_label_map_for_label(&new_label);
1188        }
1189        *label = new_label;
1190
1191        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1192    }
1193
1194    pub fn reg<R: ArchReg, LR: Into<LowLevelILRegisterKind<R>>>(
1195        &self,
1196        size: usize,
1197        reg: LR,
1198    ) -> LowLevelILMutableExpression<'_, ValueExpr> {
1199        use binaryninjacore_sys::BNLowLevelILAddExpr;
1200        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG;
1201
1202        // TODO verify valid id
1203        let reg = reg.into().id();
1204
1205        let expr_idx =
1206            unsafe { BNLowLevelILAddExpr(self.handle, LLIL_REG, size, 0, reg.0 as u64, 0, 0, 0) };
1207
1208        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1209    }
1210
1211    pub fn reg_split<R: ArchReg, LR: Into<LowLevelILRegisterKind<R>>>(
1212        &self,
1213        size: usize,
1214        hi_reg: LR,
1215        lo_reg: LR,
1216    ) -> LowLevelILMutableExpression<'_, ValueExpr> {
1217        use binaryninjacore_sys::BNLowLevelILAddExpr;
1218        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG_SPLIT;
1219
1220        // TODO verify valid id
1221        let hi_reg = hi_reg.into().id();
1222        let lo_reg = lo_reg.into().id();
1223
1224        let expr_idx = unsafe {
1225            BNLowLevelILAddExpr(
1226                self.handle,
1227                LLIL_REG_SPLIT,
1228                size,
1229                0,
1230                hi_reg.0 as u64,
1231                lo_reg.0 as u64,
1232                0,
1233                0,
1234            )
1235        };
1236
1237        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1238    }
1239
1240    pub fn set_reg<'a, R, LR, E>(
1241        &'a self,
1242        size: usize,
1243        dest_reg: LR,
1244        expr: E,
1245    ) -> ExpressionBuilder<'a, VoidExpr>
1246    where
1247        R: ArchReg,
1248        LR: Into<LowLevelILRegisterKind<R>>,
1249        E: LiftableLowLevelILWithSize<'a>,
1250    {
1251        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG;
1252
1253        // TODO verify valid id
1254        let dest_reg = dest_reg.into().id();
1255
1256        let expr = E::lift_with_size(self, expr, size);
1257
1258        ExpressionBuilder {
1259            function: self,
1260            op: LLIL_SET_REG,
1261            size,
1262            // TODO: Make these optional?
1263            flag_write: FlagWriteId(0),
1264            op1: dest_reg.0 as u64,
1265            op2: expr.index.0 as u64,
1266            op3: 0,
1267            op4: 0,
1268            _ty: PhantomData,
1269        }
1270    }
1271
1272    pub fn set_reg_split<'a, R, LR, E>(
1273        &'a self,
1274        size: usize,
1275        hi_reg: LR,
1276        lo_reg: LR,
1277        expr: E,
1278    ) -> ExpressionBuilder<'a, VoidExpr>
1279    where
1280        R: ArchReg,
1281        LR: Into<LowLevelILRegisterKind<R>>,
1282        E: LiftableLowLevelILWithSize<'a>,
1283    {
1284        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG_SPLIT;
1285
1286        // TODO verify valid id
1287        let hi_reg = hi_reg.into().id();
1288        let lo_reg = lo_reg.into().id();
1289
1290        let expr = E::lift_with_size(self, expr, size);
1291
1292        ExpressionBuilder {
1293            function: self,
1294            op: LLIL_SET_REG_SPLIT,
1295            size,
1296            flag_write: FlagWriteId(0),
1297            op1: hi_reg.0 as u64,
1298            op2: lo_reg.0 as u64,
1299            op3: expr.index.0 as u64,
1300            op4: 0,
1301            _ty: PhantomData,
1302        }
1303    }
1304
1305    pub fn flag(&self, flag: impl Flag) -> LowLevelILMutableExpression<'_, ValueExpr> {
1306        use binaryninjacore_sys::BNLowLevelILAddExpr;
1307        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG;
1308
1309        // TODO verify valid id
1310        let expr_idx = unsafe {
1311            BNLowLevelILAddExpr(self.handle, LLIL_FLAG, 0, 0, flag.id().0 as u64, 0, 0, 0)
1312        };
1313
1314        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1315    }
1316
1317    pub fn flag_cond(&self, cond: FlagCondition) -> LowLevelILMutableExpression<'_, ValueExpr> {
1318        use binaryninjacore_sys::BNLowLevelILAddExpr;
1319        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_COND;
1320
1321        // TODO verify valid id
1322        let expr_idx =
1323            unsafe { BNLowLevelILAddExpr(self.handle, LLIL_FLAG_COND, 0, 0, cond as u64, 0, 0, 0) };
1324
1325        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1326    }
1327
1328    pub fn flag_group(&self, group: impl FlagGroup) -> LowLevelILMutableExpression<'_, ValueExpr> {
1329        use binaryninjacore_sys::BNLowLevelILAddExpr;
1330        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_GROUP;
1331
1332        // TODO verify valid id
1333        let expr_idx = unsafe {
1334            BNLowLevelILAddExpr(
1335                self.handle,
1336                LLIL_FLAG_GROUP,
1337                0,
1338                0,
1339                group.id().0 as u64,
1340                0,
1341                0,
1342                0,
1343            )
1344        };
1345
1346        LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1347    }
1348
1349    pub fn set_flag<'a, E>(
1350        &'a self,
1351        dest_flag: impl Flag,
1352        expr: E,
1353    ) -> ExpressionBuilder<'a, VoidExpr>
1354    where
1355        E: LiftableLowLevelILWithSize<'a>,
1356    {
1357        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_FLAG;
1358
1359        // TODO verify valid id
1360
1361        let expr = E::lift_with_size(self, expr, 0);
1362
1363        ExpressionBuilder {
1364            function: self,
1365            op: LLIL_SET_FLAG,
1366            size: 0,
1367            flag_write: FlagWriteId(0),
1368            op1: dest_flag.id().0 as u64,
1369            op2: expr.index.0 as u64,
1370            op3: 0,
1371            op4: 0,
1372            _ty: PhantomData,
1373        }
1374    }
1375
1376    /*
1377     * TODO
1378    FlagBit(usize, Flag<A>, u64),
1379    */
1380
1381    pub fn load<'a, E>(&'a self, size: usize, source_mem: E) -> ExpressionBuilder<'a, ValueExpr>
1382    where
1383        E: LiftableLowLevelIL<'a, Result = ValueExpr>,
1384    {
1385        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_LOAD;
1386
1387        let expr = E::lift(self, source_mem);
1388
1389        ExpressionBuilder {
1390            function: self,
1391            op: LLIL_LOAD,
1392            size,
1393            flag_write: FlagWriteId(0),
1394            op1: expr.index.0 as u64,
1395            op2: 0,
1396            op3: 0,
1397            op4: 0,
1398            _ty: PhantomData,
1399        }
1400    }
1401
1402    pub fn store<'a, D, V>(
1403        &'a self,
1404        size: usize,
1405        dest_mem: D,
1406        value: V,
1407    ) -> ExpressionBuilder<'a, VoidExpr>
1408    where
1409        D: LiftableLowLevelIL<'a, Result = ValueExpr>,
1410        V: LiftableLowLevelILWithSize<'a>,
1411    {
1412        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_STORE;
1413
1414        let dest_mem = D::lift(self, dest_mem);
1415        let value = V::lift_with_size(self, value, size);
1416
1417        ExpressionBuilder {
1418            function: self,
1419            op: LLIL_STORE,
1420            size,
1421            flag_write: FlagWriteId(0),
1422            op1: dest_mem.index.0 as u64,
1423            op2: value.index.0 as u64,
1424            op3: 0,
1425            op4: 0,
1426            _ty: PhantomData,
1427        }
1428    }
1429
1430    // TODO: Reposition arguments.
1431    pub fn intrinsic<'a, R, O, P>(
1432        &'a self,
1433        outputs: impl IntoIterator<Item = O>,
1434        intrinsic: impl Intrinsic,
1435        inputs: impl IntoIterator<Item = P>,
1436    ) -> ExpressionBuilder<'a, VoidExpr>
1437    where
1438        R: ArchReg,
1439        O: Into<LowLevelILRegisterKind<R>>,
1440        P: LiftableLowLevelIL<'a, Result = ValueExpr>,
1441    {
1442        use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_CALL_PARAM, LLIL_INTRINSIC};
1443        use binaryninjacore_sys::{BNLowLevelILAddExpr, BNLowLevelILAddOperandList};
1444
1445        let mut outputs: Vec<u64> = outputs
1446            .into_iter()
1447            .map(|output| output.into().id().0 as u64)
1448            .collect();
1449        let output_expr_idx =
1450            unsafe { BNLowLevelILAddOperandList(self.handle, outputs.as_mut_ptr(), outputs.len()) };
1451
1452        let mut inputs: Vec<u64> = inputs
1453            .into_iter()
1454            .map(|input| {
1455                let input = P::lift(self, input);
1456                input.index.0 as u64
1457            })
1458            .collect();
1459        let input_list_expr_idx =
1460            unsafe { BNLowLevelILAddOperandList(self.handle, inputs.as_mut_ptr(), inputs.len()) };
1461        let input_expr_idx = unsafe {
1462            BNLowLevelILAddExpr(
1463                self.handle,
1464                LLIL_CALL_PARAM,
1465                0,
1466                0,
1467                inputs.len() as u64,
1468                input_list_expr_idx as u64,
1469                0,
1470                0,
1471            )
1472        };
1473
1474        ExpressionBuilder {
1475            function: self,
1476            op: LLIL_INTRINSIC,
1477            size: 0,
1478            flag_write: FlagWriteId(0),
1479            op1: outputs.len() as u64,
1480            op2: output_expr_idx as u64,
1481            op3: intrinsic.id().0 as u64,
1482            op4: input_expr_idx as u64,
1483            _ty: PhantomData,
1484        }
1485    }
1486
1487    sized_unary_op_lifter!(push, LLIL_PUSH, VoidExpr);
1488    sized_no_arg_lifter!(pop, LLIL_POP, ValueExpr);
1489
1490    size_changing_unary_op_lifter!(unimplemented_mem, LLIL_UNIMPL_MEM, ValueExpr);
1491
1492    pub fn unknown_mem<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, ValueExpr>
1493    where
1494        E: LiftableLowLevelILWithSize<'a>,
1495    {
1496        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_UNIMPL_MEM;
1497
1498        let expr = E::lift(self, expr);
1499
1500        ExpressionBuilder {
1501            function: self,
1502            op: LLIL_UNIMPL_MEM,
1503            size,
1504            flag_write: FlagWriteId(0),
1505            op1: expr.index.0 as u64,
1506            op2: 1,
1507            op3: 0,
1508            op4: 0,
1509            _ty: PhantomData,
1510        }
1511    }
1512
1513    sized_unary_op_lifter!(neg, LLIL_NEG, ValueExpr);
1514    sized_unary_op_lifter!(not, LLIL_NOT, ValueExpr);
1515    sized_unary_op_lifter!(bswap, LLIL_BSWAP, ValueExpr);
1516    sized_unary_op_lifter!(popcnt, LLIL_POPCNT, ValueExpr);
1517    sized_unary_op_lifter!(clz, LLIL_CLZ, ValueExpr);
1518    sized_unary_op_lifter!(ctz, LLIL_CTZ, ValueExpr);
1519    sized_unary_op_lifter!(rbit, LLIL_RBIT, ValueExpr);
1520    sized_unary_op_lifter!(cls, LLIL_CLS, ValueExpr);
1521    sized_unary_op_lifter!(abs, LLIL_ABS, ValueExpr);
1522
1523    size_changing_unary_op_lifter!(sx, LLIL_SX, ValueExpr);
1524    size_changing_unary_op_lifter!(zx, LLIL_ZX, ValueExpr);
1525    size_changing_unary_op_lifter!(low_part, LLIL_LOW_PART, ValueExpr);
1526
1527    binary_op_lifter!(add, LLIL_ADD);
1528    binary_op_lifter!(add_overflow, LLIL_ADD_OVERFLOW);
1529    binary_op_lifter!(sub, LLIL_SUB);
1530    binary_op_lifter!(and, LLIL_AND);
1531    binary_op_lifter!(or, LLIL_OR);
1532    binary_op_lifter!(xor, LLIL_XOR);
1533    binary_op_lifter!(lsl, LLIL_LSL);
1534    binary_op_lifter!(lsr, LLIL_LSR);
1535    binary_op_lifter!(asr, LLIL_ASR);
1536
1537    binary_op_lifter!(rol, LLIL_ROL);
1538    binary_op_lifter!(rlc, LLIL_RLC);
1539    binary_op_lifter!(ror, LLIL_ROR);
1540    binary_op_lifter!(rrc, LLIL_RRC);
1541    binary_op_lifter!(mul, LLIL_MUL);
1542    binary_op_lifter!(muls_dp, LLIL_MULS_DP);
1543    binary_op_lifter!(mulu_dp, LLIL_MULU_DP);
1544    binary_op_lifter!(divs, LLIL_DIVS);
1545    binary_op_lifter!(divu, LLIL_DIVU);
1546    binary_op_lifter!(mods, LLIL_MODS);
1547    binary_op_lifter!(modu, LLIL_MODU);
1548    binary_op_lifter!(min_signed, LLIL_MINS);
1549    binary_op_lifter!(max_signed, LLIL_MAXS);
1550    binary_op_lifter!(min_unsigned, LLIL_MINU);
1551    binary_op_lifter!(max_unsigned, LLIL_MAXU);
1552
1553    binary_op_carry_lifter!(adc, LLIL_ADC);
1554    binary_op_carry_lifter!(sbb, LLIL_SBB);
1555
1556    /*
1557    DivsDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1558    DivuDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1559    ModsDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1560    ModuDp(usize, Expr, Expr, Expr, Option<A::FlagWrite>),
1561    */
1562
1563    // FlagCond(u32), // TODO
1564
1565    binary_op_lifter!(cmp_e, LLIL_CMP_E);
1566    binary_op_lifter!(cmp_ne, LLIL_CMP_NE);
1567    binary_op_lifter!(cmp_slt, LLIL_CMP_SLT);
1568    binary_op_lifter!(cmp_ult, LLIL_CMP_ULT);
1569    binary_op_lifter!(cmp_sle, LLIL_CMP_SLE);
1570    binary_op_lifter!(cmp_ule, LLIL_CMP_ULE);
1571    binary_op_lifter!(cmp_sge, LLIL_CMP_SGE);
1572    binary_op_lifter!(cmp_uge, LLIL_CMP_UGE);
1573    binary_op_lifter!(cmp_sgt, LLIL_CMP_SGT);
1574    binary_op_lifter!(cmp_ugt, LLIL_CMP_UGT);
1575    binary_op_lifter!(test_bit, LLIL_TEST_BIT);
1576
1577    // TODO no flags
1578    size_changing_unary_op_lifter!(bool_to_int, LLIL_BOOL_TO_INT, ValueExpr);
1579
1580    binary_op_lifter!(fadd, LLIL_FADD);
1581    binary_op_lifter!(fsub, LLIL_FSUB);
1582    binary_op_lifter!(fmul, LLIL_FMUL);
1583    binary_op_lifter!(fdiv, LLIL_FDIV);
1584    sized_unary_op_lifter!(fsqrt, LLIL_FSQRT, ValueExpr);
1585    sized_unary_op_lifter!(fneg, LLIL_FNEG, ValueExpr);
1586    sized_unary_op_lifter!(fabs, LLIL_FABS, ValueExpr);
1587    sized_unary_op_lifter!(float_to_int, LLIL_FLOAT_TO_INT, ValueExpr);
1588    sized_unary_op_lifter!(int_to_float, LLIL_INT_TO_FLOAT, ValueExpr);
1589    sized_unary_op_lifter!(float_conv, LLIL_FLOAT_CONV, ValueExpr);
1590    sized_unary_op_lifter!(round_to_int, LLIL_ROUND_TO_INT, ValueExpr);
1591    sized_unary_op_lifter!(floor, LLIL_FLOOR, ValueExpr);
1592    sized_unary_op_lifter!(ceil, LLIL_CEIL, ValueExpr);
1593    sized_unary_op_lifter!(ftrunc, LLIL_FTRUNC, ValueExpr);
1594    binary_op_lifter!(fcmp_e, LLIL_FCMP_E);
1595    binary_op_lifter!(fcmp_ne, LLIL_FCMP_NE);
1596    binary_op_lifter!(fcmp_lt, LLIL_FCMP_LT);
1597    binary_op_lifter!(fcmp_le, LLIL_FCMP_LE);
1598    binary_op_lifter!(fcmp_ge, LLIL_FCMP_GE);
1599    binary_op_lifter!(fcmp_gt, LLIL_FCMP_GT);
1600    binary_op_lifter!(fcmp_o, LLIL_FCMP_O);
1601    binary_op_lifter!(fcmp_uo, LLIL_FCMP_UO);
1602
1603    pub fn current_address(&self) -> u64 {
1604        use binaryninjacore_sys::BNLowLevelILGetCurrentAddress;
1605        unsafe { BNLowLevelILGetCurrentAddress(self.handle) }
1606    }
1607
1608    pub fn set_current_address<L: Into<Location>>(&self, loc: L) {
1609        use binaryninjacore_sys::BNLowLevelILSetCurrentAddress;
1610
1611        let loc: Location = loc.into();
1612        let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref());
1613
1614        unsafe {
1615            BNLowLevelILSetCurrentAddress(self.handle, arch.handle, loc.addr);
1616        }
1617    }
1618
1619    pub fn set_current_source_block(&self, source: &BasicBlock<NativeBlock>) {
1620        use binaryninjacore_sys::BNLowLevelILSetCurrentSourceBlock;
1621        unsafe {
1622            BNLowLevelILSetCurrentSourceBlock(self.handle, source.handle);
1623        }
1624    }
1625
1626    pub fn label_for_address<L: Into<Location>>(&self, loc: L) -> Option<LowLevelILLabel> {
1627        use binaryninjacore_sys::BNGetLowLevelILLabelForAddress;
1628
1629        let loc: Location = loc.into();
1630        let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref());
1631        let raw_label =
1632            unsafe { BNGetLowLevelILLabelForAddress(self.handle, arch.handle, loc.addr) };
1633        match raw_label.is_null() {
1634            false => {
1635                let mut label = unsafe { LowLevelILLabel::from(*raw_label) };
1636                // Set the location so that calls to [Self::update_label_map_for_label] will update the label map.
1637                label.location = Some(loc);
1638                Some(label)
1639            }
1640            true => None,
1641        }
1642    }
1643
1644    /// Call this after updating the label through an il operation or via [`Self::mark_label`].
1645    fn update_label_map_for_label(&self, label: &LowLevelILLabel) {
1646        use binaryninjacore_sys::BNGetLowLevelILLabelForAddress;
1647
1648        // Only need to update the label if there is an associated address.
1649        if let Some(loc) = label.location {
1650            let arch = loc.arch.unwrap_or_else(|| *self.arch().as_ref());
1651            // Add the label into the label map
1652            unsafe { BNAddLowLevelILLabelForAddress(self.handle, arch.handle, loc.addr) };
1653            // Retrieve a pointer to the label in the map
1654            let raw_label =
1655                unsafe { BNGetLowLevelILLabelForAddress(self.handle, arch.handle, loc.addr) };
1656            // We should always have a valid label here
1657            assert!(!raw_label.is_null(), "Failed to add label for address!");
1658            // Update the label in the map with `label`
1659            unsafe { *raw_label = label.into() };
1660        }
1661    }
1662
1663    pub fn mark_label(&self, label: &mut LowLevelILLabel) {
1664        use binaryninjacore_sys::BNLowLevelILMarkLabel;
1665
1666        let mut raw_label = BNLowLevelILLabel::from(*label);
1667        unsafe { BNLowLevelILMarkLabel(self.handle, &mut raw_label) };
1668        let mut new_label = LowLevelILLabel::from(raw_label);
1669        if let Some(location) = label.location {
1670            new_label.location = Some(location);
1671            self.update_label_map_for_label(&new_label);
1672        }
1673        *label = new_label;
1674    }
1675
1676    pub fn set_expr_attributes(
1677        &self,
1678        expr: LowLevelExpressionIndex,
1679        value: &ILInstructionAttributeSet,
1680    ) {
1681        let mut result = 0u32;
1682        for flag in value {
1683            result |= flag.value();
1684        }
1685
1686        unsafe {
1687            BNSetLowLevelILExprAttributes(self.handle, expr.0, result);
1688        }
1689    }
1690
1691    pub fn clear_indirect_branches(&self) {
1692        unsafe { BNLowLevelILClearIndirectBranches(self.handle) };
1693    }
1694}
1695
1696#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1697pub struct LowLevelILLabel {
1698    /// Used to update the label map if the label is associated with a location.
1699    pub location: Option<Location>,
1700    pub resolved: bool,
1701    // TODO: This expr_ref is not actually a valid one sometimes...
1702    // TODO: We should make these non public and only accessible if resolved is true.
1703    pub expr_ref: LowLevelExpressionIndex,
1704    // TODO: If this is 7 this label is not valid.
1705    pub operand: usize,
1706}
1707
1708impl LowLevelILLabel {
1709    pub fn new() -> Self {
1710        use binaryninjacore_sys::BNLowLevelILInitLabel;
1711
1712        let mut raw_label = BNLowLevelILLabel::default();
1713        unsafe { BNLowLevelILInitLabel(&mut raw_label) };
1714        raw_label.into()
1715    }
1716}
1717
1718impl From<BNLowLevelILLabel> for LowLevelILLabel {
1719    fn from(value: BNLowLevelILLabel) -> Self {
1720        Self {
1721            location: None,
1722            resolved: value.resolved,
1723            expr_ref: LowLevelExpressionIndex(value.ref_),
1724            operand: value.operand,
1725        }
1726    }
1727}
1728
1729impl From<LowLevelILLabel> for BNLowLevelILLabel {
1730    fn from(value: LowLevelILLabel) -> Self {
1731        Self {
1732            resolved: value.resolved,
1733            ref_: value.expr_ref.0,
1734            operand: value.operand,
1735        }
1736    }
1737}
1738
1739impl From<&LowLevelILLabel> for BNLowLevelILLabel {
1740    fn from(value: &LowLevelILLabel) -> Self {
1741        Self::from(*value)
1742    }
1743}
1744
1745impl Default for LowLevelILLabel {
1746    fn default() -> Self {
1747        Self::new()
1748    }
1749}