diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/interactive.ml | 62 | ||||
| -rw-r--r-- | src/interactive.mli | 59 | ||||
| -rw-r--r-- | src/interpreter.ml | 2 | ||||
| -rw-r--r-- | src/isail.ml | 109 | ||||
| -rw-r--r-- | src/slice.ml | 70 |
5 files changed, 220 insertions, 82 deletions
diff --git a/src/interactive.ml b/src/interactive.ml index e5fda4cf..cf5c955b 100644 --- a/src/interactive.ml +++ b/src/interactive.ml @@ -1,3 +1,52 @@ +(**************************************************************************) +(* Sail *) +(* *) +(* Copyright (c) 2013-2017 *) +(* Kathyrn Gray *) +(* Shaked Flur *) +(* Stephen Kell *) +(* Gabriel Kerneis *) +(* Robert Norton-Wright *) +(* Christopher Pulte *) +(* Peter Sewell *) +(* Alasdair Armstrong *) +(* Brian Campbell *) +(* Thomas Bauereiss *) +(* Anthony Fox *) +(* Jon French *) +(* Dominic Mulligan *) +(* Stephen Kell *) +(* Mark Wassell *) +(* *) +(* All rights reserved. *) +(* *) +(* This software was developed by the University of Cambridge Computer *) +(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *) +(* (REMS) project, funded by EPSRC grant EP/K008528/1. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in *) +(* the documentation and/or other materials provided with the *) +(* distribution. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *) +(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) +(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *) +(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *) +(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *) +(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *) +(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *) +(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *) +(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *) +(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *) +(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *) +(* SUCH DAMAGE. *) +(**************************************************************************) let opt_interactive = ref false let opt_emacs_mode = ref false @@ -6,3 +55,16 @@ let opt_suppress_banner = ref false let env = ref Type_check.initial_env let ast = ref (Ast.Defs []) + +let ir = ref [] + +let arg str = + ("<" ^ str ^ ">") |> Util.yellow |> Util.clear + +let command str = + (":" ^ str) |> Util.green |> Util.clear + +let commands = ref [] + +let register_command ~name:name ~help:help action = + commands := (":" ^ name, (help, action)) :: !commands diff --git a/src/interactive.mli b/src/interactive.mli index 915193ec..a092ee33 100644 --- a/src/interactive.mli +++ b/src/interactive.mli @@ -1,3 +1,53 @@ +(**************************************************************************) +(* Sail *) +(* *) +(* Copyright (c) 2013-2017 *) +(* Kathyrn Gray *) +(* Shaked Flur *) +(* Stephen Kell *) +(* Gabriel Kerneis *) +(* Robert Norton-Wright *) +(* Christopher Pulte *) +(* Peter Sewell *) +(* Alasdair Armstrong *) +(* Brian Campbell *) +(* Thomas Bauereiss *) +(* Anthony Fox *) +(* Jon French *) +(* Dominic Mulligan *) +(* Stephen Kell *) +(* Mark Wassell *) +(* *) +(* All rights reserved. *) +(* *) +(* This software was developed by the University of Cambridge Computer *) +(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *) +(* (REMS) project, funded by EPSRC grant EP/K008528/1. *) +(* *) +(* Redistribution and use in source and binary forms, with or without *) +(* modification, are permitted provided that the following conditions *) +(* are met: *) +(* 1. Redistributions of source code must retain the above copyright *) +(* notice, this list of conditions and the following disclaimer. *) +(* 2. Redistributions in binary form must reproduce the above copyright *) +(* notice, this list of conditions and the following disclaimer in *) +(* the documentation and/or other materials provided with the *) +(* distribution. *) +(* *) +(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *) +(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *) +(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *) +(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *) +(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *) +(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *) +(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *) +(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *) +(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *) +(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *) +(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *) +(* SUCH DAMAGE. *) +(**************************************************************************) + open Ast open Type_check @@ -8,3 +58,12 @@ val opt_suppress_banner : bool ref val ast : tannot defs ref val env : Env.t ref + +val ir : Jib.cdef list ref + +val arg : string -> string +val command : string -> string + +val commands : (string * (string * (string -> unit))) list ref + +val register_command : name:string -> help:string -> (string -> unit) -> unit diff --git a/src/interpreter.ml b/src/interpreter.ml index 6707bc0b..dd322369 100644 --- a/src/interpreter.ml +++ b/src/interpreter.ml @@ -52,8 +52,6 @@ open Ast open Ast_util open Value - - type gstate = { registers : value Bindings.t; allow_registers : bool; (* For some uses we want to forbid touching any registers. *) diff --git a/src/isail.ml b/src/isail.ml index bb42804a..7db28ddf 100644 --- a/src/isail.ml +++ b/src/isail.ml @@ -55,6 +55,8 @@ open Ast_util open Interpreter open Pretty_print_sail +module Slice = Slice + type mode = | Evaluation of frame | Normal @@ -110,10 +112,24 @@ let vs_ids = ref (val_spec_ids !Interactive.ast) let interactive_state = ref (initial_state !Interactive.ast !Interactive.env Value.primops) -let interactive_bytecode = ref [] - let sep = "-----------------------------------------------------" |> Util.blue |> Util.clear +let () = + let open Interactive in + let open Elf_loader in + let open Printf in + + register_command ~name:"elf" ~help:(sprintf ":elf %s - Load an elf file" (arg "file")) load_elf; + + (fun iarg -> + match Util.split_on_char ' ' iarg with + | [addr_s; filename] -> + let addr = Big_int.of_string addr_s in + load_binary addr filename + | _ -> + printf "Invalid argument for :bin, expected %s %s" (arg "addr") (arg "file") + ) |> register_command ~name:"bin" ~help:(sprintf ":bin %s %s - Load a binary file at a given address" (arg "addr") (arg "file")) + let print_program () = match !current_mode with | Normal | Emacs -> () @@ -230,11 +246,6 @@ let help = | ":help" -> sprintf ":help %s - Get a description of <command>. Commands are prefixed with a colon, e.g. %s." (color yellow "<command>") (color green ":help :type") - | ":elf" -> - sprintf ":elf %s - Load an ELF file." - (color yellow "<file>") - | ":bin" -> - ":bin <address> <file> - Load a binary file at the given address." | ":r" | ":run" -> "(:r | :run) - Completely evaluate the currently evaluating expression." | ":s" | ":step" -> @@ -266,16 +277,15 @@ let help = | ":compile" -> sprintf ":compile %s - Compile AST to a specified target, valid targets are lem, coq, ocaml, c, and ir (intermediate representation)" (color yellow "<target>") - | ":slice" -> - ":slice - Slice AST to the definitions which the functions given by :slice_roots depend on, up to the functions given by :slice_cuts" - | ":thin_slice" -> - ":thin_slice - Slice AST to the function definitions given with :slice_roots" | "" -> sprintf "Type %s for a list of commands, and %s %s for information about a specific command" (color green ":commands") (color green ":help") (color yellow "<command>") | cmd -> - sprintf "Either invalid command passed to help, or no documentation for %s. Try %s." - (color green cmd) (color green ":help :help") + match List.assoc_opt cmd !Interactive.commands with + | Some (help, _) -> help + | None -> + sprintf "Either invalid command passed to help, or no documentation for %s. Try %s." + (color green cmd) (color green ":help :help") let format_pos_emacs p1 p2 contents = let open Lexing in @@ -409,9 +419,10 @@ let handle_input' input = eval_clear := false else print_endline "Invalid argument for :clear, expected either :clear on or :clear off" | ":commands" -> + let more_commands = Util.string_of_list " " fst !Interactive.commands in let commands = [ "Universal commands - :(t)ype :(i)nfer :(q)uit :(v)erbose :prove :assume :clear :commands :help :output :option"; - "Normal mode commands - :elf :(l)oad :(u)nload :let :def :(b)ind :rewrite :rewrites :list_rewrites :compile"; + "Normal mode commands - :elf :(l)oad :(u)nload :let :def :(b)ind :rewrite :rewrites :list_rewrites :compile " ^ more_commands; "Evaluation mode commands - :(r)un :(s)tep :(n)ormal"; ""; ":(c)ommand can be called as either :c or :command." ] @@ -436,18 +447,6 @@ let handle_input' input = interactive_state := initial_state !Interactive.ast !Interactive.env Value.primops | ":pretty" -> print_endline (Pretty_print_sail.to_string (Latex.defs !Interactive.ast)) - | ":ir" -> - print_endline arg; - let open Jib in - let open Jib_util in - let open PPrint in - let is_cdef = function - | CDEF_fundef (id, _, _, _) when Id.compare id (mk_id arg) = 0 -> true - | CDEF_spec (id, _, _) when Id.compare id (mk_id arg) = 0 -> true - | _ -> false - in - let cdefs = List.filter is_cdef !interactive_bytecode in - print_endline (Pretty_print_sail.to_string (separate_map hardline pp_cdef cdefs)) | ":ast" -> let chan = open_out arg in Pretty_print_sail.pp_defs chan !Interactive.ast; @@ -467,7 +466,6 @@ let handle_input' input = | Command (cmd, arg) -> (* Normal mode commands *) begin match cmd with - | ":elf" -> Elf_loader.load_elf arg | ":l" | ":load" -> let files = Util.split_on_char ' ' arg in let (_, ast, env) = load_files !Interactive.env files in @@ -475,16 +473,6 @@ let handle_input' input = interactive_state := initial_state !Interactive.ast !Interactive.env Value.primops; Interactive.env := env; vs_ids := val_spec_ids !Interactive.ast - | ":bin" -> - begin - let args = Util.split_on_char ' ' arg in - match args with - | [addr_s; filename] -> - let addr = Big_int.of_string addr_s in - Elf_loader.load_binary addr filename - | _ -> - print_endline "Invalid argument for :bin, expected <addr> <filename>" - end | ":u" | ":unload" -> Interactive.ast := Ast.Defs []; Interactive.env := Type_check.initial_env; @@ -519,48 +507,6 @@ let handle_input' input = Interactive.ast := append_ast !Interactive.ast ast; Interactive.env := env; interactive_state := initial_state !Interactive.ast !Interactive.env Value.primops; - | ":graph" -> - let format = if arg = "" then "svg" else arg in - let dotfile, out_chan = Filename.open_temp_file "sail_graph_" ".gz" in - let image = Filename.temp_file "sail_graph_" ("." ^ format) in - Slice.dot_of_ast out_chan !Interactive.ast; - close_out out_chan; - let _ = Unix.system (Printf.sprintf "dot -T%s %s -o %s" format dotfile image) in - let _ = Unix.system (Printf.sprintf "xdg-open %s" image) in - () - | ":slice_roots" -> - let args = Str.split (Str.regexp " +") arg in - let ids = List.map mk_id args |> IdSet.of_list in - Specialize.add_initial_calls ids; - slice_roots := IdSet.union ids !slice_roots - | ":slice_cuts" -> - let args = Str.split (Str.regexp " +") arg in - let ids = List.map mk_id args |> IdSet.of_list in - slice_cuts := IdSet.union ids !slice_cuts - | ":slice" -> - let open Slice in - let module SliceNodeSet = Set.Make(Slice.Node) in - let module G = Graph.Make(Slice.Node) in - let g = Slice.graph_of_ast !Interactive.ast in - let roots = !slice_roots |> IdSet.elements |> List.map (fun id -> Function id) |> SliceNodeSet.of_list in - let cuts = !slice_cuts |> IdSet.elements |> List.map (fun id -> Function id) |> SliceNodeSet.of_list in - let g = G.prune roots cuts g in - Interactive.ast := Slice.filter_ast cuts g !Interactive.ast - | ":thin_slice" -> - let open Slice in - let module SliceNodeSet = Set.Make(Slice.Node) in - let module SliceNodeMap = Map.Make(Slice.Node) in - let module G = Graph.Make(Slice.Node) in - let g = Slice.graph_of_ast !Interactive.ast in - let roots = !slice_roots |> IdSet.elements |> List.map (fun id -> Function id) |> SliceNodeSet.of_list in - let keep = function - | (Function id,_) when IdSet.mem id (!slice_roots) -> None - | (Function id,_) -> Some (Function id) - | _ -> None - in - let cuts = SliceNodeMap.bindings g |> Util.map_filter keep |> SliceNodeSet.of_list in - let g = G.prune roots cuts g in - Interactive.ast := Slice.filter_ast cuts g !Interactive.ast | ":list_rewrites" -> let print_rewrite (name, rw) = print_endline (name ^ " " ^ Util.(String.concat " " (describe_rewrite rw) |> yellow |> clear)) @@ -619,7 +565,10 @@ let handle_input' input = | Some f -> f ^ ".sail" in target (Some arg) out_name !Interactive.ast !Interactive.env - | _ -> unrecognised_command cmd + | _ -> + match List.assoc_opt cmd !Interactive.commands with + | Some (_, action) -> action arg + | None -> unrecognised_command cmd end | Expression str -> (* An expression in normal mode is type checked, then puts diff --git a/src/slice.ml b/src/slice.ml index 0011bb4d..1ac390bd 100644 --- a/src/slice.ml +++ b/src/slice.ml @@ -354,3 +354,73 @@ let dot_of_ast out_chan ast = let module NodeSet = Set.Make(Node) in let g = graph_of_ast ast in G.make_dot (node_color NodeSet.empty) edge_color node_string out_chan g + +let () = + let open Printf in + let open Interactive in + let slice_roots = ref IdSet.empty in + let slice_cuts = ref IdSet.empty in + + (fun arg -> + let args = Str.split (Str.regexp " +") arg in + let ids = List.map mk_id args |> IdSet.of_list in + Specialize.add_initial_calls ids; + slice_roots := IdSet.union ids !slice_roots + ) |> register_command + ~name:"slice_roots" + ~help:(sprintf ":slice_roots %s - Set the roots for %s" (arg "identifiers") (command "slice")); + + (fun arg -> + let args = Str.split (Str.regexp " +") arg in + let ids = List.map mk_id args |> IdSet.of_list in + slice_cuts := IdSet.union ids !slice_cuts + ) |> register_command + ~name:"slice_cuts" + ~help:(sprintf ":slice_cuts %s - Set the roots for %s" (arg "identifiers") (command "slice")); + + (fun arg -> + let module NodeSet = Set.Make(Node) in + let module G = Graph.Make(Node) in + let g = graph_of_ast !ast in + let roots = !slice_roots |> IdSet.elements |> List.map (fun id -> Function id) |> NodeSet.of_list in + let cuts = !slice_cuts |> IdSet.elements |> List.map (fun id -> Function id) |> NodeSet.of_list in + let g = G.prune roots cuts g in + ast := filter_ast cuts g !ast + ) |> register_command + ~name:"slice" + ~help:(sprintf ":slice - Slice AST to the definitions which the functions given by %s depend on, up to the functions given by %s" + (command "slice_roots") (command "slice_cuts")); + + (fun arg -> + let module NodeSet = Set.Make(Node) in + let module NodeMap = Map.Make(Node) in + let module G = Graph.Make(Node) in + let g = graph_of_ast !ast in + let roots = !slice_roots |> IdSet.elements |> List.map (fun id -> Function id) |> NodeSet.of_list in + let keep = function + | (Function id,_) when IdSet.mem id (!slice_roots) -> None + | (Function id,_) -> Some (Function id) + | _ -> None + in + let cuts = NodeMap.bindings g |> Util.map_filter keep |> NodeSet.of_list in + let g = G.prune roots cuts g in + ast := filter_ast cuts g !ast + ) |> register_command + ~name:"thin_slice" + ~help:(sprintf ":thin_slice - Slice AST to the function definitions given with %s" (command "slice_roots")); + + (fun arg -> + let format = if arg = "" then "svg" else arg in + let dotfile, out_chan = Filename.open_temp_file "sail_graph_" ".gz" in + let image = Filename.temp_file "sail_graph_" ("." ^ format) in + dot_of_ast out_chan !ast; + close_out out_chan; + let _ = Unix.system (Printf.sprintf "dot -T%s %s -o %s" format dotfile image) in + let _ = Unix.system (Printf.sprintf "xdg-open %s" image) in + () + ) |> register_command + ~name:"graph" + ~help:(sprintf ":graph %s - Draw a callgraph using dot in %s (default svg if none provided), and open with xdg-open" + (arg "format") (arg "format")); + + |
