(self)
Make sure all basic blocks in the transition graph of this function do not overlap. You will end up with a CFG
        that IDA Pro generates.

        This method does not touch the CFG result. You may call CFG{Emulated, Fast}.normalize() for that matter.

        :return: None
Make sure all basic blocks in the transition graph of this function do not overlap. You will end up with a CFG
        that IDA Pro generates.
Make sure all basic blocks in the transition graph of this function do not overlap . You will end up with a CFG that IDA Pro generates .
def normalize(self):
        """
        Make sure all basic blocks in the transition graph of this function do not overlap. You will end up with a CFG
        that IDA Pro generates.

        This method does not touch the CFG result. You may call CFG{Emulated, Fast}.normalize() for that matter.

        :return: None
        """

        # let's put a check here
        if self.startpoint is None:
            # this function is empty
            l.debug('Unexpected error: %s does not have any blocks. normalize() fails.', repr(self))
            return

        graph = self.transition_graph
        end_addresses = defaultdict(list)

        for block in self.nodes:
            if isinstance(block, BlockNode):
                end_addr = block.addr + block.size
                end_addresses[end_addr].append(block)

        while any(len(x) > 1 for x in end_addresses.values()):
            end_addr, all_nodes = \
                next((end_addr, x) for (end_addr, x) in end_addresses.items() if len(x) > 1)

            all_nodes = sorted(all_nodes, key=lambda node: node.size)
            smallest_node = all_nodes[0]
            other_nodes = all_nodes[1:]

            is_outside_node = False
            if smallest_node not in graph:
                is_outside_node = True

            # Break other nodes
            for n in other_nodes:
                new_size = get_real_address_if_arm(self._project.arch, smallest_node.addr) - get_real_address_if_arm(self._project.arch, n.addr)
                if new_size == 0:
                    # This is the node that has the same size as the smallest one
                    continue

                new_end_addr = n.addr + new_size

                # Does it already exist?
                new_node = None
                if new_end_addr in end_addresses:
                    nodes = [i for i in end_addresses[new_end_addr] if i.addr == n.addr]
                    if len(nodes) > 0:
                        new_node = nodes[0]

                if new_node is None:
                    # TODO: Do this correctly for hook nodes
                    # Create a new one
                    new_node = BlockNode(n.addr, new_size, graph=graph, thumb=n.thumb)
                    self._block_sizes[n.addr] = new_size
                    self._addr_to_block_node[n.addr] = new_node
                    # Put the newnode into end_addresses
                    end_addresses[new_end_addr].append(new_node)

                # Modify the CFG
                original_predecessors = list(graph.in_edges([n], data=True))
                original_successors = list(graph.out_edges([n], data=True))

                for _, d, data in original_successors:
                    ins_addr = data.get('ins_addr', data.get('pseudo_ins_addr', None))
                    if ins_addr is not None and ins_addr < d.addr:
                        continue
                    if d not in graph[smallest_node]:
                        if d is n:
                            graph.add_edge(smallest_node, new_node, **data)
                        else:
                            graph.add_edge(smallest_node, d, **data)

                for p, _, _ in original_predecessors:
                    graph.remove_edge(p, n)
                graph.remove_node(n)

                # update local_blocks
                if n.addr in self._local_blocks and self._local_blocks[n.addr].size != new_node.size:
                    del self._local_blocks[n.addr]
                    self._local_blocks[n.addr] = new_node

                # update block_cache and block_sizes
                if (n.addr in self._block_cache and self._block_cache[n.addr].size != new_node.size) or \
                        (n.addr in self._block_sizes and self._block_sizes[n.addr] != new_node.size):
                    # the cache needs updating
                    self._block_cache.pop(n.addr, None)
                    self._block_sizes[n.addr] = new_node.size

                for p, _, data in original_predecessors:
                    if p not in other_nodes:
                        graph.add_edge(p, new_node, **data)

                # We should find the correct successor
                new_successors = [i for i in all_nodes
                                  if i.addr == smallest_node.addr]
                if new_successors:
                    new_successor = new_successors[0]
                    graph.add_edge(new_node, new_successor,
                                   type="transition",
                                   outside=is_outside_node,
                                   # it's named "pseudo_ins_addr" because we have no way to know what the actual last
                                   # instruction is at this moment (without re-lifting the block, which would be a
                                   # waste of time).
                                   pseudo_ins_addr=new_node.addr + new_node.size - 1,
                                   )
                else:
                    # We gotta create a new one
                    l.error('normalize(): Please report it to Fish/maybe john.')

            end_addresses[end_addr] = [smallest_node]

        # Rebuild startpoint
        if self.startpoint.size != self._block_sizes[self.startpoint.addr]:
            self.startpoint = self.get_node(self.startpoint.addr)

        # Clear the cache
        self._local_transition_graph = None

        self.normalized = True
