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

« back to all changes in this revision

Viewing changes to cil/src/ext/astslicer.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
(*  Copyright (C) 2001-2003,                                              *)
 
4
(*   George C. Necula    <necula@cs.berkeley.edu>                         *)
 
5
(*   Scott McPeak        <smcpeak@cs.berkeley.edu>                        *)
 
6
(*   Wes Weimer          <weimer@cs.berkeley.edu>                         *)
 
7
(*   Ben Liblit          <liblit@cs.berkeley.edu>                         *)
 
8
(*  All rights reserved.                                                  *)
 
9
(*                                                                        *)
 
10
(*  Redistribution and use in source and binary forms, with or without    *)
 
11
(*  modification, are permitted provided that the following conditions    *)
 
12
(*  are met:                                                              *)
 
13
(*                                                                        *)
 
14
(*  1. Redistributions of source code must retain the above copyright     *)
 
15
(*  notice, this list of conditions and the following disclaimer.         *)
 
16
(*                                                                        *)
 
17
(*  2. Redistributions in binary form must reproduce the above copyright  *)
 
18
(*  notice, this list of conditions and the following disclaimer in the   *)
 
19
(*  documentation and/or other materials provided with the distribution.  *)
 
20
(*                                                                        *)
 
21
(*  3. The names of the contributors may not be used to endorse or        *)
 
22
(*  promote products derived from this software without specific prior    *)
 
23
(*  written permission.                                                   *)
 
24
(*                                                                        *)
 
25
(*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   *)
 
26
(*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     *)
 
27
(*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS     *)
 
28
(*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE        *)
 
29
(*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,   *)
 
30
(*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  *)
 
31
(*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      *)
 
32
(*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER      *)
 
33
(*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT    *)
 
34
(*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN     *)
 
35
(*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *)
 
36
(*  POSSIBILITY OF SUCH DAMAGE.                                           *)
 
37
(*                                                                        *)
 
