diff options
Diffstat (limited to 'rust/src/low_level_il/expression.rs')
| -rw-r--r-- | rust/src/low_level_il/expression.rs | 715 |
1 files changed, 715 insertions, 0 deletions
diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs new file mode 100644 index 00000000..2fc9f93d --- /dev/null +++ b/rust/src/low_level_il/expression.rs @@ -0,0 +1,715 @@ +// Copyright 2021-2024 Vector 35 Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use binaryninjacore_sys::BNGetLowLevelILByIndex; +use binaryninjacore_sys::BNLowLevelILInstruction; + +use super::operation; +use super::operation::Operation; +use super::VisitorAction; +use super::*; +use crate::architecture::Architecture; +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::marker::PhantomData; + +/// Used as a marker for an [`LowLevelILExpression`] that **can** produce a value. +#[derive(Copy, Clone, Debug)] +pub struct ValueExpr; + +/// Used as a marker for an [`LowLevelILExpression`] that can **not** produce a value. +#[derive(Copy, Clone, Debug)] +pub struct VoidExpr; + +pub trait ExpressionResultType: 'static {} +impl ExpressionResultType for ValueExpr {} +impl ExpressionResultType for VoidExpr {} + +#[repr(transparent)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct LowLevelExpressionIndex(pub usize); + +impl Display for LowLevelExpressionIndex { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + +// TODO: Probably want to rename this with a LowLevelIL prefix to avoid collisions when we add handlers for other ILs +pub trait ExpressionHandler<'func, A, M, F> +where + A: Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, F>; + + fn visit_tree<T>(&self, f: &mut T) -> VisitorAction + where + T: FnMut(&LowLevelILExpression<'func, A, M, F, ValueExpr>) -> VisitorAction; +} + +pub struct LowLevelILExpression<'func, A, M, F, R> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + R: ExpressionResultType, +{ + pub(crate) function: &'func LowLevelILFunction<A, M, F>, + pub index: LowLevelExpressionIndex, + + // tag the 'return' type of this expression + pub(crate) _ty: PhantomData<R>, +} + +impl<'func, A, M, F, R> LowLevelILExpression<'func, A, M, F, R> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + R: ExpressionResultType, +{ + pub(crate) fn new( + function: &'func LowLevelILFunction<A, M, F>, + index: LowLevelExpressionIndex, + ) -> Self { + // TODO: Validate expression here? + Self { + function, + index, + _ty: PhantomData, + } + } +} + +impl<'func, A, M, F, R> fmt::Debug for LowLevelILExpression<'func, A, M, F, R> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + R: ExpressionResultType, +{ + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct("Expression") + .field("index", &self.index) + .finish() + } +} + +impl<'func, A, M> ExpressionHandler<'func, A, M, SSA> + for LowLevelILExpression<'func, A, M, SSA, ValueExpr> +where + A: 'func + Architecture, + M: FunctionMutability, +{ + fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, SSA> { + #[allow(unused_imports)] + use binaryninjacore_sys::BNLowLevelILOperation::*; + let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; + #[allow(clippy::match_single_binding)] + match op.operation { + // Any invalid ops for SSA will be checked here. + // SAFETY: We have checked for illegal operations. + _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + } + } + + fn visit_tree<T>(&self, f: &mut T) -> VisitorAction + where + T: FnMut(&LowLevelILExpression<'func, A, M, SSA, ValueExpr>) -> VisitorAction, + { + // Visit the current expression. + match f(self) { + VisitorAction::Descend => { + // Recursively visit sub expressions. + self.kind().visit_sub_expressions(|e| e.visit_tree(f)) + } + action => action, + } + } +} + +impl<'func, A, M> ExpressionHandler<'func, A, M, NonSSA<LiftedNonSSA>> + for LowLevelILExpression<'func, A, M, NonSSA<LiftedNonSSA>, ValueExpr> +where + A: 'func + Architecture, + M: FunctionMutability, +{ + fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, NonSSA<LiftedNonSSA>> { + #[allow(unused_imports)] + use binaryninjacore_sys::BNLowLevelILOperation::*; + let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; + #[allow(clippy::match_single_binding)] + match op.operation { + // Any invalid ops for Lifted IL will be checked here. + // SAFETY: We have checked for illegal operations. + _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + } + } + + fn visit_tree<T>(&self, f: &mut T) -> VisitorAction + where + T: FnMut( + &LowLevelILExpression<'func, A, M, NonSSA<LiftedNonSSA>, ValueExpr>, + ) -> VisitorAction, + { + // Visit the current expression. + match f(self) { + VisitorAction::Descend => { + // Recursively visit sub expressions. + self.kind().visit_sub_expressions(|e| e.visit_tree(f)) + } + action => action, + } + } +} + +impl<'func, A, M> ExpressionHandler<'func, A, M, NonSSA<RegularNonSSA>> + for LowLevelILExpression<'func, A, M, NonSSA<RegularNonSSA>, ValueExpr> +where + A: 'func + Architecture, + M: FunctionMutability, +{ + fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, NonSSA<RegularNonSSA>> { + use binaryninjacore_sys::BNLowLevelILOperation::*; + let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; + match op.operation { + // Any invalid ops for Non-Lifted IL will be checked here. + LLIL_FLAG_COND => unreachable!("LLIL_FLAG_COND is only valid in Lifted IL"), + LLIL_FLAG_GROUP => unreachable!("LLIL_FLAG_GROUP is only valid in Lifted IL"), + // SAFETY: We have checked for illegal operations. + _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + } + } + + fn visit_tree<T>(&self, f: &mut T) -> VisitorAction + where + T: FnMut( + &LowLevelILExpression<'func, A, M, NonSSA<RegularNonSSA>, ValueExpr>, + ) -> VisitorAction, + { + // Visit the current expression. + match f(self) { + VisitorAction::Descend => { + // Recursively visit sub expressions. + self.kind().visit_sub_expressions(|e| e.visit_tree(f)) + } + action => action, + } + } +} + +impl<'func, A, F> LowLevelILExpression<'func, A, Finalized, F, ValueExpr> +where + A: 'func + Architecture, + F: FunctionForm, +{ + // TODO possible values +} + +#[derive(Debug)] +pub enum LowLevelILExpressionKind<'func, A, M, F> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + Load(Operation<'func, A, M, F, operation::Load>), + Pop(Operation<'func, A, M, F, operation::Pop>), + Reg(Operation<'func, A, M, F, operation::Reg>), + RegSplit(Operation<'func, A, M, F, operation::RegSplit>), + Const(Operation<'func, A, M, F, operation::Const>), + ConstPtr(Operation<'func, A, M, F, operation::Const>), + Flag(Operation<'func, A, M, F, operation::Flag>), + FlagBit(Operation<'func, A, M, F, operation::FlagBit>), + ExternPtr(Operation<'func, A, M, F, operation::Extern>), + + Add(Operation<'func, A, M, F, operation::BinaryOp>), + Adc(Operation<'func, A, M, F, operation::BinaryOpCarry>), + Sub(Operation<'func, A, M, F, operation::BinaryOp>), + Sbb(Operation<'func, A, M, F, operation::BinaryOpCarry>), + And(Operation<'func, A, M, F, operation::BinaryOp>), + Or(Operation<'func, A, M, F, operation::BinaryOp>), + Xor(Operation<'func, A, M, F, operation::BinaryOp>), + Lsl(Operation<'func, A, M, F, operation::BinaryOp>), + Lsr(Operation<'func, A, M, F, operation::BinaryOp>), + Asr(Operation<'func, A, M, F, operation::BinaryOp>), + Rol(Operation<'func, A, M, F, operation::BinaryOp>), + Rlc(Operation<'func, A, M, F, operation::BinaryOpCarry>), + Ror(Operation<'func, A, M, F, operation::BinaryOp>), + Rrc(Operation<'func, A, M, F, operation::BinaryOpCarry>), + Mul(Operation<'func, A, M, F, operation::BinaryOp>), + + MulsDp(Operation<'func, A, M, F, operation::BinaryOp>), + MuluDp(Operation<'func, A, M, F, operation::BinaryOp>), + + Divu(Operation<'func, A, M, F, operation::BinaryOp>), + Divs(Operation<'func, A, M, F, operation::BinaryOp>), + + DivuDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), + DivsDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), + + Modu(Operation<'func, A, M, F, operation::BinaryOp>), + Mods(Operation<'func, A, M, F, operation::BinaryOp>), + + ModuDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), + ModsDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), + + Neg(Operation<'func, A, M, F, operation::UnaryOp>), + Not(Operation<'func, A, M, F, operation::UnaryOp>), + Sx(Operation<'func, A, M, F, operation::UnaryOp>), + Zx(Operation<'func, A, M, F, operation::UnaryOp>), + LowPart(Operation<'func, A, M, F, operation::UnaryOp>), + + // Valid only in Lifted IL + FlagCond(Operation<'func, A, M, NonSSA<LiftedNonSSA>, operation::FlagCond>), + // Valid only in Lifted IL + FlagGroup(Operation<'func, A, M, NonSSA<LiftedNonSSA>, operation::FlagGroup>), + + CmpE(Operation<'func, A, M, F, operation::Condition>), + CmpNe(Operation<'func, A, M, F, operation::Condition>), + CmpSlt(Operation<'func, A, M, F, operation::Condition>), + CmpUlt(Operation<'func, A, M, F, operation::Condition>), + CmpSle(Operation<'func, A, M, F, operation::Condition>), + CmpUle(Operation<'func, A, M, F, operation::Condition>), + CmpSge(Operation<'func, A, M, F, operation::Condition>), + CmpUge(Operation<'func, A, M, F, operation::Condition>), + CmpSgt(Operation<'func, A, M, F, operation::Condition>), + CmpUgt(Operation<'func, A, M, F, operation::Condition>), + + //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + BoolToInt(Operation<'func, A, M, F, operation::UnaryOp>), + + Fadd(Operation<'func, A, M, F, operation::BinaryOp>), + Fsub(Operation<'func, A, M, F, operation::BinaryOp>), + Fmul(Operation<'func, A, M, F, operation::BinaryOp>), + Fdiv(Operation<'func, A, M, F, operation::BinaryOp>), + Fsqrt(Operation<'func, A, M, F, operation::UnaryOp>), + Fneg(Operation<'func, A, M, F, operation::UnaryOp>), + Fabs(Operation<'func, A, M, F, operation::UnaryOp>), + FloatToInt(Operation<'func, A, M, F, operation::UnaryOp>), + IntToFloat(Operation<'func, A, M, F, operation::UnaryOp>), + FloatConv(Operation<'func, A, M, F, operation::UnaryOp>), + RoundToInt(Operation<'func, A, M, F, operation::UnaryOp>), + Floor(Operation<'func, A, M, F, operation::UnaryOp>), + Ceil(Operation<'func, A, M, F, operation::UnaryOp>), + Ftrunc(Operation<'func, A, M, F, operation::UnaryOp>), + + FcmpE(Operation<'func, A, M, F, operation::Condition>), + FcmpNE(Operation<'func, A, M, F, operation::Condition>), + FcmpLT(Operation<'func, A, M, F, operation::Condition>), + FcmpLE(Operation<'func, A, M, F, operation::Condition>), + FcmpGE(Operation<'func, A, M, F, operation::Condition>), + FcmpGT(Operation<'func, A, M, F, operation::Condition>), + FcmpO(Operation<'func, A, M, F, operation::Condition>), + FcmpUO(Operation<'func, A, M, F, operation::Condition>), + + // TODO ADD_OVERFLOW + Unimpl(Operation<'func, A, M, F, operation::NoArgs>), + UnimplMem(Operation<'func, A, M, F, operation::UnimplMem>), + + Undef(Operation<'func, A, M, F, operation::NoArgs>), +} + +impl<'func, A, M, F> LowLevelILExpressionKind<'func, A, M, F> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + // TODO: Document what "unchecked" means and how to consume this safely. + pub(crate) unsafe fn from_raw( + function: &'func LowLevelILFunction<A, M, F>, + op: BNLowLevelILInstruction, + ) -> Self { + use binaryninjacore_sys::BNLowLevelILOperation::*; + + match op.operation { + LLIL_LOAD | LLIL_LOAD_SSA => { + LowLevelILExpressionKind::Load(Operation::new(function, op)) + } + LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op)), + LLIL_REG | LLIL_REG_SSA | LLIL_REG_SSA_PARTIAL => { + LowLevelILExpressionKind::Reg(Operation::new(function, op)) + } + LLIL_REG_SPLIT | LLIL_REG_SPLIT_SSA => { + LowLevelILExpressionKind::RegSplit(Operation::new(function, op)) + } + LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op)), + LLIL_CONST_PTR => LowLevelILExpressionKind::ConstPtr(Operation::new(function, op)), + LLIL_FLAG | LLIL_FLAG_SSA => { + LowLevelILExpressionKind::Flag(Operation::new(function, op)) + } + LLIL_FLAG_BIT | LLIL_FLAG_BIT_SSA => { + LowLevelILExpressionKind::FlagBit(Operation::new(function, op)) + } + LLIL_EXTERN_PTR => LowLevelILExpressionKind::ExternPtr(Operation::new(function, op)), + + LLIL_ADD => LowLevelILExpressionKind::Add(Operation::new(function, op)), + LLIL_ADC => LowLevelILExpressionKind::Adc(Operation::new(function, op)), + LLIL_SUB => LowLevelILExpressionKind::Sub(Operation::new(function, op)), + LLIL_SBB => LowLevelILExpressionKind::Sbb(Operation::new(function, op)), + LLIL_AND => LowLevelILExpressionKind::And(Operation::new(function, op)), + LLIL_OR => LowLevelILExpressionKind::Or(Operation::new(function, op)), + LLIL_XOR => LowLevelILExpressionKind::Xor(Operation::new(function, op)), + LLIL_LSL => LowLevelILExpressionKind::Lsl(Operation::new(function, op)), + LLIL_LSR => LowLevelILExpressionKind::Lsr(Operation::new(function, op)), + LLIL_ASR => LowLevelILExpressionKind::Asr(Operation::new(function, op)), + LLIL_ROL => LowLevelILExpressionKind::Rol(Operation::new(function, op)), + LLIL_RLC => LowLevelILExpressionKind::Rlc(Operation::new(function, op)), + LLIL_ROR => LowLevelILExpressionKind::Ror(Operation::new(function, op)), + LLIL_RRC => LowLevelILExpressionKind::Rrc(Operation::new(function, op)), + LLIL_MUL => LowLevelILExpressionKind::Mul(Operation::new(function, op)), + + LLIL_MULU_DP => LowLevelILExpressionKind::MuluDp(Operation::new(function, op)), + LLIL_MULS_DP => LowLevelILExpressionKind::MulsDp(Operation::new(function, op)), + + LLIL_DIVU => LowLevelILExpressionKind::Divu(Operation::new(function, op)), + LLIL_DIVS => LowLevelILExpressionKind::Divs(Operation::new(function, op)), + + LLIL_DIVU_DP => LowLevelILExpressionKind::DivuDp(Operation::new(function, op)), + LLIL_DIVS_DP => LowLevelILExpressionKind::DivsDp(Operation::new(function, op)), + + LLIL_MODU => LowLevelILExpressionKind::Modu(Operation::new(function, op)), + LLIL_MODS => LowLevelILExpressionKind::Mods(Operation::new(function, op)), + + LLIL_MODU_DP => LowLevelILExpressionKind::ModuDp(Operation::new(function, op)), + LLIL_MODS_DP => LowLevelILExpressionKind::ModsDp(Operation::new(function, op)), + + LLIL_NEG => LowLevelILExpressionKind::Neg(Operation::new(function, op)), + LLIL_NOT => LowLevelILExpressionKind::Not(Operation::new(function, op)), + + LLIL_SX => LowLevelILExpressionKind::Sx(Operation::new(function, op)), + LLIL_ZX => LowLevelILExpressionKind::Zx(Operation::new(function, op)), + LLIL_LOW_PART => LowLevelILExpressionKind::LowPart(Operation::new(function, op)), + + LLIL_CMP_E => LowLevelILExpressionKind::CmpE(Operation::new(function, op)), + LLIL_CMP_NE => LowLevelILExpressionKind::CmpNe(Operation::new(function, op)), + LLIL_CMP_SLT => LowLevelILExpressionKind::CmpSlt(Operation::new(function, op)), + LLIL_CMP_ULT => LowLevelILExpressionKind::CmpUlt(Operation::new(function, op)), + LLIL_CMP_SLE => LowLevelILExpressionKind::CmpSle(Operation::new(function, op)), + LLIL_CMP_ULE => LowLevelILExpressionKind::CmpUle(Operation::new(function, op)), + LLIL_CMP_SGE => LowLevelILExpressionKind::CmpSge(Operation::new(function, op)), + LLIL_CMP_UGE => LowLevelILExpressionKind::CmpUge(Operation::new(function, op)), + LLIL_CMP_SGT => LowLevelILExpressionKind::CmpSgt(Operation::new(function, op)), + LLIL_CMP_UGT => LowLevelILExpressionKind::CmpUgt(Operation::new(function, op)), + + LLIL_BOOL_TO_INT => LowLevelILExpressionKind::BoolToInt(Operation::new(function, op)), + + LLIL_FADD => LowLevelILExpressionKind::Fadd(Operation::new(function, op)), + LLIL_FSUB => LowLevelILExpressionKind::Fsub(Operation::new(function, op)), + LLIL_FMUL => LowLevelILExpressionKind::Fmul(Operation::new(function, op)), + LLIL_FDIV => LowLevelILExpressionKind::Fdiv(Operation::new(function, op)), + + LLIL_FSQRT => LowLevelILExpressionKind::Fsqrt(Operation::new(function, op)), + LLIL_FNEG => LowLevelILExpressionKind::Fneg(Operation::new(function, op)), + LLIL_FABS => LowLevelILExpressionKind::Fabs(Operation::new(function, op)), + LLIL_FLOAT_TO_INT => LowLevelILExpressionKind::FloatToInt(Operation::new(function, op)), + LLIL_INT_TO_FLOAT => LowLevelILExpressionKind::IntToFloat(Operation::new(function, op)), + LLIL_FLOAT_CONV => LowLevelILExpressionKind::FloatConv(Operation::new(function, op)), + LLIL_ROUND_TO_INT => LowLevelILExpressionKind::RoundToInt(Operation::new(function, op)), + LLIL_FLOOR => LowLevelILExpressionKind::Floor(Operation::new(function, op)), + LLIL_CEIL => LowLevelILExpressionKind::Ceil(Operation::new(function, op)), + LLIL_FTRUNC => LowLevelILExpressionKind::Ftrunc(Operation::new(function, op)), + + LLIL_FCMP_E => LowLevelILExpressionKind::FcmpE(Operation::new(function, op)), + LLIL_FCMP_NE => LowLevelILExpressionKind::FcmpNE(Operation::new(function, op)), + LLIL_FCMP_LT => LowLevelILExpressionKind::FcmpLT(Operation::new(function, op)), + LLIL_FCMP_LE => LowLevelILExpressionKind::FcmpLE(Operation::new(function, op)), + LLIL_FCMP_GT => LowLevelILExpressionKind::FcmpGT(Operation::new(function, op)), + LLIL_FCMP_GE => LowLevelILExpressionKind::FcmpGE(Operation::new(function, op)), + LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op)), + LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op)), + + LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op)), + LLIL_UNIMPL_MEM => LowLevelILExpressionKind::UnimplMem(Operation::new(function, op)), + + // TODO TEST_BIT ADD_OVERFLOW LLIL_REG_STACK_PUSH LLIL_REG_STACK_POP + _ => { + #[cfg(debug_assertions)] + log::error!( + "Got unexpected operation {:?} in value expr at 0x{:x}", + op.operation, + op.address + ); + + LowLevelILExpressionKind::Undef(Operation::new(function, op)) + } + } + } + + /// Returns the size of the result of this expression + /// + /// If the expression is malformed or is `Unimpl` there + /// is no meaningful size associated with the result. + pub fn size(&self) -> Option<usize> { + use self::LowLevelILExpressionKind::*; + + match *self { + Undef(..) | Unimpl(..) => None, + + FlagCond(..) | FlagGroup(..) | CmpE(..) | CmpNe(..) | CmpSlt(..) | CmpUlt(..) + | CmpSle(..) | CmpUle(..) | CmpSge(..) | CmpUge(..) | CmpSgt(..) | CmpUgt(..) => { + Some(0) + } + + _ => Some(self.raw_struct().size), + //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + } + } + + pub fn address(&self) -> u64 { + self.raw_struct().address + } + + /// Determines if the expressions represent the same operation + /// + /// It does not examine the operands for equality. + pub fn is_same_op_as(&self, other: &Self) -> bool { + use self::LowLevelILExpressionKind::*; + + match (self, other) { + (&Reg(..), &Reg(..)) => true, + _ => self.raw_struct().operation == other.raw_struct().operation, + } + } + + pub fn as_cmp_op(&self) -> Option<&Operation<'func, A, M, F, operation::Condition>> { + use self::LowLevelILExpressionKind::*; + + match *self { + CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op) + | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) + | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) + | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => Some(op), + _ => None, + } + } + + pub fn as_binary_op(&self) -> Option<&Operation<'func, A, M, F, operation::BinaryOp>> { + use self::LowLevelILExpressionKind::*; + + match *self { + Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) + | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) + | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) + | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => Some(op), + _ => None, + } + } + + pub fn as_binary_op_carry( + &self, + ) -> Option<&Operation<'func, A, M, F, operation::BinaryOpCarry>> { + use self::LowLevelILExpressionKind::*; + + match *self { + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => Some(op), + _ => None, + } + } + + pub fn as_double_prec_div_op( + &self, + ) -> Option<&Operation<'func, A, M, F, operation::DoublePrecDivOp>> { + use self::LowLevelILExpressionKind::*; + + match *self { + DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => Some(op), + _ => None, + } + } + + pub fn as_unary_op(&self) -> Option<&Operation<'func, A, M, F, operation::UnaryOp>> { + use self::LowLevelILExpressionKind::*; + + match *self { + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) + | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) + | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => Some(op), + _ => None, + } + } + + pub fn visit_sub_expressions<T>(&self, mut visitor: T) -> VisitorAction + where + T: FnMut(LowLevelILExpression<'func, A, M, F, ValueExpr>) -> VisitorAction, + { + use LowLevelILExpressionKind::*; + + macro_rules! visit { + ($expr:expr) => { + if let VisitorAction::Halt = visitor($expr) { + return VisitorAction::Halt; + } + }; + } + + match self { + CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op) + | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) + | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) + | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => { + visit!(op.left()); + visit!(op.right()); + } + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => { + visit!(op.left()); + visit!(op.right()); + visit!(op.carry()); + } + Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) + | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) + | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) + | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => { + visit!(op.left()); + visit!(op.right()); + } + DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => { + visit!(op.high()); + visit!(op.low()); + visit!(op.right()); + } + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) + | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) + | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => { + visit!(op.operand()); + } + UnimplMem(ref op) => { + visit!(op.mem_expr()); + } + Load(ref op) => { + visit!(op.source_mem_expr()); + } + // Do not have any sub expressions. + Pop(_) | Reg(_) | RegSplit(_) | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) + | ExternPtr(_) | FlagCond(_) | FlagGroup(_) | Unimpl(_) | Undef(_) => {} + } + + VisitorAction::Sibling + } + + pub(crate) fn raw_struct(&self) -> &BNLowLevelILInstruction { + use self::LowLevelILExpressionKind::*; + + match *self { + Undef(ref op) => &op.op, + + Unimpl(ref op) => &op.op, + + FlagCond(ref op) => &op.op, + FlagGroup(ref op) => &op.op, + + CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op) + | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) + | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) + | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => &op.op, + + Load(ref op) => &op.op, + + Pop(ref op) => &op.op, + + Reg(ref op) => &op.op, + + RegSplit(ref op) => &op.op, + + Flag(ref op) => &op.op, + + FlagBit(ref op) => &op.op, + + Const(ref op) | ConstPtr(ref op) => &op.op, + + ExternPtr(ref op) => &op.op, + + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => &op.op, + + Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) + | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) + | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) + | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => &op.op, + + DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => &op.op, + + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) + | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) + | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op, + + UnimplMem(ref op) => &op.op, + //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + } + } +} + +impl<'func, A> LowLevelILExpressionKind<'func, A, Mutable, NonSSA<LiftedNonSSA>> +where + A: 'func + Architecture, +{ + pub fn flag_write(&self) -> Option<A::FlagWrite> { + use self::LowLevelILExpressionKind::*; + + match *self { + Undef(ref _op) => None, + + Unimpl(ref _op) => None, + + FlagCond(ref _op) => None, + FlagGroup(ref _op) => None, + + CmpE(ref _op) | CmpNe(ref _op) | CmpSlt(ref _op) | CmpUlt(ref _op) + | CmpSle(ref _op) | CmpUle(ref _op) | CmpSge(ref _op) | CmpUge(ref _op) + | CmpSgt(ref _op) | CmpUgt(ref _op) | FcmpE(ref _op) | FcmpNE(ref _op) + | FcmpLT(ref _op) | FcmpLE(ref _op) | FcmpGE(ref _op) | FcmpGT(ref _op) + | FcmpO(ref _op) | FcmpUO(ref _op) => None, + + Load(ref op) => op.flag_write(), + + Pop(ref op) => op.flag_write(), + + Reg(ref op) => op.flag_write(), + + RegSplit(ref op) => op.flag_write(), + + Flag(ref op) => op.flag_write(), + + FlagBit(ref op) => op.flag_write(), + + Const(ref op) | ConstPtr(ref op) => op.flag_write(), + + ExternPtr(ref op) => op.flag_write(), + + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => op.flag_write(), + + Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) + | Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) + | MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) + | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => { + op.flag_write() + } + + DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => op.flag_write(), + + Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op) + | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) + | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) + | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(), + + UnimplMem(ref op) => op.flag_write(), + //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + } + } +} |
