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)
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!")
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")
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
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")
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
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)