2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
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.
23 #include "smatch_slist.h"
24 #include "smatch_extra.h"
25 #include "smatch_function_hashtable.h"
29 struct data_range
*range
;
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
43 #define MACRO_ASSIGN 3
45 static struct fcall_back
*alloc_fcall_back(int type
, func_hook
*call_back
,
48 struct fcall_back
*cb
;
50 cb
= __alloc_fcall_back(0);
52 cb
->call_back
= call_back
;
57 void add_function_hook(const char *look_for
, func_hook
*call_back
, void *info
)
59 struct fcall_back
*cb
;
61 cb
= alloc_fcall_back(REGULAR_CALL
, call_back
, info
);
62 add_callback(func_hash
, look_for
, cb
);
65 void add_function_assign_hook(const char *look_for
, func_hook
*call_back
,
68 struct fcall_back
*cb
;
70 cb
= alloc_fcall_back(ASSIGN_CALL
, call_back
, info
);
71 add_callback(func_hash
, look_for
, cb
);
74 void add_macro_assign_hook(const char *look_for
, func_hook
*call_back
,
77 struct fcall_back
*cb
;
79 cb
= alloc_fcall_back(MACRO_ASSIGN
, call_back
, info
);
80 add_callback(func_hash
, look_for
, cb
);
83 void return_implies_state(const char *look_for
, long long start
, long long end
,
84 implication_hook
*call_back
, void *info
)
86 struct fcall_back
*cb
;
88 cb
= alloc_fcall_back(RANGED_CALL
, (func_hook
*)call_back
, info
);
89 cb
->range
= alloc_range_perm(start
, end
);
90 add_callback(func_hash
, 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 call_ranged_call_backs(struct call_back_list
*list
,
105 const char *fn
, struct expression
*call_expr
,
106 struct expression
*assign_expr
)
108 struct fcall_back
*tmp
;
110 FOR_EACH_PTR(list
, tmp
) {
111 ((implication_hook
*)(tmp
->call_back
))(fn
, call_expr
, assign_expr
, tmp
->info
);
112 } END_FOR_EACH_PTR(tmp
);
115 static void match_function_call(struct expression
*expr
)
117 struct call_back_list
*call_backs
;
119 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
121 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
124 call_call_backs(call_backs
, REGULAR_CALL
, expr
->fn
->symbol
->ident
->name
,
128 static struct call_back_list
*get_same_ranged_call_backs(struct call_back_list
*list
,
129 struct data_range
*drange
)
131 struct call_back_list
*ret
= NULL
;
132 struct fcall_back
*tmp
;
134 FOR_EACH_PTR(list
, tmp
) {
135 if (tmp
->type
!= RANGED_CALL
)
137 if (tmp
->range
->min
== drange
->min
&& tmp
->range
->max
== drange
->max
)
138 add_ptr_list(&ret
, tmp
);
139 } END_FOR_EACH_PTR(tmp
);
143 static void assign_ranged_funcs(const char *fn
, struct expression
*expr
,
144 struct call_back_list
*call_backs
)
146 struct fcall_back
*tmp
;
150 struct smatch_state
*extra_state
;
151 struct state_list
*tmp_slist
;
152 struct state_list
*final_states
= NULL
;
153 struct range_list
*handled_ranges
= NULL
;
154 struct call_back_list
*same_range_call_backs
= NULL
;
156 var_name
= get_variable_from_expr(expr
->left
, &sym
);
157 if (!var_name
|| !sym
)
160 FOR_EACH_PTR(call_backs
, tmp
) {
161 if (tmp
->type
!= RANGED_CALL
)
163 if (in_list_exact(handled_ranges
, tmp
->range
))
165 __push_fake_cur_slist();
166 tack_on(&handled_ranges
, tmp
->range
);
168 same_range_call_backs
= get_same_ranged_call_backs(call_backs
, tmp
->range
);
169 call_ranged_call_backs(same_range_call_backs
, fn
, expr
->right
, expr
);
170 __free_ptr_list((struct ptr_list
**)&same_range_call_backs
);
172 extra_state
= alloc_extra_state_range(tmp
->range
->min
, tmp
->range
->max
);
173 set_extra_mod(var_name
, sym
, extra_state
);
175 tmp_slist
= __pop_fake_cur_slist();
176 merge_slist(&final_states
, tmp_slist
);
177 free_slist(&tmp_slist
);
178 } END_FOR_EACH_PTR(tmp
);
180 FOR_EACH_PTR(final_states
, sm
) {
182 } END_FOR_EACH_PTR(sm
);
184 free_slist(&final_states
);
186 free_string(var_name
);
189 void function_comparison(int comparison
, struct expression
*expr
, long long value
, int left
)
191 struct call_back_list
*call_backs
;
192 struct fcall_back
*tmp
;
194 struct data_range
*value_range
;
195 struct state_list
*true_states
= NULL
;
196 struct state_list
*false_states
= NULL
;
197 struct state_list
*tmp_slist
;
200 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
202 fn
= expr
->fn
->symbol
->ident
->name
;
203 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
206 value_range
= alloc_range(value
, value
);
208 /* set true states */
209 __push_fake_cur_slist();
210 FOR_EACH_PTR(call_backs
, tmp
) {
211 if (tmp
->type
!= RANGED_CALL
)
213 if (!true_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
215 ((implication_hook
*)(tmp
->call_back
))(fn
, expr
, NULL
, tmp
->info
);
216 } END_FOR_EACH_PTR(tmp
);
217 tmp_slist
= __pop_fake_cur_slist();
218 merge_slist(&true_states
, tmp_slist
);
219 free_slist(&tmp_slist
);
221 /* set false states */
222 __push_fake_cur_slist();
223 FOR_EACH_PTR(call_backs
, tmp
) {
224 if (tmp
->type
!= RANGED_CALL
)
226 if (!false_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
228 ((implication_hook
*)(tmp
->call_back
))(fn
, expr
, NULL
, tmp
->info
);
229 } END_FOR_EACH_PTR(tmp
);
230 tmp_slist
= __pop_fake_cur_slist();
231 merge_slist(&false_states
, tmp_slist
);
232 free_slist(&tmp_slist
);
234 FOR_EACH_PTR(true_states
, sm
) {
235 __set_true_false_sm(sm
, NULL
);
236 } END_FOR_EACH_PTR(sm
);
237 FOR_EACH_PTR(false_states
, sm
) {
238 __set_true_false_sm(NULL
, sm
);
239 } END_FOR_EACH_PTR(sm
);
241 free_slist(&true_states
);
242 free_slist(&false_states
);
245 static void match_assign_call(struct expression
*expr
)
247 struct call_back_list
*call_backs
;
249 struct expression
*right
;
251 right
= strip_expr(expr
->right
);
252 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
)
254 fn
= right
->fn
->symbol
->ident
->name
;
255 call_backs
= search_callback(func_hash
, (char *)fn
);
258 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, expr
);
259 assign_ranged_funcs(fn
, expr
, call_backs
);
262 static void match_macro_assign(struct expression
*expr
)
264 struct call_back_list
*call_backs
;
266 struct expression
*right
;
268 right
= strip_expr(expr
->right
);
269 macro
= get_macro_name(&right
->pos
);
270 call_backs
= search_callback(func_hash
, (char *)macro
);
273 call_call_backs(call_backs
, MACRO_ASSIGN
, macro
, expr
);
276 void create_function_hook_hash(void)
278 func_hash
= create_function_hashtable(5000);
281 void register_function_hooks(int id
)
283 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
284 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
285 add_hook(&match_macro_assign
, MACRO_ASSIGNMENT_HOOK
);