3

I am working on a Plugin for Frama-C, using the Value-analysis. I simply want to print the state of the variables (values) after each statement (I think the solution is quiet easy, but I couldn't figure it out).

I got the current state with Db.Value.get_stmt_state in the vstmt_aux method in the visitor.

How can I now get the values of the variables?

PS: I found this post, but it didn't help, there is no real solution, and with the help of the description I was not able to do it: How to use functions in Value.Eval_expr, Value.Eval_op etc modules of Frama-c Value plugin

Community
  • 1
  • 1
Thomas Böhm
  • 1,456
  • 1
  • 15
  • 27
  • 2
    The state returned by `Db.Value.get_stmt_state` is not a mapping from *variables* to abstract values, but it is more powerful than that, hence why it is slightly more complex to obtain the value for a variable. That said, the comments in the solution for the linked question do seem to conclude that it worked. Could you please specify which version of Frama-C you're using? – anol Mar 21 '16 at 16:36
  • @anol is right. If you are only interested in the values of scalar variables, simply supply `(Var x, NoOffset)` as the `lval` argument of `lval_to_loc`, assuming that `x` is the Frama-C variable (`varinfo`) you are interested in. – byako Mar 21 '16 at 16:59
  • In the comment you mentioned, what is this part of the text: `(Kstmt stmt) lv` What is lv? Is Kstmt a cast or something like that? – Thomas Böhm Mar 21 '16 at 19:45
  • `lv` is short for `lval` (a C *lvalue*), and `(Kstmt stmt)` is simply building a value, they are not related to each other (other than the fact that both are arguments to the `access` function). I do the same in my code below, but in several lines, maybe it would be clearer. Still, if you're not used to OCaml notation, it may be useful to review some of it, because Frama-C uses several OCaml concepts (named and optional parameters, classes for things such as visitors, `Format`, etc.) – anol Mar 21 '16 at 20:58

2 Answers2

8

Here's a concrete example of how to print, for each local and global variable, the result computed by Value before each statement in a given function (read the functions from bottom to top):

open Cil_types

(* Prints the value associated to variable [vi] before [stmt]. *)
let pretty_vi fmt stmt vi =
  let kinstr = Kstmt stmt in (* make a kinstr from a stmt *)
  let lval = (Var vi, NoOffset) in (* make an lval from a varinfo *)
  let loc = (* make a location from a kinstr + an lval *)
    !Db.Value.lval_to_loc kinstr ~with_alarms:CilE.warn_none_mode lval
  in
  Db.Value.fold_state_callstack
    (fun state () ->
       (* for each state in the callstack *)
       let value = Db.Value.find state loc in (* obtain value for location *)
       Format.fprintf fmt "%a -> %a@." Printer.pp_varinfo vi
         Locations.Location_Bytes.pretty value (* print mapping *)
    ) () ~after:false kinstr

(* Prints the state at statement [stmt] for each local variable in [kf],
   and for each global variable. *)
let pretty_local_and_global_vars kf fmt stmt =
  let locals = Kernel_function.get_locals kf in
  List.iter (fun vi -> pretty_vi fmt stmt vi) locals;
  Globals.Vars.iter (fun vi _ -> pretty_vi fmt stmt vi)

(* Visits each statement in [kf] and prints the result of Value before the
   statement. *)
class stmt_val_visitor kf =
  object (self)
    inherit Visitor.frama_c_inplace
    method! vstmt_aux stmt =
      (match stmt.skind with
       | Instr _ ->
         Format.printf "state for all variables before stmt: %a@.%a@."
           Printer.pp_stmt stmt (pretty_local_and_global_vars kf) stmt
       | _ -> ());
      Cil.DoChildren
  end

(* usage: frama-c file.c -load-script print_vals.ml *)
let () =
  Db.Main.extend (fun () ->
      Format.printf "computing value...@.";
      !Db.Value.compute ();
      let fun_name = "main" in
      Format.printf "visiting function: %s@." fun_name;
      let kf_vis = new stmt_val_visitor in
      let kf = Globals.Functions.find_by_name fun_name in
      let fundec = Kernel_function.get_definition kf in
      ignore (Visitor.visitFramacFunction (kf_vis kf) fundec);
      Format.printf "done!@.")

This is far from ideal, and the output is uglier than simply using Cvalue.Model.pretty state, but it could serve as base for further modifications.

This script has been tested with Frama-C Magnesium.

To retrieve the state after a statement, simply replace the ~after:false parameter in fold_state_callstack with ~after:true. My previous version of the code used a function which already bound that value for the pre-state, but no such function is exported for the post-state, so we must use fold_state_callstack (which is incidentally more powerful, because it allows retrieving a specific state per callstack).

anol
  • 8,264
  • 3
  • 34
  • 78
  • Thanks, that was exactly what I was looking for :) – Thomas Böhm Mar 22 '16 at 08:37
  • Is there also a way to get the values after the statement? – Thomas Böhm Mar 22 '16 at 09:38
  • And another question: Why is the output in format: c -> {{ NULL -> {17} }} What is this NULL? (it is not null before?) – Thomas Böhm Mar 22 '16 at 12:59
  • 1
    The `NULL` is related to the fact that none of these variables is a pointer, therefore their `Base` (as defined in the file `base.ml`) is `NULL`, which is the base used for constants. You can add a line `int *p = &c;` for instance and print it, and you'll see that it will print something like `p -> {{ c -> {0} }}`, indicating that the value of `p` is actually the base `c` with offset 0. The `NULL` is indeed ugly in my simple code, and it's one of the things that is correctly pretty-printed by the default formatter, `Cvalue.Model.pretty`. – anol Mar 22 '16 at 18:45
  • I edited the code to use a more generic function which also allows retrieving the state after a statement. The code is slightly larger, but more powerful. – anol Mar 22 '16 at 19:22
  • How do i use that Cvalue.Model.pretty? I can't just call it with value, and I'm not able to find out where to get the parameters needed for that function. – Thomas Böhm Mar 24 '16 at 11:23
  • Frama-C has lots of `pretty` functions which are based on OCaml formatters, with the usage of `%a` placeholders. For instance, if `state` contains a Value state (as in my example code), then `Format.printf "%a" Cvalue.Model.pretty state;` will pretty-print the entire state (with every variable contained in it). It might be worth asking a separate question about how to pretty-print a Value state, I could add a simplified version of the above code (i.e. because it already prints all variables, you do not have to iterate over them). – anol Mar 24 '16 at 17:47
