def get_pred(self): if self.is_ninf(): return copy.deepcopy(self) if self.is_pzero(): return Float('-0',ne=self.ne,ns=self.ns).get_pred() bv_str = self.get_bv_str() #print(bv_str) sign = bv_str[0] if sign == '0': succ = int(bv_str[1:],2) - 1 return Float(val=z3.simplify(z3.fpBVToFP(z3.Int2BV(z3.IntVal(succ),num_bits = self.ns + self.ne),z3.FPSort(self.ne,self.ns))),ne=self.ne, ns=self.ns) else: succ = int(bv_str[1:],2) + 1 return -Float(val=z3.simplify(z3.fpBVToFP(z3.Int2BV(z3.IntVal(succ),num_bits = self.ns + self.ne),z3.FPSort(self.ne,self.ns))),ne=self.ne, ns=self.ns)
def prepare(val, signext=False, size=SIZE) -> z3.BitVecRef: if z3.is_bv(val): szdiff = size - val.size() if szdiff > 0: if signext: result = z3.SignExt(szdiff, val) else: result = z3.ZeroExt(szdiff, val) elif szdiff < 0: result = z3.Extract(size - 1, 0, val) else: result = val elif type(val) == int: result = z3.BitVecVal(val, size) elif z3.is_int(val): result = z3.Int2BV(val, size) elif z3.is_fp(val): # changing up this logic to align with r2ghidra impl result = z3.fpToIEEEBV(val) #result = val else: result = z3.BitVecVal(val, size) #return z3.simplify(result) return result
def prepare(val, signext=False, size=SIZE) -> z3.BitVecRef: if z3.is_bv(val): szdiff = size-val.size() if szdiff == 0: result = val elif szdiff > 0: if signext: result = z3.SignExt(szdiff, val) else: result = z3.ZeroExt(szdiff, val) elif szdiff < 0: result = z3.Extract(size-1, 0, val) elif isinstance(val, int): result = z3.BitVecVal(val, size) elif z3.is_int(val): result = z3.Int2BV(val, size) elif z3.is_fp(val): result = z3.fpToIEEEBV(val) else: result = z3.BitVecVal(val, size) if not z3.is_bv_value(result): return z3.simplify(result) else: return result
def _binop_dunder_operation(self, op: str, op_callback, reflected=False, other: nodes.Const = None): other_defaults = other.defaults if isinstance(other, Z3Proxy) else {} left = self.value right = utilities.make_z3_const(utilities.strip_constant_node(other)) extras = [] if op in ("&", ">>", "<<"): # cast left and right to BitVector for bit operation. left, right = z3.Int2BV(left, 64), z3.Int2BV(right, 64) elif op in ("/", "//"): # special handling divide, due to we have "//" operation in py2 protocol, and # it's incompatible with z3 if op == "//": # convert result to floor. MANAGER.logger.warning( "Z3", "Floor division (//) is not supported and will cast to (/), for node: {}", repr(self)) extras.append(right != 0) op_callback = lambda x, y: x / y elif op == "%": # casting left and right to int before doing modulo if not z3.is_int(left): left = z3.ToInt(left) if not z3.is_int(right): right = z3.ToInt(right) extras.append(right != 0) try: if not reflected: result = op_callback(left, right) else: result = op_callback(right, left) res = inference.InferenceResult(Z3Proxy.init_expr( result, { **self.defaults, **other_defaults }), status=True) res.z3_assumptions |= set(extras) return res except (z3.Z3Exception, TypeError): return inference.InferenceResult.load_result(nodes.Uninferable())
def __cast_to_bits__(self, reference): if isinstance(reference, z3.ArithRef) or isinstance( reference, z3.IntNumRef): return z3.Int2BV(reference, self.longLength) elif isinstance(reference, z3.BoolRef): return z3.If(reference, 1, 0) else: return reference
def prepare(val): if z3.is_bv(val): #print(val) szdiff = SIZE - val.size() #print(szdiff, val.size()) if szdiff > 0: return z3.ZeroExt(szdiff, val) else: return val elif z3.is_int(val): return z3.Int2BV(val, SIZE) else: return z3.BitVecVal(val, SIZE)
def extend(value, width, signed=None): if not is_z3(value): return value # XXX range check if not z3.is_bv(value): value = z3.Int2BV(value, width) assert value.size() > 0 diff = try_simplify(width - value.size()) if diff > 0: if signed is None: # XXX default to unsigned signed = False if signed: return z3.SignExt(diff, value) else: return z3.ZeroExt(diff, value) return value
def val_to_register_bv(self, reg: Dict, val): new_val = val if isinstance(val, int): new_val = z3.BitVecVal(val, reg["size"]) elif z3.is_int(val): new_val = z3.Int2BV(val, reg["size"]) elif z3.is_bv(val): if val.size() > reg["size"]: new_val = z3.Extract(reg["size"] - 1, 0, val) elif val.size() < reg["size"]: new_val = z3.ZeroExt(reg["size"] - val.size(), val) else: raise ESILArgumentException("%s %s" % (reg, val)) return new_val
def proc_apply(self, expr, state): f = self.context.reduce(expr['func']) args = expr['args'] if f['what'] == 'expr:special': if f['id'] == 'gmap_lookup': state, k = self.proc(args[0], state) state, m = self.proc(args[1], state) return state, m[k] elif f['id'] == 'map_insert': state, k = self.proc(args[0], state) state, v = self.proc(args[1], state) state, m = self.proc(args[2], state) rangesort = m.range() vsome = constructor_by_name(rangesort, "Some")(v) return state, z3.Store(m, k, vsome) elif f['id'] == 'len_buf': state, buf = self.proc(args[0], state) return state, z3.Int2BV(z3.Length(buf), 64) elif f['id'] == 'resize_buf': state, newlen = self.proc(args[0], state) state, buf = self.proc(args[1], state) ## XXX should be of length newlen, not empty.. return state, z3.Empty(buf.sort()) elif f['id'] == 'uint64_gt': state, a0 = self.proc(args[0], state) state, a1 = self.proc(args[1], state) return state, z3.If(a0 > a1, self.bool_sort.constructor(0)(), self.bool_sort.constructor(1)()) elif f['id'] == 'eqDec_time': state, a0 = self.proc(args[0], state) state, a1 = self.proc(args[1], state) return state, z3.If(a0 == a1, self.sumbool_sort.constructor(0)(), self.sumbool_sort.constructor(1)()) else: raise Exception('unknown special function', f['id']) else: print expr raise Exception('unknown apply on', f['what'])
def opcode_exp(opcode_data1, opcode_data2): if not is_z3_express(opcode_data1) and not is_z3_express(opcode_data2): op1 = format_to_int(opcode_data1) op2 = format_to_int(opcode_data2) result = op1**op2 return z3.BitVecVal(result, 256) size = 0 if is_z3_express( opcode_data1) or opcode_data1.__class__ == z3.z3.BitVecNumRef: size = opcode_data1.size() opcode_data1 = z3.BV2Int(opcode_data1) if is_z3_express( opcode_data2) or opcode_data1.__class__ == z3.z3.BitVecNumRef: if opcode_data2.size() > size: size = opcode_data2.size() opcode_data2 = z3.BV2Int(opcode_data2) return (z3.simplify(z3.Int2BV(opcode_data1**opcode_data2, size)))
def val_to_register_bv(self, reg: Dict, val): new_val = val if type(val) == int: new_val = z3.BitVecVal(val, reg["size"]) elif z3.is_int(val): new_val = z3.Int2BV(val, reg["size"]) elif z3.is_bv(val): if val.size() > reg["size"]: new_val = z3.Extract(reg["size"] - 1, 0, val) elif val.size() < reg["size"]: new_val = z3.ZeroExt(reg["size"] - val.size(), val) else: new_reg = val else: raise ESILArgumentException return new_val
def cast(self, value, is_type, to_type): if is_type is Types.STRING and isinstance(to_type, z3.z3.DatatypeSortRef): # the value is a string and it should be cast to a datatyperef # (i.e. an enum-type), just return the value because we can deal with it return value value_is_int = isinstance(value, int) value_is_float = isinstance(value, float) if is_type is to_type: # already correct type, just return the value return value """ INT <---> INTEGER """ elif is_type is Types.INT and to_type is Types.INTEGER: if value_is_int or value_is_float: return value # this happens if it is an int numeral (e.g. 2) else: return z3.BV2Int(value) elif is_type is Types.INTEGER and to_type is Types.INT: if value_is_int or value_is_float: return value else: return z3.Int2BV(value, 32) """ INT <---> FLOAT """ elif is_type is Types.FLOAT and to_type is Types.INT: if value_is_float: return value # this happens if it is a float numeral (e.g. 3.14) else: return z3.fpToSBV(z3.RNE(), value, z3.BitVecSort(32)) elif is_type is Types.INT and to_type is Types.FLOAT: if value_is_int: return value else: return z3.fpSignedToFP(z3.RNE(), value, z3.Float32()) """ INTEGER <---> FLOAT """ elif is_type is Types.FLOAT and to_type is Types.INTEGER: if value_is_float: return value # this happens if it is a float numeral (e.g. 3.14) else: return self.cast(self.cast(value, Types.FLOAT, Types.INT), Types.INT, Types.INTEGER) elif is_type is Types.INTEGER and to_type is Types.FLOAT: if value_is_int: return value else: return self.cast(self.cast(value, Types.INTEGER, Types.INT), Types.INT, Types.FLOAT) """ from REAL """ elif is_type is Types.REAL and to_type is Types.INTEGER: if value_is_float: return value else: return z3.ToInt(value) elif is_type is Types.REAL and to_type is Types.INT: return self.cast(self.cast(value, Types.REAL, Types.INTEGER), Types.INTEGER, Types.INT) elif is_type is Types.REAL and to_type is Types.FLOAT: """ Rounding modes: probably should make these parameterizable! roundNearestTiesToEven ... RNE() = default roundNearestTiesToAway ... RNA() roundTowardPositive ...... RTP() roundTowardNegative ...... RTN() roundTowardZero .......... RTZ() """ if value_is_int or value_is_float: # int numeral return value else: return z3.fpRealToFP(z3.RNE(), value, z3.Float32()) """ to REAL """ elif is_type is Types.INT and to_type is Types.REAL: if value_is_int or value_is_float: # int numeral return value else: return z3.ToReal(self.cast(value, Types.INT, Types.INTEGER)) elif is_type is Types.INTEGER and to_type is Types.REAL: if value_is_int or value_is_float: # int numeral return value else: return z3.ToReal(value) elif is_type is Types.FLOAT and to_type is Types.REAL: if value_is_int or value_is_float: return value # this happens if it is a float numeral (e.g. 3.14) else: return z3.fpToReal(value) """ FROM BOOL conversions """ elif is_type is Types.BOOL and to_type is Types.INT: return z3.If(value, z3.BitVecVal(1, 32), z3.BitVecVal(0, 32)) elif is_type is Types.BOOL and to_type is Types.INTEGER: return z3.If(value, 1, 0) elif is_type is Types.BOOL and to_type is Types.REAL: return z3.If(value, 1.0, 0.0) elif is_type is Types.BOOL and to_type is Types.FLOAT: return z3.If(value, z3.FPVal(1.0, z3.Float32()), z3.FPVal(0.0, z3.Float32())) """ TO BOOL conversions """ elif is_type is Types.INT and to_type is Types.BOOL: return value == 1 elif is_type is Types.INTEGER and to_type is Types.BOOL: return value == 1 elif is_type is Types.REAL and to_type is Types.BOOL: return value == 1 elif is_type is Types.FLOAT and to_type is Types.BOOL: return value == 1 raise TypeError(f"Don't know how to cast from {is_type} to {to_type}!")
def proc_apply(self, expr, state): f = self.context.reduce(expr['func']) args = expr['args'] if f['what'] == 'expr:special': # for converting Z to u32 if f['id'] == 'u3' or f['id'] == 'u2': arg = args[0] # be able to distinguish between Z->u32 and Z->u64 if f['id'] == 'u3': arg['name'] = 'u32' else: arg['name'] = 'u64' state, val = self.proc(arg, state) return state, z3.Const(anon(), val) elif f['id'] == 'gtb': arg0 = args[0]['cases'][0]['body']['args'][0] nstate, arg1 = self.proc( args[1]['cases'][0]['body']['args'][0], state) return nstate, z3.If(arg0 > arg1, self.bool_sort.constructor(0)(), self.bool_sort.constructor(1)()) elif f['id'] == 'gmap_lookup': state, k = self.proc(args[0], state) state, m = self.proc(args[1], state) return state, m[k] elif f['id'] == 'map_insert': state, k = self.proc(args[0], state) state, v = self.proc(args[1], state) state, m = self.proc(args[2], state) rangesort = m.range() vsome = constructor_by_name(rangesort, "Some")(v) return state, z3.Store(m, k, vsome) elif f['id'] == 'reads': return state, state elif f['id'] == 'modify': _, newstate = self.proc(args[0]['body'], state) return newstate, self.unit_tt elif f['id'] == 'ret': state, res = self.proc(args[0], state) return state, res elif f['id'] == 'len_buf': state, buf = self.proc(args[0], state) return state, z3.Int2BV(z3.Length(buf), 64) elif f['id'] == 'resize_buf': state, newlen = self.proc(args[0], state) state, buf = self.proc(args[1], state) ## XXX should be of length newlen, not empty.. return state, z3.Empty(buf.sort()) elif f['id'] == 'eqDec_time': state, a0 = self.proc(args[0], state) state, a1 = self.proc(args[1], state) return state, z3.If(a0 == a1, self.sumbool_sort.constructor(0)(), self.sumbool_sort.constructor(1)()) elif f['id'] == 'time_ge': state, a0 = self.proc(args[0], state) state, a1 = self.proc(args[1], state) # constructor 0 is true, 1 is false return state, z3.If(a0 >= a1, self.bool_sort.constructor(0)(), self.bool_sort.constructor(1)()) elif f['id'] == 'symAssert': state, a = self.proc(args[0], state) return state, z3.And(a == self.bool_sort.constructor(0)()) else: raise Exception('unknown special function', f['id']) else: raise Exception('unknown apply on', f['what'])
def _cmp(cmp, a, b, **kwargs): [a, b, width, signed] = match_types(a, b) a = z3.BV2Int(a, is_signed=signed) b = z3.BV2Int(b, is_signed=signed) return z3.Int2BV(z3.If(cmp(a, b), a, b), width)
def _mk_pzero(self): self.__dict__ = copy.deepcopy(Float(val=z3.simplify(z3.fpBVToFP(z3.Int2BV(z3.IntVal(0),num_bits = self.ns + self.ne),z3.FPSort(self.ne,self.ns))),ne=self.ne, ns=self.ns).__dict__)
def _mk_nan(self): bv = '0' + ('1' * self.ne) + ('1' * (self.ns -1)) val = int(bv,2) self.__dict__ = copy.deepcopy(Float(val=z3.simplify(z3.fpBVToFP(z3.Int2BV(z3.IntVal(val),num_bits = self.ns + self.ne),z3.FPSort(self.ne,self.ns))),ne=self.ne, ns=self.ns).__dict__)
def interp(tree, lookup, z3_mode): """Evaluate the arithmetic expression. Pass a tree as a Lark `Tree` object for the parsed expression. For `lookup`, provide a function for mapping variable names to values. """ op = tree.data if op in ('add', 'sub', 'mul', 'div', 'shl', 'shr'): # Binary operators. lhs = interp(tree.children[0], lookup, z3_mode) rhs = interp(tree.children[1], lookup, z3_mode) if op == 'add': return lhs + rhs elif op == 'sub': return lhs - rhs elif op == 'mul': return lhs * rhs elif op == 'div': return lhs / rhs elif op == 'shl': return lhs << rhs elif op == 'shr': return lhs >> rhs elif op == 'neg': # Negation. sub = interp(tree.children[0], lookup, z3_mode) return -sub elif op == 'int': # Literal number. if z3_mode: return z3.BitVecVal(int(tree.children[0]), 32) else: return int(tree.children[0]) elif op == 'float': # Literal number. if z3_mode: return z3.BitVecVal(float(tree.children[0]), 32) else: return float(tree.children[0]) elif op == 'var': # Variable lookup. return lookup(tree.children[0]) elif op == 'if': # Conditional. cond = interp(tree.children[0], lookup, z3_mode) true = interp(tree.children[1], lookup, z3_mode) false = interp(tree.children[2], lookup, z3_mode) return (cond != 0) * true + (cond == 0) * false elif op == "intcast": child = interp(tree.children[0], lookup, z3_mode) if z3_mode: return z3.BV2Int(child) else: return int(child) elif op == "floatcast": child = interp(tree.children[0], lookup, z3_mode) if z3_mode: return z3.fpBVToFP(child, z3.Float32()) else: return float(child) elif op == "int2bv": child = interp(tree.children[0], lookup, z3_mode) if z3_mode: return z3.Int2BV(child, 32) else: return child elif op == "float2bv": child = interp(tree.children[0], lookup, z3_mode) if z3_mode: return z3.fpToIEEEBV(child) else: return child