Source file instrument_multicore.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
open Cil_types
open Commons
type id = int
type info = {
li_loc : Cil_types.location;
li_tag : string;
li_stmt : Cil_types.stmt;
li_annotable : Cil_types.stmt;
li_predicate : Cil_types.exp;
li_kf : Cil_types.kernel_function;
}
module KFSet = Set.Make (struct type t = Cil_types.kernel_function let compare = compare end)
module LabelInfo = Datatype.Make (struct
include Datatype.Serializable_undefined
type t = info
let name = "Instr.info_multicore"
let reprs = [ {
li_loc = Cil_datatype.Location.unknown;
li_tag = "";
li_stmt = Cil.dummyStmt;
li_annotable = Cil.dummyStmt;
li_predicate = Cil_datatype.Exp.dummy;
li_kf = Kernel_function.dummy ();
} ]
let mem_project =
Datatype.never_any_project
end)
module H = Datatype.Int.Hashtbl
module LabelInfos =
State_builder.Option_ref
(Datatype.Triple (H.Make (LabelInfo))
(H.Make (Datatype.Int))
(H.Make (Datatype.Int)))
(struct
let name = "LabelInfos_multicore"
let dependencies = [ Ast.self ]
end)
class label_mapper h = object(self)
inherit Visitor.frama_c_inplace
val mutable opened_blocks = []
method private get_parent_and_current =
match self#current_stmt, opened_blocks with
| Some stmt, block ::_ -> Some (block, stmt)
| _ -> None
method! vstmt_aux s =
match s.skind with
| Block _ ->
opened_blocks <- s :: opened_blocks;
Cil.ChangeDoChildrenPost (s, fun s -> opened_blocks <- List.tl opened_blocks; s)
| _ ->
Cil.DoChildren
method! vinst i =
begin
match i with
| Call (None, {enode=(Lval (Var {vname=name}, NoOffset))}, idexp::cond::tagexp::_, loc)
when name = label_function_name ->
begin
match Cil.isInteger idexp, cil_isString tagexp, self#get_parent_and_current with
| Some id, Some tag, Some (block_stmt,call_stmt) ->
let id = Integer.to_int_exn id in
let englobing_kf = Option.get self#current_kf in
Datatype.Int.Hashtbl.add h id {
li_loc=loc;
li_tag=tag;
li_stmt=block_stmt;
li_annotable=call_stmt;
li_predicate=cond;
li_kf=englobing_kf;
}
| None,_,_ ->
Options.warning "instr: invalid label at line %d [id]" (fst loc).Filepath.pos_lnum
| _,None,_ ->
Options.warning "instr: invalid label at line %d [tag]" (fst loc).Filepath.pos_lnum
| _,_,None ->
Options.warning "instr: invalid label at line %d [structure]" (fst loc).Filepath.pos_lnum
end
| _ -> ()
end;
Cil.SkipChildren
end
let compute () : LabelInfos.data =
let ast = Ast.get () in
let h = H.create 97 in
Visitor.visitFramacFileSameGlobals (new label_mapper h) ast;
let blocks = H.create 97 in
let calls = H.create 97 in
let f id info =
H.add blocks info.li_stmt.sid id;
H.add calls info.li_annotable.sid id;
in
H.iter f h;
h, blocks, calls
let compute () =
LabelInfos.memo compute
let get_label_ids () =
let table,_,_ = compute () in
H.fold (fun k _ l -> k::l) table []
let get id =
let table,_,_ = compute () in
H.find table id
let iter f =
let table,_,_ = compute () in
H.iter f table
let get_loc id =
(get id).li_loc
let get_tag id =
(get id).li_tag
let get_stmt id =
(get id).li_stmt
let get_annotable_stmt id =
(get id).li_annotable
let get_predicate id =
(get id).li_predicate
let get_kf id =
(get id).li_kf
let is_annotable_stmt_by_sid sid =
let _,_,calls = compute () in
if H.mem calls sid then Some (H.find calls sid)
else None
let is_annotable_stmt stmt =
is_annotable_stmt_by_sid stmt.sid
let is_stmt_by_sid sid =
let _,blocks,_ = compute () in
if H.mem blocks sid then Some (H.find blocks sid)
else None
let is_stmt stmt =
is_stmt_by_sid stmt.sid
let at = ref true
(** Emitter for uncoverable label's asertions *)
let emitter = Emitter.create "Luncov_multicore" [ Emitter.Code_annot ] ~correctness:[] ~tuning:[]
(** Visitor that removes all but a single label (given its id),
add a single assertion whose validity implies the uncoverability of a label,
and provides information to get a Property.t
*)
class label_selector lblid info prj = object (self)
inherit Visitor.frama_c_copy prj
method! vinst i =
begin
match i with
| Call _ ->
begin
match self#current_stmt with
| Some stmt ->
begin
match is_stmt_by_sid stmt.sid with
| Some lblid' when lblid' <> lblid ->
stmt.skind <- Instr (Skip (Cil_datatype.Stmt.loc stmt));
Cil.SkipChildren
| _ -> begin
match is_annotable_stmt_by_sid stmt.sid with
| Some lblid' -> if lblid' = lblid then (
self#add_label_annot stmt;
Cil.JustCopy ) else Cil.DoChildren
| _ ->
Cil.DoChildren
end
end
| _ -> Cil.DoChildren
end
| _ -> Cil.DoChildren
end;
method private add_label_annot new_stmt =
let lblinfo = get lblid in
let cond = Cil.constFold true (Visitor.visitFramacExpr (self :> Visitor.frama_c_visitor) lblinfo.li_predicate) in
let cond = (Logic_utils.expr_to_term ~coerce:true cond) in
let rel = if !at then Cil_types.Req else Cil_types.Rneq in
let pred = Logic_const.prel (rel, cond, Cil.lzero ()) in
let top_pred = Logic_const.toplevel_predicate ~kind:Check pred in
let old_kf = Option.get self#current_kf in
let new_kf = Visitor_behavior.Get.kernel_function self#behavior old_kf in
let queued_action () =
let code_annot = AAssert ([], top_pred) in
let code_annotation = Logic_const.new_code_annotation code_annot in
Annotations.add_code_annot ~kf:new_kf emitter new_stmt code_annotation;
info := Some (new_kf, new_stmt, code_annotation);
in
Queue.add queued_action self#get_filling_actions
end
let create_project_for_label ?name id =
let name = match name with None -> "label_"^string_of_int id | Some name -> name in
let info = ref None in
let prj = File.create_project_from_visitor name (new label_selector id info) in
match !info with
| Some (kf,stmt,code_annotation) ->
let ip = Property.ip_of_code_annot_single kf stmt code_annotation in
prj, Some ip
| None ->
prj, None
let lbl_stmt_map = Hashtbl.create 100
let lbl_cond_map = Hashtbl.create 100
let lbl_kf_map = Hashtbl.create 100
let kf_lbl_map = Hashtbl.create 100
let get_kf_name kf =
match kf.fundec with
| Definition (f,_) -> f.svar.vname
| Declaration (_,f,_,_) -> f.vname
let kfs = ref (KFSet.empty)
let get_kf_lbl_partition () = (!kfs,kf_lbl_map)
class label_collector prj = object (self)
inherit Visitor.frama_c_copy prj
val mutable into_lbl_fun = false
method! vinst i =
begin
match i with
| Call _ ->
begin
match self#current_stmt with
| Some stmt ->
begin
match is_annotable_stmt_by_sid stmt.sid with
| Some lblid ->
Hashtbl.add lbl_stmt_map lblid stmt;
let lblinfo = get lblid in
let cond = Cil.constFold true (Visitor.visitFramacExpr (self :> Visitor.frama_c_visitor) lblinfo.li_predicate) in
let cond = (Logic_utils.expr_to_term ~coerce:true cond) in
let rel = if !at then Cil_types.Req else Cil_types.Rneq in
let assertion = Logic_const.prel (rel, cond, Cil.lzero ()) in
Hashtbl.add lbl_cond_map lblid assertion;
let old_kf = Option.get self#current_kf in
let new_kf = Visitor_behavior.Get.kernel_function self#behavior old_kf in
Hashtbl.add lbl_kf_map lblid new_kf;
Hashtbl.add kf_lbl_map (get_kf_name new_kf) lblid;
kfs := KFSet.add new_kf !kfs;
let replace = (Skip (Cil_datatype.Stmt.loc stmt)) in
Cil.ChangeTo [replace]
| _ -> Cil.DoChildren
end
| _ -> Cil.DoChildren
end
| _ -> Cil.DoChildren
end;
end
let created_project = ref None
let previously_processed_label = ref None
let old_project = ref None
let terminate () =
match !old_project with
| Some p -> Project.set_current p
| None -> ()
let create_project _ =
match !created_project with
| Some p -> Project.set_current p; p
| None ->
old_project := Some (Project.current());
let p = File.create_project_from_visitor "pr" (new label_collector) in
Commons.copy_parameters p;
created_project := Some p;
Project.set_current p; p
let add_annotations_get_ips labels =
Annotations.iter_all_code_annot (fun s e a -> Annotations.remove_code_annot e s a);
let ips = Hashtbl.create (List.length labels) in
List.iter (fun lblid ->
try (
let new_stmt = Hashtbl.find lbl_stmt_map lblid in
let pred = Hashtbl.find lbl_cond_map lblid in
let top_pred = Logic_const.toplevel_predicate ~kind:Check pred in
let new_kf = Hashtbl.find lbl_kf_map lblid in
let code_annot = AAssert ([], top_pred) in
let code_annotation = Logic_const.new_code_annotation code_annot in
let emit = Emitter.create ("Label"^(string_of_int lblid)) [ Emitter.Code_annot ] ~correctness:[] ~tuning:[] in
Annotations.add_code_annot ~kf:new_kf emit new_stmt code_annotation;
Hashtbl.add ips lblid (Some (Property.ip_of_code_annot_single new_kf new_stmt code_annotation)))
with Not_found -> Hashtbl.add ips lblid None) labels;
ips
let add_annotation_get_ip lblid =
Annotations.iter_all_code_annot (fun s e a -> Annotations.remove_code_annot e s a);
try (
let new_stmt = Hashtbl.find lbl_stmt_map lblid in
let pred = Hashtbl.find lbl_cond_map lblid in
let top_pred = Logic_const.toplevel_predicate ~kind:Check pred in
let new_kf = Hashtbl.find lbl_kf_map lblid in
let code_annot = AAssert ([], top_pred) in
let code_annotation = Logic_const.new_code_annotation code_annot in
let emit = Emitter.create ("Label"^(string_of_int lblid)) [ Emitter.Code_annot ] ~correctness:[] ~tuning:[] in
Annotations.add_code_annot ~kf:new_kf emit new_stmt code_annotation;
Some (Property.ip_of_code_annot_single new_kf new_stmt code_annotation))
with Not_found -> previously_processed_label := None; None