Ejemplo n.º 1
0
 def test_boost_example(self):
     # Graph taken from Figure 1 of
     # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm
     edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6),
              (5, 7), (6, 4)]
     G = nx.DiGraph(edges)
     assert (nx.immediate_dominators(G, 0) == {
         0: 0,
         1: 0,
         2: 1,
         3: 1,
         4: 3,
         5: 4,
         6: 4,
         7: 1
     })
     # Test postdominance.
     with nx.utils.reversed(G):
         assert (nx.immediate_dominators(G, 7) == {
             0: 1,
             1: 7,
             2: 7,
             3: 4,
             4: 5,
             5: 7,
             6: 4,
             7: 7
         })
Ejemplo n.º 2
0
 def test_domrel_png(self):
     # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png
     edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)]
     G = nx.DiGraph(edges)
     result = nx.immediate_dominators(G, 1)
     assert result == {1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 2}
     # Test postdominance.
     result = nx.immediate_dominators(G.reverse(copy=False), 6)
     assert result == {1: 2, 2: 6, 3: 5, 4: 5, 5: 2, 6: 6}
Ejemplo n.º 3
0
 def test_domrel_png(self):
     # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png
     edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)]
     G = nx.DiGraph(edges)
     assert_equal(nx.immediate_dominators(G, 1),
                  {1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 2})
     # Test postdominance.
     with nx.utils.reversed(G):
         assert_equal(nx.immediate_dominators(G, 6),
                      {1: 2, 2: 6, 3: 5, 4: 5, 5: 2, 6: 6})
Ejemplo n.º 4
0
    def create_graph_from(self, starting_ep):
        visited = set()
        to_visit = [starting_ep]
        graph = nx.DiGraph()
        g = Digraph('G', filename='CFG.gv')
        count = 0
        while len(to_visit) > 0:
            count += 1

            current_ep = to_visit.pop(0)
            current_instr = self.program.get_instruction_at_execution_point(
                current_ep)
            for succ_ep in current_instr.get_successors_checked():
                graph.add_edge(current_ep, succ_ep)

                g.edge(str(hex(current_instr.address)),
                       str(
                           hex(
                               self.program.get_instruction_at_execution_point(
                                   succ_ep).address)),
                       label=None)
                #g.edge(current_instr, self.program.get_instruction_at_execution_point(succ_ep),label=None)

                if succ_ep not in visited:
                    visited.add(succ_ep)
                    to_visit.append(succ_ep)

        g.view()
        self.program.possible_exit_points = [
            ep for ep in graph if graph.out_degree(ep) == 0
        ]
        if len(self.program.possible_exit_points
               ) > 0 and self.program.exit_point is None:
            self.program.exit_point = self.program.possible_exit_points[-1]

        imm_doms = nx.immediate_dominators(graph, starting_ep)

        graph_reverse = graph.reverse()
        post_doms = [
            nx.immediate_dominators(graph_reverse, exit_ep)
            for exit_ep in self.program.possible_exit_points
        ]

        for ep in graph:
            instr = self.program.get_instruction_at_execution_point(ep)

            possible_post_dominators = {pd.get(ep, None) for pd in post_doms}
            if len(possible_post_dominators) == 1:
                instr.immediate_post_dominator = possible_post_dominators.pop()

            instr.predecessors = graph.predecessors(ep)
            instr.immediate_dominator = imm_doms[ep]

        return graph
Ejemplo n.º 5
0
 def test_boost_example(self):
     # Graph taken from Figure 1 of
     # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm
     edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6),
              (5, 7), (6, 4)]
     G = nx.DiGraph(edges)
     assert_equal(nx.immediate_dominators(G, 0),
                  {0: 0, 1: 0, 2: 1, 3: 1, 4: 3, 5: 4, 6: 4, 7: 1})
     # Test postdominance.
     with nx.utils.reversed(G):
         assert_equal(nx.immediate_dominators(G, 7),
                      {0: 1, 1: 7, 2: 7, 3: 4, 4: 5, 5: 7, 6: 4, 7: 7})
Ejemplo n.º 6
0
def _execute_graph(data):
    log("executing graph")
    controlflow = _get_required_controlflow_graph(data)
    splits = []
    for n, idom in nx.immediate_dominators(controlflow, root_op).items():
        if n == idom:
            continue
        if n in controlflow.successors(idom):
            continue
        splits.append((idom, n))

    # Graph mode
    order = list(nx.topological_sort(controlflow))
    iteration = 0
    max_threads = 4
    while iteration < len(order):
        ops = []
        for i in range(max_threads):
            if iteration >= len(order):
                break
            next_op = order[iteration]
            if sum([op in nx.ancestors(controlflow, next_op)
                    for op in ops]) > 0:
                break
            ops.append(order[iteration])
            iteration += 1
        _run_ops_in_parallel(ops)
