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