1 /*
2  * Copyright (C) 2006 Dan Carpenter.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16  */
17 
18 #include "smatch.h"
19 
20 enum data_type {
21 	EXPR_PTR,
22 	STMT_PTR,
23 	SYMBOL_PTR,
24 	SYM_LIST_PTR,
25 };
26 
27 struct hook_container {
28 	int hook_type;
29 	enum data_type data_type;
30 	void *fn;
31 };
32 ALLOCATOR(hook_container, "hook functions");
33 DECLARE_PTR_LIST(hook_func_list, struct hook_container);
34 static struct hook_func_list *merge_funcs;
35 static struct hook_func_list *unmatched_state_funcs;
36 static struct hook_func_list *hook_array[NUM_HOOKS] = {};
37 void (**pre_merge_hooks)(struct sm_state *sm);
38 
39 struct scope_container {
40 	void *fn;
41 	void *data;
42 };
43 ALLOCATOR(scope_container, "scope hook functions");
44 DECLARE_PTR_LIST(scope_hook_list, struct scope_container);
45 DECLARE_PTR_LIST(scope_hook_stack, struct scope_hook_list);
46 static struct scope_hook_stack *scope_hooks;
47 
48 void add_hook(void *func, enum hook_type type)
49 {
50 	struct hook_container *container = __alloc_hook_container(0);
51 
52 	container->hook_type = type;
53 	container->fn = func;
54 	switch (type) {
55 	case EXPR_HOOK:
56 		container->data_type = EXPR_PTR;
57 		break;
58 	case STMT_HOOK:
59 		container->data_type = STMT_PTR;
60 		break;
61 	case STMT_HOOK_AFTER:
62 		container->data_type = STMT_PTR;
63 		break;
64 	case SYM_HOOK:
65 		container->data_type = EXPR_PTR;
66 		break;
67 	case STRING_HOOK:
68 		container->data_type = EXPR_PTR;
69 		break;
70 	case DECLARATION_HOOK:
71 		container->data_type = SYMBOL_PTR;
72 		break;
73 	case ASSIGNMENT_HOOK:
74 		container->data_type = EXPR_PTR;
75 		break;
76 	case ASSIGNMENT_HOOK_AFTER:
77 		container->data_type = EXPR_PTR;
78 		break;
79 	case RAW_ASSIGNMENT_HOOK:
80 		container->data_type = EXPR_PTR;
81 		break;
82 	case GLOBAL_ASSIGNMENT_HOOK:
83 		container->data_type = EXPR_PTR;
84 		break;
85 	case CALL_ASSIGNMENT_HOOK:
86 		container->data_type = EXPR_PTR;
87 		break;
88 	case MACRO_ASSIGNMENT_HOOK:
89 		container->data_type = EXPR_PTR;
90 		break;
91 	case BINOP_HOOK:
92 		container->data_type = EXPR_PTR;
93 		break;
94 	case OP_HOOK:
95 		container->data_type = EXPR_PTR;
96 		break;
97 	case LOGIC_HOOK:
98 		container->data_type = EXPR_PTR;
99 		break;
100 	case PRELOOP_HOOK:
101 		container->data_type = STMT_PTR;
102 		break;
103 	case CONDITION_HOOK:
104 		container->data_type = EXPR_PTR;
105 		break;
106 	case SELECT_HOOK:
107 		container->data_type = EXPR_PTR;
108 		break;
109 	case WHOLE_CONDITION_HOOK:
110 		container->data_type = EXPR_PTR;
111 		break;
112 	case FUNCTION_CALL_HOOK:
113 		container->data_type = EXPR_PTR;
114 		break;
115 	case CALL_HOOK_AFTER_INLINE:
116 		container->data_type = EXPR_PTR;
117 		break;
118 	case FUNCTION_CALL_HOOK_AFTER_DB:
119 		container->data_type = EXPR_PTR;
120 		break;
121 	case DEREF_HOOK:
122 		container->data_type = EXPR_PTR;
123 		break;
124 	case CASE_HOOK:
125 		/* nothing needed */
126 		break;
127 	case ASM_HOOK:
128 		container->data_type = STMT_PTR;
129 		break;
130 	case CAST_HOOK:
131 		container->data_type = EXPR_PTR;
132 		break;
133 	case SIZEOF_HOOK:
134 		container->data_type = EXPR_PTR;
135 		break;
136 	case BASE_HOOK:
137 		container->data_type = SYMBOL_PTR;
138 		break;
139 	case FUNC_DEF_HOOK:
140 		container->data_type = SYMBOL_PTR;
141 		break;
142 	case AFTER_DEF_HOOK:
143 		container->data_type = SYMBOL_PTR;
144 		break;
145 	case END_FUNC_HOOK:
146 		container->data_type = SYMBOL_PTR;
147 		break;
148 	case AFTER_FUNC_HOOK:
149 		container->data_type = SYMBOL_PTR;
150 		break;
151 	case RETURN_HOOK:
152 		container->data_type = EXPR_PTR;
153 		break;
154 	case INLINE_FN_START:
155 		container->data_type = EXPR_PTR;
156 		break;
157 	case INLINE_FN_END:
158 		container->data_type = EXPR_PTR;
159 		break;
160 	case END_FILE_HOOK:
161 		container->data_type = SYM_LIST_PTR;
162 		break;
163 	}
164 	add_ptr_list(&hook_array[type], container);
165 }
166 
167 void add_merge_hook(int client_id, merge_func_t *func)
168 {
169 	struct hook_container *container = __alloc_hook_container(0);
170 	container->data_type = client_id;
171 	container->fn = func;
172 	add_ptr_list(&merge_funcs, container);
173 }
174 
175 void add_unmatched_state_hook(int client_id, unmatched_func_t *func)
176 {
177 	struct hook_container *container = __alloc_hook_container(0);
178 	container->data_type = client_id;
179 	container->fn = func;
180 	add_ptr_list(&unmatched_state_funcs, container);
181 }
182 
183 void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *sm))
184 {
185 	pre_merge_hooks[client_id] = hook;
186 }
187 
188 static void pass_to_client(void *fn)
189 {
190 	typedef void (expr_func)();
191 	((expr_func *) fn)();
192 }
193 
194 static void pass_expr_to_client(void *fn, void *data)
195 {
196 	typedef void (expr_func)(struct expression *expr);
197 	((expr_func *) fn)((struct expression *) data);
198 }
199 
200 static void pass_stmt_to_client(void *fn, void *data)
201 {
202 	typedef void (stmt_func)(struct statement *stmt);
203 	((stmt_func *) fn)((struct statement *) data);
204 }
205 
206 static void pass_sym_to_client(void *fn, void *data)
207 {
208 	typedef void (sym_func)(struct symbol *sym);
209 	((sym_func *) fn)((struct symbol *) data);
210 }
211 
212 static void pass_sym_list_to_client(void *fn, void *data)
213 {
214 	typedef void (sym_func)(struct symbol_list *sym_list);
215 	((sym_func *) fn)((struct symbol_list *) data);
216 }
217 
218 void __pass_to_client(void *data, enum hook_type type)
219 {
220 	struct hook_container *container;
221 
222 
223 	FOR_EACH_PTR(hook_array[type], container) {
224 		switch (container->data_type) {
225 		case EXPR_PTR:
226 			pass_expr_to_client(container->fn, data);
227 			break;
228 		case STMT_PTR:
229 			pass_stmt_to_client(container->fn, data);
230 			break;
231 		case SYMBOL_PTR:
232 			pass_sym_to_client(container->fn, data);
233 			break;
234 		case SYM_LIST_PTR:
235 			pass_sym_list_to_client(container->fn, data);
236 			break;
237 		}
238 	} END_FOR_EACH_PTR(container);
239 }
240 
241 void __pass_to_client_no_data(enum hook_type type)
242 {
243 	struct hook_container *container;
244 
245 	FOR_EACH_PTR(hook_array[type], container) {
246 		pass_to_client(container->fn);
247 	} END_FOR_EACH_PTR(container);
248 }
249 
250 void __pass_case_to_client(struct expression *switch_expr,
251 			   struct range_list *rl)
252 {
253 	typedef void (case_func)(struct expression *switch_expr,
254 				 struct range_list *rl);
255 	struct hook_container *container;
256 
257 	FOR_EACH_PTR(hook_array[CASE_HOOK], container) {
258 		((case_func *) container->fn)(switch_expr, rl);
259 	} END_FOR_EACH_PTR(container);
260 }
261 
262 int __has_merge_function(int client_id)
263 {
264 	struct hook_container *tmp;
265 
266 	FOR_EACH_PTR(merge_funcs, tmp) {
267 		if (tmp->data_type == client_id)
268 			return 1;
269 	} END_FOR_EACH_PTR(tmp);
270 	return 0;
271 }
272 
273 struct smatch_state *__client_merge_function(int owner,
274 					     struct smatch_state *s1,
275 					     struct smatch_state *s2)
276 {
277 	struct smatch_state *tmp_state;
278 	struct hook_container *tmp;
279 
280 	/* Pass NULL states first and the rest alphabetically by name */
281 	if (!s2 || (s1 && strcmp(s2->name, s1->name) < 0)) {
282 		tmp_state = s1;
283 		s1 = s2;
284 		s2 = tmp_state;
285 	}
286 
287 	FOR_EACH_PTR(merge_funcs, tmp) {
288 		if (tmp->data_type == owner)
289 			return ((merge_func_t *) tmp->fn)(s1, s2);
290 	} END_FOR_EACH_PTR(tmp);
291 	return &undefined;
292 }
293 
294 struct smatch_state *__client_unmatched_state_function(struct sm_state *sm)
295 {
296 	struct hook_container *tmp;
297 
298 	FOR_EACH_PTR(unmatched_state_funcs, tmp) {
299 		if (tmp->data_type == sm->owner)
300 			return ((unmatched_func_t *) tmp->fn)(sm);
301 	} END_FOR_EACH_PTR(tmp);
302 	return &undefined;
303 }
304 
305 void call_pre_merge_hook(struct sm_state *sm)
306 {
307 	if (sm->owner >= num_checks)
308 		return;
309 
310 	if (pre_merge_hooks[sm->owner])
311 		pre_merge_hooks[sm->owner](sm);
312 }
313 
314 static struct scope_hook_list *pop_scope_hook_list(struct scope_hook_stack **stack)
315 {
316 	struct scope_hook_list *hook_list;
317 
318 	hook_list = last_ptr_list((struct ptr_list *)*stack);
319 	delete_ptr_list_last((struct ptr_list **)stack);
320 	return hook_list;
321 }
322 
323 static void push_scope_hook_list(struct scope_hook_stack **stack, struct scope_hook_list *l)
324 {
325 	add_ptr_list(stack, l);
326 }
327 
328 void add_scope_hook(scope_hook *fn, void *data)
329 {
330 	struct scope_hook_list *hook_list;
331 	struct scope_container *new;
332 
333 	if (!scope_hooks)
334 		return;
335 	hook_list = pop_scope_hook_list(&scope_hooks);
336 	new = __alloc_scope_container(0);
337 	new->fn = fn;
338 	new->data = data;
339 	add_ptr_list(&hook_list, new);
340 	push_scope_hook_list(&scope_hooks, hook_list);
341 }
342 
343 void __push_scope_hooks(void)
344 {
345 	push_scope_hook_list(&scope_hooks, NULL);
346 }
347 
348 void __call_scope_hooks(void)
349 {
350 	struct scope_hook_list *hook_list;
351 	struct scope_container *tmp;
352 
353 	if (!scope_hooks)
354 		return;
355 
356 	hook_list = pop_scope_hook_list(&scope_hooks);
357 	FOR_EACH_PTR(hook_list, tmp) {
358 		((scope_hook *) tmp->fn)(tmp->data);
359 		__free_scope_container(tmp);
360 	} END_FOR_EACH_PTR(tmp);
361 }
362 
363 void allocate_hook_memory(void)
364 {
365 	pre_merge_hooks = malloc(num_checks * sizeof(*pre_merge_hooks));
366 	memset(pre_merge_hooks, 0, num_checks * sizeof(*pre_merge_hooks));
367 }
368 
369