(self, max_loop_unrolling_times)
Unroll loops for each function. The resulting CFG may still contain loops due to recursion, function calls, etc.

        :param int max_loop_unrolling_times: The maximum iterations of unrolling.
        :return: None
Unroll loops for each function. The resulting CFG may still contain loops due to recursion, function calls, etc.
Unroll loops for each function . The resulting CFG may still contain loops due to recursion function calls etc .
def unroll_loops(self, max_loop_unrolling_times):
        """
        Unroll loops for each function. The resulting CFG may still contain loops due to recursion, function calls, etc.

        :param int max_loop_unrolling_times: The maximum iterations of unrolling.
        :return: None
        """

        if not isinstance(max_loop_unrolling_times, int) or \
                        max_loop_unrolling_times < 0:
            raise AngrCFGError('Max loop unrolling times must be set to an integer greater than or equal to 0 if ' +
                               'loop unrolling is enabled.')

        def _unroll(graph, loop):
            """
            The loop callback method where loops are unrolled.

            :param networkx.DiGraph graph: The control flow graph.
            :param angr.analyses.loopfinder.Loop loop: The loop instance.
            :return: None
            """

            for back_edge in loop.continue_edges:
                loop_body_addrs = {n.addr for n in loop.body_nodes}
                src_blocknode = back_edge[0]  # type: angr.knowledge.codenode.BlockNode
                dst_blocknode = back_edge[1]  # type: angr.knowledge.codenode.BlockNode

                for src in self.get_all_nodes(src_blocknode.addr):
                    for dst in graph.successors(src):
                        if dst.addr != dst_blocknode.addr:
                            continue

                        # Duplicate the dst node
                        new_dst = dst.copy()
                        new_dst.looping_times = dst.looping_times + 1
                        if (new_dst not in graph and
                                # If the new_dst is already in the graph, we don't want to keep unrolling
                                # the this loop anymore since it may *create* a new loop. Of course we
                                # will lose some edges in this way, but in general it is acceptable.
                                new_dst.looping_times <= max_loop_unrolling_times
                            ):
                            # Log all successors of the dst node
                            dst_successors = graph.successors(dst)
                            # Add new_dst to the graph
                            edge_data = graph.get_edge_data(src, dst)
                            graph.add_edge(src, new_dst, **edge_data)
                            for ds in dst_successors:
                                if ds.looping_times == 0 and ds.addr not in loop_body_addrs:
                                    edge_data = graph.get_edge_data(dst, ds)
                                    graph.add_edge(new_dst, ds, **edge_data)

                        graph.remove_edge(src, dst)

        self._detect_loops(loop_callback=_unroll)
def unroll_loops ( self , max_loop_unrolling_times ) : if not isinstance ( max_loop_unrolling_times , int ) or max_loop_unrolling_times < 0 : raise AngrCFGError ( 'Max loop unrolling times must be set to an integer greater than or equal to 0 if ' + 'loop unrolling is enabled.' ) def _unroll ( graph , loop ) : """
            The loop callback method where loops are unrolled.

            :param networkx.DiGraph graph: The control flow graph.
            :param angr.analyses.loopfinder.Loop loop: The loop instance.
            :return: None
            """ for back_edge in loop . continue_edges : loop_body_addrs = { n . addr for n in loop . body_nodes } src_blocknode = back_edge [ 0 ] # type: angr.knowledge.codenode.BlockNode dst_blocknode = back_edge [ 1 ] # type: angr.knowledge.codenode.BlockNode for src in self . get_all_nodes ( src_blocknode . addr ) : for dst in graph . successors ( src ) : if dst . addr != dst_blocknode . addr : continue # Duplicate the dst node new_dst = dst . copy ( ) new_dst . looping_times = dst . looping_times + 1 if ( new_dst not in graph and # If the new_dst is already in the graph, we don't want to keep unrolling # the this loop anymore since it may *create* a new loop. Of course we # will lose some edges in this way, but in general it is acceptable. new_dst . looping_times <= max_loop_unrolling_times ) : # Log all successors of the dst node dst_successors = graph . successors ( dst ) # Add new_dst to the graph edge_data = graph . get_edge_data ( src , dst ) graph . add_edge ( src , new_dst , * * edge_data ) for ds in dst_successors : if ds . looping_times == 0 and ds . addr not in loop_body_addrs : edge_data = graph . get_edge_data ( dst , ds ) graph . add_edge ( new_dst , ds , * * edge_data ) graph . remove_edge ( src , dst ) self . _detect_loops ( loop_callback = _unroll )