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