![](/img/trans.png)
[英]Frama-C plugin development: Extract value analysis result as OCaml integers
[英]Frama-C Plugin development: Getting result of value-analysis
我正在使用價值分析為 Frama-C 開發一個插件。 我只是想在每個語句后打印變量(值)的 state(我認為解決方案很簡單,但我想不出來)。
我在訪問者的vstmt_aux
方法中使用Db.Value.get_stmt_state
獲得了當前的 state。
我現在如何獲取變量的值?
PS:我找到了這篇文章,但沒有幫助,沒有真正的解決方案,並且在描述的幫助下我無法做到: How to use functions in Value.Eval_expr, Value.Eval_op etc modules of Frama-c 值插件
下面是一個具體的例子,說明如何為每個本地和全局變量打印在給定函數中的每個語句之前由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測試。
要檢索語句之后的狀態下,只需更換~after:false
參數fold_state_callstack
與~after:true
。 我以前的代碼版本使用了一個函數,該函數已經為前置狀態綁定了該值,但是沒有為后置狀態導出這樣的函數,所以我們必須使用fold_state_callstack
(順便說一下,它更強大,因為它允許檢索特定的每個callstack的狀態)。
這是對先前答案的更新,使用 Eva 的新 API,自 Frama-C 25.0(鎂)起可用; 我根據舊的 Frama-C 版本為用戶留下了原始答案。
使用Eva的新API,上面的答案可以寫得更簡潔:
(* Prints the value associated to variable [vi] before [stmt]. *)
let pretty_vi fmt stmt vi =
let req = Eva.Results.before stmt in
let cvalue = Eva.Results.(eval_var vi req |> as_cvalue) in
Format.fprintf fmt "%a -> %a@." Printer.pp_varinfo vi
Cvalue.V.pretty cvalue (* print mapping *)
(* 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
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...@.";
Eva.Analysis.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!@.")
請注意,output 並不相同; 它實際上更簡潔,例如,而不是打印score -> {{ NULL -> {0} }}
,這意味着,對於 location score
,與 NULL 基相關聯的偏移量,即常數值,是0 ,它只是打印score -> {0}
。 它還根據變量類型打印最小/最大邊界(例如int __fc_errno
在前面的代碼中被打印為無界區間[--..--]
;這里使用時打印為[-2147483648..2147483647]
具有 32 位整數的 machdep)。
新的 API 還可以更輕松地回答諸如Is there also a way to get the values after the statement? 之類的查詢。 :只需使用Eva.Results.after
而不是Eva.Results.before
。
最后,對於特定於調用堆棧的信息,請在src/plugins/value/utils/results.mli
文件中搜索callstack
。 該文件還包含一些解釋 API 的冗長注釋,以及一個用法草圖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.