Ejemplo n.º 7
0
 def test_unreachable(self):
     n = 5
     assert n > 1
     G = nx.path_graph(n, create_using=nx.DiGraph())
     assert (nx.immediate_dominators(
         G, n // 2) == {i: max(i - 1, n // 2)
                        for i in range(n // 2, n)})
Ejemplo n.º 8
0
Archivo: cfg.py Proyecto: mfkiwl/dace
def acyclic_dominance_frontier(sdfg: SDFG, idom=None) -> Dict[SDFGState, Set[SDFGState]]:
    """
    Finds the dominance frontier for an SDFG while ignoring any back edges.

    This is a modified version of the dominance frontiers algorithm as
    implemented by networkx.

    :param sdfg: The SDFG for which to compute the acyclic dominance frontier.
    :param idom: Optional precomputed immediate dominators.
    :return: A dictionary keyed by states, containing the dominance frontier
             for each SDFG state.
    """
    idom = idom or nx.immediate_dominators(sdfg.nx, sdfg.start_state)

    dom_frontiers = {state: set() for state in sdfg.nodes()}
    for u in idom:
        if len(sdfg.nx.pred[u]) >= 2:
            for v in sdfg.nx.pred[u]:
                if v in idom:
                    df_candidates = set()
                    while v != idom[u]:
                        if v == u:
                            df_candidates = None
                            break
                        df_candidates.add(v)
                        v = idom[v]
                    if df_candidates is not None:
                        for candidate in df_candidates:
                            dom_frontiers[candidate].add(u)

    return dom_frontiers
Ejemplo n.º 9
0
def buildPdomTree(entryID, exitID, funName, CFGsR):
    '''build post domains tree

     Construct the postdominator tree for AugCFG

    :param entryID:
    :param exitID:
    :param funName:
    :param CFGsR:
    :return:
    '''

    #  Augment the CFG by adding a node Start with edge (Start, entry)
    #  labeled “T” and edge (Start, exit) labeled “F”;call this AugCFG
    CFGsR.add_edges_from([(entryID, funName), (exitID, funName)])
    nxPdomDict = nx.immediate_dominators(CFGsR, exitID)
    # PdomEdgeDict = dict()

    PdomEdges = list()
    for i in nxPdomDict:
        # if getNodeIDNo(nxPdomDict[i],CFGsR) not in PdomEdgeDict:
        #     PdomEdgeDict[getNodeIDNo(nxPdomDict[i],CFGsR)] = list()
        if (nxPdomDict[i] != i):
            # PdomEdgeDict[getNodeIDNo(nxPdomDict[i],CFGsR)].append(getNodeIDNo(i,CFGsR))
            PdomEdges.append((nxPdomDict[i], i))
    # print(PdomEdgeDict)
    PdomTree = nx.DiGraph()
    PdomTree.add_edges_from(PdomEdges)
    return PdomTree
Ejemplo n.º 10
0
def dominate(name):
    for (n, _) in find_nodes(name):
        lst = dict((nx.immediate_dominators(G, n).items()))
        out.write(str(lst))
        print(len(lst))
        for (t, _) in targets:
            domination = []
            temp = [t]
            while not (temp.__contains__(n)):
                list_p = []
                for tt in temp:
                    shortest = nx.dijkstra_path_length(G, lst[tt], tt)
                    print("shortest:" + str(shortest))
                    if shortest > 3:
                        parent = list(G.predecessors(tt))
                        print(parent)
                        for p in parent:
                            if p in lst.keys():
                                # shortest = nx.dijkstra_path_length(G, lst[p], tt)
                                # print("shortest:" + str(shortest))
                                if nx.dijkstra_path_length(G, lst[p], tt) <= 3:
                                    list_p.append(lst[p])

                    else:
                        list_p.append(lst[tt])
                list_p = list(set(list_p))
                temp = list_p
                list_n = []
                for l in list_p:
                    node = G.nodes[l]['label']
                    node = re.sub(r'[^\w\s]', '', node)
                    print(node)
                    list_n.append(node)
                domination.append(list_n)
                print(domination)
Ejemplo n.º 11
0
    def _build_dom_sets(self, graph: nx.DiGraph, gname=''):
        v_entry = 'virtual_entry'
        graph.add_edges_from(
            ((v_entry, node) for node, i in tuple(graph.in_degree) if i == 0))
        if v_entry not in graph:
            err_msg = f'Failed to find an entry to build dominance tree for {gname}'
            logging.error(err_msg)
            raise NoEntryForDomTreeError(err_msg)

        dom_tree = nx.DiGraph()
        dom_tree.add_nodes_from(graph.nodes)
        for node, dominator in nx.immediate_dominators(graph, v_entry).items():
            dom_tree.add_edge(dominator, node)
        dom_tree.remove_node(v_entry)

        dominances = {
            node: set.union(nx.descendants(dom_tree, node), {
                node,
            })
            for node in dom_tree.nodes
        }

        frontier = nx.dominance_frontiers(graph, v_entry)
        frontier.pop(v_entry)
        graph.remove_node(v_entry)
        return dom_tree, dominances, frontier
Ejemplo n.º 12
0
 def test_irreducible1(self):
     # Graph taken from Figure 2 of
     # K. D. Cooper, T. J. Harvey, and K. Kennedy.
     # A simple, fast dominance algorithm.
     # Software Practice & Experience, 4:110, 2001.
     edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)]
     G = nx.DiGraph(edges)
     assert (nx.immediate_dominators(G, 5) == {i: 5 for i in range(1, 6)})
Ejemplo n.º 13
0
def get_fixed_strings(r):
    # convert regex to graph
    G = nx.MultiDiGraph()
    cmd = ["./src/tools/util/regex2dfa", "-r", r]
    s = subprocess.run(cmd,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE,
                       check=True).stdout.decode("utf-8")
    end = None
    for l in s.splitlines():
        items = l.split("\t")
        if len(items) == 4:
            a, b, i, o = map(int, items)
            G.add_edge(a, b, label=(i).to_bytes(length=1, byteorder="big"))
        else:
            assert len(items) == 1
            end = int(items[0])
            break
    assert end is not None

    # convenciente function
    def get_edges(u):
        ret = []
        for v in G[u]:
            for i in G[u][v]:
                ret.append((u, v, G[u][v][i]["label"]))
        return ret

    # get relevant nodes
    start = 0
    dom = nx.immediate_dominators(G, start)
    relevant = [end]
    node = end
    while node != start:
        node = dom[node]
        relevant.append(node)
    relevant = relevant[::-1]

    # get fixed strings starting from relevant nodes
    # idea: check if a node has only one edge, collect the label and continue
    # until a branch is discovered
    strs = {}
    seen = set()
    for node in relevant:
        strs[node] = []
        edges = get_edges(node)
        while len(edges) == 1:
            u, v, l = edges[0]
            if u in seen or u == end:
                break
            seen.add(u)
            strs[node].append(l)
            edges = get_edges(v)
    return list(
        set([
            b"".join(l) for l in sorted(strs.values(), key=len, reverse=True)
            if len(l) > 0
        ]))
Ejemplo n.º 14
0
 def dominator_forest(self):
     if self._dominator_forest is not None:
         return self._dominator_forest
     self._dominator_forest = DAG()
     for root in self.roots:
         for node, dominated_by in nx.immediate_dominators(self, root).items():
             if node != dominated_by:
                 self._dominator_forest.add_edge(dominated_by, node)
     return self._dominator_forest
Ejemplo n.º 15
0
 def test_irreducible1(self):
     # Graph taken from Figure 2 of
     # K. D. Cooper, T. J. Harvey, and K. Kennedy.
     # A simple, fast dominance algorithm.
     # Software Practice & Experience, 4:110, 2001.
     edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)]
     G = nx.DiGraph(edges)
     assert_equal(nx.immediate_dominators(G, 5),
                  {i: 5 for i in range(1, 6)})
