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 ;;