#!/usr/bin/python3 import json import os import networkx as nx import sys cfg = dict() if 'CFG_OUTPUT_PATH' not in os.environ: sys.exit("CFG_OUTPUT_PATH not set") input_path = os.environ["CFG_OUTPUT_PATH"] for dirpath, _, files in os.walk(input_path): for x in files: if x.endswith(".cfg"): cfg[x] = json.load(open(os.path.join(dirpath, x))) G = nx.DiGraph() GG = nx.DiGraph() # First add all the edges node_ids = 0 f_ids = 0 fname2id = dict() for mname, module in cfg.items(): fnname2SG = dict() # First, add all the intra-procedural edges for (fname, v) in module['edges'].items(): if fname not in fname2id: GG.add_node(f_ids, label=fname) fname2id[fname] = f_ids f_ids += 1 sz = len(v) for idx in range(node_ids, node_ids + sz): G.add_node(idx) G.nodes[idx]['label'] = mname + ' ' + \ fname + ' ' + str(idx - node_ids) node_id_list = list(range(node_ids, node_ids + sz)) node_ids += sz SG = G.subgraph(node_id_list) fnname2SG[fname] = SG for src, dsts in enumerate(v): for item in dsts: G.add_edge(node_id_list[src], node_id_list[item]) # Next, build inter-procedural edges for (fname, calls) in module['calls'].items(): for (idx, target_fns) in calls.items(): # G.nodes isn't sorted src = sorted(fnname2SG[fname].nodes())[0] + int(idx) for target_fn in target_fns: if target_fn in fnname2SG: offset = module['entries'][target_fn] dst = sorted(fnname2SG[target_fn].nodes)[0] + offset # Now we have 2 index, build the edge G.add_edge(src, dst) GG.add_edge(fname2id[fname], fname2id[target_fn]) nx.nx_agraph.write_dot(G, "cfg.xdot") nx.nx_agraph.write_dot(GG, "cg.xdot")