def update_cfg_prop(cfg, prop, new_val): if cfg.props.get(prop) != new_val: mark_updated(cfg.props["name"]) print("%s: %s updated from %s to %s" % (cfg.props["name"], prop, utils.repr_stable( cfg.props.get(prop)), utils.repr_stable(new_val))) cfg.props[prop] = new_val
def print_header(self): if self.addr_in_header: print("// %s" % self.addr, file=self.stream) print("// Predecessors: %s" % sorted(self.cfg.pred(self.addr)), file=self.stream) if self.node_props: print("// Node props:", file=self.stream) for k in sorted(self.node_props.keys()): v = self.node_props[k] v = utils.repr_stable(v) v = v.replace("$", self.header_reg_prefix) print("// %s: %s" % (k, v), file=self.stream) if self.bblock_props: print("// BBlock props:", file=self.stream) for k in sorted(self.bblock_props.keys()): v = self.bblock_props[k] if k.startswith("state_"): v = repr_state(v) else: v = utils.repr_stable(v) v = v.replace("$", self.header_reg_prefix) print("// %s: %s" % (k, v), file=self.stream)
def calc_callsites_live_out(cg, callee): """Calculate function's callsites_live_out property. Go thru function's callers (using callgraph), and union their calls_live_out information pertinent to this function. """ callers = maybesorted(cg.pred(callee)) # If there're no callers, will return empty set, which # is formally correct - if there're no callers, the # function is dead. However, realistically that means # that callers aren't known, and we should treat that # specially. call_lo_union = set() for c in callers: clo = progdb.FUNC_DB[c].get("calls_live_out", []) #print(" %s: calls_live_out: %s" % (c, utils.repr_stable(clo))) for bbaddr, callee_expr, live_out in clo: if is_addr(callee_expr) and callee_expr.addr == callee: print(" %s: calls_live_out[%s]: %s" % (c, callee, utils.repr_stable((bbaddr, callee_expr, live_out)))) call_lo_union.update(live_out) progdb.FUNC_DB[callee]["callsites_live_out"] = call_lo_union return call_lo_union
def strarg(expr, arg): if isinstance(arg, (set, frozenset)): s = utils.repr_stable(arg) else: s = str(arg) preced_my = EXPR.preced(expr) preced_arg = EXPR.preced(arg) full_assoc = expr.op in {"+", "*", "&", "^", "|"} if preced_arg == preced_my and full_assoc: # Render repeated fully associative operators without extra parens pass elif preced_arg > preced_my or (preced_arg == preced_my and preced_arg != 1): # Otherwise, if precedence rules require parens, render them, unless # the arg is a unary/primary term s = "(%s)" % s else: # Parens would not be required per the precedence rules, but # handle common cases of confusing precedence in C, where parens # are usually suggested. if expr.op in ("&", "^", "|") and preced_arg != 1: # Any binary op subexpression of bitwise ops in parens s = "(%s)" % s elif expr.op in ("<<", ">>") and preced_arg != 1: # Any binary op subexpression of shift in parens s = "(%s)" % s return s
def print_graph_header(self): if self.cfg.props: print("// Graph props:", file=self.stream) for k in sorted(self.cfg.props.keys()): v = self.cfg.props[k] v = utils.repr_stable(v) print("// %s: %s" % (k, v), file=self.stream) print(file=self.stream)
def process_one(cg, func, xform_pass): global subiter_cnt, update_cnt upward_queue = [func] downward_queue = [] cnt = 0 cur_queue = upward_queue while upward_queue or downward_queue: subiter_cnt += 1 cnt += 1 if not cur_queue: if cur_queue is upward_queue: cur_queue = downward_queue else: cur_queue = upward_queue func = cur_queue.pop(0) print("--- Next to process: %s ---" % func) progdb.clear_updated() cfg = CFG_MAP["pre"][func].copy() call_lo_union = xform_inter.calc_callsites_live_out(cg, func) progdb.update_cfg_prop(cfg, "callsites_live_out", call_lo_union) print("%s: callsites_live_out set to %s" % (func, utils.repr_stable(call_lo_union))) if "modifieds" in progdb.FUNC_DB[func]: progdb.FUNC_DB[func]["returns"] = arch.ret_filter( progdb.FUNC_DB[func]["modifieds"] & call_lo_union) else: print("%s: doesn't yet have modifieds!" % func) xform_pass.apply(cfg) if progdb.UPDATED_FUNCS: assert len(progdb.UPDATED_FUNCS) == 1, repr(progdb.UPDATED_FUNCS) func2 = progdb.UPDATED_FUNCS.pop() assert func2 == func update_cnt += 1 progdb.update_funcdb(cfg) save_cfg(cfg, ".1") CFG_MAP["pre"][func].props = cfg.props upward_queue.extend(maybesorted(cg.pred(func))) for callee in maybesorted(cg.succ(func)): print("! updating callee", callee) if callee not in downward_queue: downward_queue.insert(0, callee) print("--- Finished processing: %s ---" % func) print("# New up (caller) queue:", upward_queue) print("# New down (callee) queue:", downward_queue) else: print("%s not updated" % func) print("Subiters:", cnt)
def strarg(expr, arg): if isinstance(arg, (set, frozenset)): s = utils.repr_stable(arg) else: s = str(arg) preced_my = EXPR.preced(expr) preced_arg = EXPR.preced(arg) non_assoc = expr.op in {"-", "/"} if preced_arg > preced_my or (preced_arg == preced_my and non_assoc): s = "(%s)" % s else: # Common cases of confusing precedence in C, where parens is usually # suggested. if expr.op in ("<<", ">>") and (preced_arg != 1 and arg.op in ("+", "-")): s = "(%s)" % s return s
def print_header(self): print("// Predecessors: %s" % sorted(self.cfg.pred(self.addr)), file=self.stream) if self.node_props: print("// Node props:", file=self.stream) for k in sorted(self.node_props.keys()): v = self.node_props[k] v = utils.repr_stable(v) print("// %s: %s" % (k, v), file=self.stream) if self.bblock_props: print("// BBlock props:", file=self.stream) for k in sorted(self.bblock_props.keys()): v = self.bblock_props[k] if k.startswith("state_"): v = repr_state(v) elif isinstance(v, dict): v = utils.repr_stable_dict(v) print("// %s: %s" % (k, v), file=self.stream)
def update_cfg_prop(cfg, prop, new_val): if cfg.props.get(prop) != new_val: mark_updated(cfg.props["name"]) log.info("%s: %s updated from %s to %s" % (cfg.props["name"], prop, utils.repr_stable(cfg.props.get(prop)), utils.repr_stable(new_val))) cfg.props[prop] = new_val
def process_one(cg, func, xform_pass): global subiter_cnt, update_cnt upward_queue = [func] downward_queue = [] cnt = 0 cur_queue = upward_queue while upward_queue or downward_queue: subiter_cnt += 1 cnt += 1 if not cur_queue: if cur_queue is upward_queue: cur_queue = downward_queue else: cur_queue = upward_queue func = cur_queue.pop(0) print("--- Next to process: %s ---" % func) progdb.clear_updated() cfg = CFG_MAP["pre"][func].copy() call_lo_union = xform_inter.calc_callsites_live_out(cg, func) progdb.update_cfg_prop(cfg, "callsites_live_out", call_lo_union) print("%s: callsites_live_out set to %s" % (func, utils.repr_stable(call_lo_union))) if "modifieds" in progdb.FUNC_DB[func]: progdb.FUNC_DB[func]["returns"] = arch.ret_filter(progdb.FUNC_DB[func]["modifieds"] & call_lo_union) else: print("%s: doesn't yet have modifieds!" % func) xform_pass.apply(cfg) if progdb.UPDATED_FUNCS: func_stats[func][0] += 1 assert len(progdb.UPDATED_FUNCS) == 1, repr(progdb.UPDATED_FUNCS) func2 = progdb.UPDATED_FUNCS.pop() assert func2 == func update_cnt += 1 progdb.update_funcdb(cfg) save_cfg(cfg, ".1") dot.save_dot(cfg, ".1") CFG_MAP["pre"][func].props = cfg.props for x in maybesorted(cg.pred(func)): if x not in upward_queue: upward_queue.append(x) for callee in maybesorted(cg.succ(func)): print("! updating callee", callee) if callee not in downward_queue: downward_queue.append(callee) print("--- Finished processing: %s ---" % func) print("# New up (caller) queue:", upward_queue) print("# New down (callee) queue:", downward_queue) else: func_stats[func][1] += 1 print("%s not updated" % func) # Maybe funcdb properties not updated, but bblocks props can very well be save_cfg(cfg, ".1") dot.save_dot(cfg, ".1") print("Subiters:", cnt)
def check_invariants(cfg): if "reach_exit" in cfg.props: reach = cfg.props["reach_exit"] reach_maybe = cfg.props.get("reach_exit_maybe", set()) assert reach_maybe.issubset(reach), "%s: maybe: %s, sure: %s" % ( cfg.props["name"], repr_stable(reach_maybe), repr_stable(reach))
def __repr__(self): if self.op in ("in", "not in"): return "COND(%r %s %s)" % (self.arg1, self.op, utils.repr_stable(self.arg2)) return "COND(%r %s %r)" % (self.arg1, self.op, self.arg2)
def check_invariants(cfg): if "reach_exit" in cfg.props: reach = cfg.props["reach_exit"] reach_maybe = cfg.props.get("reach_exit_maybe", set()) assert reach_maybe.issubset(reach), "%s: maybe: %s, sure: %s" % (cfg.props["name"], repr_stable(reach_maybe), repr_stable(reach))