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