(self, max_analyzing_callsites: int=3)
return facts
Analyze all call sites of the function and determine the possible number of arguments and if the function
        returns anything or not.
Analyze all call sites of the function and determine the possible number of arguments and if the function
        returns anything or not.
Analyze all call sites of the function and determine the possible number of arguments and if the function returns anything or not .
def _analyze_callsites(self, max_analyzing_callsites: int=3) -> List[CallSiteFact]:  # pylint:disable=no-self-use
        """
        Analyze all call sites of the function and determine the possible number of arguments and if the function
        returns anything or not.
        """

        if self._cfg is None:
            l.warning("CFG is not provided. Skip calling convention analysis at call sites.")
            return []

        node = self._cfg.get_any_node(self._function.addr)
        if node is None:
            l.warning("%r is not in the CFG. Skip calling convention analysis at call sites.", self._function)

        facts = [ ]
        in_edges = self._cfg.graph.in_edges(node, data=True)

        call_sites_by_function: Dict['Function',List[Tuple[int,int]]] = defaultdict(list)
        for src, _, data in in_edges:
            edge_type = data.get('jumpkind', 'Ijk_Call')
            if edge_type != 'Ijk_Call':
                continue
            if not self.project.kb.functions.contains_addr(src.function_address):
                continue
            caller = self.project.kb.functions[src.function_address]
            if caller.is_simprocedure:
                # do not analyze SimProcedures
                continue
            call_sites_by_function[caller].append((src.addr, src.instruction_addrs[-1]))

        call_sites_by_function_list = list(call_sites_by_function.items())[:max_analyzing_callsites]
        ctr = 0

        for caller, call_site_tuples in call_sites_by_function_list:
            if ctr >= max_analyzing_callsites:
                break

            # generate a subgraph that only contains the basic block that does the call and the basic block after the
            # call.
            for call_site_tuple in call_site_tuples:
                caller_block_addr, call_insn_addr = call_site_tuple
                func = self.project.kb.functions[caller.addr]
                subgraph = self._generate_callsite_subgraph(func, caller_block_addr)

                rda = self.project.analyses.ReachingDefinitions(
                    func,
                    func_graph=subgraph,
                    observation_points=[
                        ('insn', call_insn_addr, OP_BEFORE),
                        ('node', caller_block_addr, OP_AFTER)
                    ],
                )
                # rda_model: Optional[ReachingDefinitionsModel] = self.kb.defs.get_model(caller.addr)
                fact = self._analyze_callsite(caller_block_addr, call_insn_addr, rda.model)
                facts.append(fact)

                ctr += 1
                if ctr >= max_analyzing_callsites:
                    break

        return facts
def _analyze_callsites ( self , max_analyzing_callsites : int = 3 ) -> List [ CallSiteFact ] : # pylint:disable=no-self-use if self . _cfg is None : l . warning ( "CFG is not provided. Skip calling convention analysis at call sites." ) return [ ] node = self . _cfg . get_any_node ( self . _function . addr ) if node is None : l . warning ( "%r is not in the CFG. Skip calling convention analysis at call sites." , self . _function ) facts = [ ] in_edges = self . _cfg . graph . in_edges ( node , data = True ) call_sites_by_function : Dict [ 'Function' , List [ Tuple [ int , int ] ] ] = defaultdict ( list ) for src , _ , data in in_edges : edge_type = data . get ( 'jumpkind' , 'Ijk_Call' ) if edge_type != 'Ijk_Call' : continue if not self . project . kb . functions . contains_addr ( src . function_address ) : continue caller = self . project . kb . functions [ src . function_address ] if caller . is_simprocedure : # do not analyze SimProcedures continue call_sites_by_function [ caller ] . append ( ( src . addr , src . instruction_addrs [ - 1 ] ) ) call_sites_by_function_list = list ( call_sites_by_function . items ( ) ) [ : max_analyzing_callsites ] ctr = 0 for caller , call_site_tuples in call_sites_by_function_list : if ctr >= max_analyzing_callsites : break # generate a subgraph that only contains the basic block that does the call and the basic block after the # call. for call_site_tuple in call_site_tuples : caller_block_addr , call_insn_addr = call_site_tuple func = self . project . kb . functions [ caller . addr ] subgraph = self . _generate_callsite_subgraph ( func , caller_block_addr ) rda = self . project . analyses . ReachingDefinitions ( func , func_graph = subgraph , observation_points = [ ( 'insn' , call_insn_addr , OP_BEFORE ) , ( 'node' , caller_block_addr , OP_AFTER ) ] , ) # rda_model: Optional[ReachingDefinitionsModel] = self.kb.defs.get_model(caller.addr) fact = self . _analyze_callsite ( caller_block_addr , call_insn_addr , rda . model ) facts . append ( fact ) ctr += 1 if ctr >= max_analyzing_callsites : break return facts