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 MACRO_ASSIGN 3
45 struct return_implies_callback
{
47 return_implies_hook
*callback
;
49 ALLOCATOR(return_implies_callback
, "return_implies callbacks");
50 DECLARE_PTR_LIST(db_implies_list
, struct return_implies_callback
);
51 static struct db_implies_list
*db_implies_list
;
53 static struct fcall_back
*alloc_fcall_back(int type
, func_hook
*call_back
,
56 struct fcall_back
*cb
;
58 cb
= __alloc_fcall_back(0);
60 cb
->call_back
= call_back
;
65 void add_function_hook(const char *look_for
, func_hook
*call_back
, void *info
)
67 struct fcall_back
*cb
;
69 cb
= alloc_fcall_back(REGULAR_CALL
, call_back
, info
);
70 add_callback(func_hash
, look_for
, cb
);
73 void add_function_assign_hook(const char *look_for
, func_hook
*call_back
,
76 struct fcall_back
*cb
;
78 cb
= alloc_fcall_back(ASSIGN_CALL
, call_back
, info
);
79 add_callback(func_hash
, look_for
, cb
);
82 void add_macro_assign_hook(const char *look_for
, func_hook
*call_back
,
85 struct fcall_back
*cb
;
87 cb
= alloc_fcall_back(MACRO_ASSIGN
, call_back
, info
);
88 add_callback(func_hash
, look_for
, cb
);
91 void return_implies_state(const char *look_for
, long long start
, long long end
,
92 implication_hook
*call_back
, void *info
)
94 struct fcall_back
*cb
;
96 cb
= alloc_fcall_back(RANGED_CALL
, (func_hook
*)call_back
, info
);
97 cb
->range
= alloc_range_perm(start
, end
);
98 add_callback(func_hash
, look_for
, cb
);
101 void add_db_return_implies_callback(int type
, return_implies_hook
*callback
)
103 struct return_implies_callback
*cb
= __alloc_return_implies_callback(0);
106 cb
->callback
= callback
;
107 add_ptr_list(&db_implies_list
, cb
);
110 static void call_call_backs(struct call_back_list
*list
, int type
,
111 const char *fn
, struct expression
*expr
)
113 struct fcall_back
*tmp
;
115 FOR_EACH_PTR(list
, tmp
) {
116 if (tmp
->type
== type
)
117 (tmp
->call_back
)(fn
, expr
, tmp
->info
);
118 } END_FOR_EACH_PTR(tmp
);
121 static void call_ranged_call_backs(struct call_back_list
*list
,
122 const char *fn
, struct expression
*call_expr
,
123 struct expression
*assign_expr
)
125 struct fcall_back
*tmp
;
127 FOR_EACH_PTR(list
, tmp
) {
128 ((implication_hook
*)(tmp
->call_back
))(fn
, call_expr
, assign_expr
, tmp
->info
);
129 } END_FOR_EACH_PTR(tmp
);
132 static void match_function_call(struct expression
*expr
)
134 struct call_back_list
*call_backs
;
136 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
138 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
141 call_call_backs(call_backs
, REGULAR_CALL
, expr
->fn
->symbol
->ident
->name
,
145 static struct call_back_list
*get_same_ranged_call_backs(struct call_back_list
*list
,
146 struct data_range
*drange
)
148 struct call_back_list
*ret
= NULL
;
149 struct fcall_back
*tmp
;
151 FOR_EACH_PTR(list
, tmp
) {
152 if (tmp
->type
!= RANGED_CALL
)
154 if (tmp
->range
->min
== drange
->min
&& tmp
->range
->max
== drange
->max
)
155 add_ptr_list(&ret
, tmp
);
156 } END_FOR_EACH_PTR(tmp
);
160 static void assign_ranged_funcs(const char *fn
, struct expression
*expr
,
161 struct call_back_list
*call_backs
)
163 struct fcall_back
*tmp
;
167 struct smatch_state
*estate
;
168 struct state_list
*tmp_slist
;
169 struct state_list
*final_states
= NULL
;
170 struct range_list
*handled_ranges
= NULL
;
171 struct call_back_list
*same_range_call_backs
= NULL
;
173 var_name
= get_variable_from_expr(expr
->left
, &sym
);
174 if (!var_name
|| !sym
)
177 FOR_EACH_PTR(call_backs
, tmp
) {
178 if (tmp
->type
!= RANGED_CALL
)
180 if (in_list_exact(handled_ranges
, tmp
->range
))
182 __push_fake_cur_slist();
183 tack_on(&handled_ranges
, tmp
->range
);
185 same_range_call_backs
= get_same_ranged_call_backs(call_backs
, tmp
->range
);
186 call_ranged_call_backs(same_range_call_backs
, fn
, expr
->right
, expr
);
187 __free_ptr_list((struct ptr_list
**)&same_range_call_backs
);
189 estate
= alloc_estate_range(tmp
->range
->min
, tmp
->range
->max
);
190 set_extra_mod(var_name
, sym
, estate
);
192 tmp_slist
= __pop_fake_cur_slist();
193 merge_slist(&final_states
, tmp_slist
);
194 free_slist(&tmp_slist
);
195 } END_FOR_EACH_PTR(tmp
);
197 FOR_EACH_PTR(final_states
, sm
) {
199 } END_FOR_EACH_PTR(sm
);
201 free_slist(&final_states
);
203 free_string(var_name
);
206 int call_implies_callbacks(int comparison
, struct expression
*expr
, long long value
, int left
)
208 struct call_back_list
*call_backs
;
209 struct fcall_back
*tmp
;
211 struct data_range
*value_range
;
212 struct state_list
*true_states
= NULL
;
213 struct state_list
*false_states
= NULL
;
214 struct state_list
*tmp_slist
;
217 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
219 fn
= expr
->fn
->symbol
->ident
->name
;
220 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
223 value_range
= alloc_range(value
, value
);
225 /* set true states */
226 __push_fake_cur_slist();
227 FOR_EACH_PTR(call_backs
, tmp
) {
228 if (tmp
->type
!= RANGED_CALL
)
230 if (!true_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
232 ((implication_hook
*)(tmp
->call_back
))(fn
, expr
, NULL
, tmp
->info
);
233 } END_FOR_EACH_PTR(tmp
);
234 tmp_slist
= __pop_fake_cur_slist();
235 merge_slist(&true_states
, tmp_slist
);
236 free_slist(&tmp_slist
);
238 /* set false states */
239 __push_fake_cur_slist();
240 FOR_EACH_PTR(call_backs
, tmp
) {
241 if (tmp
->type
!= RANGED_CALL
)
243 if (!false_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
245 ((implication_hook
*)(tmp
->call_back
))(fn
, expr
, NULL
, tmp
->info
);
246 } END_FOR_EACH_PTR(tmp
);
247 tmp_slist
= __pop_fake_cur_slist();
248 merge_slist(&false_states
, tmp_slist
);
249 free_slist(&tmp_slist
);
251 FOR_EACH_PTR(true_states
, sm
) {
252 __set_true_false_sm(sm
, NULL
);
253 } END_FOR_EACH_PTR(sm
);
254 FOR_EACH_PTR(false_states
, sm
) {
255 __set_true_false_sm(NULL
, sm
);
256 } END_FOR_EACH_PTR(sm
);
258 free_slist(&true_states
);
259 free_slist(&false_states
);
263 struct db_callback_info
{
266 struct expression
*expr
;
267 struct range_list
*rl
;
269 struct state_list
*slist
;
271 static struct db_callback_info db_info
;
272 static int db_compare_callback(void *unused
, int argc
, char **argv
, char **azColName
)
274 struct range_list
*ret_range
;
277 struct return_implies_callback
*tmp
;
282 get_value_ranges(argv
[0], &ret_range
);
283 type
= atoi(argv
[1]);
284 param
= atoi(argv
[2]);
288 if (db_info
.true_side
) {
289 if (!possibly_true_range_lists_rl(db_info
.comparison
,
290 ret_range
, db_info
.rl
,
294 if (!possibly_false_range_lists_rl(db_info
.comparison
,
295 ret_range
, db_info
.rl
,
300 FOR_EACH_PTR(db_implies_list
, tmp
) {
301 if (tmp
->type
== type
)
302 tmp
->callback(db_info
.expr
, param
, key
, value
);
303 } END_FOR_EACH_PTR(tmp
);
307 void compare_db_implies_callbacks(int comparison
, struct expression
*expr
, long long value
, int left
)
310 static char sql_filter
[1024];
311 struct state_list
*true_states
;
312 struct state_list
*false_states
;
315 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
318 sym
= expr
->fn
->symbol
;
322 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
323 snprintf(sql_filter
, 1024,
324 "file = '%s' and function = '%s' and static = '1';",
325 get_filename(), sym
->ident
->name
);
327 snprintf(sql_filter
, 1024,
328 "function = '%s' and static = '0';", sym
->ident
->name
);
331 db_info
.comparison
= comparison
;
333 db_info
.rl
= alloc_range_list(value
, value
);
336 db_info
.true_side
= 1;
337 __push_fake_cur_slist();
338 run_sql(db_compare_callback
,
339 "select return, type, parameter, key, value from return_implies where %s",
341 true_states
= __pop_fake_cur_slist();
343 db_info
.true_side
= 0;
344 __push_fake_cur_slist();
345 run_sql(db_compare_callback
,
346 "select return, type, parameter, key, value from return_implies where %s",
348 false_states
= __pop_fake_cur_slist();
350 FOR_EACH_PTR(true_states
, sm
) {
351 __set_true_false_sm(sm
, NULL
);
352 } END_FOR_EACH_PTR(sm
);
353 FOR_EACH_PTR(false_states
, sm
) {
354 __set_true_false_sm(NULL
, sm
);
355 } END_FOR_EACH_PTR(sm
);
357 free_slist(&true_states
);
358 free_slist(&false_states
);
361 void function_comparison(int comparison
, struct expression
*expr
,
362 long long value
, int left
)
364 if (call_implies_callbacks(comparison
, expr
, value
, left
))
366 compare_db_implies_callbacks(comparison
, expr
, value
, left
);
369 static int db_assign_callback(void *unused
, int argc
, char **argv
, char **azColName
)
371 struct range_list
*ret_range
;
374 struct return_implies_callback
*tmp
;
375 struct state_list
*slist
;
380 get_value_ranges(argv
[0], &ret_range
);
381 type
= atoi(argv
[1]);
382 param
= atoi(argv
[2]);
386 __push_fake_cur_slist();
387 FOR_EACH_PTR(db_implies_list
, tmp
) {
388 if (tmp
->type
== type
)
389 tmp
->callback(db_info
.expr
->right
, param
, key
, value
);
390 } END_FOR_EACH_PTR(tmp
);
391 set_extra_expr_mod(db_info
.expr
->left
, alloc_estate_range_list(ret_range
));
392 slist
= __pop_fake_cur_slist();
394 merge_slist(&db_info
.slist
, slist
);
399 static void db_return_implies_assign(struct expression
*expr
)
402 static char sql_filter
[1024];
403 static struct sm_state
*sm
;
405 if (expr
->right
->fn
->type
!= EXPR_SYMBOL
|| !expr
->right
->fn
->symbol
)
408 sym
= expr
->right
->fn
->symbol
;
412 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
413 snprintf(sql_filter
, 1024,
414 "file = '%s' and function = '%s' and static = '1';",
415 get_filename(), sym
->ident
->name
);
417 snprintf(sql_filter
, 1024,
418 "function = '%s' and static = '0';", sym
->ident
->name
);
422 db_info
.slist
= NULL
;
423 run_sql(db_assign_callback
,
424 "select return, type, parameter, key, value from return_implies where %s",
427 FOR_EACH_PTR(db_info
.slist
, sm
) {
429 } END_FOR_EACH_PTR(sm
);
433 static void match_assign_call(struct expression
*expr
)
435 struct call_back_list
*call_backs
;
437 struct expression
*right
;
439 right
= strip_expr(expr
->right
);
440 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
)
442 fn
= right
->fn
->symbol
->ident
->name
;
443 call_backs
= search_callback(func_hash
, (char *)fn
);
445 db_return_implies_assign(expr
);
448 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, expr
);
449 assign_ranged_funcs(fn
, expr
, call_backs
);
452 static void match_macro_assign(struct expression
*expr
)
454 struct call_back_list
*call_backs
;
456 struct expression
*right
;
458 right
= strip_expr(expr
->right
);
459 macro
= get_macro_name(right
->pos
);
460 call_backs
= search_callback(func_hash
, (char *)macro
);
463 call_call_backs(call_backs
, MACRO_ASSIGN
, macro
, expr
);
466 void create_function_hook_hash(void)
468 func_hash
= create_function_hashtable(5000);
471 void register_function_hooks(int id
)
473 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
474 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
475 add_hook(&match_macro_assign
, MACRO_ASSIGNMENT_HOOK
);