Newer
Older

Loïc Correnson
committed
(**************************************************************************)
(* *)
(* This file is part of Frama-C. *)
(* *)

Loïc Correnson
committed
(* 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). *)
(* *)
(**************************************************************************)
open Data
module Md = Markdown

Loïc Correnson
committed
module Senv = Server_parameters
(* -------------------------------------------------------------------------- *)
(* --- Frama-C Parameters --- *)
(* -------------------------------------------------------------------------- *)
let package =
Package.package ~name:"parameters" ~title:"All Frama-C parameters" ()
(* Translates a parameter name into a valid camlCase request. *)
let camlCaseParameter name =
match String.split_on_char '-' name with
| "" :: head :: tail ->
List.fold_left (^) head (List.map String.capitalize_ascii tail)
| _ -> Senv.fatal "Invalid parameter %s" name
(* Registers a synchronized state for the given parameter. *)
let register_parameter parameter =
let open Typed_parameter in
let parameter_name = parameter.name in
let descr = Md.plain ("State of parameter " ^ parameter_name) in
let name = camlCaseParameter parameter_name in
let register data accessor =
let add_hook f = accessor.add_update_hook (fun _ x -> f x) in
ignore
(States.register_state ~package ~name ~descr
~data ~get:accessor.get ~set:accessor.set ~add_hook ())
in
match parameter.accessor with
| Bool (accessor, _) -> register (module Data.Jbool) accessor
| Int (accessor, _) -> register (module Data.Jint) accessor
| Float (accessor, _) -> register (module Data.Jfloat) accessor
| String (accessor, _) -> register (module Data.Jstring) accessor
(* Registers requests for all parameters of the given plugin. *)
let register_plugin_parameters plugin =
let register_group _group list =
let is_visible p = p.Typed_parameter.visible && p.reconfigurable in
List.iter register_parameter (List.filter is_visible list)
in
Hashtbl.iter register_group plugin.Plugin.p_parameters
(* Automatically registers requests for all Frama-C parameters. *)
let register_all () =
(* For now, only registers parameters from the kernel and some plugins. *)
let whitelist = [ "kernel"; "Eva"; "WP"; "rtegen" ] in
let register plugin =
if List.mem plugin.Plugin.p_name whitelist
then register_plugin_parameters plugin
in
Plugin.iter_on_plugins register
let apply_once =
let once = ref true in
fun f () -> if !once then (once := false; f())
let () = Cmdline.run_after_extended_stage (apply_once register_all)

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Frama-C Kernel Services --- *)
(* -------------------------------------------------------------------------- *)
let package = Pkg.package
~name:"services"
~title:"Kernel Services"
~readme:"kernel.md" ()

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Config --- *)
(* -------------------------------------------------------------------------- *)
let signature = Request.signature ~input:(module Junit) () in
Request.result signature ~name ~descr:(Md.plain descr) (module Jstring) in
let result_list name descr =
Request.result signature ~name ~descr:(Md.plain descr) (module Jlist (Jstring)) in
let set_version = result "version" "Frama-C version" in
let set_codename = result "codename" "Frama-C codename" in
let set_version_codename =
result "version_codename" "Frama-C version and codename"
in
let set_datadir = result_list "datadir" "Shared directory (FRAMAC_SHARE)" in
let set_pluginpath = result_list "pluginpath" "Plugin directories (FRAMAC_PLUGIN)" in
Request.register_sig
~package ~kind:`GET ~name:"getConfig"
~descr:(Md.plain "Frama-C Kernel configuration")
signature
set_version rq System_config.Version.id ;
set_codename rq System_config.Version.codename ;
set_version_codename rq System_config.Version.id_and_codename ;
set_datadir rq (Filepath.Normalized.to_string_list System_config.Share.dirs);
set_pluginpath rq
(Filepath.Normalized.to_string_list System_config.Plugins.dirs) ;

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Load saves --- *)
(* -------------------------------------------------------------------------- *)
let () =
Request.register ~package ~kind:`SET ~name:"load"
~descr:(Md.plain "Load a save file. Returns an error, if not successfull.")
~output:(module Joption(Jstring))
let () =
Request.register ~package ~kind:`SET ~name:"save"
~descr:(Md.plain "Save the current session. Returns an error, if not successfull.")
~output:(module Joption(Jstring))
(fun file ->
with Project.IOError err -> Some err)

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Log Lind --- *)
(* -------------------------------------------------------------------------- *)
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
module LogKind =
struct
let kinds = Enum.dictionary ()
let t_kind value name descr =
Enum.tag ~name ~descr:(Md.plain descr) ~value kinds
let t_error = t_kind Log.Error "ERROR" "User Error"
let t_warning = t_kind Log.Warning "WARNING" "User Warning"
let t_feedback = t_kind Log.Feedback "FEEDBACK" "Plugin Feedback"
let t_result = t_kind Log.Result "RESULT" "Plugin Result"
let t_failure = t_kind Log.Failure "FAILURE" "Plugin Failure"
let t_debug = t_kind Log.Debug "DEBUG" "Analyser Debug"
let () = Enum.set_lookup kinds
begin function
| Log.Error -> t_error
| Log.Warning -> t_warning
| Log.Feedback -> t_feedback
| Log.Result -> t_result
| Log.Failure -> t_failure
| Log.Debug -> t_debug
end
let data = Request.dictionary ~package
~name:"logkind"
~descr:(Md.plain "Log messages categories.")
kinds
include (val data : S with type t = Log.kind)
end

Loïc Correnson
committed
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
(* -------------------------------------------------------------------------- *)
(* --- Synchronized array of log events --- *)
(* -------------------------------------------------------------------------- *)
let model = States.model ()
let () = States.column model ~name:"kind"
~descr:(Md.plain "Message kind")
~data:(module LogKind)
~get:(fun (evt, _) -> evt.Log.evt_kind)
let () = States.column model ~name:"plugin"
~descr:(Md.plain "Emitter plugin")
~data:(module Jalpha)
~get:(fun (evt, _) -> evt.Log.evt_plugin)
let () = States.column model ~name:"message"
~descr:(Md.plain "Message text")
~data:(module Jstring)
~get:(fun (evt, _) -> evt.Log.evt_message)
let () = States.option model ~name:"category"
~descr:(Md.plain "Message category (only for debug or warning messages)")
~data:(module Jstring)
~get:(fun (evt, _) -> evt.Log.evt_category)
let () = States.option model ~name:"source"
~descr:(Md.plain "Source file position")
~data:(module Kernel_ast.Position)
~get:(fun (evt, _) -> evt.Log.evt_source)
let getMarker (evt, _id) =
Option.bind evt.Log.evt_source Printer_tag.loc_to_localizable
let getDecl t =
Option.bind (getMarker t) Printer_tag.declaration_of_localizable
let () = States.option model ~name:"marker"
~descr:(Md.plain "Marker at the message position (if any)")
~data:(module Kernel_ast.Marker)
~get:getMarker
let () = States.option model ~name:"decl"
~descr:(Md.plain "Declaration containing the message position (if any)")
~data:(module Kernel_ast.Decl)
~get:getDecl
let iter f = ignore (Messages.fold (fun i evt -> f (evt, i); succ i) 0)
let _array =
States.register_array
~package
~name:"message"
~descr:(Md.plain "Log messages")
~key:(fun (_evt, i) -> string_of_int i)
~iter:iter
~add_reload_hook:Messages.add_global_hook
model

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Log Events --- *)
(* -------------------------------------------------------------------------- *)
module LogEvent =
struct
type rlog
let jlog : rlog Record.signature = Record.signature ()
let kind = Record.field jlog ~name:"kind"
~descr:(Md.plain "Message kind") (module LogKind)
let plugin = Record.field jlog ~name:"plugin"
~descr:(Md.plain "Emitter plugin") (module Jalpha)
let message = Record.field jlog ~name:"message"
~descr:(Md.plain "Message text") (module Jstring)
let category = Record.option jlog ~name:"category"
~descr:(Md.plain "Message category (DEBUG or WARNING)") (module Jstring)
let source = Record.option jlog ~name:"source"
~descr:(Md.plain "Source file position") (module Kernel_ast.Position)
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
let data = Record.publish ~package ~name:"log"
~descr:(Md.plain "Message event record.") jlog
module R : Record.S with type r = rlog = (val data)
type t = Log.event
let jtype = R.jtype
let to_json evt =
R.default |>
R.set plugin evt.Log.evt_plugin |>
R.set kind evt.Log.evt_kind |>
R.set category evt.Log.evt_category |>
R.set source evt.Log.evt_source |>
R.set message evt.Log.evt_message |>
R.to_json
let of_json js =
let r = R.of_json js in
{
Log.evt_plugin = R.get plugin r ;
Log.evt_kind = R.get kind r ;
Log.evt_category = R.get category r ;
Log.evt_source = R.get source r ;
Log.evt_message = R.get message r ;
}

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Log Monitoring --- *)
(* -------------------------------------------------------------------------- *)

Loïc Correnson
committed
let monitoring = ref false
let monitored = ref false
let events : Log.event Queue.t = Queue.create ()

Loïc Correnson
committed
if flag != !monitoring then

Loïc Correnson
committed
if !monitoring && not !monitored then
begin
monitored := true ;
Log.add_listener (fun evt -> if !monitoring then Queue.add evt events)
end
let monitor_server activity =
if not (Senv.AutoLog.get ()) then set_monitoring activity
let monitor_autologs () =
if Senv.AutoLog.get () then
begin
Senv.feedback "Auto-log started." ;
set_monitoring true ;
end

Loïc Correnson
committed
let () =
Main.on monitor_server ;
Cmdline.run_after_configuring_stage monitor_autologs

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Log Requests --- *)
(* -------------------------------------------------------------------------- *)
~descr:(Md.plain "Turn logs monitoring on/off")
~input:(module Jbool) ~output:(module Junit)
set_monitoring
let () = Request.register
~descr:(Md.plain "Flush the last emitted logs since last call (max 100)")
~input:(module Junit) ~output:(module Jlist(LogEvent))
begin fun () ->
let pool = ref [] in
let count = ref 100 in
while not (Queue.is_empty events) && !count > 0 do
decr count ;
pool := Queue.pop events :: !pool
done ;
List.rev !pool
end

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)