2016-03-21 6 views
1

Я работаю над плагином для Frama-C, используя Value-analysis. Я просто хочу напечатать состояние переменных (значений) после каждого утверждения (я думаю, что решение тихое, но я не мог понять это).Разработка плагинов Frama-C: получение результата анализа стоимости

Я получил текущее состояние с Db.Value.get_stmt_state в методе vstmt_aux у посетителя.

Как я могу получить значения переменных?

PS: Я нашел этот пост, но это не помогло, нет никакого реального решения, а также с помощью описания я не был в состоянии сделать это: How to use functions in Value.Eval_expr, Value.Eval_op etc modules of Frama-c Value plugin

+2

Состояние, возвращаемое 'Db.Value.get_stmt_state', не является отображением от * переменных * к абстрактным значениям, но оно более сильное, чем это, поэтому почему-то немного сложнее получить значение для переменной. Тем не менее, комментарии в решении связанного вопроса, похоже, заключают, что он сработал. Не могли бы вы указать, какую версию Frama-C вы используете? – anol

+0

@anol - это правильно. Если вас интересуют только значения скалярных переменных, просто поставьте '(Var x, NoOffset)' как аргумент 'lval'' lval_to_loc', считая, что 'x' является переменной Frama-C (' varinfo'), вы вас интересует. – byako

+0

В комментарии, который вы упомянули, что это за текст: '(Kstmt stmt) lv' Что такое lv? Является ли Kstmt литой или что-то в этом роде? –

ответ

7

Вот конкретный пример как печатать, для каждой локальной и глобальной переменной, результат вычисляется по значению перед каждым утверждением в данной функции (читай функции снизу вверх):

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 -> %[email protected]" 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: %[email protected]%[email protected]" 
      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 [email protected]"; 
     !Db.Value.compute(); 
     let fun_name = "main" in 
     Format.printf "visiting function: %[email protected]" 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 "[email protected]") 

Это далеко от идеала, и выход чем просто с использованием Cvalue.Model.pretty state, но он может служить базой для дальнейших модификаций.

Этот скрипт был протестирован с помощью магния Frama-C.

Чтобы получить государству после с заявлением, просто замените параметр ~after:false в fold_state_callstack с ~after:true. В моей предыдущей версии кода использовалась функция, которая уже привязывала это значение для предварительного состояния, но такая функция не экспортируется для пост-состояния, поэтому мы должны использовать fold_state_callstack (что, кстати, более мощное, поскольку оно позволяет получить конкретную состояние за звонок).

+0

Спасибо, это было именно то, что я искал :) –

+0

Есть ли способ получить значения после утверждения? –

+0

И еще один вопрос: почему вывод в формате: c -> {{NULL -> {17}}} Что это за NULL? (это не ноль до?) –