proc_create: fix a whitespace issue
[smatch.git] / smatch_function_hooks.c
blob88eff2b8bed9be32e882f9ceb0ed9ab3b47987ab
1 /*
2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * There are three types of function hooks:
12 * add_function_hook() - For any time a function is called.
13 * add_function_assign_hook() - foo = the_function().
14 * add_macro_assign_hook() - foo = the_macro().
15 * return_implies_state() - For when a return value of 1 implies locked
16 * and 0 implies unlocked. etc. etc.
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include "smatch.h"
23 #include "smatch_slist.h"
24 #include "smatch_extra.h"
25 #include "smatch_function_hashtable.h"
27 struct fcall_back {
28 int type;
29 struct data_range *range;
30 func_hook *call_back;
31 void *info;
34 ALLOCATOR(fcall_back, "call backs");
35 DECLARE_PTR_LIST(call_back_list, struct fcall_back);
37 DEFINE_FUNCTION_HASHTABLE_STATIC(callback, struct fcall_back, struct call_back_list);
38 static struct hashtable *func_hash;
40 #define REGULAR_CALL 0
41 #define RANGED_CALL 1
42 #define ASSIGN_CALL 2
43 #define ASSIGN_CALL_EXTRA 3
44 #define MACRO_ASSIGN 4
45 #define MACRO_ASSIGN_EXTRA 5
47 struct return_implies_callback {
48 int type;
49 return_implies_hook *callback;
51 ALLOCATOR(return_implies_callback, "return_implies callbacks");
52 DECLARE_PTR_LIST(db_implies_list, struct return_implies_callback);
53 static struct db_implies_list *db_implies_list;
55 static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back,
56 void *info)
58 struct fcall_back *cb;
60 cb = __alloc_fcall_back(0);
61 cb->type = type;
62 cb->call_back = call_back;
63 cb->info = info;
64 return cb;
67 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
69 struct fcall_back *cb;
71 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
72 add_callback(func_hash, look_for, cb);
75 void add_function_assign_hook(const char *look_for, func_hook *call_back,
76 void *info)
78 struct fcall_back *cb;
80 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
81 add_callback(func_hash, look_for, cb);
84 void add_function_assign_hook_extra(const char *look_for, func_hook *call_back,
85 void *info)
87 struct fcall_back *cb;
89 cb = alloc_fcall_back(ASSIGN_CALL_EXTRA, call_back, info);
90 add_callback(func_hash, look_for, cb);
93 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
94 void *info)
96 struct fcall_back *cb;
98 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
99 add_callback(func_hash, look_for, cb);
102 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
103 void *info)
105 struct fcall_back *cb;
107 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
108 add_callback(func_hash, look_for, cb);
111 void return_implies_state(const char *look_for, long long start, long long end,
112 implication_hook *call_back, void *info)
114 struct fcall_back *cb;
116 cb = alloc_fcall_back(RANGED_CALL, (func_hook *)call_back, info);
117 cb->range = alloc_range_perm(start, end);
118 add_callback(func_hash, look_for, cb);
121 void add_db_return_implies_callback(int type, return_implies_hook *callback)
123 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
125 cb->type = type;
126 cb->callback = callback;
127 add_ptr_list(&db_implies_list, cb);
130 static int call_call_backs(struct call_back_list *list, int type,
131 const char *fn, struct expression *expr)
133 struct fcall_back *tmp;
134 int handled = 0;
136 FOR_EACH_PTR(list, tmp) {
137 if (tmp->type == type) {
138 (tmp->call_back)(fn, expr, tmp->info);
139 handled = 1;
141 } END_FOR_EACH_PTR(tmp);
143 return handled;
146 static void call_ranged_call_backs(struct call_back_list *list,
147 const char *fn, struct expression *call_expr,
148 struct expression *assign_expr)
150 struct fcall_back *tmp;
152 FOR_EACH_PTR(list, tmp) {
153 ((implication_hook *)(tmp->call_back))(fn, call_expr, assign_expr, tmp->info);
154 } END_FOR_EACH_PTR(tmp);
157 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
158 struct data_range *drange)
160 struct call_back_list *ret = NULL;
161 struct fcall_back *tmp;
163 FOR_EACH_PTR(list, tmp) {
164 if (tmp->type != RANGED_CALL)
165 continue;
166 if (tmp->range->min == drange->min && tmp->range->max == drange->max)
167 add_ptr_list(&ret, tmp);
168 } END_FOR_EACH_PTR(tmp);
169 return ret;
172 static int assign_ranged_funcs(const char *fn, struct expression *expr,
173 struct call_back_list *call_backs)
175 struct fcall_back *tmp;
176 struct sm_state *sm;
177 char *var_name;
178 struct symbol *sym;
179 struct smatch_state *estate;
180 struct state_list *tmp_slist;
181 struct state_list *final_states = NULL;
182 struct range_list *handled_ranges = NULL;
183 struct call_back_list *same_range_call_backs = NULL;
184 int handled = 0;
186 if (!call_backs)
187 return 0;
189 var_name = get_variable_from_expr(expr->left, &sym);
190 if (!var_name || !sym)
191 goto free;
193 FOR_EACH_PTR(call_backs, tmp) {
194 if (tmp->type != RANGED_CALL)
195 continue;
196 if (in_list_exact(handled_ranges, tmp->range))
197 continue;
198 __push_fake_cur_slist();
199 tack_on(&handled_ranges, tmp->range);
201 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
202 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
203 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
205 estate = alloc_estate_range(tmp->range->min, tmp->range->max);
206 set_extra_mod(var_name, sym, estate);
208 tmp_slist = __pop_fake_cur_slist();
209 merge_slist(&final_states, tmp_slist);
210 free_slist(&tmp_slist);
211 handled = 1;
212 } END_FOR_EACH_PTR(tmp);
214 FOR_EACH_PTR(final_states, sm) {
215 __set_sm(sm);
216 } END_FOR_EACH_PTR(sm);
218 free_slist(&final_states);
219 free:
220 free_string(var_name);
221 return handled;
224 int call_implies_callbacks(int comparison, struct expression *expr, long long value, int left)
226 struct call_back_list *call_backs;
227 struct fcall_back *tmp;
228 const char *fn;
229 struct data_range *value_range;
230 struct state_list *true_states = NULL;
231 struct state_list *false_states = NULL;
232 struct state_list *tmp_slist;
233 struct sm_state *sm;
235 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
236 return 0;
237 fn = expr->fn->symbol->ident->name;
238 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
239 if (!call_backs)
240 return 0;
241 value_range = alloc_range(value, value);
243 /* set true states */
244 __push_fake_cur_slist();
245 FOR_EACH_PTR(call_backs, tmp) {
246 if (tmp->type != RANGED_CALL)
247 continue;
248 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
249 continue;
250 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
251 } END_FOR_EACH_PTR(tmp);
252 tmp_slist = __pop_fake_cur_slist();
253 merge_slist(&true_states, tmp_slist);
254 free_slist(&tmp_slist);
256 /* set false states */
257 __push_fake_cur_slist();
258 FOR_EACH_PTR(call_backs, tmp) {
259 if (tmp->type != RANGED_CALL)
260 continue;
261 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
262 continue;
263 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
264 } END_FOR_EACH_PTR(tmp);
265 tmp_slist = __pop_fake_cur_slist();
266 merge_slist(&false_states, tmp_slist);
267 free_slist(&tmp_slist);
269 FOR_EACH_PTR(true_states, sm) {
270 __set_true_false_sm(sm, NULL);
271 } END_FOR_EACH_PTR(sm);
272 FOR_EACH_PTR(false_states, sm) {
273 __set_true_false_sm(NULL, sm);
274 } END_FOR_EACH_PTR(sm);
276 free_slist(&true_states);
277 free_slist(&false_states);
278 return 1;
281 struct db_callback_info {
282 int true_side;
283 int comparison;
284 struct expression *expr;
285 struct range_list *rl;
286 int left;
287 struct state_list *slist;
289 static struct db_callback_info db_info;
290 static int db_compare_callback(void *unused, int argc, char **argv, char **azColName)
292 struct range_list *ret_range;
293 int type, param;
294 char *key, *value;
295 struct return_implies_callback *tmp;
297 if (argc != 5)
298 return 0;
300 get_value_ranges(argv[0], &ret_range);
301 type = atoi(argv[1]);
302 param = atoi(argv[2]);
303 key = argv[3];
304 value = argv[4];
306 if (db_info.true_side) {
307 if (!possibly_true_range_lists_rl(db_info.comparison,
308 ret_range, db_info.rl,
309 db_info.left))
310 return 0;
311 } else {
312 if (!possibly_false_range_lists_rl(db_info.comparison,
313 ret_range, db_info.rl,
314 db_info.left))
315 return 0;
318 FOR_EACH_PTR(db_implies_list, tmp) {
319 if (tmp->type == type)
320 tmp->callback(db_info.expr, param, key, value);
321 } END_FOR_EACH_PTR(tmp);
322 return 0;
325 void compare_db_implies_callbacks(int comparison, struct expression *expr, long long value, int left)
327 struct symbol *sym;
328 static char sql_filter[1024];
329 struct state_list *true_states;
330 struct state_list *false_states;
331 struct sm_state *sm;
333 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
334 return;
336 sym = expr->fn->symbol;
337 if (!sym)
338 return;
340 if (sym->ctype.modifiers & MOD_STATIC) {
341 snprintf(sql_filter, 1024,
342 "file = '%s' and function = '%s' and static = '1';",
343 get_filename(), sym->ident->name);
344 } else {
345 snprintf(sql_filter, 1024,
346 "function = '%s' and static = '0';", sym->ident->name);
349 db_info.comparison = comparison;
350 db_info.expr = expr;
351 db_info.rl = alloc_range_list(value, value);
352 db_info.left = left;
354 db_info.true_side = 1;
355 __push_fake_cur_slist();
356 run_sql(db_compare_callback,
357 "select return, type, parameter, key, value from return_implies where %s",
358 sql_filter);
359 true_states = __pop_fake_cur_slist();
361 db_info.true_side = 0;
362 __push_fake_cur_slist();
363 run_sql(db_compare_callback,
364 "select return, type, parameter, key, value from return_implies where %s",
365 sql_filter);
366 false_states = __pop_fake_cur_slist();
368 FOR_EACH_PTR(true_states, sm) {
369 __set_true_false_sm(sm, NULL);
370 } END_FOR_EACH_PTR(sm);
371 FOR_EACH_PTR(false_states, sm) {
372 __set_true_false_sm(NULL, sm);
373 } END_FOR_EACH_PTR(sm);
375 free_slist(&true_states);
376 free_slist(&false_states);
379 void compare_db_return_states_callbacks(int comparison, struct expression *expr, long long value, int left)
381 struct symbol *sym;
382 static char sql_filter[1024];
383 struct state_list *true_states;
384 struct state_list *false_states;
385 struct sm_state *sm;
387 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
388 return;
390 sym = expr->fn->symbol;
391 if (!sym)
392 return;
394 if (sym->ctype.modifiers & MOD_STATIC) {
395 snprintf(sql_filter, 1024,
396 "file = '%s' and function = '%s' and static = '1';",
397 get_filename(), sym->ident->name);
398 } else {
399 snprintf(sql_filter, 1024,
400 "function = '%s' and static = '0';", sym->ident->name);
403 db_info.comparison = comparison;
404 db_info.expr = expr;
405 db_info.rl = alloc_range_list(value, value);
406 db_info.left = left;
408 db_info.true_side = 1;
409 __push_fake_cur_slist();
410 run_sql(db_compare_callback,
411 "select return, type, parameter, key, value from return_states where %s",
412 sql_filter);
413 true_states = __pop_fake_cur_slist();
415 db_info.true_side = 0;
416 __push_fake_cur_slist();
417 run_sql(db_compare_callback,
418 "select return, type, parameter, key, value from return_states where %s",
419 sql_filter);
420 false_states = __pop_fake_cur_slist();
422 FOR_EACH_PTR(true_states, sm) {
423 __set_true_false_sm(sm, NULL);
424 } END_FOR_EACH_PTR(sm);
425 FOR_EACH_PTR(false_states, sm) {
426 __set_true_false_sm(NULL, sm);
427 } END_FOR_EACH_PTR(sm);
429 free_slist(&true_states);
430 free_slist(&false_states);
435 void function_comparison(int comparison, struct expression *expr,
436 long long value, int left)
438 if (call_implies_callbacks(comparison, expr, value, left))
439 return;
440 compare_db_implies_callbacks(comparison, expr, value, left);
441 compare_db_return_states_callbacks(comparison, expr, value, left);
444 static int db_assign_callback(void *unused, int argc, char **argv, char **azColName)
446 struct range_list *ret_range;
447 int type, param;
448 char *key, *value;
449 struct return_implies_callback *tmp;
450 struct state_list *slist;
452 if (argc != 5)
453 return 0;
455 get_value_ranges(argv[0], &ret_range);
456 type = atoi(argv[1]);
457 param = atoi(argv[2]);
458 key = argv[3];
459 value = argv[4];
461 __push_fake_cur_slist();
462 FOR_EACH_PTR(db_implies_list, tmp) {
463 if (tmp->type == type)
464 tmp->callback(db_info.expr->right, param, key, value);
465 } END_FOR_EACH_PTR(tmp);
466 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
467 slist = __pop_fake_cur_slist();
469 merge_slist(&db_info.slist, slist);
471 return 0;
474 static int db_return_implies_assign(struct expression *expr)
476 struct symbol *sym;
477 static char sql_filter[1024];
478 static struct sm_state *sm;
479 int handled = 0;
481 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
482 return 0;
484 sym = expr->right->fn->symbol;
485 if (!sym)
486 return 0;
488 if (sym->ctype.modifiers & MOD_STATIC) {
489 snprintf(sql_filter, 1024,
490 "file = '%s' and function = '%s' and static = '1';",
491 get_filename(), sym->ident->name);
492 } else {
493 snprintf(sql_filter, 1024,
494 "function = '%s' and static = '0';", sym->ident->name);
497 db_info.expr = expr;
498 db_info.slist = NULL;
499 run_sql(db_assign_callback,
500 "select return, type, parameter, key, value from return_implies where %s",
501 sql_filter);
503 FOR_EACH_PTR(db_info.slist, sm) {
504 __set_sm(sm);
505 handled = 1;
506 } END_FOR_EACH_PTR(sm);
508 return handled;
511 static int prev_return_id;
512 static int db_assign_return_states_callback(void *unused, int argc, char **argv, char **azColName)
514 struct range_list *ret_range;
515 int type, param;
516 char *key, *value;
517 struct return_implies_callback *tmp;
518 struct state_list *slist;
519 int return_id;
521 if (argc != 6)
522 return 0;
524 return_id = atoi(argv[0]);
525 get_value_ranges(argv[1], &ret_range);
526 if (!ret_range)
527 ret_range = whole_range_list();
528 type = atoi(argv[2]);
529 param = atoi(argv[3]);
530 key = argv[4];
531 value = argv[5];
533 if (prev_return_id != -1 && return_id != prev_return_id) {
534 slist = __pop_fake_cur_slist();
535 merge_slist(&db_info.slist, slist);
536 __push_fake_cur_slist();
538 prev_return_id = return_id;
540 FOR_EACH_PTR(db_implies_list, tmp) {
541 if (tmp->type == type)
542 tmp->callback(db_info.expr->right, param, key, value);
543 } END_FOR_EACH_PTR(tmp);
544 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
546 return 0;
549 static int db_return_states_assign(struct expression *expr)
551 struct symbol *sym;
552 struct sm_state *sm;
553 struct state_list *slist;
554 static char sql_filter[1024];
555 int handled = 0;
557 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
558 return 0;
560 sym = expr->right->fn->symbol;
561 if (!sym)
562 return 0;
564 if (sym->ctype.modifiers & MOD_STATIC) {
565 snprintf(sql_filter, 1024,
566 "file = '%s' and function = '%s' and static = '1';",
567 get_filename(), sym->ident->name);
568 } else {
569 snprintf(sql_filter, 1024,
570 "function = '%s' and static = '0';", sym->ident->name);
573 prev_return_id = -1;
574 db_info.expr = expr;
575 db_info.slist = NULL;
576 __push_fake_cur_slist();
577 run_sql(db_assign_return_states_callback,
578 "select return_id, return, type, parameter, key, value from return_states where %s",
579 sql_filter);
580 slist = __pop_fake_cur_slist();
581 merge_slist(&db_info.slist, slist);
583 FOR_EACH_PTR(db_info.slist, sm) {
584 __set_sm(sm);
585 handled = 1;
586 } END_FOR_EACH_PTR(sm);
588 return handled;
591 static void match_assign_call(struct expression *expr)
593 struct call_back_list *call_backs;
594 const char *fn;
595 struct expression *right;
596 int handled = 0;
598 right = strip_expr(expr->right);
599 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
600 set_extra_expr_mod(expr->left, extra_undefined());
601 return;
603 fn = right->fn->symbol->ident->name;
604 call_backs = search_callback(func_hash, (char *)fn);
606 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
607 handled |= call_call_backs(call_backs, ASSIGN_CALL_EXTRA, fn, expr);
608 handled |= assign_ranged_funcs(fn, expr, call_backs);
609 if (handled)
610 return;
611 handled |= db_return_implies_assign(expr);
612 handled |= db_return_states_assign(expr);
613 if (!handled)
614 set_extra_expr_mod(expr->left, extra_undefined());
617 static int db_return_states_callback(void *unused, int argc, char **argv, char **azColName)
619 struct range_list *ret_range;
620 int type, param;
621 char *key, *value;
622 struct return_implies_callback *tmp;
623 struct state_list *slist;
624 int return_id;
626 if (argc != 6)
627 return 0;
629 return_id = atoi(argv[0]);
630 get_value_ranges(argv[1], &ret_range);
631 type = atoi(argv[2]);
632 param = atoi(argv[3]);
633 key = argv[4];
634 value = argv[5];
636 if (prev_return_id != -1 && return_id != prev_return_id) {
637 slist = __pop_fake_cur_slist();
638 merge_slist(&db_info.slist, slist);
639 __push_fake_cur_slist();
641 prev_return_id = return_id;
643 FOR_EACH_PTR(db_implies_list, tmp) {
644 if (tmp->type == type)
645 tmp->callback(db_info.expr, param, key, value);
646 } END_FOR_EACH_PTR(tmp);
648 return 0;
651 static void db_return_states(struct expression *expr)
653 struct symbol *sym;
654 struct sm_state *sm;
655 struct state_list *slist;
656 static char sql_filter[1024];
658 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
659 return;
661 sym = expr->fn->symbol;
662 if (!sym)
663 return;
665 if (sym->ctype.modifiers & MOD_STATIC) {
666 snprintf(sql_filter, 1024,
667 "file = '%s' and function = '%s' and static = '1';",
668 get_filename(), sym->ident->name);
669 } else {
670 snprintf(sql_filter, 1024,
671 "function = '%s' and static = '0';", sym->ident->name);
674 prev_return_id = -1;
675 db_info.expr = expr;
676 db_info.slist = NULL;
677 __push_fake_cur_slist();
678 run_sql(db_return_states_callback,
679 "select return_id, return, type, parameter, key, value from return_states where %s",
680 sql_filter);
681 slist = __pop_fake_cur_slist();
682 merge_slist(&db_info.slist, slist);
684 FOR_EACH_PTR(db_info.slist, sm) {
685 __set_sm(sm);
686 } END_FOR_EACH_PTR(sm);
689 static int is_assigned_call(struct expression *expr)
691 struct expression *tmp;
693 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
694 if (tmp->type == EXPR_ASSIGNMENT && tmp->right == expr)
695 return 1;
696 if (tmp->pos.line < expr->pos.line)
697 return 0;
698 } END_FOR_EACH_PTR_REVERSE(tmp);
699 return 0;
702 static void db_return_states_call(struct expression *expr)
704 if (is_assigned_call(expr))
705 return;
706 db_return_states(expr);
709 static void match_function_call(struct expression *expr)
711 struct call_back_list *call_backs;
713 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
714 return;
715 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
716 if (call_backs)
717 call_call_backs(call_backs, REGULAR_CALL,
718 expr->fn->symbol->ident->name, expr);
719 db_return_states_call(expr);
722 static void match_macro_assign(struct expression *expr)
724 struct call_back_list *call_backs;
725 const char *macro;
726 struct expression *right;
728 right = strip_expr(expr->right);
729 macro = get_macro_name(right->pos);
730 call_backs = search_callback(func_hash, (char *)macro);
731 if (!call_backs)
732 return;
733 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
734 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
737 void create_function_hook_hash(void)
739 func_hash = create_function_hashtable(5000);
742 void register_function_hooks(int id)
744 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
745 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
746 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);