Ejemplo n.º 16
0
 def _build_dom_tree(self, digraph, entry):
     if len(digraph.nodes) == 1:
         self._domTree.add_node(entry)
         return
     # Code below assumes digraph has more then one node
     idom_list = nx.immediate_dominators(digraph, entry).items()
     for tup in idom_list:
         if tup[0] == entry:
             continue
         self._domTree.add_edge(tup[1], tup[0])
 def test_irreducible2(self):
     # Graph taken from Figure 4 of
     # K. D. Cooper, T. J. Harvey, and K. Kennedy.
     # A simple, fast dominance algorithm.
     # Software Practice & Experience, 4:110, 2001.
     edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1),
              (6, 4), (6, 5)]
     G = nx.DiGraph(edges)
     assert_equal(nx.immediate_dominators(G, 6),
                  dict((i, 6) for i in range(1, 7)))
Ejemplo n.º 18
0
 def _compute_dominators(self):
     import networkx
     g = networkx.DiGraph()
     for bb in self.bbs:
         for succ in bb.succ:
             g.add_edge(bb.start, succ.start)
     self._dominators = {
         self._bb_at[k]: self._bb_at[v]
         for k, v in networkx.immediate_dominators(g, 0).items()
     }
Ejemplo n.º 19
0
def dependencies(g, entry):
    dominators = nx.immediate_dominators(g, entry)
    deps = []
    for n in g.nodes():
        for m in g.nodes():
            ifdom = dominators[m]
            if any([ifdom not in path for path in nx.all_simple_paths(g, n, m)]):
                deps.append((m, n))

    return deps
