sval: make cast_rl() preserve things better across signed casts
[smatch.git] / smatch_function_hooks.c
blob0fd18ca1abfbb84ab340b6a907cf49e8ec0902a4
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;
59 static struct db_implies_list *db_return_states_list;
61 static struct fcall_back *alloc_fcall_back(int type, void *call_back,
62 void *info)
64 struct fcall_back *cb;
66 cb = __alloc_fcall_back(0);
67 cb->type = type;
68 cb->u.call_back = call_back;
69 cb->info = info;
70 return cb;
73 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
75 struct fcall_back *cb;
77 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
78 add_callback(func_hash, look_for, cb);
81 void add_function_assign_hook(const char *look_for, func_hook *call_back,
82 void *info)
84 struct fcall_back *cb;
86 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
87 add_callback(func_hash, look_for, cb);
90 void add_implied_return_hook(const char *look_for,
91 implied_return_hook *call_back,
92 void *info)
94 struct fcall_back *cb;
96 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
97 add_callback(func_hash, look_for, cb);
100 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
101 void *info)
103 struct fcall_back *cb;
105 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
106 add_callback(func_hash, look_for, cb);
109 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
110 void *info)
112 struct fcall_back *cb;
114 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
115 add_callback(func_hash, look_for, cb);
118 void return_implies_state(const char *look_for, long long start, long long end,
119 implication_hook *call_back, void *info)
121 struct fcall_back *cb;
123 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
124 cb->range = alloc_range_perm(ll_to_sval(start), ll_to_sval(end));
125 add_callback(func_hash, look_for, cb);
128 void add_db_return_implies_callback(int type, return_implies_hook *callback)
130 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
132 cb->type = type;
133 cb->callback = callback;
134 add_ptr_list(&db_implies_list, cb);
137 void add_db_return_states_callback(int type, return_implies_hook *callback)
139 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
141 cb->type = type;
142 cb->callback = callback;
143 add_ptr_list(&db_return_states_list, cb);
146 static int call_call_backs(struct call_back_list *list, int type,
147 const char *fn, struct expression *expr)
149 struct fcall_back *tmp;
150 int handled = 0;
152 FOR_EACH_PTR(list, tmp) {
153 if (tmp->type == type) {
154 (tmp->u.call_back)(fn, expr, tmp->info);
155 handled = 1;
157 } END_FOR_EACH_PTR(tmp);
159 return handled;
162 static void call_ranged_call_backs(struct call_back_list *list,
163 const char *fn, struct expression *call_expr,
164 struct expression *assign_expr)
166 struct fcall_back *tmp;
168 FOR_EACH_PTR(list, tmp) {
169 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
170 } END_FOR_EACH_PTR(tmp);
173 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
174 struct data_range *drange)
176 struct call_back_list *ret = NULL;
177 struct fcall_back *tmp;
179 FOR_EACH_PTR(list, tmp) {
180 if (tmp->type != RANGED_CALL)
181 continue;
182 if (ranges_equiv(tmp->range, drange))
183 add_ptr_list(&ret, tmp);
184 } END_FOR_EACH_PTR(tmp);
185 return ret;
188 static int in_list_exact_sval(struct range_list *list, struct data_range *drange)
190 struct data_range *tmp;
192 FOR_EACH_PTR(list, tmp) {
193 if (ranges_equiv(tmp, drange))
194 return 1;
195 } END_FOR_EACH_PTR(tmp);
196 return 0;
199 static int assign_ranged_funcs(const char *fn, struct expression *expr,
200 struct call_back_list *call_backs)
202 struct fcall_back *tmp;
203 struct sm_state *sm;
204 char *var_name;
205 struct symbol *sym;
206 struct smatch_state *estate;
207 struct state_list *tmp_slist;
208 struct state_list *final_states = NULL;
209 struct range_list *handled_ranges = NULL;
210 struct call_back_list *same_range_call_backs = NULL;
211 int handled = 0;
213 if (!call_backs)
214 return 0;
216 var_name = get_variable_from_expr(expr->left, &sym);
217 if (!var_name || !sym)
218 goto free;
220 FOR_EACH_PTR(call_backs, tmp) {
221 if (tmp->type != RANGED_CALL)
222 continue;
224 if (in_list_exact_sval(handled_ranges, tmp->range))
225 continue;
226 __push_fake_cur_slist();
227 tack_on(&handled_ranges, tmp->range);
229 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
230 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
231 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
233 estate = alloc_estate_range(tmp->range->min, tmp->range->max);
234 set_extra_mod(var_name, sym, estate);
236 tmp_slist = __pop_fake_cur_slist();
237 merge_slist(&final_states, tmp_slist);
238 free_slist(&tmp_slist);
239 handled = 1;
240 } END_FOR_EACH_PTR(tmp);
242 FOR_EACH_PTR(final_states, sm) {
243 __set_sm(sm);
244 } END_FOR_EACH_PTR(sm);
246 free_slist(&final_states);
247 free:
248 free_string(var_name);
249 return handled;
252 static int call_implies_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
254 struct call_back_list *call_backs;
255 struct fcall_back *tmp;
256 const char *fn;
257 struct data_range *value_range;
258 struct state_list *true_states = NULL;
259 struct state_list *false_states = NULL;
260 struct state_list *tmp_slist;
261 struct sm_state *sm;
263 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
264 return 0;
265 fn = expr->fn->symbol->ident->name;
266 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
267 if (!call_backs)
268 return 0;
269 value_range = alloc_range(sval, sval);
271 /* set true states */
272 __push_fake_cur_slist();
273 FOR_EACH_PTR(call_backs, tmp) {
274 if (tmp->type != RANGED_CALL)
275 continue;
276 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
277 continue;
278 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
279 } END_FOR_EACH_PTR(tmp);
280 tmp_slist = __pop_fake_cur_slist();
281 merge_slist(&true_states, tmp_slist);
282 free_slist(&tmp_slist);
284 /* set false states */
285 __push_fake_cur_slist();
286 FOR_EACH_PTR(call_backs, tmp) {
287 if (tmp->type != RANGED_CALL)
288 continue;
289 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
290 continue;
291 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
292 } END_FOR_EACH_PTR(tmp);
293 tmp_slist = __pop_fake_cur_slist();
294 merge_slist(&false_states, tmp_slist);
295 free_slist(&tmp_slist);
297 FOR_EACH_PTR(true_states, sm) {
298 __set_true_false_sm(sm, NULL);
299 } END_FOR_EACH_PTR(sm);
300 FOR_EACH_PTR(false_states, sm) {
301 __set_true_false_sm(NULL, sm);
302 } END_FOR_EACH_PTR(sm);
304 free_slist(&true_states);
305 free_slist(&false_states);
306 return 1;
309 struct db_callback_info {
310 int true_side;
311 int comparison;
312 struct expression *expr;
313 struct range_list *rl;
314 int left;
315 struct state_list *slist;
316 struct db_implies_list *callbacks;
318 static struct db_callback_info db_info;
319 static int db_compare_callback(void *unused, int argc, char **argv, char **azColName)
321 struct range_list *ret_range;
322 int type, param;
323 char *key, *value;
324 struct return_implies_callback *tmp;
326 if (argc != 5)
327 return 0;
329 parse_value_ranges_type(get_type(db_info.expr), argv[0], &ret_range);
330 type = atoi(argv[1]);
331 param = atoi(argv[2]);
332 key = argv[3];
333 value = argv[4];
335 if (db_info.true_side) {
336 if (!possibly_true_range_lists_lr(db_info.comparison,
337 ret_range, db_info.rl,
338 db_info.left))
339 return 0;
340 } else {
341 if (!possibly_false_range_lists_lr(db_info.comparison,
342 ret_range, db_info.rl,
343 db_info.left))
344 return 0;
347 FOR_EACH_PTR(db_info.callbacks, tmp) {
348 if (tmp->type == type)
349 tmp->callback(db_info.expr, param, key, value);
350 } END_FOR_EACH_PTR(tmp);
351 return 0;
354 void compare_db_implies_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
356 struct symbol *sym;
357 static char sql_filter[1024];
358 struct state_list *true_states;
359 struct state_list *false_states;
360 struct sm_state *sm;
362 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
363 return;
365 sym = expr->fn->symbol;
366 if (!sym)
367 return;
369 if (sym->ctype.modifiers & MOD_STATIC) {
370 snprintf(sql_filter, 1024,
371 "file = '%s' and function = '%s' and static = '1';",
372 get_filename(), sym->ident->name);
373 } else {
374 snprintf(sql_filter, 1024,
375 "function = '%s' and static = '0';", sym->ident->name);
378 db_info.comparison = comparison;
379 db_info.expr = expr;
380 db_info.rl = alloc_range_list(sval, sval);
381 db_info.left = left;
382 db_info.callbacks = db_implies_list;
384 db_info.true_side = 1;
385 __push_fake_cur_slist();
386 run_sql(db_compare_callback,
387 "select return, type, parameter, key, value from return_implies where %s",
388 sql_filter);
389 true_states = __pop_fake_cur_slist();
391 db_info.true_side = 0;
392 __push_fake_cur_slist();
393 run_sql(db_compare_callback,
394 "select return, type, parameter, key, value from return_implies where %s",
395 sql_filter);
396 false_states = __pop_fake_cur_slist();
398 FOR_EACH_PTR(true_states, sm) {
399 __set_true_false_sm(sm, NULL);
400 } END_FOR_EACH_PTR(sm);
401 FOR_EACH_PTR(false_states, sm) {
402 __set_true_false_sm(NULL, sm);
403 } END_FOR_EACH_PTR(sm);
405 free_slist(&true_states);
406 free_slist(&false_states);
409 void compare_db_return_states_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
411 struct symbol *sym;
412 static char sql_filter[1024];
413 struct state_list *true_states;
414 struct state_list *false_states;
415 struct sm_state *sm;
417 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
418 return;
420 sym = expr->fn->symbol;
421 if (!sym)
422 return;
424 if (sym->ctype.modifiers & MOD_STATIC) {
425 snprintf(sql_filter, 1024,
426 "file = '%s' and function = '%s' and static = '1';",
427 get_filename(), sym->ident->name);
428 } else {
429 snprintf(sql_filter, 1024,
430 "function = '%s' and static = '0';", sym->ident->name);
433 db_info.comparison = comparison;
434 db_info.expr = expr;
435 db_info.rl = alloc_range_list(sval, sval);
436 db_info.left = left;
437 db_info.callbacks = db_return_states_list;
439 db_info.true_side = 1;
440 __push_fake_cur_slist();
441 run_sql(db_compare_callback,
442 "select return, type, parameter, key, value from return_states where %s",
443 sql_filter);
444 true_states = __pop_fake_cur_slist();
446 db_info.true_side = 0;
447 __push_fake_cur_slist();
448 run_sql(db_compare_callback,
449 "select return, type, parameter, key, value from return_states where %s",
450 sql_filter);
451 false_states = __pop_fake_cur_slist();
453 FOR_EACH_PTR(true_states, sm) {
454 __set_true_false_sm(sm, NULL);
455 } END_FOR_EACH_PTR(sm);
456 FOR_EACH_PTR(false_states, sm) {
457 __set_true_false_sm(NULL, sm);
458 } END_FOR_EACH_PTR(sm);
460 free_slist(&true_states);
461 free_slist(&false_states);
466 void function_comparison(int comparison, struct expression *expr, sval_t sval, int left)
468 if (call_implies_callbacks(comparison, expr, sval, left))
469 return;
470 compare_db_implies_callbacks(comparison, expr, sval, left);
471 compare_db_return_states_callbacks(comparison, expr, sval, left);
474 static int db_assign_callback(void *unused, int argc, char **argv, char **azColName)
476 struct range_list *ret_range;
477 int type, param;
478 char *key, *value;
479 struct return_implies_callback *tmp;
480 struct state_list *slist;
482 if (argc != 5)
483 return 0;
485 parse_value_ranges_type(get_type(db_info.expr->right), argv[0], &ret_range);
486 type = atoi(argv[1]);
487 param = atoi(argv[2]);
488 key = argv[3];
489 value = argv[4];
491 __push_fake_cur_slist();
492 FOR_EACH_PTR(db_implies_list, tmp) {
493 if (tmp->type == type)
494 tmp->callback(db_info.expr->right, param, key, value);
495 } END_FOR_EACH_PTR(tmp);
496 ret_range = cast_rl(get_type(db_info.expr->left), ret_range);
497 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
498 slist = __pop_fake_cur_slist();
500 merge_slist(&db_info.slist, slist);
502 return 0;
505 static int db_return_implies_assign(struct expression *expr)
507 struct symbol *sym;
508 static char sql_filter[1024];
509 static struct sm_state *sm;
510 int handled = 0;
512 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
513 return 0;
515 sym = expr->right->fn->symbol;
516 if (!sym)
517 return 0;
519 if (sym->ctype.modifiers & MOD_STATIC) {
520 snprintf(sql_filter, 1024,
521 "file = '%s' and function = '%s' and static = '1';",
522 get_filename(), sym->ident->name);
523 } else {
524 snprintf(sql_filter, 1024,
525 "function = '%s' and static = '0';", sym->ident->name);
528 db_info.expr = expr;
529 db_info.slist = NULL;
530 run_sql(db_assign_callback,
531 "select return, type, parameter, key, value from return_implies where %s",
532 sql_filter);
534 FOR_EACH_PTR(db_info.slist, sm) {
535 __set_sm(sm);
536 handled = 1;
537 } END_FOR_EACH_PTR(sm);
539 return handled;
542 static int prev_return_id;
543 static int db_assign_return_states_callback(void *unused, int argc, char **argv, char **azColName)
545 struct range_list *ret_range;
546 int type, param;
547 char *key, *value;
548 struct return_implies_callback *tmp;
549 struct state_list *slist;
550 int return_id;
552 if (argc != 6)
553 return 0;
555 return_id = atoi(argv[0]);
556 parse_value_ranges_type(get_type(db_info.expr->right), argv[1], &ret_range);
557 if (!ret_range)
558 ret_range = whole_range_list(cur_func_return_type());
559 type = atoi(argv[2]);
560 param = atoi(argv[3]);
561 key = argv[4];
562 value = argv[5];
564 if (prev_return_id != -1 && return_id != prev_return_id) {
565 slist = __pop_fake_cur_slist();
566 merge_slist(&db_info.slist, slist);
567 __push_fake_cur_slist();
569 prev_return_id = return_id;
571 FOR_EACH_PTR(db_return_states_list, tmp) {
572 if (tmp->type == type)
573 tmp->callback(db_info.expr, param, key, value);
574 } END_FOR_EACH_PTR(tmp);
575 ret_range = cast_rl(get_type(db_info.expr->left), ret_range);
576 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
578 return 0;
581 static int db_return_states_assign(struct expression *expr)
583 struct expression *right;
584 struct symbol *sym;
585 struct sm_state *sm;
586 struct state_list *slist;
587 static char sql_filter[1024];
588 int handled = 0;
590 right = strip_expr(expr->right);
591 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
592 return 0;
594 sym = right->fn->symbol;
595 if (!sym)
596 return 0;
598 if (sym->ctype.modifiers & MOD_STATIC) {
599 snprintf(sql_filter, 1024,
600 "file = '%s' and function = '%s' and static = '1';",
601 get_filename(), sym->ident->name);
602 } else {
603 snprintf(sql_filter, 1024,
604 "function = '%s' and static = '0';", sym->ident->name);
607 prev_return_id = -1;
608 db_info.expr = expr;
609 db_info.slist = NULL;
610 __push_fake_cur_slist();
611 run_sql(db_assign_return_states_callback,
612 "select return_id, return, type, parameter, key, value from return_states where %s",
613 sql_filter);
614 slist = __pop_fake_cur_slist();
615 merge_slist(&db_info.slist, slist);
617 FOR_EACH_PTR(db_info.slist, sm) {
618 __set_sm(sm);
619 handled = 1;
620 } END_FOR_EACH_PTR(sm);
622 return handled;
625 static int handle_implied_return(struct expression *expr)
627 struct range_list *rl;
629 if (!get_implied_return(expr->right, &rl))
630 return 0;
631 rl = cast_rl(get_type(expr->left), rl);
632 set_extra_expr_mod(expr->left, alloc_estate_range_list(rl));
633 return 1;
636 static void match_assign_call(struct expression *expr)
638 struct call_back_list *call_backs;
639 const char *fn;
640 struct expression *right;
641 int handled = 0;
643 right = strip_expr(expr->right);
644 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
645 set_extra_expr_mod(expr->left, extra_undefined(get_type(expr->left)));
646 return;
648 fn = right->fn->symbol->ident->name;
651 * some of these conflict (they try to set smatch extra twice), so we
652 * call them in order from least important to most important.
655 call_backs = search_callback(func_hash, (char *)fn);
656 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
658 handled |= db_return_states_assign(expr);
659 handled |= db_return_implies_assign(expr);
660 handled |= assign_ranged_funcs(fn, expr, call_backs);
661 handled |= handle_implied_return(expr);
663 if (!handled)
664 set_extra_expr_mod(expr->left, extra_undefined(get_type(expr->left)));
667 static int db_return_states_callback(void *unused, int argc, char **argv, char **azColName)
669 struct range_list *ret_range;
670 int type, param;
671 char *key, *value;
672 struct return_implies_callback *tmp;
673 struct state_list *slist;
674 int return_id;
676 if (argc != 6)
677 return 0;
679 return_id = atoi(argv[0]);
680 parse_value_ranges_type(get_type(db_info.expr), argv[1], &ret_range);
681 type = atoi(argv[2]);
682 param = atoi(argv[3]);
683 key = argv[4];
684 value = argv[5];
686 if (prev_return_id != -1 && return_id != prev_return_id) {
687 slist = __pop_fake_cur_slist();
688 merge_slist(&db_info.slist, slist);
689 __push_fake_cur_slist();
691 prev_return_id = return_id;
693 FOR_EACH_PTR(db_return_states_list, tmp) {
694 if (tmp->type == type)
695 tmp->callback(db_info.expr, param, key, value);
696 } END_FOR_EACH_PTR(tmp);
698 return 0;
701 static void db_return_states(struct expression *expr)
703 struct symbol *sym;
704 struct sm_state *sm;
705 struct state_list *slist;
706 static char sql_filter[1024];
708 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
709 return;
711 sym = expr->fn->symbol;
712 if (!sym)
713 return;
715 if (sym->ctype.modifiers & MOD_STATIC) {
716 snprintf(sql_filter, 1024,
717 "file = '%s' and function = '%s' and static = '1';",
718 get_filename(), sym->ident->name);
719 } else {
720 snprintf(sql_filter, 1024,
721 "function = '%s' and static = '0';", sym->ident->name);
724 prev_return_id = -1;
725 db_info.expr = expr;
726 db_info.slist = NULL;
727 __push_fake_cur_slist();
728 run_sql(db_return_states_callback,
729 "select return_id, return, type, parameter, key, value from return_states where %s",
730 sql_filter);
731 slist = __pop_fake_cur_slist();
732 merge_slist(&db_info.slist, slist);
734 FOR_EACH_PTR(db_info.slist, sm) {
735 __set_sm(sm);
736 } END_FOR_EACH_PTR(sm);
739 static int is_assigned_call(struct expression *expr)
741 struct expression *tmp;
743 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
744 if (tmp->type == EXPR_ASSIGNMENT && strip_expr(tmp->right) == expr)
745 return 1;
746 if (tmp->pos.line < expr->pos.line)
747 return 0;
748 } END_FOR_EACH_PTR_REVERSE(tmp);
749 return 0;
752 static void db_return_states_call(struct expression *expr)
754 if (is_assigned_call(expr))
755 return;
756 db_return_states(expr);
759 static void match_function_call(struct expression *expr)
761 struct call_back_list *call_backs;
763 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
764 return;
765 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
766 if (call_backs)
767 call_call_backs(call_backs, REGULAR_CALL,
768 expr->fn->symbol->ident->name, expr);
769 db_return_states_call(expr);
772 static void match_macro_assign(struct expression *expr)
774 struct call_back_list *call_backs;
775 const char *macro;
776 struct expression *right;
778 right = strip_expr(expr->right);
779 macro = get_macro_name(right->pos);
780 call_backs = search_callback(func_hash, (char *)macro);
781 if (!call_backs)
782 return;
783 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
784 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
787 int get_implied_return(struct expression *expr, struct range_list **rl)
789 struct call_back_list *call_backs;
790 struct fcall_back *tmp;
791 int handled = 0;
792 char *fn;
794 *rl = NULL;
796 expr = strip_expr(expr);
797 fn = get_variable_from_expr(expr->fn, NULL);
798 if (!fn)
799 goto out;
801 call_backs = search_callback(func_hash, fn);
803 FOR_EACH_PTR(call_backs, tmp) {
804 if (tmp->type == IMPLIED_RETURN) {
805 (tmp->u.implied_return)(expr, tmp->info, rl);
806 handled = 1;
808 } END_FOR_EACH_PTR(tmp);
810 out:
811 free_string(fn);
812 return handled;
815 void create_function_hook_hash(void)
817 func_hash = create_function_hashtable(5000);
820 void register_function_hooks(int id)
822 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
823 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
824 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);