db: add get_return_id() and return markers
[smatch.git] / smatch_function_hooks.c
blob59100cbf7acc22c88357e10d3c4b72f6b8c606c5
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 ASSIGN_CALL 1
42 #define RANGED_CALL 2
43 #define MACRO_ASSIGN 3
45 struct return_implies_callback {
46 int type;
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,
54 void *info)
56 struct fcall_back *cb;
58 cb = __alloc_fcall_back(0);
59 cb->type = type;
60 cb->call_back = call_back;
61 cb->info = info;
62 return cb;
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,
74 void *info)
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,
83 void *info)
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);
105 cb->type = type;
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)
137 return;
138 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
139 if (!call_backs)
140 return;
141 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
142 expr);
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)
153 continue;
154 if (tmp->range->min == drange->min && tmp->range->max == drange->max)
155 add_ptr_list(&ret, tmp);
156 } END_FOR_EACH_PTR(tmp);
157 return ret;
160 static void assign_ranged_funcs(const char *fn, struct expression *expr,
161 struct call_back_list *call_backs)
163 struct fcall_back *tmp;
164 struct sm_state *sm;
165 char *var_name;
166 struct symbol *sym;
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)
175 goto free;
177 FOR_EACH_PTR(call_backs, tmp) {
178 if (tmp->type != RANGED_CALL)
179 continue;
180 if (in_list_exact(handled_ranges, tmp->range))
181 continue;
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) {
198 __set_sm(sm);
199 } END_FOR_EACH_PTR(sm);
201 free_slist(&final_states);
202 free:
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;
210 const char *fn;
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;
215 struct sm_state *sm;
217 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
218 return 0;
219 fn = expr->fn->symbol->ident->name;
220 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
221 if (!call_backs)
222 return 0;
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)
229 continue;
230 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
231 continue;
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)
242 continue;
243 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
244 continue;
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);
260 return 1;
263 struct db_callback_info {
264 int true_side;
265 int comparison;
266 struct expression *expr;
267 struct range_list *rl;
268 int left;
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;
275 int type, param;
276 char *key, *value;
277 struct return_implies_callback *tmp;
279 if (argc != 5)
280 return 0;
282 get_value_ranges(argv[0], &ret_range);
283 type = atoi(argv[1]);
284 param = atoi(argv[2]);
285 key = argv[3];
286 value = argv[4];
288 if (db_info.true_side) {
289 if (!possibly_true_range_lists_rl(db_info.comparison,
290 ret_range, db_info.rl,
291 db_info.left))
292 return 0;
293 } else {
294 if (!possibly_false_range_lists_rl(db_info.comparison,
295 ret_range, db_info.rl,
296 db_info.left))
297 return 0;
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);
304 return 0;
307 void compare_db_implies_callbacks(int comparison, struct expression *expr, long long value, int left)
309 struct symbol *sym;
310 static char sql_filter[1024];
311 struct state_list *true_states;
312 struct state_list *false_states;
313 struct sm_state *sm;
315 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
316 return;
318 sym = expr->fn->symbol;
319 if (!sym)
320 return;
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);
326 } else {
327 snprintf(sql_filter, 1024,
328 "function = '%s' and static = '0';", sym->ident->name);
331 db_info.comparison = comparison;
332 db_info.expr = expr;
333 db_info.rl = alloc_range_list(value, value);
334 db_info.left = left;
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",
340 sql_filter);
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",
347 sql_filter);
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))
365 return;
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;
372 int type, param;
373 char *key, *value;
374 struct return_implies_callback *tmp;
375 struct state_list *slist;
377 if (argc != 5)
378 return 0;
380 get_value_ranges(argv[0], &ret_range);
381 type = atoi(argv[1]);
382 param = atoi(argv[2]);
383 key = argv[3];
384 value = argv[4];
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);
396 return 0;
399 static void db_return_implies_assign(struct expression *expr)
401 struct symbol *sym;
402 static char sql_filter[1024];
403 static struct sm_state *sm;
405 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
406 return;
408 sym = expr->right->fn->symbol;
409 if (!sym)
410 return;
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);
416 } else {
417 snprintf(sql_filter, 1024,
418 "function = '%s' and static = '0';", sym->ident->name);
421 db_info.expr = expr;
422 db_info.slist = NULL;
423 run_sql(db_assign_callback,
424 "select return, type, parameter, key, value from return_implies where %s",
425 sql_filter);
427 FOR_EACH_PTR(db_info.slist, sm) {
428 __set_sm(sm);
429 } END_FOR_EACH_PTR(sm);
433 static void match_assign_call(struct expression *expr)
435 struct call_back_list *call_backs;
436 const char *fn;
437 struct expression *right;
439 right = strip_expr(expr->right);
440 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
441 return;
442 fn = right->fn->symbol->ident->name;
443 call_backs = search_callback(func_hash, (char *)fn);
444 if (!call_backs) {
445 db_return_implies_assign(expr);
446 return;
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;
455 const char *macro;
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);
461 if (!call_backs)
462 return;
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);