123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)(* ************************************************************************** *)(* Topological iterators *)(* ************************************************************************** *)moduleMake(G:Graph.Sig.GwithtypeV.t=Kernel_function.t)(N:sigvalname:stringend)=struct(* Topological iterations are memoized in order to improve efficiency when
calling them several times. This has been proved to have a significant
impact in practice. *)moduleS=State_builder.Queue(Kernel_function)(structletname="Callgraph.Uses"^N.nameletdependencies=[Cg.self]end)moduleT=Graph.Topological.Make_stable(G)letitergf=(* Warns if [-cg-no-function-pointers] is in effect, which may lead
to unsound analyses for the users of the callgraph. *)ifnot(Options.Function_pointers.get())thenOptions.warning~once:true"using callgraph while option %s is unset, \
result may be unsound"Options.Function_pointers.name;ifS.is_empty()thenT.iterS.addg;S.iterfendletiter_in_order=letmoduleI=Make(Cg.G)(structletname="iter_in_order"end)infunf->I.iter(Cg.get())fletiter_in_rev_order=letmoduleI=Make(structincludeCg.G(* inverse operations over successors required by
[Graph.Topological.G] *)letiter_succ=iter_predletin_degree=out_degreeend)(structletname="iter_in_rev_order"end)infunf->I.iter(Cg.get())flet_iter_in_rev_order=Dynamic.register~comment:"Iterate over all the functions in the callgraph in reverse order"~plugin:Options.name"iter_in_rev_order"Datatype.(func(funcKernel_function.tyunit)unit)iter_in_rev_orderletiter_on_auxiter_dirfkf=letcg=Cg.get()inifCg.G.mem_vertexcgkfthenletvisited=Kernel_function.Hashtbl.create17inletrecauxkf=iter_dir(funkf'->ifnot(Kernel_function.Hashtbl.memvisitedkf')thenbeginfkf';Kernel_function.Hashtbl.addvisitedkf'();auxkf'end)cgkfinauxkfletiter_on_callers=iter_on_auxCg.G.iter_predletiter_on_callees=iter_on_auxCg.G.iter_succletnb_calls()=letg=Cg.get()in(* [g] contains bidirectional edges (from caller to callee and
conversely). Conseqently each function call is counted twice. *)Cg.G.nb_edgesg/2(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)