db: improve database debugging
[smatch.git] / smatch_local_values.c
blob19448787486fb5ccd359c6af88a687eef053a406
1 /*
2 * smatch/local_values.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "scope.h"
11 #include "smatch.h"
12 #include "smatch_slist.h"
13 #include "smatch_extra.h"
15 static int my_id;
18 * I'm going to store the states of local data at the end of each function.
19 * Then at the end of the file, I'll combine the possible range lists for
20 * each state and store the value in the on-disk database.
22 * One issue is that when I read the data back from the in-memory database at
23 * the end of the file, then I don't have access to type information. I'll just
24 * cast everything to "long long" for now, I guess. We'll see how that works.
27 static char *db_vals;
28 static int get_vals(void *unused, int argc, char **argv, char **azColName)
30 db_vals = alloc_string(argv[0]);
31 return 0;
34 int get_local_rl(struct expression *expr, struct range_list **rl)
36 char *name;
37 struct range_list *tmp;
39 if (!is_static(expr))
40 return 0;
41 name = expr_to_var(expr);
42 if (!name)
43 return 0;
45 db_vals = NULL;
46 run_sql(get_vals,
47 "select value from local_values where file = '%s' and variable = '%s'",
48 get_filename(), name);
49 free_string(name);
50 if (!db_vals)
51 return 0;
52 str_to_rl(&llong_ctype, db_vals, &tmp);
53 *rl = cast_rl(get_type(expr), tmp);
54 free_string(db_vals);
56 return 1;
59 int get_local_max_helper(struct expression *expr, sval_t *sval)
61 struct range_list *rl;
63 if (!get_local_rl(expr, &rl))
64 return 0;
65 *sval = rl_max(rl);
66 return 1;
69 int get_local_min_helper(struct expression *expr, sval_t *sval)
71 struct range_list *rl;
73 if (!get_local_rl(expr, &rl))
74 return 0;
75 *sval = rl_min(rl);
76 return 1;
79 static struct smatch_state *unmatched_state(struct sm_state *sm)
81 return alloc_estate_empty();
84 static void extra_mod_hook(const char *name, struct symbol *sym, struct smatch_state *state)
86 struct smatch_state *old;
87 struct smatch_state *new;
89 if (!(sym->ctype.modifiers & MOD_STATIC))
90 return;
91 old = get_state(my_id, name, sym);
92 if (old)
93 new = merge_estates(old, state);
94 else
95 new = state;
96 set_state(my_id, name, sym, new);
99 static void process_states(struct state_list *slist)
101 struct sm_state *sm;
102 struct smatch_state *extra;
103 struct range_list *rl;
105 FOR_EACH_PTR(slist, sm) {
106 if (sm->owner != my_id)
107 continue;
108 extra = get_state_slist(slist, SMATCH_EXTRA, sm->name, sm->sym);
109 if (extra && estate_rl(extra))
110 rl = rl_intersection(estate_rl(sm->state), estate_rl(extra));
111 else
112 rl = estate_rl(sm->state);
113 rl = cast_rl(&llong_ctype, rl);
114 mem_sql(NULL,
115 "insert into local_values values ('%s', '%s', '%s', %lu);",
116 get_filename(), sm->name, show_rl(rl),
117 (unsigned long)sm->sym);
118 } END_FOR_EACH_PTR(sm);
121 static int get_initial_value_sym(struct symbol *sym, char *name, sval_t *sval)
123 struct expression *expr_symbol, *deref, *tmp;
124 char *member_name;
126 if (!sym)
127 return 0;
129 if (!sym->initializer) {
130 *sval = sval_type_val(&llong_ctype, 0);
131 return 1;
133 if (sym->initializer->type != EXPR_INITIALIZER)
134 return get_value(sym->initializer, sval);
136 expr_symbol = symbol_expression(sym);
137 FOR_EACH_PTR(sym->initializer->expr_list, tmp) {
138 if (tmp->type != EXPR_IDENTIFIER) /* how to handle arrays?? */
139 continue;
140 deref = member_expression(expr_symbol, '.', tmp->expr_ident);
141 member_name = expr_to_var(deref);
142 if (!member_name)
143 continue;
144 if (strcmp(name, member_name) == 0) {
145 free_string(member_name);
146 return get_value(tmp->ident_expression, sval);
148 free_string(member_name);
149 } END_FOR_EACH_PTR(tmp);
151 return 0;
154 static char *cur_name;
155 static struct symbol *cur_symbol;
156 static struct range_list *cur_rl;
157 static void add_current_local(void)
159 sval_t initial;
161 if (!get_initial_value_sym(cur_symbol, cur_name, &initial)) {
162 free_string(cur_name);
163 cur_name = NULL;
164 cur_rl = NULL;
165 return;
167 add_range(&cur_rl, initial, initial);
168 if (!is_whole_rl(cur_rl))
169 sql_insert_local_values(cur_name, show_rl(cur_rl));
170 free_string(cur_name);
171 cur_name = NULL;
172 cur_rl = NULL;
175 static int save_final_values(void *unused, int argc, char **argv, char **azColName)
177 char *name = argv[0];
178 char *sym_str = argv[1];
179 char *value = argv[2];
180 struct range_list *rl;
182 if (!cur_name) {
183 cur_name = alloc_string(name);
184 cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10);
185 } else if (strcmp(cur_name, name) != 0) {
186 add_current_local();
187 cur_name = alloc_string(name);
188 cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10);
189 cur_rl = NULL;
192 str_to_rl(&llong_ctype, value, &rl);
193 cur_rl = rl_union(cur_rl, rl);
195 return 0;
198 static void match_end_file(struct symbol_list *sym_list)
200 mem_sql(save_final_values,
201 "select distinct variable, symbol, value from local_values order by variable;");
202 if (cur_name)
203 add_current_local();
206 void register_local_values(int id)
208 my_id = id;
210 if (option_info) {
211 add_extra_mod_hook(&extra_mod_hook);
212 add_unmatched_state_hook(my_id, &unmatched_state);
213 add_merge_hook(my_id, &merge_estates);
214 all_return_states_hook(&process_states);
215 add_hook(match_end_file, END_FILE_HOOK);
216 mem_sql(NULL, "alter table local_values add column symbol integer;");