Release coccinelle-0.2.0
[bpt/coccinelle.git] / tools / alloc_free.ml
CommitLineData
9f8e26f4
C
1(*
2 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
4 * This file is part of Coccinelle.
5 *
6 * Coccinelle is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, according to version 2 of the License.
9 *
10 * Coccinelle is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
20 *)
21
22
34e49164
C
23(* The following finds out for each file, how it does deallocation for each
24allocator *)
25
26let collect i =
27 let info = ref [] in
28 let rec loop _ =
29 let l = input_line i in
30 (if String.length l > 2 && String.get l 0 = '+'
31 then info := (String.sub l 1 (String.length l - 1))::!info);
32 loop() in
33 try loop()
34 with End_of_file -> List.rev !info
35
36let split l =
37 let rec loop acc = function
38 [] -> acc
39 | x::xs ->
40 if String.get x 0 = '+' (* the start of a new file *)
41 then
42 (match Str.split (Str.regexp " ") x with
43 _::x::_ -> loop ((x,[])::acc) xs
44 | _ -> failwith ("no file: "^x))
45 else
46 let acc =
47 match acc with
48 (file,instances)::rest -> (file,x::instances)::rest
49 | _ -> failwith "not possible" in
50 loop acc xs in
51 let res = List.rev (loop [] l) in
52 List.map (function (x,l) -> (x,List.rev l)) res
53
54let detect_alloc_free str l =
55 let try_add a f l =
56 let (same,diff) = List.partition (function (a1,f1) -> a = a1) l in
57 match same with
58 [(a1,f1)] -> if List.mem f f1 then l else (a1,f::f1) :: diff
59 | _ -> (a,[f])::l in
60 let rec loop acc = function
61 [] -> acc
62 | x::xs ->
63 match Str.split (Str.regexp (str^"\", ")) x with
64 _::matches ->
65 let acc =
66 List.fold_left
67 (function acc ->
68 function rest ->
69 (match Str.split (Str.regexp "[, )]+") rest with
70 alloc::free::_ -> try_add alloc free acc
71 | _ -> acc))
72 acc matches in
73 loop acc xs
74 | _ -> loop acc xs in
75 List.sort compare
76 (List.map (function (a,f) -> (a,List.sort compare f)) (loop [] l))
77
78let rec iterate str = function
79 [] -> []
80 | (x,l)::xs ->
81 List.fold_left
82 (function rest ->
83 function info ->
84 let (same,diff) =
85 List.partition (function (x1,l1) -> l1 = info) rest in
86 match same with
87 [(files,info)] -> (x::files,info)::diff
88 | _ -> ([x],info)::diff)
89 (iterate str xs) (detect_alloc_free str l)
90
91(* ------------------------------------------------------------------------ *)
92(* The following prints that information *)
93
94let print_output l =
95 List.iter
96 (function (files,(a,fs)) ->
97 List.iter (function x -> Printf.printf "%s\n" x) files;
98 Printf.printf " alloc: %s, free: %s\n" a (String.concat ", " fs);
99 Printf.printf "\n")
100 l
101
102(* ------------------------------------------------------------------------ *)
103(* The following makes a semantic patch for that information *)
104
105let sedify o generic_file dir l =
106 List.iter
107 (function (files,(a,fs)) ->
108 match fs with
109 [f] ->
110 let _ =
111 Sys.command
112 (Printf.sprintf
113 "sed s/ALLOC/%s/ %s | sed s/FREE/%s/ > %s/%s-%s.cocci\n"
114 a generic_file f dir a f) in ()
115 | _ -> ())
116 l;
117 List.iter
118 (function (files,(a,fs)) ->
119 match fs with
120 [f] -> Printf.fprintf o "mono_spatch_linux %s-%s.cocci &\n" a f
121 | _ -> ())
122 l
123
124let collect_allocs l =
125 let union =
126 List.fold_left
127 (function rest -> function x ->
128 if List.mem x rest then rest else x::rest) in
129 List.fold_left
130 (function rest ->
131 function (files,(a,fs)) ->
132 let (same,diff) =
133 List.partition (function (a1,fs1) -> a = a1) rest in
134 match same with
135 [(a1,fs1)] -> (a,union fs fs1)::diff
136 | [] -> (a,fs)::rest
137 | _ -> failwith "not possible")
138 [] l
139
140let sedify_ors o generic_file dir l =
141 let l = collect_allocs l in
142 List.iter
143 (function (a,fs) ->
144 match fs with
145 [_] | [] -> ()
146 | (f::_) ->
147 let sfs =
148 Printf.sprintf "\"\\\\\\(%s\\\\\\)\""
149 (String.concat "\\\\\\|" fs) in
150 let _ =
151 Sys.command
152 (Printf.sprintf
153 "sed s/ALLOC/%s/ %s | sed s/FREE/%s/ > %s/%s-%s_et_al.cocci\n"
154 a generic_file sfs dir a f) in ())
155 l;
156 List.iter
157 (function (a,fs) ->
158 match fs with
159 [_] | [] -> ()
160 | (f::_) ->
161 Printf.fprintf o "mono_spatch_linux %s-%s_et_al.cocci &\n" a f)
162 l
163
164(* ------------------------------------------------------------------------ *)
165
166let sed = ref false
167let gen = ref "generic2.cocci"
168let dir = ref "p2"
169let file = ref ""
170let str = ref "detected allocator"
171
172let options = [ "-sed", Arg.Set sed, "sed output";
173 "-sp", Arg.String (function x -> gen := x),
174 "detection string";
175 "-str", Arg.String (function x -> str := x),
176 "cocci file for use with sed";
177 "-dir", Arg.String (function x -> dir := x),
178 "dir for sed output"; ]
179let usage = ""
180
181let _ =
182 Arg.parse (Arg.align options) (fun x -> file := x) usage;
183 let i = open_in !file in
184 let l = collect i in
185 close_in i;
186 let l = split l in
187 let l = iterate !str l in
188 (if !sed
189 then
190 begin
191 let o = open_out (Printf.sprintf "%s/files" !dir) in
8ba84ae2 192 Printf.fprintf o "#!/bin/sh\n\n";
34e49164
C
193 sedify o !gen !dir l;
194 sedify_ors o !gen !dir l;
195 Printf.fprintf o "\nwait\n/bin/rm tmp*out\n";
196 close_out o
197 end);
198 if not !sed then print_output l