Ejemplo n.º 20
0
def dominance_frontiers(G, start):
    """Returns the dominance frontiers of all nodes of a directed graph.

    Parameters
    ----------
    G : a DiGraph or MultiDiGraph
        The graph where dominance is to be computed.

    start : node
        The start node of dominance computation.

    Returns
    -------
    df : dict keyed by nodes
        A dict containing the dominance frontiers of each node reachable from
        ``start`` as lists.

    Raises
    ------
    NetworkXNotImplemented
        If ``G`` is undirected.

    NetworkXError
        If ``start`` is not in ``G``.

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)])
    >>> sorted((u, sorted(df)) for u, df in nx.dominance_frontiers(G, 1).items())
    [(1, []), (2, [5]), (3, [5]), (4, [5]), (5, [])]

    References
    ----------
    .. [1] K. D. Cooper, T. J. Harvey, and K. Kennedy.
           A simple, fast dominance algorithm.
           Software Practice & Experience, 4:110, 2001.
    """
    idom = nx.immediate_dominators(G, start)

    df = {u: [] for u in idom}

    for u in idom:
        if len(G.pred[u]) - int(u in G.pred[u]) >= 2:
            p = set()
            for v in G.pred[u]:
                while v != idom[u] and v not in p:
                    p.add(v)
                    v = idom[v]
            p.discard(u)
            for v in p:
                df[v].append(u)

    return df
Ejemplo n.º 21
0
def dominance_frontiers(G, start):
    """Returns the dominance frontiers of all nodes of a directed graph.

    Parameters
    ----------
    G : a DiGraph or MultiDiGraph
        The graph where dominance is to be computed.

    start : node
        The start node of dominance computation.

    Returns
    -------
    df : dict keyed by nodes
        A dict containing the dominance frontiers of each node reachable from
        `start` as lists.

    Raises
    ------
    NetworkXNotImplemented
        If `G` is undirected.

    NetworkXError
        If `start` is not in `G`.

    Examples
    --------
    >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)])
    >>> sorted((u, sorted(df)) for u, df in nx.dominance_frontiers(G, 1).items())
    [(1, []), (2, [5]), (3, [5]), (4, [5]), (5, [])]

    References
    ----------
    .. [1] K. D. Cooper, T. J. Harvey, and K. Kennedy.
           A simple, fast dominance algorithm.
           Software Practice & Experience, 4:110, 2001.
    """
    idom = nx.immediate_dominators(G, start)

    df = {u: [] for u in idom}

    for u in idom:
        if len(G.pred[u]) - int(u in G.pred[u]) >= 2:
            p = set()
            for v in G.pred[u]:
                while v != idom[u] and v not in p:
                    p.add(v)
                    v = idom[v]
            p.discard(u)
            for v in p:
                df[v].append(u)

    return df
Ejemplo n.º 22
0
    def _post_dominate(reversed_graph, n1, n2):
        """
        Checks whether `n1` post-dominates `n2` in the *original* (not reversed) graph.

        :param networkx.DiGraph reversed_graph:  The reversed networkx.DiGraph instance.
        :param networkx.Node n1:                 Node 1.
        :param networkx.Node n2:                 Node 2.
        :returns bool:                           True/False.
        """

        ds = networkx.immediate_dominators(reversed_graph, n1)
        return n2 in ds
Ejemplo n.º 23
0
    def _post_dominate(reversed_graph, n1, n2):
        """
        Checks whether `n1` post-dominates `n2` in the *original* (not reversed) graph.

        :param networkx.DiGraph reversed_graph:  The reversed networkx.DiGraph instance.
        :param networkx.Node n1:                 Node 1.
        :param networkx.Node n2:                 Node 2.
        :returns bool:                           True/False.
        """

        ds = networkx.immediate_dominators(reversed_graph, n1)
        return n2 in ds
Ejemplo n.º 24
0
 def test_domrel_png(self):
     # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png
     edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)]
     G = nx.DiGraph(edges)
     assert (nx.immediate_dominators(G, 1) == {
         1: 1,
         2: 1,
         3: 2,
         4: 2,
         5: 2,
         6: 2
     })
     # Test postdominance.
     with nx.utils.reversed(G):
         assert (nx.immediate_dominators(G, 6) == {
             1: 2,
             2: 6,
             3: 5,
             4: 5,
             5: 2,
             6: 6
         })
Ejemplo n.º 25
0
def nx_dominators(G, node_target, node_start='b0'):
    # get dominator tree, parent is immediate dominator
    lookup = nx.immediate_dominators(G, node_start)
    assert node_target in lookup

    # walk up the tree
    result = []
    current = node_target
    while True:
        result.append(current)
        if current == node_start:
            break
        current = lookup[current]

    return result
