(cfg)
return attributes
:param cfg: An angr CFG object
        :returns:    a dictionary of function addresses to tuples of attributes
:param cfg: An angr CFG object
        :returns:    a dictionary of function addresses to tuples of attributes
: param cfg : An angr CFG object : returns : a dictionary of function addresses to tuples of attributes
def _compute_function_attributes(cfg):
        """
        :param cfg: An angr CFG object
        :returns:    a dictionary of function addresses to tuples of attributes
        """
        # the attributes we use are the number of basic blocks, number of edges, and number of subfunction calls
        attributes = dict()
        all_funcs = set(cfg.kb.callgraph.nodes())
        for function_addr in cfg.kb.functions:
            # skip syscalls and functions which are None in the cfg
            if cfg.kb.functions.function(function_addr) is None or cfg.kb.functions.function(function_addr).is_syscall:
                continue
            if cfg.kb.functions.function(function_addr) is not None:
                normalized_funtion = NormalizedFunction(cfg.kb.functions.function(function_addr))
                number_of_basic_blocks = len(normalized_funtion.graph.nodes())
                number_of_edges = len(normalized_funtion.graph.edges())
            else:
                number_of_basic_blocks = 0
                number_of_edges = 0
            if function_addr in all_funcs:
                number_of_subfunction_calls = len(list(cfg.kb.callgraph.successors(function_addr)))
            else:
                number_of_subfunction_calls = 0
            attributes[function_addr] = (number_of_basic_blocks, number_of_edges, number_of_subfunction_calls)

        return attributes
def _compute_function_attributes ( cfg ) : # the attributes we use are the number of basic blocks, number of edges, and number of subfunction calls attributes = dict ( ) all_funcs = set ( cfg . kb . callgraph . nodes ( ) ) for function_addr in cfg . kb . functions : # skip syscalls and functions which are None in the cfg if cfg . kb . functions . function ( function_addr ) is None or cfg . kb . functions . function ( function_addr ) . is_syscall : continue if cfg . kb . functions . function ( function_addr ) is not None : normalized_funtion = NormalizedFunction ( cfg . kb . functions . function ( function_addr ) ) number_of_basic_blocks = len ( normalized_funtion . graph . nodes ( ) ) number_of_edges = len ( normalized_funtion . graph . edges ( ) ) else : number_of_basic_blocks = 0 number_of_edges = 0 if function_addr in all_funcs : number_of_subfunction_calls = len ( list ( cfg . kb . callgraph . successors ( function_addr ) ) ) else : number_of_subfunction_calls = 0 attributes [ function_addr ] = ( number_of_basic_blocks , number_of_edges , number_of_subfunction_calls ) return attributes