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
22 #include "smatch_extra.h"
23 #include "smatch_slist.h"
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",
59 [bottom_half
] = "bottom_half",
62 [prepare_lock
] = "prepare_lock",
63 [enable_lock
] = "enable_lock",
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
},
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
)
445 if (expr
->fn
->type
!= EXPR_SYMBOL
)
447 if (strcmp(expr
->fn
->symbol_name
->name
, "spinlock_check"))
449 expr
= get_argument_from_call_expr(expr
->args
, 0);
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
))
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
;
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
));
480 arg
= get_argument_from_call_expr(expr
->args
, lock
->arg
);
483 return lock_to_name_sym(arg
, sym
);
487 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
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
)
502 if (s2
== &impossible
)
507 static struct smatch_state
*action_to_state(enum action lock_unlock
)
509 switch (lock_unlock
) {
520 static struct sm_state
*get_best_match(const char *key
, enum action lock_unlock
)
523 struct sm_state
*match
;
525 int start_pos
, state_len
, key_len
, chunks
, i
;
527 if (strncmp(key
, "$->", 3) == 0)
530 key_len
= strlen(key
);
532 for (i
= key_len
- 1; i
> 0; i
--) {
533 if (key
[i
] == '>' || key
[i
] == '.')
537 key_len
= strlen(key
);
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
))
547 state_len
= strlen(sm
->name
);
548 if (state_len
< key_len
)
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) {
556 } END_FOR_EACH_SM(sm
);
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
);
569 set_state(my_id
, match
->name
, match
->sym
, action_to_state(lock_unlock
));
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
);
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
;
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
)
603 skip
= len_total
- len_name
;
605 if (strncmp(get_filename(), path
, len_path
) == 0 &&
606 strcmp(name
+ skip
, lname
) == 0)
613 static void warn_on_double(struct sm_state
*sm
, struct smatch_state
*state
)
615 struct sm_state
*tmp
;
620 FOR_EACH_PTR(sm
->possible
, tmp
) {
621 if (tmp
->state
== state
)
623 } END_FOR_EACH_PTR(tmp
);
627 if (strcmp(sm
->name
, "bottom_half") == 0)
629 if (common_false_positive(sm
->name
))
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
;
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
)
652 macro
= get_macro_name(expr
->pos
);
656 for (i
= 0; i
< ARRAY_SIZE(macro_table
); i
++) {
657 info
= ¯o_table
[i
];
659 if (strcmp(macro
, info
->macro
) != 0)
661 arg
= get_argument_from_call_expr(expr
->args
, info
->param
);
662 name
= expr_to_str_sym(arg
, &sym
);
665 sm
= get_sm_state(my_id
, name
, sym
);
667 if (info
->action
== LOCK
) {
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
);
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
);
688 static void do_lock(const char *name
, struct symbol
*sym
, struct lock_info
*info
)
692 if (handle_macro_lock_unlock())
695 add_tracker(&locks
, my_id
, name
, sym
);
697 sm
= get_sm_state(my_id
, name
, sym
);
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
)
714 if (__path_is_null())
717 if (handle_macro_lock_unlock())
720 add_tracker(&locks
, my_id
, name
, sym
);
721 sm
= get_sm_state(my_id
, name
, sym
);
723 sm
= get_best_match(name
, UNLOCK
);
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())
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
];
755 if (lock
->arg
== NO_ARG
) {
756 lock_name
= get_full_name(NULL
, index
, &sym
);
757 } else if (lock
->arg
== RETURN_VAL
) {
760 lock_name
= get_full_name(assign_expr
, index
, &sym
);
762 lock_name
= get_full_name(call_expr
, index
, &sym
);
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
];
778 if (lock
->arg
== NO_ARG
) {
779 lock_name
= get_full_name(NULL
, index
, &sym
);
780 } else if (lock
->arg
== RETURN_VAL
) {
783 lock_name
= get_full_name(assign_expr
, index
, &sym
);
785 lock_name
= get_full_name(call_expr
, index
, &sym
);
789 do_lock_failed(lock_name
, sym
);
790 free_string(lock_name
);
793 static void match_returns_locked(const char *fn
, struct expression
*expr
,
796 int index
= PTR_INT(_index
);
797 struct lock_info
*lock
= &lock_table
[index
];
801 if (lock
->arg
!= RETURN_VAL
)
803 full_name
= get_full_name(expr
, index
, &sym
);
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
];
816 full_name
= get_full_name(expr
, index
, &sym
);
819 switch (lock
->action
) {
821 do_lock(full_name
, sym
, lock
);
824 do_unlock(full_name
, sym
, lock
);
827 do_restore(full_name
, sym
, lock
);
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
);
843 static int get_db_type(struct sm_state
*sm
)
845 if (sm
->state
== get_start_state(sm
)) {
846 if (sm
->state
== &locked
)
848 if (sm
->state
== &unlocked
)
849 return KNOWN_UNLOCKED
;
852 if (sm
->state
== &locked
)
854 if (sm
->state
== &unlocked
)
856 if (sm
->state
== &restore
)
857 return LOCK_RESTORED
;
861 static void match_return_info(int return_id
, char *return_ranges
, struct expression
*expr
)
864 const char *param_name
;
867 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
868 if (sm
->state
!= &locked
&&
869 sm
->state
!= &unlocked
&&
870 sm
->state
!= &restore
)
873 param
= get_param_key_from_sm(sm
, expr
, ¶m_name
);
874 sql_insert_return_states(return_id
, return_ranges
,
876 param
, param_name
, "");
877 } END_FOR_EACH_SM(sm
);
881 ERR_PTR
, VALID_PTR
, NEGATIVE
, ZERO
, POSITIVE
, NUM_BUCKETS
,
884 static bool is_EINTR(struct range_list
*rl
)
888 if (!rl_to_sval(rl
, &sval
))
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) */
899 if (rl_type(rl
)->type
!= SYM_PTR
&& sval_is_negative(rl_min(rl
)))
902 if (rl_min(rl
).value
== 0 && rl_max(rl
).value
== 0)
905 if (is_err_ptr(rl_min(rl
)) &&
906 is_err_ptr(rl_max(rl
)))
910 * Trying to match ERR_PTR(ret) but without the expression struct.
913 if (type_bits(&long_ctype
) == 64 &&
914 rl_type(rl
)->type
== SYM_PTR
&&
915 rl_min(rl
).value
== INT_MIN
)
921 static bool sym_in_lock_table(struct symbol
*sym
)
925 if (!sym
|| !sym
->ident
)
928 for (i
= 0; lock_table
[i
].function
!= NULL
; i
++) {
929 if (strcmp(lock_table
[i
].function
, sym
->ident
->name
) == 0)
935 static bool func_in_lock_table(struct expression
*expr
)
937 if (expr
->type
!= EXPR_SYMBOL
)
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
;
951 sval_t line
= sval_type_val(&int_ctype
, 0);
955 if (sym_in_lock_table(cur_func_sym
))
958 FOR_EACH_PTR(get_all_return_strees(), stree
) {
959 orig
= __swap_cur_stree(stree
);
961 if (is_impossible_path())
964 return_sm
= get_sm_state(RETURN_ID
, "return_ranges", NULL
);
967 line
.value
= return_sm
->line
;
969 sm
= get_sm_state(my_id
, name
, sym
);
973 if (parent_is_gone_var_sym(sm
->name
, sm
->sym
))
976 if (sm
->state
!= &locked
&&
977 sm
->state
!= &unlocked
&&
978 sm
->state
!= &restore
)
981 if ((sm
->state
== &unlocked
|| sm
->state
== &restore
) &&
982 is_EINTR(estate_rl(return_sm
->state
)))
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;
995 __swap_cur_stree(orig
);
996 } END_FOR_EACH_PTR(stree
);
999 if (!locked_lines
|| !unlocked_lines
)
1002 for (i
= 0; i
< NUM_BUCKETS
; i
++) {
1003 if (locked_buckets
[i
] && unlocked_buckets
[i
])
1006 if (locked_buckets
[NEGATIVE
] &&
1007 (unlocked_buckets
[ZERO
] || unlocked_buckets
[POSITIVE
]))
1010 if (locked_buckets
[ERR_PTR
])
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
)
1054 for (i
= 0; lock_table
[i
].function
!= NULL
; i
++) {
1055 if (lock_table
[i
].action
== LOCK
)
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
;
1069 while (call
->type
== EXPR_ASSIGNMENT
)
1070 call
= strip_expr(call
->right
);
1071 if (call
->type
!= EXPR_CALL
)
1074 if (func_in_lock_table(call
->fn
))
1078 use_best_match(key
, lock_unlock
);
1083 if (expr
->type
!= EXPR_ASSIGNMENT
)
1085 name
= get_variable_from_key(expr
->left
, key
, &sym
);
1087 arg
= get_argument_from_call_expr(call
->args
, param
);
1091 name
= get_variable_from_key(arg
, key
, &sym
);
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
);
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
;
1129 FOR_EACH_PTR(call
->args
, arg
) {
1130 arg_name
= sm_to_arg_name(arg
, sm
);
1136 } END_FOR_EACH_PTR(arg
);
1142 static void match_call_info(struct expression
*expr
)
1144 struct sm_state
*sm
;
1145 const char *param_name
;
1149 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
1150 param
= get_caller_param_lock_name(expr
, sm
, ¶m_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
;
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
;
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
))
1191 lock_name
= lock_to_name_sym(lock
, &sym
);
1192 if (!lock_name
|| !sym
)
1194 do_lock(lock_name
, sym
, NULL
);
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
;
1206 stree
= __get_cur_stree();
1207 FOR_EACH_MY_SM(my_id
, stree
, sm
) {
1208 if (sm
->state
!= &locked
)
1212 sm_printf("'%s'", sm
->name
);
1213 } END_FOR_EACH_SM(sm
);
1216 static bool is_smp_config(void)
1220 id
= built_in_ident("CONFIG_SMP");
1221 return !!lookup_symbol(id
, NS_MACRO
);
1224 void check_locking(int id
)
1228 if (option_project
!= PROJ_KERNEL
)
1231 if (!is_smp_config())
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);