Ejemplo n.º 26
0
Archivo: cfg.py Proyecto: mfkiwl/dace
def all_dominators(sdfg: SDFG, idom: Dict[SDFGState, SDFGState] = None) -> Dict[SDFGState, Set[SDFGState]]:
    """ Returns a mapping between each state and all its dominators. """
    idom = idom or nx.immediate_dominators(sdfg.nx, sdfg.start_state)
    # Create a dictionary of all dominators of each node by using the
    # transitive closure of the DAG induced by the idoms
    g = nx.DiGraph()
    for node, dom in idom.items():
        if node is dom:  # Skip root
            continue
        g.add_edge(node, dom)
    tc = nx.transitive_closure_dag(g)
    alldoms: Dict[SDFGState, Set[SDFGState]] = {sdfg.start_state: set()}
    for node in tc:
        alldoms[node] = set(dst for _, dst in tc.out_edges(node))

    return alldoms
Ejemplo n.º 27
0
def dom(p):
	g = nx.DiGraph(p.cfg_edges)
	d = nx.immediate_dominators(g, p.entry)

	roots = [node for node, idom in d.items() if node == idom]
	gd = nx.DiGraph((idom, node) for node, idom in d.items()
		if node != idom)

	r, s = [], []
	for root in roots:
		r.extend(nx.dfs_preorder_nodes(gd, root))
		s.extend(nx.dfs_postorder_nodes(gd, root))

	p = {b: i for i, b in enumerate(r)}
	q = {b: i for i, b in enumerate(s)}

	return TreeQueries(p, q), d
Ejemplo n.º 28
0
    def _refine_loop(self, graph, head, initial_loop_nodes, initial_exit_nodes):
        refined_loop_nodes = initial_loop_nodes.copy()
        refined_exit_nodes = initial_exit_nodes.copy()

        idom = networkx.immediate_dominators(graph, self._start_node)

        n_new = refined_exit_nodes
        while len(refined_exit_nodes) > 1 and len(n_new) != 0:
            n_new = set()
            for n in list(refined_exit_nodes):
                if len(set(graph.predecessors(n)) - refined_loop_nodes) == 0:
                    refined_loop_nodes.add(n)
                    refined_exit_nodes.remove(n)
                    for u in (set(graph.successors(n)) - refined_loop_nodes):
                        if self._dominates(idom, head, n):
                            n_new.add(u)
            refined_exit_nodes |= n_new
        return refined_loop_nodes, refined_exit_nodes
Ejemplo n.º 29
0
    def _refine_loop(self, graph, head, initial_loop_nodes, initial_exit_nodes):
        refined_loop_nodes = initial_loop_nodes.copy()
        refined_exit_nodes = initial_exit_nodes.copy()

        idom = networkx.immediate_dominators(graph, self._start_node)

        n_new = refined_exit_nodes
        while len(refined_exit_nodes) > 1 and len(n_new) != 0:
            n_new = set()
            for n in list(refined_exit_nodes):
                if len(set(graph.predecessors(n)) - refined_loop_nodes) == 0:
                    refined_loop_nodes.add(n)
                    refined_exit_nodes.remove(n)
                    for u in (set(graph.successors(n)) - refined_loop_nodes):
                        if self._dominates(idom, head, n):
                            n_new.add(u)
            refined_exit_nodes |= n_new
        return refined_loop_nodes, refined_exit_nodes
Ejemplo n.º 30
0
    def build_dominators(self, root: str):
        """
        This builds the requisite dominator structures:
        dominator tree, immediate dominators, and dominance frontier
        for each function present in the program.
        :param root: Name of function to build for.
        :return: None
        """
        self.frontier[root] = nx.dominance_frontiers(
            self.program.bb_graph, self.program.functions[root]['entry'])
        self.idoms[root] = nx.immediate_dominators(
            self.program.bb_graph, self.program.functions[root]['entry'])
        self.dominator_tree[root] = defaultdict(lambda: set())

        for key, value in self.idoms[root].items():
            # Ensure a self dominated node isn't added
            # This guarantees no infinite iteration
            if key != value:
                self.dominator_tree[root][value].add(key)
Ejemplo n.º 31
0
    def compare_immediate_dominators(self, start, end, edges):
        G = nx.DiGraph(edges)
        idom_nx = sorted(nx.immediate_dominators(G, start).items())

        cfg = ControlFlowGraph.fromEdgeList(start, end, edges)

        dom = dominators(cfg)
        idom_hw = immediateDominator(dom)

        # print(idom_nx)
        # print(idom_hw)

        for node, idom in idom_nx:
            if node == start:
                self.assertEqual(idom_hw[node], '')
            else:
                self.assertEqual(
                    idom_hw[node], idom,
                    "nx: {}, homework: {}".format(idom_nx, idom_hw))
