Frama-C插件开发:将值分析结果提取为OCaml整数
我读过这两篇帖子: 和。这两篇文章提供了关于如何打印价值分析值的宝贵信息 但是,我的任务要求我提取存储在value变量中的整数,然后对这些整数进行一些计算(我只关心整数值)。例如,如果某个变量的值分析结果为{1,2},我希望将结果作为整数的OCaml列表:[1,2]。这样我就可以用它做数学了。如果结果包含一个区间,我假设我可以定义一个类型来处理它。比如说,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 在文档中,
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创建的规范化代码中)在第一个语句之后为空,但在第二个语句之前为空。因此,正确处理空状态应该可以解决这两种情况。但是,您还必须处理有多个基的情况,等等。