예제 #1
0
    def _op_mapped(self, args):
        if self._from_size is not None:
            sized_args = []
            for a in args:
                s = a.size()
                if s == self._from_size:
                    sized_args.append(a)
                elif s < self._from_size:
                    if self.is_signed:
                        sized_args.append(
                            claripy.SignExt(self._from_size - s, a))
                    else:
                        sized_args.append(
                            claripy.ZeroExt(self._from_size - s, a))
                elif s > self._from_size:
                    raise SimOperationError(
                        "operation %s received too large an argument" %
                        self.name)
        else:
            sized_args = args

        if self._generic_name in bitwise_operation_map:
            o = bitwise_operation_map[self._generic_name]
        elif self._generic_name in arithmetic_operation_map:
            o = arithmetic_operation_map[self._generic_name]
        elif self._generic_name in shift_operation_map:
            o = shift_operation_map[self._generic_name]
        else:
            raise SimOperationError(
                "op_mapped called with invalid mapping, for %s" % self.name)

        return getattr(claripy.ast.BV, o)(*sized_args)
예제 #2
0
    def calculate(self, *args):
        if not all(isinstance(a, claripy.ast.Base) for a in args):
            import ipdb; ipdb.set_trace()
            raise SimOperationError("IROp needs all args as claripy expressions")

        if not self._float:
            args = tuple(arg.to_bv() for arg in args)

        try:
            return self.extend_size(self._calculate(args))
        except (TypeError, ValueError, SimValueError, claripy.ClaripyError):
            e_type, value, traceback = sys.exc_info()
            raise SimOperationError, ("%s._calculate() raised exception" % self.name, e_type, value), traceback
        except ZeroDivisionError:
            raise SimOperationError("divide by zero!")
예제 #3
0
 def _op_fgeneric_Reinterp(self, args):
     if self._to_type == 'I':
         return args[0].to_bv()
     elif self._to_type == 'F':
         return args[0].raw_to_fp()
     else:
         raise SimOperationError("unsupport Reinterp _to_type")
예제 #4
0
 def extend_size(self, o):
     cur_size = o.size()
     if cur_size < self._output_size_bits:
         l.debug("Extending output of %s from %d to %d bits", self.name, cur_size, self._output_size_bits)
         ext_size = self._output_size_bits - cur_size
         if self._to_signed == 'S' or (self._from_signed == 'S' and self._to_signed is None):
             return claripy.SignExt(ext_size, o)
         else:
             return claripy.ZeroExt(ext_size, o)
     elif cur_size > self._output_size_bits:
         __import__('ipdb').set_trace()
         raise SimOperationError('output of %s is too big', self.name)
     else:
         return o
예제 #5
0
 def generic_shift_thing(self, args, op):
     if self._vector_size is not None:
         shifted = []
         if args[1].length != self._vector_size:
             shift_by = args[1].zero_extend(self._vector_size -
                                            args[1].length)
         else:
             shift_by = args[1]
         for i in reversed(range(self._vector_count)):
             left = claripy.Extract((i + 1) * self._vector_size - 1,
                                    i * self._vector_size, args[0])
             shifted.append(op(left, shift_by))
         return claripy.Concat(*shifted)
     else:
         raise SimOperationError("you done f****d")
예제 #6
0
 def _op_generic_pack_StoU_saturation(self, args, src_size, dst_size):
     """
     Generic pack with unsigned saturation.
     Split args in chunks of src_size signed bits and in pack them into unsigned saturated chunks of dst_size bits.
     Then chunks are concatenated resulting in a BV of len(args)*dst_size/src_size*len(args[0]) bits.
     """
     if src_size <= 0 or dst_size <= 0:
         raise SimOperationError("Can't pack from or to zero or negative size" % self.name)
     result = None
     max_value = claripy.BVV(-1, dst_size).zero_extend(src_size - dst_size) #max value for unsigned saturation
     min_value = claripy.BVV(0, src_size) #min unsigned value always 0
     for v in args:
         for src_value in v.chop(src_size):
             dst_value = self._op_generic_StoU_saturation(src_value, min_value, max_value)
             dst_value = dst_value.zero_extend(dst_size - src_size)
             if result is None:
                 result = dst_value
             else:
                 result = self._op_concat((result, dst_value))
     return result
