123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)openPdg_typesmoduleNodeSet=PdgTypes.NodeSet(** Why is a node impacted. The reasons will be given as [n is impacted
by the effect of [n'], and the impact is of type reason]. *)typereason_type=|IntraproceduralofPdgTypes.Dpd.t(** The effect of [n'] in [f] impact [n], which is also in [f]. *)|InterproceduralDownward(** the effect of [n'] in [f] has an effect on a
callee [f'] of [f], in which [n] is located. *)|InterproceduralUpward(** the effect of [n'] in [f] has an effect on a
caller [f'] of [f] (once the call to [f] has ended), [n] being in [f']. *)moduleReasonType=Datatype.Make(structtypet=reason_typeletname="Impact.Reason_graph.reason_type"letreprs=[InterproceduralDownward]includeDatatype.Serializable_undefinedletcompare(v1:t)(v2:t)=Extlib.compare_basicv1v2lethash(v:t)=Hashtbl.hashvletequal(v1:t)(v2:t)=v1==v2letprettyfmt=function|InterproceduralDownward->Format.pp_print_stringfmt"InterDown"|InterproceduralUpward->Format.pp_print_stringfmt"InterUp"|Intraproceduraldpd->Format.fprintffmt"Intra%a"PdgTypes.Dpd.prettydpdend)(** Reasons for impact are expressed as sets [(n', n, reason)] *)moduleReason=Datatype.Triple_with_collections(PdgTypes.Node)(PdgTypes.Node)(ReasonType)(structletmodule_name="Impact.Reason_graph.Reason.t"end)typereason_graph=Reason.Set.ttypenodes_origin=Cil_types.kernel_functionPdgTypes.Node.Map.ttypereason={reason_graph:reason_graph;nodes_origin:nodes_origin;initial_nodes:Pdg_aux.NS.t;}letempty={reason_graph=Reason.Set.empty;nodes_origin=PdgTypes.Node.Map.empty;initial_nodes=Pdg_aux.NS.empty;}moduleDatatypeReason=Datatype.Make(structincludeDatatype.Serializable_undefinedtypet=reasonletname="Impact.Reason_graph.reason"letreprs=[empty]end)moduletypeAdditionalInfo=sigvalnodes_origin:nodes_originvalinitial_nodes:Pdg_aux.NS.tvalin_kf:Cil_types.kernel_functionoptionendmodulePrinter(X:AdditionalInfo)=structtypet=reason_graphmoduleV=structtypet=PdgTypes.Node.t(* TODO: use better pretty-printer for nodes *)letprettyfmtn=PdgIndex.Key.prettyfmt(PdgTypes.Node.elem_keyn)endmoduleE=structtypet=V.t*V.t*reason_typeletsrc(e,_,_)=eletdst(_,e,_)=eend(* Kernel_function from which a node comes from. May raise [Not_found],
typically for initial nodes. *)letnode_kfn=PdgTypes.Node.Map.findnX.nodes_origin(* Should the edge be displayed. This is decided by finding whether one
of the nodes belong to X.in_kf *)letkeep_edge(n1,n2,_)=matchX.in_kfwith|None->true|Somekf->letin_kfn=tryKernel_function.equalkf(node_kfn)withNot_found->falseinin_kfn1||in_kfn2letiter_vertexfgraph=(* Construct a set, then iter on it. Otherwise, nodes will be seen more
than once. *)letall=Reason.Set.fold(fun(src,dst,_ase)acc->ifkeep_edgeethenNodeSet.addsrc(NodeSet.adddstacc)elseacc)graphNodeSet.emptyinNodeSet.iterfallletiter_edges_efgraph=Reason.Set.iter(fune->ifkeep_edgeethenfe)graphletvertex_namen=Format.sprintf"n%d"(PdgTypes.Node.idn)letgraph_attributes_=[`Label"Impact graph"]letdefault_vertex_attributes_g=[`Style`Filled;`Shape`Box]letdefault_edge_attributes_g=[]letvertex_attributesv=lettxt=Pretty_utils.to_stringV.prettyvinlettxt=ifString.lengthtxt>100thenString.subtxt0100elsetxtinlettxt=Format.asprintf"%S"txtinlettxt=String.subtxt1(String.lengthtxt-2)inletshape=ifPdg_aux.NS.memvX.initial_nodesthen[`Shape`Diamond;`Color0x9090FF]else[]inshape@[`Labeltxt]letedge_attributes(_,_,reason)=letcolor=matchreasonwith|Intraprocedural_->0x2F9F9F|InterproceduralUpward->0x9F2F9F|InterproceduralDownward->0x9F9F2Finletattribs=[`Colorcolor]inmatchreasonwith|Intraproceduraldpd->`Label(Pretty_utils.to_stringPdgTypes.Dpd.prettydpd)::attribs|_->attribsletget_subgraphn=tryletname=Kernel_function.get_name(node_kfn)inletattrs={Graph.Graphviz.DotAttributes.sg_name=name;sg_parent=None;sg_attributes=[`Labelname];}inSomeattrswithNot_found->NoneendmoduleDot(X:AdditionalInfo)=Graph.Graphviz.Dot(Printer(X))letto_dot_formatter?in_kfreasonfmt=letmoduleDot=Dot(structletnodes_origin=reason.nodes_originletinitial_nodes=reason.initial_nodesletin_kf=in_kfend)inKernel.Unicode.without_unicode(Dot.fprint_graphfmt)reason.reason_graph(* May raise [Sys_error] *)letto_dot_file~temp?in_kfreason=letdot_file=tryletfnameext=iftempthenExtlib.temp_file_cleanup_at_exitnameextelseFilename.temp_filenameextinf"impact_reason"".dot"withExtlib.Temp_file_errors->Options.abort"cannot create temporary file: %s"sinletcout=open_outdot_fileinletfmt=Format.formatter_of_out_channelcoutinto_dot_formatter?in_kfreasonfmt;close_outcout;dot_fileletprint_dot_graphreason=tryletdot_file=to_dot_file~temp:falsereasoninOptions.result"Graph output in file '%s'"dot_filewithSys_error_asexn->Options.error"Could not generate impact graph: %s"(Printexc.to_stringexn)(* Very basic textual debugging function *)let_print_reasonreason=letpp_node=Pdg.Api.pretty_nodefalseinletppfmt(nsrc,ndst,reason)=Format.fprintffmt"@[<v 2>%a -> %a (%s)@]"pp_nodensrcpp_nodendst(matchreasonwith|Intraproceduraldpd->Format.asprintf"intra %a"PdgTypes.Dpd.prettydpd|InterproceduralDownward->"downward"|InterproceduralUpward->"upward")inOptions.result"Impact graph:@.%a"(Pretty_utils.pp_iter~pre:"@[<v>"~sep:"@ "~suf:"@]"Reason.Set.iterpp)reason