import operator
from typing import Callable, Iterable, Tuple
from pypcode import OpCode
import claripy
from claripy.ast.bv import BV
from ...errors import AngrError
# pylint:disable=abstract-method
[docs]def make_bv_sizes_equal(bv1: BV, bv2: BV) -> Tuple[BV, BV]:
"""
Makes two BVs equal in length through sign extension.
"""
if bv1.size() < bv2.size():
return (bv1.sign_extend(bv2.size() - bv1.size()), bv2)
elif bv1.size() > bv2.size():
return (bv1, bv2.sign_extend(bv1.size() - bv2.size()))
else:
return (bv1, bv2)
# FIXME: Unimplemented ops (mostly floating point related) have associated C++
# reference code from Ghidra which will need to be ported.
[docs]class OpBehavior:
"""
Base class for all operation behaviors.
"""
__slots__ = ("opcode", "is_unary", "is_special")
opcode: int
is_unary: bool
is_special: bool
def __init__(self, opcode: int, is_unary: bool, is_special: bool = False) -> None:
self.opcode = opcode
self.is_unary = is_unary
self.is_special = is_special
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV: # pylint:disable=no-self-use
raise AngrError("Not implemented!")
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV: # pylint:disable=no-self-use
raise AngrError("Not implemented!")
[docs] @staticmethod
def generic_compare(args: Iterable[BV], comparison: Callable[[BV, BV], BV]) -> BV:
return claripy.If(comparison(args[0], args[1]), claripy.BVV(1, 1), claripy.BVV(0, 1))
[docs] @classmethod
def booleanize(cls, in1: BV) -> BV:
"""
Reduce input BV to a single bit of truth: out <- 1 if (in1 != 0) else 0.
"""
return cls.generic_compare((in1, claripy.BVV(0, in1.size())), operator.ne)
[docs]class OpBehaviorCopy(OpBehavior):
"""
Behavior for the COPY operation.
"""
def __init__(self):
super().__init__(OpCode.COPY, True)
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV:
return in1
[docs]class OpBehaviorEqual(OpBehavior):
"""
Behavior for the INT_EQUAL operation.
"""
def __init__(self):
super().__init__(OpCode.INT_EQUAL, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.generic_compare((in1, in2), operator.eq)
[docs]class OpBehaviorNotEqual(OpBehavior):
"""
Behavior for the INT_NOTEQUAL operation.
"""
def __init__(self):
super().__init__(OpCode.INT_NOTEQUAL, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.generic_compare((in1, in2), operator.ne)
[docs]class OpBehaviorIntSless(OpBehavior):
"""
Behavior for the INT_SLESS operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SLESS, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.generic_compare((in1, in2), claripy.SLT)
[docs]class OpBehaviorIntSlessEqual(OpBehavior):
"""
Behavior for the INT_SLESSEQUAL operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SLESSEQUAL, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.generic_compare((in1, in2), claripy.SLE)
[docs]class OpBehaviorIntLess(OpBehavior):
"""
Behavior for the INT_LESS operation.
"""
def __init__(self):
super().__init__(OpCode.INT_LESS, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.generic_compare((in1, in2), claripy.ULT)
[docs]class OpBehaviorIntLessEqual(OpBehavior):
"""
Behavior for the INT_LESSEQUAL operation.
"""
def __init__(self):
super().__init__(OpCode.INT_LESSEQUAL, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.generic_compare((in1, in2), claripy.ULE)
[docs]class OpBehaviorIntZext(OpBehavior):
"""
Behavior for the INT_ZEXT operation.
"""
def __init__(self):
super().__init__(OpCode.INT_ZEXT, True)
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV:
return in1.zero_extend((size_out - size_in) * 8)
[docs]class OpBehaviorIntSext(OpBehavior):
"""
Behavior for the INT_SEXT operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SEXT, True)
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV:
return in1.sign_extend((size_out - size_in) * 8)
[docs]class OpBehaviorIntAdd(OpBehavior):
"""
Behavior for the INT_ADD operation.
"""
def __init__(self):
super().__init__(OpCode.INT_ADD, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 + in2
[docs]class OpBehaviorIntSub(OpBehavior):
"""
Behavior for the INT_SUB operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SUB, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 - in2
[docs]class OpBehaviorIntCarry(OpBehavior):
"""
Behavior for the INT_CARRY operation.
"""
def __init__(self):
super().__init__(OpCode.INT_CARRY, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
# origin: ccall.py pc_actions_ADD
res = in1 + in2
return claripy.If(claripy.ULT(res, in1), claripy.BVV(1, 1), claripy.BVV(0, 1))
[docs]class OpBehaviorIntScarry(OpBehavior):
"""
Behavior for the INT_SCARRY operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SCARRY, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
res = in1 + in2
a = (in1 >> (size_in * 8 - 1)) & 1
b = (in2 >> (size_in * 8 - 1)) & 1
r = (res >> (size_in * 8 - 1)) & 1
r ^= a
a ^= b
a ^= 1
r &= a
return r
[docs]class OpBehaviorIntSborrow(OpBehavior):
"""
Behavior for the INT_SBORROW operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SBORROW, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
res = in1 - in2
a = (in1 >> (size_in * 8 - 1)) & 1 # Grab sign bit
b = (in2 >> (size_in * 8 - 1)) & 1 # Grab sign bit
r = (res >> (size_in * 8 - 1)) & 1 # Grab sign bit
a ^= r
r ^= b
r ^= 1
a &= r
return a
[docs]class OpBehaviorInt2Comp(OpBehavior):
"""
Behavior for the INT_2COMP operation.
"""
def __init__(self):
super().__init__(OpCode.INT_2COMP, True)
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV:
return -in1
# uintb OpBehaviorInt2Comp::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# uintb res = uintb_negate(in1-1,size_in);
# return res;
# }
[docs]class OpBehaviorIntNegate(OpBehavior):
"""
Behavior for the INT_NEGATE operation.
"""
def __init__(self):
super().__init__(OpCode.INT_NEGATE, True)
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV:
return ~in1
[docs]class OpBehaviorIntXor(OpBehavior):
"""
Behavior for the INT_XOR operation.
"""
def __init__(self):
super().__init__(OpCode.INT_XOR, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 ^ in2
[docs]class OpBehaviorIntAnd(OpBehavior):
"""
Behavior for the INT_AND operation.
"""
def __init__(self):
super().__init__(OpCode.INT_AND, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 & in2
[docs]class OpBehaviorIntOr(OpBehavior):
"""
Behavior for the INT_OR operation.
"""
def __init__(self):
super().__init__(OpCode.INT_OR, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 | in2
[docs]class OpBehaviorIntLeft(OpBehavior):
"""
Behavior for the INT_LEFT operation.
"""
def __init__(self):
super().__init__(OpCode.INT_LEFT, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
in1, in2 = make_bv_sizes_equal(in1, in2)
return in1 << in2
[docs]class OpBehaviorIntRight(OpBehavior):
"""
Behavior for the INT_RIGHT operation.
"""
def __init__(self):
super().__init__(OpCode.INT_RIGHT, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
in1, in2 = make_bv_sizes_equal(in1, in2)
return in1.LShR(in2)
[docs]class OpBehaviorIntSright(OpBehavior):
"""
Behavior for the INT_SRIGHT operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SRIGHT, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
in1, in2 = make_bv_sizes_equal(in1, in2)
return in1 >> in2
[docs]class OpBehaviorIntMult(OpBehavior):
"""
Behavior for the INT_MULT operation.
"""
def __init__(self):
super().__init__(OpCode.INT_MULT, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1.zero_extend(size_out - size_in) * in2.zero_extend(size_out - size_in)
[docs]class OpBehaviorIntDiv(OpBehavior):
"""
Behavior for the INT_DIV operation.
"""
def __init__(self):
super().__init__(OpCode.INT_DIV, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 / in2
[docs]class OpBehaviorIntSdiv(OpBehavior):
"""
Behavior for the INT_SDIV operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SDIV, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 / in2
# uintb OpBehaviorIntSdiv::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# if (in2 == 0)
# throw EvaluationError("Divide by 0");
# intb num = in1; // Convert to signed
# intb denom = in2;
# sign_extend(num,8*size_in-1);
# sign_extend(denom,8*size_in-1);
# intb sres = num/denom; // Do the signed division
# zero_extend(sres,8*size_out-1); // Cut to appropriate size
# return (uintb)sres; // Recast as unsigned
# }
[docs]class OpBehaviorIntRem(OpBehavior):
"""
Behavior for the INT_REM operation.
"""
def __init__(self):
super().__init__(OpCode.INT_REM, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 % in2
[docs]class OpBehaviorIntSrem(OpBehavior):
"""
Behavior for the INT_SREM operation.
"""
def __init__(self):
super().__init__(OpCode.INT_SREM, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return in1 % in2
# uintb OpBehaviorIntSrem::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# if (in2 == 0)
# throw EvaluationError("Remainder by 0");
# intb val = in1;
# intb mod = in2;
# sign_extend(val,8*size_in-1); // Convert inputs to signed values
# sign_extend(mod,8*size_in-1);
# intb sres = in1 % in2; // Do the remainder
# zero_extend(sres,8*size_out-1); // Convert back to unsigned
# return (uintb)sres;
# }
[docs]class OpBehaviorBoolNegate(OpBehavior):
"""
Behavior for the BOOL_NEGATE operation.
"""
def __init__(self):
super().__init__(OpCode.BOOL_NEGATE, True)
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV:
return self.generic_compare((in1, claripy.BVV(0, in1.size())), operator.eq)
[docs]class OpBehaviorBoolXor(OpBehavior):
"""
Behavior for the BOOL_XOR operation.
"""
def __init__(self):
super().__init__(OpCode.BOOL_XOR, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.booleanize(in1) ^ self.booleanize(in2)
[docs]class OpBehaviorBoolAnd(OpBehavior):
"""
Behavior for the BOOL_AND operation.
"""
def __init__(self):
super().__init__(OpCode.BOOL_AND, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.booleanize(in1) & self.booleanize(in2)
[docs]class OpBehaviorBoolOr(OpBehavior):
"""
Behavior for the BOOL_OR operation.
"""
def __init__(self):
super().__init__(OpCode.BOOL_OR, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
return self.booleanize(in1) | self.booleanize(in2)
[docs]class OpBehaviorFloatEqual(OpBehavior):
"""
Behavior for the FLOAT_EQUAL operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_EQUAL, False)
# uintb OpBehaviorFloatEqual::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opEqual(in1,in2);
# }
[docs]class OpBehaviorFloatNotEqual(OpBehavior):
"""
Behavior for the FLOAT_NOTEQUAL operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_NOTEQUAL, False)
# uintb OpBehaviorFloatNotEqual::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opNotEqual(in1,in2);
# }
[docs]class OpBehaviorFloatLess(OpBehavior):
"""
Behavior for the FLOAT_LESS operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_LESS, False)
# uintb OpBehaviorFloatLess::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opLess(in1,in2);
# }
[docs]class OpBehaviorFloatLessEqual(OpBehavior):
"""
Behavior for the FLOAT_LESSEQUAL operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_LESSEQUAL, False)
# uintb OpBehaviorFloatLessEqual::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opLessEqual(in1,in2);
# }
[docs]class OpBehaviorFloatNan(OpBehavior):
"""
Behavior for the FLOAT_NAN operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_NAN, True)
# uintb OpBehaviorFloatNan::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opNan(in1);
# }
[docs]class OpBehaviorFloatAdd(OpBehavior):
"""
Behavior for the FLOAT_ADD operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_ADD, False)
# uintb OpBehaviorFloatAdd::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opAdd(in1,in2);
# }
[docs]class OpBehaviorFloatDiv(OpBehavior):
"""
Behavior for the FLOAT_DIV operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_DIV, False)
# uintb OpBehaviorFloatDiv::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opDiv(in1,in2);
# }
[docs]class OpBehaviorFloatMult(OpBehavior):
"""
Behavior for the FLOAT_MULT operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_MULT, False)
# uintb OpBehaviorFloatMult::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opMult(in1,in2);
# }
[docs]class OpBehaviorFloatSub(OpBehavior):
"""
Behavior for the FLOAT_SUB operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_SUB, False)
# uintb OpBehaviorFloatSub::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateBinary(size_out,size_in,in1,in2);
#
# return format->opSub(in1,in2);
# }
[docs]class OpBehaviorFloatNeg(OpBehavior):
"""
Behavior for the FLOAT_NEG operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_NEG, True)
# uintb OpBehaviorFloatNeg::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opNeg(in1);
# }
[docs]class OpBehaviorFloatAbs(OpBehavior):
"""
Behavior for the FLOAT_ABS operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_ABS, True)
# uintb OpBehaviorFloatAbs::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opAbs(in1);
# }
[docs]class OpBehaviorFloatSqrt(OpBehavior):
"""
Behavior for the FLOAT_SQRT operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_SQRT, True)
# uintb OpBehaviorFloatSqrt::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opSqrt(in1);
# }
[docs]class OpBehaviorFloatInt2Float(OpBehavior):
"""
Behavior for the FLOAT_INT2FLOAT operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_INT2FLOAT, True)
# uintb OpBehaviorFloatInt2Float::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_out);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opInt2Float(in1,size_in);
# }
[docs]class OpBehaviorFloatFloat2Float(OpBehavior):
"""
Behavior for the FLOAT_FLOAT2FLOAT operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_FLOAT2FLOAT, True)
# uintb OpBehaviorFloatFloat2Float::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *formatout = translate->getFloatFormat(size_out);
# if (formatout == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
# const FloatFormat *formatin = translate->getFloatFormat(size_in);
# if (formatin == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return formatin->opFloat2Float(in1,*formatout);
# }
[docs]class OpBehaviorFloatTrunc(OpBehavior):
"""
Behavior for the FLOAT_TRUNC operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_TRUNC, True)
# uintb OpBehaviorFloatTrunc::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opTrunc(in1,size_out);
# }
[docs]class OpBehaviorFloatCeil(OpBehavior):
"""
Behavior for the FLOAT_CEIL operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_CEIL, True)
# uintb OpBehaviorFloatCeil::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opCeil(in1);
# }
[docs]class OpBehaviorFloatFloor(OpBehavior):
"""
Behavior for the FLOAT_FLOOR operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_FLOOR, True)
# uintb OpBehaviorFloatFloor::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opFloor(in1);
# }
[docs]class OpBehaviorFloatRound(OpBehavior):
"""
Behavior for the FLOAT_ROUND operation.
"""
def __init__(self):
super().__init__(OpCode.FLOAT_ROUND, True)
# uintb OpBehaviorFloatRound::evaluateUnary(int4 size_out,int4 size_in,uintb in1) const
#
# {
# const FloatFormat *format = translate->getFloatFormat(size_in);
# if (format == (const FloatFormat *)0)
# return OpBehavior::evaluateUnary(size_out,size_in,in1);
#
# return format->opRound(in1);
# }
[docs]class OpBehaviorPiece(OpBehavior):
"""
Behavior for the PIECE operation.
"""
def __init__(self):
super().__init__(OpCode.PIECE, False)
# uintb OpBehaviorPiece::evaluateBinary(int4 size_out,int4 size_in,uintb in1,uintb in2) const
#
# {
# uintb res = ( in1<<((size_out-size_in)*8)) | in2;
# return res;
# }
[docs]class OpBehaviorSubpiece(OpBehavior):
"""
Behavior for the SUBPIECE operation.
"""
def __init__(self):
super().__init__(OpCode.SUBPIECE, False)
[docs] def evaluate_binary(self, size_out: int, size_in: int, in1: BV, in2: BV) -> BV:
if in2.size() < in1.size():
in2 = in2.sign_extend(in1.size() - in2.size())
return (in1 >> (in2 * 8)) & (2 ** (size_out * 8) - 1)
[docs]class OpBehaviorPopcount(OpBehavior):
"""
Behavior for the POPCOUNT operation.
"""
def __init__(self):
super().__init__(OpCode.POPCOUNT, True)
[docs] def evaluate_unary(self, size_out: int, size_in: int, in1: BV) -> BV:
expr = claripy.BVV(0, size_out * 8)
for a in range(len(in1)):
expr += claripy.Extract(a, a, in1).zero_extend(size_out * 8 - 1)
return expr
[docs]class BehaviorFactory:
"""
Returns the behavior object for a given opcode.
"""
def __init__(self):
self._behaviors = {}
self._register_behaviors()
[docs] def get_behavior_for_opcode(self, opcode: int) -> OpBehavior:
return self._behaviors[opcode]
def _register_behaviors(self) -> None:
self._behaviors.update(
{
OpCode.COPY: OpBehaviorCopy(),
OpCode.LOAD: OpBehavior(OpCode.LOAD, False, True),
OpCode.STORE: OpBehavior(OpCode.STORE, False, True),
OpCode.BRANCH: OpBehavior(OpCode.BRANCH, False, True),
OpCode.CBRANCH: OpBehavior(OpCode.CBRANCH, False, True),
OpCode.BRANCHIND: OpBehavior(OpCode.BRANCHIND, False, True),
OpCode.CALL: OpBehavior(OpCode.CALL, False, True),
OpCode.CALLIND: OpBehavior(OpCode.CALLIND, False, True),
OpCode.CALLOTHER: OpBehavior(OpCode.CALLOTHER, False, True),
OpCode.RETURN: OpBehavior(OpCode.RETURN, False, True),
OpCode.MULTIEQUAL: OpBehavior(OpCode.MULTIEQUAL, False, True),
OpCode.INDIRECT: OpBehavior(OpCode.INDIRECT, False, True),
OpCode.PIECE: OpBehaviorPiece(),
OpCode.SUBPIECE: OpBehaviorSubpiece(),
OpCode.INT_EQUAL: OpBehaviorEqual(),
OpCode.INT_NOTEQUAL: OpBehaviorNotEqual(),
OpCode.INT_SLESS: OpBehaviorIntSless(),
OpCode.INT_SLESSEQUAL: OpBehaviorIntSlessEqual(),
OpCode.INT_LESS: OpBehaviorIntLess(),
OpCode.INT_LESSEQUAL: OpBehaviorIntLessEqual(),
OpCode.INT_ZEXT: OpBehaviorIntZext(),
OpCode.INT_SEXT: OpBehaviorIntSext(),
OpCode.INT_ADD: OpBehaviorIntAdd(),
OpCode.INT_SUB: OpBehaviorIntSub(),
OpCode.INT_CARRY: OpBehaviorIntCarry(),
OpCode.INT_SCARRY: OpBehaviorIntScarry(),
OpCode.INT_SBORROW: OpBehaviorIntSborrow(),
OpCode.INT_2COMP: OpBehaviorInt2Comp(),
OpCode.INT_NEGATE: OpBehaviorIntNegate(),
OpCode.INT_XOR: OpBehaviorIntXor(),
OpCode.INT_AND: OpBehaviorIntAnd(),
OpCode.INT_OR: OpBehaviorIntOr(),
OpCode.INT_LEFT: OpBehaviorIntLeft(),
OpCode.INT_RIGHT: OpBehaviorIntRight(),
OpCode.INT_SRIGHT: OpBehaviorIntSright(),
OpCode.INT_MULT: OpBehaviorIntMult(),
OpCode.INT_DIV: OpBehaviorIntDiv(),
OpCode.INT_SDIV: OpBehaviorIntSdiv(),
OpCode.INT_REM: OpBehaviorIntRem(),
OpCode.INT_SREM: OpBehaviorIntSrem(),
OpCode.BOOL_NEGATE: OpBehaviorBoolNegate(),
OpCode.BOOL_XOR: OpBehaviorBoolXor(),
OpCode.BOOL_AND: OpBehaviorBoolAnd(),
OpCode.BOOL_OR: OpBehaviorBoolOr(),
OpCode.CAST: OpBehavior(OpCode.CAST, False, True),
OpCode.PTRADD: OpBehavior(OpCode.PTRADD, False, True),
OpCode.PTRSUB: OpBehavior(OpCode.PTRSUB, False, True),
OpCode.FLOAT_EQUAL: OpBehaviorFloatEqual(),
OpCode.FLOAT_NOTEQUAL: OpBehaviorFloatNotEqual(),
OpCode.FLOAT_LESS: OpBehaviorFloatLess(),
OpCode.FLOAT_LESSEQUAL: OpBehaviorFloatLessEqual(),
OpCode.FLOAT_NAN: OpBehaviorFloatNan(),
OpCode.FLOAT_ADD: OpBehaviorFloatAdd(),
OpCode.FLOAT_DIV: OpBehaviorFloatDiv(),
OpCode.FLOAT_MULT: OpBehaviorFloatMult(),
OpCode.FLOAT_SUB: OpBehaviorFloatSub(),
OpCode.FLOAT_NEG: OpBehaviorFloatNeg(),
OpCode.FLOAT_ABS: OpBehaviorFloatAbs(),
OpCode.FLOAT_SQRT: OpBehaviorFloatSqrt(),
OpCode.FLOAT_INT2FLOAT: OpBehaviorFloatInt2Float(),
OpCode.FLOAT_FLOAT2FLOAT: OpBehaviorFloatFloat2Float(),
OpCode.FLOAT_TRUNC: OpBehaviorFloatTrunc(),
OpCode.FLOAT_CEIL: OpBehaviorFloatCeil(),
OpCode.FLOAT_FLOOR: OpBehaviorFloatFloor(),
OpCode.FLOAT_ROUND: OpBehaviorFloatRound(),
OpCode.SEGMENTOP: OpBehavior(OpCode.SEGMENTOP, False, True),
OpCode.CPOOLREF: OpBehavior(OpCode.CPOOLREF, False, True),
OpCode.NEW: OpBehavior(OpCode.NEW, False, True),
OpCode.INSERT: OpBehavior(OpCode.INSERT, False, True),
OpCode.EXTRACT: OpBehavior(OpCode.EXTRACT, False, True),
OpCode.POPCOUNT: OpBehaviorPopcount(),
}
)