Print this page
12166 resync smatch to 0.6.1-rc1-il-3
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_locking.c
+++ new/usr/src/tools/smatch/src/check_locking.c
1 1 /*
2 2 * Copyright (C) 2009 Dan Carpenter.
3 + * Copyright (C) 2019 Oracle.
3 4 *
4 5 * This program is free software; you can redistribute it and/or
5 6 * modify it under the terms of the GNU General Public License
6 7 * as published by the Free Software Foundation; either version 2
7 8 * of the License, or (at your option) any later version.
8 9 *
9 10 * This program is distributed in the hope that it will be useful,
10 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 * GNU General Public License for more details.
13 14 *
14 15 * You should have received a copy of the GNU General Public License
15 16 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 17 */
17 18
18 -/*
19 - * This test checks that locks are held the same across all returns.
20 - *
21 - * Of course, some functions are designed to only hold the locks on success.
22 - * Oh well... We can rewrite it later if we want.
23 - *
24 - * The list of wine locking functions came from an earlier script written
25 - * by Michael Stefaniuc.
26 - *
27 - */
28 -
19 +#include <ctype.h>
29 20 #include "parse.h"
30 21 #include "smatch.h"
31 22 #include "smatch_extra.h"
32 23 #include "smatch_slist.h"
33 24
34 25 static int my_id;
35 26
36 -static int func_has_transition;
37 -
38 27 STATE(locked);
28 +STATE(half_locked);
39 29 STATE(start_state);
40 30 STATE(unlocked);
41 31 STATE(impossible);
32 +STATE(restore);
42 33
43 34 enum action {
44 35 LOCK,
45 36 UNLOCK,
37 + RESTORE,
46 38 };
47 39
40 +enum lock_type {
41 + spin_lock,
42 + read_lock,
43 + write_lock,
44 + mutex,
45 + bottom_half,
46 + irq,
47 + sem,
48 + prepare_lock,
49 + enable_lock,
50 +};
51 +
52 +const char *get_lock_name(enum lock_type type)
53 +{
54 + static const char *names[] = {
55 + [spin_lock] = "spin_lock",
56 + [read_lock] = "read_lock",
57 + [write_lock] = "write_lock",
58 + [mutex] = "mutex",
59 + [bottom_half] = "bottom_half",
60 + [irq] = "irq",
61 + [sem] = "sem",
62 + [prepare_lock] = "prepare_lock",
63 + [enable_lock] = "enable_lock",
64 + };
65 +
66 + return names[type];
67 +}
68 +
48 69 enum return_type {
49 70 ret_any,
50 - ret_non_zero,
51 71 ret_zero,
52 72 ret_one,
53 73 ret_negative,
54 74 ret_positive,
75 + ret_valid_ptr,
55 76 };
56 77
57 78 #define RETURN_VAL -1
58 79 #define NO_ARG -2
59 80
60 81 struct lock_info {
61 82 const char *function;
62 83 enum action action;
63 - const char *name;
84 + enum lock_type type;
64 85 int arg;
65 86 enum return_type return_type;
66 87 };
67 88
68 -static struct lock_info wine_lock_table[] = {
69 - {"create_window_handle", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
70 - {"WIN_GetPtr", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
71 - {"WIN_ReleasePtr", UNLOCK, "create_window_handle", 0, ret_any},
72 - {"EnterCriticalSection", LOCK, "CriticalSection", 0, ret_any},
73 - {"LeaveCriticalSection", UNLOCK, "CriticalSection", 0, ret_any},
74 - {"RtlEnterCriticalSection", LOCK, "RtlCriticalSection", 0, ret_any},
75 - {"RtlLeaveCriticalSection", UNLOCK, "RtlCriticalSection", 0, ret_any},
76 - {"GDI_GetObjPtr", LOCK, "GDI_Get", 0, ret_non_zero},
77 - {"GDI_ReleaseObj", UNLOCK, "GDI_Get", 0, ret_any},
78 - {"LdrLockLoaderLock", LOCK, "LdrLockLoaderLock", 2, ret_any},
79 - {"LdrUnlockLoaderLock", UNLOCK, "LdrLockLoaderLock", 1, ret_any},
80 - {"_lock", LOCK, "_lock", 0, ret_any},
81 - {"_unlock", UNLOCK, "_lock", 0, ret_any},
82 - {"msiobj_lock", LOCK, "msiobj_lock", 0, ret_any},
83 - {"msiobj_unlock", UNLOCK, "msiobj_lock", 0, ret_any},
84 - {"RtlAcquirePebLock", LOCK, "PebLock", NO_ARG, ret_any},
85 - {"RtlReleasePebLock", UNLOCK, "PebLock", NO_ARG, ret_any},
86 - {"server_enter_uninterrupted_section", LOCK, "server_uninterrupted_section", 0, ret_any},
87 - {"server_leave_uninterrupted_section", UNLOCK, "server_uninterrupted_section", 0, ret_any},
88 - {"RtlLockHeap", LOCK, "RtlLockHeap", 0, ret_any},
89 - {"RtlUnlockHeap", UNLOCK, "RtlLockHeap", 0, ret_any},
90 - {"_EnterSysLevel", LOCK, "SysLevel", 0, ret_any},
91 - {"_LeaveSysLevel", UNLOCK, "SysLevel", 0, ret_any},
92 - {"USER_Lock", LOCK, "USER_Lock", NO_ARG, ret_any},
93 - {"USER_Unlock", UNLOCK, "USER_Lock", NO_ARG, ret_any},
94 - {"wine_tsx11_lock", LOCK, "wine_tsx11_lock", NO_ARG, ret_any},
95 - {"wine_tsx11_unlock", UNLOCK, "wine_tsx11_lock", NO_ARG, ret_any},
96 - {"wine_tsx11_lock_ptr", LOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
97 - {"wine_tsx11_unlock_ptr", UNLOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
98 - {"wined3d_mutex_lock", LOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
99 - {"wined3d_mutex_unlock", UNLOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
100 - {"X11DRV_DIB_Lock", LOCK, "X11DRV_DIB_Lock", 0, ret_any},
101 - {"X11DRV_DIB_Unlock", UNLOCK, "X11DRV_DIB_Lock", 0, ret_any},
102 -};
89 +static struct lock_info lock_table[] = {
90 + {"spin_lock", LOCK, spin_lock, 0, ret_any},
91 + {"spin_unlock", UNLOCK, spin_lock, 0, ret_any},
92 + {"spin_lock_nested", LOCK, spin_lock, 0, ret_any},
93 + {"_spin_lock", LOCK, spin_lock, 0, ret_any},
94 + {"_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
95 + {"_spin_lock_nested", LOCK, spin_lock, 0, ret_any},
96 + {"__spin_lock", LOCK, spin_lock, 0, ret_any},
97 + {"__spin_unlock", UNLOCK, spin_lock, 0, ret_any},
98 + {"__spin_lock_nested", LOCK, spin_lock, 0, ret_any},
99 + {"raw_spin_lock", LOCK, spin_lock, 0, ret_any},
100 + {"raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
101 + {"_raw_spin_lock", LOCK, spin_lock, 0, ret_any},
102 + {"_raw_spin_lock_nested", LOCK, spin_lock, 0, ret_any},
103 + {"_raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
104 + {"__raw_spin_lock", LOCK, spin_lock, 0, ret_any},
105 + {"__raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
103 106
104 -static struct lock_info kernel_lock_table[] = {
105 - {"lock_kernel", LOCK, "BKL", NO_ARG, ret_any},
106 - {"unlock_kernel", UNLOCK, "BKL", NO_ARG, ret_any},
107 + {"spin_lock_irq", LOCK, spin_lock, 0, ret_any},
108 + {"spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
109 + {"_spin_lock_irq", LOCK, spin_lock, 0, ret_any},
110 + {"_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
111 + {"__spin_lock_irq", LOCK, spin_lock, 0, ret_any},
112 + {"__spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
113 + {"_raw_spin_lock_irq", LOCK, spin_lock, 0, ret_any},
114 + {"_raw_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
115 + {"__raw_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
116 + {"spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
117 + {"spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
118 + {"_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
119 + {"_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
120 + {"__spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
121 + {"__spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
122 + {"_raw_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
123 + {"_raw_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
124 + {"__raw_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
125 + {"__raw_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
126 + {"spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
127 + {"_spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
128 + {"__spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
129 + {"_raw_spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
130 + {"spin_lock_bh", LOCK, spin_lock, 0, ret_any},
131 + {"spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
132 + {"_spin_lock_bh", LOCK, spin_lock, 0, ret_any},
133 + {"_spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
134 + {"__spin_lock_bh", LOCK, spin_lock, 0, ret_any},
135 + {"__spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
107 136
108 - {"spin_lock", LOCK, "spin_lock", 0, ret_any},
109 - {"spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
110 - {"spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
111 - {"_spin_lock", LOCK, "spin_lock", 0, ret_any},
112 - {"_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
113 - {"_spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
114 - {"__spin_lock", LOCK, "spin_lock", 0, ret_any},
115 - {"__spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
116 - {"__spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
117 - {"raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
118 - {"raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
119 - {"_raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
120 - {"_raw_spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
121 - {"_raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
122 - {"__raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
123 - {"__raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
137 + {"spin_trylock", LOCK, spin_lock, 0, ret_one},
138 + {"_spin_trylock", LOCK, spin_lock, 0, ret_one},
139 + {"__spin_trylock", LOCK, spin_lock, 0, ret_one},
140 + {"raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
141 + {"_raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
142 + {"spin_trylock_irq", LOCK, spin_lock, 0, ret_one},
143 + {"spin_trylock_irqsave", LOCK, spin_lock, 0, ret_one},
144 + {"spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
145 + {"_spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
146 + {"__spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
147 + {"__raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
148 + {"_atomic_dec_and_lock", LOCK, spin_lock, 1, ret_one},
124 149
125 - {"spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
126 - {"spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
127 - {"_spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
128 - {"_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
129 - {"__spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
130 - {"__spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
131 - {"_raw_spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
132 - {"_raw_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
133 - {"__raw_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
134 - {"spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
135 - {"spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
136 - {"_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
137 - {"_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
138 - {"__spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
139 - {"__spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
140 - {"_raw_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
141 - {"_raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
142 - {"__raw_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
143 - {"__raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
144 - {"spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
145 - {"_spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
146 - {"__spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
147 - {"_raw_spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
148 - {"spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
149 - {"spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
150 - {"_spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
151 - {"_spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
152 - {"__spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
153 - {"__spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
150 + {"read_lock", LOCK, read_lock, 0, ret_any},
151 + {"down_read", LOCK, read_lock, 0, ret_any},
152 + {"down_read_nested", LOCK, read_lock, 0, ret_any},
153 + {"down_read_trylock", LOCK, read_lock, 0, ret_one},
154 + {"up_read", UNLOCK, read_lock, 0, ret_any},
155 + {"read_unlock", UNLOCK, read_lock, 0, ret_any},
156 + {"_read_lock", LOCK, read_lock, 0, ret_any},
157 + {"_read_unlock", UNLOCK, read_lock, 0, ret_any},
158 + {"__read_lock", LOCK, read_lock, 0, ret_any},
159 + {"__read_unlock", UNLOCK, read_lock, 0, ret_any},
160 + {"_raw_read_lock", LOCK, read_lock, 0, ret_any},
161 + {"_raw_read_unlock", UNLOCK, read_lock, 0, ret_any},
162 + {"__raw_read_lock", LOCK, read_lock, 0, ret_any},
163 + {"__raw_read_unlock", UNLOCK, read_lock, 0, ret_any},
164 + {"read_lock_irq", LOCK, read_lock, 0, ret_any},
165 + {"read_unlock_irq" , UNLOCK, read_lock, 0, ret_any},
166 + {"_read_lock_irq", LOCK, read_lock, 0, ret_any},
167 + {"_read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
168 + {"__read_lock_irq", LOCK, read_lock, 0, ret_any},
169 + {"__read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
170 + {"_raw_read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
171 + {"_raw_read_lock_irq", LOCK, read_lock, 0, ret_any},
172 + {"_raw_read_lock_bh", LOCK, read_lock, 0, ret_any},
173 + {"_raw_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
174 + {"read_lock_irqsave", LOCK, read_lock, 0, ret_any},
175 + {"read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
176 + {"_read_lock_irqsave", LOCK, read_lock, 0, ret_any},
177 + {"_read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
178 + {"__read_lock_irqsave", LOCK, read_lock, 0, ret_any},
179 + {"__read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
180 + {"read_lock_bh", LOCK, read_lock, 0, ret_any},
181 + {"read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
182 + {"_read_lock_bh", LOCK, read_lock, 0, ret_any},
183 + {"_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
184 + {"__read_lock_bh", LOCK, read_lock, 0, ret_any},
185 + {"__read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
186 + {"__raw_read_lock_bh", LOCK, read_lock, 0, ret_any},
187 + {"__raw_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
154 188
155 - {"spin_trylock", LOCK, "spin_lock", 0, ret_one},
156 - {"_spin_trylock", LOCK, "spin_lock", 0, ret_one},
157 - {"__spin_trylock", LOCK, "spin_lock", 0, ret_one},
158 - {"raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
159 - {"_raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
160 - {"spin_trylock_irq", LOCK, "spin_lock", 0, ret_one},
161 - {"spin_trylock_irqsave", LOCK, "spin_lock", 0, ret_one},
162 - {"spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
163 - {"_spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
164 - {"__spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
165 - {"__raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
166 - {"_atomic_dec_and_lock", LOCK, "spin_lock", 1, ret_one},
189 + {"_raw_read_lock_irqsave", LOCK, read_lock, 0, ret_any},
190 + {"_raw_read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
191 + {"_raw_read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
192 + {"_raw_read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
193 + {"_raw_spin_lock_bh", LOCK, read_lock, 0, ret_any},
194 + {"_raw_spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
195 + {"_raw_spin_lock_nest_lock", LOCK, read_lock, 0, ret_any},
196 + {"_raw_spin_unlock_bh", UNLOCK, read_lock, 0, ret_any},
197 + {"_raw_spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
198 + {"_raw_write_lock_irqsave", LOCK, write_lock, 0, ret_any},
199 + {"_raw_write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
200 + {"_raw_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
201 + {"_raw_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
202 + {"__raw_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
203 + {"__raw_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
167 204
168 - {"read_lock", LOCK, "read_lock", 0, ret_any},
169 - {"read_unlock", UNLOCK, "read_lock", 0, ret_any},
170 - {"_read_lock", LOCK, "read_lock", 0, ret_any},
171 - {"_read_unlock", UNLOCK, "read_lock", 0, ret_any},
172 - {"__read_lock", LOCK, "read_lock", 0, ret_any},
173 - {"__read_unlock", UNLOCK, "read_lock", 0, ret_any},
174 - {"_raw_read_lock", LOCK, "read_lock", 0, ret_any},
175 - {"_raw_read_unlock", UNLOCK, "read_lock", 0, ret_any},
176 - {"__raw_read_lock", LOCK, "read_lock", 0, ret_any},
177 - {"__raw_read_unlock", UNLOCK, "read_lock", 0, ret_any},
178 - {"read_lock_irq", LOCK, "read_lock", 0, ret_any},
179 - {"read_unlock_irq" , UNLOCK, "read_lock", 0, ret_any},
180 - {"_read_lock_irq", LOCK, "read_lock", 0, ret_any},
181 - {"_read_unlock_irq", UNLOCK, "read_lock", 0, ret_any},
182 - {"__read_lock_irq", LOCK, "read_lock", 0, ret_any},
183 - {"__read_unlock_irq", UNLOCK, "read_lock", 0, ret_any},
184 - {"read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
185 - {"read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
186 - {"_read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
187 - {"_read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
188 - {"__read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
189 - {"__read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
190 - {"read_lock_bh", LOCK, "read_lock", 0, ret_any},
191 - {"read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
192 - {"_read_lock_bh", LOCK, "read_lock", 0, ret_any},
193 - {"_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
194 - {"__read_lock_bh", LOCK, "read_lock", 0, ret_any},
195 - {"__read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
196 - {"_raw_read_lock_bh", LOCK, "read_lock", 0, ret_any},
197 - {"_raw_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
198 - {"__raw_read_lock_bh", LOCK, "read_lock", 0, ret_any},
199 - {"__raw_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
205 + {"generic__raw_read_trylock", LOCK, read_lock, 0, ret_one},
206 + {"read_trylock", LOCK, read_lock, 0, ret_one},
207 + {"_read_trylock", LOCK, read_lock, 0, ret_one},
208 + {"raw_read_trylock", LOCK, read_lock, 0, ret_one},
209 + {"_raw_read_trylock", LOCK, read_lock, 0, ret_one},
210 + {"__raw_read_trylock", LOCK, read_lock, 0, ret_one},
211 + {"__read_trylock", LOCK, read_lock, 0, ret_one},
200 212
201 - {"generic__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
202 - {"read_trylock", LOCK, "read_lock", 0, ret_one},
203 - {"_read_trylock", LOCK, "read_lock", 0, ret_one},
204 - {"raw_read_trylock", LOCK, "read_lock", 0, ret_one},
205 - {"_raw_read_trylock", LOCK, "read_lock", 0, ret_one},
206 - {"__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
207 - {"__read_trylock", LOCK, "read_lock", 0, ret_one},
213 + {"write_lock", LOCK, write_lock, 0, ret_any},
214 + {"down_write", LOCK, write_lock, 0, ret_any},
215 + {"down_write_nested", LOCK, write_lock, 0, ret_any},
216 + {"up_write", UNLOCK, write_lock, 0, ret_any},
217 + {"write_unlock", UNLOCK, write_lock, 0, ret_any},
218 + {"_write_lock", LOCK, write_lock, 0, ret_any},
219 + {"_write_unlock", UNLOCK, write_lock, 0, ret_any},
220 + {"__write_lock", LOCK, write_lock, 0, ret_any},
221 + {"__write_unlock", UNLOCK, write_lock, 0, ret_any},
222 + {"write_lock_irq", LOCK, write_lock, 0, ret_any},
223 + {"write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
224 + {"_write_lock_irq", LOCK, write_lock, 0, ret_any},
225 + {"_write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
226 + {"__write_lock_irq", LOCK, write_lock, 0, ret_any},
227 + {"__write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
228 + {"_raw_write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
229 + {"write_lock_irqsave", LOCK, write_lock, 0, ret_any},
230 + {"write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
231 + {"_write_lock_irqsave", LOCK, write_lock, 0, ret_any},
232 + {"_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
233 + {"__write_lock_irqsave", LOCK, write_lock, 0, ret_any},
234 + {"__write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
235 + {"write_lock_bh", LOCK, write_lock, 0, ret_any},
236 + {"write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
237 + {"_write_lock_bh", LOCK, write_lock, 0, ret_any},
238 + {"_write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
239 + {"__write_lock_bh", LOCK, write_lock, 0, ret_any},
240 + {"__write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
241 + {"_raw_write_lock", LOCK, write_lock, 0, ret_any},
242 + {"__raw_write_lock", LOCK, write_lock, 0, ret_any},
243 + {"_raw_write_unlock", UNLOCK, write_lock, 0, ret_any},
244 + {"__raw_write_unlock", UNLOCK, write_lock, 0, ret_any},
245 + {"_raw_write_lock_bh", LOCK, write_lock, 0, ret_any},
246 + {"_raw_write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
247 + {"_raw_write_lock_irq", LOCK, write_lock, 0, ret_any},
208 248
209 - {"write_lock", LOCK, "write_lock", 0, ret_any},
210 - {"write_unlock", UNLOCK, "write_lock", 0, ret_any},
211 - {"_write_lock", LOCK, "write_lock", 0, ret_any},
212 - {"_write_unlock", UNLOCK, "write_lock", 0, ret_any},
213 - {"__write_lock", LOCK, "write_lock", 0, ret_any},
214 - {"__write_unlock", UNLOCK, "write_lock", 0, ret_any},
215 - {"write_lock_irq", LOCK, "write_lock", 0, ret_any},
216 - {"write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
217 - {"_write_lock_irq", LOCK, "write_lock", 0, ret_any},
218 - {"_write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
219 - {"__write_lock_irq", LOCK, "write_lock", 0, ret_any},
220 - {"__write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
221 - {"write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
222 - {"write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
223 - {"_write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
224 - {"_write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
225 - {"__write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
226 - {"__write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
227 - {"write_lock_bh", LOCK, "write_lock", 0, ret_any},
228 - {"write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
229 - {"_write_lock_bh", LOCK, "write_lock", 0, ret_any},
230 - {"_write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
231 - {"__write_lock_bh", LOCK, "write_lock", 0, ret_any},
232 - {"__write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
233 - {"_raw_write_lock", LOCK, "write_lock", 0, ret_any},
234 - {"__raw_write_lock", LOCK, "write_lock", 0, ret_any},
235 - {"_raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
236 - {"__raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
249 + {"write_trylock", LOCK, write_lock, 0, ret_one},
250 + {"_write_trylock", LOCK, write_lock, 0, ret_one},
251 + {"raw_write_trylock", LOCK, write_lock, 0, ret_one},
252 + {"_raw_write_trylock", LOCK, write_lock, 0, ret_one},
253 + {"__write_trylock", LOCK, write_lock, 0, ret_one},
254 + {"__raw_write_trylock", LOCK, write_lock, 0, ret_one},
255 + {"down_write_trylock", LOCK, write_lock, 0, ret_one},
256 + {"down_write_killable", LOCK, write_lock, 0, ret_zero},
237 257
238 - {"write_trylock", LOCK, "write_lock", 0, ret_one},
239 - {"_write_trylock", LOCK, "write_lock", 0, ret_one},
240 - {"raw_write_trylock", LOCK, "write_lock", 0, ret_one},
241 - {"_raw_write_trylock", LOCK, "write_lock", 0, ret_one},
242 - {"__write_trylock", LOCK, "write_lock", 0, ret_one},
243 - {"__raw_write_trylock", LOCK, "write_lock", 0, ret_one},
258 + {"down", LOCK, sem, 0, ret_any},
259 + {"up", UNLOCK, sem, 0, ret_any},
260 + {"down_trylock", LOCK, sem, 0, ret_zero},
261 + {"down_timeout", LOCK, sem, 0, ret_zero},
262 + {"down_interruptible", LOCK, sem, 0, ret_zero},
263 + {"down_killable", LOCK, sem, 0, ret_zero},
244 264
245 - {"down", LOCK, "sem", 0, ret_any},
246 - {"up", UNLOCK, "sem", 0, ret_any},
247 - {"down_trylock", LOCK, "sem", 0, ret_zero},
248 - {"down_timeout", LOCK, "sem", 0, ret_zero},
249 - {"down_interruptible", LOCK, "sem", 0, ret_zero},
250 265
266 + {"mutex_lock", LOCK, mutex, 0, ret_any},
267 + {"mutex_unlock", UNLOCK, mutex, 0, ret_any},
268 + {"mutex_lock_nested", LOCK, mutex, 0, ret_any},
269 + {"mutex_lock_io", LOCK, mutex, 0, ret_any},
270 + {"mutex_lock_io_nested", LOCK, mutex, 0, ret_any},
251 271
252 - {"down_write", LOCK, "rw_sem", 0, ret_any},
253 - {"downgrade_write", UNLOCK, "rw_sem", 0, ret_any},
254 - {"downgrade_write", LOCK, "read_sem", 0, ret_any},
255 - {"up_write", UNLOCK, "rw_sem", 0, ret_any},
256 - {"down_write_trylock", LOCK, "rw_sem", 0, ret_one},
257 - {"down_write_killable", LOCK, "rw_sem", 0, ret_zero},
258 - {"down_read", LOCK, "read_sem", 0, ret_any},
259 - {"down_read_trylock", LOCK, "read_sem", 0, ret_one},
260 - {"down_read_killable", LOCK, "read_sem", 0, ret_zero},
261 - {"up_read", UNLOCK, "read_sem", 0, ret_any},
272 + {"mutex_lock_interruptible", LOCK, mutex, 0, ret_zero},
273 + {"mutex_lock_interruptible_nested", LOCK, mutex, 0, ret_zero},
274 + {"mutex_lock_killable", LOCK, mutex, 0, ret_zero},
275 + {"mutex_lock_killable_nested", LOCK, mutex, 0, ret_zero},
262 276
263 - {"mutex_lock", LOCK, "mutex", 0, ret_any},
264 - {"mutex_lock_io", LOCK, "mutex", 0, ret_any},
265 - {"mutex_unlock", UNLOCK, "mutex", 0, ret_any},
266 - {"mutex_lock_nested", LOCK, "mutex", 0, ret_any},
267 - {"mutex_lock_io_nested", LOCK, "mutex", 0, ret_any},
277 + {"mutex_trylock", LOCK, mutex, 0, ret_one},
268 278
269 - {"mutex_lock_interruptible", LOCK, "mutex", 0, ret_zero},
270 - {"mutex_lock_interruptible_nested", LOCK, "mutex", 0, ret_zero},
271 - {"mutex_lock_killable", LOCK, "mutex", 0, ret_zero},
272 - {"mutex_lock_killable_nested", LOCK, "mutex", 0, ret_zero},
279 + {"ww_mutex_lock", LOCK, mutex, 0, ret_any},
280 + {"__ww_mutex_lock", LOCK, mutex, 0, ret_any},
281 + {"ww_mutex_lock_interruptible", LOCK, mutex, 0, ret_zero},
282 + {"ww_mutex_unlock", UNLOCK, mutex, 0, ret_any},
273 283
274 - {"mutex_trylock", LOCK, "mutex", 0, ret_one},
284 + {"raw_local_irq_disable", LOCK, irq, NO_ARG, ret_any},
285 + {"raw_local_irq_enable", UNLOCK, irq, NO_ARG, ret_any},
286 + {"spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
287 + {"spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
288 + {"_spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
289 + {"_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
290 + {"__spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
291 + {"__spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
292 + {"_raw_spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
293 + {"_raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
294 + {"__raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
295 + {"spin_trylock_irq", LOCK, irq, NO_ARG, ret_one},
296 + {"read_lock_irq", LOCK, irq, NO_ARG, ret_any},
297 + {"read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
298 + {"_read_lock_irq", LOCK, irq, NO_ARG, ret_any},
299 + {"_read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
300 + {"__read_lock_irq", LOCK, irq, NO_ARG, ret_any},
301 + {"_raw_read_lock_irq", LOCK, irq, NO_ARG, ret_any},
302 + {"__read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
303 + {"_raw_read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
304 + {"write_lock_irq", LOCK, irq, NO_ARG, ret_any},
305 + {"write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
306 + {"_write_lock_irq", LOCK, irq, NO_ARG, ret_any},
307 + {"_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
308 + {"__write_lock_irq", LOCK, irq, NO_ARG, ret_any},
309 + {"__write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
310 + {"_raw_write_lock_irq", LOCK, irq, NO_ARG, ret_any},
311 + {"_raw_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
275 312
276 - {"raw_local_irq_disable", LOCK, "irq", NO_ARG, ret_any},
277 - {"raw_local_irq_enable", UNLOCK, "irq", NO_ARG, ret_any},
278 - {"spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
279 - {"spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
280 - {"_spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
281 - {"_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
282 - {"__spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
283 - {"__spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
284 - {"_raw_spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
285 - {"_raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
286 - {"__raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
287 - {"spin_trylock_irq", LOCK, "irq", NO_ARG, ret_one},
288 - {"read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
289 - {"read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
290 - {"_read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
291 - {"_read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
292 - {"__read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
293 - {"__read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
294 - {"write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
295 - {"write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
296 - {"_write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
297 - {"_write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
298 - {"__write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
299 - {"__write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
313 + {"arch_local_irq_save", LOCK, irq, RETURN_VAL, ret_any},
314 + {"arch_local_irq_restore", RESTORE, irq, 0, ret_any},
315 + {"__raw_local_irq_save", LOCK, irq, RETURN_VAL, ret_any},
316 + {"raw_local_irq_restore", RESTORE, irq, 0, ret_any},
317 + {"spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
318 + {"spin_lock_irqsave", LOCK, irq, 1, ret_any},
319 + {"spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
320 + {"_spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
321 + {"_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
322 + {"_spin_lock_irqsave", LOCK, irq, 1, ret_any},
323 + {"_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
324 + {"__spin_lock_irqsave_nested", LOCK, irq, 1, ret_any},
325 + {"__spin_lock_irqsave", LOCK, irq, 1, ret_any},
326 + {"__spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
327 + {"_raw_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
328 + {"_raw_spin_lock_irqsave", LOCK, irq, 1, ret_any},
329 + {"_raw_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
330 + {"__raw_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
331 + {"__raw_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
332 + {"_raw_spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
333 + {"spin_trylock_irqsave", LOCK, irq, 1, ret_one},
334 + {"read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
335 + {"read_lock_irqsave", LOCK, irq, 1, ret_any},
336 + {"read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
337 + {"_read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
338 + {"_read_lock_irqsave", LOCK, irq, 1, ret_any},
339 + {"_read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
340 + {"__read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
341 + {"__read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
342 + {"write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
343 + {"write_lock_irqsave", LOCK, irq, 1, ret_any},
344 + {"write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
345 + {"_write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
346 + {"_write_lock_irqsave", LOCK, irq, 1, ret_any},
347 + {"_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
348 + {"__write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
349 + {"__write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
300 350
301 - {"arch_local_irq_save", LOCK, "irqsave", RETURN_VAL, ret_any},
302 - {"arch_local_irq_restore", UNLOCK, "irqsave", 0, ret_any},
303 - {"__raw_local_irq_save", LOCK, "irqsave", RETURN_VAL, ret_any},
304 - {"raw_local_irq_restore", UNLOCK, "irqsave", 0, ret_any},
305 - {"spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
306 - {"spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
307 - {"spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
308 - {"spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
309 - {"_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
310 - {"_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
311 - {"_spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
312 - {"_spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
313 - {"__spin_lock_irqsave_nested", LOCK, "irqsave", 1, ret_any},
314 - {"__spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
315 - {"__spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
316 - {"_raw_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
317 - {"_raw_spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
318 - {"_raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
319 - {"__raw_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
320 - {"__raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
321 - {"_raw_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
322 - {"spin_trylock_irqsave", LOCK, "irqsave", 1, ret_one},
323 - {"read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
324 - {"read_lock_irqsave", LOCK, "irqsave", 1, ret_any},
325 - {"read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
326 - {"_read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
327 - {"_read_lock_irqsave", LOCK, "irqsave", 1, ret_any},
328 - {"_read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
329 - {"__read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
330 - {"__read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
331 - {"write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
332 - {"write_lock_irqsave", LOCK, "irqsave", 1, ret_any},
333 - {"write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
334 - {"_write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
335 - {"_write_lock_irqsave", LOCK, "irqsave", 1, ret_any},
336 - {"_write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
337 - {"__write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
338 - {"__write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
351 + {"local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
352 + {"_local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
353 + {"__local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
354 + {"local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
355 + {"_local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
356 + {"__local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
357 + {"spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
358 + {"spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
359 + {"_spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
360 + {"_spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
361 + {"__spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
362 + {"__spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
363 + {"read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
364 + {"read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
365 + {"_read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
366 + {"_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
367 + {"__read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
368 + {"__read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
369 + {"_raw_read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
370 + {"_raw_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
371 + {"write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
372 + {"write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
373 + {"_write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
374 + {"_write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
375 + {"__write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
376 + {"__write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
377 + {"_raw_write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
378 + {"_raw_write_unlock_bh",UNLOCK, bottom_half, NO_ARG, ret_any},
379 + {"spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
380 + {"_spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
381 + {"__spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
339 382
340 - {"local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
341 - {"_local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
342 - {"__local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
343 - {"local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
344 - {"_local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
345 - {"__local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
346 - {"spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
347 - {"spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
348 - {"_spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
349 - {"_spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
350 - {"__spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
351 - {"__spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
352 - {"read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
353 - {"read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
354 - {"_read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
355 - {"_read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
356 - {"__read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
357 - {"__read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
358 - {"_raw_read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
359 - {"_raw_read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
360 - {"write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
361 - {"write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
362 - {"_write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
363 - {"_write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
364 - {"__write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
365 - {"__write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
366 - {"spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
367 - {"_spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
368 - {"__spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
383 + {"ffs_mutex_lock", LOCK, mutex, 0, ret_zero},
369 384
370 - {"ffs_mutex_lock", LOCK, "mutex", 0, ret_zero},
385 + {"clk_prepare_lock", LOCK, prepare_lock, NO_ARG, ret_any},
386 + {"clk_prepare_unlock", UNLOCK, prepare_lock, NO_ARG, ret_any},
387 + {"clk_enable_lock", LOCK, enable_lock, -1, ret_any},
388 + {"clk_enable_unlock", UNLOCK, enable_lock, 0, ret_any},
389 +
390 + {"dma_resv_lock", LOCK, mutex, 0, ret_zero},
391 + {"dma_resv_trylock", LOCK, mutex, 0, ret_one},
392 + {"dma_resv_lock_interruptible", LOCK, mutex, 0, ret_zero},
393 + {"dma_resv_unlock", UNLOCK, mutex, 0, ret_any},
394 +
395 + {"modeset_lock", LOCK, mutex, 0, ret_zero},
396 + {"drm_ modeset_lock", LOCK, mutex, 0, ret_zero},
397 + {"drm_modeset_lock_single_interruptible", LOCK, mutex, 0, ret_zero},
398 + {"modeset_unlock", UNLOCK, mutex, 0, ret_any},
399 +
400 + {"reiserfs_write_lock_nested", LOCK, mutex, 0, ret_any},
401 + {"reiserfs_write_unlock_nested", UNLOCK, mutex, 0, ret_any},
402 +
403 + {"rw_lock", LOCK, write_lock, 1, ret_any},
404 + {"rw_unlock", UNLOCK, write_lock, 1, ret_any},
405 +
406 + {"sem_lock", LOCK, mutex, 0, ret_any},
407 + {"sem_unlock", UNLOCK, mutex, 0, ret_any},
408 +
409 + {},
371 410 };
372 411
373 -static struct lock_info *lock_table;
412 +struct macro_info {
413 + const char *macro;
414 + enum action action;
415 + int param;
416 +};
374 417
375 -static struct tracker_list *starts_locked;
376 -static struct tracker_list *starts_unlocked;
418 +static struct macro_info macro_table[] = {
419 + {"genpd_lock", LOCK, 0},
420 + {"genpd_lock_nested", LOCK, 0},
421 + {"genpd_lock_interruptible", LOCK, 0},
422 + {"genpd_unlock", UNLOCK, 0},
423 +};
377 424
378 -struct locks_on_return {
379 - int line;
380 - struct tracker_list *locked;
381 - struct tracker_list *unlocked;
382 - struct tracker_list *impossible;
383 - struct range_list *return_values;
425 +static const char *false_positives[][2] = {
426 + {"fs/jffs2/", "->alloc_sem"},
427 + {"fs/xfs/", "->b_sema"},
428 + {"mm/", "pvmw->ptl"},
384 429 };
385 -DECLARE_PTR_LIST(return_list, struct locks_on_return);
386 -static struct return_list *all_returns;
387 430
388 -static char *make_full_name(const char *lock, const char *var)
389 -{
390 - static char tmp_buf[512];
431 +static struct stree *start_states;
432 +static struct stree_stack *saved_stack;
391 433
392 - snprintf(tmp_buf, sizeof(tmp_buf), "%s:%s", lock, var);
393 - remove_parens(tmp_buf);
394 - return alloc_string(tmp_buf);
434 +static struct tracker_list *locks;
435 +
436 +static void reset(struct sm_state *sm, struct expression *mod_expr)
437 +{
438 + set_state(my_id, sm->name, sm->sym, &start_state);
395 439 }
396 440
397 441 static struct expression *remove_spinlock_check(struct expression *expr)
398 442 {
399 443 if (expr->type != EXPR_CALL)
400 444 return expr;
401 445 if (expr->fn->type != EXPR_SYMBOL)
402 446 return expr;
403 447 if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
404 448 return expr;
405 449 expr = get_argument_from_call_expr(expr->args, 0);
406 450 return expr;
407 451 }
408 452
409 -static char *get_full_name(struct expression *expr, int index)
453 +static struct expression *filter_kernel_args(struct expression *arg)
410 454 {
411 - struct expression *arg;
412 - char *name = NULL;
413 - char *full_name = NULL;
455 + if (arg->type == EXPR_PREOP && arg->op == '&')
456 + return strip_expr(arg->unop);
457 + if (!is_pointer(arg))
458 + return arg;
459 + return deref_expression(strip_expr(arg));
460 +}
461 +
462 +static char *lock_to_name_sym(struct expression *expr, struct symbol **sym)
463 +{
464 + expr = remove_spinlock_check(expr);
465 + expr = filter_kernel_args(expr);
466 + return expr_to_str_sym(expr, sym);
467 +}
468 +
469 +static char *get_full_name(struct expression *expr, int index, struct symbol **sym)
470 +{
414 471 struct lock_info *lock = &lock_table[index];
472 + struct expression *arg;
415 473
474 + *sym = NULL;
416 475 if (lock->arg == RETURN_VAL) {
417 - name = expr_to_var(expr->left);
418 - full_name = make_full_name(lock->name, name);
476 + return expr_to_var_sym(strip_expr(expr->left), sym);
419 477 } else if (lock->arg == NO_ARG) {
420 - full_name = make_full_name(lock->name, "");
478 + return alloc_string(get_lock_name(lock->type));
421 479 } else {
422 480 arg = get_argument_from_call_expr(expr->args, lock->arg);
423 481 if (!arg)
424 - goto free;
425 - arg = remove_spinlock_check(arg);
426 - name = expr_to_str(arg);
427 - if (!name)
428 - goto free;
429 - full_name = make_full_name(lock->name, name);
482 + return NULL;
483 + return lock_to_name_sym(arg, sym);
430 484 }
431 -free:
432 - free_string(name);
433 - return full_name;
434 485 }
435 486
436 -static struct smatch_state *get_start_state(struct sm_state *sm)
487 +static struct smatch_state *unmatched_state(struct sm_state *sm)
437 488 {
438 - int is_locked = 0;
439 - int is_unlocked = 0;
489 + return &start_state;
490 +}
440 491
441 - if (in_tracker_list(starts_locked, my_id, sm->name, sm->sym))
442 - is_locked = 1;
443 - if (in_tracker_list(starts_unlocked, my_id, sm->name, sm->sym))
444 - is_unlocked = 1;
445 - if (is_locked && is_unlocked)
446 - return &undefined;
447 - if (is_locked)
492 +static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
493 +{
494 + if (is_impossible_path())
495 + set_state(my_id, cur->name, cur->sym, &impossible);
496 +}
497 +
498 +static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
499 +{
500 + if (s1 == &impossible)
501 + return s2;
502 + if (s2 == &impossible)
503 + return s1;
504 + return &merged;
505 +}
506 +
507 +static struct smatch_state *action_to_state(enum action lock_unlock)
508 +{
509 + switch (lock_unlock) {
510 + case LOCK:
448 511 return &locked;
449 - if (is_unlocked)
512 + case UNLOCK:
450 513 return &unlocked;
451 - return &undefined;
514 + case RESTORE:
515 + return &restore;
516 + }
517 + return NULL;
452 518 }
453 519
454 -static struct smatch_state *unmatched_state(struct sm_state *sm)
520 +static struct sm_state *get_best_match(const char *key, enum action lock_unlock)
455 521 {
456 - return &start_state;
522 + struct sm_state *sm;
523 + struct sm_state *match;
524 + int cnt = 0;
525 + int start_pos, state_len, key_len, chunks, i;
526 +
527 + if (strncmp(key, "$->", 3) == 0)
528 + key += 3;
529 +
530 + key_len = strlen(key);
531 + chunks = 0;
532 + for (i = key_len - 1; i > 0; i--) {
533 + if (key[i] == '>' || key[i] == '.')
534 + chunks++;
535 + if (chunks == 2) {
536 + key += (i + 1);
537 + key_len = strlen(key);
538 + break;
539 + }
540 + }
541 +
542 + FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
543 + if (((lock_unlock == UNLOCK || lock_unlock == RESTORE) &&
544 + sm->state != &locked) ||
545 + (lock_unlock == LOCK && sm->state != &unlocked))
546 + continue;
547 + state_len = strlen(sm->name);
548 + if (state_len < key_len)
549 + continue;
550 + start_pos = state_len - key_len;
551 + if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
552 + strcmp(sm->name + start_pos, key) == 0) {
553 + cnt++;
554 + match = sm;
555 + }
556 + } END_FOR_EACH_SM(sm);
557 +
558 + if (cnt == 1)
559 + return match;
560 + return NULL;
457 561 }
458 562
459 -static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
563 +static void use_best_match(char *key, enum action lock_unlock)
460 564 {
461 - if (is_impossible_path())
462 - set_state(my_id, cur->name, cur->sym, &impossible);
565 + struct sm_state *match;
566 +
567 + match = get_best_match(key, lock_unlock);
568 + if (match)
569 + set_state(my_id, match->name, match->sym, action_to_state(lock_unlock));
570 + else
571 + set_state(my_id, key, NULL, action_to_state(lock_unlock));
463 572 }
464 573
465 -static bool nestable(const char *name)
574 +static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
466 575 {
467 - if (strstr(name, "read_sem:"))
468 - return true;
469 - if (strcmp(name, "bottom_half:") == 0)
470 - return true;
576 + struct smatch_state *orig;
577 +
578 + orig = get_state_stree(start_states, my_id, name, sym);
579 + if (!orig)
580 + set_state_stree(&start_states, my_id, name, sym, start);
581 + else if (orig != start)
582 + set_state_stree(&start_states, my_id, name, sym, &undefined);
583 +}
584 +
585 +static bool common_false_positive(const char *name)
586 +{
587 + const char *path, *lname;
588 + int i, len_total, len_path, len_name, skip;
589 +
590 + if (!get_filename())
591 + return false;
592 +
593 + len_total = strlen(name);
594 + for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
595 + path = false_positives[i][0];
596 + lname = false_positives[i][1];
597 +
598 + len_path = strlen(path);
599 + len_name = strlen(lname);
600 +
601 + if (len_name > len_total)
602 + continue;
603 + skip = len_total - len_name;
604 +
605 + if (strncmp(get_filename(), path, len_path) == 0 &&
606 + strcmp(name + skip, lname) == 0)
607 + return true;
608 + }
609 +
471 610 return false;
472 611 }
473 612
474 -static void do_lock(const char *name)
613 +static void warn_on_double(struct sm_state *sm, struct smatch_state *state)
475 614 {
476 - struct sm_state *sm;
615 + struct sm_state *tmp;
477 616
478 - if (__inline_fn)
617 + if (!sm)
479 618 return;
480 619
481 - sm = get_sm_state(my_id, name, NULL);
482 - if (!sm)
483 - add_tracker(&starts_unlocked, my_id, name, NULL);
484 - if (sm && slist_has_state(sm->possible, &locked) && !nestable(name))
485 - sm_error("double lock '%s'", name);
486 - if (sm)
487 - func_has_transition = TRUE;
488 - set_state(my_id, name, NULL, &locked);
620 + FOR_EACH_PTR(sm->possible, tmp) {
621 + if (tmp->state == state)
622 + goto found;
623 + } END_FOR_EACH_PTR(tmp);
624 +
625 + return;
626 +found:
627 + if (strcmp(sm->name, "bottom_half") == 0)
628 + return;
629 + if (common_false_positive(sm->name))
630 + return;
631 + sm_msg("error: double %s '%s' (orig line %u)",
632 + state->name, sm->name, tmp->line);
489 633 }
490 634
491 -static void do_lock_failed(const char *name)
635 +static bool handle_macro_lock_unlock(void)
492 636 {
637 + struct expression *expr, *arg;
638 + struct macro_info *info;
493 639 struct sm_state *sm;
640 + struct symbol *sym;
641 + const char *macro;
642 + char *name;
643 + bool ret = false;
644 + int i;
494 645
495 - if (__inline_fn)
646 + expr = last_ptr_list((struct ptr_list *)big_expression_stack);
647 + while (expr && expr->type == EXPR_ASSIGNMENT)
648 + expr = strip_expr(expr->right);
649 + if (!expr || expr->type != EXPR_CALL)
650 + return false;
651 +
652 + macro = get_macro_name(expr->pos);
653 + if (!macro)
654 + return false;
655 +
656 + for (i = 0; i < ARRAY_SIZE(macro_table); i++) {
657 + info = ¯o_table[i];
658 +
659 + if (strcmp(macro, info->macro) != 0)
660 + continue;
661 + arg = get_argument_from_call_expr(expr->args, info->param);
662 + name = expr_to_str_sym(arg, &sym);
663 + if (!name || !sym)
664 + goto free;
665 + sm = get_sm_state(my_id, name, sym);
666 +
667 + if (info->action == LOCK) {
668 + if (!sm)
669 + set_start_state(name, sym, &unlocked);
670 + if (sm && sm->line != expr->pos.line)
671 + warn_on_double(sm, &locked);
672 + set_state(my_id, name, sym, &locked);
673 + } else {
674 + if (!sm)
675 + set_start_state(name, sym, &locked);
676 + if (sm && sm->line != expr->pos.line)
677 + warn_on_double(sm, &unlocked);
678 + set_state(my_id, name, sym, &unlocked);
679 + }
680 + ret = true;
681 +free:
682 + free_string(name);
683 + return ret;
684 + }
685 + return false;
686 +}
687 +
688 +static void do_lock(const char *name, struct symbol *sym, struct lock_info *info)
689 +{
690 + struct sm_state *sm;
691 +
692 + if (handle_macro_lock_unlock())
496 693 return;
497 694
498 - sm = get_sm_state(my_id, name, NULL);
695 + add_tracker(&locks, my_id, name, sym);
696 +
697 + sm = get_sm_state(my_id, name, sym);
499 698 if (!sm)
500 - add_tracker(&starts_unlocked, my_id, name, NULL);
501 - set_state(my_id, name, NULL, &unlocked);
699 + set_start_state(name, sym, &unlocked);
700 + warn_on_double(sm, &locked);
701 + set_state(my_id, name, sym, &locked);
502 702 }
503 703
504 -static void do_unlock(const char *name)
704 +static void do_lock_failed(const char *name, struct symbol *sym)
505 705 {
706 + add_tracker(&locks, my_id, name, sym);
707 + set_state(my_id, name, sym, &unlocked);
708 +}
709 +
710 +static void do_unlock(const char *name, struct symbol *sym, struct lock_info *info)
711 +{
506 712 struct sm_state *sm;
507 713
508 - if (__inline_fn)
509 - return;
510 714 if (__path_is_null())
511 715 return;
512 - sm = get_sm_state(my_id, name, NULL);
716 +
717 + if (handle_macro_lock_unlock())
718 + return;
719 +
720 + add_tracker(&locks, my_id, name, sym);
721 + sm = get_sm_state(my_id, name, sym);
722 + if (!sm) {
723 + sm = get_best_match(name, UNLOCK);
724 + if (sm) {
725 + name = sm->name;
726 + sym = sm->sym;
727 + }
728 + }
513 729 if (!sm)
514 - add_tracker(&starts_locked, my_id, name, NULL);
515 - if (sm && slist_has_state(sm->possible, &unlocked) &&
516 - strcmp(name, "bottom_half:") != 0)
517 - sm_error("double unlock '%s'", name);
518 - if (sm)
519 - func_has_transition = TRUE;
520 - set_state(my_id, name, NULL, &unlocked);
730 + set_start_state(name, sym, &locked);
731 + warn_on_double(sm, &unlocked);
732 + set_state(my_id, name, sym, &unlocked);
521 733 }
522 734
735 +static void do_restore(const char *name, struct symbol *sym, struct lock_info *info)
736 +{
737 + if (__path_is_null())
738 + return;
739 +
740 + if (!get_state(my_id, name, sym))
741 + set_start_state(name, sym, &locked);
742 +
743 + add_tracker(&locks, my_id, name, sym);
744 + set_state(my_id, name, sym, &restore);
745 +}
746 +
523 747 static void match_lock_held(const char *fn, struct expression *call_expr,
524 - struct expression *assign_expr, void *_index)
748 + struct expression *assign_expr, void *_index)
525 749 {
526 750 int index = PTR_INT(_index);
527 - char *lock_name;
528 751 struct lock_info *lock = &lock_table[index];
752 + char *lock_name;
753 + struct symbol *sym;
529 754
530 755 if (lock->arg == NO_ARG) {
531 - lock_name = get_full_name(NULL, index);
756 + lock_name = get_full_name(NULL, index, &sym);
532 757 } else if (lock->arg == RETURN_VAL) {
533 758 if (!assign_expr)
534 759 return;
535 - lock_name = get_full_name(assign_expr, index);
760 + lock_name = get_full_name(assign_expr, index, &sym);
536 761 } else {
537 - lock_name = get_full_name(call_expr, index);
762 + lock_name = get_full_name(call_expr, index, &sym);
538 763 }
539 764 if (!lock_name)
540 765 return;
541 - do_lock(lock_name);
766 + do_lock(lock_name, sym, lock);
542 767 free_string(lock_name);
543 768 }
544 769
545 770 static void match_lock_failed(const char *fn, struct expression *call_expr,
546 771 struct expression *assign_expr, void *_index)
547 772 {
548 773 int index = PTR_INT(_index);
549 - char *lock_name;
550 774 struct lock_info *lock = &lock_table[index];
775 + char *lock_name;
776 + struct symbol *sym;
551 777
552 778 if (lock->arg == NO_ARG) {
553 - lock_name = get_full_name(NULL, index);
779 + lock_name = get_full_name(NULL, index, &sym);
554 780 } else if (lock->arg == RETURN_VAL) {
555 781 if (!assign_expr)
556 782 return;
557 - lock_name = get_full_name(assign_expr, index);
783 + lock_name = get_full_name(assign_expr, index, &sym);
558 784 } else {
559 - lock_name = get_full_name(call_expr, index);
785 + lock_name = get_full_name(call_expr, index, &sym);
560 786 }
561 787 if (!lock_name)
562 788 return;
563 - do_lock_failed(lock_name);
789 + do_lock_failed(lock_name, sym);
564 790 free_string(lock_name);
565 791 }
566 792
567 793 static void match_returns_locked(const char *fn, struct expression *expr,
568 794 void *_index)
569 795 {
570 - char *full_name = NULL;
571 796 int index = PTR_INT(_index);
572 797 struct lock_info *lock = &lock_table[index];
798 + char *full_name;
799 + struct symbol *sym;
573 800
574 801 if (lock->arg != RETURN_VAL)
575 802 return;
576 - full_name = get_full_name(expr, index);
577 - do_lock(full_name);
803 + full_name = get_full_name(expr, index, &sym);
804 + if (!full_name)
805 + return;
806 + do_lock(full_name, sym, lock);
578 807 }
579 808
580 809 static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
581 810 {
582 - char *full_name = NULL;
583 811 int index = PTR_INT(_index);
584 812 struct lock_info *lock = &lock_table[index];
813 + char *full_name;
814 + struct symbol *sym;
585 815
586 - if (__inline_fn)
587 - return;
588 -
589 - full_name = get_full_name(expr, index);
816 + full_name = get_full_name(expr, index, &sym);
590 817 if (!full_name)
591 818 return;
592 - if (lock->action == LOCK)
593 - do_lock(full_name);
594 - else
595 - do_unlock(full_name);
819 + switch (lock->action) {
820 + case LOCK:
821 + do_lock(full_name, sym, lock);
822 + break;
823 + case UNLOCK:
824 + do_unlock(full_name, sym, lock);
825 + break;
826 + case RESTORE:
827 + do_restore(full_name, sym, lock);
828 + break;
829 + }
596 830 free_string(full_name);
597 831 }
598 832
599 -static struct locks_on_return *alloc_return(struct expression *expr)
833 +static struct smatch_state *get_start_state(struct sm_state *sm)
600 834 {
601 - struct locks_on_return *ret;
835 + struct smatch_state *orig;
602 836
603 - ret = malloc(sizeof(*ret));
604 - if (!get_implied_rl(expr, &ret->return_values))
605 - ret->return_values = NULL;
606 - ret->line = get_lineno();
607 - ret->locked = NULL;
608 - ret->unlocked = NULL;
609 - ret->impossible = NULL;
610 - return ret;
837 + orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
838 + if (orig)
839 + return orig;
840 + return &undefined;
611 841 }
612 842
613 -static int check_possible(struct sm_state *sm)
843 +static int get_param_lock_name(struct sm_state *sm, struct expression *expr,
844 + const char **name)
614 845 {
615 - struct sm_state *tmp;
616 - int islocked = 0;
617 - int isunlocked = 0;
618 - int undef = 0;
846 + char *other_name;
847 + struct symbol *other_sym;
848 + const char *param_name;
849 + int param;
619 850
620 - if (!option_spammy)
621 - return 0;
851 + *name = sm->name;
622 852
623 - FOR_EACH_PTR(sm->possible, tmp) {
624 - if (tmp->state == &locked)
625 - islocked = 1;
626 - if (tmp->state == &unlocked)
627 - isunlocked = 1;
628 - if (tmp->state == &start_state) {
629 - struct smatch_state *s;
853 + param = get_param_num_from_sym(sm->sym);
854 + if (param >= 0) {
855 + param_name = get_param_name(sm);
856 + if (param_name)
857 + *name = param_name;
858 + return param;
859 + }
630 860
631 - s = get_start_state(tmp);
632 - if (s == &locked)
633 - islocked = 1;
634 - else if (s == &unlocked)
635 - isunlocked = 1;
636 - else
637 - undef = 1;
861 + if (expr) {
862 + struct symbol *ret_sym;
863 + char *ret_str;
864 +
865 + ret_str = expr_to_str_sym(expr, &ret_sym);
866 + if (ret_str && ret_sym == sm->sym) {
867 + param_name = state_name_to_param_name(sm->name, ret_str);
868 + if (param_name) {
869 + free_string(ret_str);
870 + *name = param_name;
871 + return -1;
872 + }
638 873 }
639 - if (tmp->state == &undefined)
640 - undef = 1; // i don't think this is possible any more.
641 - } END_FOR_EACH_PTR(tmp);
642 - if ((islocked && isunlocked) || undef) {
643 - sm_warning("'%s' is sometimes locked here and sometimes unlocked.", sm->name);
644 - return 1;
874 + free_string(ret_str);
645 875 }
646 - return 0;
876 +
877 + other_name = get_other_name_sym(sm->name, sm->sym, &other_sym);
878 + if (!other_name)
879 + return -2;
880 + param = get_param_num_from_sym(other_sym);
881 + if (param < 0)
882 + return -2;
883 +
884 + param_name = get_param_name_var_sym(other_name, other_sym);
885 + free_string(other_name);
886 + if (param_name)
887 + *name = param_name;
888 + return param;
647 889 }
648 890
649 -static struct position warned_pos;
891 +static int get_db_type(struct sm_state *sm)
892 +{
893 + if (sm->state == get_start_state(sm)) {
894 + if (sm->state == &locked)
895 + return KNOWN_LOCKED;
896 + if (sm->state == &unlocked)
897 + return KNOWN_UNLOCKED;
898 + }
650 899
651 -static void match_return(int return_id, char *return_ranges, struct expression *expr)
900 + if (sm->state == &locked)
901 + return LOCKED;
902 + if (sm->state == &unlocked)
903 + return UNLOCKED;
904 + if (sm->state == &restore)
905 + return LOCK_RESTORED;
906 + return LOCKED;
907 +}
908 +
909 +static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
652 910 {
653 - struct locks_on_return *ret;
654 - struct stree *stree;
655 - struct sm_state *tmp;
911 + struct sm_state *sm;
912 + const char *param_name;
913 + int param;
656 914
657 - if (!final_pass)
658 - return;
659 - if (__inline_fn)
660 - return;
915 + FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
916 + if (sm->state != &locked &&
917 + sm->state != &unlocked &&
918 + sm->state != &restore)
919 + continue;
661 920
662 - if (expr && cmp_pos(expr->pos, warned_pos) == 0)
663 - return;
921 + param = get_param_lock_name(sm, expr, ¶m_name);
922 + sql_insert_return_states(return_id, return_ranges,
923 + get_db_type(sm),
924 + param, param_name, "");
925 + } END_FOR_EACH_SM(sm);
926 +}
664 927
665 - ret = alloc_return(expr);
928 +enum {
929 + ERR_PTR, VALID_PTR, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS,
930 +};
666 931
667 - stree = __get_cur_stree();
668 - FOR_EACH_MY_SM(my_id, stree, tmp) {
669 - if (tmp->state == &locked) {
670 - add_tracker(&ret->locked, tmp->owner, tmp->name,
671 - tmp->sym);
672 - } else if (tmp->state == &unlocked) {
673 - add_tracker(&ret->unlocked, tmp->owner, tmp->name,
674 - tmp->sym);
675 - } else if (tmp->state == &start_state) {
676 - struct smatch_state *s;
932 +static bool is_EINTR(struct range_list *rl)
933 +{
934 + sval_t sval;
677 935
678 - s = get_start_state(tmp);
679 - if (s == &locked)
680 - add_tracker(&ret->locked, tmp->owner, tmp->name,
681 - tmp->sym);
682 - if (s == &unlocked)
683 - add_tracker(&ret->unlocked, tmp->owner,tmp->name,
684 - tmp->sym);
685 - } else if (tmp->state == &impossible) {
686 - add_tracker(&ret->impossible, tmp->owner, tmp->name,
687 - tmp->sym);
688 - } else {
689 - if (check_possible(tmp)) {
690 - if (expr)
691 - warned_pos = expr->pos;
692 - }
693 - }
694 - } END_FOR_EACH_SM(tmp);
695 - add_ptr_list(&all_returns, ret);
936 + if (!rl_to_sval(rl, &sval))
937 + return false;
938 + return sval.value == -4;
696 939 }
697 940
698 -static void add_line(struct range_list **rl, int line)
941 +static int success_fail_positive(struct range_list *rl)
699 942 {
700 - sval_t sval = sval_type_val(&int_ctype, line);
943 + /* void returns are the same as success (zero in the kernel) */
944 + if (!rl)
945 + return ZERO;
701 946
702 - add_range(rl, sval, sval);
947 + if (rl_type(rl)->type != SYM_PTR && sval_is_negative(rl_min(rl)))
948 + return NEGATIVE;
949 +
950 + if (rl_min(rl).value == 0 && rl_max(rl).value == 0)
951 + return ZERO;
952 +
953 + if (is_err_ptr(rl_min(rl)) &&
954 + is_err_ptr(rl_max(rl)))
955 + return ERR_PTR;
956 +
957 + /*
958 + * Trying to match ERR_PTR(ret) but without the expression struct.
959 + * Ugly...
960 + */
961 + if (type_bits(&long_ctype) == 64 &&
962 + rl_type(rl)->type == SYM_PTR &&
963 + rl_min(rl).value == INT_MIN)
964 + return ERR_PTR;
965 +
966 + return POSITIVE;
703 967 }
704 968
705 -static int line_printed(struct range_list *rl, int line)
969 +static bool sym_in_lock_table(struct symbol *sym)
706 970 {
707 - sval_t sval = sval_type_val(&int_ctype, line);
971 + int i;
708 972
709 - return rl_has_sval(rl, sval);
973 + if (!sym || !sym->ident)
974 + return false;
975 +
976 + for (i = 0; lock_table[i].function != NULL; i++) {
977 + if (strcmp(lock_table[i].function, sym->ident->name) == 0)
978 + return true;
979 + }
980 + return false;
710 981 }
711 982
712 -static void print_inconsistent_returns(struct tracker *lock,
713 - struct smatch_state *start)
983 +static bool func_in_lock_table(struct expression *expr)
714 984 {
715 - struct locks_on_return *tmp;
716 - struct range_list *printed = NULL;
985 + if (expr->type != EXPR_SYMBOL)
986 + return false;
987 + return sym_in_lock_table(expr->symbol);
988 +}
989 +
990 +static void check_lock(char *name, struct symbol *sym)
991 +{
992 + struct range_list *locked_lines = NULL;
993 + struct range_list *unlocked_lines = NULL;
994 + int locked_buckets[NUM_BUCKETS] = {};
995 + int unlocked_buckets[NUM_BUCKETS] = {};
996 + struct stree *stree, *orig;
997 + struct sm_state *return_sm;
998 + struct sm_state *sm;
999 + sval_t line = sval_type_val(&int_ctype, 0);
1000 + int bucket;
717 1001 int i;
718 1002
719 - sm_warning("inconsistent returns '%s'.", lock->name);
720 - sm_printf(" Locked on: ");
1003 + if (sym_in_lock_table(cur_func_sym))
1004 + return;
721 1005
722 - i = 0;
723 - FOR_EACH_PTR(all_returns, tmp) {
724 - if (line_printed(printed, tmp->line))
725 - continue;
726 - if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym))
727 - continue;
728 - if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym)) {
729 - if (i++)
730 - sm_printf(" ");
731 - sm_printf("line %d\n", tmp->line);
732 - add_line(&printed, tmp->line);
733 - continue;
734 - }
735 - if (start == &locked) {
736 - if (i++)
737 - sm_printf(" ");
738 - sm_printf("line %d\n", tmp->line);
739 - add_line(&printed, tmp->line);
740 - }
741 - } END_FOR_EACH_PTR(tmp);
1006 + FOR_EACH_PTR(get_all_return_strees(), stree) {
1007 + orig = __swap_cur_stree(stree);
742 1008
743 - sm_printf(" Unlocked on: ");
744 - printed = NULL;
745 - i = 0;
746 - FOR_EACH_PTR(all_returns, tmp) {
747 - if (line_printed(printed, tmp->line))
748 - continue;
749 - if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym)) {
750 - if (i++)
751 - sm_printf(" ");
752 - sm_printf("line %d\n", tmp->line);
753 - add_line(&printed, tmp->line);
754 - continue;
1009 + if (is_impossible_path())
1010 + goto swap_stree;
1011 +
1012 + return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
1013 + if (!return_sm)
1014 + goto swap_stree;
1015 + line.value = return_sm->line;
1016 +
1017 + sm = get_sm_state(my_id, name, sym);
1018 + if (!sm)
1019 + goto swap_stree;
1020 +
1021 + if (parent_is_gone_var_sym(sm->name, sm->sym))
1022 + goto swap_stree;
1023 +
1024 + if (sm->state != &locked && sm->state != &unlocked)
1025 + goto swap_stree;
1026 +
1027 + if (sm->state == &unlocked && is_EINTR(estate_rl(return_sm->state)))
1028 + goto swap_stree;
1029 +
1030 + bucket = success_fail_positive(estate_rl(return_sm->state));
1031 + if (sm->state == &locked) {
1032 + add_range(&locked_lines, line, line);
1033 + locked_buckets[bucket] = true;
755 1034 }
756 - if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym))
757 - continue;
758 - if (start == &unlocked) {
759 - if (i++)
760 - sm_printf(" ");
761 - sm_printf("line %d\n", tmp->line);
762 - add_line(&printed, tmp->line);
1035 + if (sm->state == &unlocked) {
1036 + add_range(&unlocked_lines, line, line);
1037 + unlocked_buckets[bucket] = true;
763 1038 }
764 - } END_FOR_EACH_PTR(tmp);
765 -}
1039 +swap_stree:
1040 + __swap_cur_stree(orig);
1041 + } END_FOR_EACH_PTR(stree);
766 1042
767 -static int matches_return_type(struct range_list *rl, enum return_type type)
768 -{
769 - sval_t zero_sval = ll_to_sval(0);
770 - sval_t one_sval = ll_to_sval(1);
771 1043
772 - /* All these double negatives are super ugly! */
1044 + if (!locked_lines || !unlocked_lines)
1045 + return;
773 1046
774 - switch (type) {
775 - case ret_zero:
776 - return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(zero_sval, zero_sval));
777 - case ret_one:
778 - return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(one_sval, one_sval));
779 - case ret_non_zero:
780 - return !possibly_true_rl(rl, SPECIAL_EQUAL, alloc_rl(zero_sval, zero_sval));
781 - case ret_negative:
782 - return !possibly_true_rl(rl, SPECIAL_GTE, alloc_rl(zero_sval, zero_sval));
783 - case ret_positive:
784 - return !possibly_true_rl(rl, '<', alloc_rl(zero_sval, zero_sval));
785 - case ret_any:
786 - default:
787 - return 1;
1047 + for (i = 0; i < NUM_BUCKETS; i++) {
1048 + if (locked_buckets[i] && unlocked_buckets[i])
1049 + goto complain;
788 1050 }
789 -}
1051 + if (locked_buckets[NEGATIVE] &&
1052 + (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE]))
1053 + goto complain;
790 1054
791 -static int match_held(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
792 -{
793 - if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
794 - return 0;
795 - if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
796 - return 0;
797 - if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
798 - return 1;
799 - if (start == &unlocked)
800 - return 0;
801 - return 1;
1055 + if (locked_buckets[ERR_PTR])
1056 + goto complain;
1057 +
1058 + return;
1059 +
1060 +complain:
1061 + sm_msg("warn: inconsistent returns '%s'.", name);
1062 + sm_printf(" Locked on : %s\n", show_rl(locked_lines));
1063 + sm_printf(" Unlocked on: %s\n", show_rl(unlocked_lines));
802 1064 }
803 1065
804 -static int match_released(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
1066 +static void match_func_end(struct symbol *sym)
805 1067 {
806 - if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
807 - return 0;
808 - if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
809 - return 1;
810 - if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
811 - return 0;
812 - if (start == &unlocked)
813 - return 1;
814 - return 0;
1068 + struct tracker *tracker;
1069 +
1070 + FOR_EACH_PTR(locks, tracker) {
1071 + check_lock(tracker->name, tracker->sym);
1072 + } END_FOR_EACH_PTR(tracker);
815 1073 }
816 1074
817 -static int held_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
1075 +static void register_lock(int index)
818 1076 {
819 - struct locks_on_return *tmp;
1077 + struct lock_info *lock = &lock_table[index];
1078 + void *idx = INT_PTR(index);
820 1079
821 - FOR_EACH_PTR(all_returns, tmp) {
822 - if (!matches_return_type(tmp->return_values, type))
823 - continue;
824 - if (match_held(lock, tmp, start))
825 - return 1;
826 - } END_FOR_EACH_PTR(tmp);
827 - return 0;
1080 + if (lock->return_type == ret_one) {
1081 + return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
1082 + return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
1083 + } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
1084 + add_function_assign_hook(lock->function, &match_returns_locked, idx);
1085 + } else if (lock->return_type == ret_any) {
1086 + add_function_hook(lock->function, &match_lock_unlock, idx);
1087 + } else if (lock->return_type == ret_zero) {
1088 + return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
1089 + return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
1090 + } else if (lock->return_type == ret_valid_ptr) {
1091 + return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx);
1092 + }
828 1093 }
829 1094
830 -static int released_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
1095 +static void load_table(struct lock_info *lock_table)
831 1096 {
832 - struct locks_on_return *tmp;
1097 + int i;
833 1098
834 - FOR_EACH_PTR(all_returns, tmp) {
835 - if (!matches_return_type(tmp->return_values, type))
836 - continue;
837 - if (match_released(lock, tmp, start))
838 - return 1;
839 - } END_FOR_EACH_PTR(tmp);
840 - return 0;
1099 + for (i = 0; lock_table[i].function != NULL; i++) {
1100 + if (lock_table[i].action == LOCK)
1101 + register_lock(i);
1102 + else
1103 + add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
1104 + }
841 1105 }
842 1106
843 -static void check_returns_consistently(struct tracker *lock,
844 - struct smatch_state *start)
1107 +static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock)
845 1108 {
846 - struct symbol *type;
1109 + struct expression *call, *arg;
1110 + char *name;
1111 + struct symbol *sym;
847 1112
848 - if (!held_on_return(lock, start, ret_any) ||
849 - !released_on_return(lock, start, ret_any))
1113 + call = expr;
1114 + while (call->type == EXPR_ASSIGNMENT)
1115 + call = strip_expr(call->right);
1116 + if (call->type != EXPR_CALL)
850 1117 return;
851 1118
852 - if (held_on_return(lock, start, ret_zero) &&
853 - !held_on_return(lock, start, ret_non_zero))
1119 + if (func_in_lock_table(call->fn))
854 1120 return;
855 1121
856 - if (held_on_return(lock, start, ret_positive) &&
857 - !held_on_return(lock, start, ret_zero))
1122 + if (param == -2) {
1123 + use_best_match(key, lock_unlock);
858 1124 return;
1125 + }
859 1126
860 - if (held_on_return(lock, start, ret_positive) &&
861 - !held_on_return(lock, start, ret_negative))
862 - return;
863 -
864 - type = cur_func_return_type();
865 - if (type && type->type == SYM_PTR) {
866 - if (held_on_return(lock, start, ret_non_zero) &&
867 - !held_on_return(lock, start, ret_zero))
1127 + if (param == -1) {
1128 + if (expr->type != EXPR_ASSIGNMENT)
868 1129 return;
1130 + name = get_variable_from_key(expr->left, key, &sym);
1131 + } else {
1132 + arg = get_argument_from_call_expr(call->args, param);
1133 + if (!arg)
1134 + return;
1135 +
1136 + name = get_variable_from_key(arg, key, &sym);
869 1137 }
1138 + if (!name || !sym)
1139 + goto free;
870 1140
871 - print_inconsistent_returns(lock, start);
1141 + if (lock_unlock == LOCK)
1142 + do_lock(name, sym, NULL);
1143 + else if (lock_unlock == UNLOCK)
1144 + do_unlock(name, sym, NULL);
1145 + else if (lock_unlock == RESTORE)
1146 + do_restore(name, sym, NULL);
1147 +
1148 +free:
1149 + free_string(name);
872 1150 }
873 1151
874 -static void check_consistency(struct symbol *sym)
1152 +static void db_param_locked(struct expression *expr, int param, char *key, char *value)
875 1153 {
876 - struct tracker *tmp;
1154 + db_param_locked_unlocked(expr, param, key, value, LOCK);
1155 +}
877 1156
878 - FOR_EACH_PTR(starts_locked, tmp) {
879 - if (in_tracker_list(starts_unlocked, tmp->owner, tmp->name,
880 - tmp->sym))
881 - sm_error("locking inconsistency. We assume "
882 - "'%s' is both locked and unlocked at the "
883 - "start.",
884 - tmp->name);
885 - } END_FOR_EACH_PTR(tmp);
1157 +static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
1158 +{
1159 + db_param_locked_unlocked(expr, param, key, value, UNLOCK);
1160 +}
886 1161
887 - FOR_EACH_PTR(starts_locked, tmp) {
888 - check_returns_consistently(tmp, &locked);
889 - } END_FOR_EACH_PTR(tmp);
890 -
891 - FOR_EACH_PTR(starts_unlocked, tmp) {
892 - check_returns_consistently(tmp, &unlocked);
893 - } END_FOR_EACH_PTR(tmp);
1162 +static void db_param_restore(struct expression *expr, int param, char *key, char *value)
1163 +{
1164 + db_param_locked_unlocked(expr, param, key, value, RESTORE);
894 1165 }
895 1166
896 -static void clear_lists(void)
1167 +static int get_caller_param_lock_name(struct expression *call, struct sm_state *sm, const char **name)
897 1168 {
898 - struct locks_on_return *tmp;
1169 + struct expression *arg;
1170 + char *arg_name;
1171 + int param;
899 1172
900 - func_has_transition = FALSE;
1173 + param = 0;
1174 + FOR_EACH_PTR(call->args, arg) {
1175 + arg_name = sm_to_arg_name(arg, sm);
1176 + if (arg_name) {
1177 + *name = arg_name;
1178 + return param;
1179 + }
1180 + param++;
1181 + } END_FOR_EACH_PTR(arg);
901 1182
902 - free_trackers_and_list(&starts_locked);
903 - free_trackers_and_list(&starts_unlocked);
904 -
905 - FOR_EACH_PTR(all_returns, tmp) {
906 - free_trackers_and_list(&tmp->locked);
907 - free_trackers_and_list(&tmp->unlocked);
908 - free(tmp);
909 - } END_FOR_EACH_PTR(tmp);
910 - __free_ptr_list((struct ptr_list **)&all_returns);
1183 + *name = sm->name;
1184 + return -2;
911 1185 }
912 1186
913 -static void match_func_end(struct symbol *sym)
1187 +static void match_call_info(struct expression *expr)
914 1188 {
915 - if (__inline_fn)
916 - return;
1189 + struct sm_state *sm;
1190 + const char *param_name;
1191 + int locked_type;
1192 + int param;
917 1193
918 - if (func_has_transition)
919 - check_consistency(sym);
1194 + FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
1195 + param = get_caller_param_lock_name(expr, sm, ¶m_name);
1196 + if (sm->state == &locked)
1197 + locked_type = LOCKED;
1198 + else if (sm->state == &half_locked ||
1199 + slist_has_state(sm->possible, &locked))
1200 + locked_type = HALF_LOCKED;
1201 + else
1202 + continue;
1203 + sql_insert_caller_info(expr, locked_type, param, param_name, "xxx type");
1204 +
1205 + } END_FOR_EACH_SM(sm);
920 1206 }
921 1207
922 -static void match_after_func(struct symbol *sym)
1208 +static void match_save_states(struct expression *expr)
923 1209 {
924 - if (__inline_fn)
925 - return;
926 - clear_lists();
1210 + push_stree(&saved_stack, start_states);
1211 + start_states = NULL;
927 1212 }
928 1213
929 -static void register_lock(int index)
1214 +static void match_restore_states(struct expression *expr)
930 1215 {
931 - struct lock_info *lock = &lock_table[index];
932 - void *idx = INT_PTR(index);
1216 + start_states = pop_stree(&saved_stack);
1217 +}
933 1218
934 - if (lock->return_type == ret_non_zero) {
935 - return_implies_state(lock->function, 1, INT_MAX, &match_lock_held, idx);
936 - return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
937 - } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
938 - add_function_assign_hook(lock->function, &match_returns_locked, idx);
939 - } else if (lock->return_type == ret_any) {
940 - add_function_hook(lock->function, &match_lock_unlock, idx);
941 - } else if (lock->return_type == ret_zero) {
942 - return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
943 - return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
944 - } else if (lock->return_type == ret_one) {
945 - return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
946 - return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
947 - }
1219 +static void match_after_func(struct symbol *sym)
1220 +{
1221 + free_stree(&start_states);
948 1222 }
949 1223
950 -static void load_table(struct lock_info *_lock_table, int size)
1224 +static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr,
1225 + struct expression *assign_expr, void *_index)
951 1226 {
952 - int i;
1227 + struct expression *lock, *ctx;
1228 + char *lock_name;
1229 + struct symbol *sym;
953 1230
954 - lock_table = _lock_table;
1231 + lock = get_argument_from_call_expr(call_expr->args, 0);
1232 + ctx = get_argument_from_call_expr(call_expr->args, 1);
1233 + if (!expr_is_zero(ctx))
1234 + return;
955 1235
956 - for (i = 0; i < size; i++) {
957 - if (lock_table[i].action == LOCK)
958 - register_lock(i);
959 - else
960 - add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
961 - }
1236 + lock_name = lock_to_name_sym(lock, &sym);
1237 + if (!lock_name || !sym)
1238 + goto free;
1239 + do_lock(lock_name, sym, NULL);
1240 +free:
1241 + free_string(lock_name);
962 1242 }
963 1243
964 1244 /* print_held_locks() is used in check_call_tree.c */
965 1245 void print_held_locks(void)
966 1246 {
967 1247 struct stree *stree;
968 1248 struct sm_state *sm;
969 1249 int i = 0;
970 1250
971 1251 stree = __get_cur_stree();
972 1252 FOR_EACH_MY_SM(my_id, stree, sm) {
973 1253 if (sm->state != &locked)
974 1254 continue;
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
975 1255 if (i++)
976 1256 sm_printf(" ");
977 1257 sm_printf("'%s'", sm->name);
978 1258 } END_FOR_EACH_SM(sm);
979 1259 }
980 1260
981 1261 void check_locking(int id)
982 1262 {
983 1263 my_id = id;
984 1264
985 - if (option_project == PROJ_WINE)
986 - load_table(wine_lock_table, ARRAY_SIZE(wine_lock_table));
987 - else if (option_project == PROJ_KERNEL)
988 - load_table(kernel_lock_table, ARRAY_SIZE(kernel_lock_table));
989 - else
1265 + if (option_project != PROJ_KERNEL)
990 1266 return;
991 1267
1268 + load_table(lock_table);
1269 +
1270 + set_dynamic_states(my_id);
992 1271 add_unmatched_state_hook(my_id, &unmatched_state);
993 1272 add_pre_merge_hook(my_id, &pre_merge_hook);
994 - add_split_return_callback(match_return);
1273 + add_merge_hook(my_id, &merge_func);
1274 + add_modification_hook(my_id, &reset);
1275 +
995 1276 add_hook(&match_func_end, END_FUNC_HOOK);
1277 +
996 1278 add_hook(&match_after_func, AFTER_FUNC_HOOK);
1279 + add_hook(&match_save_states, INLINE_FN_START);
1280 + add_hook(&match_restore_states, INLINE_FN_END);
997 1281
1282 + add_hook(&match_call_info, FUNCTION_CALL_HOOK);
1283 +
1284 + add_split_return_callback(match_return_info);
1285 + select_return_states_hook(LOCKED, &db_param_locked);
1286 + select_return_states_hook(UNLOCKED, &db_param_unlocked);
1287 + select_return_states_hook(LOCK_RESTORED, &db_param_restore);
1288 +
1289 + return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0);
998 1290 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX