Reputation: 165
I have read these two posts: Getting result of value analysis and Getting the values of statement. These two posts provide invaluable information on how to print the values of the value analysis.
However, my task requires me to extract the integers stored in the value variable, and then do some math with the integers (I am only concerned with integer values). For example, if the value analysis result for some variable is {1, 2}, I want to get the result as an OCaml list of integers: [1, 2]. This way I can do math with it. If the result involves an interval, I assume I can define a type to handle it. For example,
type point_or_interval =
| Point of int
| Interval of int * int
The type of the value variable is defined as type t = Cvalue.V.t
in the documentation. I have not been able to find this module in the source, so I do not know how to manipulate the value and extract the information that I need. How should I do this? A code illustration will be appreciated!
Edit:
I have tried the following code. This code is copied verbatim from Getting result of value analysis, with only some modifications in the pretty_vi
function. It is not working with my test input program - Locations.Location_Bytes.find_lonely_key
function raises Not_found
exception. My input program is also attached.
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 *)
let base, offset = Locations.Location_Bytes.find_lonely_key value in
(match offset with
| Ival.Set _ -> ()
| Ival.Float _ -> ()
| Ival.Top (_, _, _, _ )-> ());
Format.fprintf fmt "%a -> %a@." Printer.pp_varinfo vi
Db.Value.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!@.")
Test input program:
#include <stdio.h>
int main() {
int a = 1;
return 0;
}
What is the problem with this code? Why is the mapping of the value not found?
Upvotes: 1
Views: 143
Reputation: 8953
General remark: if you are using an editor which supports Merlin, I seriously recommend using it. It makes it easier to find in which module things are defined, which types are synonyms, and, combined with an auto-completion tool, Merlin allows you to find conversion functions much more easily.
In particular, Merlin should help you find out that Cvalue.V.project_ival : V.t -> Ival.t
converts a V.t
into an Ival.t
(assuming the value is convertible, e.g. it is not a pointer).
Ival.t
is a sophisticated interval-like value that can represent:
Ival.Float
);Ival.Set
);Ival.Top
, despite the name), with congruence information and optional bounds, e.g. [9..--]1%4
represents {x ∈ ℕ | x ≥ 9 ∧ x mod 4 = 1}
.Function Ival.min_and_max : Ival.t -> Integer.t option * Integer.t option
takes an Ival.t
and returns (assuming the interval does not contain a floating-point interval) a pair (maybe_min, maybe_max)
, where maybe_min
is None
if there is no lower bound (minus infinity), or Some min
otherwise, and symmetrically for maybe max
. It works both with Ival.Set
and Ival.Top
.
Note that Integer.t
are not machine integers, but an implementation of arbitrary-precision integers.
Upvotes: 3