def collect_params(cfg): func_addr = cfg.entry() e = cfg[func_addr] args = set( REG(r.name[:-2] if r.name.endswith("_0") else r.name) for r in e["live_in"]) progdb.update_cfg_prop(cfg, "params", args)
def collect_reach_exit(cfg): all_defs1 = foreach_bblock(cfg, lambda b: b.defs(True), set_union) exit = cfg.exit() if "reachdef_out" in cfg.node(exit): all_defs2 = set(x[0] for x in cfg.node(exit)["reachdef_out"]) assert all_defs1 == all_defs2, "%r vs %r" % (all_defs1, all_defs2) progdb.update_cfg_prop(cfg, "reach_exit", all_defs1) return all_defs1
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 collect_reach_exit(cfg): all_defs = foreach_bblock(cfg, lambda b: b.defs(True), set_union) exit = cfg.exit() if "reachdef_out" in cfg.node(exit): all_defs2 = set(x[0] for x in cfg.node(exit)["reachdef_out"] if x[1] is not None) if "_DEADEND_" not in cfg: assert all_defs == all_defs2, "%r vs %r" % (all_defs, all_defs2) all_defs = all_defs2 progdb.update_cfg_prop(cfg, "reach_exit", all_defs)
def collect_reach_exit(cfg): all_defs = foreach_bblock(cfg, lambda b: b.defs(True), set_union) exit = cfg.exit() if "reachdef_out" in cfg.node(exit): all_defs2 = set(x[0] for x in cfg.node(exit)["reachdef_out"] if x[1] is not None) if "_DEADEND_" not in cfg: assert all_defs == all_defs2, "%r vs %r" % (all_defs, all_defs2) all_defs = all_defs2 progdb.update_cfg_prop(cfg, "reach_exit", all_defs)
def collect_preserveds(cfg): exit_addr = cfg.exit() exit_bblock = cfg[exit_addr]["val"] state_out = exit_bblock.props["state_out"] preserveds = set() for k, v in state_out.items(): if is_reg(k) and is_reg(v): if v.name == k.name + "_0": preserveds.add(k) progdb.update_cfg_prop(cfg, "preserveds", preserveds)
def collect_preserveds(cfg): exit_addr = cfg.exit() exit_bblock = cfg[exit_addr]["val"] state_out = exit_bblock.props["state_out"] preserveds = set() for k, v in state_out.items(): if is_reg(k) and is_reg(v): if v.name == k.name + "_0": preserveds.add(k) progdb.update_cfg_prop(cfg, "preserveds", preserveds)
def collect_reach_exit_maybe(cfg): exit = cfg.exit() vardict = {} for var, addr in cfg.node(exit)["reachdef_out"]: vardict.setdefault(var, set()).add(addr) mod_maybe = set() for var, addrs in vardict.items(): if len(addrs) > 1 and None in addrs: mod_maybe.add(var) if 1: #mod_maybe or "reach_exit_maybe" in cfg.props: progdb.update_cfg_prop(cfg, "reach_exit_maybe", mod_maybe)
def estimate_params(cfg): #ana = dataflow.LiveVarAnalysis(cfg, skip_calls=True) #ana.solve() check_prop(cfg, "live_in", "This pass requires live variable information") func_addr = cfg.entry() assert func_addr == ".ENTRY", "cfg_preheader pass required" real_entry = cfg.succ(func_addr) assert len(real_entry) == 1 real_entry = real_entry[0] e = cfg[real_entry] args = set(REG(r.name[:-2] if r.name.endswith("_0") else r.name) for r in e["live_in"]) args -= set([REG("sp")]) progdb.update_cfg_prop(cfg, "estimated_params", args)
def estimate_params(cfg): #ana = dataflow.LiveVarAnalysis(cfg, skip_calls=True) #ana.solve() check_prop(cfg, "live_in", "This pass requires live variable information") func_addr = cfg.entry() assert func_addr == ".ENTRY", "cfg_preheader pass required" real_entry = cfg.succ(func_addr) assert len(real_entry) == 1 real_entry = real_entry[0] e = cfg[real_entry] args = set(REG(r.name[:-2] if r.name.endswith("_0") else r.name) for r in e["live_in"]) args -= set([REG("sp")]) progdb.update_cfg_prop(cfg, "estimated_params", args)
def collect_reach_exit_maybe(cfg): exit = cfg.exit() vardict = {} for var, addr in cfg.node(exit)["reachdef_out"]: vardict.setdefault(var, set()).add(addr) mod_maybe = set() for var, addrs in vardict.items(): if len(addrs) > 1 and None in addrs: mod_maybe.add(var) if 1: #mod_maybe or "reach_exit_maybe" in cfg.props: progdb.update_cfg_prop(cfg, "reach_exit_maybe", mod_maybe)
def collect_call_live_out(cfg): calls_live_out = [] def collect(node): bb = node["val"] if bb.items and bb[-1].op == "call": inst = bb[-1] arg = inst.args[0] # TODO: Perhaps filter in the real regs? regs = {r for r in node["live_out"] if not r.name.endswith("_0")} calls_live_out.append((bb.addr, arg, regs)) foreach_node(cfg, collect) progdb.update_cfg_prop(cfg, "calls_live_out", calls_live_out)
def collect_call_live_out(cfg): calls_live_out = [] def collect(node): bb = node["val"] if bb.items and bb[-1].op == "call": inst = bb[-1] arg = inst.args[0] # TODO: Perhaps filter in the real regs? regs = {r for r in node["live_out"] if not r.name.endswith("_0")} calls_live_out.append((bb.addr, arg, regs)) foreach_node(cfg, collect) progdb.update_cfg_prop(cfg, "calls_live_out", calls_live_out)
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 collect_params(cfg): func_addr = cfg.entry() e = cfg[func_addr] args = set(REG(r.name[:-2] if r.name.endswith("_0") else r.name) for r in e["live_in"]) args = arch.param_filter(args) progdb.update_cfg_prop(cfg, "params", args)