From bba61bda772b3e1d24cc61c8a26aadce50f945f9 Mon Sep 17 00:00:00 2001 From: Valentin Perrelle <valentin.perrelle@cea.fr> Date: Wed, 28 Aug 2019 17:30:51 +0200 Subject: [PATCH] [Dive] More input checks and use of Yojson --- src/plugins/dive/build.ml | 19 ++++--- src/plugins/dive/build.mli | 9 ++- src/plugins/dive/imprecision_graph.ml | 76 ++++++++++++------------- src/plugins/dive/server_interface.ml | 82 +++++++++++++++++++++------ 4 files changed, 122 insertions(+), 64 deletions(-) diff --git a/src/plugins/dive/build.ml b/src/plugins/dive/build.ml index ba98a800bf7..d7bdb9f1076 100644 --- a/src/plugins/dive/build.ml +++ b/src/plugins/dive/build.ml @@ -252,7 +252,7 @@ let is_hidden context node_kind = | Some vi when BaseSet.mem vi context.hidden_bases -> true | _ -> false -let get_node context node_key = +let find_node context node_key = Index.find context.vertex_table node_key let update_node context node = @@ -601,16 +601,21 @@ let add_alarm ?(depth=1) context stmt alarm = let node = build_alarm context callstack stmt alarm in complete_in_depth ~depth context node -let explore_from_vertex ~depth context node_key = - explore ~depth context (get_node context node_key) +let add_function_alarms ?(depth=1) context kf = + let add_one_alarm _emitter kf' stmt ~rank:_ alarm _code_annot = + if Kernel_function.equal kf' kf then + add_alarm ~depth context stmt alarm + in + Alarms.iter add_one_alarm + +let explore_from_node ~depth context node = + explore ~depth context node -let show ?(depth=1) context node_key = - let node = get_node context node_key in +let show ?(depth=1) context node = node.node_hidden <- false; explore ~depth context node -let hide context node_key = - let node = get_node context node_key in +let hide context node = if not node.node_hidden then begin let g = get_graph context in diff --git a/src/plugins/dive/build.mli b/src/plugins/dive/build.mli index e3e345a3e82..7bd5f3af5ad 100644 --- a/src/plugins/dive/build.mli +++ b/src/plugins/dive/build.mli @@ -34,12 +34,15 @@ val fold_base : t -> Cil_types.varinfo -> unit val hide_base : t -> Cil_types.varinfo -> unit val unhide_base : t -> Cil_types.varinfo -> unit +val find_node : t -> int -> Graph_types.node + val add_lval : ?depth:int -> t -> Cil_types.kinstr -> Cil_types.lval -> unit val add_var : ?depth:int -> t -> Cil_types.varinfo -> unit val add_alarm : ?depth:int -> t -> Cil_types.stmt -> Alarms.alarm -> unit -val explore_from_vertex : depth:int -> t -> int -> unit +val add_function_alarms : ?depth:int -> t -> Cil_types.kernel_function -> unit +val explore_from_node : depth:int -> t -> Graph_types.node -> unit -val show : ?depth:int -> t -> int -> unit -val hide : t -> int -> unit +val show : ?depth:int -> t -> Graph_types.node -> unit +val hide : t -> Graph_types.node -> unit val take_last_differences : t -> Graph_types.graph_diff diff --git a/src/plugins/dive/imprecision_graph.ml b/src/plugins/dive/imprecision_graph.ml index 86edf4c918c..9efa403a971 100644 --- a/src/plugins/dive/imprecision_graph.ml +++ b/src/plugins/dive/imprecision_graph.ml @@ -248,17 +248,17 @@ let ouptput_to_dot out_channel g = module JsonPrinter = struct let output_kinstr = function - | Cil_types.Kglobal -> Json.of_string "global" - | Cil_types.Kstmt stmt -> Json.of_int stmt.Cil_types.sid + | Cil_types.Kglobal -> `String "global" + | Cil_types.Kstmt stmt -> `Int stmt.Cil_types.sid let output_callsite (kf,kinstr) = - Json.of_fields [ - ("fun", Json.of_string (Kernel_function.get_name kf)) ; + `Assoc [ + ("fun", `String (Kernel_function.get_name kf)) ; ("instr", output_kinstr kinstr) ; ] let output_callstack cs = - Json.of_list (List.map output_callsite cs) + `List (List.map output_callsite cs) let output_node_kind kind = let s = match kind with @@ -267,15 +267,15 @@ struct | Scattered _ -> "scattered" | Alarm _ -> "alarm" in - Json.of_string s + `String s let output_node_locality { loc_file ; loc_callstack } = - let f1 = ("file", Json.of_string loc_file) in + let f1 = ("file", `String loc_file) in let fields = match loc_callstack with | [] -> [f1] | cs -> [f1 ; ("callstack", output_callstack cs)] in - Json.of_fields fields + `Assoc fields let output_node_precision_grade grade = let s = match grade with @@ -283,7 +283,7 @@ struct | Normal -> "normal" | Wide -> "wide" in - Json.of_string s + `String s let output_dep_kind kind = let s = match kind with @@ -293,30 +293,30 @@ struct | Control -> "ctrl" | Composition -> "comp" in - Json.of_string s + `String s let output_int_interval interval = (* TODO: handle overflow *) - Json.of_fields [ - ("min", Json.of_int (Integer.to_int interval.min)) ; - ("max", Json.of_int (Integer.to_int interval.max)) ; + `Assoc [ + ("min", `Int (Integer.to_int interval.min)) ; + ("max", `Int (Integer.to_int interval.max)) ; ] let output_float_interval interval = - Json.of_fields [ - ("min", Json.of_float interval.min) ; - ("max", Json.of_float interval.max) ; + `Assoc [ + ("min", `Float interval.min) ; + ("max", `Float interval.max) ; ] let output_node_int_values values = - Json.of_fields [ + `Assoc [ ("computed", output_int_interval values.values_interval) ; ("limits", output_int_interval values.values_limits) ; ("grade", output_node_precision_grade values.values_grade) ; ] let output_node_float_values values = - Json.of_fields [ + `Assoc [ ("computed", output_float_interval values.values_interval) ; ("limits", output_float_interval values.values_limits) ; ("grade", output_node_precision_grade values.values_grade) ; @@ -324,12 +324,12 @@ struct let output_node node = let label = Pretty_utils.to_string Node_kind.pretty node.node_kind in - Json.of_fields ([ - ("id", Json.of_int node.node_key) ; - ("label", Json.of_string label) ; + `Assoc ([ + ("id", `Int node.node_key) ; + ("label", `String label) ; ("kind", output_node_kind node.node_kind) ; ("locality", output_node_locality node.node_locality) ; - ("explored", Json.of_bool node.node_deps_computed) ; + ("explored", `Bool node.node_deps_computed) ; ] @ begin match node.node_int_values with | None -> [] @@ -346,22 +346,22 @@ struct | Some lval -> let typ = Cil.typeOfLval lval in let str = Pretty_utils.to_string Cil_printer.pp_typ typ in - [("type", Json.of_string str)] + [("type", `String str)] end) let output_dep (n1,dep,n2) = - Json.of_fields [ - ("id", Json.of_int dep.dependency_key) ; - ("src", Json.of_int n1.node_key) ; - ("dst", Json.of_int n2.node_key) ; + `Assoc [ + ("id", `Int dep.dependency_key) ; + ("src", `Int n1.node_key) ; + ("dst", `Int n2.node_key) ; ("kind", output_dep_kind dep.dependency_kind) ; - ("multiple", Json.of_bool dep.dependency_multiple) + ("multiple", `Bool dep.dependency_multiple) ] let output_graph g = - Json.of_fields [ - ("nodes", Json.of_list (List.map output_node (vertices g))) ; - ("deps", Json.of_list (List.map output_dep (edges g))) + `Assoc [ + ("nodes", `List (List.map output_node (vertices g))) ; + ("deps", `List (List.map output_dep (edges g))) ] let output_diff g diff = @@ -380,19 +380,19 @@ struct let set = List.fold_left collect_deps Set.empty diff.added_nodes in List.map output_dep (Set.elements set) and removed_nodes = - List.map (fun node -> Json.of_int node.node_key) diff.removed_nodes + List.map (fun node -> `Int node.node_key) diff.removed_nodes in - Json.of_fields [ - ("add", Json.of_fields [ - ("nodes", Json.of_list added_nodes) ; - ("deps", Json.of_list added_deps) + `Assoc [ + ("add", `Assoc [ + ("nodes", `List added_nodes) ; + ("deps", `List added_deps) ]) ; - ("sub", Json.of_list removed_nodes)] + ("sub", `List removed_nodes)] end let ouptput_to_json out_channel g = let json = JsonPrinter.output_graph g in - Json.save_channel ~pretty:true out_channel json + Yojson.Basic.to_channel out_channel json let to_json g = JsonPrinter.output_graph g diff --git a/src/plugins/dive/server_interface.ml b/src/plugins/dive/server_interface.ml index 23cebe7468d..d1d8dfd9d22 100644 --- a/src/plugins/dive/server_interface.ml +++ b/src/plugins/dive/server_interface.ml @@ -34,8 +34,8 @@ let get_graph = g -let page = Doc.page (`Plugin "Dive") - ~title:"Dive into dependency graph" +let page = Doc.page (`Plugin "dive") + ~title:"Dive Services" ~filename:"dive.md" module Graph = @@ -55,8 +55,8 @@ end module Variable = Data.Collection (struct module Info = struct let page = page - let name = "variable" - let descr = Markdown.rm "Variable from the program" + let name = "dive-variable-name" + let descr = Markdown.rm "The name of variable of the program" end module R = Data.Record (Info) @@ -75,7 +75,7 @@ module Variable = Data.Collection (struct let to_json v = let varname = v.Cil_types.vname in - let fields = [ "var" , `String varname ] in + let fields = [ "var", `String varname ] in let fields = match Kernel_function.find_defining_kf v with | Some kf -> ("fun", `String (Kernel_function.get_name kf)) :: fields | None -> fields @@ -83,11 +83,12 @@ module Variable = Data.Collection (struct `Assoc fields let of_json json = + let open Yojson.Basic.Util in try let funname = - try Some (Json.(string (field "fun" json))) + try Some (json |> member "fun" |> to_string) with Not_found -> None - and varname = Json.(string (field "var" json)) in + and varname = json |> member "var" |> to_string in match funname with | Some name -> let kf = @@ -116,6 +117,44 @@ module Variable = Data.Collection (struct Data.failure json "Invalid source format" end) +module Function = Data.Collection (struct + type t = Cil_types.kernel_function + + let syntax = Syntax.publish ~page ~name:"dive-function-name" + ~synopsis:Syntax.string + ~descr:(Markdown.rm "The name of a function of the program") () + + let to_json kf = + `String (Kernel_function.get_name kf) + + let of_json json = + let open Yojson.Basic.Util in + let name = to_string json in + try + Globals.Functions.find_by_name name + with Not_found -> + Data.failure json "no function '%s'" name + end) + +module Node = Data.Collection (struct + type t = Graph_types.node + + let syntax = Syntax.publish ~page ~name:"dive-node" + ~synopsis:Syntax.int + ~descr:(Markdown.rm "A node identifier in the graph") () + + let to_json node = + `Int node.Graph_types.node_key + + let of_json json = + let open Yojson.Basic.Util in + let node_key = to_int json in + try + Build.find_node (get_graph ()) node_key + with Not_found -> + Data.failure json "no node '%d' in the current graph" node_key + end) + let () = Request.register ~page ~kind:`GET ~name:"dive.graph" @@ -140,34 +179,45 @@ let () = Request.register ~page Build.get_graph g, Build.take_last_differences g end +let () = Request.register ~page + ~kind:`EXEC ~name:"dive.add_function_alarms" + ~descr:(Markdown.rm "Add all alarms of the given function") + ~input:(module Function) ~output:(module GraphDiff) + begin fun kf -> + let depth = Self.DepthLimit.get () in + let g = get_graph () in + Build.add_function_alarms ~depth g kf; + Build.get_graph g, Build.take_last_differences g + end + let () = Request.register ~page ~kind:`EXEC ~name:"dive.explore" ~descr:(Markdown.rm "Explore the graph starting from an existing vertex") - ~input:(module Data.Jint) ~output:(module GraphDiff) - begin fun node_key -> + ~input:(module Node) ~output:(module GraphDiff) + begin fun node -> let depth = Self.DepthLimit.get () in let g = get_graph () in - Build.explore_from_vertex ~depth g node_key; + Build.explore_from_node ~depth g node; Build.get_graph g, Build.take_last_differences g end let () = Request.register ~page ~kind:`EXEC ~name:"dive.show" ~descr:(Markdown.rm "Show the dependencies of an existing vertex") - ~input:(module Data.Jint) ~output:(module GraphDiff) - begin fun node_key -> + ~input:(module Node) ~output:(module GraphDiff) + begin fun node -> let depth = Self.DepthLimit.get () in let g = get_graph () in - Build.show ~depth g node_key; + Build.show ~depth g node; Build.get_graph g, Build.take_last_differences g end let () = Request.register ~page ~kind:`EXEC ~name:"dive.hide" ~descr:(Markdown.rm "Hide the dependencies of an existing vertex") - ~input:(module Data.Jint) ~output:(module GraphDiff) - begin fun node_key -> + ~input:(module Node) ~output:(module GraphDiff) + begin fun node -> let g = get_graph () in - Build.hide g node_key; + Build.hide g node; Build.get_graph g, Build.take_last_differences g end \ No newline at end of file -- GitLab