diff options
| author | Ryan Snyder <ryan@vector35.com> | 2021-01-21 18:27:48 +0000 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2021-01-21 19:06:55 +0000 |
| commit | d3140edec185f47235b9e4642bdd56d6c585a341 (patch) | |
| tree | a61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/llil/expression.rs | |
| parent | c0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (diff) | |
This is a combination of 23 commits, the work of Ryan Snyder:
Initial fresh repo
Add support for recent calling convention API updates and folds the binaryninjacore-sys crate directly into this one.
Add support for auto function analysis suppression
Finish moving binaryninjacore-sys back into this crate
Update for Symbol/Segment core API changes
Update for Symbol API cleanup
api: advance submodule reference, support Token changes
arch/lifting: support for flags in custom architectures
arch/lifting: support default flag write behaviors, handle more ops
build: enable headless binary support on MacOS via evil hack
bv: add BinaryView wrapper support, remove wrong comment
api: update to latest binja dev branch support
deps: bump dep versions
rust: bump to 2018 edition
api: bump to avoid cargo submodule brokenness
build: improve binaryninja path detection; enable linux linkhack
bv: stub for bv load settings
arch: fix flag related crash, minor llil update
api: update for recent changes
macos: disable linkhack briefly
Diffstat (limited to 'rust/src/llil/expression.rs')
| -rw-r--r-- | rust/src/llil/expression.rs | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/rust/src/llil/expression.rs b/rust/src/llil/expression.rs new file mode 100644 index 00000000..1e1edda4 --- /dev/null +++ b/rust/src/llil/expression.rs @@ -0,0 +1,816 @@ +use binaryninjacore_sys::BNGetLowLevelILByIndex; +use binaryninjacore_sys::BNLowLevelILInstruction; + +use std::marker::PhantomData; +use std::fmt; + +use super::*; +use super::operation; +use super::operation::Operation; + +use crate::architecture::Architecture; +use crate::architecture::RegisterInfo; + +// used as a marker for Expressions that can produce a value +#[derive(Copy, Clone, Debug)] +pub struct ValueExpr; + +// used as a marker for Expressions 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 {} + +pub struct Expression<'func, A, M, F, R> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + R: ExpressionResultType, +{ + pub(crate) function: &'func Function<A, M, F>, + pub(crate) expr_idx: usize, + + // tag the 'return' type of this expression + pub(crate) _ty: PhantomData<R>, +} + +impl<'func, A, M, F, R> Expression<'func, A, M, F, R> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + R: ExpressionResultType, +{ + pub fn index(&self) -> usize { + self.expr_idx + } +} + +impl<'func, A, M, V> fmt::Debug for Expression<'func, A, M, NonSSA<V>, ValueExpr> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let op_info = self.info(); + write!(f, "<expr {}: {:?}>", self.expr_idx, op_info) + } +} + +fn common_info<'func, A, M, F>(function: &'func Function<A, M, F>, op: BNLowLevelILInstruction) + -> ExprInfo<'func, A, M, F> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + use binaryninjacore_sys::BNLowLevelILOperation::*; + + match op.operation { + LLIL_CONST => ExprInfo::Const(Operation::new(function, op)), + LLIL_CONST_PTR => ExprInfo::ConstPtr(Operation::new(function, op)), + + LLIL_ADD => ExprInfo::Add(Operation::new(function, op)), + LLIL_ADC => ExprInfo::Adc(Operation::new(function, op)), + LLIL_SUB => ExprInfo::Sub(Operation::new(function, op)), + LLIL_SBB => ExprInfo::Sbb(Operation::new(function, op)), + LLIL_AND => ExprInfo::And(Operation::new(function, op)), + LLIL_OR => ExprInfo::Or (Operation::new(function, op)), + LLIL_XOR => ExprInfo::Xor(Operation::new(function, op)), + LLIL_LSL => ExprInfo::Lsl(Operation::new(function, op)), + LLIL_LSR => ExprInfo::Lsr(Operation::new(function, op)), + LLIL_ASR => ExprInfo::Asr(Operation::new(function, op)), + LLIL_ROL => ExprInfo::Rol(Operation::new(function, op)), + LLIL_RLC => ExprInfo::Rlc(Operation::new(function, op)), + LLIL_ROR => ExprInfo::Ror(Operation::new(function, op)), + LLIL_RRC => ExprInfo::Rrc(Operation::new(function, op)), + LLIL_MUL => ExprInfo::Mul(Operation::new(function, op)), + + LLIL_MULU_DP => ExprInfo::MuluDp(Operation::new(function, op)), + LLIL_MULS_DP => ExprInfo::MulsDp(Operation::new(function, op)), + + LLIL_DIVU => ExprInfo::Divu(Operation::new(function, op)), + LLIL_DIVS => ExprInfo::Divs(Operation::new(function, op)), + + LLIL_DIVU_DP => ExprInfo::DivuDp(Operation::new(function, op)), + LLIL_DIVS_DP => ExprInfo::DivsDp(Operation::new(function, op)), + + LLIL_MODU => ExprInfo::Modu(Operation::new(function, op)), + LLIL_MODS => ExprInfo::Mods(Operation::new(function, op)), + + LLIL_MODU_DP => ExprInfo::ModuDp(Operation::new(function, op)), + LLIL_MODS_DP => ExprInfo::ModsDp(Operation::new(function, op)), + + LLIL_NEG => ExprInfo::Neg(Operation::new(function, op)), + LLIL_NOT => ExprInfo::Not(Operation::new(function, op)), + + LLIL_SX => ExprInfo::Sx(Operation::new(function, op)), + LLIL_ZX => ExprInfo::Zx(Operation::new(function, op)), + LLIL_LOW_PART => ExprInfo::LowPart(Operation::new(function, op)), + + LLIL_CMP_E => ExprInfo::CmpE(Operation::new(function, op)), + LLIL_CMP_NE => ExprInfo::CmpNe(Operation::new(function, op)), + LLIL_CMP_SLT => ExprInfo::CmpSlt(Operation::new(function, op)), + LLIL_CMP_ULT => ExprInfo::CmpUlt(Operation::new(function, op)), + LLIL_CMP_SLE => ExprInfo::CmpSle(Operation::new(function, op)), + LLIL_CMP_ULE => ExprInfo::CmpUle(Operation::new(function, op)), + LLIL_CMP_SGE => ExprInfo::CmpSge(Operation::new(function, op)), + LLIL_CMP_UGE => ExprInfo::CmpUge(Operation::new(function, op)), + LLIL_CMP_SGT => ExprInfo::CmpSgt(Operation::new(function, op)), + LLIL_CMP_UGT => ExprInfo::CmpUgt(Operation::new(function, op)), + + LLIL_BOOL_TO_INT => ExprInfo::BoolToInt(Operation::new(function, op)), + + LLIL_UNIMPL => ExprInfo::Unimpl(Operation::new(function, op)), + LLIL_UNIMPL_MEM => ExprInfo::UnimplMem(Operation::new(function, op)), + + // TODO TEST_BIT ADD_OVERFLOW + _ => { + #[cfg(debug_assertions)] + { + error!("Got unexpected operation {:?} in value expr at 0x{:x}", + op.operation, op.address); + } + + ExprInfo::Undef(Operation::new(function, op)) + } + } +} + +use super::VisitorAction; + +macro_rules! visit { + ($f:expr, $($e:expr),*) => { + if let VisitorAction::Halt = $f($($e,)*) { + return VisitorAction::Halt; + } + } +} + +fn common_visit<'func, A, M, F, CB>(info: &ExprInfo<'func, A, M, F>, f: &mut CB) + -> VisitorAction +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, + CB: FnMut(&Expression<'func, A, M, F, ValueExpr>) -> VisitorAction, +{ + use self::ExprInfo::*; + + match *info { + 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) => { + visit!(f, &op.left()); + visit!(f, &op.right()); + } + + Adc(ref op) | + Sbb(ref op) | + Rlc(ref op) | + Rrc(ref op) => { + visit!(f, &op.left()); + visit!(f, &op.right()); + visit!(f, &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) => { + visit!(f, &op.left()); + visit!(f, &op.right()); + } + + DivuDp(ref op) | + DivsDp(ref op) | + ModuDp(ref op) | + ModsDp(ref op) => { + visit!(f, &op.high()); + visit!(f, &op.low()); + visit!(f, &op.right()); + } + + Neg(ref op) | + Not(ref op) | + Sx(ref op) | + Zx(ref op) | + LowPart(ref op) | + BoolToInt(ref op) => { + visit!(f, &op.operand()); + } + + UnimplMem(ref op) => { + visit!(f, &op.mem_expr()); + } + + _ => {} + }; + + VisitorAction::Sibling +} + +impl<'func, A, M, V> Expression<'func, A, M, NonSSA<V>, ValueExpr> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + pub(crate) unsafe fn info_from_op(&self, op: BNLowLevelILInstruction) -> ExprInfo<'func, A, M, NonSSA<V>> { + use binaryninjacore_sys::BNLowLevelILOperation::*; + + match op.operation { + LLIL_LOAD => ExprInfo::Load(Operation::new(self.function, op)), + LLIL_POP => ExprInfo::Pop(Operation::new(self.function, op)), + LLIL_REG => ExprInfo::Reg(Operation::new(self.function, op)), + LLIL_FLAG => ExprInfo::Flag(Operation::new(self.function, op)), + LLIL_FLAG_BIT => ExprInfo::FlagBit(Operation::new(self.function, op)), + LLIL_FLAG_COND => ExprInfo::FlagCond(Operation::new(self.function, op)), // TODO lifted only + LLIL_FLAG_GROUP => ExprInfo::FlagGroup(Operation::new(self.function, op)), // TODO lifted only + _ => common_info(self.function, op), + } + } + + pub fn info(&self) -> ExprInfo<'func, A, M, NonSSA<V>> { + unsafe { + let op = BNGetLowLevelILByIndex(self.function.handle, self.expr_idx); + self.info_from_op(op) + } + } + + pub fn visit_tree<F>(&self, f: &mut F) -> VisitorAction + where + F: FnMut(&Self, &ExprInfo<'func, A, M, NonSSA<V>>) -> VisitorAction, + { + use self::ExprInfo::*; + + let info = self.info(); + + match f(self, &info) { + VisitorAction::Descend => {}, + action => return action, + }; + + match info { + Load(ref op) => visit!(Self::visit_tree, &op.source_mem_expr(), f), + _ => { + let mut fb = |e: &Self| e.visit_tree(f); + visit!(common_visit, &info, &mut fb); + } + }; + + VisitorAction::Sibling + } +} + +impl<'func, A, M> Expression<'func, A, M, SSA, ValueExpr> +where + A: 'func + Architecture, + M: FunctionMutability, +{ + pub(crate) unsafe fn info_from_op(&self, op: BNLowLevelILInstruction) -> ExprInfo<'func, A, M, SSA> { + use binaryninjacore_sys::BNLowLevelILOperation::*; + + match op.operation { + LLIL_LOAD_SSA => ExprInfo::Load(Operation::new(self.function, op)), + LLIL_REG_SSA | + LLIL_REG_SSA_PARTIAL => ExprInfo::Reg(Operation::new(self.function, op)), + LLIL_FLAG_SSA => ExprInfo::Flag(Operation::new(self.function, op)), + LLIL_FLAG_BIT_SSA => ExprInfo::FlagBit(Operation::new(self.function, op)), + _ => common_info(self.function, op), + } + } + + pub fn info(&self) -> ExprInfo<'func, A, M, SSA> { + unsafe { + let op = BNGetLowLevelILByIndex(self.function.handle, self.expr_idx); + self.info_from_op(op) + } + } + + pub fn visit_tree<F>(&self, f: &mut F) -> VisitorAction + where + F: FnMut(&Self, &ExprInfo<'func, A, M, SSA>) -> VisitorAction, + { + use self::ExprInfo::*; + + let info = self.info(); + + match f(self, &info) { + VisitorAction::Descend => {}, + action => return action, + }; + + match info { + // TODO ssa + Load(ref _op) => {} //visit!(Self::visit_tree, &op.source_mem_expr(), f), + _ => { + let mut fb = |e: &Self| e.visit_tree(f); + visit!(common_visit, &info, &mut fb); + } + }; + + VisitorAction::Sibling + } +} + +impl<'func, A, F> Expression<'func, A, Finalized, F, ValueExpr> +where + A: 'func + Architecture, + F: FunctionForm, +{ + // TODO possible values +} + + + +pub enum ExprInfo<'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>), + 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>), + + 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>), + + FlagCond(Operation<'func, A, M, F, operation::FlagCond>), + FlagGroup(Operation<'func, A, M, F, 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>), + + // 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> ExprInfo<'func, A, M, F> +where + A: 'func + Architecture, + M: FunctionMutability, + F: FunctionForm, +{ + /// 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::ExprInfo::*; + + 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::ExprInfo::*; + + 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::ExprInfo::*; + + 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) => Some(op), + _ => None, + } + } + + pub fn as_binary_op(&self) -> Option<&Operation<'func, A, M, F, operation::BinaryOp>> { + use self::ExprInfo::*; + + 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) => Some(op), + _ => None, + } + } + + pub fn as_binary_op_carry(&self) -> Option<&Operation<'func, A, M, F, operation::BinaryOpCarry>> { + use self::ExprInfo::*; + + 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::ExprInfo::*; + + 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::ExprInfo::*; + + match *self { + Neg(ref op) | + Not(ref op) | + Sx(ref op) | + Zx(ref op) | + LowPart(ref op) | + BoolToInt(ref op) => Some(op), + _ => None, + } + } + + pub(crate) fn raw_struct(&self) -> &BNLowLevelILInstruction { + use self::ExprInfo::*; + + 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) => &op.op, + + Load(ref op) => &op.op, + + Pop(ref op) => &op.op, + + Reg(ref op) => &op.op, + + Flag(ref op) => &op.op, + + FlagBit(ref op) => &op.op, + + Const(ref op) | + ConstPtr(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) => &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) => &op.op, + + UnimplMem(ref op) => &op.op, + + //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + } + } +} + +impl<'func, A> ExprInfo<'func, A, Mutable, NonSSA<LiftedNonSSA>> +where + A: 'func + Architecture, +{ + + pub fn flag_write(&self) -> Option<A::FlagWrite> { + use self::ExprInfo::*; + + 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) => None, + + Load(ref op) => op.flag_write(), + + Pop(ref op) => op.flag_write(), + + Reg(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(), + + 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) => 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) => op.flag_write(), + + UnimplMem(ref op) => op.flag_write(), + + //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + } + } +} + +impl<'func, A, M, V> fmt::Debug for ExprInfo<'func, A, M, NonSSA<V>> +where + A: 'func + Architecture, + M: FunctionMutability, + V: NonSSAVariant, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::ExprInfo::*; + + match *self { + Undef(..) => f.write_str("undefined"), + + Unimpl(..) => f.write_str("unimplemented"), + + FlagCond(..) => f.write_str("some_flag_cond"), + FlagGroup(..) => f.write_str("some_flag_group"), + + 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) => { + let left = op.left(); + let right = op.right(); + + write!(f, "{:?}({}, {:?}, {:?})", op.op.operation, op.size(), left, right) + } + + Load(ref op) => { + let source = op.source_mem_expr(); + let size = op.size(); + + write!(f, "[{:?}].{}", source, size) + } + + Pop(ref op) => write!(f, "pop.{}", op.size()), + + Reg(ref op) => { + let reg = op.source_reg(); + let size = op.size(); + + let size = match reg { + Register::Temp(_) => Some(size), + Register::ArchReg(ref r) if r.info().size() != size => Some(size), + _ => None + }; + + match size { + Some(s) => write!(f, "{:?}.{}", reg, s), + _ => write!(f, "{:?}", reg), + } + } + + Flag(ref _op) => write!(f, "flag"), // TODO + + FlagBit(ref _op) => write!(f, "flag_bit"), // TODO + + Const(ref op) | + ConstPtr(ref op) => write!(f, "0x{:x}", op.value()), + + Adc(ref op) | + Sbb(ref op) | + Rlc(ref op) | + Rrc(ref op) => { + let left = op.left(); + let right = op.right(); + let carry = op.carry(); + + write!(f, "{:?}({}, {:?}, {:?}, carry: {:?})", + op.op.operation, op.size(), left, right, 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) => { + let left = op.left(); + let right = op.right(); + + write!(f, "{:?}({}, {:?}, {:?})", + op.op.operation, op.size(), left, right) + } + + DivuDp(ref op) | + DivsDp(ref op) | + ModuDp(ref op) | + ModsDp(ref op) => { + let high = op.high(); + let low = op.low(); + let right = op.right(); + + write!(f, "{:?}({}, {:?}:{:?},{:?})", + op.op.operation, op.size(), high, low, right) + } + + Neg(ref op) | + Not(ref op) | + Sx(ref op) | + Zx(ref op) | + LowPart(ref op) | + BoolToInt(ref op) => { + write!(f, "{:?}({}, {:?})", op.op.operation, op.size(), op.operand()) + } + + UnimplMem(ref op) => write!(f, "unimplemented_mem({:?})", op.mem_expr()), + + //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + } + } +} |
