Frama-C 插件开发:将值分析结果提取为 OCaml 整数
Frama-C plugin development: Extract value analysis result as OCaml integers
我已经阅读了这两个帖子:
和 。这两篇文章提供了关于如何打印价值分析的价值的宝贵信息。
但是,我的任务要求我提取存储在值变量中的整数,然后用这些整数做一些数学运算(我只关心整数值)。例如,如果某个变量的值分析结果是 {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_Bytes.find_lonely_key
函数引发 Not_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;
}
这段代码有什么问题?为什么找不到值的映射?
一般说明:如果您使用的编辑器支持Merlin,我强烈建议您使用它。它可以更容易地找到在哪个模块中定义的东西,哪些类型是同义词,并且结合自动完成工具,Merlin 可以让您更容易地找到转换函数。
特别是,Merlin 应该可以帮助您发现 Cvalue.V.project_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_and_max : Ival.t -> Integer.t option * Integer.t option
取一个Ival.t
和returns(假设区间不包含浮点区间)一对(maybe_min, maybe_max)
,其中maybe_min
如果没有下界(负无穷大)则为 None
,否则为 Some min
,并且对于 maybe max
是对称的。它适用于 Ival.Set
和 Ival.Top
.
请注意 Integer.t
不是机器整数,而是任意精度整数的实现。
我已经阅读了这两个帖子:
但是,我的任务要求我提取存储在值变量中的整数,然后用这些整数做一些数学运算(我只关心整数值)。例如,如果某个变量的值分析结果是 {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_Bytes.find_lonely_key
函数引发 Not_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;
}
这段代码有什么问题?为什么找不到值的映射?
一般说明:如果您使用的编辑器支持Merlin,我强烈建议您使用它。它可以更容易地找到在哪个模块中定义的东西,哪些类型是同义词,并且结合自动完成工具,Merlin 可以让您更容易地找到转换函数。
特别是,Merlin 应该可以帮助您发现 Cvalue.V.project_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_and_max : Ival.t -> Integer.t option * Integer.t option
取一个Ival.t
和returns(假设区间不包含浮点区间)一对(maybe_min, maybe_max)
,其中maybe_min
如果没有下界(负无穷大)则为 None
,否则为 Some min
,并且对于 maybe max
是对称的。它适用于 Ival.Set
和 Ival.Top
.
请注意 Integer.t
不是机器整数,而是任意精度整数的实现。