Ejemplo n.º 32
0
    def _refine_loop(self, graph, head, initial_loop_nodes, initial_exit_nodes):
        refined_loop_nodes = initial_loop_nodes.copy()
        refined_exit_nodes = initial_exit_nodes.copy()

        idom = networkx.immediate_dominators(graph, self._start_node)

        new_exit_nodes = refined_exit_nodes
        while len(refined_exit_nodes) > 1 and new_exit_nodes:
            new_exit_nodes = set()
            for n in list(refined_exit_nodes):
                if all(pred in refined_loop_nodes for pred in graph.predecessors(n)) and dominates(idom, head, n):
                    refined_loop_nodes.add(n)
                    refined_exit_nodes.remove(n)
                    for u in (set(graph.successors(n)) - refined_loop_nodes):
                        new_exit_nodes.add(u)
            refined_exit_nodes |= new_exit_nodes

        refined_loop_nodes = refined_loop_nodes - refined_exit_nodes

        return refined_loop_nodes, refined_exit_nodes
Ejemplo n.º 33
0
    def _update_stable(self):
        # compute stable vertices
        self.log("""== Computing the stable vertices ==""")

        # compute immediate dominators
        self.dominators = networkx.immediate_dominators(self.N, self.root)

        # for each vertex, assign a leaf that they are stable on
        self.stability = dict((u, u) for u in self.leaves)
        X = list(self.leaves.copy())
        while X:
            u = X.pop()
            v = self.dominators[u]
            if v not in self.stability:
                self.stability[v] = u
                X.append(v)

        if self.verbose:
            self.log('immediate dominators:')
            for u in self.stability:
                if self.is_stable(u):
                    self.log(str(u) + ': ' + str(self.stability[u]))
Ejemplo n.º 34
0
    def get_dominator_graphs(self):
        assert self.forwarding_graphs, "Forwarding Graph needs to be built before the Dominator Graphs"

        for subnet, forwarding_graph in self.forwarding_graphs.items():
            rev_graph = forwarding_graph.reverse(copy=True)

            try:
                dominators = set(
                    nx.immediate_dominators(rev_graph, 'sink').items())
            except nx.NetworkXError as e:
                self.logger.error(
                    "Sink node is not in the forwarding graph for {subnet}. "
                    "Official error message: {error}".format(subnet=subnet,
                                                             error=e))
                # sys.exit(1)
            else:

                if ("sink", "sink") in dominators:
                    dominators.remove(("sink", "sink"))

                tmp_dominator_graph = nx.DiGraph(list(dominators))
                self.dominator_graphs[subnet] = tmp_dominator_graph

        return self.dominator_graphs
Ejemplo n.º 35
0
edges = []
with open('edges.txt') as fedges:
    for line in fedges:
        e = line.split()
        edges.append((int(e[0]),int(e[1])))



# creating the graph from edges.txt
graph=nx.DiGraph()
graph.add_nodes_from(IDs)
graph.add_edges_from(edges)
dftree = nx.dfs_tree(graph,0)

#tree = nx.dfs_edges(graph)
imdom = sorted(nx.immediate_dominators(graph, 0).items()) # immediante dominance


dom_tree = nx.DiGraph()
#dom_tree.add_nodes_from(IDs)
dom_tree.add_edges_from(imdom)

fdomtree = open("domtree.txt",'w')
fdomtree.write('\n'.join('%s %s' % (str(x[0]), str(x[1])) for x in dftree.edges()))

fdomtree.close()
#nx.draw_graphviz(dftree, with_labels = True)

