【问题标题】:Frama-C Plugin development: Getting result of value-analysisFrama-C 插件开发:获取价值分析结果
【发布时间】:2016-03-23 03:22:00
【问题描述】:

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

我在访问者的vstmt_aux 方法中使用Db.Value.get_stmt_state 获得了当前状态。

我现在如何获取变量的值?

PS:我找到了这篇文章,但没有帮助,没有真正的解决方案,并且在描述的帮助下我无法做到: How to use functions in Value.Eval_expr, Value.Eval_op etc modules of Frama-c Value plugin

【问题讨论】:

  • Db.Value.get_stmt_state 返回的状态不是从 变量 到抽象值的映射,但它比这更强大,因此获取变量的值。也就是说,链接问题的解决方案中的 cmets 似乎确实得出结论认为它有效。您能否具体说明您使用的是哪个版本的 Frama-C?
  • @anol 是对的。如果您只对标量变量的值感兴趣,只需提供(Var x, NoOffset) 作为lval_to_loclval 参数,假设x 是您感兴趣的Frama-C 变量(varinfo)。
  • 在你提到的评论中,这部分文字是什么:(Kstmt stmt) lv什么是lv? Kstmt 是演员还是类似的东西?
  • lvlval 的缩写(一个C lvalue),而(Kstmt stmt) 只是构建一个值,它们彼此之间没有关联(除了事实上两者都是access 函数的参数)。我在下面的代码中做了同样的事情,但在几行中,也许会更清楚。尽管如此,如果你不习惯 OCaml 表示法,复习其中的一些可能会很有用,因为 Frama-C 使用了几个 OCaml 概念(命名和可选参数、访问者等事物的类、Format 等)

标签: ocaml frama-c value-analysis


【解决方案1】:

这是一个具体示例,说明如何为每个局部和全局变量打印由给定函数中每个语句之前的 Value 计算的结果(从下到上读取函数):

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!@.")

这远非理想,而且输出比简单地使用Cvalue.Model.pretty state 更丑陋,但它可以作为进一步修改的基础。

这个脚本已经用 Frama-C Magnesium 测试过。

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

【讨论】:

  • 谢谢,这正是我想要的:)
  • 还有没有办法获取语句后的值?
  • 还有一个问题:为什么输出格式为:c -> {{ NULL -> {17} }} 这个NULL是什么? (之前不为空?)
  • NULL 与这些变量都不是指针这一事实有关,因此它们的Base(在文件base.ml 中定义)是NULL,这是基础用于常量。例如,您可以添加一行int *p = &c; 并打印它,您会看到它会打印出类似p -> {{ c -> {0} }} 的内容,这表明p 的值实际上是偏移量为0 的基础c。@ 987654335@ 在我的简单代码中确实很难看,它是默认格式化程序Cvalue.Model.pretty 正确打印的东西之一。
  • 我编辑了代码以使用更通用的函数,该函数还允许在语句之后检索状态。代码稍大,但功能更强大。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多