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 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.
23 #include "smatch_slist.h"
24 #include "smatch_extra.h"
25 #include "smatch_function_hashtable.h"
29 struct data_range
*range
;
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
43 #define ASSIGN_CALL_EXTRA 3
44 #define MACRO_ASSIGN 4
45 #define MACRO_ASSIGN_EXTRA 5
47 struct return_implies_callback
{
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
,
58 struct fcall_back
*cb
;
60 cb
= __alloc_fcall_back(0);
62 cb
->call_back
= call_back
;
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
,
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
,
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
,
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
,
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);
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
;
136 FOR_EACH_PTR(list
, tmp
) {
137 if (tmp
->type
== type
) {
138 (tmp
->call_back
)(fn
, expr
, tmp
->info
);
141 } END_FOR_EACH_PTR(tmp
);
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
)
166 if (tmp
->range
->min
== drange
->min
&& tmp
->range
->max
== drange
->max
)
167 add_ptr_list(&ret
, tmp
);
168 } END_FOR_EACH_PTR(tmp
);
172 static int assign_ranged_funcs(const char *fn
, struct expression
*expr
,
173 struct call_back_list
*call_backs
)
175 struct fcall_back
*tmp
;
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
;
189 var_name
= get_variable_from_expr(expr
->left
, &sym
);
190 if (!var_name
|| !sym
)
193 FOR_EACH_PTR(call_backs
, tmp
) {
194 if (tmp
->type
!= RANGED_CALL
)
196 if (in_list_exact(handled_ranges
, tmp
->range
))
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
);
212 } END_FOR_EACH_PTR(tmp
);
214 FOR_EACH_PTR(final_states
, sm
) {
216 } END_FOR_EACH_PTR(sm
);
218 free_slist(&final_states
);
220 free_string(var_name
);
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
;
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
;
235 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
237 fn
= expr
->fn
->symbol
->ident
->name
;
238 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
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
)
248 if (!true_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
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
)
261 if (!false_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
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
);
281 struct db_callback_info
{
284 struct expression
*expr
;
285 struct range_list
*rl
;
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
;
295 struct return_implies_callback
*tmp
;
300 get_value_ranges(argv
[0], &ret_range
);
301 type
= atoi(argv
[1]);
302 param
= atoi(argv
[2]);
306 if (db_info
.true_side
) {
307 if (!possibly_true_range_lists_rl(db_info
.comparison
,
308 ret_range
, db_info
.rl
,
312 if (!possibly_false_range_lists_rl(db_info
.comparison
,
313 ret_range
, db_info
.rl
,
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
);
325 void compare_db_implies_callbacks(int comparison
, struct expression
*expr
, long long value
, int left
)
328 static char sql_filter
[1024];
329 struct state_list
*true_states
;
330 struct state_list
*false_states
;
333 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
336 sym
= expr
->fn
->symbol
;
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
);
345 snprintf(sql_filter
, 1024,
346 "function = '%s' and static = '0';", sym
->ident
->name
);
349 db_info
.comparison
= comparison
;
351 db_info
.rl
= alloc_range_list(value
, value
);
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",
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",
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
)
382 static char sql_filter
[1024];
383 struct state_list
*true_states
;
384 struct state_list
*false_states
;
387 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
390 sym
= expr
->fn
->symbol
;
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
);
399 snprintf(sql_filter
, 1024,
400 "function = '%s' and static = '0';", sym
->ident
->name
);
403 db_info
.comparison
= comparison
;
405 db_info
.rl
= alloc_range_list(value
, value
);
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",
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",
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
))
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
;
449 struct return_implies_callback
*tmp
;
450 struct state_list
*slist
;
455 get_value_ranges(argv
[0], &ret_range
);
456 type
= atoi(argv
[1]);
457 param
= atoi(argv
[2]);
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
);
474 static int db_return_implies_assign(struct expression
*expr
)
477 static char sql_filter
[1024];
478 static struct sm_state
*sm
;
481 if (expr
->right
->fn
->type
!= EXPR_SYMBOL
|| !expr
->right
->fn
->symbol
)
484 sym
= expr
->right
->fn
->symbol
;
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
);
493 snprintf(sql_filter
, 1024,
494 "function = '%s' and static = '0';", sym
->ident
->name
);
498 db_info
.slist
= NULL
;
499 run_sql(db_assign_callback
,
500 "select return, type, parameter, key, value from return_implies where %s",
503 FOR_EACH_PTR(db_info
.slist
, sm
) {
506 } END_FOR_EACH_PTR(sm
);
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
;
517 struct return_implies_callback
*tmp
;
518 struct state_list
*slist
;
524 return_id
= atoi(argv
[0]);
525 get_value_ranges(argv
[1], &ret_range
);
527 ret_range
= whole_range_list();
528 type
= atoi(argv
[2]);
529 param
= atoi(argv
[3]);
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
));
549 static int db_return_states_assign(struct expression
*expr
)
553 struct state_list
*slist
;
554 static char sql_filter
[1024];
557 if (expr
->right
->fn
->type
!= EXPR_SYMBOL
|| !expr
->right
->fn
->symbol
)
560 sym
= expr
->right
->fn
->symbol
;
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
);
569 snprintf(sql_filter
, 1024,
570 "function = '%s' and static = '0';", sym
->ident
->name
);
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",
580 slist
= __pop_fake_cur_slist();
581 merge_slist(&db_info
.slist
, slist
);
583 FOR_EACH_PTR(db_info
.slist
, sm
) {
586 } END_FOR_EACH_PTR(sm
);
591 static void match_assign_call(struct expression
*expr
)
593 struct call_back_list
*call_backs
;
595 struct expression
*right
;
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());
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
);
611 handled
|= db_return_implies_assign(expr
);
612 handled
|= db_return_states_assign(expr
);
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
;
622 struct return_implies_callback
*tmp
;
623 struct state_list
*slist
;
629 return_id
= atoi(argv
[0]);
630 get_value_ranges(argv
[1], &ret_range
);
631 type
= atoi(argv
[2]);
632 param
= atoi(argv
[3]);
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
);
651 static void db_return_states(struct expression
*expr
)
655 struct state_list
*slist
;
656 static char sql_filter
[1024];
658 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
661 sym
= expr
->fn
->symbol
;
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
);
670 snprintf(sql_filter
, 1024,
671 "function = '%s' and static = '0';", sym
->ident
->name
);
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",
681 slist
= __pop_fake_cur_slist();
682 merge_slist(&db_info
.slist
, slist
);
684 FOR_EACH_PTR(db_info
.slist
, 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
)
696 if (tmp
->pos
.line
< expr
->pos
.line
)
698 } END_FOR_EACH_PTR_REVERSE(tmp
);
702 static void db_return_states_call(struct expression
*expr
)
704 if (is_assigned_call(expr
))
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
)
715 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
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
;
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
);
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
);