def simp_cond_int(expr_simp, expr): if (expr.cond.is_op(TOK_EQUAL) and expr.cond.args[1].is_int() and expr.cond.args[0].is_compose() and len(expr.cond.args[0].args) == 2 and expr.cond.args[0].args[1].is_int(0)): # ({X, 0} == int) => X == int[:] src = expr.cond.args[0].args[0] int_val = int(expr.cond.args[1]) new_int = ExprInt(int_val, src.size) expr = expr_simp( ExprCond(ExprOp(TOK_EQUAL, src, new_int), expr.src1, expr.src2)) elif (expr.cond.is_op() and expr.cond.op in [ TOK_EQUAL, TOK_INF_SIGNED, TOK_INF_EQUAL_SIGNED, TOK_INF_UNSIGNED, TOK_INF_EQUAL_UNSIGNED ] and expr.cond.args[1].is_int() and expr.cond.args[0].is_op("+") and expr.cond.args[0].args[-1].is_int()): # X + int1 == int2 => X == int2-int1 left, right = expr.cond.args left, int_diff = left.args[:-1], left.args[-1] if len(left) == 1: left = left[0] else: left = ExprOp('+', *left) new_int = expr_simp(right - int_diff) expr = expr_simp( ExprCond(ExprOp(expr.cond.op, left, new_int), expr.src1, expr.src2)) return expr
def simp_cond(_, expr): """ Common simplifications on ExprCond. Eval exprcond src1/src2 with satifiable/unsatisfiable condition propagation """ if (not expr.cond.is_int()) and expr.cond.size == 1: src1 = expr.src1.replace_expr({expr.cond: ExprInt(1, 1)}) src2 = expr.src2.replace_expr({expr.cond: ExprInt(0, 1)}) if src1 != expr.src1 or src2 != expr.src2: return ExprCond(expr.cond, src1, src2) # -A ? B:C => A ? B:C if expr.cond.is_op('-') and len(expr.cond.args) == 1: expr = ExprCond(expr.cond.args[0], expr.src1, expr.src2) # a?x:x elif expr.src1 == expr.src2: expr = expr.src1 # int ? A:B => A or B elif expr.cond.is_int(): if expr.cond.arg == 0: expr = expr.src2 else: expr = expr.src1 # a?(a?b:c):x => a?b:x elif expr.src1.is_cond() and expr.cond == expr.src1.cond: expr = ExprCond(expr.cond, expr.src1.src1, expr.src2) # a?x:(a?b:c) => a?x:c elif expr.src2.is_cond() and expr.cond == expr.src2.cond: expr = ExprCond(expr.cond, expr.src1, expr.src2.src2) # a|int ? b:c => b with int != 0 elif (expr.cond.is_op('|') and expr.cond.args[1].is_int() and expr.cond.args[1].arg != 0): return expr.src1 # (C?int1:int2)?(A:B) => elif (expr.cond.is_cond() and expr.cond.src1.is_int() and expr.cond.src2.is_int()): int1 = expr.cond.src1.arg.arg int2 = expr.cond.src2.arg.arg if int1 and int2: expr = expr.src1 elif int1 == 0 and int2 == 0: expr = expr.src2 elif int1 == 0 and int2: expr = ExprCond(expr.cond.cond, expr.src2, expr.src1) elif int1 and int2 == 0: expr = ExprCond(expr.cond.cond, expr.src1, expr.src2) elif expr.cond.is_compose(): # {0, X, 0}?(A:B) => X?(A:B) args = [arg for arg in expr.cond.args if not arg.is_int(0)] if len(args) == 1: arg = args.pop() return ExprCond(arg, expr.src1, expr.src2) elif len(args) < len(expr.cond.args): return ExprCond(ExprCompose(*args), expr.src1, expr.src2) return expr
def eval_exprcond(self, expr, **kwargs): """[DEV]: Evaluate an ExprCond using the current state""" cond = self.eval_expr_visitor(expr.cond, **kwargs) src1 = self.eval_expr_visitor(expr.src1, **kwargs) src2 = self.eval_expr_visitor(expr.src2, **kwargs) ret = ExprCond(cond, src1, src2) return ret
def simp_cond_op_int(e_s, expr): "Extract conditions from operations" # x?a:b + x?c:d + e => x?(a+c+e:b+d+e) if not expr.op in ["+", "|", "^", "&", "*", '<<', '>>', 'a>>']: return expr if len(expr.args) < 2: return expr conds = set() for arg in expr.args: if arg.is_cond(): conds.add(arg) if len(conds) != 1: return expr cond = list(conds).pop() args1, args2 = [], [] for arg in expr.args: if arg.is_cond(): args1.append(arg.src1) args2.append(arg.src2) else: args1.append(arg) args2.append(arg) return ExprCond(cond.cond, ExprOp(expr.op, *args1), ExprOp(expr.op, *args2))
def simp_cond_logic_ext(expr_s, expr): """(X.zeroExt() + ... + Int) ? A:B => X + ... + int[:] ? A:B""" cond = expr.cond if not cond.is_op(): return expr if cond.op not in ["&", "^", "|"]: return expr is_ok = True sizes = set() for arg in cond.args: if arg.is_int(): continue if (arg.is_op() and arg.op.startswith("zeroExt")): sizes.add(arg.args[0].size) continue is_ok = False break if not is_ok: return expr if len(sizes) != 1: return expr size = list(sizes)[0] args = [expr_s(arg[:size]) for arg in cond.args] cond = ExprOp(cond.op, *args) return ExprCond(cond, expr.src1, expr.src2)
def csinc(ir, instr, arg1, arg2, arg3, arg4): e = [] cond_expr = cond2expr[arg4.name] e.append( ExprAssign(arg1, ExprCond(cond_expr, arg2, arg3 + ExprInt(1, arg3.size)))) return e, []
def simp_cond_factor(e_s, expr): "Merge similar conditions" if not expr.op in ["+", "|", "^", "&", "*", '<<', '>>', 'a>>']: return expr if len(expr.args) < 2: return expr conds = {} not_conds = [] multi_cond = False for arg in expr.args: if not arg.is_cond(): not_conds.append(arg) continue cond = arg.cond if not cond in conds: conds[cond] = [] else: multi_cond = True conds[cond].append(arg) if not multi_cond: return expr c_out = not_conds[:] for cond, vals in conds.items(): new_src1 = [x.src1 for x in vals] new_src2 = [x.src2 for x in vals] src1 = e_s.expr_simp_wrapper(ExprOp(expr.op, *new_src1)) src2 = e_s.expr_simp_wrapper(ExprOp(expr.op, *new_src2)) c_out.append(ExprCond(cond, src1, src2)) if len(c_out) == 1: new_e = c_out[0] else: new_e = ExprOp(expr.op, *c_out) return new_e
def sbvck3(ir, instr, r0, rn, rm): """SBVCK3 - Check substraction overflow""" # if(Overflow(Rn-Rm)) R0<-1 else R0<-0 (Signed) # Substract registers reg_sub = ExprOp("+", rn, rm) # Get the register storing the highest value max_rn_rm = ExprCond(ExprOp(">", rn, rm), rn, rm) # Check for an overflow overflow_test = ExprOp(">", reg_sub, max_rn_rm) # Return the result condition = ExprCond(overflow_test, ExprInt(1, 32), ExprInt(0, 32)) return [ExprAff(r0, condition)], []
def cset(ir, instr, arg1, arg2): e = [] cond_expr = cond2expr[arg2.name] e.append( ExprAssign( arg1, ExprCond(cond_expr, ExprInt(1, arg1.size), ExprInt(0, arg1.size)))) return e, []
def simp_mem(e_s, expr): "Common simplifications on ExprMem" # @32[x?a:b] => x?@32[a]:@32[b] if expr.arg.is_cond(): cond = expr.arg ret = ExprCond(cond.cond, ExprMem(cond.src1, expr.size), ExprMem(cond.src2, expr.size)) return ret return expr
def simp_cond_eq_zero(_, expr): """(X == 0)?(A:B) => X?(B:A)""" cond = expr.cond if not cond.is_op(TOK_EQUAL): return expr arg1, arg2 = cond.args if not arg2.is_int(0): return expr new_expr = ExprCond(arg1, expr.src2, expr.src1) return new_expr
def eval_exprcond(self, expr, **kwargs): """[DEV]: Evaluate an ExprCond using the current state""" cond = self.eval_expr_visitor(expr.cond, **kwargs) src1 = self.eval_expr_visitor(expr.src1, **kwargs) src2 = self.eval_expr_visitor(expr.src2, **kwargs) if cond.is_id(TOPSTR) or src1.is_id(TOPSTR) or src2.is_id(TOPSTR): ret = exprid_top(expr) else: ret = ExprCond(cond, src1, src2) return ret
def test_bgei(self): """Test BGEI execution""" # BGEI Rn,imm4,disp17.align2 exec_instruction( "BGEI R1, 0x5, 0x10000", [(ExprId("R1", 32), ExprInt(0x10, 32))], [(ExprId("PC", 32), ExprCond(ExprOp(">=", ExprInt(0x10, 32), ExprInt(0x5, 32)), ExprInt(0xFFFF0010, 32), ExprInt(0x14, 32)))], offset=0x10)
def categorize(self, node, lvl=0, **kwargs): """Recursively apply rules to @node @node: ExprNode to analyze @lvl: actual recusion level """ expr = node.expr log_reduce.debug("\t" * lvl + "Reduce...: %s", node.expr) if isinstance(expr, ExprId): node = ExprNodeId(expr) elif isinstance(expr, ExprInt): node = ExprNodeInt(expr) elif isinstance(expr, ExprLoc): node = ExprNodeLoc(expr) elif isinstance(expr, ExprMem): arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs) node = ExprNodeMem(ExprMem(arg.expr, expr.size)) node.arg = arg elif isinstance(expr, ExprSlice): arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs) node = ExprNodeSlice(ExprSlice(arg.expr, expr.start, expr.stop)) node.arg = arg elif isinstance(expr, ExprOp): new_args = [] for arg in node.args: new_a = self.categorize(arg, lvl=lvl + 1, **kwargs) assert new_a.expr.size == arg.expr.size new_args.append(new_a) node = ExprNodeOp(ExprOp(expr.op, *[x.expr for x in new_args])) node.args = new_args expr = node.expr elif isinstance(expr, ExprCompose): new_args = [] new_expr_args = [] for arg in node.args: arg = self.categorize(arg, lvl=lvl + 1, **kwargs) new_args.append(arg) new_expr_args.append(arg.expr) new_expr = ExprCompose(*new_expr_args) node = ExprNodeCompose(new_expr) node.args = new_args elif isinstance(expr, ExprCond): cond = self.categorize(node.cond, lvl=lvl + 1, **kwargs) src1 = self.categorize(node.src1, lvl=lvl + 1, **kwargs) src2 = self.categorize(node.src2, lvl=lvl + 1, **kwargs) node = ExprNodeCond(ExprCond(cond.expr, src1.expr, src2.expr)) node.cond, node.src1, node.src2 = cond, src1, src2 else: raise TypeError("Unknown Expr Type %r", type(expr)) node.info = self.apply_rules(node, lvl=lvl, **kwargs) log_reduce.debug("\t" * lvl + "Reduce result: %s %r", node.expr, node.info) return node
def ccmp(ir, instr, arg1, arg2, arg3, arg4): e = [] if (arg2.is_int()): arg2 = ExprInt(arg2.arg.arg, arg1.size) default_nf = arg3[0:1] default_zf = arg3[1:2] default_cf = arg3[2:3] default_of = arg3[3:4] cond_expr = cond2expr[arg4.name] res = arg1 - arg2 new_nf = nf new_zf = update_flag_zf(res)[0].src new_cf = update_flag_sub_cf(arg1, arg2)[0].src new_of = update_flag_sub_of(arg1, arg2)[0].src e.append(ExprAssign(nf, ExprCond(cond_expr, new_nf, default_nf))) e.append(ExprAssign(zf, ExprCond(cond_expr, new_zf, default_zf))) e.append(ExprAssign(cf, ExprCond(cond_expr, new_cf, default_cf))) e.append(ExprAssign(of, ExprCond(cond_expr, new_of, default_of))) return e, []
def simp_cond_zeroext(_, expr): """ X.zeroExt()?(A:B) => X ? A:B X.signExt()?(A:B) => X ? A:B """ if not (expr.cond.is_op() and (expr.cond.op.startswith("zeroExt") or expr.cond.op.startswith("signExt"))): return expr ret = ExprCond(expr.cond.args[0], expr.src1, expr.src2) return ret
def simp_mem(_, expr): """ Common simplifications on ExprMem: @32[x?a:b] => x?@32[a]:@32[b] """ if expr.ptr.is_cond(): cond = expr.ptr ret = ExprCond(cond.cond, ExprMem(cond.src1, expr.size), ExprMem(cond.src2, expr.size)) return ret return expr
def simp_cmp_int_arg(_, expr): """ (0x10 <= R0) ? A:B => (R0 < 0x10) ? B:A """ cond = expr.cond if not cond.is_op(): return expr op = cond.op if op not in [ TOK_EQUAL, TOK_INF_SIGNED, TOK_INF_EQUAL_SIGNED, TOK_INF_UNSIGNED, TOK_INF_EQUAL_UNSIGNED ]: return expr arg1, arg2 = cond.args if arg2.is_int(): return expr if not arg1.is_int(): return expr src1, src2 = expr.src1, expr.src2 if op == TOK_EQUAL: return ExprCond(ExprOp(TOK_EQUAL, arg2, arg1), src1, src2) arg1, arg2 = arg2, arg1 src1, src2 = src2, src1 if op == TOK_INF_SIGNED: op = TOK_INF_EQUAL_SIGNED elif op == TOK_INF_EQUAL_SIGNED: op = TOK_INF_SIGNED elif op == TOK_INF_UNSIGNED: op = TOK_INF_EQUAL_UNSIGNED elif op == TOK_INF_EQUAL_UNSIGNED: op = TOK_INF_UNSIGNED return ExprCond(ExprOp(op, arg1, arg2), src1, src2)
def test_div(self): """Test DIV execution""" # DIV Rn,Rm exec_instruction("DIV R0, R1", [(ExprId("R0", 32), ExprInt(0x80, 32)), (ExprId("R1", 32), ExprInt(0x0, 32)), (ExprId("HI", 32), ExprInt(0, 32)), (ExprId("LO", 32), ExprInt(0, 32))], [(ExprId("HI", 32), ExprInt(0, 32)), (ExprId("LO", 32), ExprInt(0, 32)), (ExprId("exception_flags", 32), ExprInt(EXCEPT_DIV_BY_ZERO, 32))]) # Negative numbers exec_instruction("DIV R0, R1", [(ExprId("R0", 32), ExprInt(-4, 32)), (ExprId("R1", 32), ExprInt(-2, 32))], [(ExprId("HI", 32), ExprInt(0, 32)), (ExprId("LO", 32), ExprInt(2, 32))]) exec_instruction("DIV R0, R1", [(ExprId("R0", 32), ExprInt(-5, 32)), (ExprId("R1", 32), ExprInt(-2, 32))], [(ExprId("HI", 32), ExprInt(1, 32)), (ExprId("LO", 32), ExprInt(2, 32))]) # Positive numbers exec_instruction("DIV R0, R1", [(ExprId("R0", 32), ExprInt(4, 32)), (ExprId("R1", 32), ExprInt(2, 32))], [(ExprId("HI", 32), ExprCond(ExprOp("==", ExprInt(0, 32), ExprInt(0x80000000, 32)), ExprInt(0, 32), ExprInt(0xFFFFFFFC, 32))), (ExprId("LO", 32), ExprCond(ExprOp("==", ExprInt(0, 32), ExprInt(0x80000000, 32)), ExprInt(2, 32), ExprInt(0, 32)))]) # Negative & positive numbers exec_instruction("DIV R0, R1", [(ExprId("R0", 32), ExprInt(-5, 32)), (ExprId("R1", 32), ExprInt(2, 32))], [(ExprId("HI", 32), ExprCond(ExprOp("==", ExprInt(0, 32), ExprInt(0x80000000, 32)), ExprInt(1, 32), ExprInt(0xFFFFFFFF, 32))), (ExprId("LO", 32), ExprCond(ExprOp("==", ExprInt(0, 32), ExprInt(0x80000000, 32)), ExprInt(0x7FFFFFFD, 32), ExprInt(0xFFFFFFFE, 32)))]) exec_instruction("DIV R0, R1", [(ExprId("R0", 32), ExprInt(5, 32)), (ExprId("R1", 32), ExprInt(-2, 32))], [(ExprId("HI", 32), ExprCond(ExprOp("==", ExprInt(0, 32), ExprInt(0x80000000, 32)), ExprInt(5, 32), ExprInt(0xFFFFFFFF, 32))), (ExprId("LO", 32), ExprCond(ExprOp("==", ExprInt(0, 32), ExprInt(0x80000000, 32)), ExprInt(0, 32), ExprInt(0xFFFFFFFE, 32)))])
def simp_compose(e_s, expr): "Commons simplification on ExprCompose" args = merge_sliceto_slice(expr) out = [] # compose of compose for arg in args: if arg.is_compose(): out += arg.args else: out.append(arg) args = out # Compose(a) with a.size = compose.size => a if len(args) == 1 and args[0].size == expr.size: return args[0] # {(X[z:], 0, X.size-z), (0, X.size-z, X.size)} => (X >> z) if len(args) == 2 and args[1].is_int(0): if (args[0].is_slice() and args[0].stop == args[0].arg.size and args[0].size + args[1].size == args[0].arg.size): new_expr = args[0].arg >> ExprInt(args[0].start, args[0].arg.size) return new_expr # {@X[base + i] 0 X, @Y[base + i + X] X (X + Y)} => @(X+Y)[base + i] for i, arg in enumerate(args[:-1]): nxt = args[i + 1] if arg.is_mem() and nxt.is_mem(): gap = e_s(nxt.arg - arg.arg) if gap.is_int() and arg.size % 8 == 0 and int(gap) == arg.size / 8: args = args[:i] + [ExprMem(arg.arg, arg.size + nxt.size)] + args[i + 2:] return ExprCompose(*args) # {a, x?b:d, x?c:e, f} => x?{a, b, c, f}:{a, d, e, f} conds = set(arg.cond for arg in expr.args if arg.is_cond()) if len(conds) == 1: cond = list(conds)[0] args1, args2 = [], [] for arg in expr.args: if arg.is_cond(): args1.append(arg.src1) args2.append(arg.src2) else: args1.append(arg) args2.append(arg) arg1 = e_s(ExprCompose(*args1)) arg2 = e_s(ExprCompose(*args2)) return ExprCond(cond, arg1, arg2) return ExprCompose(*args)
def simp_cond_sign_bit(_, expr): """(a & .. & 0x80000000) ? A:B => (a & ...) <s 0 ? A:B""" cond = expr.cond if not cond.is_op('&'): return expr last = cond.args[-1] if not last.is_int(1 << (last.size - 1)): return expr zero = ExprInt(0, expr.cond.size) if len(cond.args) == 2: args = [cond.args[0], zero] else: args = [ExprOp('&', *list(cond.args[:-1])), zero] cond = ExprOp(TOK_INF_SIGNED, *args) return ExprCond(cond, expr.src1, expr.src2)
def simp_ext(_, expr): if expr.op.startswith('zeroExt_'): arg = expr.args[0] if expr.size == arg.size: return arg return ExprCompose(arg, ExprInt(0, expr.size - arg.size)) if expr.op.startswith("signExt_"): arg = expr.args[0] add_size = expr.size - arg.size new_expr = ExprCompose( arg, ExprCond(arg.msb(), ExprInt(size2mask(add_size), add_size), ExprInt(0, add_size))) return new_expr return expr
def call_effects(self, ad, instr): call_assignblk = AssignBlock( [ ExprAff( self.ret_reg, ExprOp( 'call_func_ret', ad, self.arch.regs.R0, self.arch.regs.R1, self.arch.regs.R2, self.arch.regs.R3, ) ), ExprAff( self.sp, ExprOp('call_func_stack', ad, self.sp) ), ], instr ) cond = instr.additional_info.cond if cond == 14: # COND_ALWAYS: return [call_assignblk], [] # Call is a conditional instruction cond = tab_cond[cond] loc_next = self.get_next_loc_key(instr) loc_next_expr = ExprLoc(loc_next, 32) loc_do = self.loc_db.add_location() loc_do_expr = ExprLoc(loc_do, 32) dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr) call_assignblks = [ call_assignblk, AssignBlock([ExprAff(self.IRDst, loc_next_expr)], instr), ] e_do = IRBlock(loc_do, call_assignblks) assignblks_out = [ AssignBlock([ExprAff(self.IRDst, dst_cond)], instr) ] return assignblks_out, [e_do]
def div(rn, rm): """DIV - Signed division""" # LO <- Rn / Rm, HI <- Rn % Rm (Signed) # Mask sign bits sign_mask = i32(0x80000000) sign_rn = rn & sign_mask sign_rm = rm & sign_mask # Check if both numbers are positive or negative are_both_neg = sign_rn & sign_rm are_both_pos = ExprCond( are_both_neg - sign_mask, ExprInt(0, are_both_neg.size), ExprInt(1, are_both_neg.size) ) # Invert both numbers rn_inv = ~rn + i32(1) rm_inv = ~rm + i32(1) # Used to delay the arithmetic computations tmp_rm = rm if rm else i32(1) tmp_rm_inv = rm_inv if rm_inv else i32(1) # Results if only rn, or rm is negative LO_rn_neg = (~(rn_inv / tmp_rm) + i32(1)) if sign_rn else (~(rn / tmp_rm_inv) + i32(1)) HI_rn_neg = (~(rn_inv % tmp_rm) + i32(1)) if sign_rn else (~(rn % tmp_rm_inv) + i32(1)) # Results if both numbers are positive LO_pos = rn / tmp_rm if are_both_pos else LO_rn_neg HI_pos = rn % tmp_rm if are_both_pos else HI_rn_neg # Results if both numbers are negative LO_neg = rn_inv / tmp_rm_inv if are_both_neg else LO_pos HI_neg = rn_inv % tmp_rm_inv if are_both_neg else HI_pos # Results if rm is equal to zero LO = LO_neg if rm else LO HI = HI_neg if rm else HI exception_flags = i32(0) if rm else i32(EXCEPT_DIV_BY_ZERO)
def simp_cond_factor(e_s, expr): "Merge similar conditions" if not expr.op in ["+", "|", "^", "&", "*", '<<', '>>', 'a>>']: return expr if len(expr.args) < 2: return expr if expr.op in ['>>', '<<', 'a>>']: assert len(expr.args) == 2 # Note: the following code is correct for non-commutative operation only if # there is 2 arguments. Otherwise, the order is not conserved # Regroup sub-expression by similar conditions conds = {} not_conds = [] multi_cond = False for arg in expr.args: if not arg.is_cond(): not_conds.append(arg) continue cond = arg.cond if not cond in conds: conds[cond] = [] else: multi_cond = True conds[cond].append(arg) if not multi_cond: return expr # Rebuild the new expression c_out = not_conds for cond, vals in conds.items(): new_src1 = [x.src1 for x in vals] new_src2 = [x.src2 for x in vals] src1 = e_s.expr_simp_wrapper(ExprOp(expr.op, *new_src1)) src2 = e_s.expr_simp_wrapper(ExprOp(expr.op, *new_src2)) c_out.append(ExprCond(cond, src1, src2)) if len(c_out) == 1: new_e = c_out[0] else: new_e = ExprOp(expr.op, *c_out) return new_e
def simp_x_and_cst_eq_cst(_, expr): """ (x & ... & onebitmask == onebitmask) ? A:B => (x & ... & onebitmask) ? A:B """ cond = expr.cond if not cond.is_op(TOK_EQUAL): return expr arg1, mask2 = cond.args if not mask2.is_int(): return expr if not test_one_bit_set(int(mask2)): return expr if not arg1.is_op('&'): return expr mask1 = arg1.args[-1] if mask1 != mask2: return expr cond = ExprOp('&', *arg1.args) return ExprCond(cond, expr.src1, expr.src2)
def simp_cond_add(expr_s, expr): """ (a+b)?X:Y => (a == b)?Y:X (a^b)?X:Y => (a == b)?Y:X """ cond = expr.cond if not cond.is_op(): return expr if cond.op not in ['+', '^']: return expr if len(cond.args) != 2: return expr arg1, arg2 = cond.args if cond.is_op('+'): new_cond = ExprOp('==', arg1, expr_s(-arg2)) elif cond.is_op('^'): new_cond = ExprOp('==', arg1, arg2) else: raise ValueError('Bad case') return ExprCond(new_cond, expr.src2, expr.src1)
def simp_cond(e_s, expr): "Common simplifications on ExprCond" # eval exprcond src1/src2 with satifiable/unsatisfiable condition # propagation if (not expr.cond.is_int()) and expr.cond.size == 1: src1 = expr.src1.replace_expr({expr.cond: ExprInt(1, 1)}) src2 = expr.src2.replace_expr({expr.cond: ExprInt(0, 1)}) if src1 != expr.src1 or src2 != expr.src2: return ExprCond(expr.cond, src1, src2) # -A ? B:C => A ? B:C if expr.cond.is_op('-') and len(expr.cond.args) == 1: expr = ExprCond(expr.cond.args[0], expr.src1, expr.src2) # a?x:x elif expr.src1 == expr.src2: expr = expr.src1 # int ? A:B => A or B elif expr.cond.is_int(): if expr.cond.arg == 0: expr = expr.src2 else: expr = expr.src1 # a?(a?b:c):x => a?b:x elif expr.src1.is_cond() and expr.cond == expr.src1.cond: expr = ExprCond(expr.cond, expr.src1.src1, expr.src2) # a?x:(a?b:c) => a?x:c elif expr.src2.is_cond() and expr.cond == expr.src2.cond: expr = ExprCond(expr.cond, expr.src1, expr.src2.src2) # a|int ? b:c => b with int != 0 elif (expr.cond.is_op('|') and expr.cond.args[1].is_int() and expr.cond.args[1].arg != 0): return expr.src1 # (C?int1:int2)?(A:B) => elif (expr.cond.is_cond() and expr.cond.src1.is_int() and expr.cond.src2.is_int()): int1 = expr.cond.src1.arg.arg int2 = expr.cond.src2.arg.arg if int1 and int2: expr = expr.src1 elif int1 == 0 and int2 == 0: expr = expr.src2 elif int1 == 0 and int2: expr = ExprCond(expr.cond.cond, expr.src2, expr.src1) elif int1 and int2 == 0: expr = ExprCond(expr.cond.cond, expr.src1, expr.src2) return expr
def casp(ir, instr, arg1, arg2, arg3): # XXX TODO: memory barrier e = [] if arg1.size == 32: regs = gpregs32_expr else: regs = gpregs64_expr index1 = regs.index(arg1) index2 = regs.index(arg2) # TODO endianness comp_value = ExprCompose(regs[index1], regs[index1 + 1]) new_value = ExprCompose(regs[index2], regs[index2 + 1]) assert arg3.is_op('preinc') ptr = arg3.args[0] data = ExprMem(ptr, comp_value.size) loc_store = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) loc_do = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size) loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size) e.append( ExprAssign( ir.IRDst, ExprCond(ExprOp("FLAG_EQ_CMP", data, comp_value), loc_do, loc_store))) e_store = [] e_store.append(ExprAssign(data, new_value)) e_store.append(ExprAssign(ir.IRDst, loc_do)) blk_store = IRBlock(loc_store.loc_key, [AssignBlock(e_store, instr)]) e_do = [] e_do.append(ExprAssign(regs[index1], data[:data.size / 2])) e_do.append(ExprAssign(regs[index1 + 1], data[data.size / 2:])) e_do.append(ExprAssign(ir.IRDst, loc_next)) blk_do = IRBlock(loc_do.loc_key, [AssignBlock(e_do, instr)]) return e, [blk_store, blk_do]
def simp_cc_conds(expr_simp, expr): if (expr.is_op("CC_U>=") and test_cc_eq_args( expr, "FLAG_SUB_CF" )): expr = ExprCond( ExprOp(TOK_INF_UNSIGNED, *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1)) elif (expr.is_op("CC_U<") and test_cc_eq_args( expr, "FLAG_SUB_CF" )): expr = ExprOp(TOK_INF_UNSIGNED, *expr.args[0].args) elif (expr.is_op("CC_NEG") and test_cc_eq_args( expr, "FLAG_SIGN_SUB" )): expr = ExprOp(TOK_INF_SIGNED, *expr.args[0].args) elif (expr.is_op("CC_POS") and test_cc_eq_args( expr, "FLAG_SIGN_SUB" )): expr = ExprCond( ExprOp(TOK_INF_SIGNED, *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_EQ") and test_cc_eq_args( expr, "FLAG_EQ" )): arg = expr.args[0].args[0] expr = ExprOp(TOK_EQUAL, arg, ExprInt(0, arg.size)) elif (expr.is_op("CC_NE") and test_cc_eq_args( expr, "FLAG_EQ" )): arg = expr.args[0].args[0] expr = ExprCond( ExprOp(TOK_EQUAL,arg, ExprInt(0, arg.size)), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_NE") and test_cc_eq_args( expr, "FLAG_EQ_CMP" )): expr = ExprCond( ExprOp(TOK_EQUAL, *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_EQ") and test_cc_eq_args( expr, "FLAG_EQ_CMP" )): expr = ExprOp(TOK_EQUAL, *expr.args[0].args) elif (expr.is_op("CC_NE") and test_cc_eq_args( expr, "FLAG_EQ_AND" )): expr = ExprOp("&", *expr.args[0].args) elif (expr.is_op("CC_EQ") and test_cc_eq_args( expr, "FLAG_EQ_AND" )): expr = ExprCond( ExprOp("&", *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_S>") and test_cc_eq_args( expr, "FLAG_SIGN_SUB", "FLAG_SUB_OF", "FLAG_EQ_CMP", )): expr = ExprCond( ExprOp(TOK_INF_EQUAL_SIGNED, *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_S>") and len(expr.args) == 3 and expr.args[0].is_op("FLAG_SIGN_SUB") and expr.args[2].is_op("FLAG_EQ_CMP") and expr.args[0].args == expr.args[2].args and expr.args[1].is_int(0)): expr = ExprCond( ExprOp(TOK_INF_EQUAL_SIGNED, *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_S>=") and test_cc_eq_args( expr, "FLAG_SIGN_SUB", "FLAG_SUB_OF" )): expr = ExprCond( ExprOp(TOK_INF_SIGNED, *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_S<") and test_cc_eq_args( expr, "FLAG_SIGN_SUB", "FLAG_SUB_OF" )): expr = ExprOp(TOK_INF_SIGNED, *expr.args[0].args) elif (expr.is_op("CC_S<=") and test_cc_eq_args( expr, "FLAG_SIGN_SUB", "FLAG_SUB_OF", "FLAG_EQ_CMP", )): expr = ExprOp(TOK_INF_EQUAL_SIGNED, *expr.args[0].args) elif (expr.is_op("CC_S<=") and len(expr.args) == 3 and expr.args[0].is_op("FLAG_SIGN_SUB") and expr.args[2].is_op("FLAG_EQ_CMP") and expr.args[0].args == expr.args[2].args and expr.args[1].is_int(0)): expr = ExprOp(TOK_INF_EQUAL_SIGNED, *expr.args[0].args) elif (expr.is_op("CC_U<=") and test_cc_eq_args( expr, "FLAG_SUB_CF", "FLAG_EQ_CMP", )): expr = ExprOp(TOK_INF_EQUAL_UNSIGNED, *expr.args[0].args) elif (expr.is_op("CC_U>") and test_cc_eq_args( expr, "FLAG_SUB_CF", "FLAG_EQ_CMP", )): expr = ExprCond( ExprOp(TOK_INF_EQUAL_UNSIGNED, *expr.args[0].args), ExprInt(0, 1), ExprInt(1, 1) ) elif (expr.is_op("CC_S<") and test_cc_eq_args( expr, "FLAG_SIGN_ADD", "FLAG_ADD_OF" )): arg0, arg1 = expr.args[0].args expr = ExprOp(TOK_INF_SIGNED, arg0, -arg1) return expr
print k, v reqs.append((k, v)) all_info.append((addr, reqs)) all_cases = set() symbexec = SymbolicExecutionEngine(ir_arch) for addr, reqs_cond in all_info: out = ['(set-logic QF_ABV)', '(set-info :smt-lib-version 2.0)'] conditions = [] all_ids = set() for expr, value in reqs_cond: all_ids.update(get_expr_ids(expr)) expr_test = ExprCond(expr, ExprInt(1, value.size), ExprInt(0, value.size)) cond = translator_smt2.from_expr(ExprAssign(expr_test, value)) conditions.append(cond) for name in all_ids: out.append("(declare-fun %s () (_ BitVec %d))" % (name, name.size)) if not out: continue out += conditions out.append('(check-sat)') open('out.dot', 'w').write('\n'.join(out)) try: cases = subprocess.check_output([ "/home/serpilliere/tools/stp/stp", "-p", '--SMTLIB2', "out.dot" ])