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
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401 | (**************************************************************************)
(* *)
(* This file is part of the Concurrency Plugin for Frama-C *)
(* *)
(* Copyright (C) 2013 *)
(* Adelard LLP *)
(* CINIF (Control and Instrumentation Nuclear Industry Forum) *)
(* *)
(* You can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License as published by the Free Software *)
(* Foundation, version 3. *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU Lesser General Public License for more details. *)
(* *)
(* See the GNU Lesser General Public License version v3 *)
(* for more details (enclosed in the file ./LGPLv3). *)
(* *)
(**************************************************************************)
(**
* This is the main entry for the Concurrency plugin gui.
*)
(*GUIs*)
open Gtk_helper
open Pretty_source
(*Plugin modules*)
open Concurrency_main
open Cil_datatype
open Cil_types
open Visitor
(*open Option - was not been able to link this library ExtLib*)
open Concurguiglobs
open Vappgui
open Accessesgui
open Epsgui
let show_column = ref (fun _ -> ());; (*the 'Concurrency' column in filetree*)
(** Computes an intersection of the variable sets used by the main thread
* and the selected thread*)
let update_var_overlap () =
if (List.length (SelectedThreads.get ())) > 0 && ((SelectedMain.get) () != init_fundec)
then
(
let main_vars = variables_used (get_option !cg) (SelectedMain.get ()) in
let intersect_vars st f2 =
if f2 != (SelectedMain.get ()) then
Varinfo.Set.inter st (variables_used (get_option !cg) f2)
else
st
in
let out_set = List.fold_left intersect_vars main_vars (SelectedThreads.get ()) in
VarOverlapSet_ref.set out_set;
)
else
() ;;
(** Updates the R/W access locations for a particular variable and thread
* and converts this data to the local data holder type*)
let update_acc() =
if (List.length (SelectedThreads.get ())) > 0
&& (SelectedMain.get ()) != init_fundec
&& (LockedVar.get ()) != init_varinfo
then
begin
(*obtains the locs for the current entry point*)
let get_locs_for_v_from_ep v ep =
let vis = new varAccess v in
let visfun _ f =
let _ = visitFramacFunction (vis:>frama_c_visitor) f in ()
in
cg_dfs_fundecs (get_option !cg) visfun ep;
vis#locs
in
(*converts locs to the AccessForList type*)
let to_access_for ep (a, b, c) =
(ep, a, b, c)
in
let main_locs = get_locs_for_v_from_ep (LockedVar.get ()) (SelectedMain.get ()) in
AccessForList.set [];
AccessForList.set (List.append (AccessForList.get ()) (List.map (to_access_for (SelectedMain.get ())) main_locs));
let apply_to_all_eps ep =
let ep_locs = get_locs_for_v_from_ep (LockedVar.get ()) ep in
AccessForList.set (List.append (AccessForList.get ()) (List.map (to_access_for ep) ep_locs))
in
List.iter apply_to_all_eps (SelectedThreads.get ())
end ;;
(** Updates the pretty source viewer part of the Frama-C GUI
* to highlight the critical regions in the code.
*)
let concur_highlighter buffer loc ~start ~stop =
if (List.length (AccessForList.get ())) > 0 then
begin
let highlight clr =
(*make_tag apply_tag are frama-c functions*)
let tag = make_tag buffer "concurrency" [`BACKGROUND clr ] in
apply_tag buffer tag start stop
in
match loc with
| PLval (_, ki, (lh,_)) ->
let same_lval ki lh (_,k,_,_) =
(Kinstr.equal ki k) &&
match lh with
| Var(vi) -> (Varinfo.equal vi (LockedVar.get ()))
| _ -> false
in
if List.exists (same_lval ki lh) (AccessForList.get ()) then
highlight "yellow";
| PTermLval (_,ki,(lh,_)) ->
let same_tlval ki lh (_,k,_,_) =
(Kinstr.equal ki k) &&
match lh with
| TVar(tv) ->
begin
match tv.lv_origin with
| Some(vi) -> (Varinfo.equal vi (LockedVar.get ()))
| None -> false
end
| _ -> false
in
if List.exists (same_tlval ki lh) (AccessForList.get ()) then
highlight "yellow"
| PVDecl(_, vi') when Varinfo.equal (LockedVar.get ()) vi' ->
highlight "yellow"
| PVDecl _ | PStmt _ | PGlobal _ | PIP _ -> ()
end;;
(** Configures the concurrency plugin side panel and loads the additional forms.
*)
let concurrency_panel main_ui =
let eps_display = new vEpsWindow in (*entry points form*)
let var_overlap_display = new vAppWindow in (*intersected variables form*)
let access_display = new vAccWindow main_ui in (*access form*)
(*setup the side panel*)
let v_box = GPack.vbox () in
let h0_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Filter:"
~width:100
~packing:(h0_box#pack ~expand:false) ()
in
let open_ep_filter = GButton.button ~label:"Entry Points" ~packing:h0_box#pack () in
ignore (open_ep_filter#connect#pressed (fun () -> eps_display#show_eps ()));
(*Create Main combo and label*)
let h2_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Current main: "
~width:100
~packing:(h2_box#pack ~expand:false) ()
in
let main_combo = GEdit.combo_box_text ~strings:[]
~has_frame:true ~packing:h2_box#pack ()
in
(*Populates the main entry point combo box with
selection of available entry points*)
let populate_main () =
let add_eps_to_combo ep =
let ep_name = (Kernel_function.get_name ep) in
GEdit.text_combo_add main_combo ep_name
in
let (_,(a,_)) = main_combo in
a#clear ();
List.iter add_eps_to_combo (FilteredEntryPoints.get ())
in
let (a,_) = main_combo in
ignore(a#connect#changed (fun () ->
let mn = match GEdit.text_combo_get_active main_combo with
| Some(a) -> Globals.Functions.find_by_name a
| None -> init_fundec
in
if mn != init_fundec then
begin
SelectedMain.set mn;
LockedVar.set init_varinfo;
AccessForList.set [];
SelectedThreads.set [];
VarOverlapSet_ref.set Varinfo.Set.empty;
refresh := (false,true,true,true,false) (*update gui*)
end));
(*Create E.P. combo and label*)
let h3_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Current E.P.: "
~width:100
~packing:(h3_box#pack ~expand:false) ()
in
let eps_combo = GEdit.combo_box_text ~strings:[] ~has_frame:true ~packing:h3_box#pack () in
(* Populates the Entry Points combo with the
available entry points except what was selected as a main entry point*)
let populate_eps () =
let current_main = match GEdit.text_combo_get_active main_combo with
| Some(a) -> a
| None -> ""
in
let add_eps_to_combo ep =
let ep_name = (Kernel_function.get_name ep) in
if not (ep_name = current_main) then
GEdit.text_combo_add eps_combo ep_name
in
let (_,(a,_)) = eps_combo in
a#clear ();
List.iter add_eps_to_combo (FilteredEntryPoints.get ())
in
let (a,_) = eps_combo in
ignore(a#connect#changed (
fun () ->
let ep = match GEdit.text_combo_get_active eps_combo with
| Some(a) -> Globals.Functions.find_by_name a
| None -> init_fundec
in
if ep != init_fundec then
begin
SelectedThreads.set [ep];
LockedVar.set init_varinfo;
VarOverlapSet_ref.set Varinfo.Set.empty;
AccessForList.set [];
refresh := (false,false,true,true,false) (*update gui*)
end));
(*Create the currently selected variable combo box*)
let h1_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Current variable:"
~width:100
~packing:(h1_box#pack ~expand:false) ()
in
let var_combo = GEdit.combo_box_text ~strings:[] ~has_frame:true ~packing:h1_box#pack () in
(*Populates the combo box with the current
variables shared between main and EP thread.*)
let populate_var () =
let (a,(b,_)) = var_combo in
let add_vars_to_combo vi c =
if not (Cil.isFunctionType vi.vtype) then begin
GEdit.text_combo_add var_combo vi.vname;
(*the purpose of this is to activate the currently selected variable*)
if vi.vname == (LockedVar.get ()).vname then
a#set_active c; (*how to get the number of elements added*)
c+1
end
else c
in
b#clear ();
ignore(Varinfo.Set.fold add_vars_to_combo (VarOverlapSet_ref.get ()) 0);
in
let (a,_) = var_combo in
ignore(a#connect#changed (fun () ->
let vi = match GEdit.text_combo_get_active var_combo with
| Some(a) ->
(try Globals.Vars.find_from_astinfo a VGlobal
with Not_found -> init_varinfo)
| None -> init_varinfo
in
if vi != init_varinfo then
LockedVar.set vi;
AccessForList.set [];
refresh := (false, false, false, true, false) (*update gui*)
));
(*create buttons*)
let show_vapp = GButton.button ~label:"Details" ~packing:h1_box#pack () in
ignore (show_vapp#connect#pressed (fun () -> var_overlap_display#show_vapp ()));
let h4_box = GPack.hbox ~packing: v_box#pack () in
let _ = GMisc.label
~xalign:0.0
~text:"Compute:"
~width:100
~packing:(h4_box#pack ~expand:false) ()
in
let button_access_details = GButton.button ~label:"Show Details" ~packing:h4_box#pack () in
ignore (button_access_details#connect#pressed(fun () -> update_acc (); access_display#show_acc ()));
(* Drives the GUI statemachine updating the Concurrency section of the GUI*)
let refresh = fun () ->
begin
(*We could replace this by some sort of signal*)
let (m,e,v,g,_) = !refresh in
if m then
populate_main ();
(*main has changed*)
if e then
populate_eps ();
(*main or eps have changed*)
if v then
begin
update_var_overlap ();
populate_var ();
!show_column `Visibility
end;
(*main or eps or var have changed*)
if g then
begin
populate_var ();
update_acc ();
!show_column `Visibility
end;
if m || e || v || g then
(
var_overlap_display#refresh ();
access_display#refresh ();
main_ui#rehighlight ();
);
refresh := (false,false, false, false, false)
end
in
"Concurrency", v_box#coerce, Some refresh
;;
(** Decorates the file tree Concurrency colum to show the
* functions where a particular variable is used.
*)
let file_tree_decorate (file_tree:Filetree.t) =
show_column :=
file_tree#append_pixbuf_column
~title:"Concurrency"
(fun globs ->
if List.length (AccessForList.get ()) > 0 then
begin
let in_globals (_,ki,_,_) =
match ki with
| Kglobal -> false
| Kstmt stmt ->
let kf = Kernel_function.find_englobing_kf stmt in
let {vid=v0} = Kernel_function.get_vi kf in
List.exists
(fun glob -> match glob with
| GFun ({svar ={vid=v1}},_ ) -> v1=v0
| _ -> false)
globs
in
if (List.exists in_globals (AccessForList.get ())) then [`STOCK_ID "gtk-apply"]
else [`STOCK_ID ""]
end
else
[`STOCK_ID ""])
(fun () -> not (Varinfo.equal (LockedVar.get ()) init_varinfo));
!show_column `Visibility ;;
let concur_gui_f main_ui=
(*init*)
start_concurrency ();
Self.result "Starting concur plugin";
(*menu accessible from right clicking on the source viewer*)
(*main_ui#register_source_selector concur_menu_item;*)
(*highlights in main code display when necessary parameters of the plugin
are set*)
main_ui#register_source_highlighter concur_highlighter;
main_ui#register_panel concurrency_panel;
file_tree_decorate main_ui#file_tree;
;;
(*Register the main_gui function as enty point for Concur GUI*)
let () = Design.register_extension concur_gui_f ;;
|