~ubuntu-branches/debian/sid/frama-c/sid

« back to all changes in this revision

Viewing changes to src/slicing/register.ml

  • Committer: Bazaar Package Importer
  • Author(s): Mehdi Dogguy
  • Date: 2009-06-03 08:19:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090603081925-kihvxvt0wy3zc4ar
Tags: upstream-20081201.dfsg
ImportĀ upstreamĀ versionĀ 20081201.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(**************************************************************************)
 
2
(*                                                                        *)
 
3
(*  This file is part of Frama-C.                                         *)
 
4
(*                                                                        *)
 
5
(*  Copyright (C) 2007-2008                                               *)
 
6
(*    CEA   (Commissariat ļæ½ l'ļæ½nergie Atomique)                           *)
 
7
(*    INRIA (Institut National de Recherche en Informatique et en         *)
 
8
(*           Automatique)                                                 *)
 
9
(*                                                                        *)
 
10
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
 
11
(*  Lesser General Public License as published by the Free Software       *)
 
12
(*  Foundation, version 2.1.                                              *)
 
13
(*                                                                        *)
 
14
(*  It is distributed in the hope that it will be useful,                 *)
 
15
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
 
16
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
 
17
(*  GNU Lesser General Public License for more details.                   *)
 
18
(*                                                                        *)
 
19
(*  See the GNU Lesser General Public License version v2.1                *)
 
20
(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
 
21
(*                                                                        *)
 
22
(**************************************************************************)
 
23
 
 
24
open Cil_types
 
25
 
 
26
module T = SlicingTypes.Internals
 
27
module M = SlicingMacros
 
28
module U = SlicingMacros
 
29
module C = SlicingCmds
 
30
module Act = SlicingActions
 
31
 
 
32
type appli = Project.t
 
33
 
 
34
let check_call stmt is_call =
 
35
  let err = match stmt.skind with
 
36
    | Instr (Call _) -> not is_call
 
37
    | _ -> is_call
 
38
  in
 
39
    if err then
 
40
      let str = if is_call then "not" else "" in
 
41
      let msg = "This statement is "^str^" a call" in
 
42
        raise (Invalid_argument msg)
 
43
    else stmt
 
44
 
 
45
let pretty_list pretty fmt l = List.iter (pretty fmt) l
 
46
 
 
47
let print_select fmt db_select =
 
48
  let db_fvar, select = db_select in
 
49
    Format.fprintf fmt "In %a : %a@."
 
50
      Ast_info.pretty_vname db_fvar Act.print_f_crit select
 
51
 
 
52
let get_select_kf (fvar, _select) = Globals.Functions.get fvar
 
53
 
 
54
let check_db_select fvar db_select =
 
55
  let db_fvar, select = db_select in
 
56
  if db_fvar.vid <> fvar.vid then
 
57
    begin
 
58
      Format.printf "slice name = %s <> select = %a@."
 
59
        (fvar.vname) print_select db_select;
 
60
      raise (Invalid_argument
 
61
           "This selection doesn't belong to the given function");
 
62
    end;
 
63
  fvar, select
 
64
 
 
65
let empty_db_select kf = (Kernel_function.get_vi kf, T.CuSelect [])
 
66
let top_db_select kf m = (Kernel_function.get_vi kf, T.CuTop m)
 
67
let check_kf_db_select kf = check_db_select (Kernel_function.get_vi kf)
 
68
let check_fi_db_select fi = check_db_select (M.fi_svar fi)
 
69
let check_ff_db_select ff = check_db_select (M.ff_svar ff)
 
70
 
 
71
let bottom_msg kf =
 
72
  Cil.log "[slicing] bottom PDG for function '%s': ignore selection"
 
73
    (Kernel_function.get_name kf)
 
74
 
 
75
let basic_add_select kf select nodes ?(undef) nd_marks =
 
76
  let fvar, sel = check_kf_db_select kf select in
 
77
  match sel with
 
78
    | T.CuTop _ -> select
 
79
    | T.CuSelect sel ->
 
80
        let pdg = !Db.Pdg.get kf in
 
81
        let nodes = 
 
82
          List.map (fun n -> (n, None) (*TODO: add z_part ? *)) nodes in
 
83
        (* let nd_marks = Act.build_node_and_dpds_selection mark in *)
 
84
        (* let nd_marks = Act.build_simple_node_selection mark in *)
 
85
        let crit = [(nodes, nd_marks)] in
 
86
        let sel = Act.translate_crit_to_select pdg ~to_select:sel crit  in
 
87
        let sel = match undef with None -> sel
 
88
          | Some (undef, mark) ->
 
89
              PdgMarks.add_undef_in_to_select sel undef mark in
 
90
        let sel = T.CuSelect sel in
 
91
          (fvar, sel)
 
92
 
 
93
let select_pdg_nodes kf ?(select=empty_db_select kf) nodes mark =
 
94
  M.debug 1 "[slicing] select_pdg_nodes@." ;
 
95
  let nd_marks = Act.build_node_and_dpds_selection mark in
 
96
  try basic_add_select kf select nodes nd_marks
 
97
  with Db.Pdg.Top | Db.Pdg.Bottom -> 
 
98
      assert false (* if we have node, we must have a pdg somewhere ! *)
 
99
 
 
100
let mk_select pdg sel nodes undef mark =
 
101
  let nd_marks = Act.build_simple_node_selection mark in
 
102
  let crit = [(nodes, nd_marks)] in
 
103
  let sel = Act.translate_crit_to_select pdg ~to_select:sel crit in
 
104
  let sel = PdgMarks.add_undef_in_to_select sel undef mark in
 
105
  let sel = T.CuSelect sel in
 
106
    sel
 
107
 
 
108
let select_stmt_zone kf ?(select=empty_db_select kf) stmt ~before loc mark =
 
109
  M.debug 1 "[slicing] select_stmt_zone %a %s stmt %d (m=%a)@."
 
110
      Locations.Zone.pretty loc
 
111
      (if before then "before" else "after") stmt.sid
 
112
       SlicingMarks.pretty_mark mark;
 
113
  let fvar, sel = check_kf_db_select kf select in
 
114
  match sel with
 
115
    | T.CuTop _ -> select
 
116
    | T.CuSelect sel ->
 
117
        try
 
118
          let pdg = !Db.Pdg.get kf in
 
119
          let nodes, undef =
 
120
            !Db.Pdg.find_location_nodes_at_stmt pdg stmt before loc in
 
121
          let sel = mk_select pdg sel nodes undef mark in
 
122
            (fvar, sel)
 
123
        with
 
124
          | Db.Pdg.NotFound -> (* stmt probably unreachable *)
 
125
          let msg = M.sprintf "%a %s stmt %d"
 
126
                      Locations.Zone.pretty loc
 
127
                      (if before then "before" else "after") stmt.sid
 
128
          in Format.printf "Nothing to select for %s@." msg;
 
129
             select
 
130
          | Db.Pdg.Top -> top_db_select kf mark
 
131
          | Db.Pdg.Bottom -> bottom_msg kf; select
 
132
 
 
133
 
 
134
(** this one is similar to [select_stmt_zone] with the return statement
 
135
* when the function is defined, but it can also be used for undefined functions. *)
 
136
let select_in_out_zone ~at_end ~use_undef kf select loc mark =
 
137
  M.debug 1 "[slicing] select zone %a (m=%a) at %s of %a@."
 
138
      Locations.Zone.pretty loc SlicingMarks.pretty_mark mark
 
139
      (if at_end then "end" else "begin") Kernel_function.pretty_name kf;
 
140
  let fvar, sel = check_kf_db_select kf select in
 
141
  match sel with
 
142
    | T.CuTop _ -> select
 
143
    | T.CuSelect sel ->
 
144
        try
 
145
          let pdg = !Db.Pdg.get kf in
 
146
          let find = 
 
147
            if at_end then !Db.Pdg.find_location_nodes_at_end 
 
148
            else !Db.Pdg.find_location_nodes_at_begin in
 
149
          let nodes, undef = find pdg loc in
 
150
          let undef = if use_undef then undef else None in
 
151
          let sel = mk_select pdg sel nodes undef mark in
 
152
            (fvar, sel)
 
153
        with
 
154
          | Db.Pdg.NotFound -> assert false 
 
155
          | Db.Pdg.Top -> top_db_select kf mark
 
156
          | Db.Pdg.Bottom -> bottom_msg kf; select
 
157
 
 
158
let select_zone_at_end kf  ?(select=empty_db_select kf) loc mark =
 
159
  select_in_out_zone ~at_end:true ~use_undef:true kf select loc mark
 
160
 
 
161
let select_modified_output_zone kf  ?(select=empty_db_select kf) loc mark =
 
162
  select_in_out_zone ~at_end:true ~use_undef:false kf select loc mark
 
163
 
 
164
let select_zone_at_entry kf  ?(select=empty_db_select kf) loc mark =
 
165
  select_in_out_zone ~at_end:false ~use_undef:true kf select loc mark
 
166
 
 
167
let stmt_nodes_to_select pdg stmt =
 
168
  let stmt_nodes =
 
169
    try !Db.Pdg.find_stmt_and_blocks_nodes pdg stmt with Db.Pdg.NotFound -> []
 
170
  in
 
171
      (* TODO : add this when visibility of anotations are ok
 
172
let stmt_nodes =
 
173
  if List.length stmt_nodes > 1 then
 
174
    begin (* this is surely a call statement *)
 
175
      let out_and_ctrl node =
 
176
        let key = PdgTypes.Node.elem_key node in
 
177
    match key with
 
178
      | PdgIndex.Key.SigCallKey (_, (PdgIndex.Signature.In _))
 
179
        -> false
 
180
            | PdgIndex.Key.SigCallKey (_, (PdgIndex.Signature.InCtrl))
 
181
                | PdgIndex.Key.SigCallKey (_, (PdgIndex.Signature.Out _))
 
182
                  -> true
 
183
            | _ -> assert false
 
184
  in
 
185
    List.filter out_and_ctrl stmt_nodes
 
186
      end
 
187
          else
 
188
            stmt_nodes
 
189
  in
 
190
        *)
 
191
      M.debug 2 "   add_stmt_nodes on stmt %d (%a)@." stmt.sid
 
192
          (fun fmt l -> List.iter (!Db.Pdg.pretty_node true fmt) l)
 
193
          stmt_nodes;
 
194
      stmt_nodes
 
195
 
 
196
let select_stmt_computation kf ?(select=empty_db_select kf) stmt mark =
 
197
  M.debug 1 "[slicing] select_stmt_computation on stmt %d@." stmt.sid;
 
198
    try
 
199
      let pdg = !Db.Pdg.get kf in
 
200
      let stmt_nodes = stmt_nodes_to_select pdg stmt in
 
201
      let nd_marks = Act.build_node_and_dpds_selection mark in
 
202
        basic_add_select kf select stmt_nodes nd_marks
 
203
    with Db.Pdg.Top -> top_db_select kf mark
 
204
      | Db.Pdg.Bottom -> bottom_msg kf; select
 
205
 
 
206
(** marking a call node means that a [choose_call] will have to decide that to
 
207
 * call according to the slicing-level, but anyway, the call will be visible.
 
208
 *)
 
209
let select_minimal_call kf ?(select=empty_db_select kf) stmt m =
 
210
  M.debug 1 "[slicing] select_minimal_call@.";
 
211
    try 
 
212
      let pdg = !Db.Pdg.get kf in
 
213
      let call = check_call stmt true in
 
214
      let call_node = !Db.Pdg.find_call_ctrl_node pdg call in
 
215
      let nd_marks = Act.build_simple_node_selection m in
 
216
        basic_add_select kf select [call_node] nd_marks
 
217
    with Db.Pdg.Top -> top_db_select kf m
 
218
      | Db.Pdg.Bottom -> bottom_msg kf; select
 
219
 
 
220
let select_stmt_ctrl kf ?(select=empty_db_select kf) stmt =
 
221
  M.debug 1 "[slicing] select_stmt_ctrl of sid:%d@." stmt.sid;
 
222
  let mark = SlicingMarks.mk_user_mark ~ctrl:true ~data:false ~addr:false in
 
223
  try
 
224
    let pdg = !Db.Pdg.get kf in
 
225
    let stmt_nodes = !Db.Pdg.find_simple_stmt_nodes pdg stmt in
 
226
    let nd_marks = Act.build_ctrl_dpds_selection mark in
 
227
      basic_add_select kf select stmt_nodes nd_marks
 
228
  with Db.Pdg.Top -> top_db_select kf mark
 
229
    | Db.Pdg.Bottom -> bottom_msg kf; empty_db_select kf
 
230
 
 
231
let select_entry_point kf ?(select=empty_db_select kf) mark =
 
232
  M.debug 1 "[slicing] select_entry_point of %a@." 
 
233
      Kernel_function.pretty_name kf;
 
234
  try
 
235
    let pdg = !Db.Pdg.get kf in
 
236
    let node = !Db.Pdg.find_entry_point_node pdg in
 
237
    let nd_marks = Act.build_simple_node_selection mark in
 
238
      basic_add_select kf select [node] nd_marks
 
239
  with Db.Pdg.Top -> top_db_select kf mark
 
240
    | Db.Pdg.Bottom -> bottom_msg kf; empty_db_select kf
 
241
 
 
242
let select_return kf ?(select=empty_db_select kf) mark =
 
243
  M.debug 1 "[slicing] select_return of %a@." 
 
244
      Kernel_function.pretty_name kf;
 
245
  try
 
246
    let pdg = !Db.Pdg.get kf in
 
247
    let node = !Db.Pdg.find_ret_output_node pdg in
 
248
    let nd_marks = Act.build_simple_node_selection mark in
 
249
      basic_add_select kf select [node] nd_marks
 
250
  with 
 
251
    | Db.Pdg.NotFound -> (* unreachable ? *) select
 
252
    | Db.Pdg.Top -> top_db_select kf mark
 
253
    | Db.Pdg.Bottom -> bottom_msg kf; empty_db_select kf
 
254
 
 
255
 
 
256
let merge_select select1 select2 =
 
257
  let select = match select1, select2 with
 
258
      | T.CuTop m, _ | _, T.CuTop m -> T.CuTop m
 
259
      | T.CuSelect select1, T.CuSelect select2 ->
 
260
          (* TODO : we can probably do better...*)
 
261
          T.CuSelect (select1 @ select2)
 
262
  in select
 
263
 
 
264
let merge_db_select db_select1 db_select2 =
 
265
  let fvar, select1 = db_select1 in
 
266
  let _, select2 = check_db_select fvar db_select2 in
 
267
  let select = merge_select select1 select2 in
 
268
    (fvar, select)
 
269
 
 
270
let empty_selects () = Cilutil.VarinfoHashtbl.create 7
 
271
 
 
272
let add_to_selects db_select hsel =
 
273
  let vf, select = db_select in
 
274
  let select =
 
275
    try let old_selection = Cilutil.VarinfoHashtbl.find hsel vf in
 
276
      merge_select old_selection select
 
277
    with Not_found -> select
 
278
  in Cilutil.VarinfoHashtbl.replace hsel vf select
 
279
 
 
280
let fold_selects f hsel acc =
 
281
  let dof v sel acc = f (v, sel) acc in
 
282
  Cilutil.VarinfoHashtbl.fold dof hsel acc
 
283
 
 
284
let iter_selects f hsel = fold_selects (fun s _ -> f s) hsel ()
 
285
 
 
286
(** add [hsel1] to [hsel2] *)
 
287
let add_selects_to_selects hsel1 hsel2 =
 
288
  let add (vf, sel) () = add_to_selects (vf, sel) hsel2 in
 
289
    fold_selects add hsel1 ()
 
290
 
 
291
let print_fct_stmts fmt (_proj, kf) =
 
292
  try
 
293
    let pdg = !Db.Pdg.get kf in
 
294
    PrintSlice.print_fct_from_pdg fmt pdg;
 
295
    Format.pp_print_flush fmt ()
 
296
  with Not_found -> ()
 
297
 
 
298
let add_crit_ff_change_call proj ff_caller call f_to_call =
 
299
  let crit = Act.mk_crit_change_call ff_caller call f_to_call in
 
300
    SlicingProject.add_filter proj crit
 
301
 
 
302
(** change the call to call the given slice.
 
303
 * This is a user request, so it might be the case that
 
304
 * the new function doesn't compute enough outputs :
 
305
 * in that case, add outputs first.
 
306
 *)
 
307
let call_ff_in_caller proj ~caller ~to_call =
 
308
  let kf_caller = M.get_ff_kf caller in
 
309
  let kf_to_call = M.get_ff_kf to_call in
 
310
  let call_stmts = !Db.Pdg.find_call_stmts ~caller:kf_caller  kf_to_call in
 
311
  let ff_to_call = T.CallSlice to_call in
 
312
  let add_change_call stmt =
 
313
    add_crit_ff_change_call proj caller stmt ff_to_call ;
 
314
    match Fct_slice.check_outputs_before_change_call proj caller
 
315
                             stmt to_call with
 
316
      | [] -> ()
 
317
      | [c] -> SlicingProject.add_filter proj c
 
318
      | _ -> assert false
 
319
 
 
320
  in List.iter add_change_call call_stmts
 
321
 
 
322
let call_fsrc_in_caller proj ~caller ~to_call =
 
323
  let kf_caller = M.get_ff_kf caller in
 
324
  let fi_to_call = M.get_kf_fi proj to_call in
 
325
  let kf_to_call = M.get_fi_kf fi_to_call in
 
326
  let call_stmts = !Db.Pdg.find_call_stmts ~caller:kf_caller kf_to_call in
 
327
  let add_change_call stmt =
 
328
    add_crit_ff_change_call proj caller stmt (T.CallSrc (Some fi_to_call))
 
329
  in List.iter add_change_call call_stmts
 
330
 
 
331
let call_min_f_in_caller proj ~caller ~to_call =
 
332
  let kf_caller = M.get_ff_kf caller in
 
333
  let pdg = U.get_ff_pdg caller in
 
334
  let call_stmts = !Db.Pdg.find_call_stmts ~caller:kf_caller to_call in
 
335
  let call_nodes = 
 
336
    List.map (fun call -> (!Db.Pdg.find_call_ctrl_node pdg call),None) 
 
337
      call_stmts in
 
338
  let m = SlicingMarks.mk_user_spare in
 
339
  let nd_marks = Act.build_simple_node_selection m in
 
340
  let select = Act.translate_crit_to_select pdg [(call_nodes, nd_marks)] in
 
341
    SlicingProject.add_fct_ff_filter proj caller (T.CuSelect select)
 
342
 
 
343
let is_already_selected ff db_select =
 
344
  let _, select = check_ff_db_select ff db_select in
 
345
    match select with
 
346
      | T.CuTop _ -> assert false
 
347
      | T.CuSelect to_select ->
 
348
          (* let pdg = !Db.Pdg.get (Globals.Functions.get fvar) in *)
 
349
          let new_marks = Fct_slice.filter_already_in ff to_select in
 
350
            M.debug 1 "[slicing] is_already_selected %a ?@."
 
351
                !Db.Slicing.Select.pretty db_select;
 
352
            let ok = if new_marks = [] then true else false in
 
353
              if ok then M.debug 1 "\t--> yes@."
 
354
              else M.debug 1 "\t--> no (missing %a)@."
 
355
                       Act.print_sel_marks_list new_marks;
 
356
              ok
 
357
 
 
358
let add_ff_selection proj ff db_select =
 
359
  M.debug 1 "[slicing:add_ff_selection] %a to %s@."
 
360
      !Db.Slicing.Select.pretty db_select (M.ff_name ff);
 
361
  let _, select = check_ff_db_select ff db_select in
 
362
      SlicingProject.add_fct_ff_filter proj ff select
 
363
 
 
364
(** add a persistant selection to the function.
 
365
* This might change its slicing level in order to call slices later on. *)
 
366
let add_fi_selection proj db_select =
 
367
  M.debug 1 "[slicing:add_fi_selection] %a@."
 
368
                      !Db.Slicing.Select.pretty db_select;
 
369
  let kf = get_select_kf db_select in
 
370
  let fi = M.get_kf_fi proj kf in
 
371
  let _, select = db_select in
 
372
    SlicingProject.add_fct_src_filter proj fi select;
 
373
    match M.fi_slicing_level fi with
 
374
      |  T.DontSlice |  T.DontSliceButComputeMarks ->
 
375
          M.change_fi_slicing_level fi  T.MinNbSlice;
 
376
          M.debug 1 "[slicing] changing %s slicing level to %s@."
 
377
              (M.fi_name fi)
 
378
              (M.str_level_option (M.fi_slicing_level fi))
 
379
 
 
380
      |  T.MinNbSlice |  T.MaxNbSlice -> ()
 
381
 
 
382
let get_mark_from_param ff var =
 
383
  let kf = M.get_ff_kf ff in
 
384
  let param_list = Kernel_function.get_formals kf in
 
385
  let rec find n var_list = match var_list with
 
386
  | [] -> raise Not_found
 
387
  | v :: var_list -> if v.vid = var.vid then n
 
388
                     else find (n+1) var_list
 
389
  in let n = find 1 param_list in
 
390
  Fct_slice.get_param_mark ff n
 
391
 
 
392
let get_called_slice ff stmt =
 
393
  match stmt.skind with
 
394
  | Instr (Call _) -> fst (Fct_slice.get_called_slice ff stmt)
 
395
  | _ -> None
 
396
 
 
397
let get_called_funcs ff stmt =
 
398
  match stmt.skind with
 
399
  | Instr (Call (_,expr_f,_,_)) ->
 
400
      if snd (Fct_slice.get_called_slice ff stmt)
 
401
      then snd (!Db.Value.expr_to_kernel_function
 
402
                  (Kstmt stmt)
 
403
                  ~with_alarms:CilE.warn_none_mode
 
404
                  ~deps:None
 
405
                  expr_f)
 
406
      else
 
407
        []
 
408
  | _ -> []
 
409
 
 
410
 
 
411
let db_pretty fmt (_project, kf) =
 
412
    try !Db.Pdg.pretty fmt (!Db.Pdg.get kf)
 
413
    with Not_found -> ()
 
414
 
 
415
let dot_project ~filename ~title project =
 
416
  PrintSlice.build_dot_project filename title project
 
417
 
 
418
let create_slice =
 
419
  M.debug 1 "[slicing] create_slice@.";
 
420
  SlicingProject.create_slice
 
421
let copy_slice _proj ff =
 
422
  M.debug 1 "[slicing] copy_slice@.";
 
423
  Fct_slice.copy_slice ff
 
424
let split_slice =
 
425
  M.debug 1 "[slicing] split_slice@.";
 
426
  SlicingProject.split_slice
 
427
let merge_slices proj ff_1 ff_2 ~replace =
 
428
  M.debug 1 "[slicing] merge_slices@.";
 
429
  SlicingProject.merge_slices proj ff_1 ff_2 replace
 
430
let remove_slice =
 
431
  M.debug 1 "[slicing] remove_slice@.";
 
432
  SlicingProject.remove_ff
 
433
 
 
434
let apply_next_action =
 
435
  M.debug 1 "[slicing] apply_next_action@.";
 
436
  SlicingProject.apply_next_action
 
437
 
 
438
let apply_all_actions =
 
439
  M.debug 1 "[slicing] apply_all_actions@.";
 
440
  SlicingProject.apply_all_actions
 
441
 
 
442
(** Global data managment *)
 
443
 
 
444
 
 
445
type t_project_management = 
 
446
    SlicingTypes.sl_project list * SlicingTypes.sl_project option
 
447
 
 
448
module P =
 
449
  Computation.Ref
 
450
    (struct
 
451
       include Project.Datatype.Imperative
 
452
         (struct
 
453
            type t = t_project_management
 
454
            let copy _ = assert false (* TODO: deep copy *)
 
455
            let name = "t_project_management"
 
456
          end)
 
457
       let default () = [], None
 
458
     end)
 
459
    (struct
 
460
       let name = "Slicing.Project"
 
461
       let dependencies = [ ] (* others delayed below *)
 
462
     end)
 
463
 
 
464
let get_all () = let all,_current = P.get () in all
 
465
let get_project () = let _all,current = P.get () in current
 
466
let set_project proj_opt = P.set (get_all (),  proj_opt)
 
467
let mk_project name =
 
468
  !Db.Value.compute () ;
 
469
  let project = (SlicingProject.mk_project name) in
 
470
  let all,current = P.get () in
 
471
    P.set ((project :: all), current);
 
472
    project
 
473
 
 
474
(** {2 Initialisation of the slicing plugin } *)
 
475
 
 
476
let () =
 
477
  Options.register_plugin_init
 
478
    (fun () ->
 
479
       let add = Project.Computation.add_dependency P.self in
 
480
         add !Db.Pdg.self;
 
481
         add !Db.Inputs.self_external;
 
482
         add !Db.Outputs.self_external)
 
483
 
 
484
(** Register external functions into Db.  *)
 
485
let () =
 
486
  Db.Slicing.self := P.self;
 
487
  Db.Slicing.Project.mk_project := mk_project;
 
488
  Db.Slicing.Project.get_all := get_all;
 
489
  Db.Slicing.Project.get_project := get_project;
 
490
  Db.Slicing.Project.set_project := set_project;
 
491
  Db.Slicing.Project.get_name := SlicingProject.get_name;
 
492
  Db.Slicing.Project.pretty := SlicingProject.print_project_and_worklist ;
 
493
  Db.Slicing.Project.print_dot := dot_project ;
 
494
  Db.Slicing.Project.extract := SlicingTransform.extract ;
 
495
  Db.Slicing.Project.is_directly_called_internal := M.is_src_fun_called ;
 
496
  Db.Slicing.Project.is_called := SlicingTransform.is_src_fun_called ;
 
497
  Db.Slicing.Project.has_persistent_selection := M.has_persistent_selection ;
 
498
  Db.Slicing.Project.change_slicing_level := M.change_slicing_level ;
 
499
 
 
500
  Db.Slicing.Select.select_stmt_internal := select_stmt_computation ;
 
501
  Db.Slicing.Select.select_entry_point_internal := select_entry_point;
 
502
  Db.Slicing.Select.select_return_internal := select_return;
 
503
  Db.Slicing.Select.select_min_call_internal := select_minimal_call ;
 
504
  Db.Slicing.Select.select_stmt_ctrl_internal := select_stmt_ctrl ;
 
505
  Db.Slicing.Select.select_stmt_zone_internal := select_stmt_zone ;
 
506
  Db.Slicing.Select.select_zone_at_entry_point_internal := select_zone_at_entry ;
 
507
  Db.Slicing.Select.select_zone_at_end_internal := select_zone_at_end ;
 
508
  Db.Slicing.Select.select_modified_output_zone_internal := 
 
509
                    select_modified_output_zone ;
 
510
  Db.Slicing.Select.select_pdg_nodes_internal := select_pdg_nodes ;
 
511
 
 
512
  Db.Slicing.Select.empty_selects := empty_selects ;
 
513
  Db.Slicing.Select.add_to_selects_internal := add_to_selects ;
 
514
  Db.Slicing.Select.iter_selects_internal := iter_selects ;
 
515
 
 
516
  Db.Slicing.Select.merge_internal := merge_db_select ;
 
517
  Db.Slicing.Select.get_function := get_select_kf;
 
518
  Db.Slicing.Select.pretty := print_select;
 
519
 
 
520
  (* higher level function from slicingCmds *)
 
521
  Db.Slicing.Select.select_pdg_nodes := C.select_pdg_nodes ;
 
522
  Db.Slicing.Select.select_stmt := C.select_stmt ;
 
523
  Db.Slicing.Select.select_stmt_ctrl := C.select_stmt_ctrl ;
 
524
  Db.Slicing.Select.select_stmt_lval := C.select_stmt_lval ;
 
525
  Db.Slicing.Select.select_stmt_lval_rw := C.select_stmt_lval_rw ;
 
526
  Db.Slicing.Select.select_stmt_zone := C.select_stmt_zone ;
 
527
  Db.Slicing.Select.select_stmt_pred := C.select_stmt_pred ;
 
528
  Db.Slicing.Select.select_stmt_term := C.select_stmt_term ;
 
529
  Db.Slicing.Select.select_stmt_annot := C.select_stmt_annot ;
 
530
  Db.Slicing.Select.select_stmt_annots := C.select_stmt_annots ;
 
531
  Db.Slicing.Select.select_func_annots := C.select_func_annots ;
 
532
  Db.Slicing.Select.select_func_lval := C.select_func_lval ;
 
533
  Db.Slicing.Select.select_func_lval_rw := C.select_func_lval_rw ;
 
534
  Db.Slicing.Select.select_func_zone := C.select_func_zone ;
 
535
  Db.Slicing.Select.select_func_return := C.select_func_return ;
 
536
  Db.Slicing.Select.select_func_calls_to := C.select_func_calls_to ;
 
537
  Db.Slicing.Select.select_func_calls_into := C.select_func_calls_into ;
 
538
 
 
539
  Db.Slicing.Slice.create := create_slice ;
 
540
  Db.Slicing.Slice.remove := remove_slice ;
 
541
  Db.Slicing.Slice.remove_uncalled := SlicingProject.remove_uncalled_slices ;
 
542
  Db.Slicing.Slice.get_all := SlicingProject.get_slices ;
 
543
  Db.Slicing.Slice.get_callers := SlicingProject.get_slice_callers ;
 
544
  Db.Slicing.Slice.get_called_slice := get_called_slice ;
 
545
  Db.Slicing.Slice.get_called_funcs := get_called_funcs ;
 
546
  Db.Slicing.Slice.pretty := SlicingProject.pretty_slice ;
 
547
  Db.Slicing.Slice.get_mark_from_stmt := Fct_slice.get_stmt_mark;
 
548
  Db.Slicing.Slice.get_mark_from_label := Fct_slice.get_label_mark ;
 
549
  Db.Slicing.Slice.get_mark_from_formal := get_mark_from_param ;
 
550
  Db.Slicing.Slice.get_mark_from_local_var := Fct_slice.get_local_var_mark ;
 
551
  Db.Slicing.Slice.get_user_mark_from_inputs := Fct_slice.merge_inputs_m1_mark ;
 
552
  Db.Slicing.Slice.get_callers := SlicingProject.get_slice_callers ;
 
553
  Db.Slicing.Slice.get_function := M.get_ff_kf ;
 
554
 
 
555
  (* higher level function from slicingCmds *)
 
556
  Db.Slicing.Request.propagate_user_marks := C.topologic_propagation ;
 
557
  Db.Slicing.Request.add_selection := C.add_selection ;
 
558
  Db.Slicing.Request.add_persistent_selection := C.add_persistent_selection ;
 
559
  Db.Slicing.Request.add_persistent_cmdline := C.add_persistent_cmdline ;
 
560
 
 
561
  Db.Slicing.Request.is_already_selected_internal := is_already_selected ;
 
562
  Db.Slicing.Request.add_slice_selection_internal := add_ff_selection ;
 
563
  Db.Slicing.Request.add_selection_internal := add_fi_selection ;
 
564
  Db.Slicing.Request.add_call_slice := call_ff_in_caller ;
 
565
  Db.Slicing.Request.add_call_fun := call_fsrc_in_caller ;
 
566
  Db.Slicing.Request.add_call_min_fun := call_min_f_in_caller ;
 
567
  Db.Slicing.Request.merge_slices := merge_slices ;
 
568
  Db.Slicing.Request.copy_slice := copy_slice ;
 
569
  Db.Slicing.Request.split_slice := split_slice ;
 
570
  Db.Slicing.Request.apply_next_internal := apply_next_action ;
 
571
  Db.Slicing.Request.apply_all_internal := apply_all_actions ;
 
572
  Db.Slicing.Request.apply_all := C.apply_all ;
 
573
  Db.Slicing.Request.pretty := SlicingProject.print_proj_worklist ;
 
574
 
 
575
  Db.Slicing.Mark.compare := SlicingMarks.compare_marks ;
 
576
  Db.Slicing.Mark.pretty := SlicingMarks.pretty_mark ;
 
577
  Db.Slicing.Mark.make := SlicingMarks.mk_user_mark ;
 
578
  Db.Slicing.Mark.is_bottom := SlicingMarks.is_bottom_mark ;
 
579
  Db.Slicing.Mark.is_spare := SlicingMarks.is_spare_mark ;
 
580
  Db.Slicing.Mark.is_ctrl := SlicingMarks.is_ctrl_mark ;
 
581
  Db.Slicing.Mark.is_addr := SlicingMarks.is_addr_mark ;
 
582
  Db.Slicing.Mark.is_data := SlicingMarks.is_data_mark ;
 
583
  Db.Slicing.Mark.is_data := SlicingMarks.is_data_mark ;
 
584
  Db.Slicing.Mark.get_from_src_func := Fct_slice.get_mark_from_src_fun;
 
585
 
 
586
;;
 
587
 
 
588
let main fmt =
 
589
  if Cmdline.Slicing.is_on () then begin
 
590
    Format.fprintf fmt "@\n[slicing] in progress...@.";
 
591
 
 
592
    (* have to do the value analysis before the selections
 
593
     * because some functions use its results,
 
594
     * and the value analysis is not launched automatically. *)
 
595
    !Db.Value.compute ();
 
596
 
 
597
    let project = !Db.Slicing.Project.mk_project "Slicing" in
 
598
    !Db.Slicing.Project.set_project (Some project);
 
599
    !Db.Slicing.Request.add_persistent_cmdline project;
 
600
 
 
601
    (* Apply all pending requests. *)
 
602
    if Cmdline.Slicing.Mode.Verbose.get () > 2 then
 
603
      Format.fprintf fmt "[slicing] requests:@\n %a@\n"
 
604
        !Db.Slicing.Request.pretty project ;
 
605
    !Db.Slicing.Request.apply_all_internal project;
 
606
 
 
607
    if Cmdline.Slicing.Mode.Callers.get () then
 
608
      !Db.Slicing.Slice.remove_uncalled project;
 
609
 
 
610
    let sliced_project =
 
611
      !Db.Slicing.Project.extract 
 
612
        (!Db.Slicing.Project.get_name project ^ " export") 
 
613
        project
 
614
    in
 
615
    if Cmdline.Slicing.Print.get () then begin
 
616
      File.pretty (Cmdline.CodeOutput.get_fmt ()) ~prj:sliced_project;
 
617
      if Cmdline.Slicing.Mode.Verbose.get () > 0 then
 
618
        Format.fprintf fmt "Slicing result :@. %a@."
 
619
          !Db.Slicing.Project.pretty project
 
620
    end;
 
621
 
 
622
    Format.fprintf fmt "@\n====== SLICED CODE COMPUTED ======@.";
 
623
  end
 
624
 
 
625
let () = Db.Main.extend main
 
626
 
 
627
(** Register the plugin options *)
 
628
let () =
 
629
  Options.add_plugin ~name:"slicing" ~descr:"slicing analysis"
 
630
    [
 
631
      "-slice-print",
 
632
      Arg.Unit Cmdline.Slicing.Print.on,
 
633
      ": pretty print the sliced code";
 
634
 
 
635
      "-slice-undef-functions",
 
636
      Arg.Unit Cmdline.Slicing.Mode.SliceUndef.on,
 
637
      ": "
 
638
      ^ (if Cmdline.Slicing.Mode.SliceUndef.get () then "by default, " else "")
 
639
      ^ "allow the use of the -slicing-level option for calls to undefined functions";
 
640
      
 
641
      "-no-slice-undef-functions",
 
642
      Arg.Unit Cmdline.Slicing.Mode.SliceUndef.off,
 
643
      ": "
 
644
      ^ (if Cmdline.Slicing.Mode.SliceUndef.get () then "" else "by default, ")
 
645
      ^ "don't slice the prototype of undefined functions";
 
646
 
 
647
      "-slicing-level",
 
648
      Arg.Int (fun n -> match n with
 
649
                 | 0 | 1 | 2 | 3 -> Cmdline.Slicing.Mode.Calls.set n
 
650
                 | _ -> raise
 
651
                     (Arg.Help ("Invalid argument for -slicing-level option:" ^
 
652
                        " not in range [0-3]\n"))
 
653
      ),
 
654
      "n : set the default level of slicing used to propagate to the calls\n"
 
655
      ^"\t0 : don't slice the called functions\n"
 
656
      ^"\t1 : don't slice the called functions but propagate the marks anyway\n"
 
657
      ^"\t2 : try to use existing slices, create at most one\n"
 
658
      ^"\t3 : most precise slices\n"
 
659
      ^"  note: this value"
 
660
      ^ (Format.sprintf " (defaults to %d) " (Cmdline.Slicing.Mode.Calls.get ()))
 
661
      ^"is not used for calls to undefined functions\n"
 
662
      ^"\texcept when '-slice-undef-functions' option is set."
 
663
      ^"\n"; (* A new line as separator for
 
664
                next options related to slicing requests.
 
665
                Alphabetic order is used for them. *)
 
666
 
 
667
      "-slice-assert",
 
668
      Arg.String Cmdline.Slicing.Select.Assert.add_set,
 
669
      "f1,...,fn : select the assertions of functions f1,...,fn";
 
670
 
 
671
      "-slice-calls",
 
672
      Arg.String Cmdline.Slicing.Select.Calls.add_set,
 
673
      "f1,...,fn : select every calls to functions f1,...,fn, and all their effect";
 
674
 
 
675
      "-slice-loop-inv",
 
676
      Arg.String Cmdline.Slicing.Select.LoopInv.add_set,
 
677
      "f1,...,fn : select the loop invariants of functions f1,...,fn";
 
678
 
 
679
      "-slice-loop-var",
 
680
      Arg.String Cmdline.Slicing.Select.LoopVar.add_set,
 
681
      "f1,...,fn : select the loop variants of functions f1,...,fn";
 
682
 
 
683
      "-slice-pragma",
 
684
      Arg.String Cmdline.Slicing.Select.Pragma.add_set,
 
685
      "f1,...,fn : use the slicing pragmas in the code of functions f1,...,fn as slicing criteria\n"
 
686
      ^"\t//@slice pragma ctrl; : to reach this control-flow point\n"
 
687
      ^"\t//@slice pragma expr <expr_desc;> : to preserve the value of an expression at this control-flow point\n"
 
688
      ^"\t//@slice pragma stmt; : to preserve the effect of the next statement";
 
689
 
 
690
      "-slice-return",
 
691
      Arg.String Cmdline.Slicing.Select.Return.add_set,
 
692
      "f1,...,fn : select the result (returned value) of functions f1,...,fn";
 
693
 
 
694
      "-slice-threat",
 
695
      Arg.String Cmdline.Slicing.Select.Threat.add_set,
 
696
      "f1,...,fn : select the threats of functions f1,...,fn";
 
697
 
 
698
      "-slice-value",
 
699
      Arg.String Cmdline.Slicing.Select.Value.add_set,
 
700
      "v1,...,vn : select the result of left-values v1,...,vn at the end of the function given as entry point\n"
 
701
      ^"\t (addresses are evaluated at the beginning of the function given as entry point)";
 
702
 
 
703
      "-slice-rd",
 
704
      Arg.String Cmdline.Slicing.Select.RdAccess.add_set,
 
705
      "v1,...,vn : select the read accesses to left-values v1,...,vn\n"
 
706
      ^"\t (addresses are evaluated at the beginning of the function given as entry point)";
 
707
 
 
708
      "-slice-wr",
 
709
      Arg.String Cmdline.Slicing.Select.WrAccess.add_set,
 
710
      "v1,...,vn : select the write accesses to left-values v1,...,vn\n"
 
711
      ^"\t (addresses are evaluated at the beginning of the function given as entry point)"
 
712
      ^"\n"; (* A new line as separator for
 
713
                next options related to debug. *)
 
714
    ]
 
715
    ~debug:[ "-debug",
 
716
        Arg.Int Cmdline.Slicing.Mode.Verbose.set,
 
717
        " n : set the level of slicing debug to n";
 
718
 
 
719
        "-verbose",
 
720
        Arg.Unit Cmdline.Slicing.Mode.Verbose.incr,
 
721
        ": increment the level of slicing debug";
 
722
 
 
723
        "-no-slice-callers",
 
724
        Arg.Unit Cmdline.Slicing.Mode.Callers.off,
 
725
        ": don't propagate the slicing to the function callers";
 
726
           ]
 
727
 
 
728
;;