0

Update using Eva's new API (since Frama-C 25.0)

This is an update to the previous answer, using Eva's new API, available since Frama-C 25.0 (Magnesium); I left the original answer for users based on older Frama-C versions.

Using Eva's new API, the above answer can be written more succinctly:

(* Prints the value associated to variable [vi] before [stmt]. *)
let pretty_vi fmt stmt vi =
  let req = Eva.Results.before stmt in
  let cvalue = Eva.Results.(eval_var vi req |> as_cvalue) in
  Format.fprintf fmt "%a -> %a@." Printer.pp_varinfo vi
    Cvalue.V.pretty cvalue (* print mapping *)

(* Prints the state at statement [stmt] for each local variable in [kf],
   and for each global variable. *)
let pretty_local_and_global_vars kf fmt stmt =
  let locals = Kernel_function.get_locals kf in
  List.iter (fun vi -> pretty_vi fmt stmt vi) locals;
  Globals.Vars.iter (fun vi _ -> pretty_vi fmt stmt vi)

(* Visits each statement in [kf] and prints the result of Value before the
   statement. *)
class stmt_val_visitor kf =
  object
    inherit Visitor.frama_c_inplace
    method! vstmt_aux stmt =
      (match stmt.skind with
       | Instr _ ->
         Format.printf "state for all variables before stmt: %a@.%a@."
           Printer.pp_stmt stmt (pretty_local_and_global_vars kf) stmt
       | _ -> ());
      Cil.DoChildren
  end

(* usage: frama-c file.c -load-script print_vals.ml *)
let () =
  Db.Main.extend (fun () ->
      Format.printf "computing value...@.";
      Eva.Analysis.compute ();
      let fun_name = "main" in
      Format.printf "visiting function: %s@." fun_name;
      let kf_vis = new stmt_val_visitor in
      let kf = Globals.Functions.find_by_name fun_name in
      let fundec = Kernel_function.get_definition kf in
      ignore (Visitor.visitFramacFunction (kf_vis kf) fundec);
      Format.printf "done!@.")

Note that the output is not identical; it is actually more condensed, as in, instead of printing e.g. score -> {{ NULL -> {0} }}, which means, for location score, the offset associated to the NULL base, that is, a constant value, is 0, it simply prints score -> {0}. It also prints minimum/maximum bounds according to the variable type (e.g. int __fc_errno was printed as an unbounded interval [--..--] with the previous code; here, it is printed as [-2147483648..2147483647] when using a machdep with 32-bit integers).

The new API also makes it easier to answer queries such as Is there also a way to get the values after the statement?: just use Eva.Results.after instead of Eva.Results.before.

Finally, for callstack-specific information, search for callstack in the src/plugins/value/utils/results.mli file. This file also contains some lenghty comments explaining the API, as well as a usage sketch.

anol
  • 8,264
  • 3
  • 34
  • 78