简体   繁体   中英

Frama-C plugin development: Extract value analysis result as OCaml integers

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.Vt 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?

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 : Vt -> Ival.t converts a Vt into an Ival.t (assuming the value is convertible, eg it is not a pointer).

Ival.t is a sophisticated interval-like value that can represent:

  • a contiguous interval of floating-point values ( Ival.Float );
  • a small set of integer values ( Ival.Set );
  • or an actual integer interval ( Ival.Top , despite the name), with congruence information and optional bounds, eg [9..--]1%4 represents {x ∈ ℕ | x ≥ 9 ∧ x mod 4 = 1} {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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM