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