binaryninja/low_level_il/
expression.rs

1// Copyright 2021-2025 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                // #[cfg(debug_assertions)]
540                log::error!(
541                    "Got unexpected operation {:?} in value expr at 0x{:x}",
542                    op.operation,
543                    op.address
544                );
545
546                LowLevelILExpressionKind::Undef(Operation::new(function, op, index))
547            }
548        }
549    }
550
551    /// Returns the size of the result of this expression
552    ///
553    /// If the expression is malformed or is `Unimpl` there
554    /// is no meaningful size associated with the result.
555    pub fn size(&self) -> Option<usize> {
556        use self::LowLevelILExpressionKind::*;
557
558        match *self {
559            Undef(..) | Unimpl(..) => None,
560
561            FlagCond(..) | FlagGroup(..) | CmpE(..) | CmpNe(..) | CmpSlt(..) | CmpUlt(..)
562            | CmpSle(..) | CmpUle(..) | CmpSge(..) | CmpUge(..) | CmpSgt(..) | CmpUgt(..) => {
563                Some(0)
564            }
565
566            _ => Some(self.raw_struct().size),
567        }
568    }
569
570    pub fn address(&self) -> u64 {
571        self.raw_struct().address
572    }
573
574    /// Determines if the expressions represent the same operation
575    ///
576    /// It does not examine the operands for equality.
577    pub fn is_same_op_as(&self, other: &Self) -> bool {
578        use self::LowLevelILExpressionKind::*;
579
580        match (self, other) {
581            (&Reg(..), &Reg(..)) => true,
582            _ => self.raw_struct().operation == other.raw_struct().operation,
583        }
584    }
585
586    pub fn as_cmp_op(&self) -> Option<&Operation<'func, M, F, operation::Condition>> {
587        use self::LowLevelILExpressionKind::*;
588
589        match *self {
590            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
591            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
592            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
593            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => Some(op),
594            _ => None,
595        }
596    }
597
598    pub fn as_binary_op(&self) -> Option<&Operation<'func, M, F, operation::BinaryOp>> {
599        use self::LowLevelILExpressionKind::*;
600
601        match *self {
602            Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
603            | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op)
604            | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op)
605            | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op)
606            | DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => Some(op),
607            _ => None,
608        }
609    }
610
611    pub fn as_binary_op_carry(&self) -> Option<&Operation<'func, M, F, operation::BinaryOpCarry>> {
612        use self::LowLevelILExpressionKind::*;
613
614        match *self {
615            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => Some(op),
616            _ => None,
617        }
618    }
619
620    pub fn as_unary_op(&self) -> Option<&Operation<'func, M, F, operation::UnaryOp>> {
621        use self::LowLevelILExpressionKind::*;
622
623        match *self {
624            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
625            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
626            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
627            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => Some(op),
628            _ => None,
629        }
630    }
631
632    pub fn visit_sub_expressions<T>(&self, mut visitor: T) -> VisitorAction
633    where
634        T: FnMut(LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction,
635    {
636        use LowLevelILExpressionKind::*;
637
638        macro_rules! visit {
639            ($expr:expr) => {
640                if let VisitorAction::Halt = visitor($expr) {
641                    return VisitorAction::Halt;
642                }
643            };
644        }
645
646        match self {
647            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
648            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
649            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
650            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => {
651                visit!(op.left());
652                visit!(op.right());
653            }
654            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => {
655                visit!(op.left());
656                visit!(op.right());
657                visit!(op.carry());
658            }
659            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
660            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
661            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
662            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
663            | DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) | Fdiv(ref op)
664            | TestBit(ref op) => {
665                visit!(op.left());
666                visit!(op.right());
667            }
668            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
669            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
670            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
671            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => {
672                visit!(op.operand());
673            }
674            UnimplMem(ref op) => {
675                visit!(op.mem_expr());
676            }
677            Load(ref op) => {
678                visit!(op.source_expr());
679            }
680            LoadSsa(ref op) => {
681                visit!(op.source_expr());
682            }
683            CallParamSsa(ref op) => {
684                for param_expr in op.param_exprs() {
685                    visit!(param_expr);
686                }
687            }
688            SeparateParamListSsa(ref op) => {
689                for param_expr in op.param_exprs() {
690                    visit!(param_expr);
691                }
692            }
693            // Do not have any sub expressions.
694            Pop(_) | Reg(_) | RegSsa(_) | RegPartialSsa(_) | RegSplit(_) | RegSplitSsa(_)
695            | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) | ExternPtr(_) | FlagCond(_)
696            | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) | RegStackFreeReg(_)
697            | CallOutputSsa(_) | CallStackSsa(_) | FloatConst(_) => {}
698        }
699
700        VisitorAction::Sibling
701    }
702
703    pub(crate) fn raw_struct(&self) -> &BNLowLevelILInstruction {
704        use self::LowLevelILExpressionKind::*;
705
706        match *self {
707            Undef(ref op) => &op.op,
708
709            Unimpl(ref op) => &op.op,
710
711            FlagCond(ref op) => &op.op,
712            FlagGroup(ref op) => &op.op,
713
714            CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
715            | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
716            | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
717            | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => &op.op,
718
719            Load(ref op) => &op.op,
720
721            LoadSsa(ref op) => &op.op,
722
723            Pop(ref op) => &op.op,
724
725            Reg(ref op) => &op.op,
726
727            RegSsa(ref op) => &op.op,
728
729            RegPartialSsa(ref op) => &op.op,
730
731            RegSplit(ref op) => &op.op,
732
733            RegSplitSsa(ref op) => &op.op,
734
735            Flag(ref op) => &op.op,
736
737            FlagBit(ref op) => &op.op,
738
739            Const(ref op) | ConstPtr(ref op) => &op.op,
740
741            FloatConst(ref op) => &op.op,
742
743            ExternPtr(ref op) => &op.op,
744
745            RegStackPop(ref op) => &op.op,
746            RegStackFreeReg(ref op) => &op.op,
747
748            CallOutputSsa(ref op) => &op.op,
749            CallParamSsa(ref op) => &op.op,
750            CallStackSsa(ref op) => &op.op,
751
752            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => &op.op,
753
754            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
755            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
756            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
757            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
758            | Fdiv(ref op) | TestBit(ref op) => &op.op,
759
760            DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => &op.op,
761
762            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
763            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
764            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
765            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op,
766
767            SeparateParamListSsa(ref op) => &op.op,
768
769            UnimplMem(ref op) => &op.op,
770        }
771    }
772}
773
774impl LowLevelILExpressionKind<'_, Mutable, NonSSA> {
775    pub fn flag_write(&self) -> Option<CoreFlagWrite> {
776        use self::LowLevelILExpressionKind::*;
777
778        match *self {
779            Undef(ref _op) => None,
780
781            Unimpl(ref _op) => None,
782
783            FlagCond(ref _op) => None,
784            FlagGroup(ref _op) => None,
785
786            CmpE(ref _op) | CmpNe(ref _op) | CmpSlt(ref _op) | CmpUlt(ref _op)
787            | CmpSle(ref _op) | CmpUle(ref _op) | CmpSge(ref _op) | CmpUge(ref _op)
788            | CmpSgt(ref _op) | CmpUgt(ref _op) | FcmpE(ref _op) | FcmpNE(ref _op)
789            | FcmpLT(ref _op) | FcmpLE(ref _op) | FcmpGE(ref _op) | FcmpGT(ref _op)
790            | FcmpO(ref _op) | FcmpUO(ref _op) => None,
791
792            Load(ref op) => op.flag_write(),
793
794            LoadSsa(ref op) => op.flag_write(),
795
796            Pop(ref op) => op.flag_write(),
797
798            Reg(ref op) => op.flag_write(),
799
800            RegSsa(ref op) => op.flag_write(),
801
802            RegPartialSsa(ref op) => op.flag_write(),
803
804            RegSplit(ref op) => op.flag_write(),
805
806            RegSplitSsa(ref op) => op.flag_write(),
807
808            Flag(ref op) => op.flag_write(),
809
810            FlagBit(ref op) => op.flag_write(),
811
812            Const(ref op) | ConstPtr(ref op) => op.flag_write(),
813
814            FloatConst(ref op) => op.flag_write(),
815
816            ExternPtr(ref op) => op.flag_write(),
817
818            RegStackPop(ref op) => op.flag_write(),
819            RegStackFreeReg(ref op) => op.flag_write(),
820
821            CallOutputSsa(ref op) => op.flag_write(),
822            CallParamSsa(ref op) => op.flag_write(),
823            CallStackSsa(ref op) => op.flag_write(),
824
825            Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => op.flag_write(),
826
827            Add(ref op) | AddOverflow(ref op) | Sub(ref op) | And(ref op) | Or(ref op)
828            | Xor(ref op) | Lsl(ref op) | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op)
829            | Mul(ref op) | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op)
830            | Modu(ref op) | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op)
831            | Fdiv(ref op) | TestBit(ref op) => op.flag_write(),
832
833            DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => op.flag_write(),
834
835            Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
836            | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
837            | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
838            | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(),
839
840            SeparateParamListSsa(ref op) => op.flag_write(),
841
842            UnimplMem(ref op) => op.flag_write(),
843        }
844    }
845}