38
(*  File modified by CEA (Commissariat ļæ½ l'ļæ½nergie Atomique).             *)
 
39
(**************************************************************************)
 
40
 
 
41
(*
 
42
 *
 
43
 * Copyright (c) 2001-2002,
 
44
 *  George C. Necula    <necula@cs.berkeley.edu>
 
45
 *  Scott McPeak        <smcpeak@cs.berkeley.edu>
 
46
 *  Wes Weimer          <weimer@cs.berkeley.edu>
 
47
 * All rights reserved.
 
48
 *
 
49
 * Redistribution and use in source and binary forms, with or without
 
50
 * modification, are permitted provided that the following conditions are
 
51
 * met:
 
52
 *
 
53
 * 1. Redistributions of source code must retain the above copyright
 
54
 * notice, this list of conditions and the following disclaimer.
 
55
 *
 
56
 * 2. Redistributions in binary form must reproduce the above copyright
 
57
 * notice, this list of conditions and the following disclaimer in the
 
58
 * documentation and/or other materials provided with the distribution.
 
59
 *
 
60
 * 3. The names of the contributors may not be used to endorse or promote
 
61
 * products derived from this software without specific prior written
 
62
 * permission.
 
63
 *
 
64
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
65
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
66
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
67
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 
68
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
69
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
70
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
71
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
72
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
73
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
74
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
75
 *
 
76
 *)
 
77
open Cil
 
78
module E = Errormsg
 
79
(*
 
80
 * Weimer: an AST Slicer for use in Daniel's Delta Debugging Algorithm.
 
81
 *)
 
82
let debug = ref false
 
83
 
 
84
(*
 
85
 * This type encapsulates a mapping form program tsets to names
 
86
 * in our naming convention.
 
87
 *)
 
88
type enumeration_info = {
 
89
  statements : (stmt, string) Hashtbl.t ;
 
90
  instructions : (instr, string) Hashtbl.t ;
 
91
}
 
92
 
 
93
(**********************************************************************
 
94
 * Enumerate 1
 
95
 *
 
96
 * Given a cil file, enumerate all of the statement names in it using
 
97
 * our naming scheme.
 
98
 **********************************************************************)
 
99
let enumerate out (f : Cil.file) =
 
100
  let st_ht = Hashtbl.create 32767 in
 
101
  let in_ht = Hashtbl.create 32767 in
 
102
 
 
103
  let emit base i ht elt =
 
104
    let str = Printf.sprintf "%s.%d" base !i in
 
105
    Printf.fprintf out "%s\n" str ;
 
106
    Hashtbl.add ht elt str ;
 
107
    incr i
 
108
  in
 
109
  let emit_call base i str2 ht elt =
 
110
    let str = Printf.sprintf "%s.%d" base !i in
 
111
    Printf.fprintf out "%s - %s\n" str str2 ;
 
112
    Hashtbl.add ht elt str ;
 
113
    incr i
 
114
  in
 
115
  let descend base i =
 
116
    let res = (Printf.sprintf "%s.%d" base !i),(ref 0) in
 
117
    res
 
118
  in
 
119
  let rec doBlock b base i =
 
120
    doStmtList b.bstmts base i
 
121
  and doStmtList sl base i =
 
122
    List.iter (fun s -> match s.skind with
 
123
    | Instr(il) -> doIL il base i
 
124
    | Return(_,_)
 
125
    | Goto(_,_)
 
126
    | Continue(_)
 
127
    | Break(_) -> emit base i st_ht s
 
128
    | If(e,b1,b2,_) ->
 
129
          emit base i st_ht s ;
 
130
          decr i ;
 
131
          Printf.fprintf out "(\n" ;
 
132
          let base',i' = descend base i in
 
133
          doBlock b1 base' i' ;
 
134
          Printf.fprintf out ") (\n" ;
 
135
          let base'',i'' = descend base i in
 
136
          doBlock b2 base'' i'' ;
 
137
          Printf.fprintf out ")\n" ;
 
138
          incr i
 
139
    | Switch(_,b,_,_)
 
140
    | Loop(b,_,_,_)
 
141
    | Block(b) ->
 
142
          emit base i st_ht s ;
 
143
          decr i ;
 
144
          let base',i' = descend base i in
 
145
          Printf.fprintf out "(\n" ;
 
146
          doBlock b base' i' ;
 
147
          Printf.fprintf out ")\n" ;
 
148
          incr i
 
149
    | TryExcept _ | TryFinally _ ->
 
150
        E.s (E.unimp "astslicer:enumerate")
 
151
    ) sl
 
152
  and doIL il base i =
 
153
    List.iter (fun ins -> match ins with
 
154
      | Set _
 
155
      | Asm _ -> emit base i in_ht ins
 
156
      | Call(_,(Lval(Var(vi),NoOffset)),_,_) ->
 
157
                 emit_call base i vi.vname in_ht ins
 
158
      | Call(_,f,_,_) -> emit_call base i "*" in_ht ins
 
159
    ) il
 
160
  in
 
161
  let doGlobal g = match g with
 
162
  | GFun(fd,_) ->
 
163
      Printf.fprintf out "%s (\n" (!Cil.output_ident fd.svar.vname) ;
 
164
      let cur = ref 0 in
 
165
      doBlock fd.sbody fd.svar.vname cur ;
 
166
      Printf.fprintf out ")\n" ;
 
167
      ()
 
168
  | _ -> ()
 
169
  in
 
170
  List.iter doGlobal f.globals ;
 
171
  { statements = st_ht ;
 
172
    instructions = in_ht ; }
 
173
 
 
174
(**********************************************************************
 
175
 * Enumerate 2
 
176
 *
 
177
 * Given a cil file and some enumeration information, do a log-calls-like
 
178
 * transformation on it that prints out our names as you reach them.
 
179
 **********************************************************************)
 
180
(*
 
181
 * This is the visitor that handles annotations
 
182
 *)
 
183
let print_it pfun name =
 
184
  ((Call(None,Lval(Var(pfun),NoOffset),
 
185
    [mkString (name ^ "\n")],locUnknown)))
 
186
 
 
187
class enumVisitor pfun st_ht in_ht = object
 
188
  inherit nopCilVisitor
 
189
  method vinst i =
 
190
    if Hashtbl.mem in_ht i then begin
 
191
      let name = Hashtbl.find in_ht i in
 
192
      let newinst = print_it pfun name in
 
193
      ChangeTo([newinst ; i])
 
194
    end else
 
195
      DoChildren
 
196
  method vstmt s =
 
197
    if Hashtbl.mem st_ht s then begin
 
198
      let name = Hashtbl.find st_ht s in
 
199
      let newinst = print_it pfun name in
 
200
      let newstmt = mkStmtOneInstr newinst in
 
201
      let newblock = mkBlock [newstmt ; s] in
 
202
      let replace_with = mkStmt (Block(newblock)) in
 
203
      ChangeDoChildrenPost(s,(fun i -> replace_with))
 
204
    end else
 
205
      DoChildren
 
206
  method vfunc f =
 
207
      let newinst = print_it pfun f.svar.vname in
 
208
      let newstmt = mkStmtOneInstr newinst in
 
209
      let new_f = { f with sbody = { f.sbody with
 
210
        bstmts = newstmt :: f.sbody.bstmts }} in
 
211
      ChangeDoChildrenPost(new_f,(fun i -> i))
 
212
end
 
213
 
 
214
let annotate (f : Cil.file) ei = begin
 
215
  (* Create a prototype for the logging function *)
 
216
  let printfFun =
 
217
    let fdec = emptyFunction "printf" in
 
218
    let argf  = makeLocalVar fdec "format" charConstPtrType in
 
219
    fdec.svar.vtype <- TFun(intType, Some [ ("format", charConstPtrType, [])],
 
220
                            true, []);
 
221
    fdec
 
222
  in
 
223
  let visitor = (new enumVisitor printfFun.svar ei.statements
 
224
    ei.instructions) in
 
225
  visitCilFileSameGlobals visitor f;
 
226
  f
 
227
end
 
228
 
 
229
(**********************************************************************
 
230
 * STAGE 2
 
231
 *
 
232
 * Perform a transitive-closure-like operation on the parts of the program
 
233
 * that the user wants to keep. We use a CIL visitor to walk around
 
234
 * and a number of hash tables to keep track of the things we want to keep.
 
235
 **********************************************************************)
 
236
(*
 
237
 * Hashtables:
 
238
 * ws   - wanted stmts
 
239
 * wi   - wanted instructions
 
240
 * wt   - wanted typeinfo
 
241
 * wc   - wanted compinfo
 
242
 * we   - wanted enuminfo
 
243
 * wv   - wanted varinfo
 
244
 *)
 
245
 
 
246
let mode = ref false (* was our parented wanted? *)
 
247
let finished = ref true (* set to false if we update something *)
 
248
 
 
249
(* In the given hashtable, mark the given element was "wanted" *)
 
250
let update ht elt =
 
251
  if Hashtbl.mem ht elt && (Hashtbl.find ht elt = true) then ()
 
252
  else begin
 
253
    Hashtbl.add ht elt true ;
 
254
    finished := false
 
255
  end
 
256
 
 
257
(* Handle a particular stage of the AST tree walk. Use "mode" (i.e.,
 
258
 * whether our parent was wanted) and the hashtable (which tells us whether
 
259
 * the user had any special instructions for this element) to determine
 
260
 * what do to. *)
 
261
let handle ht elt rep =
 
262
    if !mode then begin
 
263
      if Hashtbl.mem ht elt && (Hashtbl.find ht elt = false) then begin
 
264
        (* our parent is Wanted but we were told to ignore this subtree,
 
265
         * so we won't be wanted. *)
 
266
        mode := false ;
 
267
        ChangeDoChildrenPost(rep,(fun elt -> mode := true ; elt))
 
268
      end else begin
 
269
        (* we were not told to ignore this subtree, and our parent is
 
270
         * Wanted, so we will be Wanted too! *)
 
271
        update ht elt ;
 
272
        DoChildren
 
273
      end
 
274
    end else if Hashtbl.mem ht elt && (Hashtbl.find ht elt = true) then begin
 
275
      (* our parent was not wanted but we were wanted, so turn the
 
276
       * mode on for now *)
 
277
      mode := true ;
 
278
      ChangeDoChildrenPost(rep,(fun elt -> mode := false ; elt))
 
279
    end else
 
280
      DoChildren
 
281
 
 
282
let handle_no_default ht elt rep old_mode =
 
283
    if Hashtbl.mem ht elt && (Hashtbl.find ht elt = true) then begin
 
284
      (* our parent was not wanted but we were wanted, so turn the
 
285
       * mode on for now *)
 
286
      mode := true ;
 
287
      ChangeDoChildrenPost(rep,(fun elt -> mode := old_mode ; elt))
 
288
    end else begin
 
289
      mode := false ;
 
290
      ChangeDoChildrenPost(rep,(fun elt -> mode := old_mode ; elt))
 
291
    end
 
292
 
 
293
(*
 
294
 * This is the visitor that handles elements (marks them as wanted)
 
295
 *)
 
296
class transVisitor ws wi wt wc we wv = object
 
297
  inherit nopCilVisitor
 
298
 
 
299
  method vvdec vi = handle_no_default wv vi vi !mode
 
300
  method vvrbl vi = handle wv vi vi
 
301
  method vinst i = handle wi i [i]
 
302
  method vstmt s = handle ws s s
 
303
  method vfunc f = handle wv f.svar f
 
304
  method vglob g = begin
 
305
    match g with
 
306
    | GType(ti,_) -> handle wt ti [g]
 
307
    | GCompTag(ci,_)
 
308
    | GCompTagDecl(ci,_) -> handle wc ci [g]
 
309
    | GEnumTag(ei,_)
 
310
    | GEnumTagDecl(ei,_) -> handle we ei [g]
 
311
    | GVarDecl(vi,_)
 
312
    | GVar(vi,_,_) -> handle wv vi [g]
 
313
    | GFun(f,_) -> handle wv f.svar [g]
 
314
    | _ -> DoChildren
 
315
  end
 
316
  method vtype t = begin
 
317
    match t with
 
318
    | TNamed(ti,_) -> handle wt ti t
 
319
    | TComp(ci,_) -> handle wc ci t
 
320
    | TEnum(ei,_) -> handle we ei t
 
321
    | _ -> DoChildren
 
322
  end
 
323
end
 
324
 
 
325
(**********************************************************************
 
326
 * STAGE 3
 
327
 *
 
328
 * Eliminate all of the elements from the program that are not marked
 
329
 * "keep".
 
330
 **********************************************************************)
 
331
(*
 
332
 * This is the visitor that throws away elements
 
333
 *)
 
334
let handle ht elt keep drop =
 
335
  if (Hashtbl.mem ht elt) && (Hashtbl.find ht elt = true) then
 
336
    (* DoChildren *) ChangeDoChildrenPost(keep,(fun a -> a))
 
337
  else
 
338
    ChangeTo(drop)
 
339
 
 
340
class dropVisitor ws wi wt wc we wv = object
 
341
  inherit nopCilVisitor
 
342
 
 
343
  method vinst i = handle wi i [i] []
 
344
  method vstmt s = handle ws s s (mkStmt (Instr([])))
 
345
  method vglob g = begin
 
346
    match g with
 
347
    | GType(ti,_) -> handle wt ti [g] []
 
348
    | GCompTag(ci,_)
 
349
    | GCompTagDecl(ci,_) -> handle wc ci [g] []
 
350
    | GEnumTag(ei,_)
 
351
    | GEnumTagDecl(ei,_) -> handle we ei [g] []
 
352
    | GVarDecl(vi,_)
 
353
    | GVar(vi,_,_) -> handle wv vi [g] []
 
354
    | GFun(f,l) ->
 
355
        let new_locals = List.filter (fun vi ->
 
356
          Hashtbl.mem wv vi && (Hashtbl.find wv vi = true)) f.slocals in
 
357
        let new_fundec = { f with slocals = new_locals} in
 
358
        handle wv f.svar [(GFun(new_fundec,l))] []
 
359
    | _ -> DoChildren
 
360
  end
 
361
end
 
362
 
 
363
(**********************************************************************
 
364
 * STAGE 1
 
365
 *
 
366
 * Mark up the file with user-given information about what to keep and
 
367
 * what to drop.
 
368
 **********************************************************************)
 
369
type mark = Wanted | Unwanted | Unspecified
 
370
(* Given a cil file and a list of strings, mark all of the given ASTSlicer
 
371
 * points as wanted or unwanted. *)
 
372
let mark_file (f : Cil.file) (names : (string, mark) Hashtbl.t) =
 
373
  let ws = Hashtbl.create 32767 in
 
374
  let wi = Hashtbl.create 32767 in
 
375
  let wt = Hashtbl.create 32767 in
 
376
  let wc = Hashtbl.create 32767 in
 
377
  let we = Hashtbl.create 32767 in
 
378
  let wv = Hashtbl.create 32767 in
 
379
  if !debug then Printf.printf "Applying user marks to file ...\n" ;
 
380
  let descend base i =
 
381
    let res = (Printf.sprintf "%s.%d" base !i),(ref 0) in
 
382
    res
 
383
  in
 
384
  let check base i (default : mark) =
 
385
    let str = Printf.sprintf "%s.%d" base !i in
 
386
    if !debug then Printf.printf "Looking for [%s]\n" str ;
 
387
    try Hashtbl.find names str
 
388
    with _ -> default
 
389
  in
 
390
  let mark ht stmt wanted = match wanted with
 
391
    Unwanted -> Hashtbl.replace ht stmt false
 
392
  | Wanted -> Hashtbl.replace ht stmt true
 
393
  | Unspecified -> ()
 
394
  in
 
395
  let rec doBlock b base i default =
 
396
    doStmtList b.bstmts base i default
 
397
  and doStmtList sl base i default =
 
398
    List.iter (fun s -> match s.skind with
 
399
    | Instr(il) -> doIL il base i default
 
400
    | Return(_,_)
 
401
    | Goto(_,_)
 
402
    | Continue(_)
 
403
    | Break(_) ->
 
404
        mark ws s (check base i default) ; incr i
 
405
    | If(e,b1,b2,_) ->
 
406
        let inside = check base i default in
 
407
        mark ws s inside ;
 
408
        let base',i' = descend base i in
 
409
        doBlock b1 base' i' inside ;
 
410
        let base'',i'' = descend base i in
 
411
        doBlock b2 base'' i'' inside ;
 
412
        incr i
 
413
    | Switch(_,b,_,_)
 
414
    | Loop(b,_,_,_)
 
415
    | Block(b) ->
 
416
        let inside = check base i default in
 
417
        mark ws s inside ;
 
418
        let base',i' = descend base i in
 
419
        doBlock b base' i' inside ;
 
420
        incr i
 
421
    | TryExcept _ | TryFinally _ ->
 
422
        E.s (E.unimp "astslicer: mark")
 
423
    ) sl
 
424
  and doIL il base i default =
 
425
    List.iter (fun ins -> mark wi ins (check base i default) ; incr i) il
 
426
  in
 
427
  let doGlobal g = match g with
 
428
  | GFun(fd,_) ->
 
429
      let cur = ref 0 in
 
430
      if Hashtbl.mem names fd.svar.vname then begin
 
431
        if Hashtbl.find names fd.svar.vname = Wanted then begin
 
432
          Hashtbl.replace wv fd.svar true ;
 
433
          doBlock fd.sbody fd.svar.vname cur (Wanted);
 
434
        end else begin
 
435
          Hashtbl.replace wv fd.svar false ;
 
436
          doBlock fd.sbody fd.svar.vname cur (Unspecified);
 
437
        end
 
438
      end else begin
 
439
        doBlock fd.sbody fd.svar.vname cur (Unspecified);
 
440
      end
 
441
  | _ -> ()
 
442
  in
 
443
  List.iter doGlobal f.globals ;
 
444
  if !debug then begin
 
445
    Hashtbl.iter (fun k v ->
 
446
      ignore (Pretty.printf "want-s %b %a\n" v d_stmt k)) ws ;
 
447
    Hashtbl.iter (fun k v ->
 
448
      ignore (Pretty.printf "want-i %b %a\n" v d_instr k)) wi ;
 
449
    Hashtbl.iter (fun k v ->
 
450
      ignore (Pretty.printf "want-v %b %s\n" v (!Cil.output_ident k.vname)))
 
451
      wv ;
 
452
  end ;
 
453
  (*
 
454
   * Now repeatedly mark all other things that must be kept.
 
455
   *)
 
456
  let visitor = (new transVisitor ws wi wt wc we wv) in
 
457
  finished := false ;
 
458
  if !debug then  (Printf.printf "\nPerforming Transitive Closure\n\n" );
 
459
  while not !finished do
 
460
    finished := true ;
 
461
    visitCilFileSameGlobals visitor f
 
462
  done  ;
 
463
  if !debug then begin
 
464
    Hashtbl.iter (fun k v ->
 
465
      if v then ignore (Pretty.printf "want-s %a\n" d_stmt k)) ws ;
 
466
    Hashtbl.iter (fun k v ->
 
467
      if v then ignore (Pretty.printf "want-i %a\n" d_instr k)) wi ;
 
468
    Hashtbl.iter (fun k v ->
 
469
      if v then ignore (Pretty.printf "want-t %s\n" k.tname)) wt ;
 
470
    Hashtbl.iter (fun k v ->
 
471
      if v then ignore (Pretty.printf "want-c %s\n" k.cname)) wc ;
 
472
    Hashtbl.iter (fun k v ->
 
473
      if v then ignore (Pretty.printf "want-e %s\n" k.ename)) we ;
 
474
    Hashtbl.iter (fun k v ->
 
475
      if v then ignore (Pretty.printf "want-v %s\n" k.vname)) wv ;
 
476
  end ;
 
477
 
 
478
  (*
 
479
   * Now drop everything we didn't need.
 
480
   *)
 
481
  if !debug then  (Printf.printf "Dropping Unwanted Elements\n" );
 
482
  let visitor = (new dropVisitor ws wi wt wc we wv) in
 
483
  visitCilFile visitor f