def normalize ( self ) : # let's put a check here if self . startpoint is None : # this function is empty l . debug ( 'Unexpected error: %s does not have any blocks. normalize() fails.' , repr ( self ) ) return graph = self . transition_graph end_addresses = defaultdict ( list ) for block in self . nodes : if isinstance ( block , BlockNode ) : end_addr = block . addr + block . size end_addresses [ end_addr ] . append ( block ) while any ( len ( x ) > 1 for x in end_addresses . values ( ) ) : end_addr , all_nodes = next ( ( end_addr , x ) for ( end_addr , x ) in end_addresses . items ( ) if len ( x ) > 1 ) all_nodes = sorted ( all_nodes , key = lambda node : node . size ) smallest_node = all_nodes [ 0 ] other_nodes = all_nodes [ 1 : ] is_outside_node = False if smallest_node not in graph : is_outside_node = True # Break other nodes for n in other_nodes : new_size = get_real_address_if_arm ( self . _project . arch , smallest_node . addr ) - get_real_address_if_arm ( self . _project . arch , n . addr ) if new_size == 0 : # This is the node that has the same size as the smallest one continue new_end_addr = n . addr + new_size # Does it already exist? new_node = None if new_end_addr in end_addresses : nodes = [ i for i in end_addresses [ new_end_addr ] if i . addr == n . addr ] if len ( nodes ) > 0 : new_node = nodes [ 0 ] if new_node is None : # TODO: Do this correctly for hook nodes # Create a new one new_node = BlockNode ( n . addr , new_size , graph = graph , thumb = n . thumb ) self . _block_sizes [ n . addr ] = new_size self . _addr_to_block_node [ n . addr ] = new_node # Put the newnode into end_addresses end_addresses [ new_end_addr ] . append ( new_node ) # Modify the CFG original_predecessors = list ( graph . in_edges ( [ n ] , data = True ) ) original_successors = list ( graph . out_edges ( [ n ] , data = True ) ) for _ , d , data in original_successors : ins_addr = data . get ( 'ins_addr' , data . get ( 'pseudo_ins_addr' , None ) ) if ins_addr is not None and ins_addr < d . addr : continue if d not in graph [ smallest_node ] : if d is n : graph . add_edge ( smallest_node , new_node , * * data ) else : graph . add_edge ( smallest_node , d , * * data ) for p , _ , _ in original_predecessors : graph . remove_edge ( p , n ) graph . remove_node ( n ) # update local_blocks if n . addr in self . _local_blocks and self . _local_blocks [ n . addr ] . size != new_node . size : del self . _local_blocks [ n . addr ] self . _local_blocks [ n . addr ] = new_node # update block_cache and block_sizes if ( n . addr in self . _block_cache and self . _block_cache [ n . addr ] . size != new_node . size ) or ( n . addr in self . _block_sizes and self . _block_sizes [ n . addr ] != new_node . size ) : # the cache needs updating self . _block_cache . pop ( n . addr , None ) self . _block_sizes [ n . addr ] = new_node . size for p , _ , data in original_predecessors : if p not in other_nodes : graph . add_edge ( p , new_node , * * data ) # We should find the correct successor new_successors = [ i for i in all_nodes if i . addr == smallest_node . addr ] if new_successors : new_successor = new_successors [ 0 ] graph . add_edge ( new_node , new_successor , type = "transition" , outside = is_outside_node , # it's named "pseudo_ins_addr" because we have no way to know what the actual last # instruction is at this moment (without re-lifting the block, which would be a # waste of time). pseudo_ins_addr = new_node . addr + new_node . size - 1 , ) else : # We gotta create a new one l . error ( 'normalize(): Please report it to Fish/maybe john.' ) end_addresses [ end_addr ] = [ smallest_node ] # Rebuild startpoint if self . startpoint . size != self . _block_sizes [ self . startpoint . addr ] : self . startpoint = self . get_node ( self . startpoint . addr ) # Clear the cache self . _local_transition_graph = None self . normalized = True