modification_hooks: delete a blank line
[smatch.git] / smatch_type_val.c
blob410099fad05251afc3c67826f7d130c6dcb66eeb
1 /*
2 * sparse/smatch_type_val.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
11 * The plan here is to save all the possible values store to a given struct
12 * member.
14 * We will load all the values in to the function_type_val table first then
15 * run a script on that and load all the resulting values into the type_val
16 * table.
18 * So in this file we want to take the union of everything assigned to the
19 * struct member and insert it into the function_type_val at the end.
21 * You would think that we could use smatch_modification_hooks.c or
22 * extra_modification_hook() here to get the information here but in the end we
23 * need to code everything again a third time.
27 #include "smatch.h"
28 #include "smatch_slist.h"
29 #include "smatch_extra.h"
31 static int my_id;
33 struct state_list_stack *fn_type_val_stack;
34 struct state_list *fn_type_val;
35 struct state_list *global_type_val;
37 static char *db_vals;
38 static int get_vals(void *unused, int argc, char **argv, char **azColName)
40 db_vals = alloc_string(argv[0]);
41 return 0;
44 static void match_inline_start(struct expression *expr)
46 push_slist(&fn_type_val_stack, fn_type_val);
47 fn_type_val = NULL;
50 static void match_inline_end(struct expression *expr)
52 fn_type_val = pop_slist(&fn_type_val_stack);
55 int get_db_type_rl(struct expression *expr, struct range_list **rl)
57 char *member;
58 struct range_list *tmp;
60 member = get_member_name(expr);
61 if (!member)
62 return 0;
64 db_vals = NULL;
65 run_sql(get_vals,
66 "select value from type_value where type = '%s'", member);
67 free_string(member);
68 if (!db_vals)
69 return 0;
70 str_to_rl(&llong_ctype, db_vals, &tmp);
71 tmp = cast_rl(get_type(expr), tmp);
72 if (is_whole_rl(tmp))
73 return 0;
74 *rl = tmp;
75 free_string(db_vals);
77 return 1;
81 * One of the complications is that smatch tries to free a bunch of data at the
82 * end of every function.
84 static struct data_info *clone_dinfo_perm(struct data_info *dinfo)
86 struct data_info *ret;
88 ret = malloc(sizeof(*ret));
89 ret->related = NULL;
90 ret->value_ranges = clone_rl_permanent(dinfo->value_ranges);
91 ret->hard_max = 0;
92 return ret;
95 static struct smatch_state *clone_estate_perm(struct smatch_state *state)
97 struct smatch_state *ret;
99 ret = malloc(sizeof(*ret));
100 ret->name = alloc_string(state->name);
101 ret->data = clone_dinfo_perm(get_dinfo(state));
102 return ret;
105 static void set_state_slist_perm(struct state_list **slist, int owner, const char *name,
106 struct symbol *sym, struct smatch_state *state)
108 struct sm_state *sm;
110 sm = malloc(sizeof(*sm));
111 memset(sm, 0, sizeof(*sm));
112 sm->owner = owner;
113 sm->name = name;
114 sm->sym = sym;
115 sm->state = state;
117 overwrite_sm_state(slist, sm);
120 static void add_type_val(char *member, struct range_list *rl)
122 struct smatch_state *old, *add, *new;
124 member = alloc_string(member);
125 old = get_state_slist(fn_type_val, my_id, member, NULL);
126 add = alloc_estate_rl(rl);
127 if (old)
128 new = merge_estates(old, add);
129 else
130 new = add;
131 set_state_slist(&fn_type_val, my_id, member, NULL, new);
134 static void add_global_type_val(char *member, struct range_list *rl)
136 struct smatch_state *old, *add, *new;
138 member = alloc_string(member);
139 old = get_state_slist(global_type_val, my_id, member, NULL);
140 add = alloc_estate_rl(rl);
141 if (old)
142 new = merge_estates(old, add);
143 else
144 new = add;
145 new = clone_estate_perm(new);
146 set_state_slist_perm(&global_type_val, my_id, member, NULL, new);
149 static void match_assign_value(struct expression *expr)
151 char *member, *right_member;
152 struct range_list *rl;
153 struct symbol *type;
155 type = get_type(expr->left);
156 if (type && type->type == SYM_STRUCT)
157 return;
159 member = get_member_name(expr->left);
160 if (!member)
161 return;
163 /* if we're saying foo->mtu = bar->mtu then that doesn't add information */
164 right_member = get_member_name(expr->right);
165 if (right_member && strcmp(right_member, member) == 0)
166 goto free;
168 if (expr->op != '=') {
169 add_type_val(member, alloc_whole_rl(get_type(expr->left)));
170 goto free;
172 get_absolute_rl(expr->right, &rl);
173 rl = cast_rl(type, rl);
174 add_type_val(member, rl);
175 free:
176 free_string(right_member);
177 free_string(member);
181 * If we too: int *p = &my_struct->member then abandon all hope of tracking
182 * my_struct->member.
184 static void match_assign_pointer(struct expression *expr)
186 struct expression *right;
187 char *member;
188 struct range_list *rl;
189 struct symbol *type;
191 right = strip_expr(expr->right);
192 if (right->type != EXPR_PREOP || right->op != '&')
193 return;
194 right = strip_expr(right->unop);
196 member = get_member_name(right);
197 if (!member)
198 return;
199 type = get_type(right);
200 rl = alloc_whole_rl(type);
201 add_type_val(member, rl);
202 free_string(member);
205 static void match_global_assign(struct expression *expr)
207 char *member;
208 struct range_list *rl;
210 member = get_member_name(expr->left);
211 if (!member)
212 return;
213 get_absolute_rl(expr->right, &rl);
214 add_global_type_val(member, rl);
215 free_string(member);
218 static void unop_expr(struct expression *expr)
220 struct range_list *rl;
221 char *member;
223 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
224 return;
226 expr = strip_expr(expr->unop);
227 member = get_member_name(expr);
228 if (!member)
229 return;
230 rl = alloc_whole_rl(get_type(expr));
231 add_type_val(member, rl);
232 free_string(member);
235 static void asm_expr(struct statement *stmt)
237 struct expression *expr;
238 struct range_list *rl;
239 char *member;
240 int state = 0;
242 FOR_EACH_PTR(stmt->asm_outputs, expr) {
243 switch (state) {
244 case 0: /* identifier */
245 case 1: /* constraint */
246 state++;
247 continue;
248 case 2: /* expression */
249 state = 0;
250 member = get_member_name(expr);
251 if (!member)
252 continue;
253 rl = alloc_whole_rl(get_type(expr));
254 add_type_val(member, rl);
255 free_string(member);
256 continue;
258 } END_FOR_EACH_PTR(expr);
261 static void db_param_add(struct expression *expr, int param, char *key, char *value)
263 struct expression *arg;
264 struct symbol *type;
265 struct range_list *rl;
266 char *member;
268 if (strcmp(key, "*$$") != 0)
269 return;
271 while (expr->type == EXPR_ASSIGNMENT)
272 expr = strip_expr(expr->right);
273 if (expr->type != EXPR_CALL)
274 return;
276 arg = get_argument_from_call_expr(expr->args, param);
277 arg = strip_expr(arg);
278 if (!arg)
279 return;
280 type = get_member_type_from_key(arg, key);
281 if (arg->type != EXPR_PREOP || arg->op != '&')
282 return;
283 arg = strip_expr(arg->unop);
285 member = get_member_name(arg);
286 if (!member)
287 return;
288 call_results_to_rl(expr, type, value, &rl);
289 add_type_val(member, rl);
290 free_string(member);
293 static void match_end_func_info(struct symbol *sym)
295 struct sm_state *sm;
297 FOR_EACH_PTR(fn_type_val, sm) {
298 sql_insert_function_type_value(sm->name, sm->state->name);
299 } END_FOR_EACH_PTR(sm);
301 free_slist(&fn_type_val);
304 static void match_end_file(struct symbol_list *sym_list)
306 struct sm_state *sm;
308 FOR_EACH_PTR(global_type_val, sm) {
309 sql_insert_function_type_value(sm->name, sm->state->name);
310 } END_FOR_EACH_PTR(sm);
313 void register_type_val(int id)
315 if (!option_info)
316 return;
318 my_id = id;
320 add_hook(&match_assign_value, ASSIGNMENT_HOOK);
321 add_hook(&match_assign_pointer, ASSIGNMENT_HOOK);
322 add_hook(&unop_expr, OP_HOOK);
323 add_hook(&asm_expr, ASM_HOOK);
324 select_return_states_hook(ADDED_VALUE, &db_param_add);
326 add_hook(&match_inline_start, INLINE_FN_START);
327 add_hook(&match_inline_end, INLINE_FN_END);
329 add_hook(&match_end_func_info, END_FUNC_HOOK);
331 add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK);
332 add_hook(&match_end_file, END_FILE_HOOK);