Ocaml Frama-C插件开发:获得价值分析结果

Ocaml Frama-C插件开发:获得价值分析结果,ocaml,frama-c,value-analysis,Ocaml,Frama C,Value Analysis,我正在使用价值分析为Frama-C开发一个插件。 我只想在每条语句之后打印变量(值)的状态(我认为解决方案非常简单,但我无法理解) 我在访问者的vstmt\u aux方法中使用Db.Value.get\stmt\u state获取当前状态 现在如何获取变量的值 PS:我找到了这篇文章,但没有帮助,没有真正的解决方案,在描述的帮助下,我无法做到: 以下是一个具体示例,说明如何为每个局部和全局变量打印给定函数中每个语句前的值计算的结果(从下到上阅读函数): 这远远不够理想,输出比简单地使用Cvalu

我正在使用价值分析为Frama-C开发一个插件。 我只想在每条语句之后打印变量(值)的状态(我认为解决方案非常简单,但我无法理解)

我在访问者的
vstmt\u aux
方法中使用
Db.Value.get\stmt\u state
获取当前状态

现在如何获取变量的值

PS:我找到了这篇文章,但没有帮助,没有真正的解决方案,在描述的帮助下,我无法做到:
以下是一个具体示例,说明如何为每个局部和全局变量打印给定函数中每个语句前的值计算的结果(从下到上阅读函数):

这远远不够理想,输出比简单地使用
Cvalue.Model.pretty state
更糟糕,但它可以作为进一步修改的基础

该脚本已使用Frama-C镁进行了测试


要在语句之后检索状态,只需将
fold\u state\u callstack
中的
~after:false
参数替换为
~after:true
。我以前版本的代码使用了一个函数,该函数已经为pre状态绑定了该值,但没有为post状态导出这样的函数,因此我们必须使用
fold\u state\u callstack
(顺便说一句,它更强大,因为它允许检索每个callstack的特定状态).

Db.Value.get\stmt\u state返回的状态不是从变量到抽象值的映射,但它的功能更强大,因此获取变量的值稍微复杂一些。尽管如此,针对相关问题的解决方案中的评论似乎确实得出了这样的结论:它是有效的。请您指定您使用的Frama-C的版本好吗?@anol是正确的。如果您只对标量变量的值感兴趣,只需提供
(Var x,NoOffset)
作为
lval\u to_loc
lval
参数,假设
x
是您感兴趣的Frama-C变量(
varinfo
)lv什么是lv?Kstmt是cast还是类似的东西?
lv
lval
(C左值)的缩写,
(Kstmt stmt)
只是构建一个值,它们彼此不相关(除了两者都是
访问
函数的参数这一事实)。我在下面的代码中也做了同样的操作,但在几行代码中,可能会更清晰。尽管如此,如果您不习惯OCaml表示法,查看其中一些可能会很有用,因为Frama-C使用了几个OCaml概念(命名和可选参数、访客类、
格式
等)。谢谢,这正是我想要的:)还有一个问题:为什么输出的格式是c->{{NULL->{17}}}这个NULL是什么?(之前是否为空?)
null
与这些变量都不是指针这一事实有关,因此它们的
Base
(如文件
Base.ml
中定义的)是
null
,这是常量使用的基础。您可以添加一行
int*p=&c并将其打印,您将看到它将打印类似于
p->{{c->{0}}}
,这表明
p
的值实际上是偏移量为0的基
c
。在我的简单代码中,
NULL
确实很难看,它是默认格式化程序
Cvalue.Model.pretty正确打印的内容之一。我编辑代码以使用更通用的函数,该函数还允许在语句后检索状态。代码稍大一些,但功能更强大。
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!@.")