Frama-C插件开发:将值分析结果提取为OCaml整数

Frama-C插件开发:将值分析结果提取为OCaml整数,ocaml,frama-c,Ocaml,Frama C,我读过这两篇帖子: 和。这两篇文章提供了关于如何打印价值分析值的宝贵信息 但是,我的任务要求我提取存储在value变量中的整数,然后对这些整数进行一些计算(我只关心整数值)。例如,如果某个变量的值分析结果为{1,2},我希望将结果作为整数的OCaml列表:[1,2]。这样我就可以用它做数学了。如果结果包含一个区间,我假设我可以定义一个类型来处理它。比如说, type point_or_interval = | Point of int | Interval of int * int 在文档中,

我读过这两篇帖子: 和。这两篇文章提供了关于如何打印价值分析值的宝贵信息

但是,我的任务要求我提取存储在value变量中的整数,然后对这些整数进行一些计算(我只关心整数值)。例如,如果某个变量的值分析结果为{1,2},我希望将结果作为整数的OCaml列表:[1,2]。这样我就可以用它做数学了。如果结果包含一个区间,我假设我可以定义一个类型来处理它。比如说,

type point_or_interval =
| Point of int
| Interval of int * int
在文档中,值变量的类型定义为
type t=Cvalue.V.t
。我在源代码中找不到这个模块,所以我不知道如何操作值和提取我需要的信息。我该怎么做?代码说明将不胜感激

编辑: 我尝试了以下代码。此代码是逐字复制的,只需对
pretty_vi
函数进行一些修改。它不适用于我的测试输入程序-
Locations.Location\u Bytes.find\u lonely\u key
函数引发
not\u found
异常。我的输入程序也附后了

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!@.")
测试输入程序:

#include <stdio.h>

int main() {
    int a = 1;
    return 0;
}
#包括
int main(){
INTA=1;
返回0;
}

这个代码有什么问题?为什么找不到值的映射?

一般说明:如果您使用的是支持的编辑器,我郑重建议您使用它。它可以更容易地找到在哪个模块中定义的东西,哪些类型是同义词,并且,结合自动完成工具,Merlin允许您更容易地找到转换函数

特别是,Merlin应该帮助您发现
Cvalue.V.project\u ival:V.t->ival.t
V.t
转换为
ival.t
(假设该值是可转换的,例如它不是指针)

Ival.t
是一个复杂的类似区间的值,可以表示:

  • 浮点值的连续间隔(
    Ival.Float
  • 一小组整数值(
    Ival.set
  • 或实际的整数间隔(
    Ival.Top
    ,尽管名称不同),带有同余信息和可选边界,例如
    [9..-]1%4
    表示
    {x∈ ℕ | x≥ 9∧ x mod 4=1}
函数
Ival.min\u和\u max:Ival.t->Integer.t option*Integer.t option
接受
Ival.t
并返回(假设区间不包含浮点区间)一对
(可能_min,可能_max)
,其中
可能_min
的,如果没有下限(负无穷),或者
一些最小值
否则,对于
可能是最大值
对称。它同时适用于
Ival.Set
Ival.Top


请注意,
Integer.t
不是机器整数,而是任意精度整数的实现。

请看一下
src/plugins/value\u types/cvalue.mli
?谢谢@这是可以理解的!我已经写了一些代码,但它不适用于我的输入程序。你知道我的代码有什么问题吗?我编辑了我的问题,并附上了代码。我的代码更像是一个快速的“黑客”解决方案,给出了总体思路,而不是一个实际的防弹代码。特别是,每当文档说类似于
raise@Not\u found other
(如
find\u lonely\u key
)的话时,您必须使用
进行一次尝试,在这种情况下,您应该将其打印为空。通过添加足够多的漂亮打印(例如,捕获
未找到
并打印当前语句和varinfo),您将发现第一个语句之前的变量
a
为空,或者该变量
\u retres
(在CIL创建的规范化代码中)在第一个语句之后为空,但在第二个语句之前为空。因此,正确处理空状态应该可以解决这两种情况。但是,您还必须处理有多个基的情况,等等。