__module_put_and_exit() doesn't return.
[smatch.git] / smatch_function_hooks.c
blob8e2733b56fdec72140063a848007b6c608350405
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;
45 char *old_key = NULL;
47 e.key = alloc_string(look_for);
48 hsearch_r(e, FIND, &ep, &func_hash);
49 if (!ep) {
50 struct call_back_list *list = NULL;
52 add_ptr_list(&list, cb);
53 e.data = list;
54 } else {
55 old_key = e.key;
56 e.key = ep->key;
57 add_ptr_list((struct call_back_list **)&ep->data, cb);
58 e.data = ep->data;
60 if (!hsearch_r(e, ENTER, &ep, &func_hash)) {
61 printf("Error hash table too small in smatch_function_hooks.c\n");
62 exit(1);
64 free_string(old_key);
67 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
69 struct fcall_back *cb;
71 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
72 add_cb_hook(look_for, cb);
75 void add_conditional_hook(const char *look_for, func_hook *call_back,
76 void *info)
78 struct fcall_back *cb;
80 cb = alloc_fcall_back(CONDITIONAL_CALL, call_back, info);
81 add_cb_hook(look_for, cb);
84 void add_function_assign_hook(const char *look_for, func_hook *call_back,
85 void *info)
87 struct fcall_back *cb;
89 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
90 add_cb_hook(look_for, cb);
93 static void call_call_backs(struct call_back_list *list, int type,
94 const char *fn, struct expression *expr)
96 struct fcall_back *tmp;
98 FOR_EACH_PTR(list, tmp) {
99 if (tmp->type == type)
100 (tmp->call_back)(fn, expr, tmp->info);
101 } END_FOR_EACH_PTR(tmp);
104 static void match_function_call(struct expression *expr)
106 struct call_back_list *call_backs;
108 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
109 return;
110 call_backs = get_call_backs(expr->fn->symbol->ident->name);
111 if (!call_backs)
112 return;
113 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
114 expr);
117 void __match_initializer_call(struct symbol *sym)
119 struct call_back_list *call_backs;
120 struct expression *initializer = sym->initializer;
121 struct expression *e_assign, *e_symbol;
123 if (initializer->fn->type != EXPR_SYMBOL
124 || !initializer->fn->symbol)
125 return;
126 call_backs = get_call_backs(initializer->fn->symbol->ident->name);
127 if (!call_backs)
128 return;
130 e_assign = alloc_expression(initializer->pos, EXPR_ASSIGNMENT);
131 e_symbol = alloc_expression(initializer->pos, EXPR_SYMBOL);
132 e_symbol->symbol = sym;
133 e_symbol->symbol_name = sym->ident;
134 e_assign->left = e_symbol;
135 e_assign->right = initializer;
136 call_call_backs(call_backs, ASSIGN_CALL,
137 initializer->fn->symbol->ident->name, e_assign);
140 static void match_assign_call(struct expression *expr)
142 struct call_back_list *call_backs;
143 const char *fn;
145 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
146 return;
147 fn = expr->right->fn->symbol->ident->name;
148 call_backs = get_call_backs(fn);
149 if (!call_backs)
150 return;
151 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
154 static void match_conditional_call(struct expression *expr)
156 struct call_back_list *call_backs;
157 struct fcall_back *tmp;
158 struct sm_state *sm;
159 const char *fn;
161 if (expr->type != EXPR_CALL)
162 return;
164 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
165 return;
167 fn = expr->fn->symbol->ident->name;
168 call_backs = get_call_backs(fn);
169 if (!call_backs)
170 return;
171 in_hook = 1;
172 FOR_EACH_PTR(call_backs, tmp) {
173 if (tmp->type != CONDITIONAL_CALL)
174 continue;
176 (tmp->call_back)(fn, expr, tmp->info);
178 FOR_EACH_PTR(cond_true, sm) {
179 __set_true_false_sm(sm, NULL);
180 } END_FOR_EACH_PTR(sm);
181 free_slist(&cond_true);
183 FOR_EACH_PTR(cond_false, sm) {
184 __set_true_false_sm(NULL, sm);
185 } END_FOR_EACH_PTR(sm);
186 free_slist(&cond_false);
188 } END_FOR_EACH_PTR(tmp);
189 in_hook = 0;
192 void set_cond_states(const char *name, int owner, struct symbol *sym,
193 struct smatch_state *true_state,
194 struct smatch_state *false_state)
196 if (!in_hook) {
197 printf("Error: call set_true_false_states() not"
198 "set_cond_states()\n");
199 return;
202 if (debug_states) {
203 struct smatch_state *tmp;
205 tmp = get_state(name, owner, sym);
206 SM_DEBUG("%d set_true_false '%s'. Was %s. Now T:%s F:%s\n",
207 get_lineno(), name, show_state(tmp),
208 show_state(true_state), show_state(false_state));
211 if (true_state) {
212 set_state_slist(&cond_true, name, owner, sym, true_state);
214 if (false_state)
215 set_state_slist(&cond_false, name, owner, sym, false_state);
218 void create_function_hash(void)
220 hcreate_r(10000, &func_hash); // Apparently 1000 is too few...
223 void register_function_hooks(int id)
225 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
226 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
227 add_hook(&match_conditional_call, CONDITION_HOOK);