# drawings
# nx.draw_networkx(dom_tree, with_labels = True)
#nx.draw(graph)
Ejemplo n.º 36
0
    def recover_reaching_conditions(self,
                                    region,
                                    with_successors=False,
                                    jump_tables=None):
        def _strictly_postdominates(inv_idoms, node_a, node_b):
            """
            Does node A strictly post-dominate node B on the graph?
            """
            return dominates(inv_idoms, node_a, node_b)

        edge_conditions = {}
        predicate_mapping = {}
        # traverse the graph to recover the condition for each edge
        for src in region.graph.nodes():
            nodes = list(region.graph[src])
            if len(nodes) >= 1:
                for dst in nodes:
                    edge = src, dst
                    edge_data = region.graph.get_edge_data(*edge)
                    edge_type = edge_data.get('type', 'transition')
                    try:
                        predicate = self._extract_predicate(
                            src, dst, edge_type)
                    except EmptyBlockNotice:
                        # catch empty block notice - although this should not really happen
                        predicate = claripy.true
                    edge_conditions[edge] = predicate
                    predicate_mapping[predicate] = dst

        if jump_tables:
            self.recover_reaching_conditions_for_jumptables(
                region, jump_tables, edge_conditions)

        if with_successors and region.graph_with_successors is not None:
            _g = region.graph_with_successors
        else:
            _g = region.graph
        end_nodes = {n for n in _g.nodes() if _g.out_degree(n) == 0}
        inverted_graph = shallow_reverse(_g)
        if end_nodes:
            if len(end_nodes) > 1:
                # make sure there is only one end node
                dummy_node = "DUMMY_NODE"
                for end_node in end_nodes:
                    inverted_graph.add_edge(dummy_node, end_node)
                endnode = dummy_node
            else:
                endnode = next(iter(end_nodes))  # pick the end node

            idoms = networkx.immediate_dominators(inverted_graph, endnode)
        else:
            idoms = None

        reaching_conditions = {}
        # recover the reaching condition for each node
        sorted_nodes = CFGUtils.quasi_topological_sort_nodes(_g)
        terminating_nodes = []
        for node in sorted_nodes:
            preds = _g.predecessors(node)
            reaching_condition = None

            out_degree = _g.out_degree(node)
            if out_degree == 0:
                terminating_nodes.append(node)

            if node is region.head:
                # the head is always reachable
                reaching_condition = claripy.true
            elif idoms is not None and _strictly_postdominates(
                    idoms, node, region.head):
                # the node that post dominates the head is always reachable
                reaching_conditions[node] = claripy.true
            else:
                for pred in preds:
                    edge = (pred, node)
                    pred_condition = reaching_conditions.get(
                        pred, claripy.true)
                    edge_condition = edge_conditions.get(edge, claripy.true)

                    if reaching_condition is None:
                        reaching_condition = claripy.And(
                            pred_condition, edge_condition)
                    else:
                        reaching_condition = claripy.Or(
                            claripy.And(pred_condition, edge_condition),
                            reaching_condition)

            if reaching_condition is not None:
                reaching_conditions[node] = self.simplify_condition(
                    reaching_condition)

        # My hypothesis to be proved: in any regioned graph, there must be a node with a 0 out-degree whose reaching
        # conditions can be marked as True. In other words, if all 0 out-degree nodes have non-trivial reaching
        # conditions, we can always pick one of them and change its reaching condition to True, without changing the
        # semantics of the regioned graph.
        if terminating_nodes and all(not reaching_conditions[node].is_true()
                                     for node in terminating_nodes
                                     if node in reaching_conditions):
            # pick the node with the greatest in-degree
            terminating_nodes = sorted(terminating_nodes, key=_g.in_degree)
            node_with_greatest_indegree = terminating_nodes[-1]
            if _g.in_degree(node_with_greatest_indegree) > 1:
                # forcing the in-degree to be greater than 1 allows us to skip the case blocks in switch-cases
                # otherwise structurer will fail to structure the control flow
                reaching_conditions[node_with_greatest_indegree] = claripy.true
                l.warning(
                    "Marking node %r as trivially reachable. Disable this optimization in condition_processor.py "
                    "if it leads to incorrect decompilation result.",
                    node_with_greatest_indegree)

        # Another hypothesis: for nodes where two paths come together *and* those that cannot be further structured into
        # another if-else construct (we take the short-cut by testing if the operator is an "Or" after running our
        # condition simplifiers previously), we are better off using their "guarding conditions" instead of their
        # reaching conditions for if-else. see my super long chatlog with rhelmot on 5/14/2021.
        guarding_conditions = {}
        for the_node in sorted_nodes:

            preds = list(_g.predecessors(the_node))
            if len(preds) != 2:
                continue
            # generate a graph slice that goes from the region head to this node
            slice_nodes = list(networkx.dfs_tree(inverted_graph, the_node))
            subgraph = networkx.subgraph(_g, slice_nodes)
            # figure out which paths cause the divergence from this node
            nodes_do_not_reach_the_node = set()
            for node_ in subgraph:
                if node_ is the_node:
                    continue
                for succ in _g.successors(node_):
                    if not networkx.has_path(_g, succ, the_node):
                        nodes_do_not_reach_the_node.add(succ)

            diverging_conditions = []

            for node_ in nodes_do_not_reach_the_node:
                preds_ = list(_g.predecessors(node_))
                for pred_ in preds_:
                    if pred_ in nodes_do_not_reach_the_node:
                        continue
                    # this predecessor is the diverging node!
                    edge_ = pred_, node_
                    edge_condition = edge_conditions.get(edge_, None)
                    if edge_condition is not None:
                        diverging_conditions.append(edge_condition)

            if diverging_conditions:
                # the negation of the union of diverging conditions is the guarding condition for this node
                cond = claripy.Or(*map(claripy.Not, diverging_conditions))
                guarding_conditions[the_node] = cond

        self.reaching_conditions = reaching_conditions
        self.guarding_conditions = guarding_conditions
Ejemplo n.º 37
0
 def test_cycle(self):
     n = 5
     G = nx.cycle_graph(n, create_using=nx.DiGraph())
     assert_equal(nx.immediate_dominators(G, 0),
                  {i: max(i - 1, 0) for i in range(n)})
