import functools
from typing import Union
from pyvex.const import get_type_size
from pyvex.expr import Const, IRExpr, RdTmp
from .vex_helper import IRSBCustomizer, Type
[docs]
def checkparams(rhstype=None):
def decorator(fn):
@functools.wraps(fn)
def inner_decorator(self, *args, **kwargs):
irsb_cs = {a.irsb_c for a in list(args) + [self] if isinstance(a, VexValue)} # pylint: disable=no-member
assert len(irsb_cs) == 1, "All VexValues must belong to the same irsb_c"
args = list(args)
for idx, arg in enumerate(args):
if isinstance(arg, int):
thetype = rhstype if rhstype else self.ty
args[idx] = VexValue.Constant(self.irsb_c, arg, thetype)
elif not isinstance(arg, VexValue):
raise Exception("Cannot convert param %s" % str(arg))
args = tuple(args)
return fn(self, *args, **kwargs)
return inner_decorator
return decorator
[docs]
def vvifyresults(f):
@functools.wraps(f)
def decor(self, *args, **kwargs):
returned = f(self, *args, **kwargs)
assert isinstance(returned, RdTmp) or isinstance(returned, Const)
return VexValue(self.irsb_c, returned)
return decor
[docs]
class VexValue:
[docs]
def __init__(self, irsb_c: "IRSBCustomizer", rdt: "Union[RdTmp, Const]", signed=False):
self.irsb_c = irsb_c
self.ty = self.irsb_c.get_type(rdt)
self.rdt = rdt
self.width = get_type_size(self.ty)
self._is_signed = signed
@property
def value(self):
if isinstance(self.rdt, Const):
return self.rdt.con.value
else:
raise ValueError("Non-constant VexValue has no value property")
@property
def signed(self):
return VexValue(self.irsb_c, self.rdt, True)
[docs]
@vvifyresults
def widen_unsigned(self, ty):
return self.irsb_c.op_widen_int_unsigned(self.rdt, ty)
[docs]
@vvifyresults
def cast_to(self, ty, signed=False, high=False):
return self.irsb_c.cast_to(self.rdt, ty, signed=signed, high=high)
[docs]
@vvifyresults
def widen_signed(self, ty):
return self.irsb_c.op_widen_int_signed(self.rdt, ty)
[docs]
@vvifyresults
def narrow_high(self, ty):
return self.irsb_c.op_narrow_int(self.rdt, ty, high_half=True)
[docs]
@vvifyresults
def narrow_low(self, ty):
return self.irsb_c.op_narrow_int(self.rdt, ty, high_half=False)
# TODO at some point extend this to Vex nonconstants
def __getitem__(self, idx):
def getb(i):
return VexValue(self.irsb_c, self.irsb_c.get_bit(self.rdt, i))
def makeconstant(x):
return VexValue.Constant(self.irsb_c, x, Type.int_8).rdt
if not isinstance(idx, slice):
actualindex = slice(idx).indices(self.width)[1]
return getb(makeconstant(actualindex))
else:
return [getb(makeconstant(i)) for i in range(*idx.indices(self.width))]
def __setitem__(self, idx, bval):
setted = self.set_bit(idx, bval)
self.__init__(setted.irsb_c, setted.rdt)
[docs]
@checkparams(rhstype=Type.int_8)
@vvifyresults
def set_bit(self, idx, bval):
return self.irsb_c.set_bit(self.rdt, idx.rdt, bval.rdt)
[docs]
@checkparams()
@vvifyresults
def set_bits(self, idxsandvals):
return self.irsb_c.set_bits(self.rdt, [(i.cast_to(Type.int_8).rdt, b.rdt) for i, b in idxsandvals])
[docs]
@checkparams()
@vvifyresults
def ite(self, iftrue, iffalse):
onebitcond = self.cast_to(Type.int_1)
return self.irsb_c.ite(onebitcond.rdt, iftrue.rdt, iffalse.rdt)
[docs]
@checkparams()
@vvifyresults
def sar(self, right):
"""
`v.sar(r)` should do arithmetic shift right of `v` by `r`
:param right:VexValue value to shift by
:return: VexValue - result of a shift
"""
return self.irsb_c.op_sar(self.rdt, right.rdt)
@checkparams()
@vvifyresults
def __add__(self, right):
return self.irsb_c.op_add(self.rdt, right.rdt)
@checkparams()
def __radd__(self, left):
return self + left
@checkparams()
@vvifyresults
def __sub__(self, right):
return self.irsb_c.op_sub(self.rdt, right.rdt)
@checkparams()
def __rsub__(self, left):
return left - self
@checkparams()
@vvifyresults
def __div__(self, right):
if self._is_signed:
return self.irsb_c.op_sdiv(self.rdt, right.rdt)
else:
return self.irsb_c.op_udiv(self.rdt, right.rdt)
@checkparams()
def __rdiv__(self, left):
return left // self
@checkparams()
def __floordiv__(self, right): # Note: nonprimitive
return self.__div__(right)
@checkparams()
def __rfloordiv__(self, left):
return left // self
@checkparams()
def __truediv__(self, right): # Note: nonprimitive
return self / right
@checkparams()
def __rtruediv__(self, left):
return left.__truediv__(self)
@checkparams()
@vvifyresults
def __and__(self, right):
return self.irsb_c.op_and(self.rdt, right.rdt)
@checkparams()
def __rand__(self, left):
return left & self
@checkparams()
@vvifyresults
def __eq__(self, right):
return self.irsb_c.op_cmp_eq(self.rdt, right.rdt)
@checkparams()
@vvifyresults
def __ne__(self, other):
return self.irsb_c.op_cmp_ne(self.rdt, other.rdt)
@checkparams()
@vvifyresults
def __invert__(self):
return self.irsb_c.op_not(self.rdt)
@checkparams()
@vvifyresults
def __le__(self, right):
if self._is_signed:
return self.irsb_c.op_cmp_sle(self.rdt, right.rdt)
else:
return self.irsb_c.op_cmp_ule(self.rdt, right.rdt)
@checkparams()
@vvifyresults
def __gt__(self, other):
if self._is_signed:
return self.irsb_c.op_cmp_sgt(self.rdt, other.rdt)
else:
return self.irsb_c.op_cmp_ugt(self.rdt, other.rdt)
@checkparams()
@vvifyresults
def __ge__(self, right):
if self._is_signed:
return self.irsb_c.op_cmp_sge(self.rdt, right.rdt)
else:
return self.irsb_c.op_cmp_uge(self.rdt, right.rdt)
@checkparams(rhstype=Type.int_8)
@vvifyresults
def __lshift__(self, right): # TODO put better type inference in irsb_c so we can have rlshift
"""
logical shift left
"""
return self.irsb_c.op_shl(self.rdt, right.rdt)
@checkparams()
@vvifyresults
def __lt__(self, right):
if self._is_signed:
return self.irsb_c.op_cmp_slt(self.rdt, right.rdt)
else:
return self.irsb_c.op_cmp_ult(self.rdt, right.rdt)
@checkparams()
@vvifyresults
def __mod__(self, right): # Note: nonprimitive
return self.irsb_c.op_mod(self.rdt, right.rdt)
@checkparams()
def __rmod__(self, left):
return left % self
@checkparams()
@vvifyresults
def __mul__(self, right):
if self._is_signed:
return self.irsb_c.op_smul(self.rdt, right.rdt)
else:
return self.irsb_c.op_umul(self.rdt, right.rdt)
@checkparams()
def __rmul__(self, left):
return left * self
@checkparams()
@vvifyresults
def __neg__(self): # Note: nonprimitive
if not self._is_signed:
raise Exception("Number is unsigned, cannot change sign!")
else:
return self.rdt * -1
@checkparams()
@vvifyresults
def __or__(self, right):
return self.irsb_c.op_or(self.rdt, right.rdt)
def __ror__(self, left):
return self | left
@checkparams()
@vvifyresults
def __pos__(self):
return self
@checkparams(rhstype=Type.int_8)
@vvifyresults
def __rshift__(self, right):
"""
logical shift right
"""
return self.irsb_c.op_shr(self.rdt, right.rdt)
@checkparams()
def __rlshift__(self, left):
return left << self
@checkparams()
def __rrshift__(self, left):
return left >> self
@checkparams()
@vvifyresults
def __xor__(self, right):
return self.irsb_c.op_xor(self.rdt, right.rdt)
def __rxor__(self, left):
return self ^ left
[docs]
@classmethod
def Constant(cls, irsb_c, val, ty):
"""
Creates a constant as a VexValue
:param irsb_c: The IRSBCustomizer to use
:param val: The value, as an integer
:param ty: The type of the resulting VexValue
:return: a VexValue
"""
assert not (isinstance(val, VexValue) or isinstance(val, IRExpr))
rdt = irsb_c.mkconst(val, ty)
return cls(irsb_c, rdt)