db/return_states: fix return values for USER_DATA
[smatch.git] / smatch_function_hooks.c
blobcdc7ca21f618f5803ea15c1c87926389da2f5f7d
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 several 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_implied_return_hook() - Calculates the implied return value.
15 * add_macro_assign_hook() - foo = the_macro().
16 * return_implies_state() - For when a return value of 1 implies locked
17 * and 0 implies unlocked. etc. etc.
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "smatch.h"
24 #include "smatch_slist.h"
25 #include "smatch_extra.h"
26 #include "smatch_function_hashtable.h"
28 struct fcall_back {
29 int type;
30 struct data_range *range;
31 union {
32 func_hook *call_back;
33 implication_hook *ranged;
34 implied_return_hook *implied_return;
35 } u;
36 void *info;
39 ALLOCATOR(fcall_back, "call backs");
40 DECLARE_PTR_LIST(call_back_list, struct fcall_back);
42 DEFINE_FUNCTION_HASHTABLE_STATIC(callback, struct fcall_back, struct call_back_list);
43 static struct hashtable *func_hash;
45 #define REGULAR_CALL 0
46 #define RANGED_CALL 1
47 #define ASSIGN_CALL 2
48 #define IMPLIED_RETURN 3
49 #define MACRO_ASSIGN 4
50 #define MACRO_ASSIGN_EXTRA 5
52 struct return_implies_callback {
53 int type;
54 return_implies_hook *callback;
56 ALLOCATOR(return_implies_callback, "return_implies callbacks");
57 DECLARE_PTR_LIST(db_implies_list, struct return_implies_callback);
58 static struct db_implies_list *db_implies_list;
60 static struct fcall_back *alloc_fcall_back(int type, void *call_back,
61 void *info)
63 struct fcall_back *cb;
65 cb = __alloc_fcall_back(0);
66 cb->type = type;
67 cb->u.call_back = call_back;
68 cb->info = info;
69 return cb;
72 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
74 struct fcall_back *cb;
76 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
77 add_callback(func_hash, look_for, cb);
80 void add_function_assign_hook(const char *look_for, func_hook *call_back,
81 void *info)
83 struct fcall_back *cb;
85 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
86 add_callback(func_hash, look_for, cb);
89 void add_implied_return_hook(const char *look_for,
90 implied_return_hook *call_back,
91 void *info)
93 struct fcall_back *cb;
95 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
96 add_callback(func_hash, look_for, cb);
99 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
100 void *info)
102 struct fcall_back *cb;
104 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
105 add_callback(func_hash, look_for, cb);
108 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
109 void *info)
111 struct fcall_back *cb;
113 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
114 add_callback(func_hash, look_for, cb);
117 void return_implies_state(const char *look_for, long long start, long long end,
118 implication_hook *call_back, void *info)
120 struct fcall_back *cb;
122 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
123 cb->range = alloc_range_perm(start, end);
124 add_callback(func_hash, look_for, cb);
127 void add_db_return_implies_callback(int type, return_implies_hook *callback)
129 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
131 cb->type = type;
132 cb->callback = callback;
133 add_ptr_list(&db_implies_list, cb);
136 static int call_call_backs(struct call_back_list *list, int type,
137 const char *fn, struct expression *expr)
139 struct fcall_back *tmp;
140 int handled = 0;
142 FOR_EACH_PTR(list, tmp) {
143 if (tmp->type == type) {
144 (tmp->u.call_back)(fn, expr, tmp->info);
145 handled = 1;
147 } END_FOR_EACH_PTR(tmp);
149 return handled;
152 static void call_ranged_call_backs(struct call_back_list *list,
153 const char *fn, struct expression *call_expr,
154 struct expression *assign_expr)
156 struct fcall_back *tmp;
158 FOR_EACH_PTR(list, tmp) {
159 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
160 } END_FOR_EACH_PTR(tmp);
163 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
164 struct data_range *drange)
166 struct call_back_list *ret = NULL;
167 struct fcall_back *tmp;
169 FOR_EACH_PTR(list, tmp) {
170 if (tmp->type != RANGED_CALL)
171 continue;
172 if (tmp->range->min == drange->min && tmp->range->max == drange->max)
173 add_ptr_list(&ret, tmp);
174 } END_FOR_EACH_PTR(tmp);
175 return ret;
178 static int assign_ranged_funcs(const char *fn, struct expression *expr,
179 struct call_back_list *call_backs)
181 struct fcall_back *tmp;
182 struct sm_state *sm;
183 char *var_name;
184 struct symbol *sym;
185 struct smatch_state *estate;
186 struct state_list *tmp_slist;
187 struct state_list *final_states = NULL;
188 struct range_list *handled_ranges = NULL;
189 struct call_back_list *same_range_call_backs = NULL;
190 int handled = 0;
192 if (!call_backs)
193 return 0;
195 var_name = get_variable_from_expr(expr->left, &sym);
196 if (!var_name || !sym)
197 goto free;
199 FOR_EACH_PTR(call_backs, tmp) {
200 if (tmp->type != RANGED_CALL)
201 continue;
202 if (in_list_exact(handled_ranges, tmp->range))
203 continue;
204 __push_fake_cur_slist();
205 tack_on(&handled_ranges, tmp->range);
207 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
208 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
209 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
211 estate = alloc_estate_range(tmp->range->min, tmp->range->max);
212 set_extra_mod(var_name, sym, estate);
214 tmp_slist = __pop_fake_cur_slist();
215 merge_slist(&final_states, tmp_slist);
216 free_slist(&tmp_slist);
217 handled = 1;
218 } END_FOR_EACH_PTR(tmp);
220 FOR_EACH_PTR(final_states, sm) {
221 __set_sm(sm);
222 } END_FOR_EACH_PTR(sm);
224 free_slist(&final_states);
225 free:
226 free_string(var_name);
227 return handled;
230 int call_implies_callbacks(int comparison, struct expression *expr, long long value, int left)
232 struct call_back_list *call_backs;
233 struct fcall_back *tmp;
234 const char *fn;
235 struct data_range *value_range;
236 struct state_list *true_states = NULL;
237 struct state_list *false_states = NULL;
238 struct state_list *tmp_slist;
239 struct sm_state *sm;
241 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
242 return 0;
243 fn = expr->fn->symbol->ident->name;
244 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
245 if (!call_backs)
246 return 0;
247 value_range = alloc_range(value, value);
249 /* set true states */
250 __push_fake_cur_slist();
251 FOR_EACH_PTR(call_backs, tmp) {
252 if (tmp->type != RANGED_CALL)
253 continue;
254 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
255 continue;
256 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
257 } END_FOR_EACH_PTR(tmp);
258 tmp_slist = __pop_fake_cur_slist();
259 merge_slist(&true_states, tmp_slist);
260 free_slist(&tmp_slist);
262 /* set false states */
263 __push_fake_cur_slist();
264 FOR_EACH_PTR(call_backs, tmp) {
265 if (tmp->type != RANGED_CALL)
266 continue;
267 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
268 continue;
269 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
270 } END_FOR_EACH_PTR(tmp);
271 tmp_slist = __pop_fake_cur_slist();
272 merge_slist(&false_states, tmp_slist);
273 free_slist(&tmp_slist);
275 FOR_EACH_PTR(true_states, sm) {
276 __set_true_false_sm(sm, NULL);
277 } END_FOR_EACH_PTR(sm);
278 FOR_EACH_PTR(false_states, sm) {
279 __set_true_false_sm(NULL, sm);
280 } END_FOR_EACH_PTR(sm);
282 free_slist(&true_states);
283 free_slist(&false_states);
284 return 1;
287 struct db_callback_info {
288 int true_side;
289 int comparison;
290 struct expression *expr;
291 struct range_list *rl;
292 int left;
293 struct state_list *slist;
295 static struct db_callback_info db_info;
296 static int db_compare_callback(void *unused, int argc, char **argv, char **azColName)
298 struct range_list *ret_range;
299 int type, param;
300 char *key, *value;
301 struct return_implies_callback *tmp;
303 if (argc != 5)
304 return 0;
306 get_value_ranges(argv[0], &ret_range);
307 type = atoi(argv[1]);
308 param = atoi(argv[2]);
309 key = argv[3];
310 value = argv[4];
312 if (db_info.true_side) {
313 if (!possibly_true_range_lists_rl(db_info.comparison,
314 ret_range, db_info.rl,
315 db_info.left))
316 return 0;
317 } else {
318 if (!possibly_false_range_lists_rl(db_info.comparison,
319 ret_range, db_info.rl,
320 db_info.left))
321 return 0;
324 FOR_EACH_PTR(db_implies_list, tmp) {
325 if (tmp->type == type)
326 tmp->callback(db_info.expr, param, key, value);
327 } END_FOR_EACH_PTR(tmp);
328 return 0;
331 void compare_db_implies_callbacks(int comparison, struct expression *expr, long long value, int left)
333 struct symbol *sym;
334 static char sql_filter[1024];
335 struct state_list *true_states;
336 struct state_list *false_states;
337 struct sm_state *sm;
339 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
340 return;
342 sym = expr->fn->symbol;
343 if (!sym)
344 return;
346 if (sym->ctype.modifiers & MOD_STATIC) {
347 snprintf(sql_filter, 1024,
348 "file = '%s' and function = '%s' and static = '1';",
349 get_filename(), sym->ident->name);
350 } else {
351 snprintf(sql_filter, 1024,
352 "function = '%s' and static = '0';", sym->ident->name);
355 db_info.comparison = comparison;
356 db_info.expr = expr;
357 db_info.rl = alloc_range_list(value, value);
358 db_info.left = left;
360 db_info.true_side = 1;
361 __push_fake_cur_slist();
362 run_sql(db_compare_callback,
363 "select return, type, parameter, key, value from return_implies where %s",
364 sql_filter);
365 true_states = __pop_fake_cur_slist();
367 db_info.true_side = 0;
368 __push_fake_cur_slist();
369 run_sql(db_compare_callback,
370 "select return, type, parameter, key, value from return_implies where %s",
371 sql_filter);
372 false_states = __pop_fake_cur_slist();
374 FOR_EACH_PTR(true_states, sm) {
375 __set_true_false_sm(sm, NULL);
376 } END_FOR_EACH_PTR(sm);
377 FOR_EACH_PTR(false_states, sm) {
378 __set_true_false_sm(NULL, sm);
379 } END_FOR_EACH_PTR(sm);
381 free_slist(&true_states);
382 free_slist(&false_states);
385 void compare_db_return_states_callbacks(int comparison, struct expression *expr, long long value, int left)
387 struct symbol *sym;
388 static char sql_filter[1024];
389 struct state_list *true_states;
390 struct state_list *false_states;
391 struct sm_state *sm;
393 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
394 return;
396 sym = expr->fn->symbol;
397 if (!sym)
398 return;
400 if (sym->ctype.modifiers & MOD_STATIC) {
401 snprintf(sql_filter, 1024,
402 "file = '%s' and function = '%s' and static = '1';",
403 get_filename(), sym->ident->name);
404 } else {
405 snprintf(sql_filter, 1024,
406 "function = '%s' and static = '0';", sym->ident->name);
409 db_info.comparison = comparison;
410 db_info.expr = expr;
411 db_info.rl = alloc_range_list(value, value);
412 db_info.left = left;
414 db_info.true_side = 1;
415 __push_fake_cur_slist();
416 run_sql(db_compare_callback,
417 "select return, type, parameter, key, value from return_states where %s",
418 sql_filter);
419 true_states = __pop_fake_cur_slist();
421 db_info.true_side = 0;
422 __push_fake_cur_slist();
423 run_sql(db_compare_callback,
424 "select return, type, parameter, key, value from return_states where %s",
425 sql_filter);
426 false_states = __pop_fake_cur_slist();
428 FOR_EACH_PTR(true_states, sm) {
429 __set_true_false_sm(sm, NULL);
430 } END_FOR_EACH_PTR(sm);
431 FOR_EACH_PTR(false_states, sm) {
432 __set_true_false_sm(NULL, sm);
433 } END_FOR_EACH_PTR(sm);
435 free_slist(&true_states);
436 free_slist(&false_states);
441 void function_comparison(int comparison, struct expression *expr,
442 long long value, int left)
444 if (call_implies_callbacks(comparison, expr, value, left))
445 return;
446 compare_db_implies_callbacks(comparison, expr, value, left);
447 compare_db_return_states_callbacks(comparison, expr, value, left);
450 static int db_assign_callback(void *unused, int argc, char **argv, char **azColName)
452 struct range_list *ret_range;
453 int type, param;
454 char *key, *value;
455 struct return_implies_callback *tmp;
456 struct state_list *slist;
458 if (argc != 5)
459 return 0;
461 get_value_ranges(argv[0], &ret_range);
462 type = atoi(argv[1]);
463 param = atoi(argv[2]);
464 key = argv[3];
465 value = argv[4];
467 __push_fake_cur_slist();
468 FOR_EACH_PTR(db_implies_list, tmp) {
469 if (tmp->type == type)
470 tmp->callback(db_info.expr->right, param, key, value);
471 } END_FOR_EACH_PTR(tmp);
472 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
473 slist = __pop_fake_cur_slist();
475 merge_slist(&db_info.slist, slist);
477 return 0;
480 static int db_return_implies_assign(struct expression *expr)
482 struct symbol *sym;
483 static char sql_filter[1024];
484 static struct sm_state *sm;
485 int handled = 0;
487 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
488 return 0;
490 sym = expr->right->fn->symbol;
491 if (!sym)
492 return 0;
494 if (sym->ctype.modifiers & MOD_STATIC) {
495 snprintf(sql_filter, 1024,
496 "file = '%s' and function = '%s' and static = '1';",
497 get_filename(), sym->ident->name);
498 } else {
499 snprintf(sql_filter, 1024,
500 "function = '%s' and static = '0';", sym->ident->name);
503 db_info.expr = expr;
504 db_info.slist = NULL;
505 run_sql(db_assign_callback,
506 "select return, type, parameter, key, value from return_implies where %s",
507 sql_filter);
509 FOR_EACH_PTR(db_info.slist, sm) {
510 __set_sm(sm);
511 handled = 1;
512 } END_FOR_EACH_PTR(sm);
514 return handled;
517 static int prev_return_id;
518 static int db_assign_return_states_callback(void *unused, int argc, char **argv, char **azColName)
520 struct range_list *ret_range;
521 int type, param;
522 char *key, *value;
523 struct return_implies_callback *tmp;
524 struct state_list *slist;
525 int return_id;
527 if (argc != 6)
528 return 0;
530 return_id = atoi(argv[0]);
531 get_value_ranges(argv[1], &ret_range);
532 if (!ret_range)
533 ret_range = whole_range_list();
534 type = atoi(argv[2]);
535 param = atoi(argv[3]);
536 key = argv[4];
537 value = argv[5];
539 if (prev_return_id != -1 && return_id != prev_return_id) {
540 slist = __pop_fake_cur_slist();
541 merge_slist(&db_info.slist, slist);
542 __push_fake_cur_slist();
544 prev_return_id = return_id;
546 FOR_EACH_PTR(db_implies_list, tmp) {
547 if (tmp->type == type)
548 tmp->callback(db_info.expr, param, key, value);
549 } END_FOR_EACH_PTR(tmp);
550 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
552 return 0;
555 static int db_return_states_assign(struct expression *expr)
557 struct symbol *sym;
558 struct sm_state *sm;
559 struct state_list *slist;
560 static char sql_filter[1024];
561 int handled = 0;
563 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
564 return 0;
566 sym = expr->right->fn->symbol;
567 if (!sym)
568 return 0;
570 if (sym->ctype.modifiers & MOD_STATIC) {
571 snprintf(sql_filter, 1024,
572 "file = '%s' and function = '%s' and static = '1';",
573 get_filename(), sym->ident->name);
574 } else {
575 snprintf(sql_filter, 1024,
576 "function = '%s' and static = '0';", sym->ident->name);
579 prev_return_id = -1;
580 db_info.expr = expr;
581 db_info.slist = NULL;
582 __push_fake_cur_slist();
583 run_sql(db_assign_return_states_callback,
584 "select return_id, return, type, parameter, key, value from return_states where %s",
585 sql_filter);
586 slist = __pop_fake_cur_slist();
587 merge_slist(&db_info.slist, slist);
589 FOR_EACH_PTR(db_info.slist, sm) {
590 __set_sm(sm);
591 handled = 1;
592 } END_FOR_EACH_PTR(sm);
594 return handled;
597 static int handle_implied_return(struct expression *expr)
599 struct range_list *rl;
601 if (!get_implied_return(expr->right, &rl))
602 return 0;
603 set_extra_expr_mod(expr->left, alloc_estate_range_list(rl));
604 return 1;
607 static void match_assign_call(struct expression *expr)
609 struct call_back_list *call_backs;
610 const char *fn;
611 struct expression *right;
612 int handled = 0;
614 right = strip_expr(expr->right);
615 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
616 set_extra_expr_mod(expr->left, extra_undefined());
617 return;
619 fn = right->fn->symbol->ident->name;
620 call_backs = search_callback(func_hash, (char *)fn);
622 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
623 handled |= handle_implied_return(expr);
624 handled |= assign_ranged_funcs(fn, expr, call_backs);
625 if (handled)
626 return;
627 handled |= db_return_implies_assign(expr);
628 handled |= db_return_states_assign(expr);
629 if (!handled)
630 set_extra_expr_mod(expr->left, extra_undefined());
633 static int db_return_states_callback(void *unused, int argc, char **argv, char **azColName)
635 struct range_list *ret_range;
636 int type, param;
637 char *key, *value;
638 struct return_implies_callback *tmp;
639 struct state_list *slist;
640 int return_id;
642 if (argc != 6)
643 return 0;
645 return_id = atoi(argv[0]);
646 get_value_ranges(argv[1], &ret_range);
647 type = atoi(argv[2]);
648 param = atoi(argv[3]);
649 key = argv[4];
650 value = argv[5];
652 if (prev_return_id != -1 && return_id != prev_return_id) {
653 slist = __pop_fake_cur_slist();
654 merge_slist(&db_info.slist, slist);
655 __push_fake_cur_slist();
657 prev_return_id = return_id;
659 FOR_EACH_PTR(db_implies_list, tmp) {
660 if (tmp->type == type)
661 tmp->callback(db_info.expr, param, key, value);
662 } END_FOR_EACH_PTR(tmp);
664 return 0;
667 static void db_return_states(struct expression *expr)
669 struct symbol *sym;
670 struct sm_state *sm;
671 struct state_list *slist;
672 static char sql_filter[1024];
674 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
675 return;
677 sym = expr->fn->symbol;
678 if (!sym)
679 return;
681 if (sym->ctype.modifiers & MOD_STATIC) {
682 snprintf(sql_filter, 1024,
683 "file = '%s' and function = '%s' and static = '1';",
684 get_filename(), sym->ident->name);
685 } else {
686 snprintf(sql_filter, 1024,
687 "function = '%s' and static = '0';", sym->ident->name);
690 prev_return_id = -1;
691 db_info.expr = expr;
692 db_info.slist = NULL;
693 __push_fake_cur_slist();
694 run_sql(db_return_states_callback,
695 "select return_id, return, type, parameter, key, value from return_states where %s",
696 sql_filter);
697 slist = __pop_fake_cur_slist();
698 merge_slist(&db_info.slist, slist);
700 FOR_EACH_PTR(db_info.slist, sm) {
701 __set_sm(sm);
702 } END_FOR_EACH_PTR(sm);
705 static int is_assigned_call(struct expression *expr)
707 struct expression *tmp;
709 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
710 if (tmp->type == EXPR_ASSIGNMENT && tmp->right == expr)
711 return 1;
712 if (tmp->pos.line < expr->pos.line)
713 return 0;
714 } END_FOR_EACH_PTR_REVERSE(tmp);
715 return 0;
718 static void db_return_states_call(struct expression *expr)
720 if (is_assigned_call(expr))
721 return;
722 db_return_states(expr);
725 static void match_function_call(struct expression *expr)
727 struct call_back_list *call_backs;
729 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
730 return;
731 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
732 if (call_backs)
733 call_call_backs(call_backs, REGULAR_CALL,
734 expr->fn->symbol->ident->name, expr);
735 db_return_states_call(expr);
738 static void match_macro_assign(struct expression *expr)
740 struct call_back_list *call_backs;
741 const char *macro;
742 struct expression *right;
744 right = strip_expr(expr->right);
745 macro = get_macro_name(right->pos);
746 call_backs = search_callback(func_hash, (char *)macro);
747 if (!call_backs)
748 return;
749 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
750 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
753 int get_implied_return(struct expression *expr, struct range_list **rl)
755 struct call_back_list *call_backs;
756 struct fcall_back *tmp;
757 int handled = 0;
758 char *fn;
760 *rl = NULL;
762 expr = strip_expr(expr);
763 fn = get_variable_from_expr(expr->fn, NULL);
764 if (!fn)
765 goto out;
767 call_backs = search_callback(func_hash, fn);
769 FOR_EACH_PTR(call_backs, tmp) {
770 if (tmp->type == IMPLIED_RETURN) {
771 (tmp->u.implied_return)(expr, tmp->info, rl);
772 handled = 1;
774 } END_FOR_EACH_PTR(tmp);
776 out:
777 free_string(fn);
778 return handled;
781 void create_function_hook_hash(void)
783 func_hash = create_function_hashtable(5000);
786 void register_function_hooks(int id)
788 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
789 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
790 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);