4

I want to query the value analysis plugin in Frama-C for instructions to get their value. For each array, it returns the value range of the whole array. For example, if the instruction is array[i] = 1;, I got result = {1} for array[i] from value analysis plugin. Now, for e.g. array[i], I would like to get the variable name i and its value from value analysis.

Below is a sample of my code

class print_VA_result out = object 
inherit Visitor.frama_c_inplace
     (**..*)
 method vstmt_aux s = 
  if Db.Value.is_computed () then
     match s.skind with
    | Instr i ->
       begin
         match i with
         | Set(lval,_,_) ->     
            print_value lval s
         |_ -> "<>"   
 ...

Can anybody help me for this? Thanks a lot in advance.

svick
  • 236,525
  • 50
  • 385
  • 514
user2544482
  • 157
  • 4

1 Answers1

7

I assume that you know how to write a function print_val of type Db.Value.t -> unit The following code, to be placed before your matching on a Set instruction, will catch an access to an array at index e

match i with
(* Access to an array *)
| Set ((_, Index (e, _)), _, _) ->
  let v = !Db.Value.access_expr (Kstmt s) e in
  print_val v 
(* End special case *)
| Set(lval,_,_) ->     
  print_value lval s

Alternatively, if you know the name of your variable, you can use the function Globals.Vars.find_from_astinfo to find the corresponding varinfo vi, and this code to query the contents of the varinfo.

open Cil_types    

let vi_content stmt vi =
  let lv = (Var vi, NoOffset) in
  !Db.Value.access (Kstmt stmt) lv
byako
  • 3,372
  • 2
  • 21
  • 36
  • 1
    I followed the code of value analysis GUI to display the result. It uses `Value.get_stmt_state stmt` for "before value" and `Value.AfterTable.find stmt` for "after value", then maps this to an offsetmap using lval and prints out by that offsetmap. Could you please guide me how to print out the type `Db.Value.t -> unit` as you suggested? – user2544482 Jul 12 '13 at 21:37
  • 2
    Offsetmap copy is useful only for very complicated cases, or to display structured things like structs or arrays. For scalar variables, it is simpler to compute something of type `Db.Value.t` and print it. The function `let print_val v = Format.printf "%a" Db.Value.pretty v` should do the job. – byako Jul 12 '13 at 22:16
  • Hi @BorisYakobowski, Thanks a lot for your anwser. I managed to handle that. By the way, how can we handle for the index of right hand side arrays e.g. get value of j in array1[i] = array2[j] ...? Thanks! – user2544482 Jul 15 '13 at 18:35
  • 2
    Handling a read from an array is similar, except that you must match on the second argument of the `Set` constructor. This argument has type`exp`, so you must look for an expression that is an l-value that is itself an access to an array. `| Set (_, {enode = Lval (_, Index (e, _))}, _) ->` – byako Jul 15 '13 at 21:47
  • Currently, I had two cases: `| Set ((_, Index (e, _)), _, lc) ->` `| Set(lval,_,lc) ->` When adding `| Set (_, {enode = Lval (_, Index (e, _))}, _) ->` as you suggested, the compiler said: `Warning 11: this match case is unused.` In general, I would like to walk through the expression (the second argument) to get every variable there (including array indices) in order to query their values. Do you know any document guiding this? – user2544482 Jul 20 '13 at 13:21
  • You have probably added your new match case after the `| Set(lval,_,_) ->` one, which is strictly more general. Write `Set (_, {enode = ...}, _) -> ... | Set ((_, Index (e, _)), _, _) -> ... | Set (lval, _) -> ...` instead. I'm also updating my answer to explain how to cover all the variables that are assigned. – byako Jul 22 '13 at 20:03