11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2009 Dan Carpenter.
35a0e240fSJohn Levon  * Copyright (C) 2019 Oracle.
41f5207b7SJohn Levon  *
51f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
61f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
71f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
81f5207b7SJohn Levon  * of the License, or (at your option) any later version.
91f5207b7SJohn Levon  *
101f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
111f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
121f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
131f5207b7SJohn Levon  * GNU General Public License for more details.
141f5207b7SJohn Levon  *
151f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
161f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
171f5207b7SJohn Levon  */
181f5207b7SJohn Levon 
195a0e240fSJohn Levon #include <ctype.h>
201f5207b7SJohn Levon #include "parse.h"
211f5207b7SJohn Levon #include "smatch.h"
221f5207b7SJohn Levon #include "smatch_extra.h"
231f5207b7SJohn Levon #include "smatch_slist.h"
241f5207b7SJohn Levon 
251f5207b7SJohn Levon static int my_id;
261f5207b7SJohn Levon 
271f5207b7SJohn Levon STATE(locked);
285a0e240fSJohn Levon STATE(half_locked);
291f5207b7SJohn Levon STATE(start_state);
301f5207b7SJohn Levon STATE(unlocked);
311f5207b7SJohn Levon STATE(impossible);
325a0e240fSJohn Levon STATE(restore);
331f5207b7SJohn Levon 
341f5207b7SJohn Levon enum action {
351f5207b7SJohn Levon 	LOCK,
361f5207b7SJohn Levon 	UNLOCK,
375a0e240fSJohn Levon 	RESTORE,
385a0e240fSJohn Levon };
395a0e240fSJohn Levon 
405a0e240fSJohn Levon enum lock_type {
415a0e240fSJohn Levon 	spin_lock,
425a0e240fSJohn Levon 	read_lock,
435a0e240fSJohn Levon 	write_lock,
445a0e240fSJohn Levon 	mutex,
455a0e240fSJohn Levon 	bottom_half,
465a0e240fSJohn Levon 	irq,
475a0e240fSJohn Levon 	sem,
485a0e240fSJohn Levon 	prepare_lock,
495a0e240fSJohn Levon 	enable_lock,
501f5207b7SJohn Levon };
511f5207b7SJohn Levon 
get_lock_name(enum lock_type type)525a0e240fSJohn Levon const char *get_lock_name(enum lock_type type)
535a0e240fSJohn Levon {
545a0e240fSJohn Levon 	static const char *names[] = {
555a0e240fSJohn Levon 		[spin_lock] = "spin_lock",
565a0e240fSJohn Levon 		[read_lock] = "read_lock",
575a0e240fSJohn Levon 		[write_lock] = "write_lock",
585a0e240fSJohn Levon 		[mutex] = "mutex",
595a0e240fSJohn Levon 		[bottom_half] = "bottom_half",
605a0e240fSJohn Levon 		[irq] = "irq",
615a0e240fSJohn Levon 		[sem] = "sem",
625a0e240fSJohn Levon 		[prepare_lock] = "prepare_lock",
635a0e240fSJohn Levon 		[enable_lock] = "enable_lock",
645a0e240fSJohn Levon 	};
655a0e240fSJohn Levon 
665a0e240fSJohn Levon 	return names[type];
675a0e240fSJohn Levon }
685a0e240fSJohn Levon 
691f5207b7SJohn Levon enum return_type {
701f5207b7SJohn Levon 	ret_any,
711f5207b7SJohn Levon 	ret_zero,
72efe51d0cSJohn Levon 	ret_one,
731f5207b7SJohn Levon 	ret_negative,
741f5207b7SJohn Levon 	ret_positive,
755a0e240fSJohn Levon 	ret_valid_ptr,
761f5207b7SJohn Levon };
771f5207b7SJohn Levon 
781f5207b7SJohn Levon #define RETURN_VAL -1
791f5207b7SJohn Levon #define NO_ARG -2
801f5207b7SJohn Levon 
811f5207b7SJohn Levon struct lock_info {
821f5207b7SJohn Levon 	const char *function;
831f5207b7SJohn Levon 	enum action action;
845a0e240fSJohn Levon 	enum lock_type type;
851f5207b7SJohn Levon 	int arg;
861f5207b7SJohn Levon 	enum return_type return_type;
871f5207b7SJohn Levon };
881f5207b7SJohn Levon 
895a0e240fSJohn Levon static struct lock_info lock_table[] = {
905a0e240fSJohn Levon 	{"spin_lock",                  LOCK,   spin_lock, 0, ret_any},
915a0e240fSJohn Levon 	{"spin_unlock",                UNLOCK, spin_lock, 0, ret_any},
925a0e240fSJohn Levon 	{"spin_lock_nested",           LOCK,   spin_lock, 0, ret_any},
935a0e240fSJohn Levon 	{"_spin_lock",                 LOCK,   spin_lock, 0, ret_any},
945a0e240fSJohn Levon 	{"_spin_unlock",               UNLOCK, spin_lock, 0, ret_any},
955a0e240fSJohn Levon 	{"_spin_lock_nested",          LOCK,   spin_lock, 0, ret_any},
965a0e240fSJohn Levon 	{"__spin_lock",                LOCK,   spin_lock, 0, ret_any},
975a0e240fSJohn Levon 	{"__spin_unlock",              UNLOCK, spin_lock, 0, ret_any},
985a0e240fSJohn Levon 	{"__spin_lock_nested",         LOCK,   spin_lock, 0, ret_any},
995a0e240fSJohn Levon 	{"raw_spin_lock",              LOCK,   spin_lock, 0, ret_any},
1005a0e240fSJohn Levon 	{"raw_spin_unlock",            UNLOCK, spin_lock, 0, ret_any},
1015a0e240fSJohn Levon 	{"_raw_spin_lock",             LOCK,   spin_lock, 0, ret_any},
1025a0e240fSJohn Levon 	{"_raw_spin_lock_nested",      LOCK,   spin_lock, 0, ret_any},
1035a0e240fSJohn Levon 	{"_raw_spin_unlock",           UNLOCK, spin_lock, 0, ret_any},
1045a0e240fSJohn Levon 	{"__raw_spin_lock",            LOCK,   spin_lock, 0, ret_any},
1055a0e240fSJohn Levon 	{"__raw_spin_unlock",          UNLOCK, spin_lock, 0, ret_any},
1065a0e240fSJohn Levon 
1075a0e240fSJohn Levon 	{"spin_lock_irq",                 LOCK,   spin_lock, 0, ret_any},
1085a0e240fSJohn Levon 	{"spin_unlock_irq",               UNLOCK, spin_lock, 0, ret_any},
1095a0e240fSJohn Levon 	{"_spin_lock_irq",                LOCK,   spin_lock, 0, ret_any},
1105a0e240fSJohn Levon 	{"_spin_unlock_irq",              UNLOCK, spin_lock, 0, ret_any},
1115a0e240fSJohn Levon 	{"__spin_lock_irq",               LOCK,   spin_lock, 0, ret_any},
1125a0e240fSJohn Levon 	{"__spin_unlock_irq",             UNLOCK, spin_lock, 0, ret_any},
1135a0e240fSJohn Levon 	{"_raw_spin_lock_irq",            LOCK,   spin_lock, 0, ret_any},
1145a0e240fSJohn Levon 	{"_raw_spin_unlock_irq",          UNLOCK, spin_lock, 0, ret_any},
1155a0e240fSJohn Levon 	{"__raw_spin_unlock_irq",         UNLOCK, spin_lock, 0, ret_any},
1165a0e240fSJohn Levon 	{"spin_lock_irqsave",             LOCK,   spin_lock, 0, ret_any},
1175a0e240fSJohn Levon 	{"spin_unlock_irqrestore",        UNLOCK, spin_lock, 0, ret_any},
1185a0e240fSJohn Levon 	{"_spin_lock_irqsave",            LOCK,   spin_lock, 0, ret_any},
1195a0e240fSJohn Levon 	{"_spin_unlock_irqrestore",       UNLOCK, spin_lock, 0, ret_any},
1205a0e240fSJohn Levon 	{"__spin_lock_irqsave",           LOCK,   spin_lock, 0, ret_any},
1215a0e240fSJohn Levon 	{"__spin_unlock_irqrestore",      UNLOCK, spin_lock, 0, ret_any},
1225a0e240fSJohn Levon 	{"_raw_spin_lock_irqsave",        LOCK,   spin_lock, 0, ret_any},
1235a0e240fSJohn Levon 	{"_raw_spin_unlock_irqrestore",   UNLOCK, spin_lock, 0, ret_any},
1245a0e240fSJohn Levon 	{"__raw_spin_lock_irqsave",       LOCK,   spin_lock, 0, ret_any},
1255a0e240fSJohn Levon 	{"__raw_spin_unlock_irqrestore",  UNLOCK, spin_lock, 0, ret_any},
1265a0e240fSJohn Levon 	{"spin_lock_irqsave_nested",      LOCK,   spin_lock, 0, ret_any},
1275a0e240fSJohn Levon 	{"_spin_lock_irqsave_nested",     LOCK,   spin_lock, 0, ret_any},
1285a0e240fSJohn Levon 	{"__spin_lock_irqsave_nested",    LOCK,   spin_lock, 0, ret_any},
1295a0e240fSJohn Levon 	{"_raw_spin_lock_irqsave_nested", LOCK,   spin_lock, 0, ret_any},
1305a0e240fSJohn Levon 	{"spin_lock_bh",                  LOCK,   spin_lock, 0, ret_any},
1315a0e240fSJohn Levon 	{"spin_unlock_bh",                UNLOCK, spin_lock, 0, ret_any},
1325a0e240fSJohn Levon 	{"_spin_lock_bh",                 LOCK,   spin_lock, 0, ret_any},
1335a0e240fSJohn Levon 	{"_spin_unlock_bh",               UNLOCK, spin_lock, 0, ret_any},
1345a0e240fSJohn Levon 	{"__spin_lock_bh",                LOCK,   spin_lock, 0, ret_any},
1355a0e240fSJohn Levon 	{"__spin_unlock_bh",              UNLOCK, spin_lock, 0, ret_any},
1365a0e240fSJohn Levon 
1375a0e240fSJohn Levon 	{"spin_trylock",               LOCK,   spin_lock, 0, ret_one},
1385a0e240fSJohn Levon 	{"_spin_trylock",              LOCK,   spin_lock, 0, ret_one},
1395a0e240fSJohn Levon 	{"__spin_trylock",             LOCK,   spin_lock, 0, ret_one},
1405a0e240fSJohn Levon 	{"raw_spin_trylock",           LOCK,   spin_lock, 0, ret_one},
1415a0e240fSJohn Levon 	{"_raw_spin_trylock",          LOCK,   spin_lock, 0, ret_one},
1425a0e240fSJohn Levon 	{"spin_trylock_irq",           LOCK,   spin_lock, 0, ret_one},
1435a0e240fSJohn Levon 	{"spin_trylock_irqsave",       LOCK,   spin_lock, 0, ret_one},
1445a0e240fSJohn Levon 	{"spin_trylock_bh",            LOCK,   spin_lock, 0, ret_one},
1455a0e240fSJohn Levon 	{"_spin_trylock_bh",           LOCK,   spin_lock, 0, ret_one},
1465a0e240fSJohn Levon 	{"__spin_trylock_bh",          LOCK,   spin_lock, 0, ret_one},
1475a0e240fSJohn Levon 	{"__raw_spin_trylock",         LOCK,   spin_lock, 0, ret_one},
1485a0e240fSJohn Levon 	{"_atomic_dec_and_lock",       LOCK,   spin_lock, 1, ret_one},
1495a0e240fSJohn Levon 
1505a0e240fSJohn Levon 	{"read_lock",                 LOCK,   read_lock, 0, ret_any},
1515a0e240fSJohn Levon 	{"down_read",                 LOCK,   read_lock, 0, ret_any},
1525a0e240fSJohn Levon 	{"down_read_nested",          LOCK,   read_lock, 0, ret_any},
1535a0e240fSJohn Levon 	{"down_read_trylock",         LOCK,   read_lock, 0, ret_one},
1545a0e240fSJohn Levon 	{"up_read",                   UNLOCK, read_lock, 0, ret_any},
1555a0e240fSJohn Levon 	{"read_unlock",               UNLOCK, read_lock, 0, ret_any},
1565a0e240fSJohn Levon 	{"_read_lock",                LOCK,   read_lock, 0, ret_any},
1575a0e240fSJohn Levon 	{"_read_unlock",              UNLOCK, read_lock, 0, ret_any},
1585a0e240fSJohn Levon 	{"__read_lock",               LOCK,   read_lock, 0, ret_any},
1595a0e240fSJohn Levon 	{"__read_unlock",             UNLOCK, read_lock, 0, ret_any},
1605a0e240fSJohn Levon 	{"_raw_read_lock",            LOCK,   read_lock, 0, ret_any},
1615a0e240fSJohn Levon 	{"_raw_read_unlock",          UNLOCK, read_lock, 0, ret_any},
1625a0e240fSJohn Levon 	{"__raw_read_lock",           LOCK,   read_lock, 0, ret_any},
1635a0e240fSJohn Levon 	{"__raw_read_unlock",         UNLOCK, read_lock, 0, ret_any},
1645a0e240fSJohn Levon 	{"read_lock_irq",             LOCK,   read_lock, 0, ret_any},
1655a0e240fSJohn Levon 	{"read_unlock_irq" ,          UNLOCK, read_lock, 0, ret_any},
1665a0e240fSJohn Levon 	{"_read_lock_irq",            LOCK,   read_lock, 0, ret_any},
1675a0e240fSJohn Levon 	{"_read_unlock_irq",          UNLOCK, read_lock, 0, ret_any},
1685a0e240fSJohn Levon 	{"__read_lock_irq",           LOCK,   read_lock, 0, ret_any},
1695a0e240fSJohn Levon 	{"__read_unlock_irq",         UNLOCK, read_lock, 0, ret_any},
1705a0e240fSJohn Levon 	{"_raw_read_unlock_irq",      UNLOCK, read_lock, 0, ret_any},
1715a0e240fSJohn Levon 	{"_raw_read_lock_irq",        LOCK,   read_lock, 0, ret_any},
1725a0e240fSJohn Levon 	{"_raw_read_lock_bh",         LOCK,   read_lock, 0, ret_any},
1735a0e240fSJohn Levon 	{"_raw_read_unlock_bh",       UNLOCK, read_lock, 0, ret_any},
1745a0e240fSJohn Levon 	{"read_lock_irqsave",         LOCK,   read_lock, 0, ret_any},
1755a0e240fSJohn Levon 	{"read_unlock_irqrestore",    UNLOCK, read_lock, 0, ret_any},
1765a0e240fSJohn Levon 	{"_read_lock_irqsave",        LOCK,   read_lock, 0, ret_any},
1775a0e240fSJohn Levon 	{"_read_unlock_irqrestore",   UNLOCK, read_lock, 0, ret_any},
1785a0e240fSJohn Levon 	{"__read_lock_irqsave",       LOCK,   read_lock, 0, ret_any},
1795a0e240fSJohn Levon 	{"__read_unlock_irqrestore",  UNLOCK, read_lock, 0, ret_any},
1805a0e240fSJohn Levon 	{"read_lock_bh",              LOCK,   read_lock, 0, ret_any},
1815a0e240fSJohn Levon 	{"read_unlock_bh",            UNLOCK, read_lock, 0, ret_any},
1825a0e240fSJohn Levon 	{"_read_lock_bh",             LOCK,   read_lock, 0, ret_any},
1835a0e240fSJohn Levon 	{"_read_unlock_bh",           UNLOCK, read_lock, 0, ret_any},
1845a0e240fSJohn Levon 	{"__read_lock_bh",            LOCK,   read_lock, 0, ret_any},
1855a0e240fSJohn Levon 	{"__read_unlock_bh",          UNLOCK, read_lock, 0, ret_any},
1865a0e240fSJohn Levon 	{"__raw_read_lock_bh",        LOCK,   read_lock, 0, ret_any},
1875a0e240fSJohn Levon 	{"__raw_read_unlock_bh",      UNLOCK, read_lock, 0, ret_any},
1885a0e240fSJohn Levon 
1895a0e240fSJohn Levon 	{"_raw_read_lock_irqsave",        LOCK,    read_lock,   0,          ret_any},
1905a0e240fSJohn Levon 	{"_raw_read_lock_irqsave",        LOCK,    irq,	        RETURN_VAL, ret_any},
1915a0e240fSJohn Levon 	{"_raw_read_unlock_irqrestore",   UNLOCK,  read_lock,   0,          ret_any},
1925a0e240fSJohn Levon 	{"_raw_read_unlock_irqrestore",   RESTORE, irq,         1,          ret_any},
1935a0e240fSJohn Levon 	{"_raw_spin_lock_bh",             LOCK,    read_lock,   0,          ret_any},
1945a0e240fSJohn Levon 	{"_raw_spin_lock_bh",             LOCK,    bottom_half, NO_ARG,     ret_any},
1955a0e240fSJohn Levon 	{"_raw_spin_lock_nest_lock",      LOCK,    read_lock,   0,          ret_any},
1965a0e240fSJohn Levon 	{"_raw_spin_unlock_bh",           UNLOCK,  read_lock,   0,          ret_any},
1975a0e240fSJohn Levon 	{"_raw_spin_unlock_bh",           UNLOCK,  bottom_half, NO_ARG,     ret_any},
1985a0e240fSJohn Levon 	{"_raw_write_lock_irqsave",       LOCK,    write_lock,  0,          ret_any},
1995a0e240fSJohn Levon 	{"_raw_write_lock_irqsave",       LOCK,    irq,         RETURN_VAL, ret_any},
2005a0e240fSJohn Levon 	{"_raw_write_unlock_irqrestore",  UNLOCK,  write_lock,  0,          ret_any},
2015a0e240fSJohn Levon 	{"_raw_write_unlock_irqrestore",  RESTORE, irq,         1,          ret_any},
2025a0e240fSJohn Levon 	{"__raw_write_unlock_irqrestore", UNLOCK,  write_lock,  0,          ret_any},
2035a0e240fSJohn Levon 	{"__raw_write_unlock_irqrestore", RESTORE, irq,         1,          ret_any},
2045a0e240fSJohn Levon 
2055a0e240fSJohn Levon 	{"generic__raw_read_trylock", LOCK,   read_lock, 0, ret_one},
2065a0e240fSJohn Levon 	{"read_trylock",              LOCK,   read_lock, 0, ret_one},
2075a0e240fSJohn Levon 	{"_read_trylock",             LOCK,   read_lock, 0, ret_one},
2085a0e240fSJohn Levon 	{"raw_read_trylock",          LOCK,   read_lock, 0, ret_one},
2095a0e240fSJohn Levon 	{"_raw_read_trylock",         LOCK,   read_lock, 0, ret_one},
2105a0e240fSJohn Levon 	{"__raw_read_trylock",        LOCK,   read_lock, 0, ret_one},
2115a0e240fSJohn Levon 	{"__read_trylock",            LOCK,   read_lock, 0, ret_one},
2125a0e240fSJohn Levon 
2135a0e240fSJohn Levon 	{"write_lock",                LOCK,   write_lock, 0, ret_any},
2145a0e240fSJohn Levon 	{"down_write",                LOCK,   write_lock, 0, ret_any},
2155a0e240fSJohn Levon 	{"down_write_nested",         LOCK,   write_lock, 0, ret_any},
2165a0e240fSJohn Levon 	{"up_write",                  UNLOCK, write_lock, 0, ret_any},
2175a0e240fSJohn Levon 	{"write_unlock",              UNLOCK, write_lock, 0, ret_any},
2185a0e240fSJohn Levon 	{"_write_lock",               LOCK,   write_lock, 0, ret_any},
2195a0e240fSJohn Levon 	{"_write_unlock",             UNLOCK, write_lock, 0, ret_any},
2205a0e240fSJohn Levon 	{"__write_lock",              LOCK,   write_lock, 0, ret_any},
2215a0e240fSJohn Levon 	{"__write_unlock",            UNLOCK, write_lock, 0, ret_any},
2225a0e240fSJohn Levon 	{"write_lock_irq",            LOCK,   write_lock, 0, ret_any},
2235a0e240fSJohn Levon 	{"write_unlock_irq",          UNLOCK, write_lock, 0, ret_any},
2245a0e240fSJohn Levon 	{"_write_lock_irq",           LOCK,   write_lock, 0, ret_any},
2255a0e240fSJohn Levon 	{"_write_unlock_irq",         UNLOCK, write_lock, 0, ret_any},
2265a0e240fSJohn Levon 	{"__write_lock_irq",          LOCK,   write_lock, 0, ret_any},
2275a0e240fSJohn Levon 	{"__write_unlock_irq",        UNLOCK, write_lock, 0, ret_any},
2285a0e240fSJohn Levon 	{"_raw_write_unlock_irq",     UNLOCK, write_lock, 0, ret_any},
2295a0e240fSJohn Levon 	{"write_lock_irqsave",        LOCK,   write_lock, 0, ret_any},
2305a0e240fSJohn Levon 	{"write_unlock_irqrestore",   UNLOCK, write_lock, 0, ret_any},
2315a0e240fSJohn Levon 	{"_write_lock_irqsave",       LOCK,   write_lock, 0, ret_any},
2325a0e240fSJohn Levon 	{"_write_unlock_irqrestore",  UNLOCK, write_lock, 0, ret_any},
2335a0e240fSJohn Levon 	{"__write_lock_irqsave",      LOCK,   write_lock, 0, ret_any},
2345a0e240fSJohn Levon 	{"__write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
2355a0e240fSJohn Levon 	{"write_lock_bh",             LOCK,   write_lock, 0, ret_any},
2365a0e240fSJohn Levon 	{"write_unlock_bh",           UNLOCK, write_lock, 0, ret_any},
2375a0e240fSJohn Levon 	{"_write_lock_bh",            LOCK,   write_lock, 0, ret_any},
2385a0e240fSJohn Levon 	{"_write_unlock_bh",          UNLOCK, write_lock, 0, ret_any},
2395a0e240fSJohn Levon 	{"__write_lock_bh",           LOCK,   write_lock, 0, ret_any},
2405a0e240fSJohn Levon 	{"__write_unlock_bh",         UNLOCK, write_lock, 0, ret_any},
2415a0e240fSJohn Levon 	{"_raw_write_lock",           LOCK,   write_lock, 0, ret_any},
2425a0e240fSJohn Levon 	{"__raw_write_lock",          LOCK,   write_lock, 0, ret_any},
2435a0e240fSJohn Levon 	{"_raw_write_unlock",         UNLOCK, write_lock, 0, ret_any},
2445a0e240fSJohn Levon 	{"__raw_write_unlock",        UNLOCK, write_lock, 0, ret_any},
2455a0e240fSJohn Levon 	{"_raw_write_lock_bh",        LOCK,   write_lock, 0, ret_any},
2465a0e240fSJohn Levon 	{"_raw_write_unlock_bh",      UNLOCK, write_lock, 0, ret_any},
2475a0e240fSJohn Levon 	{"_raw_write_lock_irq",       LOCK,   write_lock, 0, ret_any},
2485a0e240fSJohn Levon 
2495a0e240fSJohn Levon 	{"write_trylock",             LOCK,   write_lock, 0, ret_one},
2505a0e240fSJohn Levon 	{"_write_trylock",            LOCK,   write_lock, 0, ret_one},
2515a0e240fSJohn Levon 	{"raw_write_trylock",         LOCK,   write_lock, 0, ret_one},
2525a0e240fSJohn Levon 	{"_raw_write_trylock",        LOCK,   write_lock, 0, ret_one},
2535a0e240fSJohn Levon 	{"__write_trylock",           LOCK,   write_lock, 0, ret_one},
2545a0e240fSJohn Levon 	{"__raw_write_trylock",       LOCK,   write_lock, 0, ret_one},
2555a0e240fSJohn Levon 	{"down_write_trylock",        LOCK,   write_lock, 0, ret_one},
2565a0e240fSJohn Levon 	{"down_write_killable",       LOCK,   write_lock, 0, ret_zero},
2575a0e240fSJohn Levon 
2585a0e240fSJohn Levon 	{"down",               LOCK,   sem, 0, ret_any},
2595a0e240fSJohn Levon 	{"up",                 UNLOCK, sem, 0, ret_any},
2605a0e240fSJohn Levon 	{"down_trylock",       LOCK,   sem, 0, ret_zero},
2615a0e240fSJohn Levon 	{"down_timeout",       LOCK,   sem, 0, ret_zero},
2625a0e240fSJohn Levon 	{"down_interruptible", LOCK,   sem, 0, ret_zero},
2635a0e240fSJohn Levon 	{"down_killable",      LOCK,   sem, 0, ret_zero},
2645a0e240fSJohn Levon 
2655a0e240fSJohn Levon 
2665a0e240fSJohn Levon 	{"mutex_lock",                      LOCK,   mutex, 0, ret_any},
2675a0e240fSJohn Levon 	{"mutex_unlock",                    UNLOCK, mutex, 0, ret_any},
2685a0e240fSJohn Levon 	{"mutex_lock_nested",               LOCK,   mutex, 0, ret_any},
2695a0e240fSJohn Levon 	{"mutex_lock_io",                   LOCK,   mutex, 0, ret_any},
2705a0e240fSJohn Levon 	{"mutex_lock_io_nested",            LOCK,   mutex, 0, ret_any},
2715a0e240fSJohn Levon 
2725a0e240fSJohn Levon 	{"mutex_lock_interruptible",        LOCK,   mutex, 0, ret_zero},
2735a0e240fSJohn Levon 	{"mutex_lock_interruptible_nested", LOCK,   mutex, 0, ret_zero},
2745a0e240fSJohn Levon 	{"mutex_lock_killable",             LOCK,   mutex, 0, ret_zero},
2755a0e240fSJohn Levon 	{"mutex_lock_killable_nested",      LOCK,   mutex, 0, ret_zero},
2765a0e240fSJohn Levon 
2775a0e240fSJohn Levon 	{"mutex_trylock",                   LOCK,   mutex, 0, ret_one},
2785a0e240fSJohn Levon 
2795a0e240fSJohn Levon 	{"ww_mutex_lock",		LOCK,   mutex, 0, ret_any},
2805a0e240fSJohn Levon 	{"__ww_mutex_lock",		LOCK,   mutex, 0, ret_any},
2815a0e240fSJohn Levon 	{"ww_mutex_lock_interruptible",	LOCK,   mutex, 0, ret_zero},
2825a0e240fSJohn Levon 	{"ww_mutex_unlock",		UNLOCK, mutex, 0, ret_any},
2835a0e240fSJohn Levon 
2845a0e240fSJohn Levon 	{"raw_local_irq_disable", LOCK,   irq, NO_ARG, ret_any},
2855a0e240fSJohn Levon 	{"raw_local_irq_enable",  UNLOCK, irq, NO_ARG, ret_any},
2865a0e240fSJohn Levon 	{"spin_lock_irq",         LOCK,   irq, NO_ARG, ret_any},
2875a0e240fSJohn Levon 	{"spin_unlock_irq",       UNLOCK, irq, NO_ARG, ret_any},
2885a0e240fSJohn Levon 	{"_spin_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
2895a0e240fSJohn Levon 	{"_spin_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
2905a0e240fSJohn Levon 	{"__spin_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
2915a0e240fSJohn Levon 	{"__spin_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
2925a0e240fSJohn Levon 	{"_raw_spin_lock_irq",    LOCK,   irq, NO_ARG, ret_any},
2935a0e240fSJohn Levon 	{"_raw_spin_unlock_irq",  UNLOCK, irq, NO_ARG, ret_any},
2945a0e240fSJohn Levon 	{"__raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
2955a0e240fSJohn Levon 	{"spin_trylock_irq",      LOCK,   irq, NO_ARG, ret_one},
2965a0e240fSJohn Levon 	{"read_lock_irq",         LOCK,   irq, NO_ARG, ret_any},
2975a0e240fSJohn Levon 	{"read_unlock_irq",       UNLOCK, irq, NO_ARG, ret_any},
2985a0e240fSJohn Levon 	{"_read_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
2995a0e240fSJohn Levon 	{"_read_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
3005a0e240fSJohn Levon 	{"__read_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
3015a0e240fSJohn Levon 	{"_raw_read_lock_irq",    LOCK,   irq, NO_ARG, ret_any},
3025a0e240fSJohn Levon 	{"__read_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
3035a0e240fSJohn Levon 	{"_raw_read_unlock_irq",  UNLOCK, irq, NO_ARG, ret_any},
3045a0e240fSJohn Levon 	{"write_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
3055a0e240fSJohn Levon 	{"write_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
3065a0e240fSJohn Levon 	{"_write_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
3075a0e240fSJohn Levon 	{"_write_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
3085a0e240fSJohn Levon 	{"__write_lock_irq",      LOCK,   irq, NO_ARG, ret_any},
3095a0e240fSJohn Levon 	{"__write_unlock_irq",    UNLOCK, irq, NO_ARG, ret_any},
3105a0e240fSJohn Levon 	{"_raw_write_lock_irq",   LOCK,   irq, NO_ARG, ret_any},
3115a0e240fSJohn Levon 	{"_raw_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
3125a0e240fSJohn Levon 
3135a0e240fSJohn Levon 	{"arch_local_irq_save",        LOCK,      irq, RETURN_VAL, ret_any},
3145a0e240fSJohn Levon 	{"arch_local_irq_restore",     RESTORE,   irq, 0,	   ret_any},
3155a0e240fSJohn Levon 	{"__raw_local_irq_save",       LOCK,      irq, RETURN_VAL, ret_any},
3165a0e240fSJohn Levon 	{"raw_local_irq_restore",      RESTORE,   irq, 0,	   ret_any},
3175a0e240fSJohn Levon 	{"spin_lock_irqsave_nested",   LOCK,      irq, RETURN_VAL, ret_any},
3185a0e240fSJohn Levon 	{"spin_lock_irqsave",          LOCK,      irq, 1,	   ret_any},
3195a0e240fSJohn Levon 	{"spin_unlock_irqrestore",     RESTORE,   irq, 1,	   ret_any},
3205a0e240fSJohn Levon 	{"_spin_lock_irqsave_nested",  LOCK,      irq, RETURN_VAL, ret_any},
3215a0e240fSJohn Levon 	{"_spin_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
3225a0e240fSJohn Levon 	{"_spin_lock_irqsave",         LOCK,      irq, 1,	   ret_any},
3235a0e240fSJohn Levon 	{"_spin_unlock_irqrestore",    RESTORE,   irq, 1,	   ret_any},
3245a0e240fSJohn Levon 	{"__spin_lock_irqsave_nested", LOCK,      irq, 1,	   ret_any},
3255a0e240fSJohn Levon 	{"__spin_lock_irqsave",        LOCK,      irq, 1,	   ret_any},
3265a0e240fSJohn Levon 	{"__spin_unlock_irqrestore",   RESTORE,   irq, 1,	   ret_any},
3275a0e240fSJohn Levon 	{"_raw_spin_lock_irqsave",     LOCK,      irq, RETURN_VAL, ret_any},
3285a0e240fSJohn Levon 	{"_raw_spin_lock_irqsave",     LOCK,      irq, 1,	   ret_any},
3295a0e240fSJohn Levon 	{"_raw_spin_unlock_irqrestore", RESTORE,  irq, 1,	   ret_any},
3305a0e240fSJohn Levon 	{"__raw_spin_lock_irqsave",    LOCK,      irq, RETURN_VAL, ret_any},
3315a0e240fSJohn Levon 	{"__raw_spin_unlock_irqrestore", RESTORE, irq, 1,	   ret_any},
3325a0e240fSJohn Levon 	{"_raw_spin_lock_irqsave_nested", LOCK,   irq, RETURN_VAL, ret_any},
3335a0e240fSJohn Levon 	{"spin_trylock_irqsave",       LOCK,      irq, 1,	   ret_one},
3345a0e240fSJohn Levon 	{"read_lock_irqsave",          LOCK,      irq, RETURN_VAL, ret_any},
3355a0e240fSJohn Levon 	{"read_lock_irqsave",          LOCK,      irq, 1,	   ret_any},
3365a0e240fSJohn Levon 	{"read_unlock_irqrestore",     RESTORE,   irq, 1,	   ret_any},
3375a0e240fSJohn Levon 	{"_read_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
3385a0e240fSJohn Levon 	{"_read_lock_irqsave",         LOCK,      irq, 1,	   ret_any},
3395a0e240fSJohn Levon 	{"_read_unlock_irqrestore",    RESTORE,   irq, 1,	   ret_any},
3405a0e240fSJohn Levon 	{"__read_lock_irqsave",        LOCK,      irq, RETURN_VAL, ret_any},
3415a0e240fSJohn Levon 	{"__read_unlock_irqrestore",   RESTORE,   irq, 1,	   ret_any},
3425a0e240fSJohn Levon 	{"write_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
3435a0e240fSJohn Levon 	{"write_lock_irqsave",         LOCK,      irq, 1,	   ret_any},
3445a0e240fSJohn Levon 	{"write_unlock_irqrestore",    RESTORE,   irq, 1,	   ret_any},
3455a0e240fSJohn Levon 	{"_write_lock_irqsave",        LOCK,      irq, RETURN_VAL, ret_any},
3465a0e240fSJohn Levon 	{"_write_lock_irqsave",        LOCK,      irq, 1,	   ret_any},
3475a0e240fSJohn Levon 	{"_write_unlock_irqrestore",   RESTORE,   irq, 1,	   ret_any},
3485a0e240fSJohn Levon 	{"__write_lock_irqsave",       LOCK,      irq, RETURN_VAL, ret_any},
3495a0e240fSJohn Levon 	{"__write_unlock_irqrestore",  RESTORE,   irq, 1,	   ret_any},
3505a0e240fSJohn Levon 
3515a0e240fSJohn Levon 	{"local_bh_disable",	LOCK,	bottom_half, NO_ARG, ret_any},
3525a0e240fSJohn Levon 	{"_local_bh_disable",	LOCK,	bottom_half, NO_ARG, ret_any},
3535a0e240fSJohn Levon 	{"__local_bh_disable",	LOCK,	bottom_half, NO_ARG, ret_any},
3545a0e240fSJohn Levon 	{"local_bh_enable",	UNLOCK,	bottom_half, NO_ARG, ret_any},
3555a0e240fSJohn Levon 	{"_local_bh_enable",	UNLOCK,	bottom_half, NO_ARG, ret_any},
3565a0e240fSJohn Levon 	{"__local_bh_enable",	UNLOCK,	bottom_half, NO_ARG, ret_any},
3575a0e240fSJohn Levon 	{"spin_lock_bh",        LOCK,   bottom_half, NO_ARG, ret_any},
3585a0e240fSJohn Levon 	{"spin_unlock_bh",      UNLOCK, bottom_half, NO_ARG, ret_any},
3595a0e240fSJohn Levon 	{"_spin_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
3605a0e240fSJohn Levon 	{"_spin_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
3615a0e240fSJohn Levon 	{"__spin_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
3625a0e240fSJohn Levon 	{"__spin_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
3635a0e240fSJohn Levon 	{"read_lock_bh",        LOCK,   bottom_half, NO_ARG, ret_any},
3645a0e240fSJohn Levon 	{"read_unlock_bh",      UNLOCK, bottom_half, NO_ARG, ret_any},
3655a0e240fSJohn Levon 	{"_read_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
3665a0e240fSJohn Levon 	{"_read_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
3675a0e240fSJohn Levon 	{"__read_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
3685a0e240fSJohn Levon 	{"__read_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
3695a0e240fSJohn Levon 	{"_raw_read_lock_bh",   LOCK,   bottom_half, NO_ARG, ret_any},
3705a0e240fSJohn Levon 	{"_raw_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
3715a0e240fSJohn Levon 	{"write_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
3725a0e240fSJohn Levon 	{"write_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
3735a0e240fSJohn Levon 	{"_write_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
3745a0e240fSJohn Levon 	{"_write_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
3755a0e240fSJohn Levon 	{"__write_lock_bh",     LOCK,   bottom_half, NO_ARG, ret_any},
3765a0e240fSJohn Levon 	{"__write_unlock_bh",   UNLOCK, bottom_half, NO_ARG, ret_any},
3775a0e240fSJohn Levon 	{"_raw_write_lock_bh",  LOCK,   bottom_half, NO_ARG, ret_any},
3785a0e240fSJohn Levon 	{"_raw_write_unlock_bh",UNLOCK, bottom_half, NO_ARG, ret_any},
3795a0e240fSJohn Levon 	{"spin_trylock_bh",     LOCK,   bottom_half, NO_ARG, ret_one},
3805a0e240fSJohn Levon 	{"_spin_trylock_bh",    LOCK,   bottom_half, NO_ARG, ret_one},
3815a0e240fSJohn Levon 	{"__spin_trylock_bh",   LOCK,   bottom_half, NO_ARG, ret_one},
3825a0e240fSJohn Levon 
3835a0e240fSJohn Levon 	{"ffs_mutex_lock",      LOCK,   mutex, 0, ret_zero},
3845a0e240fSJohn Levon 
3855a0e240fSJohn Levon 	{"clk_prepare_lock",    LOCK,   prepare_lock, NO_ARG, ret_any},
3865a0e240fSJohn Levon 	{"clk_prepare_unlock",  UNLOCK, prepare_lock, NO_ARG, ret_any},
3875a0e240fSJohn Levon 	{"clk_enable_lock",     LOCK,   enable_lock, -1, ret_any},
3885a0e240fSJohn Levon 	{"clk_enable_unlock",   UNLOCK, enable_lock,  0, ret_any},
3895a0e240fSJohn Levon 
3905a0e240fSJohn Levon 	{"dma_resv_lock",	        LOCK,   mutex, 0, ret_zero},
3915a0e240fSJohn Levon 	{"dma_resv_trylock",	        LOCK,	mutex, 0, ret_one},
3925a0e240fSJohn Levon 	{"dma_resv_lock_interruptible", LOCK,	mutex, 0, ret_zero},
3935a0e240fSJohn Levon 	{"dma_resv_unlock",		UNLOCK, mutex, 0, ret_any},
3945a0e240fSJohn Levon 
3955a0e240fSJohn Levon 	{"modeset_lock",			  LOCK,   mutex, 0, ret_zero},
3965a0e240fSJohn Levon 	{"drm_ modeset_lock",			  LOCK,   mutex, 0, ret_zero},
3975a0e240fSJohn Levon 	{"drm_modeset_lock_single_interruptible", LOCK,   mutex, 0, ret_zero},
3985a0e240fSJohn Levon 	{"modeset_unlock",			  UNLOCK, mutex, 0, ret_any},
3995a0e240fSJohn Levon 
4005a0e240fSJohn Levon 	{"reiserfs_write_lock_nested",	 LOCK,   mutex, 0, ret_any},
4015a0e240fSJohn Levon 	{"reiserfs_write_unlock_nested", UNLOCK, mutex, 0, ret_any},
4025a0e240fSJohn Levon 
4035a0e240fSJohn Levon 	{"rw_lock",                LOCK,   write_lock, 1, ret_any},
4045a0e240fSJohn Levon 	{"rw_unlock",              UNLOCK, write_lock, 1, ret_any},
4055a0e240fSJohn Levon 
4065a0e240fSJohn Levon 	{"sem_lock",               LOCK,   mutex, 0, ret_any},
4075a0e240fSJohn Levon 	{"sem_unlock",             UNLOCK, mutex, 0, ret_any},
4085a0e240fSJohn Levon 
4095a0e240fSJohn Levon 	{},
4101f5207b7SJohn Levon };
4111f5207b7SJohn Levon 
4125a0e240fSJohn Levon struct macro_info {
4135a0e240fSJohn Levon 	const char *macro;
4145a0e240fSJohn Levon 	enum action action;
4155a0e240fSJohn Levon 	int param;
4161f5207b7SJohn Levon };
4171f5207b7SJohn Levon 
4185a0e240fSJohn Levon static struct macro_info macro_table[] = {
4195a0e240fSJohn Levon 	{"genpd_lock",               LOCK,   0},
4205a0e240fSJohn Levon 	{"genpd_lock_nested",        LOCK,   0},
4215a0e240fSJohn Levon 	{"genpd_lock_interruptible", LOCK,   0},
4225a0e240fSJohn Levon 	{"genpd_unlock",             UNLOCK, 0},
4235a0e240fSJohn Levon };
4241f5207b7SJohn Levon 
4255a0e240fSJohn Levon static const char *false_positives[][2] = {
4265a0e240fSJohn Levon 	{"fs/jffs2/", "->alloc_sem"},
4275a0e240fSJohn Levon 	{"fs/xfs/", "->b_sema"},
4285a0e240fSJohn Levon 	{"mm/", "pvmw->ptl"},
4291f5207b7SJohn Levon };
4301f5207b7SJohn Levon 
4315a0e240fSJohn Levon static struct stree *start_states;
4325a0e240fSJohn Levon static struct stree_stack *saved_stack;
4331f5207b7SJohn Levon 
4345a0e240fSJohn Levon static struct tracker_list *locks;
4355a0e240fSJohn Levon 
reset(struct sm_state * sm,struct expression * mod_expr)4365a0e240fSJohn Levon static void reset(struct sm_state *sm, struct expression *mod_expr)
4375a0e240fSJohn Levon {
4385a0e240fSJohn Levon 	set_state(my_id, sm->name, sm->sym, &start_state);
4391f5207b7SJohn Levon }
4401f5207b7SJohn Levon 
remove_spinlock_check(struct expression * expr)4411f5207b7SJohn Levon static struct expression *remove_spinlock_check(struct expression *expr)
4421f5207b7SJohn Levon {
4431f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
4441f5207b7SJohn Levon 		return expr;
4451f5207b7SJohn Levon 	if (expr->fn->type != EXPR_SYMBOL)
4461f5207b7SJohn Levon 		return expr;
4471f5207b7SJohn Levon 	if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
4481f5207b7SJohn Levon 		return expr;
4491f5207b7SJohn Levon 	expr = get_argument_from_call_expr(expr->args, 0);
4501f5207b7SJohn Levon 	return expr;
4511f5207b7SJohn Levon }
4521f5207b7SJohn Levon 
filter_kernel_args(struct expression * arg)4535a0e240fSJohn Levon static struct expression *filter_kernel_args(struct expression *arg)
4545a0e240fSJohn Levon {
4555a0e240fSJohn Levon 	if (arg->type == EXPR_PREOP && arg->op == '&')
4565a0e240fSJohn Levon 		return strip_expr(arg->unop);
4575a0e240fSJohn Levon 	if (!is_pointer(arg))
4585a0e240fSJohn Levon 		return arg;
4595a0e240fSJohn Levon 	return deref_expression(strip_expr(arg));
4605a0e240fSJohn Levon }
4615a0e240fSJohn Levon 
lock_to_name_sym(struct expression * expr,struct symbol ** sym)4625a0e240fSJohn Levon static char *lock_to_name_sym(struct expression *expr, struct symbol **sym)
4635a0e240fSJohn Levon {
4645a0e240fSJohn Levon 	expr = remove_spinlock_check(expr);
4655a0e240fSJohn Levon 	expr = filter_kernel_args(expr);
4665a0e240fSJohn Levon 	return expr_to_str_sym(expr, sym);
4675a0e240fSJohn Levon }
4685a0e240fSJohn Levon 
get_full_name(struct expression * expr,int index,struct symbol ** sym)4695a0e240fSJohn Levon static char *get_full_name(struct expression *expr, int index, struct symbol **sym)
4701f5207b7SJohn Levon {
4711f5207b7SJohn Levon 	struct lock_info *lock = &lock_table[index];
4725a0e240fSJohn Levon 	struct expression *arg;
4731f5207b7SJohn Levon 
4745a0e240fSJohn Levon 	*sym = NULL;
4751f5207b7SJohn Levon 	if (lock->arg == RETURN_VAL) {
4765a0e240fSJohn Levon 		return expr_to_var_sym(strip_expr(expr->left), sym);
4771f5207b7SJohn Levon 	} else if (lock->arg == NO_ARG) {
4785a0e240fSJohn Levon 		return alloc_string(get_lock_name(lock->type));
4791f5207b7SJohn Levon 	} else {
4801f5207b7SJohn Levon 		arg = get_argument_from_call_expr(expr->args, lock->arg);
4811f5207b7SJohn Levon 		if (!arg)
4825a0e240fSJohn Levon 			return NULL;
4835a0e240fSJohn Levon 		return lock_to_name_sym(arg, sym);
4841f5207b7SJohn Levon 	}
4851f5207b7SJohn Levon }
4861f5207b7SJohn Levon 
unmatched_state(struct sm_state * sm)4875a0e240fSJohn Levon static struct smatch_state *unmatched_state(struct sm_state *sm)
4885a0e240fSJohn Levon {
4895a0e240fSJohn Levon 	return &start_state;
4905a0e240fSJohn Levon }
4915a0e240fSJohn Levon 
pre_merge_hook(struct sm_state * cur,struct sm_state * other)4925a0e240fSJohn Levon static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
4931f5207b7SJohn Levon {
4945a0e240fSJohn Levon 	if (is_impossible_path())
4955a0e240fSJohn Levon 		set_state(my_id, cur->name, cur->sym, &impossible);
4965a0e240fSJohn Levon }
4971f5207b7SJohn Levon 
merge_func(struct smatch_state * s1,struct smatch_state * s2)4985a0e240fSJohn Levon static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
4995a0e240fSJohn Levon {
5005a0e240fSJohn Levon 	if (s1 == &impossible)
5015a0e240fSJohn Levon 		return s2;
5025a0e240fSJohn Levon 	if (s2 == &impossible)
5035a0e240fSJohn Levon 		return s1;
5045a0e240fSJohn Levon 	return &merged;
5055a0e240fSJohn Levon }
5065a0e240fSJohn Levon 
action_to_state(enum action lock_unlock)5075a0e240fSJohn Levon static struct smatch_state *action_to_state(enum action lock_unlock)
5085a0e240fSJohn Levon {
5095a0e240fSJohn Levon 	switch (lock_unlock) {
5105a0e240fSJohn Levon 	case LOCK:
5111f5207b7SJohn Levon 		return &locked;
5125a0e240fSJohn Levon 	case UNLOCK:
5131f5207b7SJohn Levon 		return &unlocked;
5145a0e240fSJohn Levon 	case RESTORE:
5155a0e240fSJohn Levon 		return &restore;
5165a0e240fSJohn Levon 	}
5175a0e240fSJohn Levon 	return NULL;
5181f5207b7SJohn Levon }
5191f5207b7SJohn Levon 
get_best_match(const char * key,enum action lock_unlock)5205a0e240fSJohn Levon static struct sm_state *get_best_match(const char *key, enum action lock_unlock)
5211f5207b7SJohn Levon {
5225a0e240fSJohn Levon 	struct sm_state *sm;
5235a0e240fSJohn Levon 	struct sm_state *match;
5245a0e240fSJohn Levon 	int cnt = 0;
5255a0e240fSJohn Levon 	int start_pos, state_len, key_len, chunks, i;
5265a0e240fSJohn Levon 
5275a0e240fSJohn Levon 	if (strncmp(key, "$->", 3) == 0)
5285a0e240fSJohn Levon 		key += 3;
5295a0e240fSJohn Levon 
5305a0e240fSJohn Levon 	key_len = strlen(key);
5315a0e240fSJohn Levon 	chunks = 0;
5325a0e240fSJohn Levon 	for (i = key_len - 1; i > 0; i--) {
5335a0e240fSJohn Levon 		if (key[i] == '>' || key[i] == '.')
5345a0e240fSJohn Levon 			chunks++;
5355a0e240fSJohn Levon 		if (chunks == 2) {
5365a0e240fSJohn Levon 			key += (i + 1);
5375a0e240fSJohn Levon 			key_len = strlen(key);
5385a0e240fSJohn Levon 			break;
5395a0e240fSJohn Levon 		}
5405a0e240fSJohn Levon 	}
5415a0e240fSJohn Levon 
5425a0e240fSJohn Levon 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
5435a0e240fSJohn Levon 		if (((lock_unlock == UNLOCK || lock_unlock == RESTORE) &&
5445a0e240fSJohn Levon 		     sm->state != &locked) ||
5455a0e240fSJohn Levon 		    (lock_unlock == LOCK && sm->state != &unlocked))
5465a0e240fSJohn Levon 			continue;
5475a0e240fSJohn Levon 		state_len = strlen(sm->name);
5485a0e240fSJohn Levon 		if (state_len < key_len)
5495a0e240fSJohn Levon 			continue;
5505a0e240fSJohn Levon 		start_pos = state_len - key_len;
5515a0e240fSJohn Levon 		if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
5525a0e240fSJohn Levon 		    strcmp(sm->name + start_pos, key) == 0) {
5535a0e240fSJohn Levon 			cnt++;
5545a0e240fSJohn Levon 			match = sm;
5555a0e240fSJohn Levon 		}
5565a0e240fSJohn Levon 	} END_FOR_EACH_SM(sm);
5575a0e240fSJohn Levon 
5585a0e240fSJohn Levon 	if (cnt == 1)
5595a0e240fSJohn Levon 		return match;
5605a0e240fSJohn Levon 	return NULL;
5611f5207b7SJohn Levon }
5621f5207b7SJohn Levon 
use_best_match(char * key,enum action lock_unlock)5635a0e240fSJohn Levon static void use_best_match(char *key, enum action lock_unlock)
5641f5207b7SJohn Levon {
5655a0e240fSJohn Levon 	struct sm_state *match;
5665a0e240fSJohn Levon 
5675a0e240fSJohn Levon 	match = get_best_match(key, lock_unlock);
5685a0e240fSJohn Levon 	if (match)
5695a0e240fSJohn Levon 		set_state(my_id, match->name, match->sym, action_to_state(lock_unlock));
5705a0e240fSJohn Levon 	else
5715a0e240fSJohn Levon 		set_state(my_id, key, NULL, action_to_state(lock_unlock));
5721f5207b7SJohn Levon }
5731f5207b7SJohn Levon 
set_start_state(const char * name,struct symbol * sym,struct smatch_state * start)5745a0e240fSJohn Levon static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
575efe51d0cSJohn Levon {
5765a0e240fSJohn Levon 	struct smatch_state *orig;
5775a0e240fSJohn Levon 
5785a0e240fSJohn Levon 	orig = get_state_stree(start_states, my_id, name, sym);
5795a0e240fSJohn Levon 	if (!orig)
5805a0e240fSJohn Levon 		set_state_stree(&start_states, my_id, name, sym, start);
5815a0e240fSJohn Levon 	else if (orig != start)
5825a0e240fSJohn Levon 		set_state_stree(&start_states, my_id, name, sym, &undefined);
5835a0e240fSJohn Levon }
5845a0e240fSJohn Levon 
common_false_positive(const char * name)5855a0e240fSJohn Levon static bool common_false_positive(const char *name)
5865a0e240fSJohn Levon {
5875a0e240fSJohn Levon 	const char *path, *lname;
5885a0e240fSJohn Levon 	int i, len_total, len_path, len_name, skip;
5895a0e240fSJohn Levon 
5905a0e240fSJohn Levon 	if (!get_filename())
5915a0e240fSJohn Levon 		return false;
5925a0e240fSJohn Levon 
5935a0e240fSJohn Levon 	len_total = strlen(name);
5945a0e240fSJohn Levon 	for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
5955a0e240fSJohn Levon 		path = false_positives[i][0];
5965a0e240fSJohn Levon 		lname = false_positives[i][1];
5975a0e240fSJohn Levon 
5985a0e240fSJohn Levon 		len_path = strlen(path);
5995a0e240fSJohn Levon 		len_name = strlen(lname);
6005a0e240fSJohn Levon 
6015a0e240fSJohn Levon 		if (len_name > len_total)
6025a0e240fSJohn Levon 			continue;
6035a0e240fSJohn Levon 		skip = len_total - len_name;
6045a0e240fSJohn Levon 
6055a0e240fSJohn Levon 		if (strncmp(get_filename(), path, len_path) == 0 &&
6065a0e240fSJohn Levon 		    strcmp(name + skip, lname) == 0)
6075a0e240fSJohn Levon 			return true;
6085a0e240fSJohn Levon 	}
6095a0e240fSJohn Levon 
610efe51d0cSJohn Levon 	return false;
611efe51d0cSJohn Levon }
612efe51d0cSJohn Levon 
warn_on_double(struct sm_state * sm,struct smatch_state * state)6135a0e240fSJohn Levon static void warn_on_double(struct sm_state *sm, struct smatch_state *state)
6141f5207b7SJohn Levon {
6155a0e240fSJohn Levon 	struct sm_state *tmp;
6161f5207b7SJohn Levon 
6175a0e240fSJohn Levon 	if (!sm)
6181f5207b7SJohn Levon 		return;
6191f5207b7SJohn Levon 
6205a0e240fSJohn Levon 	FOR_EACH_PTR(sm->possible, tmp) {
6215a0e240fSJohn Levon 		if (tmp->state == state)
6225a0e240fSJohn Levon 			goto found;
6235a0e240fSJohn Levon 	} END_FOR_EACH_PTR(tmp);
6245a0e240fSJohn Levon 
6255a0e240fSJohn Levon 	return;
6265a0e240fSJohn Levon found:
6275a0e240fSJohn Levon 	if (strcmp(sm->name, "bottom_half") == 0)
6285a0e240fSJohn Levon 		return;
6295a0e240fSJohn Levon 	if (common_false_positive(sm->name))
6305a0e240fSJohn Levon 		return;
6315a0e240fSJohn Levon 	sm_msg("error: double %s '%s' (orig line %u)",
6325a0e240fSJohn Levon 	       state->name, sm->name, tmp->line);
6331f5207b7SJohn Levon }
6341f5207b7SJohn Levon 
handle_macro_lock_unlock(void)6355a0e240fSJohn Levon static bool handle_macro_lock_unlock(void)
6361f5207b7SJohn Levon {
6375a0e240fSJohn Levon 	struct expression *expr, *arg;
6385a0e240fSJohn Levon 	struct macro_info *info;
6391f5207b7SJohn Levon 	struct sm_state *sm;
6405a0e240fSJohn Levon 	struct symbol *sym;
6415a0e240fSJohn Levon 	const char *macro;
6425a0e240fSJohn Levon 	char *name;
6435a0e240fSJohn Levon 	bool ret = false;
6445a0e240fSJohn Levon 	int i;
6451f5207b7SJohn Levon 
6465a0e240fSJohn Levon 	expr = last_ptr_list((struct ptr_list *)big_expression_stack);
6475a0e240fSJohn Levon 	while (expr && expr->type == EXPR_ASSIGNMENT)
6485a0e240fSJohn Levon 		expr = strip_expr(expr->right);
6495a0e240fSJohn Levon 	if (!expr || expr->type != EXPR_CALL)
6505a0e240fSJohn Levon 		return false;
6515a0e240fSJohn Levon 
6525a0e240fSJohn Levon 	macro = get_macro_name(expr->pos);
6535a0e240fSJohn Levon 	if (!macro)
6545a0e240fSJohn Levon 		return false;
6555a0e240fSJohn Levon 
6565a0e240fSJohn Levon 	for (i = 0; i < ARRAY_SIZE(macro_table); i++) {
6575a0e240fSJohn Levon 		info = &macro_table[i];
6585a0e240fSJohn Levon 
6595a0e240fSJohn Levon 		if (strcmp(macro, info->macro) != 0)
6605a0e240fSJohn Levon 			continue;
6615a0e240fSJohn Levon 		arg = get_argument_from_call_expr(expr->args, info->param);
6625a0e240fSJohn Levon 		name = expr_to_str_sym(arg, &sym);
6635a0e240fSJohn Levon 		if (!name || !sym)
6645a0e240fSJohn Levon 			goto free;
6655a0e240fSJohn Levon 		sm = get_sm_state(my_id, name, sym);
6665a0e240fSJohn Levon 
6675a0e240fSJohn Levon 		if (info->action == LOCK) {
6685a0e240fSJohn Levon 			if (!sm)
6695a0e240fSJohn Levon 				set_start_state(name, sym, &unlocked);
6705a0e240fSJohn Levon 			if (sm && sm->line != expr->pos.line)
6715a0e240fSJohn Levon 				warn_on_double(sm, &locked);
6725a0e240fSJohn Levon 			set_state(my_id, name, sym, &locked);
6735a0e240fSJohn Levon 		} else {
6745a0e240fSJohn Levon 			if (!sm)
6755a0e240fSJohn Levon 				set_start_state(name, sym, &locked);
6765a0e240fSJohn Levon 			if (sm && sm->line != expr->pos.line)
6775a0e240fSJohn Levon 				warn_on_double(sm, &unlocked);
6785a0e240fSJohn Levon 			set_state(my_id, name, sym, &unlocked);
6795a0e240fSJohn Levon 		}
6805a0e240fSJohn Levon 		ret = true;
6815a0e240fSJohn Levon free:
6825a0e240fSJohn Levon 		free_string(name);
6835a0e240fSJohn Levon 		return ret;
6845a0e240fSJohn Levon 	}
6855a0e240fSJohn Levon 	return false;
6865a0e240fSJohn Levon }
6875a0e240fSJohn Levon 
do_lock(const char * name,struct symbol * sym,struct lock_info * info)6885a0e240fSJohn Levon static void do_lock(const char *name, struct symbol *sym, struct lock_info *info)
6895a0e240fSJohn Levon {
6905a0e240fSJohn Levon 	struct sm_state *sm;
6915a0e240fSJohn Levon 
6925a0e240fSJohn Levon 	if (handle_macro_lock_unlock())
6931f5207b7SJohn Levon 		return;
6941f5207b7SJohn Levon 
6955a0e240fSJohn Levon 	add_tracker(&locks, my_id, name, sym);
6965a0e240fSJohn Levon 
6975a0e240fSJohn Levon 	sm = get_sm_state(my_id, name, sym);
6981f5207b7SJohn Levon 	if (!sm)
6995a0e240fSJohn Levon 		set_start_state(name, sym, &unlocked);
7005a0e240fSJohn Levon 	warn_on_double(sm, &locked);
7015a0e240fSJohn Levon 	set_state(my_id, name, sym, &locked);
7025a0e240fSJohn Levon }
7035a0e240fSJohn Levon 
do_lock_failed(const char * name,struct symbol * sym)7045a0e240fSJohn Levon static void do_lock_failed(const char *name, struct symbol *sym)
7055a0e240fSJohn Levon {
7065a0e240fSJohn Levon 	add_tracker(&locks, my_id, name, sym);
7075a0e240fSJohn Levon 	set_state(my_id, name, sym, &unlocked);
7081f5207b7SJohn Levon }
7091f5207b7SJohn Levon 
do_unlock(const char * name,struct symbol * sym,struct lock_info * info)7105a0e240fSJohn Levon static void do_unlock(const char *name, struct symbol *sym, struct lock_info *info)
7111f5207b7SJohn Levon {
7121f5207b7SJohn Levon 	struct sm_state *sm;
7131f5207b7SJohn Levon 
7141f5207b7SJohn Levon 	if (__path_is_null())
7151f5207b7SJohn Levon 		return;
7165a0e240fSJohn Levon 
7175a0e240fSJohn Levon 	if (handle_macro_lock_unlock())
7185a0e240fSJohn Levon 		return;
7195a0e240fSJohn Levon 
7205a0e240fSJohn Levon 	add_tracker(&locks, my_id, name, sym);
7215a0e240fSJohn Levon 	sm = get_sm_state(my_id, name, sym);
7225a0e240fSJohn Levon 	if (!sm) {
7235a0e240fSJohn Levon 		sm = get_best_match(name, UNLOCK);
7245a0e240fSJohn Levon 		if (sm) {
7255a0e240fSJohn Levon 			name = sm->name;
7265a0e240fSJohn Levon 			sym = sm->sym;
7275a0e240fSJohn Levon 		}
7285a0e240fSJohn Levon 	}
7291f5207b7SJohn Levon 	if (!sm)
7305a0e240fSJohn Levon 		set_start_state(name, sym, &locked);
7315a0e240fSJohn Levon 	warn_on_double(sm, &unlocked);
7325a0e240fSJohn Levon 	set_state(my_id, name, sym, &unlocked);
7335a0e240fSJohn Levon }
7345a0e240fSJohn Levon 
do_restore(const char * name,struct symbol * sym,struct lock_info * info)7355a0e240fSJohn Levon static void do_restore(const char *name, struct symbol *sym, struct lock_info *info)
7365a0e240fSJohn Levon {
7375a0e240fSJohn Levon 	if (__path_is_null())
7385a0e240fSJohn Levon 		return;
7395a0e240fSJohn Levon 
7405a0e240fSJohn Levon 	if (!get_state(my_id, name, sym))
7415a0e240fSJohn Levon 		set_start_state(name, sym, &locked);
7425a0e240fSJohn Levon 
7435a0e240fSJohn Levon 	add_tracker(&locks, my_id, name, sym);
7445a0e240fSJohn Levon 	set_state(my_id, name, sym, &restore);
7451f5207b7SJohn Levon }
7461f5207b7SJohn Levon 
match_lock_held(const char * fn,struct expression * call_expr,struct expression * assign_expr,void * _index)7471f5207b7SJohn Levon static void match_lock_held(const char *fn, struct expression *call_expr,
7485a0e240fSJohn Levon 			    struct expression *assign_expr, void *_index)
7491f5207b7SJohn Levon {
7501f5207b7SJohn Levon 	int index = PTR_INT(_index);
7511f5207b7SJohn Levon 	struct lock_info *lock = &lock_table[index];
7525a0e240fSJohn Levon 	char *lock_name;
7535a0e240fSJohn Levon 	struct symbol *sym;
7541f5207b7SJohn Levon 
7551f5207b7SJohn Levon 	if (lock->arg == NO_ARG) {
7565a0e240fSJohn Levon 		lock_name = get_full_name(NULL, index, &sym);
7571f5207b7SJohn Levon 	} else if (lock->arg == RETURN_VAL) {
7581f5207b7SJohn Levon 		if (!assign_expr)
7591f5207b7SJohn Levon 			return;
7605a0e240fSJohn Levon 		lock_name = get_full_name(assign_expr, index, &sym);
7611f5207b7SJohn Levon 	} else {
7625a0e240fSJohn Levon 		lock_name = get_full_name(call_expr, index, &sym);
7631f5207b7SJohn Levon 	}
7641f5207b7SJohn Levon 	if (!lock_name)
7651f5207b7SJohn Levon 		return;
7665a0e240fSJohn Levon 	do_lock(lock_name, sym, lock);
7671f5207b7SJohn Levon 	free_string(lock_name);
7681f5207b7SJohn Levon }
7691f5207b7SJohn Levon 
match_lock_failed(const char * fn,struct expression * call_expr,struct expression * assign_expr,void * _index)7701f5207b7SJohn Levon static void match_lock_failed(const char *fn, struct expression *call_expr,
7711f5207b7SJohn Levon 			struct expression *assign_expr, void *_index)
7721f5207b7SJohn Levon {
7731f5207b7SJohn Levon 	int index = PTR_INT(_index);
7741f5207b7SJohn Levon 	struct lock_info *lock = &lock_table[index];
7755a0e240fSJohn Levon 	char *lock_name;
7765a0e240fSJohn Levon 	struct symbol *sym;
7771f5207b7SJohn Levon 
7781f5207b7SJohn Levon 	if (lock->arg == NO_ARG) {
7795a0e240fSJohn Levon 		lock_name = get_full_name(NULL, index, &sym);
7801f5207b7SJohn Levon 	} else if (lock->arg == RETURN_VAL) {
7811f5207b7SJohn Levon 		if (!assign_expr)
7821f5207b7SJohn Levon 			return;
7835a0e240fSJohn Levon 		lock_name = get_full_name(assign_expr, index, &sym);
7841f5207b7SJohn Levon 	} else {
7855a0e240fSJohn Levon 		lock_name = get_full_name(call_expr, index, &sym);
7861f5207b7SJohn Levon 	}
7871f5207b7SJohn Levon 	if (!lock_name)
7881f5207b7SJohn Levon 		return;
7895a0e240fSJohn Levon 	do_lock_failed(lock_name, sym);
7901f5207b7SJohn Levon 	free_string(lock_name);
7911f5207b7SJohn Levon }
7921f5207b7SJohn Levon 
match_returns_locked(const char * fn,struct expression * expr,void * _index)7931f5207b7SJohn Levon static void match_returns_locked(const char *fn, struct expression *expr,
7941f5207b7SJohn Levon 				      void *_index)
7951f5207b7SJohn Levon {
7961f5207b7SJohn Levon 	int index = PTR_INT(_index);
7971f5207b7SJohn Levon 	struct lock_info *lock = &lock_table[index];
7985a0e240fSJohn Levon 	char *full_name;
7995a0e240fSJohn Levon 	struct symbol *sym;
8001f5207b7SJohn Levon 
8011f5207b7SJohn Levon 	if (lock->arg != RETURN_VAL)
8021f5207b7SJohn Levon 		return;
8035a0e240fSJohn Levon 	full_name = get_full_name(expr, index, &sym);
8045a0e240fSJohn Levon 	if (!full_name)
8055a0e240fSJohn Levon 		return;
8065a0e240fSJohn Levon 	do_lock(full_name, sym, lock);
8071f5207b7SJohn Levon }
8081f5207b7SJohn Levon 
match_lock_unlock(const char * fn,struct expression * expr,void * _index)8091f5207b7SJohn Levon static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
8101f5207b7SJohn Levon {
8111f5207b7SJohn Levon 	int index = PTR_INT(_index);
8121f5207b7SJohn Levon 	struct lock_info *lock = &lock_table[index];
8135a0e240fSJohn Levon 	char *full_name;
8145a0e240fSJohn Levon 	struct symbol *sym;
8151f5207b7SJohn Levon 
8165a0e240fSJohn Levon 	full_name = get_full_name(expr, index, &sym);
8171f5207b7SJohn Levon 	if (!full_name)
8181f5207b7SJohn Levon 		return;
8195a0e240fSJohn Levon 	switch (lock->action) {
8205a0e240fSJohn Levon 	case LOCK:
8215a0e240fSJohn Levon 		do_lock(full_name, sym, lock);
8225a0e240fSJohn Levon 		break;
8235a0e240fSJohn Levon 	case UNLOCK:
8245a0e240fSJohn Levon 		do_unlock(full_name, sym, lock);
8255a0e240fSJohn Levon 		break;
8265a0e240fSJohn Levon 	case RESTORE:
8275a0e240fSJohn Levon 		do_restore(full_name, sym, lock);
8285a0e240fSJohn Levon 		break;
8295a0e240fSJohn Levon 	}
8301f5207b7SJohn Levon 	free_string(full_name);
8311f5207b7SJohn Levon }
8321f5207b7SJohn Levon 
get_start_state(struct sm_state * sm)8335a0e240fSJohn Levon static struct smatch_state *get_start_state(struct sm_state *sm)
8341f5207b7SJohn Levon {
8355a0e240fSJohn Levon 	struct smatch_state *orig;
8361f5207b7SJohn Levon 
8375a0e240fSJohn Levon 	orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
8385a0e240fSJohn Levon 	if (orig)
8395a0e240fSJohn Levon 		return orig;
8405a0e240fSJohn Levon 	return &undefined;
8411f5207b7SJohn Levon }
8421f5207b7SJohn Levon 
get_param_lock_name(struct sm_state * sm,struct expression * expr,const char ** name)8435a0e240fSJohn Levon static int get_param_lock_name(struct sm_state *sm, struct expression *expr,
8445a0e240fSJohn Levon 			       const char **name)
8451f5207b7SJohn Levon {
8465a0e240fSJohn Levon 	char *other_name;
8475a0e240fSJohn Levon 	struct symbol *other_sym;
8485a0e240fSJohn Levon 	const char *param_name;
8495a0e240fSJohn Levon 	int param;
8505a0e240fSJohn Levon 
8515a0e240fSJohn Levon 	*name = sm->name;
8525a0e240fSJohn Levon 
8535a0e240fSJohn Levon 	param = get_param_num_from_sym(sm->sym);
8545a0e240fSJohn Levon 	if (param >= 0) {
8555a0e240fSJohn Levon 		param_name = get_param_name(sm);
8565a0e240fSJohn Levon 		if (param_name)
8575a0e240fSJohn Levon 			*name = param_name;
8585a0e240fSJohn Levon 		return param;
8595a0e240fSJohn Levon 	}
8601f5207b7SJohn Levon 
8615a0e240fSJohn Levon 	if (expr) {
8625a0e240fSJohn Levon 		struct symbol *ret_sym;
8635a0e240fSJohn Levon 		char *ret_str;
8645a0e240fSJohn Levon 
8655a0e240fSJohn Levon 		ret_str = expr_to_str_sym(expr, &ret_sym);
8665a0e240fSJohn Levon 		if (ret_str && ret_sym == sm->sym) {
8675a0e240fSJohn Levon 			param_name = state_name_to_param_name(sm->name, ret_str);
8685a0e240fSJohn Levon 			if (param_name) {
8695a0e240fSJohn Levon 				free_string(ret_str);
8705a0e240fSJohn Levon 				*name = param_name;
8715a0e240fSJohn Levon 				return -1;
8725a0e240fSJohn Levon 			}
8731f5207b7SJohn Levon 		}
8745a0e240fSJohn Levon 		free_string(ret_str);
8751f5207b7SJohn Levon 	}
8761f5207b7SJohn Levon 
8775a0e240fSJohn Levon 	other_name = get_other_name_sym(sm->name, sm->sym, &other_sym);
8785a0e240fSJohn Levon 	if (!other_name)
8795a0e240fSJohn Levon 		return -2;
8805a0e240fSJohn Levon 	param = get_param_num_from_sym(other_sym);
8815a0e240fSJohn Levon 	if (param < 0)
8825a0e240fSJohn Levon 		return -2;
8835a0e240fSJohn Levon 
8845a0e240fSJohn Levon 	param_name = get_param_name_var_sym(other_name, other_sym);
8855a0e240fSJohn Levon 	free_string(other_name);
8865a0e240fSJohn Levon 	if (param_name)
8875a0e240fSJohn Levon 		*name = param_name;
8885a0e240fSJohn Levon 	return param;
8895a0e240fSJohn Levon }
8901f5207b7SJohn Levon 
get_db_type(struct sm_state * sm)8915a0e240fSJohn Levon static int get_db_type(struct sm_state *sm)
8921f5207b7SJohn Levon {
8935a0e240fSJohn Levon 	if (sm->state == get_start_state(sm)) {
8945a0e240fSJohn Levon 		if (sm->state == &locked)
8955a0e240fSJohn Levon 			return KNOWN_LOCKED;
8965a0e240fSJohn Levon 		if (sm->state == &unlocked)
8975a0e240fSJohn Levon 			return KNOWN_UNLOCKED;
8985a0e240fSJohn Levon 	}
8991f5207b7SJohn Levon 
9005a0e240fSJohn Levon 	if (sm->state == &locked)
9015a0e240fSJohn Levon 		return LOCKED;
9025a0e240fSJohn Levon 	if (sm->state == &unlocked)
9035a0e240fSJohn Levon 		return UNLOCKED;
9045a0e240fSJohn Levon 	if (sm->state == &restore)
9055a0e240fSJohn Levon 		return LOCK_RESTORED;
9065a0e240fSJohn Levon 	return LOCKED;
9075a0e240fSJohn Levon }
9081f5207b7SJohn Levon 
match_return_info(int return_id,char * return_ranges,struct expression * expr)9095a0e240fSJohn Levon static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
9105a0e240fSJohn Levon {
9115a0e240fSJohn Levon 	struct sm_state *sm;
9125a0e240fSJohn Levon 	const char *param_name;
9135a0e240fSJohn Levon 	int param;
9141f5207b7SJohn Levon 
9155a0e240fSJohn Levon 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
9165a0e240fSJohn Levon 		if (sm->state != &locked &&
9175a0e240fSJohn Levon 		    sm->state != &unlocked &&
9185a0e240fSJohn Levon 		    sm->state != &restore)
9195a0e240fSJohn Levon 			continue;
9201f5207b7SJohn Levon 
9215a0e240fSJohn Levon 		param = get_param_lock_name(sm, expr, &param_name);
9225a0e240fSJohn Levon 		sql_insert_return_states(return_id, return_ranges,
9235a0e240fSJohn Levon 					 get_db_type(sm),
9245a0e240fSJohn Levon 					 param, param_name, "");
9255a0e240fSJohn Levon 	} END_FOR_EACH_SM(sm);
9261f5207b7SJohn Levon }
9271f5207b7SJohn Levon 
9285a0e240fSJohn Levon enum {
9295a0e240fSJohn Levon 	ERR_PTR, VALID_PTR, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS,
9305a0e240fSJohn Levon };
9315a0e240fSJohn Levon 
is_EINTR(struct range_list * rl)9325a0e240fSJohn Levon static bool is_EINTR(struct range_list *rl)
9331f5207b7SJohn Levon {
9345a0e240fSJohn Levon 	sval_t sval;
9351f5207b7SJohn Levon 
9365a0e240fSJohn Levon 	if (!rl_to_sval(rl, &sval))
9375a0e240fSJohn Levon 		return false;
9385a0e240fSJohn Levon 	return sval.value == -4;
9391f5207b7SJohn Levon }
9401f5207b7SJohn Levon 
success_fail_positive(struct range_list * rl)9415a0e240fSJohn Levon static int success_fail_positive(struct range_list *rl)
9421f5207b7SJohn Levon {
9435a0e240fSJohn Levon 	/* void returns are the same as success (zero in the kernel) */
9445a0e240fSJohn Levon 	if (!rl)
9455a0e240fSJohn Levon 		return ZERO;
9465a0e240fSJohn Levon 
9475a0e240fSJohn Levon 	if (rl_type(rl)->type != SYM_PTR && sval_is_negative(rl_min(rl)))
9485a0e240fSJohn Levon 		return NEGATIVE;
9495a0e240fSJohn Levon 
9505a0e240fSJohn Levon 	if (rl_min(rl).value == 0 && rl_max(rl).value == 0)
9515a0e240fSJohn Levon 		return ZERO;
9525a0e240fSJohn Levon 
9535a0e240fSJohn Levon 	if (is_err_ptr(rl_min(rl)) &&
9545a0e240fSJohn Levon 	    is_err_ptr(rl_max(rl)))
9555a0e240fSJohn Levon 		return ERR_PTR;
9565a0e240fSJohn Levon 
9575a0e240fSJohn Levon 	/*
9585a0e240fSJohn Levon 	 * Trying to match ERR_PTR(ret) but without the expression struct.
9595a0e240fSJohn Levon 	 * Ugly...
9605a0e240fSJohn Levon 	 */
9615a0e240fSJohn Levon 	if (type_bits(&long_ctype) == 64 &&
9625a0e240fSJohn Levon 	    rl_type(rl)->type == SYM_PTR &&
9635a0e240fSJohn Levon 	    rl_min(rl).value == INT_MIN)
9645a0e240fSJohn Levon 		return ERR_PTR;
9655a0e240fSJohn Levon 
9665a0e240fSJohn Levon 	return POSITIVE;
9675a0e240fSJohn Levon }
9685a0e240fSJohn Levon 
sym_in_lock_table(struct symbol * sym)9695a0e240fSJohn Levon static bool sym_in_lock_table(struct symbol *sym)
9705a0e240fSJohn Levon {
9715a0e240fSJohn Levon 	int i;
9721f5207b7SJohn Levon 
9735a0e240fSJohn Levon 	if (!sym || !sym->ident)
9745a0e240fSJohn Levon 		return false;
9755a0e240fSJohn Levon 
9765a0e240fSJohn Levon 	for (i = 0; lock_table[i].function != NULL; i++) {
9775a0e240fSJohn Levon 		if (strcmp(lock_table[i].function, sym->ident->name) == 0)
9785a0e240fSJohn Levon 			return true;
9795a0e240fSJohn Levon 	}
9805a0e240fSJohn Levon 	return false;
9811f5207b7SJohn Levon }
9821f5207b7SJohn Levon 
func_in_lock_table(struct expression * expr)9835a0e240fSJohn Levon static bool func_in_lock_table(struct expression *expr)
9841f5207b7SJohn Levon {
9855a0e240fSJohn Levon 	if (expr->type != EXPR_SYMBOL)
9865a0e240fSJohn Levon 		return false;
9875a0e240fSJohn Levon 	return sym_in_lock_table(expr->symbol);
9885a0e240fSJohn Levon }
9895a0e240fSJohn Levon 
check_lock(char * name,struct symbol * sym)9905a0e240fSJohn Levon static void check_lock(char *name, struct symbol *sym)
9915a0e240fSJohn Levon {
9925a0e240fSJohn Levon 	struct range_list *locked_lines = NULL;
9935a0e240fSJohn Levon 	struct range_list *unlocked_lines = NULL;
9945a0e240fSJohn Levon 	int locked_buckets[NUM_BUCKETS] = {};
9955a0e240fSJohn Levon 	int unlocked_buckets[NUM_BUCKETS] = {};
9965a0e240fSJohn Levon 	struct stree *stree, *orig;
9975a0e240fSJohn Levon 	struct sm_state *return_sm;
9985a0e240fSJohn Levon 	struct sm_state *sm;
9995a0e240fSJohn Levon 	sval_t line = sval_type_val(&int_ctype, 0);
10005a0e240fSJohn Levon 	int bucket;
10011f5207b7SJohn Levon 	int i;
10021f5207b7SJohn Levon 
10035a0e240fSJohn Levon 	if (sym_in_lock_table(cur_func_sym))
10045a0e240fSJohn Levon 		return;
10051f5207b7SJohn Levon 
10065a0e240fSJohn Levon 	FOR_EACH_PTR(get_all_return_strees(), stree) {
10075a0e240fSJohn Levon 		orig = __swap_cur_stree(stree);
10081f5207b7SJohn Levon 
10095a0e240fSJohn Levon 		if (is_impossible_path())
10105a0e240fSJohn Levon 			goto swap_stree;
10115a0e240fSJohn Levon 
10125a0e240fSJohn Levon 		return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
10135a0e240fSJohn Levon 		if (!return_sm)
10145a0e240fSJohn Levon 			goto swap_stree;
10155a0e240fSJohn Levon 		line.value = return_sm->line;
10165a0e240fSJohn Levon 
10175a0e240fSJohn Levon 		sm = get_sm_state(my_id, name, sym);
10185a0e240fSJohn Levon 		if (!sm)
10195a0e240fSJohn Levon 			goto swap_stree;
10205a0e240fSJohn Levon 
10215a0e240fSJohn Levon 		if (parent_is_gone_var_sym(sm->name, sm->sym))
10225a0e240fSJohn Levon 			goto swap_stree;
10235a0e240fSJohn Levon 
1024*31ad075eSJohn Levon 		if (sm->state != &locked &&
1025*31ad075eSJohn Levon 		    sm->state != &unlocked &&
1026*31ad075eSJohn Levon 		    sm->state != &restore)
10275a0e240fSJohn Levon 			goto swap_stree;
10285a0e240fSJohn Levon 
1029*31ad075eSJohn Levon 		if ((sm->state == &unlocked || sm->state == &restore) &&
1030*31ad075eSJohn Levon 		    is_EINTR(estate_rl(return_sm->state)))
10315a0e240fSJohn Levon 			goto swap_stree;
10325a0e240fSJohn Levon 
10335a0e240fSJohn Levon 		bucket = success_fail_positive(estate_rl(return_sm->state));
10345a0e240fSJohn Levon 		if (sm->state == &locked) {
10355a0e240fSJohn Levon 			add_range(&locked_lines, line, line);
10365a0e240fSJohn Levon 			locked_buckets[bucket] = true;
10371f5207b7SJohn Levon 		}
1038*31ad075eSJohn Levon 		if (sm->state == &unlocked || sm->state == &restore) {
10395a0e240fSJohn Levon 			add_range(&unlocked_lines, line, line);
10405a0e240fSJohn Levon 			unlocked_buckets[bucket] = true;
10411f5207b7SJohn Levon 		}
10425a0e240fSJohn Levon swap_stree:
10435a0e240fSJohn Levon 		__swap_cur_stree(orig);
10445a0e240fSJohn Levon 	} END_FOR_EACH_PTR(stree);
10451f5207b7SJohn Levon 
10461f5207b7SJohn Levon 
10475a0e240fSJohn Levon 	if (!locked_lines || !unlocked_lines)
10485a0e240fSJohn Levon 		return;
10491f5207b7SJohn Levon 
10505a0e240fSJohn Levon 	for (i = 0; i < NUM_BUCKETS; i++) {
10515a0e240fSJohn Levon 		if (locked_buckets[i] && unlocked_buckets[i])
10525a0e240fSJohn Levon 			goto complain;
10531f5207b7SJohn Levon 	}
10545a0e240fSJohn Levon 	if (locked_buckets[NEGATIVE] &&
10555a0e240fSJohn Levon 	    (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE]))
10565a0e240fSJohn Levon 		goto complain;
10571f5207b7SJohn Levon 
10585a0e240fSJohn Levon 	if (locked_buckets[ERR_PTR])
10595a0e240fSJohn Levon 		goto complain;
10601f5207b7SJohn Levon 
10615a0e240fSJohn Levon 	return;
10625a0e240fSJohn Levon 
10635a0e240fSJohn Levon complain:
10645a0e240fSJohn Levon 	sm_msg("warn: inconsistent returns '%s'.", name);
10655a0e240fSJohn Levon 	sm_printf("  Locked on  : %s\n", show_rl(locked_lines));
10665a0e240fSJohn Levon 	sm_printf("  Unlocked on: %s\n", show_rl(unlocked_lines));
10671f5207b7SJohn Levon }
10681f5207b7SJohn Levon 
match_func_end(struct symbol * sym)10695a0e240fSJohn Levon static void match_func_end(struct symbol *sym)
10701f5207b7SJohn Levon {
10715a0e240fSJohn Levon 	struct tracker *tracker;
10721f5207b7SJohn Levon 
10735a0e240fSJohn Levon 	FOR_EACH_PTR(locks, tracker) {
10745a0e240fSJohn Levon 		check_lock(tracker->name, tracker->sym);
10755a0e240fSJohn Levon 	} END_FOR_EACH_PTR(tracker);
10761f5207b7SJohn Levon }
10771f5207b7SJohn Levon 
register_lock(int index)10785a0e240fSJohn Levon static void register_lock(int index)
10791f5207b7SJohn Levon {
10805a0e240fSJohn Levon 	struct lock_info *lock = &lock_table[index];
10815a0e240fSJohn Levon 	void *idx = INT_PTR(index);
10821f5207b7SJohn Levon 
10835a0e240fSJohn Levon 	if (lock->return_type == ret_one) {
10845a0e240fSJohn Levon 		return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
10855a0e240fSJohn Levon 		return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
10865a0e240fSJohn Levon 	} else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
10875a0e240fSJohn Levon 		add_function_assign_hook(lock->function, &match_returns_locked, idx);
10885a0e240fSJohn Levon 	} else if (lock->return_type == ret_any) {
10895a0e240fSJohn Levon 		add_function_hook(lock->function, &match_lock_unlock, idx);
10905a0e240fSJohn Levon 	} else if (lock->return_type == ret_zero) {
10915a0e240fSJohn Levon 		return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
10925a0e240fSJohn Levon 		return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
10935a0e240fSJohn Levon 	} else if (lock->return_type == ret_valid_ptr) {
10945a0e240fSJohn Levon 		return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx);
10955a0e240fSJohn Levon 	}
10961f5207b7SJohn Levon }
10971f5207b7SJohn Levon 
load_table(struct lock_info * lock_table)10985a0e240fSJohn Levon static void load_table(struct lock_info *lock_table)
10991f5207b7SJohn Levon {
11005a0e240fSJohn Levon 	int i;
11011f5207b7SJohn Levon 
11025a0e240fSJohn Levon 	for (i = 0; lock_table[i].function != NULL; i++) {
11035a0e240fSJohn Levon 		if (lock_table[i].action == LOCK)
11045a0e240fSJohn Levon 			register_lock(i);
11055a0e240fSJohn Levon 		else
11065a0e240fSJohn Levon 			add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
11075a0e240fSJohn Levon 	}
11085a0e240fSJohn Levon }
11091f5207b7SJohn Levon 
db_param_locked_unlocked(struct expression * expr,int param,char * key,char * value,enum action lock_unlock)11105a0e240fSJohn Levon static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock)
11115a0e240fSJohn Levon {
11125a0e240fSJohn Levon 	struct expression *call, *arg;
11135a0e240fSJohn Levon 	char *name;
11145a0e240fSJohn Levon 	struct symbol *sym;
11155a0e240fSJohn Levon 
11165a0e240fSJohn Levon 	call = expr;
11175a0e240fSJohn Levon 	while (call->type == EXPR_ASSIGNMENT)
11185a0e240fSJohn Levon 		call = strip_expr(call->right);
11195a0e240fSJohn Levon 	if (call->type != EXPR_CALL)
11201f5207b7SJohn Levon 		return;
11211f5207b7SJohn Levon 
11225a0e240fSJohn Levon 	if (func_in_lock_table(call->fn))
11231f5207b7SJohn Levon 		return;
11241f5207b7SJohn Levon 
11255a0e240fSJohn Levon 	if (param == -2) {
11265a0e240fSJohn Levon 		use_best_match(key, lock_unlock);
11271f5207b7SJohn Levon 		return;
11285a0e240fSJohn Levon 	}
11291f5207b7SJohn Levon 
11305a0e240fSJohn Levon 	if (param == -1) {
11315a0e240fSJohn Levon 		if (expr->type != EXPR_ASSIGNMENT)
11325a0e240fSJohn Levon 			return;
11335a0e240fSJohn Levon 		name = get_variable_from_key(expr->left, key, &sym);
11345a0e240fSJohn Levon 	} else {
11355a0e240fSJohn Levon 		arg = get_argument_from_call_expr(call->args, param);
11365a0e240fSJohn Levon 		if (!arg)
11371f5207b7SJohn Levon 			return;
11385a0e240fSJohn Levon 
11395a0e240fSJohn Levon 		name = get_variable_from_key(arg, key, &sym);
11401f5207b7SJohn Levon 	}
11415a0e240fSJohn Levon 	if (!name || !sym)
11425a0e240fSJohn Levon 		goto free;
11431f5207b7SJohn Levon 
11445a0e240fSJohn Levon 	if (lock_unlock == LOCK)
11455a0e240fSJohn Levon 		do_lock(name, sym, NULL);
11465a0e240fSJohn Levon 	else if (lock_unlock == UNLOCK)
11475a0e240fSJohn Levon 		do_unlock(name, sym, NULL);
11485a0e240fSJohn Levon 	else if (lock_unlock == RESTORE)
11495a0e240fSJohn Levon 		do_restore(name, sym, NULL);
11505a0e240fSJohn Levon 
11515a0e240fSJohn Levon free:
11525a0e240fSJohn Levon 	free_string(name);
11531f5207b7SJohn Levon }
11541f5207b7SJohn Levon 
db_param_locked(struct expression * expr,int param,char * key,char * value)11555a0e240fSJohn Levon static void db_param_locked(struct expression *expr, int param, char *key, char *value)
11561f5207b7SJohn Levon {
11575a0e240fSJohn Levon 	db_param_locked_unlocked(expr, param, key, value, LOCK);
11581f5207b7SJohn Levon }
11591f5207b7SJohn Levon 
db_param_unlocked(struct expression * expr,int param,char * key,char * value)11605a0e240fSJohn Levon static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
11611f5207b7SJohn Levon {
11625a0e240fSJohn Levon 	db_param_locked_unlocked(expr, param, key, value, UNLOCK);
11635a0e240fSJohn Levon }
11641f5207b7SJohn Levon 
db_param_restore(struct expression * expr,int param,char * key,char * value)11655a0e240fSJohn Levon static void db_param_restore(struct expression *expr, int param, char *key, char *value)
11665a0e240fSJohn Levon {
11675a0e240fSJohn Levon 	db_param_locked_unlocked(expr, param, key, value, RESTORE);
11685a0e240fSJohn Levon }
11691f5207b7SJohn Levon 
get_caller_param_lock_name(struct expression * call,struct sm_state * sm,const char ** name)11705a0e240fSJohn Levon static int get_caller_param_lock_name(struct expression *call, struct sm_state *sm, const char **name)
11715a0e240fSJohn Levon {
11725a0e240fSJohn Levon 	struct expression *arg;
11735a0e240fSJohn Levon 	char *arg_name;
11745a0e240fSJohn Levon 	int param;
11755a0e240fSJohn Levon 
11765a0e240fSJohn Levon 	param = 0;
11775a0e240fSJohn Levon 	FOR_EACH_PTR(call->args, arg) {
11785a0e240fSJohn Levon 		arg_name = sm_to_arg_name(arg, sm);
11795a0e240fSJohn Levon 		if (arg_name) {
11805a0e240fSJohn Levon 			*name = arg_name;
11815a0e240fSJohn Levon 			return param;
11825a0e240fSJohn Levon 		}
11835a0e240fSJohn Levon 		param++;
11845a0e240fSJohn Levon 	} END_FOR_EACH_PTR(arg);
11851f5207b7SJohn Levon 
11865a0e240fSJohn Levon 	*name = sm->name;
11875a0e240fSJohn Levon 	return -2;
11881f5207b7SJohn Levon }
11891f5207b7SJohn Levon 
match_call_info(struct expression * expr)11905a0e240fSJohn Levon static void match_call_info(struct expression *expr)
11911f5207b7SJohn Levon {
11925a0e240fSJohn Levon 	struct sm_state *sm;
11935a0e240fSJohn Levon 	const char *param_name;
11945a0e240fSJohn Levon 	int locked_type;
11955a0e240fSJohn Levon 	int param;
11965a0e240fSJohn Levon 
11975a0e240fSJohn Levon 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
11985a0e240fSJohn Levon 		param = get_caller_param_lock_name(expr, sm, &param_name);
11995a0e240fSJohn Levon 		if (sm->state == &locked)
12005a0e240fSJohn Levon 			locked_type = LOCKED;
12015a0e240fSJohn Levon 		else if (sm->state == &half_locked ||
12025a0e240fSJohn Levon 			 slist_has_state(sm->possible, &locked))
12035a0e240fSJohn Levon 			locked_type = HALF_LOCKED;
12045a0e240fSJohn Levon 		else
12055a0e240fSJohn Levon 			continue;
12065a0e240fSJohn Levon 		sql_insert_caller_info(expr, locked_type, param, param_name, "xxx type");
12071f5207b7SJohn Levon 
12085a0e240fSJohn Levon 	} END_FOR_EACH_SM(sm);
12091f5207b7SJohn Levon }
12101f5207b7SJohn Levon 
match_save_states(struct expression * expr)12115a0e240fSJohn Levon static void match_save_states(struct expression *expr)
12121f5207b7SJohn Levon {
12135a0e240fSJohn Levon 	push_stree(&saved_stack, start_states);
12145a0e240fSJohn Levon 	start_states = NULL;
12151f5207b7SJohn Levon }
12161f5207b7SJohn Levon 
match_restore_states(struct expression * expr)12175a0e240fSJohn Levon static void match_restore_states(struct expression *expr)
12181f5207b7SJohn Levon {
12195a0e240fSJohn Levon 	start_states = pop_stree(&saved_stack);
12205a0e240fSJohn Levon }
12211f5207b7SJohn Levon 
match_after_func(struct symbol * sym)12225a0e240fSJohn Levon static void match_after_func(struct symbol *sym)
12235a0e240fSJohn Levon {
12245a0e240fSJohn Levon 	free_stree(&start_states);
12251f5207b7SJohn Levon }
12261f5207b7SJohn Levon 
match_dma_resv_lock_NULL(const char * fn,struct expression * call_expr,struct expression * assign_expr,void * _index)12275a0e240fSJohn Levon static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr,
12285a0e240fSJohn Levon 				     struct expression *assign_expr, void *_index)
12291f5207b7SJohn Levon {
12305a0e240fSJohn Levon 	struct expression *lock, *ctx;
12315a0e240fSJohn Levon 	char *lock_name;
12325a0e240fSJohn Levon 	struct symbol *sym;
12331f5207b7SJohn Levon 
12345a0e240fSJohn Levon 	lock = get_argument_from_call_expr(call_expr->args, 0);
12355a0e240fSJohn Levon 	ctx = get_argument_from_call_expr(call_expr->args, 1);
12365a0e240fSJohn Levon 	if (!expr_is_zero(ctx))
12375a0e240fSJohn Levon 		return;
12381f5207b7SJohn Levon 
12395a0e240fSJohn Levon 	lock_name = lock_to_name_sym(lock, &sym);
12405a0e240fSJohn Levon 	if (!lock_name || !sym)
12415a0e240fSJohn Levon 		goto free;
12425a0e240fSJohn Levon 	do_lock(lock_name, sym, NULL);
12435a0e240fSJohn Levon free:
12445a0e240fSJohn Levon 	free_string(lock_name);
12451f5207b7SJohn Levon }
12461f5207b7SJohn Levon 
12471f5207b7SJohn Levon /* print_held_locks() is used in check_call_tree.c */
print_held_locks(void)12481f5207b7SJohn Levon void print_held_locks(void)
12491f5207b7SJohn Levon {
12501f5207b7SJohn Levon 	struct stree *stree;
12511f5207b7SJohn Levon 	struct sm_state *sm;
12521f5207b7SJohn Levon 	int i = 0;
12531f5207b7SJohn Levon 
12541f5207b7SJohn Levon 	stree = __get_cur_stree();
12551f5207b7SJohn Levon 	FOR_EACH_MY_SM(my_id, stree, sm) {
12561f5207b7SJohn Levon 		if (sm->state != &locked)
12571f5207b7SJohn Levon 			continue;
12581f5207b7SJohn Levon 		if (i++)
12591f5207b7SJohn Levon 			sm_printf(" ");
12601f5207b7SJohn Levon 		sm_printf("'%s'", sm->name);
12611f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
12621f5207b7SJohn Levon }
12631f5207b7SJohn Levon 
check_locking(int id)12641f5207b7SJohn Levon void check_locking(int id)
12651f5207b7SJohn Levon {
12661f5207b7SJohn Levon 	my_id = id;
12671f5207b7SJohn Levon 
12685a0e240fSJohn Levon 	if (option_project != PROJ_KERNEL)
12691f5207b7SJohn Levon 		return;
12701f5207b7SJohn Levon 
12715a0e240fSJohn Levon 	load_table(lock_table);
12725a0e240fSJohn Levon 
12735a0e240fSJohn Levon 	set_dynamic_states(my_id);
12741f5207b7SJohn Levon 	add_unmatched_state_hook(my_id, &unmatched_state);
12751f5207b7SJohn Levon 	add_pre_merge_hook(my_id, &pre_merge_hook);
12765a0e240fSJohn Levon 	add_merge_hook(my_id, &merge_func);
12775a0e240fSJohn Levon 	add_modification_hook(my_id, &reset);
12785a0e240fSJohn Levon 
12791f5207b7SJohn Levon 	add_hook(&match_func_end, END_FUNC_HOOK);
12805a0e240fSJohn Levon 
12811f5207b7SJohn Levon 	add_hook(&match_after_func, AFTER_FUNC_HOOK);
12825a0e240fSJohn Levon 	add_hook(&match_save_states, INLINE_FN_START);
12835a0e240fSJohn Levon 	add_hook(&match_restore_states, INLINE_FN_END);
12845a0e240fSJohn Levon 
12855a0e240fSJohn Levon 	add_hook(&match_call_info, FUNCTION_CALL_HOOK);
12865a0e240fSJohn Levon 
12875a0e240fSJohn Levon 	add_split_return_callback(match_return_info);
12885a0e240fSJohn Levon 	select_return_states_hook(LOCKED, &db_param_locked);
12895a0e240fSJohn Levon 	select_return_states_hook(UNLOCKED, &db_param_unlocked);
12905a0e240fSJohn Levon 	select_return_states_hook(LOCK_RESTORED, &db_param_restore);
12911f5207b7SJohn Levon 
12925a0e240fSJohn Levon 	return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0);
12931f5207b7SJohn Levon }
1294