2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
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.
24 #include "smatch_slist.h"
25 #include "smatch_extra.h"
26 #include "smatch_function_hashtable.h"
30 struct data_range
*range
;
33 implication_hook
*ranged
;
34 implied_return_hook
*implied_return
;
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
48 #define IMPLIED_RETURN 3
49 #define MACRO_ASSIGN 4
50 #define MACRO_ASSIGN_EXTRA 5
52 struct return_implies_callback
{
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
,
63 struct fcall_back
*cb
;
65 cb
= __alloc_fcall_back(0);
67 cb
->u
.call_back
= call_back
;
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
,
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
,
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
,
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
,
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);
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
;
142 FOR_EACH_PTR(list
, tmp
) {
143 if (tmp
->type
== type
) {
144 (tmp
->u
.call_back
)(fn
, expr
, tmp
->info
);
147 } END_FOR_EACH_PTR(tmp
);
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
)
172 if (tmp
->range
->min
== drange
->min
&& tmp
->range
->max
== drange
->max
)
173 add_ptr_list(&ret
, tmp
);
174 } END_FOR_EACH_PTR(tmp
);
178 static int assign_ranged_funcs(const char *fn
, struct expression
*expr
,
179 struct call_back_list
*call_backs
)
181 struct fcall_back
*tmp
;
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
;
195 var_name
= get_variable_from_expr(expr
->left
, &sym
);
196 if (!var_name
|| !sym
)
199 FOR_EACH_PTR(call_backs
, tmp
) {
200 if (tmp
->type
!= RANGED_CALL
)
202 if (in_list_exact(handled_ranges
, tmp
->range
))
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
);
218 } END_FOR_EACH_PTR(tmp
);
220 FOR_EACH_PTR(final_states
, sm
) {
222 } END_FOR_EACH_PTR(sm
);
224 free_slist(&final_states
);
226 free_string(var_name
);
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
;
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
;
241 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
243 fn
= expr
->fn
->symbol
->ident
->name
;
244 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
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
)
254 if (!true_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
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
)
267 if (!false_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
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
);
287 struct db_callback_info
{
290 struct expression
*expr
;
291 struct range_list
*rl
;
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
;
301 struct return_implies_callback
*tmp
;
306 get_value_ranges(argv
[0], &ret_range
);
307 type
= atoi(argv
[1]);
308 param
= atoi(argv
[2]);
312 if (db_info
.true_side
) {
313 if (!possibly_true_range_lists_rl(db_info
.comparison
,
314 ret_range
, db_info
.rl
,
318 if (!possibly_false_range_lists_rl(db_info
.comparison
,
319 ret_range
, db_info
.rl
,
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
);
331 void compare_db_implies_callbacks(int comparison
, struct expression
*expr
, long long value
, int left
)
334 static char sql_filter
[1024];
335 struct state_list
*true_states
;
336 struct state_list
*false_states
;
339 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
342 sym
= expr
->fn
->symbol
;
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
);
351 snprintf(sql_filter
, 1024,
352 "function = '%s' and static = '0';", sym
->ident
->name
);
355 db_info
.comparison
= comparison
;
357 db_info
.rl
= alloc_range_list(value
, value
);
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",
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",
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
)
388 static char sql_filter
[1024];
389 struct state_list
*true_states
;
390 struct state_list
*false_states
;
393 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
396 sym
= expr
->fn
->symbol
;
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
);
405 snprintf(sql_filter
, 1024,
406 "function = '%s' and static = '0';", sym
->ident
->name
);
409 db_info
.comparison
= comparison
;
411 db_info
.rl
= alloc_range_list(value
, value
);
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",
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",
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
))
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
;
455 struct return_implies_callback
*tmp
;
456 struct state_list
*slist
;
461 get_value_ranges(argv
[0], &ret_range
);
462 type
= atoi(argv
[1]);
463 param
= atoi(argv
[2]);
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
);
480 static int db_return_implies_assign(struct expression
*expr
)
483 static char sql_filter
[1024];
484 static struct sm_state
*sm
;
487 if (expr
->right
->fn
->type
!= EXPR_SYMBOL
|| !expr
->right
->fn
->symbol
)
490 sym
= expr
->right
->fn
->symbol
;
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
);
499 snprintf(sql_filter
, 1024,
500 "function = '%s' and static = '0';", sym
->ident
->name
);
504 db_info
.slist
= NULL
;
505 run_sql(db_assign_callback
,
506 "select return, type, parameter, key, value from return_implies where %s",
509 FOR_EACH_PTR(db_info
.slist
, sm
) {
512 } END_FOR_EACH_PTR(sm
);
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
;
523 struct return_implies_callback
*tmp
;
524 struct state_list
*slist
;
530 return_id
= atoi(argv
[0]);
531 get_value_ranges(argv
[1], &ret_range
);
533 ret_range
= whole_range_list();
534 type
= atoi(argv
[2]);
535 param
= atoi(argv
[3]);
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
));
555 static int db_return_states_assign(struct expression
*expr
)
559 struct state_list
*slist
;
560 static char sql_filter
[1024];
563 if (expr
->right
->fn
->type
!= EXPR_SYMBOL
|| !expr
->right
->fn
->symbol
)
566 sym
= expr
->right
->fn
->symbol
;
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
);
575 snprintf(sql_filter
, 1024,
576 "function = '%s' and static = '0';", sym
->ident
->name
);
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",
586 slist
= __pop_fake_cur_slist();
587 merge_slist(&db_info
.slist
, slist
);
589 FOR_EACH_PTR(db_info
.slist
, sm
) {
592 } END_FOR_EACH_PTR(sm
);
597 static int handle_implied_return(struct expression
*expr
)
599 struct range_list
*rl
;
601 if (!get_implied_return(expr
->right
, &rl
))
603 set_extra_expr_mod(expr
->left
, alloc_estate_range_list(rl
));
607 static void match_assign_call(struct expression
*expr
)
609 struct call_back_list
*call_backs
;
611 struct expression
*right
;
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());
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
);
627 handled
|= db_return_implies_assign(expr
);
628 handled
|= db_return_states_assign(expr
);
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
;
638 struct return_implies_callback
*tmp
;
639 struct state_list
*slist
;
645 return_id
= atoi(argv
[0]);
646 get_value_ranges(argv
[1], &ret_range
);
647 type
= atoi(argv
[2]);
648 param
= atoi(argv
[3]);
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
);
667 static void db_return_states(struct expression
*expr
)
671 struct state_list
*slist
;
672 static char sql_filter
[1024];
674 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
677 sym
= expr
->fn
->symbol
;
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
);
686 snprintf(sql_filter
, 1024,
687 "function = '%s' and static = '0';", sym
->ident
->name
);
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",
697 slist
= __pop_fake_cur_slist();
698 merge_slist(&db_info
.slist
, slist
);
700 FOR_EACH_PTR(db_info
.slist
, 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
)
712 if (tmp
->pos
.line
< expr
->pos
.line
)
714 } END_FOR_EACH_PTR_REVERSE(tmp
);
718 static void db_return_states_call(struct expression
*expr
)
720 if (is_assigned_call(expr
))
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
)
731 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
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
;
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
);
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
;
762 expr
= strip_expr(expr
);
763 fn
= get_variable_from_expr(expr
->fn
, NULL
);
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
);
774 } END_FOR_EACH_PTR(tmp
);
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
);