xref: /illumos-gate/usr/src/tools/smatch/src/smatch_hooks.c (revision c85f09cc92abd00c84e58ec9f0f5d942906cb713)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2006 Dan Carpenter.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon #include "smatch.h"
191f5207b7SJohn Levon 
201f5207b7SJohn Levon enum data_type {
21*c85f09ccSJohn Levon 	NO_DATA,
221f5207b7SJohn Levon 	EXPR_PTR,
231f5207b7SJohn Levon 	STMT_PTR,
241f5207b7SJohn Levon 	SYMBOL_PTR,
251f5207b7SJohn Levon 	SYM_LIST_PTR,
261f5207b7SJohn Levon };
271f5207b7SJohn Levon 
281f5207b7SJohn Levon struct hook_container {
291f5207b7SJohn Levon 	int hook_type;
30*c85f09ccSJohn Levon 	int owner;
311f5207b7SJohn Levon 	void *fn;
321f5207b7SJohn Levon };
331f5207b7SJohn Levon ALLOCATOR(hook_container, "hook functions");
341f5207b7SJohn Levon DECLARE_PTR_LIST(hook_func_list, struct hook_container);
35*c85f09ccSJohn Levon 
36*c85f09ccSJohn Levon typedef void (expr_func)(struct expression *expr);
37*c85f09ccSJohn Levon typedef void (stmt_func)(struct statement *stmt);
38*c85f09ccSJohn Levon typedef void (sym_func)(struct symbol *sym);
39*c85f09ccSJohn Levon typedef void (sym_list_func)(struct symbol_list *sym_list);
40*c85f09ccSJohn Levon 
411f5207b7SJohn Levon static struct hook_func_list *merge_funcs;
421f5207b7SJohn Levon static struct hook_func_list *unmatched_state_funcs;
431f5207b7SJohn Levon static struct hook_func_list *hook_array[NUM_HOOKS] = {};
44*c85f09ccSJohn Levon static const enum data_type data_types[NUM_HOOKS] = {
45*c85f09ccSJohn Levon 	[EXPR_HOOK] = EXPR_PTR,
46*c85f09ccSJohn Levon 	[EXPR_HOOK_AFTER] = EXPR_PTR,
47*c85f09ccSJohn Levon 	[STMT_HOOK] = STMT_PTR,
48*c85f09ccSJohn Levon 	[STMT_HOOK_AFTER] = STMT_PTR,
49*c85f09ccSJohn Levon 	[SYM_HOOK] = EXPR_PTR,
50*c85f09ccSJohn Levon 	[STRING_HOOK] = EXPR_PTR,
51*c85f09ccSJohn Levon 	[DECLARATION_HOOK] = SYMBOL_PTR,
52*c85f09ccSJohn Levon 	[ASSIGNMENT_HOOK] = EXPR_PTR,
53*c85f09ccSJohn Levon 	[ASSIGNMENT_HOOK_AFTER] = EXPR_PTR,
54*c85f09ccSJohn Levon 	[RAW_ASSIGNMENT_HOOK] = EXPR_PTR,
55*c85f09ccSJohn Levon 	[GLOBAL_ASSIGNMENT_HOOK] = EXPR_PTR,
56*c85f09ccSJohn Levon 	[CALL_ASSIGNMENT_HOOK] = EXPR_PTR,
57*c85f09ccSJohn Levon 	[MACRO_ASSIGNMENT_HOOK] = EXPR_PTR,
58*c85f09ccSJohn Levon 	[BINOP_HOOK] = EXPR_PTR,
59*c85f09ccSJohn Levon 	[OP_HOOK] = EXPR_PTR,
60*c85f09ccSJohn Levon 	[LOGIC_HOOK] = EXPR_PTR,
61*c85f09ccSJohn Levon 	[PRELOOP_HOOK] = STMT_PTR,
62*c85f09ccSJohn Levon 	[CONDITION_HOOK] = EXPR_PTR,
63*c85f09ccSJohn Levon 	[SELECT_HOOK] = EXPR_PTR,
64*c85f09ccSJohn Levon 	[WHOLE_CONDITION_HOOK] = EXPR_PTR,
65*c85f09ccSJohn Levon 	[FUNCTION_CALL_HOOK] = EXPR_PTR,
66*c85f09ccSJohn Levon 	[CALL_HOOK_AFTER_INLINE] = EXPR_PTR,
67*c85f09ccSJohn Levon 	[FUNCTION_CALL_HOOK_AFTER_DB] = EXPR_PTR,
68*c85f09ccSJohn Levon 	[DEREF_HOOK] = EXPR_PTR,
69*c85f09ccSJohn Levon 	[CASE_HOOK] = NO_DATA,
70*c85f09ccSJohn Levon 	[ASM_HOOK] = STMT_PTR,
71*c85f09ccSJohn Levon 	[CAST_HOOK] = EXPR_PTR,
72*c85f09ccSJohn Levon 	[SIZEOF_HOOK] = EXPR_PTR,
73*c85f09ccSJohn Levon 	[BASE_HOOK] = SYMBOL_PTR,
74*c85f09ccSJohn Levon 	[FUNC_DEF_HOOK] = SYMBOL_PTR,
75*c85f09ccSJohn Levon 	[AFTER_DEF_HOOK] = SYMBOL_PTR,
76*c85f09ccSJohn Levon 	[END_FUNC_HOOK] = SYMBOL_PTR,
77*c85f09ccSJohn Levon 	[AFTER_FUNC_HOOK] = SYMBOL_PTR,
78*c85f09ccSJohn Levon 	[RETURN_HOOK] = EXPR_PTR,
79*c85f09ccSJohn Levon 	[INLINE_FN_START] = EXPR_PTR,
80*c85f09ccSJohn Levon 	[INLINE_FN_END] = EXPR_PTR,
81*c85f09ccSJohn Levon 	[END_FILE_HOOK] = SYM_LIST_PTR,
82*c85f09ccSJohn Levon };
83*c85f09ccSJohn Levon 
84*c85f09ccSJohn Levon void (**pre_merge_hooks)(struct sm_state *cur, struct sm_state *other);
851f5207b7SJohn Levon 
861f5207b7SJohn Levon struct scope_container {
871f5207b7SJohn Levon 	void *fn;
881f5207b7SJohn Levon 	void *data;
891f5207b7SJohn Levon };
901f5207b7SJohn Levon ALLOCATOR(scope_container, "scope hook functions");
911f5207b7SJohn Levon DECLARE_PTR_LIST(scope_hook_list, struct scope_container);
921f5207b7SJohn Levon DECLARE_PTR_LIST(scope_hook_stack, struct scope_hook_list);
931f5207b7SJohn Levon static struct scope_hook_stack *scope_hooks;
941f5207b7SJohn Levon 
add_hook(void * func,enum hook_type type)951f5207b7SJohn Levon void add_hook(void *func, enum hook_type type)
961f5207b7SJohn Levon {
971f5207b7SJohn Levon 	struct hook_container *container = __alloc_hook_container(0);
981f5207b7SJohn Levon 
991f5207b7SJohn Levon 	container->hook_type = type;
1001f5207b7SJohn Levon 	container->fn = func;
101*c85f09ccSJohn Levon 
1021f5207b7SJohn Levon 	add_ptr_list(&hook_array[type], container);
1031f5207b7SJohn Levon }
1041f5207b7SJohn Levon 
add_merge_hook(int client_id,merge_func_t * func)1051f5207b7SJohn Levon void add_merge_hook(int client_id, merge_func_t *func)
1061f5207b7SJohn Levon {
1071f5207b7SJohn Levon 	struct hook_container *container = __alloc_hook_container(0);
108*c85f09ccSJohn Levon 	container->owner = client_id;
1091f5207b7SJohn Levon 	container->fn = func;
1101f5207b7SJohn Levon 	add_ptr_list(&merge_funcs, container);
1111f5207b7SJohn Levon }
1121f5207b7SJohn Levon 
add_unmatched_state_hook(int client_id,unmatched_func_t * func)1131f5207b7SJohn Levon void add_unmatched_state_hook(int client_id, unmatched_func_t *func)
1141f5207b7SJohn Levon {
1151f5207b7SJohn Levon 	struct hook_container *container = __alloc_hook_container(0);
116*c85f09ccSJohn Levon 	container->owner = client_id;
1171f5207b7SJohn Levon 	container->fn = func;
1181f5207b7SJohn Levon 	add_ptr_list(&unmatched_state_funcs, container);
1191f5207b7SJohn Levon }
1201f5207b7SJohn Levon 
add_pre_merge_hook(int client_id,void (* hook)(struct sm_state * cur,struct sm_state * other))121*c85f09ccSJohn Levon void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *cur, struct sm_state *other))
1221f5207b7SJohn Levon {
1231f5207b7SJohn Levon 	pre_merge_hooks[client_id] = hook;
1241f5207b7SJohn Levon }
1251f5207b7SJohn Levon 
pass_expr_to_client(void * fn,void * data)1261f5207b7SJohn Levon static void pass_expr_to_client(void *fn, void *data)
1271f5207b7SJohn Levon {
1281f5207b7SJohn Levon 	((expr_func *)fn)((struct expression *)data);
1291f5207b7SJohn Levon }
1301f5207b7SJohn Levon 
pass_stmt_to_client(void * fn,void * data)1311f5207b7SJohn Levon static void pass_stmt_to_client(void *fn, void *data)
1321f5207b7SJohn Levon {
1331f5207b7SJohn Levon 	((stmt_func *)fn)((struct statement *)data);
1341f5207b7SJohn Levon }
1351f5207b7SJohn Levon 
pass_sym_to_client(void * fn,void * data)1361f5207b7SJohn Levon static void pass_sym_to_client(void *fn, void *data)
1371f5207b7SJohn Levon {
1381f5207b7SJohn Levon 	((sym_func *)fn)((struct symbol *)data);
1391f5207b7SJohn Levon }
1401f5207b7SJohn Levon 
pass_sym_list_to_client(void * fn,void * data)1411f5207b7SJohn Levon static void pass_sym_list_to_client(void *fn, void *data)
1421f5207b7SJohn Levon {
143*c85f09ccSJohn Levon 	((sym_list_func *)fn)((struct symbol_list *)data);
1441f5207b7SJohn Levon }
1451f5207b7SJohn Levon 
__pass_to_client(void * data,enum hook_type type)1461f5207b7SJohn Levon void __pass_to_client(void *data, enum hook_type type)
1471f5207b7SJohn Levon {
1481f5207b7SJohn Levon 	struct hook_container *container;
1491f5207b7SJohn Levon 
1501f5207b7SJohn Levon 	FOR_EACH_PTR(hook_array[type], container) {
151*c85f09ccSJohn Levon 		switch (data_types[type]) {
1521f5207b7SJohn Levon 		case EXPR_PTR:
1531f5207b7SJohn Levon 			pass_expr_to_client(container->fn, data);
1541f5207b7SJohn Levon 			break;
1551f5207b7SJohn Levon 		case STMT_PTR:
1561f5207b7SJohn Levon 			pass_stmt_to_client(container->fn, data);
1571f5207b7SJohn Levon 			break;
1581f5207b7SJohn Levon 		case SYMBOL_PTR:
1591f5207b7SJohn Levon 			pass_sym_to_client(container->fn, data);
1601f5207b7SJohn Levon 			break;
1611f5207b7SJohn Levon 		case SYM_LIST_PTR:
1621f5207b7SJohn Levon 			pass_sym_list_to_client(container->fn, data);
1631f5207b7SJohn Levon 			break;
1641f5207b7SJohn Levon 		}
1651f5207b7SJohn Levon 	} END_FOR_EACH_PTR(container);
1661f5207b7SJohn Levon }
1671f5207b7SJohn Levon 
__pass_case_to_client(struct expression * switch_expr,struct range_list * rl)1681f5207b7SJohn Levon void __pass_case_to_client(struct expression *switch_expr,
1691f5207b7SJohn Levon 			   struct range_list *rl)
1701f5207b7SJohn Levon {
1711f5207b7SJohn Levon 	typedef void (case_func)(struct expression *switch_expr,
1721f5207b7SJohn Levon 				 struct range_list *rl);
1731f5207b7SJohn Levon 	struct hook_container *container;
1741f5207b7SJohn Levon 
1751f5207b7SJohn Levon 	FOR_EACH_PTR(hook_array[CASE_HOOK], container) {
1761f5207b7SJohn Levon 		((case_func *)container->fn)(switch_expr, rl);
1771f5207b7SJohn Levon 	} END_FOR_EACH_PTR(container);
1781f5207b7SJohn Levon }
1791f5207b7SJohn Levon 
__has_merge_function(int client_id)1801f5207b7SJohn Levon int __has_merge_function(int client_id)
1811f5207b7SJohn Levon {
1821f5207b7SJohn Levon 	struct hook_container *tmp;
1831f5207b7SJohn Levon 
1841f5207b7SJohn Levon 	FOR_EACH_PTR(merge_funcs, tmp) {
185*c85f09ccSJohn Levon 		if (tmp->owner == client_id)
1861f5207b7SJohn Levon 			return 1;
1871f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
1881f5207b7SJohn Levon 	return 0;
1891f5207b7SJohn Levon }
1901f5207b7SJohn Levon 
__client_merge_function(int owner,struct smatch_state * s1,struct smatch_state * s2)1911f5207b7SJohn Levon struct smatch_state *__client_merge_function(int owner,
1921f5207b7SJohn Levon 					     struct smatch_state *s1,
1931f5207b7SJohn Levon 					     struct smatch_state *s2)
1941f5207b7SJohn Levon {
1951f5207b7SJohn Levon 	struct smatch_state *tmp_state;
1961f5207b7SJohn Levon 	struct hook_container *tmp;
1971f5207b7SJohn Levon 
1981f5207b7SJohn Levon 	/* Pass NULL states first and the rest alphabetically by name */
1991f5207b7SJohn Levon 	if (!s2 || (s1 && strcmp(s2->name, s1->name) < 0)) {
2001f5207b7SJohn Levon 		tmp_state = s1;
2011f5207b7SJohn Levon 		s1 = s2;
2021f5207b7SJohn Levon 		s2 = tmp_state;
2031f5207b7SJohn Levon 	}
2041f5207b7SJohn Levon 
2051f5207b7SJohn Levon 	FOR_EACH_PTR(merge_funcs, tmp) {
206*c85f09ccSJohn Levon 		if (tmp->owner == owner)
2071f5207b7SJohn Levon 			return ((merge_func_t *)tmp->fn)(s1, s2);
2081f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
2091f5207b7SJohn Levon 	return &undefined;
2101f5207b7SJohn Levon }
2111f5207b7SJohn Levon 
__client_unmatched_state_function(struct sm_state * sm)2121f5207b7SJohn Levon struct smatch_state *__client_unmatched_state_function(struct sm_state *sm)
2131f5207b7SJohn Levon {
2141f5207b7SJohn Levon 	struct hook_container *tmp;
2151f5207b7SJohn Levon 
2161f5207b7SJohn Levon 	FOR_EACH_PTR(unmatched_state_funcs, tmp) {
217*c85f09ccSJohn Levon 		if (tmp->owner == sm->owner)
2181f5207b7SJohn Levon 			return ((unmatched_func_t *)tmp->fn)(sm);
2191f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
2201f5207b7SJohn Levon 	return &undefined;
2211f5207b7SJohn Levon }
2221f5207b7SJohn Levon 
call_pre_merge_hook(struct sm_state * cur,struct sm_state * other)223*c85f09ccSJohn Levon void call_pre_merge_hook(struct sm_state *cur, struct sm_state *other)
2241f5207b7SJohn Levon {
225*c85f09ccSJohn Levon 	if (cur->owner >= num_checks)
2261f5207b7SJohn Levon 		return;
2271f5207b7SJohn Levon 
228*c85f09ccSJohn Levon 	if (pre_merge_hooks[cur->owner])
229*c85f09ccSJohn Levon 		pre_merge_hooks[cur->owner](cur, other);
2301f5207b7SJohn Levon }
2311f5207b7SJohn Levon 
pop_scope_hook_list(struct scope_hook_stack ** stack)2321f5207b7SJohn Levon static struct scope_hook_list *pop_scope_hook_list(struct scope_hook_stack **stack)
2331f5207b7SJohn Levon {
2341f5207b7SJohn Levon 	struct scope_hook_list *hook_list;
2351f5207b7SJohn Levon 
2361f5207b7SJohn Levon 	hook_list = last_ptr_list((struct ptr_list *)*stack);
2371f5207b7SJohn Levon 	delete_ptr_list_last((struct ptr_list **)stack);
2381f5207b7SJohn Levon 	return hook_list;
2391f5207b7SJohn Levon }
2401f5207b7SJohn Levon 
push_scope_hook_list(struct scope_hook_stack ** stack,struct scope_hook_list * l)2411f5207b7SJohn Levon static void push_scope_hook_list(struct scope_hook_stack **stack, struct scope_hook_list *l)
2421f5207b7SJohn Levon {
2431f5207b7SJohn Levon 	add_ptr_list(stack, l);
2441f5207b7SJohn Levon }
2451f5207b7SJohn Levon 
add_scope_hook(scope_hook * fn,void * data)2461f5207b7SJohn Levon void add_scope_hook(scope_hook *fn, void *data)
2471f5207b7SJohn Levon {
2481f5207b7SJohn Levon 	struct scope_hook_list *hook_list;
2491f5207b7SJohn Levon 	struct scope_container *new;
2501f5207b7SJohn Levon 
2511f5207b7SJohn Levon 	if (!scope_hooks)
2521f5207b7SJohn Levon 		return;
2531f5207b7SJohn Levon 	hook_list = pop_scope_hook_list(&scope_hooks);
2541f5207b7SJohn Levon 	new = __alloc_scope_container(0);
2551f5207b7SJohn Levon 	new->fn = fn;
2561f5207b7SJohn Levon 	new->data = data;
2571f5207b7SJohn Levon 	add_ptr_list(&hook_list, new);
2581f5207b7SJohn Levon 	push_scope_hook_list(&scope_hooks, hook_list);
2591f5207b7SJohn Levon }
2601f5207b7SJohn Levon 
__push_scope_hooks(void)2611f5207b7SJohn Levon void __push_scope_hooks(void)
2621f5207b7SJohn Levon {
2631f5207b7SJohn Levon 	push_scope_hook_list(&scope_hooks, NULL);
2641f5207b7SJohn Levon }
2651f5207b7SJohn Levon 
__call_scope_hooks(void)2661f5207b7SJohn Levon void __call_scope_hooks(void)
2671f5207b7SJohn Levon {
2681f5207b7SJohn Levon 	struct scope_hook_list *hook_list;
2691f5207b7SJohn Levon 	struct scope_container *tmp;
2701f5207b7SJohn Levon 
2711f5207b7SJohn Levon 	if (!scope_hooks)
2721f5207b7SJohn Levon 		return;
2731f5207b7SJohn Levon 
2741f5207b7SJohn Levon 	hook_list = pop_scope_hook_list(&scope_hooks);
2751f5207b7SJohn Levon 	FOR_EACH_PTR(hook_list, tmp) {
2761f5207b7SJohn Levon 		((scope_hook *)tmp->fn)(tmp->data);
2771f5207b7SJohn Levon 		__free_scope_container(tmp);
2781f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
2791f5207b7SJohn Levon }
2801f5207b7SJohn Levon 
allocate_hook_memory(void)2811f5207b7SJohn Levon void allocate_hook_memory(void)
2821f5207b7SJohn Levon {
2831f5207b7SJohn Levon 	pre_merge_hooks = malloc(num_checks * sizeof(*pre_merge_hooks));
2841f5207b7SJohn Levon 	memset(pre_merge_hooks, 0, num_checks * sizeof(*pre_merge_hooks));
2851f5207b7SJohn Levon }
2861f5207b7SJohn Levon 
287