Small clean up. Allocating filter.
[smatch.git] / smatch_function_hooks.c
blob8075b5f9c4f28d00a7fe99e756a21498e3758719
1 #define _GNU_SOURCE
2 #include <search.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include "smatch.h"
6 #include "smatch_slist.h"
7 #include "smatch_extra.h"
9 ALLOCATOR(fcall_back, "call backs");
11 static struct hsearch_data func_hash;
13 static struct state_list *cond_true = NULL;
14 static struct state_list *cond_false = NULL;
15 static int in_hook = 0;
16 #define REGULAR_CALL 0
17 #define CONDITIONAL_CALL 1
18 #define ASSIGN_CALL 2
20 static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back,
21 void *info)
23 struct fcall_back *cb;
25 cb = __alloc_fcall_back(0);
26 cb->type = type;
27 cb->call_back = call_back;
28 cb->info = info;
29 return cb;
32 static struct call_back_list *get_call_backs(const char *look_for)
34 ENTRY e, *ep;
36 e.key = (char *)look_for;
37 hsearch_r(e, FIND, &ep, &func_hash);
38 if (!ep)
39 return NULL;
40 return (struct call_back_list *)ep->data;
43 static void add_cb_hook(const char *look_for, struct fcall_back *cb)
45 ENTRY e, *ep;
46 char *old_key = NULL;
48 e.key = alloc_string(look_for);
49 hsearch_r(e, FIND, &ep, &func_hash);
50 if (!ep) {
51 struct call_back_list *list = NULL;
53 add_ptr_list(&list, cb);
54 e.data = list;
55 } else {
56 old_key = e.key;
57 e.key = ep->key;
58 add_ptr_list((struct call_back_list **)&ep->data, cb);
59 e.data = ep->data;
61 if (!hsearch_r(e, ENTER, &ep, &func_hash)) {
62 printf("Error hash table too small in smatch_function_hooks.c\n");
63 exit(1);
65 free_string(old_key);
68 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
70 struct fcall_back *cb;
72 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
73 add_cb_hook(look_for, cb);
76 void add_conditional_hook(const char *look_for, func_hook *call_back,
77 void *info)
79 struct fcall_back *cb;
81 cb = alloc_fcall_back(CONDITIONAL_CALL, call_back, info);
82 add_cb_hook(look_for, cb);
85 void add_function_assign_hook(const char *look_for, func_hook *call_back,
86 void *info)
88 struct fcall_back *cb;
90 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
91 add_cb_hook(look_for, cb);
94 static void call_call_backs(struct call_back_list *list, int type,
95 const char *fn, struct expression *expr)
97 struct fcall_back *tmp;
99 FOR_EACH_PTR(list, tmp) {
100 if (tmp->type == type)
101 (tmp->call_back)(fn, expr, tmp->info);
102 } END_FOR_EACH_PTR(tmp);
105 static void match_function_call(struct expression *expr)
107 struct call_back_list *call_backs;
109 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
110 return;
111 call_backs = get_call_backs(expr->fn->symbol->ident->name);
112 if (!call_backs)
113 return;
114 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
115 expr);
118 static void assign_condition_funcs(const char *fn, struct expression *expr,
119 struct call_back_list *call_backs)
121 struct fcall_back *tmp;
122 struct sm_state *sm;
123 int conditional = 0;
124 char *var_name;
125 struct symbol *sym;
126 struct smatch_state *zero_state, *non_zero_state;
128 var_name = get_variable_from_expr(expr->left, &sym);
129 if (!var_name || !sym)
130 goto free;
132 in_hook = 1;
133 FOR_EACH_PTR(call_backs, tmp) {
134 if (tmp->type != CONDITIONAL_CALL)
135 continue;
137 conditional = 1;
138 (tmp->call_back)(fn, expr->right, tmp->info);
139 } END_FOR_EACH_PTR(tmp);
140 if (conditional) {
141 zero_state = alloc_extra_state(0);
142 non_zero_state = add_filter(extra_undefined(), 0);
143 set_cond_states(var_name, SMATCH_EXTRA, sym, non_zero_state, zero_state);
145 in_hook = 0;
147 if (!conditional)
148 goto free;
150 merge_slist(&cond_true, cond_false);
152 FOR_EACH_PTR(cond_true, sm) {
153 __set_state(sm);
154 } END_FOR_EACH_PTR(sm);
155 free_slist(&cond_true);
156 free_slist(&cond_false);
157 free:
158 free_string(var_name);
162 void __match_initializer_call(struct symbol *sym)
164 struct call_back_list *call_backs;
165 struct expression *initializer = sym->initializer;
166 struct expression *e_assign, *e_symbol;
167 const char *fn;
169 if (initializer->fn->type != EXPR_SYMBOL
170 || !initializer->fn->symbol)
171 return;
172 fn = initializer->fn->symbol->ident->name;
173 call_backs = get_call_backs(fn);
174 if (!call_backs)
175 return;
177 e_assign = alloc_expression(initializer->pos, EXPR_ASSIGNMENT);
178 e_symbol = alloc_expression(initializer->pos, EXPR_SYMBOL);
179 e_symbol->symbol = sym;
180 e_symbol->symbol_name = sym->ident;
181 e_assign->left = e_symbol;
182 e_assign->right = initializer;
183 call_call_backs(call_backs, ASSIGN_CALL, fn, e_assign);
184 assign_condition_funcs(fn, e_assign, call_backs);
187 static void match_assign_call(struct expression *expr)
189 struct call_back_list *call_backs;
190 const char *fn;
192 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
193 return;
194 fn = expr->right->fn->symbol->ident->name;
195 call_backs = get_call_backs(fn);
196 if (!call_backs)
197 return;
198 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
199 assign_condition_funcs(fn, expr, call_backs);
202 static void match_conditional_call(struct expression *expr)
204 struct call_back_list *call_backs;
205 struct fcall_back *tmp;
206 struct sm_state *sm;
207 const char *fn;
209 if (expr->type != EXPR_CALL)
210 return;
212 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
213 return;
215 fn = expr->fn->symbol->ident->name;
216 call_backs = get_call_backs(fn);
217 if (!call_backs)
218 return;
219 in_hook = 1;
220 FOR_EACH_PTR(call_backs, tmp) {
221 if (tmp->type != CONDITIONAL_CALL)
222 continue;
224 (tmp->call_back)(fn, expr, tmp->info);
226 FOR_EACH_PTR(cond_true, sm) {
227 __set_true_false_sm(sm, NULL);
228 } END_FOR_EACH_PTR(sm);
229 free_slist(&cond_true);
231 FOR_EACH_PTR(cond_false, sm) {
232 __set_true_false_sm(NULL, sm);
233 } END_FOR_EACH_PTR(sm);
234 free_slist(&cond_false);
236 } END_FOR_EACH_PTR(tmp);
237 in_hook = 0;
240 void set_cond_states(const char *name, int owner, struct symbol *sym,
241 struct smatch_state *true_state,
242 struct smatch_state *false_state)
244 if (!in_hook) {
245 printf("Error: call set_true_false_states() not"
246 "set_cond_states()\n");
247 return;
250 if (debug_states) {
251 struct smatch_state *tmp;
253 tmp = get_state(name, owner, sym);
254 SM_DEBUG("%d set_true_false '%s'. Was %s. Now T:%s F:%s\n",
255 get_lineno(), name, show_state(tmp),
256 show_state(true_state), show_state(false_state));
259 if (true_state) {
260 set_state_slist(&cond_true, name, owner, sym, true_state);
262 if (false_state)
263 set_state_slist(&cond_false, name, owner, sym, false_state);
266 void create_function_hash(void)
268 hcreate_r(10000, &func_hash); // Apparently 1000 is too few...
271 void register_function_hooks(int id)
273 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
274 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
275 add_hook(&match_conditional_call, CONDITION_HOOK);