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 NO_DATA, 22 EXPR_PTR, 23 STMT_PTR, 24 SYMBOL_PTR, 25 SYM_LIST_PTR, 26 }; 27 28 struct hook_container { 29 int hook_type; 30 int owner; 31 void *fn; 32 }; 33 ALLOCATOR(hook_container, "hook functions"); 34 DECLARE_PTR_LIST(hook_func_list, struct hook_container); 35 36 typedef void (expr_func)(struct expression *expr); 37 typedef void (stmt_func)(struct statement *stmt); 38 typedef void (sym_func)(struct symbol *sym); 39 typedef void (sym_list_func)(struct symbol_list *sym_list); 40 41 static struct hook_func_list *merge_funcs; 42 static struct hook_func_list *unmatched_state_funcs; 43 static struct hook_func_list *hook_array[NUM_HOOKS] = {}; 44 static const enum data_type data_types[NUM_HOOKS] = { 45 [EXPR_HOOK] = EXPR_PTR, 46 [EXPR_HOOK_AFTER] = EXPR_PTR, 47 [STMT_HOOK] = STMT_PTR, 48 [STMT_HOOK_AFTER] = STMT_PTR, 49 [SYM_HOOK] = EXPR_PTR, 50 [STRING_HOOK] = EXPR_PTR, 51 [DECLARATION_HOOK] = SYMBOL_PTR, 52 [ASSIGNMENT_HOOK] = EXPR_PTR, 53 [ASSIGNMENT_HOOK_AFTER] = EXPR_PTR, 54 [RAW_ASSIGNMENT_HOOK] = EXPR_PTR, 55 [GLOBAL_ASSIGNMENT_HOOK] = EXPR_PTR, 56 [CALL_ASSIGNMENT_HOOK] = EXPR_PTR, 57 [MACRO_ASSIGNMENT_HOOK] = EXPR_PTR, 58 [BINOP_HOOK] = EXPR_PTR, 59 [OP_HOOK] = EXPR_PTR, 60 [LOGIC_HOOK] = EXPR_PTR, 61 [PRELOOP_HOOK] = STMT_PTR, 62 [CONDITION_HOOK] = EXPR_PTR, 63 [SELECT_HOOK] = EXPR_PTR, 64 [WHOLE_CONDITION_HOOK] = EXPR_PTR, 65 [FUNCTION_CALL_HOOK] = EXPR_PTR, 66 [CALL_HOOK_AFTER_INLINE] = EXPR_PTR, 67 [FUNCTION_CALL_HOOK_AFTER_DB] = EXPR_PTR, 68 [DEREF_HOOK] = EXPR_PTR, 69 [CASE_HOOK] = NO_DATA, 70 [ASM_HOOK] = STMT_PTR, 71 [CAST_HOOK] = EXPR_PTR, 72 [SIZEOF_HOOK] = EXPR_PTR, 73 [BASE_HOOK] = SYMBOL_PTR, 74 [FUNC_DEF_HOOK] = SYMBOL_PTR, 75 [AFTER_DEF_HOOK] = SYMBOL_PTR, 76 [END_FUNC_HOOK] = SYMBOL_PTR, 77 [AFTER_FUNC_HOOK] = SYMBOL_PTR, 78 [RETURN_HOOK] = EXPR_PTR, 79 [INLINE_FN_START] = EXPR_PTR, 80 [INLINE_FN_END] = EXPR_PTR, 81 [END_FILE_HOOK] = SYM_LIST_PTR, 82 }; 83 84 void (**pre_merge_hooks)(struct sm_state *cur, struct sm_state *other); 85 86 struct scope_container { 87 void *fn; 88 void *data; 89 }; 90 ALLOCATOR(scope_container, "scope hook functions"); 91 DECLARE_PTR_LIST(scope_hook_list, struct scope_container); 92 DECLARE_PTR_LIST(scope_hook_stack, struct scope_hook_list); 93 static struct scope_hook_stack *scope_hooks; 94 95 void add_hook(void *func, enum hook_type type) 96 { 97 struct hook_container *container = __alloc_hook_container(0); 98 99 container->hook_type = type; 100 container->fn = func; 101 102 add_ptr_list(&hook_array[type], container); 103 } 104 105 void add_merge_hook(int client_id, merge_func_t *func) 106 { 107 struct hook_container *container = __alloc_hook_container(0); 108 container->owner = client_id; 109 container->fn = func; 110 add_ptr_list(&merge_funcs, container); 111 } 112 113 void add_unmatched_state_hook(int client_id, unmatched_func_t *func) 114 { 115 struct hook_container *container = __alloc_hook_container(0); 116 container->owner = client_id; 117 container->fn = func; 118 add_ptr_list(&unmatched_state_funcs, container); 119 } 120 121 void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *cur, struct sm_state *other)) 122 { 123 pre_merge_hooks[client_id] = hook; 124 } 125 126 static void pass_expr_to_client(void *fn, void *data) 127 { 128 ((expr_func *)fn)((struct expression *)data); 129 } 130 131 static void pass_stmt_to_client(void *fn, void *data) 132 { 133 ((stmt_func *)fn)((struct statement *)data); 134 } 135 136 static void pass_sym_to_client(void *fn, void *data) 137 { 138 ((sym_func *)fn)((struct symbol *)data); 139 } 140 141 static void pass_sym_list_to_client(void *fn, void *data) 142 { 143 ((sym_list_func *)fn)((struct symbol_list *)data); 144 } 145 146 void __pass_to_client(void *data, enum hook_type type) 147 { 148 struct hook_container *container; 149 150 FOR_EACH_PTR(hook_array[type], container) { 151 switch (data_types[type]) { 152 case EXPR_PTR: 153 pass_expr_to_client(container->fn, data); 154 break; 155 case STMT_PTR: 156 pass_stmt_to_client(container->fn, data); 157 break; 158 case SYMBOL_PTR: 159 pass_sym_to_client(container->fn, data); 160 break; 161 case SYM_LIST_PTR: 162 pass_sym_list_to_client(container->fn, data); 163 break; 164 } 165 } END_FOR_EACH_PTR(container); 166 } 167 168 void __pass_case_to_client(struct expression *switch_expr, 169 struct range_list *rl) 170 { 171 typedef void (case_func)(struct expression *switch_expr, 172 struct range_list *rl); 173 struct hook_container *container; 174 175 FOR_EACH_PTR(hook_array[CASE_HOOK], container) { 176 ((case_func *)container->fn)(switch_expr, rl); 177 } END_FOR_EACH_PTR(container); 178 } 179 180 int __has_merge_function(int client_id) 181 { 182 struct hook_container *tmp; 183 184 FOR_EACH_PTR(merge_funcs, tmp) { 185 if (tmp->owner == client_id) 186 return 1; 187 } END_FOR_EACH_PTR(tmp); 188 return 0; 189 } 190 191 struct smatch_state *__client_merge_function(int owner, 192 struct smatch_state *s1, 193 struct smatch_state *s2) 194 { 195 struct smatch_state *tmp_state; 196 struct hook_container *tmp; 197 198 /* Pass NULL states first and the rest alphabetically by name */ 199 if (!s2 || (s1 && strcmp(s2->name, s1->name) < 0)) { 200 tmp_state = s1; 201 s1 = s2; 202 s2 = tmp_state; 203 } 204 205 FOR_EACH_PTR(merge_funcs, tmp) { 206 if (tmp->owner == owner) 207 return ((merge_func_t *)tmp->fn)(s1, s2); 208 } END_FOR_EACH_PTR(tmp); 209 return &undefined; 210 } 211 212 struct smatch_state *__client_unmatched_state_function(struct sm_state *sm) 213 { 214 struct hook_container *tmp; 215 216 FOR_EACH_PTR(unmatched_state_funcs, tmp) { 217 if (tmp->owner == sm->owner) 218 return ((unmatched_func_t *)tmp->fn)(sm); 219 } END_FOR_EACH_PTR(tmp); 220 return &undefined; 221 } 222 223 void call_pre_merge_hook(struct sm_state *cur, struct sm_state *other) 224 { 225 if (cur->owner >= num_checks) 226 return; 227 228 if (pre_merge_hooks[cur->owner]) 229 pre_merge_hooks[cur->owner](cur, other); 230 } 231 232 static struct scope_hook_list *pop_scope_hook_list(struct scope_hook_stack **stack) 233 { 234 struct scope_hook_list *hook_list; 235 236 hook_list = last_ptr_list((struct ptr_list *)*stack); 237 delete_ptr_list_last((struct ptr_list **)stack); 238 return hook_list; 239 } 240 241 static void push_scope_hook_list(struct scope_hook_stack **stack, struct scope_hook_list *l) 242 { 243 add_ptr_list(stack, l); 244 } 245 246 void add_scope_hook(scope_hook *fn, void *data) 247 { 248 struct scope_hook_list *hook_list; 249 struct scope_container *new; 250 251 if (!scope_hooks) 252 return; 253 hook_list = pop_scope_hook_list(&scope_hooks); 254 new = __alloc_scope_container(0); 255 new->fn = fn; 256 new->data = data; 257 add_ptr_list(&hook_list, new); 258 push_scope_hook_list(&scope_hooks, hook_list); 259 } 260 261 void __push_scope_hooks(void) 262 { 263 push_scope_hook_list(&scope_hooks, NULL); 264 } 265 266 void __call_scope_hooks(void) 267 { 268 struct scope_hook_list *hook_list; 269 struct scope_container *tmp; 270 271 if (!scope_hooks) 272 return; 273 274 hook_list = pop_scope_hook_list(&scope_hooks); 275 FOR_EACH_PTR(hook_list, tmp) { 276 ((scope_hook *)tmp->fn)(tmp->data); 277 __free_scope_container(tmp); 278 } END_FOR_EACH_PTR(tmp); 279 } 280 281 void allocate_hook_memory(void) 282 { 283 pre_merge_hooks = malloc(num_checks * sizeof(*pre_merge_hooks)); 284 memset(pre_merge_hooks, 0, num_checks * sizeof(*pre_merge_hooks)); 285 } 286