1 /*
2 * Copyright (C) 2009 Dan Carpenter.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 */
17
18 /*
19 * This test checks that locks are held the same across all returns.
20 *
21 * Of course, some functions are designed to only hold the locks on success.
22 * Oh well... We can rewrite it later if we want.
23 *
24 * The list of wine locking functions came from an earlier script written
25 * by Michael Stefaniuc.
26 *
27 */
28
29 #include "parse.h"
30 #include "smatch.h"
31 #include "smatch_extra.h"
32 #include "smatch_slist.h"
33
34 static int my_id;
35
36 static int func_has_transition;
37
38 STATE(locked);
39 STATE(start_state);
40 STATE(unlocked);
41 STATE(impossible);
42
43 enum action {
44 LOCK,
45 UNLOCK,
46 };
47
48 enum return_type {
49 ret_any,
50 ret_non_zero,
51 ret_zero,
52 ret_one,
53 ret_negative,
54 ret_positive,
55 };
56
57 #define RETURN_VAL -1
58 #define NO_ARG -2
59
60 struct lock_info {
61 const char *function;
62 enum action action;
63 const char *name;
64 int arg;
65 enum return_type return_type;
66 };
67
68 static struct lock_info wine_lock_table[] = {
69 {"create_window_handle", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
70 {"WIN_GetPtr", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
71 {"WIN_ReleasePtr", UNLOCK, "create_window_handle", 0, ret_any},
72 {"EnterCriticalSection", LOCK, "CriticalSection", 0, ret_any},
73 {"LeaveCriticalSection", UNLOCK, "CriticalSection", 0, ret_any},
74 {"RtlEnterCriticalSection", LOCK, "RtlCriticalSection", 0, ret_any},
75 {"RtlLeaveCriticalSection", UNLOCK, "RtlCriticalSection", 0, ret_any},
76 {"GDI_GetObjPtr", LOCK, "GDI_Get", 0, ret_non_zero},
77 {"GDI_ReleaseObj", UNLOCK, "GDI_Get", 0, ret_any},
78 {"LdrLockLoaderLock", LOCK, "LdrLockLoaderLock", 2, ret_any},
79 {"LdrUnlockLoaderLock", UNLOCK, "LdrLockLoaderLock", 1, ret_any},
80 {"_lock", LOCK, "_lock", 0, ret_any},
81 {"_unlock", UNLOCK, "_lock", 0, ret_any},
82 {"msiobj_lock", LOCK, "msiobj_lock", 0, ret_any},
83 {"msiobj_unlock", UNLOCK, "msiobj_lock", 0, ret_any},
84 {"RtlAcquirePebLock", LOCK, "PebLock", NO_ARG, ret_any},
85 {"RtlReleasePebLock", UNLOCK, "PebLock", NO_ARG, ret_any},
86 {"server_enter_uninterrupted_section", LOCK, "server_uninterrupted_section", 0, ret_any},
87 {"server_leave_uninterrupted_section", UNLOCK, "server_uninterrupted_section", 0, ret_any},
88 {"RtlLockHeap", LOCK, "RtlLockHeap", 0, ret_any},
89 {"RtlUnlockHeap", UNLOCK, "RtlLockHeap", 0, ret_any},
90 {"_EnterSysLevel", LOCK, "SysLevel", 0, ret_any},
91 {"_LeaveSysLevel", UNLOCK, "SysLevel", 0, ret_any},
92 {"USER_Lock", LOCK, "USER_Lock", NO_ARG, ret_any},
93 {"USER_Unlock", UNLOCK, "USER_Lock", NO_ARG, ret_any},
94 {"wine_tsx11_lock", LOCK, "wine_tsx11_lock", NO_ARG, ret_any},
95 {"wine_tsx11_unlock", UNLOCK, "wine_tsx11_lock", NO_ARG, ret_any},
96 {"wine_tsx11_lock_ptr", LOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
97 {"wine_tsx11_unlock_ptr", UNLOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
98 {"wined3d_mutex_lock", LOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
99 {"wined3d_mutex_unlock", UNLOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
100 {"X11DRV_DIB_Lock", LOCK, "X11DRV_DIB_Lock", 0, ret_any},
101 {"X11DRV_DIB_Unlock", UNLOCK, "X11DRV_DIB_Lock", 0, ret_any},
102 };
103
104 static struct lock_info kernel_lock_table[] = {
105 {"lock_kernel", LOCK, "BKL", NO_ARG, ret_any},
106 {"unlock_kernel", UNLOCK, "BKL", NO_ARG, ret_any},
107
108 {"spin_lock", LOCK, "spin_lock", 0, ret_any},
109 {"spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
110 {"spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
111 {"_spin_lock", LOCK, "spin_lock", 0, ret_any},
112 {"_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
113 {"_spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
114 {"__spin_lock", LOCK, "spin_lock", 0, ret_any},
115 {"__spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
116 {"__spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
117 {"raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
118 {"raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
119 {"_raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
120 {"_raw_spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
121 {"_raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
122 {"__raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
123 {"__raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
124
125 {"spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
126 {"spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
127 {"_spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
128 {"_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
129 {"__spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
130 {"__spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
131 {"_raw_spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
132 {"_raw_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
133 {"__raw_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
134 {"spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
135 {"spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
136 {"_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
137 {"_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
138 {"__spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
139 {"__spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
140 {"_raw_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
141 {"_raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
142 {"__raw_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
143 {"__raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
144 {"spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
145 {"_spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
146 {"__spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
147 {"_raw_spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
148 {"spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
149 {"spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
150 {"_spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
151 {"_spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
152 {"__spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
153 {"__spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
154
155 {"spin_trylock", LOCK, "spin_lock", 0, ret_one},
156 {"_spin_trylock", LOCK, "spin_lock", 0, ret_one},
157 {"__spin_trylock", LOCK, "spin_lock", 0, ret_one},
158 {"raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
159 {"_raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
160 {"spin_trylock_irq", LOCK, "spin_lock", 0, ret_one},
161 {"spin_trylock_irqsave", LOCK, "spin_lock", 0, ret_one},
162 {"spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
163 {"_spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
164 {"__spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
165 {"__raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
166 {"_atomic_dec_and_lock", LOCK, "spin_lock", 1, ret_one},
167
168 {"read_lock", LOCK, "read_lock", 0, ret_any},
169 {"read_unlock", UNLOCK, "read_lock", 0, ret_any},
170 {"_read_lock", LOCK, "read_lock", 0, ret_any},
171 {"_read_unlock", UNLOCK, "read_lock", 0, ret_any},
172 {"__read_lock", LOCK, "read_lock", 0, ret_any},
173 {"__read_unlock", UNLOCK, "read_lock", 0, ret_any},
174 {"_raw_read_lock", LOCK, "read_lock", 0, ret_any},
175 {"_raw_read_unlock", UNLOCK, "read_lock", 0, ret_any},
176 {"__raw_read_lock", LOCK, "read_lock", 0, ret_any},
177 {"__raw_read_unlock", UNLOCK, "read_lock", 0, ret_any},
178 {"read_lock_irq", LOCK, "read_lock", 0, ret_any},
179 {"read_unlock_irq" , UNLOCK, "read_lock", 0, ret_any},
180 {"_read_lock_irq", LOCK, "read_lock", 0, ret_any},
181 {"_read_unlock_irq", UNLOCK, "read_lock", 0, ret_any},
182 {"__read_lock_irq", LOCK, "read_lock", 0, ret_any},
183 {"__read_unlock_irq", UNLOCK, "read_lock", 0, ret_any},
184 {"read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
185 {"read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
186 {"_read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
187 {"_read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
188 {"__read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
189 {"__read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
190 {"read_lock_bh", LOCK, "read_lock", 0, ret_any},
191 {"read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
192 {"_read_lock_bh", LOCK, "read_lock", 0, ret_any},
193 {"_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
194 {"__read_lock_bh", LOCK, "read_lock", 0, ret_any},
195 {"__read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
196 {"_raw_read_lock_bh", LOCK, "read_lock", 0, ret_any},
197 {"_raw_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
198 {"__raw_read_lock_bh", LOCK, "read_lock", 0, ret_any},
199 {"__raw_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
200
201 {"generic__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
202 {"read_trylock", LOCK, "read_lock", 0, ret_one},
203 {"_read_trylock", LOCK, "read_lock", 0, ret_one},
204 {"raw_read_trylock", LOCK, "read_lock", 0, ret_one},
205 {"_raw_read_trylock", LOCK, "read_lock", 0, ret_one},
206 {"__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
207 {"__read_trylock", LOCK, "read_lock", 0, ret_one},
208
209 {"write_lock", LOCK, "write_lock", 0, ret_any},
210 {"write_unlock", UNLOCK, "write_lock", 0, ret_any},
211 {"_write_lock", LOCK, "write_lock", 0, ret_any},
212 {"_write_unlock", UNLOCK, "write_lock", 0, ret_any},
213 {"__write_lock", LOCK, "write_lock", 0, ret_any},
214 {"__write_unlock", UNLOCK, "write_lock", 0, ret_any},
215 {"write_lock_irq", LOCK, "write_lock", 0, ret_any},
216 {"write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
217 {"_write_lock_irq", LOCK, "write_lock", 0, ret_any},
218 {"_write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
219 {"__write_lock_irq", LOCK, "write_lock", 0, ret_any},
220 {"__write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
221 {"write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
222 {"write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
223 {"_write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
224 {"_write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
225 {"__write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
226 {"__write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
227 {"write_lock_bh", LOCK, "write_lock", 0, ret_any},
228 {"write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
229 {"_write_lock_bh", LOCK, "write_lock", 0, ret_any},
230 {"_write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
231 {"__write_lock_bh", LOCK, "write_lock", 0, ret_any},
232 {"__write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
233 {"_raw_write_lock", LOCK, "write_lock", 0, ret_any},
234 {"__raw_write_lock", LOCK, "write_lock", 0, ret_any},
235 {"_raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
236 {"__raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
237
238 {"write_trylock", LOCK, "write_lock", 0, ret_one},
239 {"_write_trylock", LOCK, "write_lock", 0, ret_one},
240 {"raw_write_trylock", LOCK, "write_lock", 0, ret_one},
241 {"_raw_write_trylock", LOCK, "write_lock", 0, ret_one},
242 {"__write_trylock", LOCK, "write_lock", 0, ret_one},
243 {"__raw_write_trylock", LOCK, "write_lock", 0, ret_one},
244
245 {"down", LOCK, "sem", 0, ret_any},
246 {"up", UNLOCK, "sem", 0, ret_any},
247 {"down_trylock", LOCK, "sem", 0, ret_zero},
248 {"down_timeout", LOCK, "sem", 0, ret_zero},
249 {"down_interruptible", LOCK, "sem", 0, ret_zero},
250
251
252 {"down_write", LOCK, "rw_sem", 0, ret_any},
253 {"downgrade_write", UNLOCK, "rw_sem", 0, ret_any},
254 {"downgrade_write", LOCK, "read_sem", 0, ret_any},
255 {"up_write", UNLOCK, "rw_sem", 0, ret_any},
256 {"down_write_trylock", LOCK, "rw_sem", 0, ret_one},
257 {"down_write_killable", LOCK, "rw_sem", 0, ret_zero},
258 {"down_read", LOCK, "read_sem", 0, ret_any},
259 {"down_read_trylock", LOCK, "read_sem", 0, ret_one},
260 {"down_read_killable", LOCK, "read_sem", 0, ret_zero},
261 {"up_read", UNLOCK, "read_sem", 0, ret_any},
262
263 {"mutex_lock", LOCK, "mutex", 0, ret_any},
264 {"mutex_lock_io", LOCK, "mutex", 0, ret_any},
265 {"mutex_unlock", UNLOCK, "mutex", 0, ret_any},
266 {"mutex_lock_nested", LOCK, "mutex", 0, ret_any},
267 {"mutex_lock_io_nested", LOCK, "mutex", 0, ret_any},
268
269 {"mutex_lock_interruptible", LOCK, "mutex", 0, ret_zero},
270 {"mutex_lock_interruptible_nested", LOCK, "mutex", 0, ret_zero},
271 {"mutex_lock_killable", LOCK, "mutex", 0, ret_zero},
272 {"mutex_lock_killable_nested", LOCK, "mutex", 0, ret_zero},
273
274 {"mutex_trylock", LOCK, "mutex", 0, ret_one},
275
276 {"raw_local_irq_disable", LOCK, "irq", NO_ARG, ret_any},
277 {"raw_local_irq_enable", UNLOCK, "irq", NO_ARG, ret_any},
278 {"spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
279 {"spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
280 {"_spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
281 {"_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
282 {"__spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
283 {"__spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
284 {"_raw_spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
285 {"_raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
286 {"__raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
287 {"spin_trylock_irq", LOCK, "irq", NO_ARG, ret_one},
288 {"read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
289 {"read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
290 {"_read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
291 {"_read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
292 {"__read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
293 {"__read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
294 {"write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
295 {"write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
296 {"_write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
297 {"_write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
298 {"__write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
299 {"__write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
300
301 {"arch_local_irq_save", LOCK, "irqsave", RETURN_VAL, ret_any},
302 {"arch_local_irq_restore", UNLOCK, "irqsave", 0, ret_any},
303 {"__raw_local_irq_save", LOCK, "irqsave", RETURN_VAL, ret_any},
304 {"raw_local_irq_restore", UNLOCK, "irqsave", 0, ret_any},
305 {"spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
306 {"spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
307 {"spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
308 {"spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
309 {"_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
310 {"_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
311 {"_spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
312 {"_spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
313 {"__spin_lock_irqsave_nested", LOCK, "irqsave", 1, ret_any},
314 {"__spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
315 {"__spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
316 {"_raw_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
317 {"_raw_spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
318 {"_raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
319 {"__raw_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
320 {"__raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
321 {"_raw_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
322 {"spin_trylock_irqsave", LOCK, "irqsave", 1, ret_one},
323 {"read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
324 {"read_lock_irqsave", LOCK, "irqsave", 1, ret_any},
325 {"read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
326 {"_read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
327 {"_read_lock_irqsave", LOCK, "irqsave", 1, ret_any},
328 {"_read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
329 {"__read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
330 {"__read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
331 {"write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
332 {"write_lock_irqsave", LOCK, "irqsave", 1, ret_any},
333 {"write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
334 {"_write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
335 {"_write_lock_irqsave", LOCK, "irqsave", 1, ret_any},
336 {"_write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
337 {"__write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
338 {"__write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
339
340 {"local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
341 {"_local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
342 {"__local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
343 {"local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
344 {"_local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
345 {"__local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
346 {"spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
347 {"spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
348 {"_spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
349 {"_spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
350 {"__spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
351 {"__spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
352 {"read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
353 {"read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
354 {"_read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
355 {"_read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
356 {"__read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
357 {"__read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
358 {"_raw_read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
359 {"_raw_read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
360 {"write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
361 {"write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
362 {"_write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
363 {"_write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
364 {"__write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
365 {"__write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
366 {"spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
367 {"_spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
368 {"__spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
369
370 {"ffs_mutex_lock", LOCK, "mutex", 0, ret_zero},
371 };
372
373 static struct lock_info *lock_table;
374
375 static struct tracker_list *starts_locked;
376 static struct tracker_list *starts_unlocked;
377
378 struct locks_on_return {
379 int line;
380 struct tracker_list *locked;
381 struct tracker_list *unlocked;
382 struct tracker_list *impossible;
383 struct range_list *return_values;
384 };
385 DECLARE_PTR_LIST(return_list, struct locks_on_return);
386 static struct return_list *all_returns;
387
388 static char *make_full_name(const char *lock, const char *var)
389 {
390 static char tmp_buf[512];
391
392 snprintf(tmp_buf, sizeof(tmp_buf), "%s:%s", lock, var);
393 remove_parens(tmp_buf);
394 return alloc_string(tmp_buf);
395 }
396
397 static struct expression *remove_spinlock_check(struct expression *expr)
398 {
399 if (expr->type != EXPR_CALL)
400 return expr;
401 if (expr->fn->type != EXPR_SYMBOL)
402 return expr;
403 if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
404 return expr;
405 expr = get_argument_from_call_expr(expr->args, 0);
406 return expr;
407 }
408
409 static char *get_full_name(struct expression *expr, int index)
410 {
411 struct expression *arg;
412 char *name = NULL;
413 char *full_name = NULL;
414 struct lock_info *lock = &lock_table[index];
415
416 if (lock->arg == RETURN_VAL) {
417 name = expr_to_var(expr->left);
418 full_name = make_full_name(lock->name, name);
419 } else if (lock->arg == NO_ARG) {
420 full_name = make_full_name(lock->name, "");
421 } else {
422 arg = get_argument_from_call_expr(expr->args, lock->arg);
423 if (!arg)
424 goto free;
425 arg = remove_spinlock_check(arg);
426 name = expr_to_str(arg);
427 if (!name)
428 goto free;
429 full_name = make_full_name(lock->name, name);
430 }
431 free:
432 free_string(name);
433 return full_name;
434 }
435
436 static struct smatch_state *get_start_state(struct sm_state *sm)
437 {
438 int is_locked = 0;
439 int is_unlocked = 0;
440
441 if (in_tracker_list(starts_locked, my_id, sm->name, sm->sym))
442 is_locked = 1;
443 if (in_tracker_list(starts_unlocked, my_id, sm->name, sm->sym))
444 is_unlocked = 1;
445 if (is_locked && is_unlocked)
446 return &undefined;
447 if (is_locked)
448 return &locked;
449 if (is_unlocked)
450 return &unlocked;
451 return &undefined;
452 }
453
454 static struct smatch_state *unmatched_state(struct sm_state *sm)
455 {
456 return &start_state;
457 }
458
459 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
460 {
461 if (is_impossible_path())
462 set_state(my_id, cur->name, cur->sym, &impossible);
463 }
464
465 static bool nestable(const char *name)
466 {
467 if (strstr(name, "read_sem:"))
468 return true;
469 if (strcmp(name, "bottom_half:") == 0)
470 return true;
471 return false;
472 }
473
474 static void do_lock(const char *name)
475 {
476 struct sm_state *sm;
477
478 if (__inline_fn)
479 return;
480
481 sm = get_sm_state(my_id, name, NULL);
482 if (!sm)
483 add_tracker(&starts_unlocked, my_id, name, NULL);
484 if (sm && slist_has_state(sm->possible, &locked) && !nestable(name))
485 sm_error("double lock '%s'", name);
486 if (sm)
487 func_has_transition = TRUE;
488 set_state(my_id, name, NULL, &locked);
489 }
490
491 static void do_lock_failed(const char *name)
492 {
493 struct sm_state *sm;
494
495 if (__inline_fn)
496 return;
497
498 sm = get_sm_state(my_id, name, NULL);
499 if (!sm)
500 add_tracker(&starts_unlocked, my_id, name, NULL);
501 set_state(my_id, name, NULL, &unlocked);
502 }
503
504 static void do_unlock(const char *name)
505 {
506 struct sm_state *sm;
507
508 if (__inline_fn)
509 return;
510 if (__path_is_null())
511 return;
512 sm = get_sm_state(my_id, name, NULL);
513 if (!sm)
514 add_tracker(&starts_locked, my_id, name, NULL);
515 if (sm && slist_has_state(sm->possible, &unlocked) &&
516 strcmp(name, "bottom_half:") != 0)
517 sm_error("double unlock '%s'", name);
518 if (sm)
519 func_has_transition = TRUE;
520 set_state(my_id, name, NULL, &unlocked);
521 }
522
523 static void match_lock_held(const char *fn, struct expression *call_expr,
524 struct expression *assign_expr, void *_index)
525 {
526 int index = PTR_INT(_index);
527 char *lock_name;
528 struct lock_info *lock = &lock_table[index];
529
530 if (lock->arg == NO_ARG) {
531 lock_name = get_full_name(NULL, index);
532 } else if (lock->arg == RETURN_VAL) {
533 if (!assign_expr)
534 return;
535 lock_name = get_full_name(assign_expr, index);
536 } else {
537 lock_name = get_full_name(call_expr, index);
538 }
539 if (!lock_name)
540 return;
541 do_lock(lock_name);
542 free_string(lock_name);
543 }
544
545 static void match_lock_failed(const char *fn, struct expression *call_expr,
546 struct expression *assign_expr, void *_index)
547 {
548 int index = PTR_INT(_index);
549 char *lock_name;
550 struct lock_info *lock = &lock_table[index];
551
552 if (lock->arg == NO_ARG) {
553 lock_name = get_full_name(NULL, index);
554 } else if (lock->arg == RETURN_VAL) {
555 if (!assign_expr)
556 return;
557 lock_name = get_full_name(assign_expr, index);
558 } else {
559 lock_name = get_full_name(call_expr, index);
560 }
561 if (!lock_name)
562 return;
563 do_lock_failed(lock_name);
564 free_string(lock_name);
565 }
566
567 static void match_returns_locked(const char *fn, struct expression *expr,
568 void *_index)
569 {
570 char *full_name = NULL;
571 int index = PTR_INT(_index);
572 struct lock_info *lock = &lock_table[index];
573
574 if (lock->arg != RETURN_VAL)
575 return;
576 full_name = get_full_name(expr, index);
577 do_lock(full_name);
578 }
579
580 static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
581 {
582 char *full_name = NULL;
583 int index = PTR_INT(_index);
584 struct lock_info *lock = &lock_table[index];
585
586 if (__inline_fn)
587 return;
588
589 full_name = get_full_name(expr, index);
590 if (!full_name)
591 return;
592 if (lock->action == LOCK)
593 do_lock(full_name);
594 else
595 do_unlock(full_name);
596 free_string(full_name);
597 }
598
599 static struct locks_on_return *alloc_return(struct expression *expr)
600 {
601 struct locks_on_return *ret;
602
603 ret = malloc(sizeof(*ret));
604 if (!get_implied_rl(expr, &ret->return_values))
605 ret->return_values = NULL;
606 ret->line = get_lineno();
607 ret->locked = NULL;
608 ret->unlocked = NULL;
609 ret->impossible = NULL;
610 return ret;
611 }
612
613 static int check_possible(struct sm_state *sm)
614 {
615 struct sm_state *tmp;
616 int islocked = 0;
617 int isunlocked = 0;
618 int undef = 0;
619
620 if (!option_spammy)
621 return 0;
622
623 FOR_EACH_PTR(sm->possible, tmp) {
624 if (tmp->state == &locked)
625 islocked = 1;
626 if (tmp->state == &unlocked)
627 isunlocked = 1;
628 if (tmp->state == &start_state) {
629 struct smatch_state *s;
630
631 s = get_start_state(tmp);
632 if (s == &locked)
633 islocked = 1;
634 else if (s == &unlocked)
635 isunlocked = 1;
636 else
637 undef = 1;
638 }
639 if (tmp->state == &undefined)
640 undef = 1; // i don't think this is possible any more.
641 } END_FOR_EACH_PTR(tmp);
642 if ((islocked && isunlocked) || undef) {
643 sm_warning("'%s' is sometimes locked here and sometimes unlocked.", sm->name);
644 return 1;
645 }
646 return 0;
647 }
648
649 static struct position warned_pos;
650
651 static void match_return(int return_id, char *return_ranges, struct expression *expr)
652 {
653 struct locks_on_return *ret;
654 struct stree *stree;
655 struct sm_state *tmp;
656
657 if (!final_pass)
658 return;
659 if (__inline_fn)
660 return;
661
662 if (expr && cmp_pos(expr->pos, warned_pos) == 0)
663 return;
664
665 ret = alloc_return(expr);
666
667 stree = __get_cur_stree();
668 FOR_EACH_MY_SM(my_id, stree, tmp) {
669 if (tmp->state == &locked) {
670 add_tracker(&ret->locked, tmp->owner, tmp->name,
671 tmp->sym);
672 } else if (tmp->state == &unlocked) {
673 add_tracker(&ret->unlocked, tmp->owner, tmp->name,
674 tmp->sym);
675 } else if (tmp->state == &start_state) {
676 struct smatch_state *s;
677
678 s = get_start_state(tmp);
679 if (s == &locked)
680 add_tracker(&ret->locked, tmp->owner, tmp->name,
681 tmp->sym);
682 if (s == &unlocked)
683 add_tracker(&ret->unlocked, tmp->owner,tmp->name,
684 tmp->sym);
685 } else if (tmp->state == &impossible) {
686 add_tracker(&ret->impossible, tmp->owner, tmp->name,
687 tmp->sym);
688 } else {
689 if (check_possible(tmp)) {
690 if (expr)
691 warned_pos = expr->pos;
692 }
693 }
694 } END_FOR_EACH_SM(tmp);
695 add_ptr_list(&all_returns, ret);
696 }
697
698 static void add_line(struct range_list **rl, int line)
699 {
700 sval_t sval = sval_type_val(&int_ctype, line);
701
702 add_range(rl, sval, sval);
703 }
704
705 static int line_printed(struct range_list *rl, int line)
706 {
707 sval_t sval = sval_type_val(&int_ctype, line);
708
709 return rl_has_sval(rl, sval);
710 }
711
712 static void print_inconsistent_returns(struct tracker *lock,
713 struct smatch_state *start)
714 {
715 struct locks_on_return *tmp;
716 struct range_list *printed = NULL;
717 int i;
718
719 sm_warning("inconsistent returns '%s'.", lock->name);
720 sm_printf(" Locked on: ");
721
722 i = 0;
723 FOR_EACH_PTR(all_returns, tmp) {
724 if (line_printed(printed, tmp->line))
725 continue;
726 if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym))
727 continue;
728 if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym)) {
729 if (i++)
730 sm_printf(" ");
731 sm_printf("line %d\n", tmp->line);
732 add_line(&printed, tmp->line);
733 continue;
734 }
735 if (start == &locked) {
736 if (i++)
737 sm_printf(" ");
738 sm_printf("line %d\n", tmp->line);
739 add_line(&printed, tmp->line);
740 }
741 } END_FOR_EACH_PTR(tmp);
742
743 sm_printf(" Unlocked on: ");
744 printed = NULL;
745 i = 0;
746 FOR_EACH_PTR(all_returns, tmp) {
747 if (line_printed(printed, tmp->line))
748 continue;
749 if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym)) {
750 if (i++)
751 sm_printf(" ");
752 sm_printf("line %d\n", tmp->line);
753 add_line(&printed, tmp->line);
754 continue;
755 }
756 if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym))
757 continue;
758 if (start == &unlocked) {
759 if (i++)
760 sm_printf(" ");
761 sm_printf("line %d\n", tmp->line);
762 add_line(&printed, tmp->line);
763 }
764 } END_FOR_EACH_PTR(tmp);
765 }
766
767 static int matches_return_type(struct range_list *rl, enum return_type type)
768 {
769 sval_t zero_sval = ll_to_sval(0);
770 sval_t one_sval = ll_to_sval(1);
771
772 /* All these double negatives are super ugly! */
773
774 switch (type) {
775 case ret_zero:
776 return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(zero_sval, zero_sval));
777 case ret_one:
778 return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(one_sval, one_sval));
779 case ret_non_zero:
780 return !possibly_true_rl(rl, SPECIAL_EQUAL, alloc_rl(zero_sval, zero_sval));
781 case ret_negative:
782 return !possibly_true_rl(rl, SPECIAL_GTE, alloc_rl(zero_sval, zero_sval));
783 case ret_positive:
784 return !possibly_true_rl(rl, '<', alloc_rl(zero_sval, zero_sval));
785 case ret_any:
786 default:
787 return 1;
788 }
789 }
790
791 static int match_held(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
792 {
793 if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
794 return 0;
795 if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
796 return 0;
797 if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
798 return 1;
799 if (start == &unlocked)
800 return 0;
801 return 1;
802 }
803
804 static int match_released(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
805 {
806 if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
807 return 0;
808 if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
809 return 1;
810 if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
811 return 0;
812 if (start == &unlocked)
813 return 1;
814 return 0;
815 }
816
817 static int held_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
818 {
819 struct locks_on_return *tmp;
820
821 FOR_EACH_PTR(all_returns, tmp) {
822 if (!matches_return_type(tmp->return_values, type))
823 continue;
824 if (match_held(lock, tmp, start))
825 return 1;
826 } END_FOR_EACH_PTR(tmp);
827 return 0;
828 }
829
830 static int released_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
831 {
832 struct locks_on_return *tmp;
833
834 FOR_EACH_PTR(all_returns, tmp) {
835 if (!matches_return_type(tmp->return_values, type))
836 continue;
837 if (match_released(lock, tmp, start))
838 return 1;
839 } END_FOR_EACH_PTR(tmp);
840 return 0;
841 }
842
843 static void check_returns_consistently(struct tracker *lock,
844 struct smatch_state *start)
845 {
846 struct symbol *type;
847
848 if (!held_on_return(lock, start, ret_any) ||
849 !released_on_return(lock, start, ret_any))
850 return;
851
852 if (held_on_return(lock, start, ret_zero) &&
853 !held_on_return(lock, start, ret_non_zero))
854 return;
855
856 if (held_on_return(lock, start, ret_positive) &&
857 !held_on_return(lock, start, ret_zero))
858 return;
859
860 if (held_on_return(lock, start, ret_positive) &&
861 !held_on_return(lock, start, ret_negative))
862 return;
863
864 type = cur_func_return_type();
865 if (type && type->type == SYM_PTR) {
866 if (held_on_return(lock, start, ret_non_zero) &&
867 !held_on_return(lock, start, ret_zero))
868 return;
869 }
870
871 print_inconsistent_returns(lock, start);
872 }
873
874 static void check_consistency(struct symbol *sym)
875 {
876 struct tracker *tmp;
877
878 FOR_EACH_PTR(starts_locked, tmp) {
879 if (in_tracker_list(starts_unlocked, tmp->owner, tmp->name,
880 tmp->sym))
881 sm_error("locking inconsistency. We assume "
882 "'%s' is both locked and unlocked at the "
883 "start.",
884 tmp->name);
885 } END_FOR_EACH_PTR(tmp);
886
887 FOR_EACH_PTR(starts_locked, tmp) {
888 check_returns_consistently(tmp, &locked);
889 } END_FOR_EACH_PTR(tmp);
890
891 FOR_EACH_PTR(starts_unlocked, tmp) {
892 check_returns_consistently(tmp, &unlocked);
893 } END_FOR_EACH_PTR(tmp);
894 }
895
896 static void clear_lists(void)
897 {
898 struct locks_on_return *tmp;
899
900 func_has_transition = FALSE;
901
902 free_trackers_and_list(&starts_locked);
903 free_trackers_and_list(&starts_unlocked);
904
905 FOR_EACH_PTR(all_returns, tmp) {
906 free_trackers_and_list(&tmp->locked);
907 free_trackers_and_list(&tmp->unlocked);
908 free(tmp);
909 } END_FOR_EACH_PTR(tmp);
910 __free_ptr_list((struct ptr_list **)&all_returns);
911 }
912
913 static void match_func_end(struct symbol *sym)
914 {
915 if (__inline_fn)
916 return;
917
918 if (func_has_transition)
919 check_consistency(sym);
920 }
921
922 static void match_after_func(struct symbol *sym)
923 {
924 if (__inline_fn)
925 return;
926 clear_lists();
927 }
928
929 static void register_lock(int index)
930 {
931 struct lock_info *lock = &lock_table[index];
932 void *idx = INT_PTR(index);
933
934 if (lock->return_type == ret_non_zero) {
935 return_implies_state(lock->function, 1, INT_MAX, &match_lock_held, idx);
936 return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
937 } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
938 add_function_assign_hook(lock->function, &match_returns_locked, idx);
939 } else if (lock->return_type == ret_any) {
940 add_function_hook(lock->function, &match_lock_unlock, idx);
941 } else if (lock->return_type == ret_zero) {
942 return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
943 return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
944 } else if (lock->return_type == ret_one) {
945 return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
946 return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
947 }
948 }
949
950 static void load_table(struct lock_info *_lock_table, int size)
951 {
952 int i;
953
954 lock_table = _lock_table;
955
956 for (i = 0; i < size; i++) {
957 if (lock_table[i].action == LOCK)
958 register_lock(i);
959 else
960 add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
961 }
962 }
963
964 /* print_held_locks() is used in check_call_tree.c */
965 void print_held_locks(void)
966 {
967 struct stree *stree;
968 struct sm_state *sm;
969 int i = 0;
970
971 stree = __get_cur_stree();
972 FOR_EACH_MY_SM(my_id, stree, sm) {
973 if (sm->state != &locked)
974 continue;
975 if (i++)
976 sm_printf(" ");
977 sm_printf("'%s'", sm->name);
978 } END_FOR_EACH_SM(sm);
979 }
980
981 void check_locking(int id)
982 {
983 my_id = id;
984
985 if (option_project == PROJ_WINE)
986 load_table(wine_lock_table, ARRAY_SIZE(wine_lock_table));
987 else if (option_project == PROJ_KERNEL)
988 load_table(kernel_lock_table, ARRAY_SIZE(kernel_lock_table));
989 else
990 return;
991
992 add_unmatched_state_hook(my_id, &unmatched_state);
993 add_pre_merge_hook(my_id, &pre_merge_hook);
994 add_split_return_callback(match_return);
995 add_hook(&match_func_end, END_FUNC_HOOK);
996 add_hook(&match_after_func, AFTER_FUNC_HOOK);
997
998 }
|
1 /*
2 * Copyright (C) 2009 Dan Carpenter.
3 * Copyright (C) 2019 Oracle.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program 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 this program; if not, see http://www.gnu.org/copyleft/gpl.txt
17 */
18
19 #include <ctype.h>
20 #include "parse.h"
21 #include "smatch.h"
22 #include "smatch_extra.h"
23 #include "smatch_slist.h"
24
25 static int my_id;
26
27 STATE(locked);
28 STATE(half_locked);
29 STATE(start_state);
30 STATE(unlocked);
31 STATE(impossible);
32 STATE(restore);
33
34 enum action {
35 LOCK,
36 UNLOCK,
37 RESTORE,
38 };
39
40 enum lock_type {
41 spin_lock,
42 read_lock,
43 write_lock,
44 mutex,
45 bottom_half,
46 irq,
47 sem,
48 prepare_lock,
49 enable_lock,
50 };
51
52 const char *get_lock_name(enum lock_type type)
53 {
54 static const char *names[] = {
55 [spin_lock] = "spin_lock",
56 [read_lock] = "read_lock",
57 [write_lock] = "write_lock",
58 [mutex] = "mutex",
59 [bottom_half] = "bottom_half",
60 [irq] = "irq",
61 [sem] = "sem",
62 [prepare_lock] = "prepare_lock",
63 [enable_lock] = "enable_lock",
64 };
65
66 return names[type];
67 }
68
69 enum return_type {
70 ret_any,
71 ret_zero,
72 ret_one,
73 ret_negative,
74 ret_positive,
75 ret_valid_ptr,
76 };
77
78 #define RETURN_VAL -1
79 #define NO_ARG -2
80
81 struct lock_info {
82 const char *function;
83 enum action action;
84 enum lock_type type;
85 int arg;
86 enum return_type return_type;
87 };
88
89 static struct lock_info lock_table[] = {
90 {"spin_lock", LOCK, spin_lock, 0, ret_any},
91 {"spin_unlock", UNLOCK, spin_lock, 0, ret_any},
92 {"spin_lock_nested", LOCK, spin_lock, 0, ret_any},
93 {"_spin_lock", LOCK, spin_lock, 0, ret_any},
94 {"_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
95 {"_spin_lock_nested", LOCK, spin_lock, 0, ret_any},
96 {"__spin_lock", LOCK, spin_lock, 0, ret_any},
97 {"__spin_unlock", UNLOCK, spin_lock, 0, ret_any},
98 {"__spin_lock_nested", LOCK, spin_lock, 0, ret_any},
99 {"raw_spin_lock", LOCK, spin_lock, 0, ret_any},
100 {"raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
101 {"_raw_spin_lock", LOCK, spin_lock, 0, ret_any},
102 {"_raw_spin_lock_nested", LOCK, spin_lock, 0, ret_any},
103 {"_raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
104 {"__raw_spin_lock", LOCK, spin_lock, 0, ret_any},
105 {"__raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
106
107 {"spin_lock_irq", LOCK, spin_lock, 0, ret_any},
108 {"spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
109 {"_spin_lock_irq", LOCK, spin_lock, 0, ret_any},
110 {"_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
111 {"__spin_lock_irq", LOCK, spin_lock, 0, ret_any},
112 {"__spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
113 {"_raw_spin_lock_irq", LOCK, spin_lock, 0, ret_any},
114 {"_raw_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
115 {"__raw_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
116 {"spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
117 {"spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
118 {"_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
119 {"_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
120 {"__spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
121 {"__spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
122 {"_raw_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
123 {"_raw_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
124 {"__raw_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
125 {"__raw_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
126 {"spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
127 {"_spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
128 {"__spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
129 {"_raw_spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
130 {"spin_lock_bh", LOCK, spin_lock, 0, ret_any},
131 {"spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
132 {"_spin_lock_bh", LOCK, spin_lock, 0, ret_any},
133 {"_spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
134 {"__spin_lock_bh", LOCK, spin_lock, 0, ret_any},
135 {"__spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
136
137 {"spin_trylock", LOCK, spin_lock, 0, ret_one},
138 {"_spin_trylock", LOCK, spin_lock, 0, ret_one},
139 {"__spin_trylock", LOCK, spin_lock, 0, ret_one},
140 {"raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
141 {"_raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
142 {"spin_trylock_irq", LOCK, spin_lock, 0, ret_one},
143 {"spin_trylock_irqsave", LOCK, spin_lock, 0, ret_one},
144 {"spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
145 {"_spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
146 {"__spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
147 {"__raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
148 {"_atomic_dec_and_lock", LOCK, spin_lock, 1, ret_one},
149
150 {"read_lock", LOCK, read_lock, 0, ret_any},
151 {"down_read", LOCK, read_lock, 0, ret_any},
152 {"down_read_nested", LOCK, read_lock, 0, ret_any},
153 {"down_read_trylock", LOCK, read_lock, 0, ret_one},
154 {"up_read", UNLOCK, read_lock, 0, ret_any},
155 {"read_unlock", UNLOCK, read_lock, 0, ret_any},
156 {"_read_lock", LOCK, read_lock, 0, ret_any},
157 {"_read_unlock", UNLOCK, read_lock, 0, ret_any},
158 {"__read_lock", LOCK, read_lock, 0, ret_any},
159 {"__read_unlock", UNLOCK, read_lock, 0, ret_any},
160 {"_raw_read_lock", LOCK, read_lock, 0, ret_any},
161 {"_raw_read_unlock", UNLOCK, read_lock, 0, ret_any},
162 {"__raw_read_lock", LOCK, read_lock, 0, ret_any},
163 {"__raw_read_unlock", UNLOCK, read_lock, 0, ret_any},
164 {"read_lock_irq", LOCK, read_lock, 0, ret_any},
165 {"read_unlock_irq" , UNLOCK, read_lock, 0, ret_any},
166 {"_read_lock_irq", LOCK, read_lock, 0, ret_any},
167 {"_read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
168 {"__read_lock_irq", LOCK, read_lock, 0, ret_any},
169 {"__read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
170 {"_raw_read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
171 {"_raw_read_lock_irq", LOCK, read_lock, 0, ret_any},
172 {"_raw_read_lock_bh", LOCK, read_lock, 0, ret_any},
173 {"_raw_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
174 {"read_lock_irqsave", LOCK, read_lock, 0, ret_any},
175 {"read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
176 {"_read_lock_irqsave", LOCK, read_lock, 0, ret_any},
177 {"_read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
178 {"__read_lock_irqsave", LOCK, read_lock, 0, ret_any},
179 {"__read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
180 {"read_lock_bh", LOCK, read_lock, 0, ret_any},
181 {"read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
182 {"_read_lock_bh", LOCK, read_lock, 0, ret_any},
183 {"_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
184 {"__read_lock_bh", LOCK, read_lock, 0, ret_any},
185 {"__read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
186 {"__raw_read_lock_bh", LOCK, read_lock, 0, ret_any},
187 {"__raw_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
188
189 {"_raw_read_lock_irqsave", LOCK, read_lock, 0, ret_any},
190 {"_raw_read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
191 {"_raw_read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
192 {"_raw_read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
193 {"_raw_spin_lock_bh", LOCK, read_lock, 0, ret_any},
194 {"_raw_spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
195 {"_raw_spin_lock_nest_lock", LOCK, read_lock, 0, ret_any},
196 {"_raw_spin_unlock_bh", UNLOCK, read_lock, 0, ret_any},
197 {"_raw_spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
198 {"_raw_write_lock_irqsave", LOCK, write_lock, 0, ret_any},
199 {"_raw_write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
200 {"_raw_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
201 {"_raw_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
202 {"__raw_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
203 {"__raw_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
204
205 {"generic__raw_read_trylock", LOCK, read_lock, 0, ret_one},
206 {"read_trylock", LOCK, read_lock, 0, ret_one},
207 {"_read_trylock", LOCK, read_lock, 0, ret_one},
208 {"raw_read_trylock", LOCK, read_lock, 0, ret_one},
209 {"_raw_read_trylock", LOCK, read_lock, 0, ret_one},
210 {"__raw_read_trylock", LOCK, read_lock, 0, ret_one},
211 {"__read_trylock", LOCK, read_lock, 0, ret_one},
212
213 {"write_lock", LOCK, write_lock, 0, ret_any},
214 {"down_write", LOCK, write_lock, 0, ret_any},
215 {"down_write_nested", LOCK, write_lock, 0, ret_any},
216 {"up_write", UNLOCK, write_lock, 0, ret_any},
217 {"write_unlock", UNLOCK, write_lock, 0, ret_any},
218 {"_write_lock", LOCK, write_lock, 0, ret_any},
219 {"_write_unlock", UNLOCK, write_lock, 0, ret_any},
220 {"__write_lock", LOCK, write_lock, 0, ret_any},
221 {"__write_unlock", UNLOCK, write_lock, 0, ret_any},
222 {"write_lock_irq", LOCK, write_lock, 0, ret_any},
223 {"write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
224 {"_write_lock_irq", LOCK, write_lock, 0, ret_any},
225 {"_write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
226 {"__write_lock_irq", LOCK, write_lock, 0, ret_any},
227 {"__write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
228 {"_raw_write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
229 {"write_lock_irqsave", LOCK, write_lock, 0, ret_any},
230 {"write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
231 {"_write_lock_irqsave", LOCK, write_lock, 0, ret_any},
232 {"_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
233 {"__write_lock_irqsave", LOCK, write_lock, 0, ret_any},
234 {"__write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
235 {"write_lock_bh", LOCK, write_lock, 0, ret_any},
236 {"write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
237 {"_write_lock_bh", LOCK, write_lock, 0, ret_any},
238 {"_write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
239 {"__write_lock_bh", LOCK, write_lock, 0, ret_any},
240 {"__write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
241 {"_raw_write_lock", LOCK, write_lock, 0, ret_any},
242 {"__raw_write_lock", LOCK, write_lock, 0, ret_any},
243 {"_raw_write_unlock", UNLOCK, write_lock, 0, ret_any},
244 {"__raw_write_unlock", UNLOCK, write_lock, 0, ret_any},
245 {"_raw_write_lock_bh", LOCK, write_lock, 0, ret_any},
246 {"_raw_write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
247 {"_raw_write_lock_irq", LOCK, write_lock, 0, ret_any},
248
249 {"write_trylock", LOCK, write_lock, 0, ret_one},
250 {"_write_trylock", LOCK, write_lock, 0, ret_one},
251 {"raw_write_trylock", LOCK, write_lock, 0, ret_one},
252 {"_raw_write_trylock", LOCK, write_lock, 0, ret_one},
253 {"__write_trylock", LOCK, write_lock, 0, ret_one},
254 {"__raw_write_trylock", LOCK, write_lock, 0, ret_one},
255 {"down_write_trylock", LOCK, write_lock, 0, ret_one},
256 {"down_write_killable", LOCK, write_lock, 0, ret_zero},
257
258 {"down", LOCK, sem, 0, ret_any},
259 {"up", UNLOCK, sem, 0, ret_any},
260 {"down_trylock", LOCK, sem, 0, ret_zero},
261 {"down_timeout", LOCK, sem, 0, ret_zero},
262 {"down_interruptible", LOCK, sem, 0, ret_zero},
263 {"down_killable", LOCK, sem, 0, ret_zero},
264
265
266 {"mutex_lock", LOCK, mutex, 0, ret_any},
267 {"mutex_unlock", UNLOCK, mutex, 0, ret_any},
268 {"mutex_lock_nested", LOCK, mutex, 0, ret_any},
269 {"mutex_lock_io", LOCK, mutex, 0, ret_any},
270 {"mutex_lock_io_nested", LOCK, mutex, 0, ret_any},
271
272 {"mutex_lock_interruptible", LOCK, mutex, 0, ret_zero},
273 {"mutex_lock_interruptible_nested", LOCK, mutex, 0, ret_zero},
274 {"mutex_lock_killable", LOCK, mutex, 0, ret_zero},
275 {"mutex_lock_killable_nested", LOCK, mutex, 0, ret_zero},
276
277 {"mutex_trylock", LOCK, mutex, 0, ret_one},
278
279 {"ww_mutex_lock", LOCK, mutex, 0, ret_any},
280 {"__ww_mutex_lock", LOCK, mutex, 0, ret_any},
281 {"ww_mutex_lock_interruptible", LOCK, mutex, 0, ret_zero},
282 {"ww_mutex_unlock", UNLOCK, mutex, 0, ret_any},
283
284 {"raw_local_irq_disable", LOCK, irq, NO_ARG, ret_any},
285 {"raw_local_irq_enable", UNLOCK, irq, NO_ARG, ret_any},
286 {"spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
287 {"spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
288 {"_spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
289 {"_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
290 {"__spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
291 {"__spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
292 {"_raw_spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
293 {"_raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
294 {"__raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
295 {"spin_trylock_irq", LOCK, irq, NO_ARG, ret_one},
296 {"read_lock_irq", LOCK, irq, NO_ARG, ret_any},
297 {"read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
298 {"_read_lock_irq", LOCK, irq, NO_ARG, ret_any},
299 {"_read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
300 {"__read_lock_irq", LOCK, irq, NO_ARG, ret_any},
301 {"_raw_read_lock_irq", LOCK, irq, NO_ARG, ret_any},
302 {"__read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
303 {"_raw_read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
304 {"write_lock_irq", LOCK, irq, NO_ARG, ret_any},
305 {"write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
306 {"_write_lock_irq", LOCK, irq, NO_ARG, ret_any},
307 {"_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
308 {"__write_lock_irq", LOCK, irq, NO_ARG, ret_any},
309 {"__write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
310 {"_raw_write_lock_irq", LOCK, irq, NO_ARG, ret_any},
311 {"_raw_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
312
313 {"arch_local_irq_save", LOCK, irq, RETURN_VAL, ret_any},
314 {"arch_local_irq_restore", RESTORE, irq, 0, ret_any},
315 {"__raw_local_irq_save", LOCK, irq, RETURN_VAL, ret_any},
316 {"raw_local_irq_restore", RESTORE, irq, 0, ret_any},
317 {"spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
318 {"spin_lock_irqsave", LOCK, irq, 1, ret_any},
319 {"spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
320 {"_spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
321 {"_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
322 {"_spin_lock_irqsave", LOCK, irq, 1, ret_any},
323 {"_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
324 {"__spin_lock_irqsave_nested", LOCK, irq, 1, ret_any},
325 {"__spin_lock_irqsave", LOCK, irq, 1, ret_any},
326 {"__spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
327 {"_raw_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
328 {"_raw_spin_lock_irqsave", LOCK, irq, 1, ret_any},
329 {"_raw_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
330 {"__raw_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
331 {"__raw_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
332 {"_raw_spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
333 {"spin_trylock_irqsave", LOCK, irq, 1, ret_one},
334 {"read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
335 {"read_lock_irqsave", LOCK, irq, 1, ret_any},
336 {"read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
337 {"_read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
338 {"_read_lock_irqsave", LOCK, irq, 1, ret_any},
339 {"_read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
340 {"__read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
341 {"__read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
342 {"write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
343 {"write_lock_irqsave", LOCK, irq, 1, ret_any},
344 {"write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
345 {"_write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
346 {"_write_lock_irqsave", LOCK, irq, 1, ret_any},
347 {"_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
348 {"__write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
349 {"__write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
350
351 {"local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
352 {"_local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
353 {"__local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
354 {"local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
355 {"_local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
356 {"__local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
357 {"spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
358 {"spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
359 {"_spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
360 {"_spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
361 {"__spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
362 {"__spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
363 {"read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
364 {"read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
365 {"_read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
366 {"_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
367 {"__read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
368 {"__read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
369 {"_raw_read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
370 {"_raw_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
371 {"write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
372 {"write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
373 {"_write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
374 {"_write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
375 {"__write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
376 {"__write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
377 {"_raw_write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
378 {"_raw_write_unlock_bh",UNLOCK, bottom_half, NO_ARG, ret_any},
379 {"spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
380 {"_spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
381 {"__spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
382
383 {"ffs_mutex_lock", LOCK, mutex, 0, ret_zero},
384
385 {"clk_prepare_lock", LOCK, prepare_lock, NO_ARG, ret_any},
386 {"clk_prepare_unlock", UNLOCK, prepare_lock, NO_ARG, ret_any},
387 {"clk_enable_lock", LOCK, enable_lock, -1, ret_any},
388 {"clk_enable_unlock", UNLOCK, enable_lock, 0, ret_any},
389
390 {"dma_resv_lock", LOCK, mutex, 0, ret_zero},
391 {"dma_resv_trylock", LOCK, mutex, 0, ret_one},
392 {"dma_resv_lock_interruptible", LOCK, mutex, 0, ret_zero},
393 {"dma_resv_unlock", UNLOCK, mutex, 0, ret_any},
394
395 {"modeset_lock", LOCK, mutex, 0, ret_zero},
396 {"drm_ modeset_lock", LOCK, mutex, 0, ret_zero},
397 {"drm_modeset_lock_single_interruptible", LOCK, mutex, 0, ret_zero},
398 {"modeset_unlock", UNLOCK, mutex, 0, ret_any},
399
400 {"reiserfs_write_lock_nested", LOCK, mutex, 0, ret_any},
401 {"reiserfs_write_unlock_nested", UNLOCK, mutex, 0, ret_any},
402
403 {"rw_lock", LOCK, write_lock, 1, ret_any},
404 {"rw_unlock", UNLOCK, write_lock, 1, ret_any},
405
406 {"sem_lock", LOCK, mutex, 0, ret_any},
407 {"sem_unlock", UNLOCK, mutex, 0, ret_any},
408
409 {},
410 };
411
412 struct macro_info {
413 const char *macro;
414 enum action action;
415 int param;
416 };
417
418 static struct macro_info macro_table[] = {
419 {"genpd_lock", LOCK, 0},
420 {"genpd_lock_nested", LOCK, 0},
421 {"genpd_lock_interruptible", LOCK, 0},
422 {"genpd_unlock", UNLOCK, 0},
423 };
424
425 static const char *false_positives[][2] = {
426 {"fs/jffs2/", "->alloc_sem"},
427 {"fs/xfs/", "->b_sema"},
428 {"mm/", "pvmw->ptl"},
429 };
430
431 static struct stree *start_states;
432 static struct stree_stack *saved_stack;
433
434 static struct tracker_list *locks;
435
436 static void reset(struct sm_state *sm, struct expression *mod_expr)
437 {
438 set_state(my_id, sm->name, sm->sym, &start_state);
439 }
440
441 static struct expression *remove_spinlock_check(struct expression *expr)
442 {
443 if (expr->type != EXPR_CALL)
444 return expr;
445 if (expr->fn->type != EXPR_SYMBOL)
446 return expr;
447 if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
448 return expr;
449 expr = get_argument_from_call_expr(expr->args, 0);
450 return expr;
451 }
452
453 static struct expression *filter_kernel_args(struct expression *arg)
454 {
455 if (arg->type == EXPR_PREOP && arg->op == '&')
456 return strip_expr(arg->unop);
457 if (!is_pointer(arg))
458 return arg;
459 return deref_expression(strip_expr(arg));
460 }
461
462 static char *lock_to_name_sym(struct expression *expr, struct symbol **sym)
463 {
464 expr = remove_spinlock_check(expr);
465 expr = filter_kernel_args(expr);
466 return expr_to_str_sym(expr, sym);
467 }
468
469 static char *get_full_name(struct expression *expr, int index, struct symbol **sym)
470 {
471 struct lock_info *lock = &lock_table[index];
472 struct expression *arg;
473
474 *sym = NULL;
475 if (lock->arg == RETURN_VAL) {
476 return expr_to_var_sym(strip_expr(expr->left), sym);
477 } else if (lock->arg == NO_ARG) {
478 return alloc_string(get_lock_name(lock->type));
479 } else {
480 arg = get_argument_from_call_expr(expr->args, lock->arg);
481 if (!arg)
482 return NULL;
483 return lock_to_name_sym(arg, sym);
484 }
485 }
486
487 static struct smatch_state *unmatched_state(struct sm_state *sm)
488 {
489 return &start_state;
490 }
491
492 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
493 {
494 if (is_impossible_path())
495 set_state(my_id, cur->name, cur->sym, &impossible);
496 }
497
498 static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
499 {
500 if (s1 == &impossible)
501 return s2;
502 if (s2 == &impossible)
503 return s1;
504 return &merged;
505 }
506
507 static struct smatch_state *action_to_state(enum action lock_unlock)
508 {
509 switch (lock_unlock) {
510 case LOCK:
511 return &locked;
512 case UNLOCK:
513 return &unlocked;
514 case RESTORE:
515 return &restore;
516 }
517 return NULL;
518 }
519
520 static struct sm_state *get_best_match(const char *key, enum action lock_unlock)
521 {
522 struct sm_state *sm;
523 struct sm_state *match;
524 int cnt = 0;
525 int start_pos, state_len, key_len, chunks, i;
526
527 if (strncmp(key, "$->", 3) == 0)
528 key += 3;
529
530 key_len = strlen(key);
531 chunks = 0;
532 for (i = key_len - 1; i > 0; i--) {
533 if (key[i] == '>' || key[i] == '.')
534 chunks++;
535 if (chunks == 2) {
536 key += (i + 1);
537 key_len = strlen(key);
538 break;
539 }
540 }
541
542 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
543 if (((lock_unlock == UNLOCK || lock_unlock == RESTORE) &&
544 sm->state != &locked) ||
545 (lock_unlock == LOCK && sm->state != &unlocked))
546 continue;
547 state_len = strlen(sm->name);
548 if (state_len < key_len)
549 continue;
550 start_pos = state_len - key_len;
551 if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
552 strcmp(sm->name + start_pos, key) == 0) {
553 cnt++;
554 match = sm;
555 }
556 } END_FOR_EACH_SM(sm);
557
558 if (cnt == 1)
559 return match;
560 return NULL;
561 }
562
563 static void use_best_match(char *key, enum action lock_unlock)
564 {
565 struct sm_state *match;
566
567 match = get_best_match(key, lock_unlock);
568 if (match)
569 set_state(my_id, match->name, match->sym, action_to_state(lock_unlock));
570 else
571 set_state(my_id, key, NULL, action_to_state(lock_unlock));
572 }
573
574 static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
575 {
576 struct smatch_state *orig;
577
578 orig = get_state_stree(start_states, my_id, name, sym);
579 if (!orig)
580 set_state_stree(&start_states, my_id, name, sym, start);
581 else if (orig != start)
582 set_state_stree(&start_states, my_id, name, sym, &undefined);
583 }
584
585 static bool common_false_positive(const char *name)
586 {
587 const char *path, *lname;
588 int i, len_total, len_path, len_name, skip;
589
590 if (!get_filename())
591 return false;
592
593 len_total = strlen(name);
594 for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
595 path = false_positives[i][0];
596 lname = false_positives[i][1];
597
598 len_path = strlen(path);
599 len_name = strlen(lname);
600
601 if (len_name > len_total)
602 continue;
603 skip = len_total - len_name;
604
605 if (strncmp(get_filename(), path, len_path) == 0 &&
606 strcmp(name + skip, lname) == 0)
607 return true;
608 }
609
610 return false;
611 }
612
613 static void warn_on_double(struct sm_state *sm, struct smatch_state *state)
614 {
615 struct sm_state *tmp;
616
617 if (!sm)
618 return;
619
620 FOR_EACH_PTR(sm->possible, tmp) {
621 if (tmp->state == state)
622 goto found;
623 } END_FOR_EACH_PTR(tmp);
624
625 return;
626 found:
627 if (strcmp(sm->name, "bottom_half") == 0)
628 return;
629 if (common_false_positive(sm->name))
630 return;
631 sm_msg("error: double %s '%s' (orig line %u)",
632 state->name, sm->name, tmp->line);
633 }
634
635 static bool handle_macro_lock_unlock(void)
636 {
637 struct expression *expr, *arg;
638 struct macro_info *info;
639 struct sm_state *sm;
640 struct symbol *sym;
641 const char *macro;
642 char *name;
643 bool ret = false;
644 int i;
645
646 expr = last_ptr_list((struct ptr_list *)big_expression_stack);
647 while (expr && expr->type == EXPR_ASSIGNMENT)
648 expr = strip_expr(expr->right);
649 if (!expr || expr->type != EXPR_CALL)
650 return false;
651
652 macro = get_macro_name(expr->pos);
653 if (!macro)
654 return false;
655
656 for (i = 0; i < ARRAY_SIZE(macro_table); i++) {
657 info = ¯o_table[i];
658
659 if (strcmp(macro, info->macro) != 0)
660 continue;
661 arg = get_argument_from_call_expr(expr->args, info->param);
662 name = expr_to_str_sym(arg, &sym);
663 if (!name || !sym)
664 goto free;
665 sm = get_sm_state(my_id, name, sym);
666
667 if (info->action == LOCK) {
668 if (!sm)
669 set_start_state(name, sym, &unlocked);
670 if (sm && sm->line != expr->pos.line)
671 warn_on_double(sm, &locked);
672 set_state(my_id, name, sym, &locked);
673 } else {
674 if (!sm)
675 set_start_state(name, sym, &locked);
676 if (sm && sm->line != expr->pos.line)
677 warn_on_double(sm, &unlocked);
678 set_state(my_id, name, sym, &unlocked);
679 }
680 ret = true;
681 free:
682 free_string(name);
683 return ret;
684 }
685 return false;
686 }
687
688 static void do_lock(const char *name, struct symbol *sym, struct lock_info *info)
689 {
690 struct sm_state *sm;
691
692 if (handle_macro_lock_unlock())
693 return;
694
695 add_tracker(&locks, my_id, name, sym);
696
697 sm = get_sm_state(my_id, name, sym);
698 if (!sm)
699 set_start_state(name, sym, &unlocked);
700 warn_on_double(sm, &locked);
701 set_state(my_id, name, sym, &locked);
702 }
703
704 static void do_lock_failed(const char *name, struct symbol *sym)
705 {
706 add_tracker(&locks, my_id, name, sym);
707 set_state(my_id, name, sym, &unlocked);
708 }
709
710 static void do_unlock(const char *name, struct symbol *sym, struct lock_info *info)
711 {
712 struct sm_state *sm;
713
714 if (__path_is_null())
715 return;
716
717 if (handle_macro_lock_unlock())
718 return;
719
720 add_tracker(&locks, my_id, name, sym);
721 sm = get_sm_state(my_id, name, sym);
722 if (!sm) {
723 sm = get_best_match(name, UNLOCK);
724 if (sm) {
725 name = sm->name;
726 sym = sm->sym;
727 }
728 }
729 if (!sm)
730 set_start_state(name, sym, &locked);
731 warn_on_double(sm, &unlocked);
732 set_state(my_id, name, sym, &unlocked);
733 }
734
735 static void do_restore(const char *name, struct symbol *sym, struct lock_info *info)
736 {
737 if (__path_is_null())
738 return;
739
740 if (!get_state(my_id, name, sym))
741 set_start_state(name, sym, &locked);
742
743 add_tracker(&locks, my_id, name, sym);
744 set_state(my_id, name, sym, &restore);
745 }
746
747 static void match_lock_held(const char *fn, struct expression *call_expr,
748 struct expression *assign_expr, void *_index)
749 {
750 int index = PTR_INT(_index);
751 struct lock_info *lock = &lock_table[index];
752 char *lock_name;
753 struct symbol *sym;
754
755 if (lock->arg == NO_ARG) {
756 lock_name = get_full_name(NULL, index, &sym);
757 } else if (lock->arg == RETURN_VAL) {
758 if (!assign_expr)
759 return;
760 lock_name = get_full_name(assign_expr, index, &sym);
761 } else {
762 lock_name = get_full_name(call_expr, index, &sym);
763 }
764 if (!lock_name)
765 return;
766 do_lock(lock_name, sym, lock);
767 free_string(lock_name);
768 }
769
770 static void match_lock_failed(const char *fn, struct expression *call_expr,
771 struct expression *assign_expr, void *_index)
772 {
773 int index = PTR_INT(_index);
774 struct lock_info *lock = &lock_table[index];
775 char *lock_name;
776 struct symbol *sym;
777
778 if (lock->arg == NO_ARG) {
779 lock_name = get_full_name(NULL, index, &sym);
780 } else if (lock->arg == RETURN_VAL) {
781 if (!assign_expr)
782 return;
783 lock_name = get_full_name(assign_expr, index, &sym);
784 } else {
785 lock_name = get_full_name(call_expr, index, &sym);
786 }
787 if (!lock_name)
788 return;
789 do_lock_failed(lock_name, sym);
790 free_string(lock_name);
791 }
792
793 static void match_returns_locked(const char *fn, struct expression *expr,
794 void *_index)
795 {
796 int index = PTR_INT(_index);
797 struct lock_info *lock = &lock_table[index];
798 char *full_name;
799 struct symbol *sym;
800
801 if (lock->arg != RETURN_VAL)
802 return;
803 full_name = get_full_name(expr, index, &sym);
804 if (!full_name)
805 return;
806 do_lock(full_name, sym, lock);
807 }
808
809 static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
810 {
811 int index = PTR_INT(_index);
812 struct lock_info *lock = &lock_table[index];
813 char *full_name;
814 struct symbol *sym;
815
816 full_name = get_full_name(expr, index, &sym);
817 if (!full_name)
818 return;
819 switch (lock->action) {
820 case LOCK:
821 do_lock(full_name, sym, lock);
822 break;
823 case UNLOCK:
824 do_unlock(full_name, sym, lock);
825 break;
826 case RESTORE:
827 do_restore(full_name, sym, lock);
828 break;
829 }
830 free_string(full_name);
831 }
832
833 static struct smatch_state *get_start_state(struct sm_state *sm)
834 {
835 struct smatch_state *orig;
836
837 orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
838 if (orig)
839 return orig;
840 return &undefined;
841 }
842
843 static int get_param_lock_name(struct sm_state *sm, struct expression *expr,
844 const char **name)
845 {
846 char *other_name;
847 struct symbol *other_sym;
848 const char *param_name;
849 int param;
850
851 *name = sm->name;
852
853 param = get_param_num_from_sym(sm->sym);
854 if (param >= 0) {
855 param_name = get_param_name(sm);
856 if (param_name)
857 *name = param_name;
858 return param;
859 }
860
861 if (expr) {
862 struct symbol *ret_sym;
863 char *ret_str;
864
865 ret_str = expr_to_str_sym(expr, &ret_sym);
866 if (ret_str && ret_sym == sm->sym) {
867 param_name = state_name_to_param_name(sm->name, ret_str);
868 if (param_name) {
869 free_string(ret_str);
870 *name = param_name;
871 return -1;
872 }
873 }
874 free_string(ret_str);
875 }
876
877 other_name = get_other_name_sym(sm->name, sm->sym, &other_sym);
878 if (!other_name)
879 return -2;
880 param = get_param_num_from_sym(other_sym);
881 if (param < 0)
882 return -2;
883
884 param_name = get_param_name_var_sym(other_name, other_sym);
885 free_string(other_name);
886 if (param_name)
887 *name = param_name;
888 return param;
889 }
890
891 static int get_db_type(struct sm_state *sm)
892 {
893 if (sm->state == get_start_state(sm)) {
894 if (sm->state == &locked)
895 return KNOWN_LOCKED;
896 if (sm->state == &unlocked)
897 return KNOWN_UNLOCKED;
898 }
899
900 if (sm->state == &locked)
901 return LOCKED;
902 if (sm->state == &unlocked)
903 return UNLOCKED;
904 if (sm->state == &restore)
905 return LOCK_RESTORED;
906 return LOCKED;
907 }
908
909 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
910 {
911 struct sm_state *sm;
912 const char *param_name;
913 int param;
914
915 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
916 if (sm->state != &locked &&
917 sm->state != &unlocked &&
918 sm->state != &restore)
919 continue;
920
921 param = get_param_lock_name(sm, expr, ¶m_name);
922 sql_insert_return_states(return_id, return_ranges,
923 get_db_type(sm),
924 param, param_name, "");
925 } END_FOR_EACH_SM(sm);
926 }
927
928 enum {
929 ERR_PTR, VALID_PTR, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS,
930 };
931
932 static bool is_EINTR(struct range_list *rl)
933 {
934 sval_t sval;
935
936 if (!rl_to_sval(rl, &sval))
937 return false;
938 return sval.value == -4;
939 }
940
941 static int success_fail_positive(struct range_list *rl)
942 {
943 /* void returns are the same as success (zero in the kernel) */
944 if (!rl)
945 return ZERO;
946
947 if (rl_type(rl)->type != SYM_PTR && sval_is_negative(rl_min(rl)))
948 return NEGATIVE;
949
950 if (rl_min(rl).value == 0 && rl_max(rl).value == 0)
951 return ZERO;
952
953 if (is_err_ptr(rl_min(rl)) &&
954 is_err_ptr(rl_max(rl)))
955 return ERR_PTR;
956
957 /*
958 * Trying to match ERR_PTR(ret) but without the expression struct.
959 * Ugly...
960 */
961 if (type_bits(&long_ctype) == 64 &&
962 rl_type(rl)->type == SYM_PTR &&
963 rl_min(rl).value == INT_MIN)
964 return ERR_PTR;
965
966 return POSITIVE;
967 }
968
969 static bool sym_in_lock_table(struct symbol *sym)
970 {
971 int i;
972
973 if (!sym || !sym->ident)
974 return false;
975
976 for (i = 0; lock_table[i].function != NULL; i++) {
977 if (strcmp(lock_table[i].function, sym->ident->name) == 0)
978 return true;
979 }
980 return false;
981 }
982
983 static bool func_in_lock_table(struct expression *expr)
984 {
985 if (expr->type != EXPR_SYMBOL)
986 return false;
987 return sym_in_lock_table(expr->symbol);
988 }
989
990 static void check_lock(char *name, struct symbol *sym)
991 {
992 struct range_list *locked_lines = NULL;
993 struct range_list *unlocked_lines = NULL;
994 int locked_buckets[NUM_BUCKETS] = {};
995 int unlocked_buckets[NUM_BUCKETS] = {};
996 struct stree *stree, *orig;
997 struct sm_state *return_sm;
998 struct sm_state *sm;
999 sval_t line = sval_type_val(&int_ctype, 0);
1000 int bucket;
1001 int i;
1002
1003 if (sym_in_lock_table(cur_func_sym))
1004 return;
1005
1006 FOR_EACH_PTR(get_all_return_strees(), stree) {
1007 orig = __swap_cur_stree(stree);
1008
1009 if (is_impossible_path())
1010 goto swap_stree;
1011
1012 return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
1013 if (!return_sm)
1014 goto swap_stree;
1015 line.value = return_sm->line;
1016
1017 sm = get_sm_state(my_id, name, sym);
1018 if (!sm)
1019 goto swap_stree;
1020
1021 if (parent_is_gone_var_sym(sm->name, sm->sym))
1022 goto swap_stree;
1023
1024 if (sm->state != &locked && sm->state != &unlocked)
1025 goto swap_stree;
1026
1027 if (sm->state == &unlocked && is_EINTR(estate_rl(return_sm->state)))
1028 goto swap_stree;
1029
1030 bucket = success_fail_positive(estate_rl(return_sm->state));
1031 if (sm->state == &locked) {
1032 add_range(&locked_lines, line, line);
1033 locked_buckets[bucket] = true;
1034 }
1035 if (sm->state == &unlocked) {
1036 add_range(&unlocked_lines, line, line);
1037 unlocked_buckets[bucket] = true;
1038 }
1039 swap_stree:
1040 __swap_cur_stree(orig);
1041 } END_FOR_EACH_PTR(stree);
1042
1043
1044 if (!locked_lines || !unlocked_lines)
1045 return;
1046
1047 for (i = 0; i < NUM_BUCKETS; i++) {
1048 if (locked_buckets[i] && unlocked_buckets[i])
1049 goto complain;
1050 }
1051 if (locked_buckets[NEGATIVE] &&
1052 (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE]))
1053 goto complain;
1054
1055 if (locked_buckets[ERR_PTR])
1056 goto complain;
1057
1058 return;
1059
1060 complain:
1061 sm_msg("warn: inconsistent returns '%s'.", name);
1062 sm_printf(" Locked on : %s\n", show_rl(locked_lines));
1063 sm_printf(" Unlocked on: %s\n", show_rl(unlocked_lines));
1064 }
1065
1066 static void match_func_end(struct symbol *sym)
1067 {
1068 struct tracker *tracker;
1069
1070 FOR_EACH_PTR(locks, tracker) {
1071 check_lock(tracker->name, tracker->sym);
1072 } END_FOR_EACH_PTR(tracker);
1073 }
1074
1075 static void register_lock(int index)
1076 {
1077 struct lock_info *lock = &lock_table[index];
1078 void *idx = INT_PTR(index);
1079
1080 if (lock->return_type == ret_one) {
1081 return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
1082 return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
1083 } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
1084 add_function_assign_hook(lock->function, &match_returns_locked, idx);
1085 } else if (lock->return_type == ret_any) {
1086 add_function_hook(lock->function, &match_lock_unlock, idx);
1087 } else if (lock->return_type == ret_zero) {
1088 return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
1089 return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
1090 } else if (lock->return_type == ret_valid_ptr) {
1091 return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx);
1092 }
1093 }
1094
1095 static void load_table(struct lock_info *lock_table)
1096 {
1097 int i;
1098
1099 for (i = 0; lock_table[i].function != NULL; i++) {
1100 if (lock_table[i].action == LOCK)
1101 register_lock(i);
1102 else
1103 add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
1104 }
1105 }
1106
1107 static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock)
1108 {
1109 struct expression *call, *arg;
1110 char *name;
1111 struct symbol *sym;
1112
1113 call = expr;
1114 while (call->type == EXPR_ASSIGNMENT)
1115 call = strip_expr(call->right);
1116 if (call->type != EXPR_CALL)
1117 return;
1118
1119 if (func_in_lock_table(call->fn))
1120 return;
1121
1122 if (param == -2) {
1123 use_best_match(key, lock_unlock);
1124 return;
1125 }
1126
1127 if (param == -1) {
1128 if (expr->type != EXPR_ASSIGNMENT)
1129 return;
1130 name = get_variable_from_key(expr->left, key, &sym);
1131 } else {
1132 arg = get_argument_from_call_expr(call->args, param);
1133 if (!arg)
1134 return;
1135
1136 name = get_variable_from_key(arg, key, &sym);
1137 }
1138 if (!name || !sym)
1139 goto free;
1140
1141 if (lock_unlock == LOCK)
1142 do_lock(name, sym, NULL);
1143 else if (lock_unlock == UNLOCK)
1144 do_unlock(name, sym, NULL);
1145 else if (lock_unlock == RESTORE)
1146 do_restore(name, sym, NULL);
1147
1148 free:
1149 free_string(name);
1150 }
1151
1152 static void db_param_locked(struct expression *expr, int param, char *key, char *value)
1153 {
1154 db_param_locked_unlocked(expr, param, key, value, LOCK);
1155 }
1156
1157 static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
1158 {
1159 db_param_locked_unlocked(expr, param, key, value, UNLOCK);
1160 }
1161
1162 static void db_param_restore(struct expression *expr, int param, char *key, char *value)
1163 {
1164 db_param_locked_unlocked(expr, param, key, value, RESTORE);
1165 }
1166
1167 static int get_caller_param_lock_name(struct expression *call, struct sm_state *sm, const char **name)
1168 {
1169 struct expression *arg;
1170 char *arg_name;
1171 int param;
1172
1173 param = 0;
1174 FOR_EACH_PTR(call->args, arg) {
1175 arg_name = sm_to_arg_name(arg, sm);
1176 if (arg_name) {
1177 *name = arg_name;
1178 return param;
1179 }
1180 param++;
1181 } END_FOR_EACH_PTR(arg);
1182
1183 *name = sm->name;
1184 return -2;
1185 }
1186
1187 static void match_call_info(struct expression *expr)
1188 {
1189 struct sm_state *sm;
1190 const char *param_name;
1191 int locked_type;
1192 int param;
1193
1194 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
1195 param = get_caller_param_lock_name(expr, sm, ¶m_name);
1196 if (sm->state == &locked)
1197 locked_type = LOCKED;
1198 else if (sm->state == &half_locked ||
1199 slist_has_state(sm->possible, &locked))
1200 locked_type = HALF_LOCKED;
1201 else
1202 continue;
1203 sql_insert_caller_info(expr, locked_type, param, param_name, "xxx type");
1204
1205 } END_FOR_EACH_SM(sm);
1206 }
1207
1208 static void match_save_states(struct expression *expr)
1209 {
1210 push_stree(&saved_stack, start_states);
1211 start_states = NULL;
1212 }
1213
1214 static void match_restore_states(struct expression *expr)
1215 {
1216 start_states = pop_stree(&saved_stack);
1217 }
1218
1219 static void match_after_func(struct symbol *sym)
1220 {
1221 free_stree(&start_states);
1222 }
1223
1224 static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr,
1225 struct expression *assign_expr, void *_index)
1226 {
1227 struct expression *lock, *ctx;
1228 char *lock_name;
1229 struct symbol *sym;
1230
1231 lock = get_argument_from_call_expr(call_expr->args, 0);
1232 ctx = get_argument_from_call_expr(call_expr->args, 1);
1233 if (!expr_is_zero(ctx))
1234 return;
1235
1236 lock_name = lock_to_name_sym(lock, &sym);
1237 if (!lock_name || !sym)
1238 goto free;
1239 do_lock(lock_name, sym, NULL);
1240 free:
1241 free_string(lock_name);
1242 }
1243
1244 /* print_held_locks() is used in check_call_tree.c */
1245 void print_held_locks(void)
1246 {
1247 struct stree *stree;
1248 struct sm_state *sm;
1249 int i = 0;
1250
1251 stree = __get_cur_stree();
1252 FOR_EACH_MY_SM(my_id, stree, sm) {
1253 if (sm->state != &locked)
1254 continue;
1255 if (i++)
1256 sm_printf(" ");
1257 sm_printf("'%s'", sm->name);
1258 } END_FOR_EACH_SM(sm);
1259 }
1260
1261 void check_locking(int id)
1262 {
1263 my_id = id;
1264
1265 if (option_project != PROJ_KERNEL)
1266 return;
1267
1268 load_table(lock_table);
1269
1270 set_dynamic_states(my_id);
1271 add_unmatched_state_hook(my_id, &unmatched_state);
1272 add_pre_merge_hook(my_id, &pre_merge_hook);
1273 add_merge_hook(my_id, &merge_func);
1274 add_modification_hook(my_id, &reset);
1275
1276 add_hook(&match_func_end, END_FUNC_HOOK);
1277
1278 add_hook(&match_after_func, AFTER_FUNC_HOOK);
1279 add_hook(&match_save_states, INLINE_FN_START);
1280 add_hook(&match_restore_states, INLINE_FN_END);
1281
1282 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
1283
1284 add_split_return_callback(match_return_info);
1285 select_return_states_hook(LOCKED, &db_param_locked);
1286 select_return_states_hook(UNLOCKED, &db_param_unlocked);
1287 select_return_states_hook(LOCK_RESTORED, &db_param_restore);
1288
1289 return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0);
1290 }
|