Skip to main content

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