def _abstract_internal(self, ctx, ast, split_on=None): h = self._z3_ast_hash(ctx, ast) try: return self._ast_cache[h] except KeyError: pass decl = z3.Z3_get_app_decl(ctx, ast) decl_num = z3.Z3_get_decl_kind(ctx, decl) z3_sort = z3.Z3_get_sort(ctx, ast) if decl_num not in z3_op_nums: raise ClaripyError("unknown decl kind %d" % decl_num) if z3_op_nums[decl_num] not in op_map: raise ClaripyError("unknown decl op %s" % z3_op_nums[decl_num]) op_name = op_map[z3_op_nums[decl_num]] num_args = z3.Z3_get_app_num_args(ctx, ast) split_on = self._split_on if split_on is None else split_on new_split_on = split_on if op_name in split_on else set() children = [ self._abstract_internal(ctx, z3.Z3_get_app_arg(ctx, ast, i), new_split_on) for i in range(num_args) ] append_children = True if op_name == 'True': return BoolV(True) elif op_name == 'False': return BoolV(False) elif op_name.startswith('RM_'): return RM.from_name(op_name) elif op_name == 'BitVecVal': bv_size = z3.Z3_get_bv_sort_size(ctx, z3_sort) if z3.Z3_get_numeral_uint64(ctx, ast, self._c_uint64_p): return BVV(self._c_uint64_p.contents.value, bv_size) else: bv_num = int(z3.Z3_get_numeral_string(ctx, ast)) return BVV(bv_num, bv_size) elif op_name in ('FPVal', 'MinusZero', 'MinusInf', 'PlusZero', 'PlusInf', 'NaN'): ebits = z3.Z3_fpa_get_ebits(ctx, z3_sort) sbits = z3.Z3_fpa_get_sbits(ctx, z3_sort) sort = FSort.from_params(ebits, sbits) val = self._abstract_fp_val(ctx, ast, op_name) return FPV(val, sort) elif op_name == 'UNINTERPRETED' and num_args == 0: # symbolic value symbol_name = z3.Z3_get_symbol_string( ctx, z3.Z3_get_decl_name(ctx, decl)) symbol_ty = z3.Z3_get_sort_kind(ctx, z3_sort) if symbol_ty == z3.Z3_BV_SORT: bv_size = z3.Z3_get_bv_sort_size(ctx, z3_sort) return BV('BVS', (symbol_name, None, None, None, False, False, None), length=bv_size, variables={symbol_name}, symbolic=True) elif symbol_ty == z3.Z3_FLOATING_POINT_SORT: ebits = z3.Z3_fpa_get_ebits(ctx, z3_sort) sbits = z3.Z3_fpa_get_sbits(ctx, z3_sort) sort = FSort.from_params(ebits, sbits) return FP('FPS', (symbol_name, sort), variables={symbol_name}, symbolic=True, length=sort.length) else: raise BackendError("Unknown z3 term type %d...?" % symbol_ty) elif op_name == 'UNINTERPRETED': mystery_name = z3.Z3_get_symbol_string( ctx, z3.Z3_get_decl_name(ctx, decl)) args = [] # # TODO: DEPRECATED: remove the following after some reasonable amount of time. # if mystery_name == 'bvsmod_i': l.error( "Your Z3 is out of date. Please update angr-only-z3-custom or future releases of claripy will fail." ) op_name = '__mod__' decl_num = z3.Z3_OP_BSMOD elif mystery_name == 'bvsdiv_i': l.error( "Your Z3 is out of date. Please update angr-only-z3-custom or future releases of claripy will fail." ) op_name = 'SDiv' decl_num = z3.Z3_OP_BSDIV else: l.error( "Mystery operation %s in BackendZ3._abstract_internal. Please report this.", mystery_name) elif op_name == 'Extract': hi = z3.Z3_get_decl_int_parameter(ctx, decl, 0) lo = z3.Z3_get_decl_int_parameter(ctx, decl, 1) args = [hi, lo] elif op_name in ('SignExt', 'ZeroExt'): num = z3.Z3_get_decl_int_parameter(ctx, decl, 0) args = [num] elif op_name in ('fpToFP', 'fpToFPSigned'): exp = z3.Z3_fpa_get_ebits(ctx, z3_sort) mantissa = z3.Z3_fpa_get_sbits(ctx, z3_sort) sort = FSort.from_params(exp, mantissa) args = children + [sort] append_children = False elif op_name in ('fpToSBV', 'fpToUBV'): # uuuuuugggggghhhhhh bv_size = z3.Z3_get_bv_sort_size(ctx, z3_sort) args = children + [bv_size] append_children = False else: args = [] if append_children: args.extend(children) # hmm.... honestly not sure what to do here result_ty = op_type_map[z3_op_nums[decl_num]] ty = type(args[-1]) if type(result_ty) is str: err = "Unknown Z3 error in abstraction (result_ty == '%s'). Update your version of Z3, and, if the problem persists, open a claripy issue." % result_ty l.error(err) raise BackendError(err) if op_name == 'If': # If is polymorphic and thus must be handled specially ty = type(args[1]) a = ty('If', tuple(args), length=args[1].length) elif hasattr(ty, op_name) or hasattr(_all_operations, op_name): op = getattr(ty if hasattr(ty, op_name) else _all_operations, op_name) if op.calc_length is not None: length = op.calc_length(*args) a = result_ty(op_name, tuple(args), length=length) else: a = result_ty(op_name, tuple(args)) else: a = result_ty(op_name, tuple(args)) self._ast_cache[h] = a return a
def _abstract_internal(self, ctx, ast, split_on=None): h = self._z3_ast_hash(ctx, ast) try: return self._ast_cache[h] except KeyError: pass decl = z3.Z3_get_app_decl(ctx, ast) decl_num = z3.Z3_get_decl_kind(ctx, decl) z3_sort = z3.Z3_get_sort(ctx, ast) if decl_num not in z3_op_nums: raise ClaripyError("unknown decl kind %d" % decl_num) if z3_op_nums[decl_num] not in op_map: raise ClaripyError("unknown decl op %s" % z3_op_nums[decl_num]) op_name = op_map[z3_op_nums[decl_num]] num_args = z3.Z3_get_app_num_args(ctx, ast) split_on = self._split_on if split_on is None else split_on new_split_on = split_on if op_name in split_on else set() children = [ self._abstract_internal(ctx, z3.Z3_get_app_arg(ctx, ast, i), new_split_on) for i in range(num_args) ] append_children = True if op_name == 'True': return BoolI(True) elif op_name == 'False': return BoolI(False) elif op_name.startswith('RM_'): return RM.from_name(op_name) elif op_name == 'BitVecVal': bv_num = long(z3.Z3_get_numeral_string(ctx, ast)) bv_size = z3.Z3_get_bv_sort_size(ctx, z3_sort) return BVI(NativeBVV(bv_num, bv_size), length=bv_size) elif op_name == 'FPVal': # this is really imprecise fp_mantissa = float(z3.Z3_fpa_get_numeral_significand_string(ctx, ast)) fp_exp = long(z3.Z3_fpa_get_numeral_exponent_string(ctx, ast)) value = fp_mantissa * (2 ** fp_exp) ebits = z3.Z3_fpa_get_ebits(ctx, z3_sort) sbits = z3.Z3_fpa_get_sbits(ctx, z3_sort) sort = FSort.from_params(ebits, sbits) return FPI(NativeFPV(value, sort)) elif op_name in ('MinusZero', 'MinusInf', 'PlusZero', 'PlusInf', 'NaN'): ebits = z3.Z3_fpa_get_ebits(ctx, z3_sort) sbits = z3.Z3_fpa_get_sbits(ctx, z3_sort) sort = FSort.from_params(ebits, sbits) if op_name == 'MinusZero': return FPI(NativeFPV(-0.0, sort)) elif op_name == 'MinusInf': return FPI(NativeFPV(float('-inf'), sort)) elif op_name == 'PlusZero': return FPI(NativeFPV(0.0, sort)) elif op_name == 'PlusInf': return FPI(NativeFPV(float('inf'), sort)) elif op_name == 'NaN': return FPI(NativeFPV(float('nan'), sort)) elif op_name == 'UNINTERPRETED': # this *might* be a BitVec ;-) bv_name = z3.Z3_get_symbol_string(ctx, z3.Z3_get_decl_name(ctx, decl)) bv_size = z3.Z3_get_bv_sort_size(ctx, z3_sort) #if bv_name.count('_') < 2: # import ipdb; ipdb.set_trace() return BV("BitVec", (bv_name, bv_size), length=bv_size, variables={ bv_name }, symbolic=True) elif op_name == 'Extract': hi = z3.Z3_get_decl_int_parameter(ctx, decl, 0) lo = z3.Z3_get_decl_int_parameter(ctx, decl, 1) args = [ hi, lo ] elif op_name in ('SignExt', 'ZeroExt'): num = z3.Z3_get_decl_int_parameter(ctx, decl, 0) args = [ num ] elif op_name in ('fpToFP', 'fpToFPSigned'): exp = z3.Z3_fpa_get_ebits(ctx, z3_sort) mantissa = z3.Z3_fpa_get_sbits(ctx, z3_sort) sort = FSort.from_params(exp, mantissa) args = children + [sort] append_children = False elif op_name in ('fpToSBV', 'fpToUBV'): # uuuuuugggggghhhhhh bv_size = z3.Z3_get_bv_sort_size(ctx, z3_sort) args = children + [bv_size] append_children = False else: args = [ ] if append_children: args.extend(children) # fix up many-arg __add__ if op_name in bin_ops and len(args) > 2: many_args = args #pylint:disable=unused-variable last = args[-1] rest = args[:-1] a = args[0].make_like(op_name, rest[:2]) for b in rest[2:]: a = args[0].make_like(op_name, [a,b]) args = [ a, last ] # hmm.... honestly not sure what to do here result_ty = op_type_map[z3_op_nums[decl_num]] ty = type(args[-1]) if op_name == 'If': # If is polymorphic and thus must be handled specially ty = type(args[1]) a = ty('If', tuple(args), length=args[1].length) else: if hasattr(ty, op_name) or hasattr(_all_operations, op_name): op = getattr(ty if hasattr(ty, op_name) else _all_operations, op_name) if op.calc_length is not None: length = op.calc_length(*args) a = result_ty(op_name, tuple(args), length=length) else: a = result_ty(op_name, tuple(args)) else: a = result_ty(op_name, tuple(args)) self._ast_cache[h] = a return a