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 && 1025 sm->state != &unlocked && 1026 sm->state != &restore) 1027 goto swap_stree; 1028 1029 if ((sm->state == &unlocked || sm->state == &restore) && 1030 is_EINTR(estate_rl(return_sm->state))) 1031 goto swap_stree; 1032 1033 bucket = success_fail_positive(estate_rl(return_sm->state)); 1034 if (sm->state == &locked) { 1035 add_range(&locked_lines, line, line); 1036 locked_buckets[bucket] = true; 1037 } 1038 if (sm->state == &unlocked || sm->state == &restore) { 1039 add_range(&unlocked_lines, line, line); 1040 unlocked_buckets[bucket] = true; 1041 } 1042 swap_stree: 1043 __swap_cur_stree(orig); 1044 } END_FOR_EACH_PTR(stree); 1045 1046 1047 if (!locked_lines || !unlocked_lines) 1048 return; 1049 1050 for (i = 0; i < NUM_BUCKETS; i++) { 1051 if (locked_buckets[i] && unlocked_buckets[i]) 1052 goto complain; 1053 } 1054 if (locked_buckets[NEGATIVE] && 1055 (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE])) 1056 goto complain; 1057 1058 if (locked_buckets[ERR_PTR]) 1059 goto complain; 1060 1061 return; 1062 1063 complain: 1064 sm_msg("warn: inconsistent returns '%s'.", name); 1065 sm_printf(" Locked on : %s\n", show_rl(locked_lines)); 1066 sm_printf(" Unlocked on: %s\n", show_rl(unlocked_lines)); 1067 } 1068 1069 static void match_func_end(struct symbol *sym) 1070 { 1071 struct tracker *tracker; 1072 1073 FOR_EACH_PTR(locks, tracker) { 1074 check_lock(tracker->name, tracker->sym); 1075 } END_FOR_EACH_PTR(tracker); 1076 } 1077 1078 static void register_lock(int index) 1079 { 1080 struct lock_info *lock = &lock_table[index]; 1081 void *idx = INT_PTR(index); 1082 1083 if (lock->return_type == ret_one) { 1084 return_implies_state(lock->function, 1, 1, &match_lock_held, idx); 1085 return_implies_state(lock->function, 0, 0, &match_lock_failed, idx); 1086 } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) { 1087 add_function_assign_hook(lock->function, &match_returns_locked, idx); 1088 } else if (lock->return_type == ret_any) { 1089 add_function_hook(lock->function, &match_lock_unlock, idx); 1090 } else if (lock->return_type == ret_zero) { 1091 return_implies_state(lock->function, 0, 0, &match_lock_held, idx); 1092 return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx); 1093 } else if (lock->return_type == ret_valid_ptr) { 1094 return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx); 1095 } 1096 } 1097 1098 static void load_table(struct lock_info *lock_table) 1099 { 1100 int i; 1101 1102 for (i = 0; lock_table[i].function != NULL; i++) { 1103 if (lock_table[i].action == LOCK) 1104 register_lock(i); 1105 else 1106 add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i)); 1107 } 1108 } 1109 1110 static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock) 1111 { 1112 struct expression *call, *arg; 1113 char *name; 1114 struct symbol *sym; 1115 1116 call = expr; 1117 while (call->type == EXPR_ASSIGNMENT) 1118 call = strip_expr(call->right); 1119 if (call->type != EXPR_CALL) 1120 return; 1121 1122 if (func_in_lock_table(call->fn)) 1123 return; 1124 1125 if (param == -2) { 1126 use_best_match(key, lock_unlock); 1127 return; 1128 } 1129 1130 if (param == -1) { 1131 if (expr->type != EXPR_ASSIGNMENT) 1132 return; 1133 name = get_variable_from_key(expr->left, key, &sym); 1134 } else { 1135 arg = get_argument_from_call_expr(call->args, param); 1136 if (!arg) 1137 return; 1138 1139 name = get_variable_from_key(arg, key, &sym); 1140 } 1141 if (!name || !sym) 1142 goto free; 1143 1144 if (lock_unlock == LOCK) 1145 do_lock(name, sym, NULL); 1146 else if (lock_unlock == UNLOCK) 1147 do_unlock(name, sym, NULL); 1148 else if (lock_unlock == RESTORE) 1149 do_restore(name, sym, NULL); 1150 1151 free: 1152 free_string(name); 1153 } 1154 1155 static void db_param_locked(struct expression *expr, int param, char *key, char *value) 1156 { 1157 db_param_locked_unlocked(expr, param, key, value, LOCK); 1158 } 1159 1160 static void db_param_unlocked(struct expression *expr, int param, char *key, char *value) 1161 { 1162 db_param_locked_unlocked(expr, param, key, value, UNLOCK); 1163 } 1164 1165 static void db_param_restore(struct expression *expr, int param, char *key, char *value) 1166 { 1167 db_param_locked_unlocked(expr, param, key, value, RESTORE); 1168 } 1169 1170 static int get_caller_param_lock_name(struct expression *call, struct sm_state *sm, const char **name) 1171 { 1172 struct expression *arg; 1173 char *arg_name; 1174 int param; 1175 1176 param = 0; 1177 FOR_EACH_PTR(call->args, arg) { 1178 arg_name = sm_to_arg_name(arg, sm); 1179 if (arg_name) { 1180 *name = arg_name; 1181 return param; 1182 } 1183 param++; 1184 } END_FOR_EACH_PTR(arg); 1185 1186 *name = sm->name; 1187 return -2; 1188 } 1189 1190 static void match_call_info(struct expression *expr) 1191 { 1192 struct sm_state *sm; 1193 const char *param_name; 1194 int locked_type; 1195 int param; 1196 1197 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { 1198 param = get_caller_param_lock_name(expr, sm, ¶m_name); 1199 if (sm->state == &locked) 1200 locked_type = LOCKED; 1201 else if (sm->state == &half_locked || 1202 slist_has_state(sm->possible, &locked)) 1203 locked_type = HALF_LOCKED; 1204 else 1205 continue; 1206 sql_insert_caller_info(expr, locked_type, param, param_name, "xxx type"); 1207 1208 } END_FOR_EACH_SM(sm); 1209 } 1210 1211 static void match_save_states(struct expression *expr) 1212 { 1213 push_stree(&saved_stack, start_states); 1214 start_states = NULL; 1215 } 1216 1217 static void match_restore_states(struct expression *expr) 1218 { 1219 start_states = pop_stree(&saved_stack); 1220 } 1221 1222 static void match_after_func(struct symbol *sym) 1223 { 1224 free_stree(&start_states); 1225 } 1226 1227 static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr, 1228 struct expression *assign_expr, void *_index) 1229 { 1230 struct expression *lock, *ctx; 1231 char *lock_name; 1232 struct symbol *sym; 1233 1234 lock = get_argument_from_call_expr(call_expr->args, 0); 1235 ctx = get_argument_from_call_expr(call_expr->args, 1); 1236 if (!expr_is_zero(ctx)) 1237 return; 1238 1239 lock_name = lock_to_name_sym(lock, &sym); 1240 if (!lock_name || !sym) 1241 goto free; 1242 do_lock(lock_name, sym, NULL); 1243 free: 1244 free_string(lock_name); 1245 } 1246 1247 /* print_held_locks() is used in check_call_tree.c */ 1248 void print_held_locks(void) 1249 { 1250 struct stree *stree; 1251 struct sm_state *sm; 1252 int i = 0; 1253 1254 stree = __get_cur_stree(); 1255 FOR_EACH_MY_SM(my_id, stree, sm) { 1256 if (sm->state != &locked) 1257 continue; 1258 if (i++) 1259 sm_printf(" "); 1260 sm_printf("'%s'", sm->name); 1261 } END_FOR_EACH_SM(sm); 1262 } 1263 1264 void check_locking(int id) 1265 { 1266 my_id = id; 1267 1268 if (option_project != PROJ_KERNEL) 1269 return; 1270 1271 load_table(lock_table); 1272 1273 set_dynamic_states(my_id); 1274 add_unmatched_state_hook(my_id, &unmatched_state); 1275 add_pre_merge_hook(my_id, &pre_merge_hook); 1276 add_merge_hook(my_id, &merge_func); 1277 add_modification_hook(my_id, &reset); 1278 1279 add_hook(&match_func_end, END_FUNC_HOOK); 1280 1281 add_hook(&match_after_func, AFTER_FUNC_HOOK); 1282 add_hook(&match_save_states, INLINE_FN_START); 1283 add_hook(&match_restore_states, INLINE_FN_END); 1284 1285 add_hook(&match_call_info, FUNCTION_CALL_HOOK); 1286 1287 add_split_return_callback(match_return_info); 1288 select_return_states_hook(LOCKED, &db_param_locked); 1289 select_return_states_hook(UNLOCKED, &db_param_unlocked); 1290 select_return_states_hook(LOCK_RESTORED, &db_param_restore); 1291 1292 return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0); 1293 } 1294