diff --git a/src/plugins/wp/RegionDump.ml b/src/plugins/wp/RegionDump.ml new file mode 100644 index 0000000000000000000000000000000000000000..500f578937befa044fc06b796043f2dfef2ff5bf --- /dev/null +++ b/src/plugins/wp/RegionDump.ml @@ -0,0 +1,303 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2024 *) +(* CEA (Commissariat a l'energie atomique et aux energies *) +(* 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). *) +(* *) +(**************************************************************************) + +[@@@ warning "-32"] + +module Wp = Wp_parameters +(* +module G = Dotgraph +module R = G.Node(Region.Map) +*) +let node_default = [`Attr("fontname","monospace")] +let edge_default = [`Attr("fontname","monospace")] + +let attr_offset = [ `Filled ; `Color "grey" ; `Box ] +let attr_write = [ `Label "W" ; `Fillcolor "green" ; `Filled ] +let attr_read = [ `Label "R" ; `Fillcolor "green" ; `Filled ] +let attr_alias = [ `Label "&" ; `Fillcolor "orange" ; `Filled ] +let attr_merge = [ `Color "red" ; `Fillcolor "red" ; `Filled ] +let attr_shift = [ `Label "[]" ] +let attr_delta = [ `Filled ; `Color "lightblue" ; `Box ] +let attr_deref = [ `ArrowHead "tee" ] +let attr_cil = [ `Filled ; `Fillcolor "yellow" ] +let attr_region = `Shape "tab" :: attr_cil +let attr_var = `Shape "cds" :: attr_cil +let attr_garbled = [`Fillcolor "red";`Filled] +let attr_froms = [ `Color "blue" ; `Attr("dir","back") ] + +let attr_pointed = [ + `Color "red" +] + +let attr_pointed_deref = [ + `Attr("taillabel","*"); + `Attr("labelangle","+30"); + `Color "red"; +] + +let attr_pointed_shift = [ + `Attr("taillabel","[..]"); + `Attr("labeldistance","1.7"); + `Attr("labelangle","+40"); + `Color "red"; +] + +let rid_key = Wp.register_category "rid" +let dot_key = Wp.register_category "dot" +let pdf_key = Wp.register_category "pdf" +let deref_key = Wp.register_category "deref" +let roots_key = Wp.register_category "roots" +let froms_key = Wp.register_category "froms" +let cluster_key = Wp.register_category "cluster" +let chunk_key = Wp.register_category "chunk" +let offset_key = Wp.register_category "offset" + +(* +let sfprintf = Format.asprintf + +let dotpointed ~label r = + let attr = + if Region.is_shifted r + then attr_pointed_shift else attr_pointed_deref in + let target = G.port (R.get r) "w" in + `Port ("",["",attr,target],label) + +let dotvalue ?(prefix="") value : Dotgraph.record = + let open Layout in + match value with + | Int i -> `Label (sfprintf "%s%a" prefix Ctypes.pp_int i) + | Float f -> `Label (sfprintf "%s%a" prefix Ctypes.pp_float f) + | Pointer r -> dotpointed ~label:(prefix ^ "ptr") r + +let dotrange ?(prefix="") rg : Dotgraph.record = + let open Layout in + let pp_dim fmt = function + | Raw _ -> Format.pp_print_string fmt "raw" + | Dim(s,ds) -> Format.fprintf fmt "%d%a" s Matrix.pretty ds + in + let label = sfprintf "%d..%d: %s%a" + rg.ofs (rg.ofs + rg.len - 1) + prefix pp_dim rg.dim in + `Port("",["",[`Dotted],R.get rg.reg],label) + +let dotcluster cluster : Dotgraph.record = + let open Layout in + match cluster with + | Empty -> `Label "-" + | Garbled -> `Label "Garbled" + | Chunk v -> dotvalue v + | Layout { sizeof ; layout } -> + let label = Printf.sprintf "sizeof:%d" sizeof in + `Hbox (`Label label :: List.map dotrange layout) + +let dotchunk mem : Dotgraph.record = + let open Layout in + match mem with + | Mraw(_,None) -> `Label "Raw" + | Mraw(_,Some r) -> dotpointed ~label:"Raw" r + | Mref r -> dotpointed ~label:"Ref" r + | Mmem(rt,v) -> + let prefix = if Layout.Root.indexed rt then "Mem " else "Var " in + dotvalue ~prefix v + | Mcomp(_,ovl) -> + let range rg = dotrange + ~prefix:(if Overlay.once rg.reg ovl then "D" else "C") rg in + `Hbox (List.map range ovl) + +let dotregion dot map region node = + begin + let is_read = Region.is_read region in + let is_written = Region.is_written region in + let is_aliased = Region.is_aliased region in + let is_accessed = is_read || is_written || is_aliased in + let has_deref = Wp.has_dkey deref_key && Region.has_deref region in + let has_roots = Wp.has_dkey roots_key && Region.has_roots map region in + let has_index_infos = has_deref || has_roots in + let has_side_cluster = + is_accessed || + has_index_infos || + Region.has_names region || + Wp.has_dkey offset_key || + Wp.has_dkey rid_key || + not (Wp.has_dkey cluster_key || Wp.has_dkey chunk_key) || + not (Wp.Region_fixpoint.get ()) + in + if has_side_cluster then + begin + let attr = G.decorate [ `Oval ] [ + is_read , attr_read ; + Region.has_pointed region , [ `Label "D" ] ; + is_written , attr_write ; + Region.is_shifted region , attr_shift ; + is_aliased , attr_alias ; + Region.get_alias map region != region , attr_merge ; + Region.is_garbled region , attr_merge ; + ] in + G.node dot node attr ; + end ; + if Wp.has_dkey offset_key then + Region.iter_offset map + (fun offset target -> + let label = Pretty_utils.to_string Layout.Offset.pretty offset in + let delta = G.inode dot (`Label label :: attr_offset) in + G.link dot [node;delta;R.get target] [`Dotted] + ) region ; + if Wp.has_dkey offset_key then + Option.iter + (fun target -> + let label = if Region.is_shifted target then "[..]" else "*" in + let deref = G.inode dot (`Label label :: attr_offset) in + G.link dot [node;deref;R.get target] attr_pointed + ) (Region.get_pointed map region) ; + if has_index_infos then + begin + let derefs = ref [] in + let label s = derefs := s :: !derefs in + if has_roots then + label @@ sfprintf "roots:%a" + Layout.Root.pretty (Region.get_roots map region) ; + if has_deref then + Region.iter_deref + (fun deref -> + label @@ Pretty_utils.to_string Layout.Deref.pretty deref + ) region ; + if !derefs <> [] then + begin + let label = String.concat "\n" (List.rev !derefs) in + let delta = G.inode dot (`Label label :: attr_delta) in + G.rank dot [node;delta] ; + G.edge dot delta node attr_deref + end + end ; + if Wp.has_dkey cluster_key then + begin + let cluster = Region.cluster map region in + if not (has_side_cluster && Layout.Cluster.is_empty cluster) then + let record = dotcluster cluster in + let attr = if Region.is_garbled region then attr_garbled else [] in + if has_side_cluster then + let delta = G.irecord dot ~attr record in + G.edge dot node (G.port delta "w") attr_deref + else + G.record dot node ~attr record + end ; + if Wp.has_dkey chunk_key then + begin + let chunk = Region.chunk map region in + let record = dotchunk chunk in + let attr = if Region.is_garbled region then attr_garbled else [] in + if has_side_cluster then + let delta = G.irecord dot ~attr record in + G.edge dot node (G.port delta "w") attr_deref + else + G.record dot node ~attr record + end ; + if Wp.has_dkey froms_key then + begin + let open Layout in + List.iter + (function + | Fvar _ -> () + | Farray r -> + G.edge dot (R.get r) node (`Label "[]"::attr_froms) + | Fderef r -> + G.edge dot (R.get r) node (`Label "*"::attr_froms) + | Findex r -> + G.edge dot (R.get r) node (`Label "+(..)"::attr_froms) + | Ffield(r,ofs) -> + let label = Printf.sprintf "+%d" ofs in + G.edge dot (R.get r) node (`Label label::attr_froms) + ) (Region.get_froms map region) + end ; + Region.iter_copies map + (fun target -> + G.edge dot node (R.get target) [`Color "green"] + ) region ; + Option.iter + (fun target -> + G.edge dot node (R.get target) [`Color "red"] + ) (Region.get_merged map region) ; + end + +let dotvar dot x r = + begin + let open Cil_types in + let xnode = G.inode dot ~prefix:"V" (`Label x.vname :: attr_var) in + G.edge dot (G.port xnode "e") (R.get r) [] ; + end + +let dotlabel dot a r = + begin + let anode = G.inode dot ~prefix:"R" (`Label a :: attr_region) in + let rnode = R.get r in + G.rank dot [ anode ; rnode ] ; + G.edge dot anode rnode [] + end + +let dotrid dot r = + dotlabel dot (Pretty_utils.to_string Region.R.pretty r) r + +let dotstr dot r cst = + dotlabel dot (String.escaped cst) r + +let dotgraph dot map = + begin + G.node_default dot node_default ; + G.edge_default dot edge_default ; + R.clear () ; + R.define dot (dotregion dot map) ; + Region.iter_vars map (dotvar dot) ; + Region.iter_strings map (dotstr dot) ; + G.run dot ; + if Wp.has_dkey rid_key then Region.iter map (dotrid dot) ; + Region.iter_names map (dotlabel dot) ; + if Region.has_return map then + dotlabel dot "\\result" (Region.of_return map) ; + Region.iter_fusion map (fun i r -> + let rid = Region.id r in + if i <> rid then + dotlabel dot (Printf.sprintf "Fusion R%03d" i) r + else + dotlabel dot "Fusion (Self)" r + ) ; + G.run dot ; + end + +let dump_in_file ~file name map = + if Wp.has_dkey dot_key || Wp.has_dkey pdf_key then + begin + let file = Pretty_utils.to_string Datatype.Filepath.pretty file in + let dot = Dotgraph.open_dot ~attr:[`LR] ~name ~file () in + dotgraph dot map ; + Dotgraph.close dot ; + let outcome = + if Wp.has_dkey pdf_key + then Dotgraph.layout dot + else file in + Wp.result "Region Graph: %s" outcome + end + +let dump_in_dir ~dir name map = + let file = Datatype.Filepath.concat dir (name ^ ".dot") in + dump_in_file ~file name map + +*) diff --git a/src/plugins/wp/RegionDump.mli b/src/plugins/wp/RegionDump.mli new file mode 100644 index 0000000000000000000000000000000000000000..44ac5d848f5ef3f0c9c7c25b9e27e67bbc8eb3e5 --- /dev/null +++ b/src/plugins/wp/RegionDump.mli @@ -0,0 +1,29 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2024 *) +(* CEA (Commissariat a l'energie atomique et aux energies *) +(* 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). *) +(* *) +(**************************************************************************) + +(* Dump region graphs to dir according to -wp options. + By default, does nothing. *) +(* +val dump_in_dir : dir:Datatype.Filepath.t -> string -> Region.map -> unit + +val dump_in_file : file:Datatype.Filepath.t -> string -> Region.map -> unit +*)