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