return_to_param: delete debug code
[smatch.git] / check_locking.c
blob299ad23aa908905945edf4a4ee67d169ad3a2e28
1 /*
2 * Copyright (C) 2009 Dan Carpenter.
3 * Copyright (C) 2019 Oracle.
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.
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.
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
19 #include <ctype.h>
20 #include "parse.h"
21 #include "smatch.h"
22 #include "smatch_extra.h"
23 #include "smatch_slist.h"
25 static int my_id;
27 STATE(locked);
28 STATE(half_locked);
29 STATE(start_state);
30 STATE(unlocked);
31 STATE(impossible);
32 STATE(restore);
34 enum action {
35 LOCK,
36 UNLOCK,
37 RESTORE,
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,
52 const char *get_lock_name(enum lock_type type)
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",
66 return names[type];
69 enum return_type {
70 ret_any,
71 ret_zero,
72 ret_one,
73 ret_negative,
74 ret_positive,
75 ret_valid_ptr,
78 #define RETURN_VAL -1
79 #define NO_ARG -2
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;
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
277 {"mutex_trylock", LOCK, mutex, 0, ret_one},
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},
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},
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},
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},
383 {"ffs_mutex_lock", LOCK, mutex, 0, ret_zero},
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},
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},
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},
400 {"reiserfs_write_lock_nested", LOCK, mutex, 0, ret_any},
401 {"reiserfs_write_unlock_nested", UNLOCK, mutex, 0, ret_any},
403 {"rw_lock", LOCK, write_lock, 1, ret_any},
404 {"rw_unlock", UNLOCK, write_lock, 1, ret_any},
406 {"sem_lock", LOCK, mutex, 0, ret_any},
407 {"sem_unlock", UNLOCK, mutex, 0, ret_any},
412 struct macro_info {
413 const char *macro;
414 enum action action;
415 int param;
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},
425 static const char *false_positives[][2] = {
426 {"fs/jffs2/", "->alloc_sem"},
427 {"fs/xfs/", "->b_sema"},
428 {"mm/", "pvmw->ptl"},
431 static struct stree *start_states;
432 static struct stree_stack *saved_stack;
434 static struct tracker_list *locks;
436 static void reset(struct sm_state *sm, struct expression *mod_expr)
438 set_state(my_id, sm->name, sm->sym, &start_state);
441 static struct expression *remove_spinlock_check(struct expression *expr)
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;
453 static struct expression *filter_kernel_args(struct expression *arg)
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));
462 static char *lock_to_name_sym(struct expression *expr, struct symbol **sym)
464 expr = remove_spinlock_check(expr);
465 expr = filter_kernel_args(expr);
466 return expr_to_str_sym(expr, sym);
469 static char *get_full_name(struct expression *expr, int index, struct symbol **sym)
471 struct lock_info *lock = &lock_table[index];
472 struct expression *arg;
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);
487 static struct smatch_state *unmatched_state(struct sm_state *sm)
489 return &start_state;
492 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
494 if (is_impossible_path())
495 set_state(my_id, cur->name, cur->sym, &impossible);
498 static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
500 if (s1 == &impossible)
501 return s2;
502 if (s2 == &impossible)
503 return s1;
504 return &merged;
507 static struct smatch_state *action_to_state(enum action lock_unlock)
509 switch (lock_unlock) {
510 case LOCK:
511 return &locked;
512 case UNLOCK:
513 return &unlocked;
514 case RESTORE:
515 return &restore;
517 return NULL;
520 static struct sm_state *get_best_match(const char *key, enum action lock_unlock)
522 struct sm_state *sm;
523 struct sm_state *match;
524 int cnt = 0;
525 int start_pos, state_len, key_len, chunks, i;
527 if (strncmp(key, "$->", 3) == 0)
528 key += 3;
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;
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;
556 } END_FOR_EACH_SM(sm);
558 if (cnt == 1)
559 return match;
560 return NULL;
563 static void use_best_match(char *key, enum action lock_unlock)
565 struct sm_state *match;
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));
574 static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
576 struct smatch_state *orig;
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);
585 static bool common_false_positive(const char *name)
587 const char *path, *lname;
588 int i, len_total, len_path, len_name, skip;
590 if (!get_filename())
591 return false;
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];
598 len_path = strlen(path);
599 len_name = strlen(lname);
601 if (len_name > len_total)
602 continue;
603 skip = len_total - len_name;
605 if (strncmp(get_filename(), path, len_path) == 0 &&
606 strcmp(name + skip, lname) == 0)
607 return true;
610 return false;
613 static void warn_on_double(struct sm_state *sm, struct smatch_state *state)
615 struct sm_state *tmp;
617 if (!sm)
618 return;
620 FOR_EACH_PTR(sm->possible, tmp) {
621 if (tmp->state == state)
622 goto found;
623 } END_FOR_EACH_PTR(tmp);
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);
635 static bool handle_macro_lock_unlock(void)
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;
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;
652 macro = get_macro_name(expr->pos);
653 if (!macro)
654 return false;
656 for (i = 0; i < ARRAY_SIZE(macro_table); i++) {
657 info = &macro_table[i];
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);
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);
680 ret = true;
681 free:
682 free_string(name);
683 return ret;
685 return false;
688 static void do_lock(const char *name, struct symbol *sym, struct lock_info *info)
690 struct sm_state *sm;
692 if (handle_macro_lock_unlock())
693 return;
695 add_tracker(&locks, my_id, name, sym);
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);
704 static void do_lock_failed(const char *name, struct symbol *sym)
706 add_tracker(&locks, my_id, name, sym);
707 set_state(my_id, name, sym, &unlocked);
710 static void do_unlock(const char *name, struct symbol *sym, struct lock_info *info)
712 struct sm_state *sm;
714 if (__path_is_null())
715 return;
717 if (handle_macro_lock_unlock())
718 return;
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;
729 if (!sm)
730 set_start_state(name, sym, &locked);
731 warn_on_double(sm, &unlocked);
732 set_state(my_id, name, sym, &unlocked);
735 static void do_restore(const char *name, struct symbol *sym, struct lock_info *info)
737 if (__path_is_null())
738 return;
740 if (!get_state(my_id, name, sym))
741 set_start_state(name, sym, &locked);
743 add_tracker(&locks, my_id, name, sym);
744 set_state(my_id, name, sym, &restore);
747 static void match_lock_held(const char *fn, struct expression *call_expr,
748 struct expression *assign_expr, void *_index)
750 int index = PTR_INT(_index);
751 struct lock_info *lock = &lock_table[index];
752 char *lock_name;
753 struct symbol *sym;
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);
764 if (!lock_name)
765 return;
766 do_lock(lock_name, sym, lock);
767 free_string(lock_name);
770 static void match_lock_failed(const char *fn, struct expression *call_expr,
771 struct expression *assign_expr, void *_index)
773 int index = PTR_INT(_index);
774 struct lock_info *lock = &lock_table[index];
775 char *lock_name;
776 struct symbol *sym;
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);
787 if (!lock_name)
788 return;
789 do_lock_failed(lock_name, sym);
790 free_string(lock_name);
793 static void match_returns_locked(const char *fn, struct expression *expr,
794 void *_index)
796 int index = PTR_INT(_index);
797 struct lock_info *lock = &lock_table[index];
798 char *full_name;
799 struct symbol *sym;
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);
809 static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
811 int index = PTR_INT(_index);
812 struct lock_info *lock = &lock_table[index];
813 char *full_name;
814 struct symbol *sym;
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;
830 free_string(full_name);
833 static struct smatch_state *get_start_state(struct sm_state *sm)
835 struct smatch_state *orig;
837 orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
838 if (orig)
839 return orig;
840 return &undefined;
843 static int get_db_type(struct sm_state *sm)
845 if (sm->state == get_start_state(sm)) {
846 if (sm->state == &locked)
847 return KNOWN_LOCKED;
848 if (sm->state == &unlocked)
849 return KNOWN_UNLOCKED;
852 if (sm->state == &locked)
853 return LOCKED;
854 if (sm->state == &unlocked)
855 return UNLOCKED;
856 if (sm->state == &restore)
857 return LOCK_RESTORED;
858 return LOCKED;
861 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
863 struct sm_state *sm;
864 const char *param_name;
865 int param;
867 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
868 if (sm->state != &locked &&
869 sm->state != &unlocked &&
870 sm->state != &restore)
871 continue;
873 param = get_param_key_from_sm(sm, expr, &param_name);
874 sql_insert_return_states(return_id, return_ranges,
875 get_db_type(sm),
876 param, param_name, "");
877 } END_FOR_EACH_SM(sm);
880 enum {
881 ERR_PTR, VALID_PTR, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS,
884 static bool is_EINTR(struct range_list *rl)
886 sval_t sval;
888 if (!rl_to_sval(rl, &sval))
889 return false;
890 return sval.value == -4;
893 static int success_fail_positive(struct range_list *rl)
895 /* void returns are the same as success (zero in the kernel) */
896 if (!rl)
897 return ZERO;
899 if (rl_type(rl)->type != SYM_PTR && sval_is_negative(rl_min(rl)))
900 return NEGATIVE;
902 if (rl_min(rl).value == 0 && rl_max(rl).value == 0)
903 return ZERO;
905 if (is_err_ptr(rl_min(rl)) &&
906 is_err_ptr(rl_max(rl)))
907 return ERR_PTR;
910 * Trying to match ERR_PTR(ret) but without the expression struct.
911 * Ugly...
913 if (type_bits(&long_ctype) == 64 &&
914 rl_type(rl)->type == SYM_PTR &&
915 rl_min(rl).value == INT_MIN)
916 return ERR_PTR;
918 return POSITIVE;
921 static bool sym_in_lock_table(struct symbol *sym)
923 int i;
925 if (!sym || !sym->ident)
926 return false;
928 for (i = 0; lock_table[i].function != NULL; i++) {
929 if (strcmp(lock_table[i].function, sym->ident->name) == 0)
930 return true;
932 return false;
935 static bool func_in_lock_table(struct expression *expr)
937 if (expr->type != EXPR_SYMBOL)
938 return false;
939 return sym_in_lock_table(expr->symbol);
942 static void check_lock(char *name, struct symbol *sym)
944 struct range_list *locked_lines = NULL;
945 struct range_list *unlocked_lines = NULL;
946 int locked_buckets[NUM_BUCKETS] = {};
947 int unlocked_buckets[NUM_BUCKETS] = {};
948 struct stree *stree, *orig;
949 struct sm_state *return_sm;
950 struct sm_state *sm;
951 sval_t line = sval_type_val(&int_ctype, 0);
952 int bucket;
953 int i;
955 if (sym_in_lock_table(cur_func_sym))
956 return;
958 FOR_EACH_PTR(get_all_return_strees(), stree) {
959 orig = __swap_cur_stree(stree);
961 if (is_impossible_path())
962 goto swap_stree;
964 return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
965 if (!return_sm)
966 goto swap_stree;
967 line.value = return_sm->line;
969 sm = get_sm_state(my_id, name, sym);
970 if (!sm)
971 goto swap_stree;
973 if (parent_is_gone_var_sym(sm->name, sm->sym))
974 goto swap_stree;
976 if (sm->state != &locked &&
977 sm->state != &unlocked &&
978 sm->state != &restore)
979 goto swap_stree;
981 if ((sm->state == &unlocked || sm->state == &restore) &&
982 is_EINTR(estate_rl(return_sm->state)))
983 goto swap_stree;
985 bucket = success_fail_positive(estate_rl(return_sm->state));
986 if (sm->state == &locked) {
987 add_range(&locked_lines, line, line);
988 locked_buckets[bucket] = true;
990 if (sm->state == &unlocked || sm->state == &restore) {
991 add_range(&unlocked_lines, line, line);
992 unlocked_buckets[bucket] = true;
994 swap_stree:
995 __swap_cur_stree(orig);
996 } END_FOR_EACH_PTR(stree);
999 if (!locked_lines || !unlocked_lines)
1000 return;
1002 for (i = 0; i < NUM_BUCKETS; i++) {
1003 if (locked_buckets[i] && unlocked_buckets[i])
1004 goto complain;
1006 if (locked_buckets[NEGATIVE] &&
1007 (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE]))
1008 goto complain;
1010 if (locked_buckets[ERR_PTR])
1011 goto complain;
1013 return;
1015 complain:
1016 sm_msg("warn: inconsistent returns '%s'.", name);
1017 sm_printf(" Locked on : %s\n", show_rl(locked_lines));
1018 sm_printf(" Unlocked on: %s\n", show_rl(unlocked_lines));
1021 static void match_func_end(struct symbol *sym)
1023 struct tracker *tracker;
1025 FOR_EACH_PTR(locks, tracker) {
1026 check_lock(tracker->name, tracker->sym);
1027 } END_FOR_EACH_PTR(tracker);
1030 static void register_lock(int index)
1032 struct lock_info *lock = &lock_table[index];
1033 void *idx = INT_PTR(index);
1035 if (lock->return_type == ret_one) {
1036 return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
1037 return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
1038 } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
1039 add_function_assign_hook(lock->function, &match_returns_locked, idx);
1040 } else if (lock->return_type == ret_any) {
1041 add_function_hook(lock->function, &match_lock_unlock, idx);
1042 } else if (lock->return_type == ret_zero) {
1043 return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
1044 return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
1045 } else if (lock->return_type == ret_valid_ptr) {
1046 return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx);
1050 static void load_table(struct lock_info *lock_table)
1052 int i;
1054 for (i = 0; lock_table[i].function != NULL; i++) {
1055 if (lock_table[i].action == LOCK)
1056 register_lock(i);
1057 else
1058 add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
1062 static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock)
1064 struct expression *call, *arg;
1065 char *name;
1066 struct symbol *sym;
1068 call = expr;
1069 while (call->type == EXPR_ASSIGNMENT)
1070 call = strip_expr(call->right);
1071 if (call->type != EXPR_CALL)
1072 return;
1074 if (func_in_lock_table(call->fn))
1075 return;
1077 if (param == -2) {
1078 use_best_match(key, lock_unlock);
1079 return;
1082 if (param == -1) {
1083 if (expr->type != EXPR_ASSIGNMENT)
1084 return;
1085 name = get_variable_from_key(expr->left, key, &sym);
1086 } else {
1087 arg = get_argument_from_call_expr(call->args, param);
1088 if (!arg)
1089 return;
1091 name = get_variable_from_key(arg, key, &sym);
1093 if (!name || !sym)
1094 goto free;
1096 if (lock_unlock == LOCK)
1097 do_lock(name, sym, NULL);
1098 else if (lock_unlock == UNLOCK)
1099 do_unlock(name, sym, NULL);
1100 else if (lock_unlock == RESTORE)
1101 do_restore(name, sym, NULL);
1103 free:
1104 free_string(name);
1107 static void db_param_locked(struct expression *expr, int param, char *key, char *value)
1109 db_param_locked_unlocked(expr, param, key, value, LOCK);
1112 static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
1114 db_param_locked_unlocked(expr, param, key, value, UNLOCK);
1117 static void db_param_restore(struct expression *expr, int param, char *key, char *value)
1119 db_param_locked_unlocked(expr, param, key, value, RESTORE);
1122 static int get_caller_param_lock_name(struct expression *call, struct sm_state *sm, const char **name)
1124 struct expression *arg;
1125 char *arg_name;
1126 int param;
1128 param = 0;
1129 FOR_EACH_PTR(call->args, arg) {
1130 arg_name = sm_to_arg_name(arg, sm);
1131 if (arg_name) {
1132 *name = arg_name;
1133 return param;
1135 param++;
1136 } END_FOR_EACH_PTR(arg);
1138 *name = sm->name;
1139 return -2;
1142 static void match_call_info(struct expression *expr)
1144 struct sm_state *sm;
1145 const char *param_name;
1146 int locked_type;
1147 int param;
1149 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
1150 param = get_caller_param_lock_name(expr, sm, &param_name);
1151 if (sm->state == &locked)
1152 locked_type = LOCKED;
1153 else if (sm->state == &half_locked ||
1154 slist_has_state(sm->possible, &locked))
1155 locked_type = HALF_LOCKED;
1156 else
1157 continue;
1158 sql_insert_caller_info(expr, locked_type, param, param_name, "xxx type");
1160 } END_FOR_EACH_SM(sm);
1163 static void match_save_states(struct expression *expr)
1165 push_stree(&saved_stack, start_states);
1166 start_states = NULL;
1169 static void match_restore_states(struct expression *expr)
1171 start_states = pop_stree(&saved_stack);
1174 static void match_after_func(struct symbol *sym)
1176 free_stree(&start_states);
1179 static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr,
1180 struct expression *assign_expr, void *_index)
1182 struct expression *lock, *ctx;
1183 char *lock_name;
1184 struct symbol *sym;
1186 lock = get_argument_from_call_expr(call_expr->args, 0);
1187 ctx = get_argument_from_call_expr(call_expr->args, 1);
1188 if (!expr_is_zero(ctx))
1189 return;
1191 lock_name = lock_to_name_sym(lock, &sym);
1192 if (!lock_name || !sym)
1193 goto free;
1194 do_lock(lock_name, sym, NULL);
1195 free:
1196 free_string(lock_name);
1199 /* print_held_locks() is used in check_call_tree.c */
1200 void print_held_locks(void)
1202 struct stree *stree;
1203 struct sm_state *sm;
1204 int i = 0;
1206 stree = __get_cur_stree();
1207 FOR_EACH_MY_SM(my_id, stree, sm) {
1208 if (sm->state != &locked)
1209 continue;
1210 if (i++)
1211 sm_printf(" ");
1212 sm_printf("'%s'", sm->name);
1213 } END_FOR_EACH_SM(sm);
1216 static bool is_smp_config(void)
1218 struct ident *id;
1220 id = built_in_ident("CONFIG_SMP");
1221 return !!lookup_symbol(id, NS_MACRO);
1224 void check_locking(int id)
1226 my_id = id;
1228 if (option_project != PROJ_KERNEL)
1229 return;
1231 if (!is_smp_config())
1232 return;
1234 load_table(lock_table);
1236 set_dynamic_states(my_id);
1237 add_unmatched_state_hook(my_id, &unmatched_state);
1238 add_pre_merge_hook(my_id, &pre_merge_hook);
1239 add_merge_hook(my_id, &merge_func);
1240 add_modification_hook(my_id, &reset);
1242 add_hook(&match_func_end, END_FUNC_HOOK);
1244 add_hook(&match_after_func, AFTER_FUNC_HOOK);
1245 add_hook(&match_save_states, INLINE_FN_START);
1246 add_hook(&match_restore_states, INLINE_FN_END);
1248 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
1250 add_split_return_callback(match_return_info);
1251 select_return_states_hook(LOCKED, &db_param_locked);
1252 select_return_states_hook(UNLOCKED, &db_param_unlocked);
1253 select_return_states_hook(LOCK_RESTORED, &db_param_restore);
1255 return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0);