binaryninja/low_level_il/
expression.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 binaryninjacore_sys::BNLowLevelILInstruction;
16use binaryninjacore_sys::{
17    BNGetLowLevelILByIndex, BNGetLowLevelILExprValue, BNGetLowLevelILPossibleExprValues,
18};
19
20use super::operation;
21use super::operation::Operation;
22use super::VisitorAction;
23use super::*;
24use crate::architecture::CoreFlagWrite;
25use crate::variable::{PossibleValueSet, RegisterValue};
26use crate::DataFlowQueryOption;
27use std::fmt;
28use std::fmt::{Debug, Display, Formatter};
29use std::marker::PhantomData;
30
31/// Used as a marker for an [`LowLevelILExpression`] that **can** produce a value.
32#[derive(Copy, Clone, Debug)]
33pub struct ValueExpr;
34
35/// Used as a marker for an [`LowLevelILExpression`] that can **not** produce a value.
36#[derive(Copy, Clone, Debug)]
37pub struct VoidExpr;
38
39pub trait ExpressionResultType: 'static + Debug {}
40impl ExpressionResultType for ValueExpr {}
41impl ExpressionResultType for VoidExpr {}
42
43#[repr(transparent)]
44#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
45pub struct LowLevelExpressionIndex(pub usize);
46
47impl Display for LowLevelExpressionIndex {
48    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
49        f.write_fmt(format_args!("{}", self.0))
50    }
51}
52
53// TODO: Probably want to rename this with a LowLevelIL prefix to avoid collisions when we add handlers for other ILs
54pub trait ExpressionHandler<'func, M, F>
55where
56    M: FunctionMutability,
57    F: FunctionForm,
58{
59    fn kind(&self) -> LowLevelILExpressionKind<'func, M, F>;
60
61    fn visit_tree<T>(&self, f: &mut T) -> VisitorAction
62    where
63        T: FnMut(&LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction;
64}
65
66#[derive(Copy)]
67pub struct LowLevelILExpression<'func, M, F, R>
68where
69    M: FunctionMutability,
70    F: FunctionForm,
71    R: ExpressionResultType,
72{
73    pub(crate) function: &'func LowLevelILFunction<M, F>,
74    pub index: LowLevelExpressionIndex,
75
76    // tag the 'return' type of this expression
77    pub(crate) _ty: PhantomData<R>,
78}
79
80impl<M, F, R> Clone for LowLevelILExpression<'_, M, F, R>
81where
82    M: FunctionMutability,
83    F: FunctionForm,
84    R: ExpressionResultType,
85{
86    fn clone(&self) -> Self {
87        Self {
88            function: self.function,
89            index: self.index,
90            _ty: PhantomData,
91        }
92    }
93}
94
95impl<'func, M, F, R> LowLevelILExpression<'func, M, F, R>
96where
97    M: FunctionMutability,
98    F: FunctionForm,
99    R: ExpressionResultType,
100{
101    pub fn new(function: &'func LowLevelILFunction<M, F>, index: LowLevelExpressionIndex) -> Self {
102        // TODO: Validate expression here?
103        Self {
104            function,
105            index,
106            _ty: PhantomData,
107        }
108    }
109}
110
111impl<M, F, R> Debug for LowLevelILExpression<'_, M, F, R>
112where
113    M: FunctionMutability,
114    F: FunctionForm,
115    R: ExpressionResultType,
116{
117    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
118        let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) };
119        let kind = LowLevelILExpressionKind::from_raw(self.function, op, self.index);
120        kind.fmt(f)
121    }
122}
123
124impl<M, R> LowLevelILExpression<'_, M, SSA, R>
125where
126    M: FunctionMutability,
127    R: ExpressionResultType,
128{
129    pub fn non_ssa_form<'func>(
130        &self,
131        non_ssa: &'func LowLevelILFunction<M, NonSSA>,
132    ) -> LowLevelILExpression<'func, M, NonSSA, R> {
133        use binaryninjacore_sys::BNGetLowLevelILNonSSAExprIndex;
134        let idx = unsafe { BNGetLowLevelILNonSSAExprIndex(self.function.handle, self.index.0) };
135        LowLevelILExpression::new(non_ssa, LowLevelExpressionIndex(idx))
136    }
137}
138
139impl<M, R> LowLevelILExpression<'_, M, NonSSA, R>
140where
141    M: FunctionMutability,
142    R: ExpressionResultType,
143{
144    pub fn ssa_form<'func>(
145        &self,
146        ssa: &'func LowLevelILFunction<M, SSA>,
147    ) -> LowLevelILExpression<'func, M, SSA, R> {
148        use binaryninjacore_sys::BNGetLowLevelILSSAExprIndex;
149        let idx = unsafe { BNGetLowLevelILSSAExprIndex(self.function.handle, self.index.0) };
150        LowLevelILExpression::new(ssa, LowLevelExpressionIndex(idx))
151    }
152}
153
154impl<'func, M> ExpressionHandler<'func, M, SSA> for LowLevelILExpression<'func, M, SSA, ValueExpr>
155where
156    M: FunctionMutability,
157{
158    fn kind(&self) -> LowLevelILExpressionKind<'func, M, SSA> {
159        #[allow(unused_imports)]
160        use binaryninjacore_sys::BNLowLevelILOperation::*;
161        let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) };
162        #[allow(clippy::match_single_binding)]
163        match op.operation {
164            // Any invalid ops for SSA will be checked here.
165            // SAFETY: We have checked for illegal operations.
166            _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index),
167        }
168    }
169
170    fn visit_tree<T>(&self, f: &mut T) -> VisitorAction
171    where
172        T: FnMut(&LowLevelILExpression<'func, M, SSA, ValueExpr>) -> VisitorAction,
173    {
174        // Visit the current expression.
175        match f(self) {
176            VisitorAction::Descend => {
177                // Recursively visit sub expressions.
178                self.kind().visit_sub_expressions(|e| e.visit_tree(f))
179            }
180            action => action,
181        }
182    }
183}
184
185impl<'func, M> ExpressionHandler<'func, M, NonSSA>
186    for LowLevelILExpression<'func, M, NonSSA, ValueExpr>
187where
188    M: FunctionMutability,
189{
190    fn kind(&self) -> LowLevelILExpressionKind<'func, M, NonSSA> {
191        #[allow(unused_imports)]
192        use binaryninjacore_sys::BNLowLevelILOperation::*;
193        let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) };
194        #[allow(clippy::match_single_binding)]
195        match op.operation {
196            // Any invalid ops for Lifted IL will be checked here.
197            // SAFETY: We have checked for illegal operations.
198            _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index),
199        }
200    }
201
202    fn visit_tree<T>(&self, f: &mut T) -> VisitorAction
203    where
204        T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction,
205    {
206        // Visit the current expression.
207        match f(self) {
208            VisitorAction::Descend => {
209                // Recursively visit sub expressions.
210                self.kind().visit_sub_expressions(|e| e.visit_tree(f))
211            }
212            action => action,
213        }
214    }
215}
216
217impl<M, F> LowLevelILExpression<'_, M, F, ValueExpr>
218where
219    M: FunctionMutability,
220    F: FunctionForm,
221{
222    /// Value of expression if constant or a known value.
223    ///
224    /// NOTE: If a value is expressed but not concrete, use [`LowLevelILExpression::possible_values`].
225    pub fn value(&self) -> RegisterValue {
226        let value = unsafe { BNGetLowLevelILExprValue(self.function.handle, self.index.0) };
227        RegisterValue::from(value)
228    }
229
230    /// Possible values of expression using path-sensitive static data flow analysis
231    pub fn possible_values(&self) -> PossibleValueSet {
232        self.possible_values_with_opts(&[])
233    }
234
235    /// Possible values of expression using path-sensitive static data flow analysis
236    pub fn possible_values_with_opts(&self, options: &[DataFlowQueryOption]) -> PossibleValueSet {
237        let value = unsafe {
238            BNGetLowLevelILPossibleExprValues(
239                self.function.handle,
240                self.index.0,
241                options.as_ptr() as *mut _,
242                options.len(),
243            )
244        };
245        PossibleValueSet::from_owned_core_raw(value)
246    }
247
248    // TODO: Possible register, stack and flag values.
249}
250
251#[derive(Debug)]
252pub enum LowLevelILExpressionKind<'func, M, F>
253where
254    M: FunctionMutability,
255    F: FunctionForm,
256{
257    Load(Operation<'func, M, F, operation::Load>),
258    LoadSsa(Operation<'func, M, F, operation::LoadSsa>),
259    Pop(Operation<'func, M, F, operation::Pop>),
260    Reg(Operation<'func, M, F, operation::Reg>),
261    RegSsa(Operation<'func, M, F, operation::RegSsa>),
262    RegPartialSsa(Operation<'func, M, F, operation::RegPartialSsa>),
263    RegSplit(Operation<'func, M, F, operation::RegSplit>),
264    RegSplitSsa(Operation<'func, M, F, operation::RegSplitSsa>),
265    Const(Operation<'func, M, F, operation::Const>),
266    ConstPtr(Operation<'func, M, F, operation::Const>),
267    Flag(Operation<'func, M, F, operation::Flag>),
268    FlagBit(Operation<'func, M, F, operation::FlagBit>),
269    ExternPtr(Operation<'func, M, F, operation::Extern>),
270
271    RegStackPop(Operation<'func, M, F, operation::RegStackPop>),
272    RegStackFreeReg(Operation<'func, M, F, operation::RegStackPop>),
273
274    CallOutputSsa(Operation<'func, M, F, operation::CallOutputSsa>),
275    CallParamSsa(Operation<'func, M, F, operation::CallParamSsa>),
276    CallStackSsa(Operation<'func, M, F, operation::CallStackSsa>),
277
278    Add(Operation<'func, M, F, operation::BinaryOp>),
279    AddOverflow(Operation<'func, M, F, operation::BinaryOp>),
280    Adc(Operation<'func, M, F, operation::BinaryOpCarry>),
281    Sub(Operation<'func, M, F, operation::BinaryOp>),
282    Sbb(Operation<'func, M, F, operation::BinaryOpCarry>),
283    And(Operation<'func, M, F, operation::BinaryOp>),
284    Or(Operation<'func, M, F, operation::BinaryOp>),
285    Xor(Operation<'func, M, F, operation::BinaryOp>),
286    Lsl(Operation<'func, M, F, operation::BinaryOp>),
287    Lsr(Operation<'func, M, F, operation::BinaryOp>),
288    Asr(Operation<'func, M, F, operation::BinaryOp>),
289    Rol(Operation<'func, M, F, operation::BinaryOp>),
290    Rlc(Operation<'func, M, F, operation::BinaryOpCarry>),
291    Ror(Operation<'func, M, F, operation::BinaryOp>),
292    Rrc(Operation<'func, M, F, operation::BinaryOpCarry>),
293    Mul(Operation<'func, M, F, operation::BinaryOp>),
294
295    MulsDp(Operation<'func, M, F, operation::BinaryOp>),
296    MuluDp(Operation<'func, M, F, operation::BinaryOp>),
297
298    Divu(Operation<'func, M, F, operation::BinaryOp>),
299    Divs(Operation<'func, M, F, operation::BinaryOp>),
300
301    DivuDp(Operation<'func, M, F, operation::BinaryOp>),
302    DivsDp(Operation<'func, M, F, operation::BinaryOp>),
303
304    Modu(Operation<'func, M, F, operation::BinaryOp>),
305    Mods(Operation<'func, M, F, operation::BinaryOp>),
306
307    ModuDp(Operation<'func, M, F, operation::BinaryOp>),
308    ModsDp(Operation<'func, M, F, operation::BinaryOp>),
309
310    Neg(Operation<'func, M, F, operation::UnaryOp>),
311    Not(Operation<'func, M, F, operation::UnaryOp>),
312    Bswap(Operation<'func, M, F, operation::UnaryOp>),
313    Popcnt(Operation<'func, M, F, operation::UnaryOp>),
314    Clz(Operation<'func, M, F, operation::UnaryOp>),
315    Ctz(Operation<'func, M, F, operation::UnaryOp>),
316    Rbit(Operation<'func, M, F, operation::UnaryOp>),
317    Cls(Operation<'func, M, F, operation::UnaryOp>),
318
319    MinSigned(Operation<'func, M, F, operation::BinaryOp>),
320    MaxSigned(Operation<'func, M, F, operation::BinaryOp>),
321    MinUnsigned(Operation<'func, M, F, operation::BinaryOp>),
322    MaxUnsigned(Operation<'func, M, F, operation::BinaryOp>),
323    Abs(Operation<'func, M, F, operation::UnaryOp>),
324
325    Sx(Operation<'func, M, F, operation::UnaryOp>),
326    Zx(Operation<'func, M, F, operation::UnaryOp>),
327    LowPart(Operation<'func, M, F, operation::UnaryOp>),
328
329    // Valid only in Lifted IL
330    FlagCond(Operation<'func, M, F, operation::FlagCond>),
331    // Valid only in Lifted IL
332    FlagGroup(Operation<'func, M, F, operation::FlagGroup>),
333
334    CmpE(Operation<'func, M, F, operation::Condition>),
335    CmpNe(Operation<'func, M, F, operation::Condition>),
336    CmpSlt(Operation<'func, M, F, operation::Condition>),
337    CmpUlt(Operation<'func, M, F, operation::Condition>),
338    CmpSle(Operation<'func, M, F, operation::Condition>),
339    CmpUle(Operation<'func, M, F, operation::Condition>),
340    CmpSge(Operation<'func, M, F, operation::Condition>),
341    CmpUge(Operation<'func, M, F, operation::Condition>),
342    CmpSgt(Operation<'func, M, F, operation::Condition>),
343    CmpUgt(Operation<'func, M, F, operation::Condition>),
344
345    TestBit(Operation<'func, M, F, operation::BinaryOp>),
346    BoolToInt(Operation<'func, M, F, operation::UnaryOp>),
347
348    Fadd(Operation<'func, M, F, operation::BinaryOp>),
349    Fsub(Operation<'func, M, F, operation::BinaryOp>),
350    Fmul(Operation<'func, M, F, operation::BinaryOp>),
351    Fdiv(Operation<'func, M, F, operation::BinaryOp>),
352    Fsqrt(Operation<'func, M, F, operation::UnaryOp>),
353    Fneg(Operation<'func, M, F, operation::UnaryOp>),
354    Fabs(Operation<'func, M, F, operation::UnaryOp>),
355    FloatToInt(Operation<'func, M, F, operation::UnaryOp>),
356    IntToFloat(Operation<'func, M, F, operation::UnaryOp>),
357    FloatConv(Operation<'func, M, F, operation::UnaryOp>),
358    RoundToInt(Operation<'func, M, F, operation::UnaryOp>),
359    Floor(Operation<'func, M, F, operation::UnaryOp>),
360    Ceil(Operation<'func, M, F, operation::UnaryOp>),
361    Ftrunc(Operation<'func, M, F, operation::UnaryOp>),
362
363    FloatConst(Operation<'func, M, F, operation::FloatConst>),
364
365    FcmpE(Operation<'func, M, F, operation::Condition>),
366    FcmpNE(Operation<'func, M, F, operation::Condition>),
367    FcmpLT(Operation<'func, M, F, operation::Condition>),
368    FcmpLE(Operation<'func, M, F, operation::Condition>),
369    FcmpGE(Operation<'func, M, F, operation::Condition>),
370    FcmpGT(Operation<'func, M, F, operation::Condition>),
371    FcmpO(Operation<'func, M, F, operation::Condition>),
372    FcmpUO(Operation<'func, M, F, operation::Condition>),
373
374    SeparateParamListSsa(Operation<'func, M, F, operation::SeparateParamListSsa>),
375
376    Unimpl(Operation<'func, M, F, operation::NoArgs>),
377    UnimplMem(Operation<'func, M, F, operation::UnimplMem>),
378
379    Undef(Operation<'func, M, F, operation::NoArgs>),
380}
381
382impl<'func, M, F> LowLevelILExpressionKind<'func, M, F>
383where
384    M: FunctionMutability,
385    F: FunctionForm,
386{
387    pub(crate) fn from_raw(
388        function: &'func LowLevelILFunction<M, F>,
389        op: BNLowLevelILInstruction,
390        index: LowLevelExpressionIndex,
391    ) -> Self {
392        use binaryninjacore_sys::BNLowLevelILOperation::*;
393
394        match op.operation {
395            LLIL_LOAD => LowLevelILExpressionKind::Load(Operation::new(function, op, index)),
396            LLIL_LOAD_SSA => LowLevelILExpressionKind::LoadSsa(Operation::new(function, op, index)),
397            LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op, index)),
398            LLIL_REG => LowLevelILExpressionKind::Reg(Operation::new(function, op, index)),
399            LLIL_REG_SSA => LowLevelILExpressionKind::RegSsa(Operation::new(function, op, index)),
400            LLIL_REG_SSA_PARTIAL => {
401                LowLevelILExpressionKind::RegPartialSsa(Operation::new(function, op, index))
402            }
403            LLIL_REG_SPLIT => {
404                LowLevelILExpressionKind::RegSplit(Operation::new(function, op, index))
405            }
406            LLIL_REG_SPLIT_SSA => {
407                LowLevelILExpressionKind::RegSplitSsa(Operation::new(function, op, index))
408            }
409            LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op, index)),
410            LLIL_CONST_PTR => {
411                LowLevelILExpressionKind::ConstPtr(Operation::new(function, op, index))
412            }
413            LLIL_FLAG | LLIL_FLAG_SSA => {
414                LowLevelILExpressionKind::Flag(Operation::new(function, op, index))
415            }
416            LLIL_FLAG_GROUP => {
417                LowLevelILExpressionKind::FlagGroup(Operation::new(function, op, index))
418            }
419            LLIL_FLAG_COND => {
420                LowLevelILExpressionKind::FlagCond(Operation::new(function, op, index))
421            }
422            LLIL_FLAG_BIT | LLIL_FLAG_BIT_SSA => {
423                LowLevelILExpressionKind::FlagBit(Operation::new(function, op, index))
424            }
425            LLIL_EXTERN_PTR => {
426                LowLevelILExpressionKind::ExternPtr(Operation::new(function, op, index))
427            }
428
429            LLIL_REG_STACK_POP => {
430                LowLevelILExpressionKind::RegStackPop(Operation::new(function, op, index))
431            }
432            LLIL_REG_STACK_FREE_REG => {
433                LowLevelILExpressionKind::RegStackFreeReg(Operation::new(function, op, index))
434            }
435
436            LLIL_CALL_OUTPUT_SSA => {
437                LowLevelILExpressionKind::CallOutputSsa(Operation::new(function, op, index))
438            }
439            LLIL_CALL_PARAM => {
440                LowLevelILExpressionKind::CallParamSsa(Operation::new(function, op, index))
441            }
442            LLIL_CALL_STACK_SSA => {
443                LowLevelILExpressionKind::CallStackSsa(Operation::new(function, op, index))
444            }
445
446            LLIL_ADD => LowLevelILExpressionKind::Add(Operation::new(function, op, index)),
447            LLIL_ADD_OVERFLOW => {
448                LowLevelILExpressionKind::AddOverflow(Operation::new(function, op, index))
449            }
450            LLIL_ADC => LowLevelILExpressionKind::Adc(Operation::new(function, op, index)),
451            LLIL_SUB => LowLevelILExpressionKind::Sub(Operation::new(function, op, index)),
452            LLIL_SBB => LowLevelILExpressionKind::Sbb(Operation::new(function, op, index)),
453            LLIL_AND => LowLevelILExpressionKind::And(Operation::new(function, op, index)),
454            LLIL_OR => LowLevelILExpressionKind::Or(Operation::new(function, op, index)),
455            LLIL_XOR => LowLevelILExpressionKind::Xor(Operation::new(function, op, index)),
456            LLIL_LSL => LowLevelILExpressionKind::Lsl(Operation::new(function, op, index)),
457            LLIL_LSR => LowLevelILExpressionKind::Lsr(Operation::new(function, op, index)),
458            LLIL_ASR => LowLevelILExpressionKind::Asr(Operation::new(function, op, index)),
459            LLIL_ROL => LowLevelILExpressionKind::Rol(Operation::new(function, op, index)),
460            LLIL_RLC => LowLevelILExpressionKind::Rlc(Operation::new(function, op, index)),
461            LLIL_ROR => LowLevelILExpressionKind::Ror(Operation::new(function, op, index)),
462            LLIL_RRC => LowLevelILExpressionKind::Rrc(Operation::new(function, op, index)),
463            LLIL_MUL => LowLevelILExpressionKind::Mul(Operation::new(function, op, index)),
464
465            LLIL_MULU_DP => LowLevelILExpressionKind::MuluDp(Operation::new(function, op, index)),
466            LLIL_MULS_DP => LowLevelILExpressionKind::MulsDp(Operation::new(function, op, index)),
467
468            LLIL_DIVU => LowLevelILExpressionKind::Divu(Operation::new(function, op, index)),
469            LLIL_DIVS => LowLevelILExpressionKind::Divs(Operation::new(function, op, index)),
470
471            LLIL_DIVU_DP => LowLevelILExpressionKind::DivuDp(Operation::new(function, op, index)),
472            LLIL_DIVS_DP => LowLevelILExpressionKind::DivsDp(Operation::new(function, op, index)),
473
474            LLIL_MODU => LowLevelILExpressionKind::Modu(Operation::new(function, op, index)),
475            LLIL_MODS => LowLevelILExpressionKind::Mods(Operation::new(function, op, index)),
476
477            LLIL_MODU_DP => LowLevelILExpressionKind::ModuDp(Operation::new(function, op, index)),
478            LLIL_MODS_DP => LowLevelILExpressionKind::ModsDp(Operation::new(function, op, index)),
479
480            LLIL_NEG => LowLevelILExpressionKind::Neg(Operation::new(function, op, index)),
481            LLIL_NOT => LowLevelILExpressionKind::Not(Operation::new(function, op, index)),
482            LLIL_BSWAP => LowLevelILExpressionKind::Bswap(Operation::new(function, op, index)),
483            LLIL_POPCNT => LowLevelILExpressionKind::Popcnt(Operation::new(function, op, index)),
484            LLIL_CLZ => LowLevelILExpressionKind::Clz(Operation::new(function, op, index)),
485            LLIL_CTZ => LowLevelILExpressionKind::Ctz(Operation::new(function, op, index)),
486            LLIL_RBIT => LowLevelILExpressionKind::Rbit(Operation::new(function, op, index)),
487            LLIL_CLS => LowLevelILExpressionKind::Cls(Operation::new(function, op, index)),
488
489            LLIL_MINS => LowLevelILExpressionKind::MinSigned(Operation::new(function, op, index)),
490            LLIL_MAXS => LowLevelILExpressionKind::MaxSigned(Operation::new(function, op, index)),
491            LLIL_MINU => LowLevelILExpressionKind::MinUnsigned(Operation::new(function, op, index)),
492            LLIL_MAXU => LowLevelILExpressionKind::MaxUnsigned(Operation::new(function, op, index)),
493            LLIL_ABS => LowLevelILExpressionKind::Abs(Operation::new(function, op, index)),
494
495            LLIL_SX => LowLevelILExpressionKind::Sx(Operation::new(function, op, index)),
496            LLIL_ZX => LowLevelILExpressionKind::Zx(Operation::new(function, op, index)),
497            LLIL_LOW_PART => LowLevelILExpressionKind::LowPart(Operation::new(function, op, index)),
498
499            LLIL_CMP_E => LowLevelILExpressionKind::CmpE(Operation::new(function, op, index)),
500            LLIL_CMP_NE => LowLevelILExpressionKind::CmpNe(Operation::new(function, op, index)),
501            LLIL_CMP_SLT => LowLevelILExpressionKind::CmpSlt(Operation::new(function, op, index)),
502            LLIL_CMP_ULT => LowLevelILExpressionKind::CmpUlt(Operation::new(function, op, index)),
503            LLIL_CMP_SLE => LowLevelILExpressionKind::CmpSle(Operation::new(function, op, index)),
504            LLIL_CMP_ULE => LowLevelILExpressionKind::CmpUle(Operation::new(function, op, index)),
505            LLIL_CMP_SGE => LowLevelILExpressionKind::CmpSge(Operation::new(function, op, index)),
506            LLIL_CMP_UGE => LowLevelILExpressionKind::CmpUge(Operation::new(function, op, index)),
507            LLIL_CMP_SGT => LowLevelILExpressionKind::CmpSgt(Operation::new(function, op, index)),
508            LLIL_CMP_UGT => LowLevelILExpressionKind::CmpUgt(Operation::new(function, op, index)),
509
510            LLIL_TEST_BIT => LowLevelILExpressionKind::TestBit(Operation::new(function, op, index)),
511            LLIL_BOOL_TO_INT => {
512                LowLevelILExpressionKind::BoolToInt(Operation::new(function, op, index))
513            }
514
515            LLIL_FADD => LowLevelILExpressionKind::Fadd(Operation::new(function, op, index)),
516            LLIL_FSUB => LowLevelILExpressionKind::Fsub(Operation::new(function, op, index)),
517            LLIL_FMUL => LowLevelILExpressionKind::Fmul(Operation::new(function, op, index)),
518            LLIL_FDIV => LowLevelILExpressionKind::Fdiv(Operation::new(function, op, index)),
519
520            LLIL_FSQRT => LowLevelILExpressionKind::Fsqrt(Operation::new(function, op, index)),
521            LLIL_FNEG => LowLevelILExpressionKind::Fneg(Operation::new(function, op, index)),
522            LLIL_FABS => LowLevelILExpressionKind::Fabs(Operation::new(function, op, index)),
523            LLIL_FLOAT_TO_INT => {
524                LowLevelILExpressionKind::FloatToInt(Operation::new(function, op, index))
525            }
526            LLIL_INT_TO_FLOAT => {
527                LowLevelILExpressionKind::IntToFloat(Operation::new(function, op, index))
528            }
529            LLIL_FLOAT_CONV => {
530                LowLevelILExpressionKind::FloatConv(Operation::new(function, op, index))
531            }
532            LLIL_ROUND_TO_INT => {
533                LowLevelILExpressionKind::RoundToInt(Operation::new(function, op, index))
534            }
535            LLIL_FLOOR => LowLevelILExpressionKind::Floor(Operation::new(function, op, index)),
536            LLIL_CEIL => LowLevelILExpressionKind::Ceil(Operation::new(function, op, index)),
537            LLIL_FTRUNC => LowLevelILExpressionKind::Ftrunc(Operation::new(function, op, index)),
538
539            LLIL_FCMP_E => LowLevelILExpressionKind::FcmpE(Operation::new(function, op, index)),
540            LLIL_FCMP_NE => LowLevelILExpressionKind::FcmpNE(Operation::new(function, op, index)),
541            LLIL_FCMP_LT => LowLevelILExpressionKind::FcmpLT(Operation::new(function, op, index)),
542            LLIL_FCMP_LE => LowLevelILExpressionKind::FcmpLE(Operation::new(function, op, index)),
543            LLIL_FCMP_GT => LowLevelILExpressionKind::FcmpGT(Operation::new(function, op, index)),
544            LLIL_FCMP_GE => LowLevelILExpressionKind::FcmpGE(Operation::new(function, op, index)),
545            LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op, index)),
546            LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op, index)),
547
548            LLIL_FLOAT_CONST => {
549                LowLevelILExpressionKind::FloatConst(Operation::new(function, op, index))
550            }
551
552            LLIL_SEPARATE_PARAM_LIST_SSA => {
553                LowLevelILExpressionKind::SeparateParamListSsa(Operation::new(function, op, index))
554            }
555
556            LLIL_UNDEF => LowLevelILExpressionKind::Undef(Operation::new(function, op, index)),
557
558            LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op, index)),
559            LLIL_UNIMPL_MEM => {
560                LowLevelILExpressionKind::UnimplMem(Operation::new(function, op, index))
561            }
562
563            _ => {
564                tracing::error!(
565                    "Got unexpected operation {:?} in value expr at 0x{:x}",
566                    op.operation,
567                    op.address
568                );
569
570                LowLevelILExpressionKind::Undef(Operation::new(function, op, index))
571            }
572        }
573    }
574
575    /// Returns the size of the result of this expression
576    ///
577    /// If the expression is malformed or is `Unimpl` there
578    /// is no meaningful size associated with the result.
579    pub fn size(&self) -> Option<usize> {
580        use self::LowLevelILExpressionKind::*;
581
582        match *self {
583            Undef(..) | Unimpl(..) => None,
584
585            FlagCond(..) | FlagGroup(..) | CmpE(..) | CmpNe(..) | CmpSlt(..) | CmpUlt(..)
586            | CmpSle(..) | CmpUle(..) | CmpSge(..) | CmpUge(..) | CmpSgt(..) | CmpUgt(..) => {
587                Some(0)
588            }
589
590            _ => Some(self.raw_struct().size),
591        }
592    }
593
594    pub fn address(&self) -> u64 {
595        self.raw_struct().address
596    }
597
598    /// Determines if the expressions represent the same operation
599    ///
600    /// It does not examine the operands for equality.
601    pub fn is_same_op_as(&self, other: &Self) -> bool {
602        use self::LowLevelILExpressionKind::*;
603
604        match (self, other) {
605            (&Reg(..), &Reg(..)) => true,
606            _ => self.raw_struct().operation == other.raw_struct().operation,
607        }
608    }
609
610    pub fn as_cmp_op(&self) -> Option<&Operation<'func, M, F, operation::Condition>> {
611        use self::LowLevelILExpressionKind::*;
612
613        match *self {
614            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
615            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
616            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
617            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => Some(op),
618            _ => None,
619        }
620    }
621
622    pub fn as_binary_op(&self) -> Option<&Operation<'func, M, F, operation::BinaryOp>> {
623        use self::LowLevelILExpressionKind::*;
624
625        match *self {
626            Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
627            | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op)
628            | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op)
629            | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op)
630            | DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op)
631            | MinSigned(ref op) | MaxSigned(ref op) | MinUnsigned(ref op) | MaxUnsigned(ref op) => {
632                Some(op)
633            }
634            _ => None,
635        }
636    }
637
638    pub fn as_binary_op_carry(&self) -> Option<&Operation<'func, M, F, operation::BinaryOpCarry>> {
639        use self::LowLevelILExpressionKind::*;
640
641        match *self {
642            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => Some(op),
643            _ => None,
644        }
645    }
646
647    pub fn as_unary_op(&self) -> Option<&Operation<'func, M, F, operation::UnaryOp>> {
648        use self::LowLevelILExpressionKind::*;
649
650        match *self {
651            Neg(ref op) | Not(ref op) | Bswap(ref op) | Popcnt(ref op) | Clz(ref op)
652            | Ctz(ref op) | Rbit(ref op) | Cls(ref op) | Abs(ref op) | Sx(ref op) | Zx(ref op)
653            | LowPart(ref op) | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
654            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
655            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => Some(op),
656            _ => None,
657        }
658    }
659
660    pub fn visit_sub_expressions<T>(&self, mut visitor: T) -> VisitorAction
661    where
662        T: FnMut(LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction,
663    {
664        use LowLevelILExpressionKind::*;
665
666        macro_rules! visit {
667            ($expr:expr) => {
668                if let VisitorAction::Halt = visitor($expr) {
669                    return VisitorAction::Halt;
670                }
671            };
672        }
673
674        match self {
675            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
676            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
677            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
678            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => {
679                visit!(op.left());
680                visit!(op.right());
681            }
682            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => {
683                visit!(op.left());
684                visit!(op.right());
685                visit!(op.carry());
686            }
687            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
688            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
689            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
690            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
691            | DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) | Fdiv(ref op)
692            | MinSigned(ref op) | MaxSigned(ref op) | MinUnsigned(ref op) | MaxUnsigned(ref op)
693            | TestBit(ref op) => {
694                visit!(op.left());
695                visit!(op.right());
696            }
697            Neg(ref op) | Not(ref op) | Bswap(ref op) | Popcnt(ref op) | Clz(ref op)
698            | Ctz(ref op) | Rbit(ref op) | Cls(ref op) | Abs(ref op) | Sx(ref op) | Zx(ref op)
699            | LowPart(ref op) | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
700            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
701            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => {
702                visit!(op.operand());
703            }
704            UnimplMem(ref op) => {
705                visit!(op.mem_expr());
706            }
707            Load(ref op) => {
708                visit!(op.source_expr());
709            }
710            LoadSsa(ref op) => {
711                visit!(op.source_expr());
712            }
713            CallParamSsa(ref op) => {
714                for param_expr in op.param_exprs() {
715                    visit!(param_expr);
716                }
717            }
718            SeparateParamListSsa(ref op) => {
719                for param_expr in op.param_exprs() {
720                    visit!(param_expr);
721                }
722            }
723            // Do not have any sub expressions.
724            Pop(_) | Reg(_) | RegSsa(_) | RegPartialSsa(_) | RegSplit(_) | RegSplitSsa(_)
725            | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) | ExternPtr(_) | FlagCond(_)
726            | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) | RegStackFreeReg(_)
727            | CallOutputSsa(_) | CallStackSsa(_) | FloatConst(_) => {}
728        }
729
730        VisitorAction::Sibling
731    }
732
733    pub(crate) fn raw_struct(&self) -> &BNLowLevelILInstruction {
734        use self::LowLevelILExpressionKind::*;
735
736        match *self {
737            Undef(ref op) => &op.op,
738
739            Unimpl(ref op) => &op.op,
740
741            FlagCond(ref op) => &op.op,
742            FlagGroup(ref op) => &op.op,
743
744            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
745            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
746            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
747            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => &op.op,
748
749            Load(ref op) => &op.op,
750
751            LoadSsa(ref op) => &op.op,
752
753            Pop(ref op) => &op.op,
754
755            Reg(ref op) => &op.op,
756
757            RegSsa(ref op) => &op.op,
758
759            RegPartialSsa(ref op) => &op.op,
760
761            RegSplit(ref op) => &op.op,
762
763            RegSplitSsa(ref op) => &op.op,
764
765            Flag(ref op) => &op.op,
766
767            FlagBit(ref op) => &op.op,
768
769            Const(ref op) | ConstPtr(ref op) => &op.op,
770
771            FloatConst(ref op) => &op.op,
772
773            ExternPtr(ref op) => &op.op,
774
775            RegStackPop(ref op) => &op.op,
776            RegStackFreeReg(ref op) => &op.op,
777
778            CallOutputSsa(ref op) => &op.op,
779            CallParamSsa(ref op) => &op.op,
780            CallStackSsa(ref op) => &op.op,
781
782            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => &op.op,
783
784            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
785            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
786            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
787            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
788            | MinSigned(ref op) | MaxSigned(ref op) | MinUnsigned(ref op) | MaxUnsigned(ref op)
789            | Fdiv(ref op) | TestBit(ref op) => &op.op,
790
791            DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => &op.op,
792
793            Neg(ref op) | Not(ref op) | Bswap(ref op) | Popcnt(ref op) | Clz(ref op)
794            | Ctz(ref op) | Rbit(ref op) | Cls(ref op) | Abs(ref op) | Sx(ref op) | Zx(ref op)
795            | LowPart(ref op) | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
796            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
797            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op,
798
799            SeparateParamListSsa(ref op) => &op.op,
800
801            UnimplMem(ref op) => &op.op,
802        }
803    }
804}
805
806impl LowLevelILExpressionKind<'_, Mutable, NonSSA> {
807    pub fn flag_write(&self) -> Option<CoreFlagWrite> {
808        use self::LowLevelILExpressionKind::*;
809
810        match *self {
811            Undef(ref _op) => None,
812
813            Unimpl(ref _op) => None,
814
815            FlagCond(ref _op) => None,
816            FlagGroup(ref _op) => None,
817
818            CmpE(ref _op) | CmpNe(ref _op) | CmpSlt(ref _op) | CmpUlt(ref _op)
819            | CmpSle(ref _op) | CmpUle(ref _op) | CmpSge(ref _op) | CmpUge(ref _op)
820            | CmpSgt(ref _op) | CmpUgt(ref _op) | FcmpE(ref _op) | FcmpNE(ref _op)
821            | FcmpLT(ref _op) | FcmpLE(ref _op) | FcmpGE(ref _op) | FcmpGT(ref _op)
822            | FcmpO(ref _op) | FcmpUO(ref _op) => None,
823
824            Load(ref op) => op.flag_write(),
825
826            LoadSsa(ref op) => op.flag_write(),
827
828            Pop(ref op) => op.flag_write(),
829
830            Reg(ref op) => op.flag_write(),
831
832            RegSsa(ref op) => op.flag_write(),
833
834            RegPartialSsa(ref op) => op.flag_write(),
835
836            RegSplit(ref op) => op.flag_write(),
837
838            RegSplitSsa(ref op) => op.flag_write(),
839
840            Flag(ref op) => op.flag_write(),
841
842            FlagBit(ref op) => op.flag_write(),
843
844            Const(ref op) | ConstPtr(ref op) => op.flag_write(),
845
846            FloatConst(ref op) => op.flag_write(),
847
848            ExternPtr(ref op) => op.flag_write(),
849
850            RegStackPop(ref op) => op.flag_write(),
851            RegStackFreeReg(ref op) => op.flag_write(),
852
853            CallOutputSsa(ref op) => op.flag_write(),
854            CallParamSsa(ref op) => op.flag_write(),
855            CallStackSsa(ref op) => op.flag_write(),
856
857            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => op.flag_write(),
858
859            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
860            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
861            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
862            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
863            | MinSigned(ref op) | MaxSigned(ref op) | MinUnsigned(ref op) | MaxUnsigned(ref op)
864            | Fdiv(ref op) | TestBit(ref op) => op.flag_write(),
865
866            DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => op.flag_write(),
867
868            Neg(ref op) | Not(ref op) | Bswap(ref op) | Popcnt(ref op) | Clz(ref op)
869            | Ctz(ref op) | Rbit(ref op) | Cls(ref op) | Abs(ref op) | Sx(ref op) | Zx(ref op)
870            | LowPart(ref op) | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
871            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
872            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(),
873
874            SeparateParamListSsa(ref op) => op.flag_write(),
875
876            UnimplMem(ref op) => op.flag_write(),
877        }
878    }
879}