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    Sx(Operation<'func, M, F, operation::UnaryOp>),
313    Zx(Operation<'func, M, F, operation::UnaryOp>),
314    LowPart(Operation<'func, M, F, operation::UnaryOp>),
315
316    // Valid only in Lifted IL
317    FlagCond(Operation<'func, M, F, operation::FlagCond>),
318    // Valid only in Lifted IL
319    FlagGroup(Operation<'func, M, F, operation::FlagGroup>),
320
321    CmpE(Operation<'func, M, F, operation::Condition>),
322    CmpNe(Operation<'func, M, F, operation::Condition>),
323    CmpSlt(Operation<'func, M, F, operation::Condition>),
324    CmpUlt(Operation<'func, M, F, operation::Condition>),
325    CmpSle(Operation<'func, M, F, operation::Condition>),
326    CmpUle(Operation<'func, M, F, operation::Condition>),
327    CmpSge(Operation<'func, M, F, operation::Condition>),
328    CmpUge(Operation<'func, M, F, operation::Condition>),
329    CmpSgt(Operation<'func, M, F, operation::Condition>),
330    CmpUgt(Operation<'func, M, F, operation::Condition>),
331
332    TestBit(Operation<'func, M, F, operation::BinaryOp>),
333    BoolToInt(Operation<'func, M, F, operation::UnaryOp>),
334
335    Fadd(Operation<'func, M, F, operation::BinaryOp>),
336    Fsub(Operation<'func, M, F, operation::BinaryOp>),
337    Fmul(Operation<'func, M, F, operation::BinaryOp>),
338    Fdiv(Operation<'func, M, F, operation::BinaryOp>),
339    Fsqrt(Operation<'func, M, F, operation::UnaryOp>),
340    Fneg(Operation<'func, M, F, operation::UnaryOp>),
341    Fabs(Operation<'func, M, F, operation::UnaryOp>),
342    FloatToInt(Operation<'func, M, F, operation::UnaryOp>),
343    IntToFloat(Operation<'func, M, F, operation::UnaryOp>),
344    FloatConv(Operation<'func, M, F, operation::UnaryOp>),
345    RoundToInt(Operation<'func, M, F, operation::UnaryOp>),
346    Floor(Operation<'func, M, F, operation::UnaryOp>),
347    Ceil(Operation<'func, M, F, operation::UnaryOp>),
348    Ftrunc(Operation<'func, M, F, operation::UnaryOp>),
349
350    FloatConst(Operation<'func, M, F, operation::FloatConst>),
351
352    FcmpE(Operation<'func, M, F, operation::Condition>),
353    FcmpNE(Operation<'func, M, F, operation::Condition>),
354    FcmpLT(Operation<'func, M, F, operation::Condition>),
355    FcmpLE(Operation<'func, M, F, operation::Condition>),
356    FcmpGE(Operation<'func, M, F, operation::Condition>),
357    FcmpGT(Operation<'func, M, F, operation::Condition>),
358    FcmpO(Operation<'func, M, F, operation::Condition>),
359    FcmpUO(Operation<'func, M, F, operation::Condition>),
360
361    SeparateParamListSsa(Operation<'func, M, F, operation::SeparateParamListSsa>),
362
363    Unimpl(Operation<'func, M, F, operation::NoArgs>),
364    UnimplMem(Operation<'func, M, F, operation::UnimplMem>),
365
366    Undef(Operation<'func, M, F, operation::NoArgs>),
367}
368
369impl<'func, M, F> LowLevelILExpressionKind<'func, M, F>
370where
371    M: FunctionMutability,
372    F: FunctionForm,
373{
374    pub(crate) fn from_raw(
375        function: &'func LowLevelILFunction<M, F>,
376        op: BNLowLevelILInstruction,
377        index: LowLevelExpressionIndex,
378    ) -> Self {
379        use binaryninjacore_sys::BNLowLevelILOperation::*;
380
381        match op.operation {
382            LLIL_LOAD => LowLevelILExpressionKind::Load(Operation::new(function, op, index)),
383            LLIL_LOAD_SSA => LowLevelILExpressionKind::LoadSsa(Operation::new(function, op, index)),
384            LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op, index)),
385            LLIL_REG => LowLevelILExpressionKind::Reg(Operation::new(function, op, index)),
386            LLIL_REG_SSA => LowLevelILExpressionKind::RegSsa(Operation::new(function, op, index)),
387            LLIL_REG_SSA_PARTIAL => {
388                LowLevelILExpressionKind::RegPartialSsa(Operation::new(function, op, index))
389            }
390            LLIL_REG_SPLIT => {
391                LowLevelILExpressionKind::RegSplit(Operation::new(function, op, index))
392            }
393            LLIL_REG_SPLIT_SSA => {
394                LowLevelILExpressionKind::RegSplitSsa(Operation::new(function, op, index))
395            }
396            LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op, index)),
397            LLIL_CONST_PTR => {
398                LowLevelILExpressionKind::ConstPtr(Operation::new(function, op, index))
399            }
400            LLIL_FLAG | LLIL_FLAG_SSA => {
401                LowLevelILExpressionKind::Flag(Operation::new(function, op, index))
402            }
403            LLIL_FLAG_GROUP => {
404                LowLevelILExpressionKind::FlagGroup(Operation::new(function, op, index))
405            }
406            LLIL_FLAG_COND => {
407                LowLevelILExpressionKind::FlagCond(Operation::new(function, op, index))
408            }
409            LLIL_FLAG_BIT | LLIL_FLAG_BIT_SSA => {
410                LowLevelILExpressionKind::FlagBit(Operation::new(function, op, index))
411            }
412            LLIL_EXTERN_PTR => {
413                LowLevelILExpressionKind::ExternPtr(Operation::new(function, op, index))
414            }
415
416            LLIL_REG_STACK_POP => {
417                LowLevelILExpressionKind::RegStackPop(Operation::new(function, op, index))
418            }
419            LLIL_REG_STACK_FREE_REG => {
420                LowLevelILExpressionKind::RegStackFreeReg(Operation::new(function, op, index))
421            }
422
423            LLIL_CALL_OUTPUT_SSA => {
424                LowLevelILExpressionKind::CallOutputSsa(Operation::new(function, op, index))
425            }
426            LLIL_CALL_PARAM => {
427                LowLevelILExpressionKind::CallParamSsa(Operation::new(function, op, index))
428            }
429            LLIL_CALL_STACK_SSA => {
430                LowLevelILExpressionKind::CallStackSsa(Operation::new(function, op, index))
431            }
432
433            LLIL_ADD => LowLevelILExpressionKind::Add(Operation::new(function, op, index)),
434            LLIL_ADD_OVERFLOW => {
435                LowLevelILExpressionKind::AddOverflow(Operation::new(function, op, index))
436            }
437            LLIL_ADC => LowLevelILExpressionKind::Adc(Operation::new(function, op, index)),
438            LLIL_SUB => LowLevelILExpressionKind::Sub(Operation::new(function, op, index)),
439            LLIL_SBB => LowLevelILExpressionKind::Sbb(Operation::new(function, op, index)),
440            LLIL_AND => LowLevelILExpressionKind::And(Operation::new(function, op, index)),
441            LLIL_OR => LowLevelILExpressionKind::Or(Operation::new(function, op, index)),
442            LLIL_XOR => LowLevelILExpressionKind::Xor(Operation::new(function, op, index)),
443            LLIL_LSL => LowLevelILExpressionKind::Lsl(Operation::new(function, op, index)),
444            LLIL_LSR => LowLevelILExpressionKind::Lsr(Operation::new(function, op, index)),
445            LLIL_ASR => LowLevelILExpressionKind::Asr(Operation::new(function, op, index)),
446            LLIL_ROL => LowLevelILExpressionKind::Rol(Operation::new(function, op, index)),
447            LLIL_RLC => LowLevelILExpressionKind::Rlc(Operation::new(function, op, index)),
448            LLIL_ROR => LowLevelILExpressionKind::Ror(Operation::new(function, op, index)),
449            LLIL_RRC => LowLevelILExpressionKind::Rrc(Operation::new(function, op, index)),
450            LLIL_MUL => LowLevelILExpressionKind::Mul(Operation::new(function, op, index)),
451
452            LLIL_MULU_DP => LowLevelILExpressionKind::MuluDp(Operation::new(function, op, index)),
453            LLIL_MULS_DP => LowLevelILExpressionKind::MulsDp(Operation::new(function, op, index)),
454
455            LLIL_DIVU => LowLevelILExpressionKind::Divu(Operation::new(function, op, index)),
456            LLIL_DIVS => LowLevelILExpressionKind::Divs(Operation::new(function, op, index)),
457
458            LLIL_DIVU_DP => LowLevelILExpressionKind::DivuDp(Operation::new(function, op, index)),
459            LLIL_DIVS_DP => LowLevelILExpressionKind::DivsDp(Operation::new(function, op, index)),
460
461            LLIL_MODU => LowLevelILExpressionKind::Modu(Operation::new(function, op, index)),
462            LLIL_MODS => LowLevelILExpressionKind::Mods(Operation::new(function, op, index)),
463
464            LLIL_MODU_DP => LowLevelILExpressionKind::ModuDp(Operation::new(function, op, index)),
465            LLIL_MODS_DP => LowLevelILExpressionKind::ModsDp(Operation::new(function, op, index)),
466
467            LLIL_NEG => LowLevelILExpressionKind::Neg(Operation::new(function, op, index)),
468            LLIL_NOT => LowLevelILExpressionKind::Not(Operation::new(function, op, index)),
469
470            LLIL_SX => LowLevelILExpressionKind::Sx(Operation::new(function, op, index)),
471            LLIL_ZX => LowLevelILExpressionKind::Zx(Operation::new(function, op, index)),
472            LLIL_LOW_PART => LowLevelILExpressionKind::LowPart(Operation::new(function, op, index)),
473
474            LLIL_CMP_E => LowLevelILExpressionKind::CmpE(Operation::new(function, op, index)),
475            LLIL_CMP_NE => LowLevelILExpressionKind::CmpNe(Operation::new(function, op, index)),
476            LLIL_CMP_SLT => LowLevelILExpressionKind::CmpSlt(Operation::new(function, op, index)),
477            LLIL_CMP_ULT => LowLevelILExpressionKind::CmpUlt(Operation::new(function, op, index)),
478            LLIL_CMP_SLE => LowLevelILExpressionKind::CmpSle(Operation::new(function, op, index)),
479            LLIL_CMP_ULE => LowLevelILExpressionKind::CmpUle(Operation::new(function, op, index)),
480            LLIL_CMP_SGE => LowLevelILExpressionKind::CmpSge(Operation::new(function, op, index)),
481            LLIL_CMP_UGE => LowLevelILExpressionKind::CmpUge(Operation::new(function, op, index)),
482            LLIL_CMP_SGT => LowLevelILExpressionKind::CmpSgt(Operation::new(function, op, index)),
483            LLIL_CMP_UGT => LowLevelILExpressionKind::CmpUgt(Operation::new(function, op, index)),
484
485            LLIL_TEST_BIT => LowLevelILExpressionKind::TestBit(Operation::new(function, op, index)),
486            LLIL_BOOL_TO_INT => {
487                LowLevelILExpressionKind::BoolToInt(Operation::new(function, op, index))
488            }
489
490            LLIL_FADD => LowLevelILExpressionKind::Fadd(Operation::new(function, op, index)),
491            LLIL_FSUB => LowLevelILExpressionKind::Fsub(Operation::new(function, op, index)),
492            LLIL_FMUL => LowLevelILExpressionKind::Fmul(Operation::new(function, op, index)),
493            LLIL_FDIV => LowLevelILExpressionKind::Fdiv(Operation::new(function, op, index)),
494
495            LLIL_FSQRT => LowLevelILExpressionKind::Fsqrt(Operation::new(function, op, index)),
496            LLIL_FNEG => LowLevelILExpressionKind::Fneg(Operation::new(function, op, index)),
497            LLIL_FABS => LowLevelILExpressionKind::Fabs(Operation::new(function, op, index)),
498            LLIL_FLOAT_TO_INT => {
499                LowLevelILExpressionKind::FloatToInt(Operation::new(function, op, index))
500            }
501            LLIL_INT_TO_FLOAT => {
502                LowLevelILExpressionKind::IntToFloat(Operation::new(function, op, index))
503            }
504            LLIL_FLOAT_CONV => {
505                LowLevelILExpressionKind::FloatConv(Operation::new(function, op, index))
506            }
507            LLIL_ROUND_TO_INT => {
508                LowLevelILExpressionKind::RoundToInt(Operation::new(function, op, index))
509            }
510            LLIL_FLOOR => LowLevelILExpressionKind::Floor(Operation::new(function, op, index)),
511            LLIL_CEIL => LowLevelILExpressionKind::Ceil(Operation::new(function, op, index)),
512            LLIL_FTRUNC => LowLevelILExpressionKind::Ftrunc(Operation::new(function, op, index)),
513
514            LLIL_FCMP_E => LowLevelILExpressionKind::FcmpE(Operation::new(function, op, index)),
515            LLIL_FCMP_NE => LowLevelILExpressionKind::FcmpNE(Operation::new(function, op, index)),
516            LLIL_FCMP_LT => LowLevelILExpressionKind::FcmpLT(Operation::new(function, op, index)),
517            LLIL_FCMP_LE => LowLevelILExpressionKind::FcmpLE(Operation::new(function, op, index)),
518            LLIL_FCMP_GT => LowLevelILExpressionKind::FcmpGT(Operation::new(function, op, index)),
519            LLIL_FCMP_GE => LowLevelILExpressionKind::FcmpGE(Operation::new(function, op, index)),
520            LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op, index)),
521            LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op, index)),
522
523            LLIL_FLOAT_CONST => {
524                LowLevelILExpressionKind::FloatConst(Operation::new(function, op, index))
525            }
526
527            LLIL_SEPARATE_PARAM_LIST_SSA => {
528                LowLevelILExpressionKind::SeparateParamListSsa(Operation::new(function, op, index))
529            }
530
531            LLIL_UNDEF => LowLevelILExpressionKind::Undef(Operation::new(function, op, index)),
532
533            LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op, index)),
534            LLIL_UNIMPL_MEM => {
535                LowLevelILExpressionKind::UnimplMem(Operation::new(function, op, index))
536            }
537
538            _ => {
539                tracing::error!(
540                    "Got unexpected operation {:?} in value expr at 0x{:x}",
541                    op.operation,
542                    op.address
543                );
544
545                LowLevelILExpressionKind::Undef(Operation::new(function, op, index))
546            }
547        }
548    }
549
550    /// Returns the size of the result of this expression
551    ///
552    /// If the expression is malformed or is `Unimpl` there
553    /// is no meaningful size associated with the result.
554    pub fn size(&self) -> Option<usize> {
555        use self::LowLevelILExpressionKind::*;
556
557        match *self {
558            Undef(..) | Unimpl(..) => None,
559
560            FlagCond(..) | FlagGroup(..) | CmpE(..) | CmpNe(..) | CmpSlt(..) | CmpUlt(..)
561            | CmpSle(..) | CmpUle(..) | CmpSge(..) | CmpUge(..) | CmpSgt(..) | CmpUgt(..) => {
562                Some(0)
563            }
564
565            _ => Some(self.raw_struct().size),
566        }
567    }
568
569    pub fn address(&self) -> u64 {
570        self.raw_struct().address
571    }
572
573    /// Determines if the expressions represent the same operation
574    ///
575    /// It does not examine the operands for equality.
576    pub fn is_same_op_as(&self, other: &Self) -> bool {
577        use self::LowLevelILExpressionKind::*;
578
579        match (self, other) {
580            (&Reg(..), &Reg(..)) => true,
581            _ => self.raw_struct().operation == other.raw_struct().operation,
582        }
583    }
584
585    pub fn as_cmp_op(&self) -> Option<&Operation<'func, M, F, operation::Condition>> {
586        use self::LowLevelILExpressionKind::*;
587
588        match *self {
589            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
590            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
591            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
592            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => Some(op),
593            _ => None,
594        }
595    }
596
597    pub fn as_binary_op(&self) -> Option<&Operation<'func, M, F, operation::BinaryOp>> {
598        use self::LowLevelILExpressionKind::*;
599
600        match *self {
601            Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
602            | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op)
603            | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op)
604            | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op)
605            | DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => Some(op),
606            _ => None,
607        }
608    }
609
610    pub fn as_binary_op_carry(&self) -> Option<&Operation<'func, M, F, operation::BinaryOpCarry>> {
611        use self::LowLevelILExpressionKind::*;
612
613        match *self {
614            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => Some(op),
615            _ => None,
616        }
617    }
618
619    pub fn as_unary_op(&self) -> Option<&Operation<'func, M, F, operation::UnaryOp>> {
620        use self::LowLevelILExpressionKind::*;
621
622        match *self {
623            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
624            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
625            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
626            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => Some(op),
627            _ => None,
628        }
629    }
630
631    pub fn visit_sub_expressions<T>(&self, mut visitor: T) -> VisitorAction
632    where
633        T: FnMut(LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction,
634    {
635        use LowLevelILExpressionKind::*;
636
637        macro_rules! visit {
638            ($expr:expr) => {
639                if let VisitorAction::Halt = visitor($expr) {
640                    return VisitorAction::Halt;
641                }
642            };
643        }
644
645        match self {
646            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
647            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
648            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
649            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => {
650                visit!(op.left());
651                visit!(op.right());
652            }
653            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => {
654                visit!(op.left());
655                visit!(op.right());
656                visit!(op.carry());
657            }
658            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
659            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
660            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
661            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
662            | DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) | Fdiv(ref op)
663            | TestBit(ref op) => {
664                visit!(op.left());
665                visit!(op.right());
666            }
667            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
668            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
669            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
670            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => {
671                visit!(op.operand());
672            }
673            UnimplMem(ref op) => {
674                visit!(op.mem_expr());
675            }
676            Load(ref op) => {
677                visit!(op.source_expr());
678            }
679            LoadSsa(ref op) => {
680                visit!(op.source_expr());
681            }
682            CallParamSsa(ref op) => {
683                for param_expr in op.param_exprs() {
684                    visit!(param_expr);
685                }
686            }
687            SeparateParamListSsa(ref op) => {
688                for param_expr in op.param_exprs() {
689                    visit!(param_expr);
690                }
691            }
692            // Do not have any sub expressions.
693            Pop(_) | Reg(_) | RegSsa(_) | RegPartialSsa(_) | RegSplit(_) | RegSplitSsa(_)
694            | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) | ExternPtr(_) | FlagCond(_)
695            | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) | RegStackFreeReg(_)
696            | CallOutputSsa(_) | CallStackSsa(_) | FloatConst(_) => {}
697        }
698
699        VisitorAction::Sibling
700    }
701
702    pub(crate) fn raw_struct(&self) -> &BNLowLevelILInstruction {
703        use self::LowLevelILExpressionKind::*;
704
705        match *self {
706            Undef(ref op) => &op.op,
707
708            Unimpl(ref op) => &op.op,
709
710            FlagCond(ref op) => &op.op,
711            FlagGroup(ref op) => &op.op,
712
713            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
714            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
715            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
716            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => &op.op,
717
718            Load(ref op) => &op.op,
719
720            LoadSsa(ref op) => &op.op,
721
722            Pop(ref op) => &op.op,
723
724            Reg(ref op) => &op.op,
725
726            RegSsa(ref op) => &op.op,
727
728            RegPartialSsa(ref op) => &op.op,
729
730            RegSplit(ref op) => &op.op,
731
732            RegSplitSsa(ref op) => &op.op,
733
734            Flag(ref op) => &op.op,
735
736            FlagBit(ref op) => &op.op,
737
738            Const(ref op) | ConstPtr(ref op) => &op.op,
739
740            FloatConst(ref op) => &op.op,
741
742            ExternPtr(ref op) => &op.op,
743
744            RegStackPop(ref op) => &op.op,
745            RegStackFreeReg(ref op) => &op.op,
746
747            CallOutputSsa(ref op) => &op.op,
748            CallParamSsa(ref op) => &op.op,
749            CallStackSsa(ref op) => &op.op,
750
751            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => &op.op,
752
753            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
754            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
755            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
756            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
757            | Fdiv(ref op) | TestBit(ref op) => &op.op,
758
759            DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => &op.op,
760
761            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
762            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
763            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
764            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op,
765
766            SeparateParamListSsa(ref op) => &op.op,
767
768            UnimplMem(ref op) => &op.op,
769        }
770    }
771}
772
773impl LowLevelILExpressionKind<'_, Mutable, NonSSA> {
774    pub fn flag_write(&self) -> Option<CoreFlagWrite> {
775        use self::LowLevelILExpressionKind::*;
776
777        match *self {
778            Undef(ref _op) => None,
779
780            Unimpl(ref _op) => None,
781
782            FlagCond(ref _op) => None,
783            FlagGroup(ref _op) => None,
784
785            CmpE(ref _op) | CmpNe(ref _op) | CmpSlt(ref _op) | CmpUlt(ref _op)
786            | CmpSle(ref _op) | CmpUle(ref _op) | CmpSge(ref _op) | CmpUge(ref _op)
787            | CmpSgt(ref _op) | CmpUgt(ref _op) | FcmpE(ref _op) | FcmpNE(ref _op)
788            | FcmpLT(ref _op) | FcmpLE(ref _op) | FcmpGE(ref _op) | FcmpGT(ref _op)
789            | FcmpO(ref _op) | FcmpUO(ref _op) => None,
790
791            Load(ref op) => op.flag_write(),
792
793            LoadSsa(ref op) => op.flag_write(),
794
795            Pop(ref op) => op.flag_write(),
796
797            Reg(ref op) => op.flag_write(),
798
799            RegSsa(ref op) => op.flag_write(),
800
801            RegPartialSsa(ref op) => op.flag_write(),
802
803            RegSplit(ref op) => op.flag_write(),
804
805            RegSplitSsa(ref op) => op.flag_write(),
806
807            Flag(ref op) => op.flag_write(),
808
809            FlagBit(ref op) => op.flag_write(),
810
811            Const(ref op) | ConstPtr(ref op) => op.flag_write(),
812
813            FloatConst(ref op) => op.flag_write(),
814
815            ExternPtr(ref op) => op.flag_write(),
816
817            RegStackPop(ref op) => op.flag_write(),
818            RegStackFreeReg(ref op) => op.flag_write(),
819
820            CallOutputSsa(ref op) => op.flag_write(),
821            CallParamSsa(ref op) => op.flag_write(),
822            CallStackSsa(ref op) => op.flag_write(),
823
824            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => op.flag_write(),
825
826            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
827            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
828            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
829            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
830            | Fdiv(ref op) | TestBit(ref op) => op.flag_write(),
831
832            DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => op.flag_write(),
833
834            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
835            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
836            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
837            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(),
838
839            SeparateParamListSsa(ref op) => op.flag_write(),
840
841            UnimplMem(ref op) => op.flag_write(),
842        }
843    }
844}