Ejemplo n.º 38
0
 def test_unreachable(self):
     n = 5
     assert_greater(n, 1)
     G = nx.path_graph(n, create_using=nx.DiGraph())
     assert_equal(nx.immediate_dominators(G, n // 2),
                  {i: max(i - 1, n // 2) for i in range(n // 2, n)})
Ejemplo n.º 39
0
    def recover_reaching_conditions(self, region, with_successors=False, jump_tables=None):

        def _strictly_postdominates(inv_idoms, node_a, node_b):
            """
            Does node A strictly post-dominate node B on the graph?
            """
            return dominates(inv_idoms, node_a, node_b)

        edge_conditions = {}
        predicate_mapping = {}
        # traverse the graph to recover the condition for each edge
        for src in region.graph.nodes():
            nodes = list(region.graph[src])
            if len(nodes) >= 1:
                for dst in nodes:
                    edge = src, dst
                    edge_data = region.graph.get_edge_data(*edge)
                    edge_type = edge_data.get('type', 'transition')
                    try:
                        predicate = self._extract_predicate(src, dst, edge_type)
                    except EmptyBlockNotice:
                        # catch empty block notice - although this should not really happen
                        predicate = claripy.true
                    edge_conditions[edge] = predicate
                    predicate_mapping[predicate] = dst

        if jump_tables:
            self.recover_reaching_conditions_for_jumptables(region, jump_tables, edge_conditions)

        if with_successors and region.graph_with_successors is not None:
            _g = region.graph_with_successors
        else:
            _g = region.graph
        end_nodes = {n for n in _g.nodes() if _g.out_degree(n) == 0}
        if end_nodes:
            inverted_graph = shallow_reverse(_g)
            if len(end_nodes) > 1:
                # make sure there is only one end node
                dummy_node = "DUMMY_NODE"
                for end_node in end_nodes:
                    inverted_graph.add_edge(dummy_node, end_node)
                endnode = dummy_node
            else:
                endnode = next(iter(end_nodes))  # pick the end node

            idoms = networkx.immediate_dominators(inverted_graph, endnode)
        else:
            idoms = None

        reaching_conditions = {}
        # recover the reaching condition for each node
        sorted_nodes = CFGUtils.quasi_topological_sort_nodes(_g)
        terminating_nodes = [ ]
        for node in sorted_nodes:
            preds = _g.predecessors(node)
            reaching_condition = None

            out_degree = _g.out_degree(node)
            if out_degree == 0:
                terminating_nodes.append(node)

            if node is region.head:
                # the head is always reachable
                reaching_condition = claripy.true
            elif idoms is not None and _strictly_postdominates(idoms, node, region.head):
                # the node that post dominates the head is always reachable
                reaching_conditions[node] = claripy.true
            else:
                for pred in preds:
                    edge = (pred, node)
                    pred_condition = reaching_conditions.get(pred, claripy.true)
                    edge_condition = edge_conditions.get(edge, claripy.true)

                    if reaching_condition is None:
                        reaching_condition = claripy.And(pred_condition, edge_condition)
                    else:
                        reaching_condition = claripy.Or(claripy.And(pred_condition, edge_condition), reaching_condition)

            if reaching_condition is not None:
                reaching_conditions[node] = self.simplify_condition(reaching_condition)

        # My hypothesis to be proved: in any regioned graph, there must be a node with a 0 out-degree whose reaching
        # conditions can be marked as True. In other words, if all 0 out-degree nodes have non-trivial reaching
        # conditions, we can always pick one of them and change its reaching condition to True, without changing the
        # semantics of the regioned graph.
        if terminating_nodes and all(not reaching_conditions[node].is_true() for node in terminating_nodes
                                     if node in reaching_conditions):
            # pick the node with the greatest in-degree
            terminating_nodes = sorted(terminating_nodes, key=_g.in_degree)
            node_with_greatest_indegree = terminating_nodes[-1]
            if _g.in_degree(node_with_greatest_indegree) > 1:
                # forcing the in-degree to be greater than 1 allows us to skip the case blocks in switch-cases
                # otherwise structurer will fail to structure the control flow
                reaching_conditions[node_with_greatest_indegree] = claripy.true
                l.warning("Marking node %r as trivially reachable. Disable this optimization in condition_processor.py "
                          "if it leads to incorrect decompilation result.", node_with_greatest_indegree)

        self.reaching_conditions = reaching_conditions
Ejemplo n.º 40
0
 def test_singleton(self):
     G = nx.DiGraph()
     G.add_node(0)
     assert_equal(nx.immediate_dominators(G, 0), {0: 0})
     G.add_edge(0, 0)
     assert_equal(nx.immediate_dominators(G, 0), {0: 0})