예제 #7
0
    def __init__(self, name, **attrs):
        l.debug("Creating SimIROp(%s)", name)
        self.name = name
        self.op_attrs = attrs

        self._generic_name = None
        self._from_size = None
        self._from_side = None
        self._from_type = None
        self._from_signed = None
        self._to_size = None
        self._to_type = None
        self._to_signed = None
        self._conversion = None
        self._vector_size = None
        self._vector_signed = None
        self._vector_type = None
        self._vector_zero = None
        self._vector_count = None

        self._rounding_mode = None

        for k, v in self.op_attrs.items():
            if v is not None and ('size' in k or 'count' in k):
                v = int(v)
            setattr(self, '_%s' % k, v)

        # determine the output size
        #pylint:disable=no-member
        self._output_type = pyvex.typeOfIROp(name)
        #pylint:enable=no-member
        self._output_size_bits = size_bits(self._output_type)
        l.debug("... VEX says the output size should be %s",
                self._output_size_bits)

        size_check = self._to_size is None or (
            self._to_size * 2 if self._generic_name == 'DivMod' else
            self._to_size) == self._output_size_bits
        if not size_check:
            raise SimOperationError(
                "VEX output size doesn't match detected output size")

        #
        # Some categorization
        #

        generic_names.add(self._generic_name)
        if self._conversion is not None:
            conversions[(self._from_type, self._from_signed, self._to_type,
                         self._to_signed)].append(self)

        if len({self._vector_type, self._from_type, self._to_type}
               & {'F', 'D'}) != 0:
            # print self.op_attrs
            self._float = True

            if len({self._vector_type, self._from_type, self._to_type}
                   & {'D'}) != 0:
                l.debug('... aborting on BCD!')
                # fp_ops.add(self.name)
                raise UnsupportedIROpError("BCD ops aren't supported")
        else:
            self._float = False

        #
        # Now determine the operation
        #

        self._calculate = None

        # is it explicitly implemented?
        if hasattr(self, '_op_' + name):
            self._calculate = getattr(self, '_op_' + name)
        # if the generic name is None and there's a conversion present, this is a standard
        # widening or narrowing or sign-extension
        elif self._generic_name is None and self._conversion:
            # convert int to float
            if self._float and self._from_type == 'I':
                self._calculate = self._op_int_to_fp

            # convert float to differently-sized float
            elif self._from_type == 'F' and self._to_type == 'F':
                self._calculate = self._op_fp_to_fp

            elif self._from_type == 'F' and self._to_type == 'I':
                self._calculate = self._op_fp_to_int

            # this concatenates the args into the high and low halves of the result
            elif self._from_side == 'HL':
                l.debug("... using simple concat")
                self._calculate = self._op_concat

            # this just returns the high half of the first arg
            elif self._from_size > self._to_size and self._from_side == 'HI':
                l.debug("... using hi half")
                self._calculate = self._op_hi_half

            # this just returns the high half of the first arg
            elif self._from_size > self._to_size and self._from_side in ('L',
                                                                         'LO'):
                l.debug("... using lo half")
                self._calculate = self._op_lo_half

            elif self._from_size > self._to_size and self._from_side is None:
                l.debug("... just extracting")
                self._calculate = self._op_extract

            elif self._from_size < self._to_size and self.is_signed:
                l.debug("... using simple sign-extend")
                self._calculate = self._op_sign_extend

            elif self._from_size < self._to_size and not self.is_signed:
                l.debug("... using simple zero-extend")
                self._calculate = self._op_zero_extend

            else:
                l.error(
                    "%s is an unexpected conversion operation configuration",
                    self)
                assert False

        # other conversions
        elif self._conversion and self._generic_name != 'Round' and self._generic_name != 'Reinterp':
            if self._generic_name == "DivMod":
                l.debug("... using divmod")
                self._calculate = self._op_divmod
            else:
                unsupported_conversions.append(self.name)
                common_unsupported_generics[self._generic_name] += 1

        # generic bitwise
        elif self._generic_name in bitwise_operation_map:
            l.debug("... using generic mapping op")
            assert self._from_side is None
            self._calculate = self._op_mapped

        # generic mapping operations
        elif self._generic_name in arithmetic_operation_map or self._generic_name in shift_operation_map:
            l.debug("... using generic mapping op")
            assert self._from_side is None

            if self._float and self._vector_zero:
                self._calculate = self._op_float_op_just_low
            elif self._float and self._vector_count is None:
                self._calculate = self._op_float_mapped
            elif not self._float and self._vector_count is not None:
                self._calculate = self._op_vector_mapped
            else:
                self._calculate = self._op_mapped

        # TODO: clean up this mess
        # specifically-implemented generics
        elif self._float and hasattr(self,
                                     '_op_fgeneric_%s' % self._generic_name):
            l.debug("... using generic method")
            calculate = getattr(self, '_op_fgeneric_%s' % self._generic_name)
            if self._vector_size is not None and \
               not hasattr(calculate, 'supports_vector'):
                # unsupported vector ops
                vector_operations.append(name)
            else:
                self._calculate = calculate

        elif not self._float and hasattr(
                self, '_op_generic_%s' % self._generic_name):
            l.debug("... using generic method")
            calculate = getattr(self, '_op_generic_%s' % self._generic_name)
            if self._vector_size is not None and \
               not hasattr(calculate, 'supports_vector'):
                # unsupported vector ops
                vector_operations.append(name)
            else:
                self._calculate = calculate

        else:
            common_unsupported_generics[self._generic_name] += 1
            other_operations.append(name)

        # if we're here and calculate is None, we don't support this
        if self._calculate is None:
            l.debug("... can't support operations")
            raise UnsupportedIROpError(
                "no calculate function identified for %s" % self.name)