Add comment. get_value returns UNDEFINED on error.
[smatch.git] / smatch_function_hooks.c
blob2f424645e219926e6f48a2bfcf8d98512f63c49b
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"
8 ALLOCATOR(fcall_back, "call backs");
10 static struct hsearch_data func_hash;
12 static struct state_list *cond_true = NULL;
13 static struct state_list *cond_false = NULL;
14 static int in_hook = 0;
15 #define REGULAR_CALL 0
16 #define CONDITIONAL_CALL 1
17 #define ASSIGN_CALL 2
19 static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back,
20 void *info)
22 struct fcall_back *cb;
24 cb = __alloc_fcall_back(0);
25 cb->type = type;
26 cb->call_back = call_back;
27 cb->info = info;
28 return cb;
31 static struct call_back_list *get_call_backs(const char *look_for)
33 ENTRY e, *ep;
35 e.key = (char *)look_for;
36 hsearch_r(e, FIND, &ep, &func_hash);
37 if (!ep)
38 return NULL;
39 return (struct call_back_list *)ep->data;
42 static void add_cb_hook(const char *look_for, struct fcall_back *cb)
44 ENTRY e, *ep;
46 e.key = alloc_string(look_for);
47 hsearch_r(e, FIND, &ep, &func_hash);
48 if (!ep) {
49 struct call_back_list *list = NULL;
51 add_ptr_list(&list, cb);
52 e.data = list;
53 } else {
54 free_string(ep->key);
55 add_ptr_list((struct call_back_list **)&ep->data, cb);
56 e.data = ep->data;
58 if (!hsearch_r(e, ENTER, &ep, &func_hash)) {
59 printf("Error hash table too small in smatch_function_hooks.c\n");
60 exit(1);
64 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
66 struct fcall_back *cb;
68 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
69 add_cb_hook(look_for, cb);
72 void add_conditional_hook(const char *look_for, func_hook *call_back,
73 void *info)
75 struct fcall_back *cb;
77 cb = alloc_fcall_back(CONDITIONAL_CALL, call_back, info);
78 add_cb_hook(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_cb_hook(look_for, cb);
90 static void call_call_backs(struct call_back_list *list, int type,
91 const char *fn, struct expression *expr)
93 struct fcall_back *tmp;
95 FOR_EACH_PTR(list, tmp) {
96 if (tmp->type == type)
97 (tmp->call_back)(fn, expr, tmp->info);
98 } END_FOR_EACH_PTR(tmp);
101 static void match_function_call(struct expression *expr)
103 struct call_back_list *call_backs;
105 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
106 return;
107 call_backs = get_call_backs(expr->fn->symbol->ident->name);
108 if (!call_backs)
109 return;
110 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
111 expr);
114 void __match_initializer_call(struct symbol *sym)
116 struct call_back_list *call_backs;
117 struct expression *initializer = sym->initializer;
118 struct expression *e_assign, *e_symbol;
120 if (initializer->fn->type != EXPR_SYMBOL
121 || !initializer->fn->symbol)
122 return;
123 call_backs = get_call_backs(initializer->fn->symbol->ident->name);
124 if (!call_backs)
125 return;
127 e_assign = alloc_expression(initializer->pos, EXPR_ASSIGNMENT);
128 e_symbol = alloc_expression(initializer->pos, EXPR_SYMBOL);
129 e_symbol->symbol = sym;
130 e_symbol->symbol_name = sym->ident;
131 e_assign->left = e_symbol;
132 e_assign->right = initializer;
133 call_call_backs(call_backs, ASSIGN_CALL,
134 initializer->fn->symbol->ident->name, e_assign);
137 static void match_assign_call(struct expression *expr)
139 struct call_back_list *call_backs;
140 const char *fn;
142 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
143 return;
144 fn = expr->right->fn->symbol->ident->name;
145 call_backs = get_call_backs(fn);
146 if (!call_backs)
147 return;
148 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
151 static void match_conditional_call(struct expression *expr)
153 struct call_back_list *call_backs;
154 struct fcall_back *tmp;
155 struct sm_state *sm;
156 const char *fn;
158 if (expr->type != EXPR_CALL)
159 return;
161 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
162 return;
164 fn = expr->fn->symbol->ident->name;
165 call_backs = get_call_backs(fn);
166 if (!call_backs)
167 return;
168 in_hook = 1;
169 FOR_EACH_PTR(call_backs, tmp) {
170 if (tmp->type != CONDITIONAL_CALL)
171 continue;
173 (tmp->call_back)(fn, expr, tmp->info);
175 FOR_EACH_PTR(cond_true, sm) {
176 __set_true_false_sm(sm, NULL);
177 } END_FOR_EACH_PTR(sm);
178 free_slist(&cond_true);
180 FOR_EACH_PTR(cond_false, sm) {
181 __set_true_false_sm(NULL, sm);
182 } END_FOR_EACH_PTR(sm);
183 free_slist(&cond_false);
185 } END_FOR_EACH_PTR(tmp);
186 in_hook = 0;
189 void set_cond_states(const char *name, int owner, struct symbol *sym,
190 struct smatch_state *true_state,
191 struct smatch_state *false_state)
193 if (!in_hook) {
194 printf("Error: call set_true_false_states() not"
195 "set_cond_states()\n");
196 return;
199 if (debug_states) {
200 struct smatch_state *tmp;
202 tmp = get_state(name, owner, sym);
203 SM_DEBUG("%d set_true_false '%s'. Was %s. Now T:%s F:%s\n",
204 get_lineno(), name, show_state(tmp),
205 show_state(true_state), show_state(false_state));
208 if (true_state) {
209 set_state_slist(&cond_true, name, owner, sym, true_state);
211 if (false_state)
212 set_state_slist(&cond_false, name, owner, sym, false_state);
215 void create_function_hash(void)
217 hcreate_r(10000, &func_hash); // Apparently 1000 is too few...
220 void register_function_hooks(int id)
222 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
223 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
224 add_hook(&match_conditional_call, CONDITION_HOOK);