states: make debug output more consistent
[smatch.git] / smatch_modification_hooks.c
blobf12c7d87684b090394b66bec645834468c22091b
1 /*
2 * Copyright (C) 2009 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * There are a number of ways that variables are modified:
20 * 1) assignment
21 * 2) increment/decrement
22 * 3) assembly
23 * 4) inside functions.
25 * For setting stuff inside a function then, of course, it's more accurate if
26 * you have the cross function database built. Otherwise we are super
27 * aggressive about marking things as modified and if you have "frob(foo);" then
28 * we assume "foo->bar" is modified.
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include "smatch.h"
34 #include "smatch_extra.h"
35 #include "smatch_slist.h"
37 enum {
38 match_none = 0,
39 match_exact,
40 match_indirect
43 enum {
44 EARLY = 0,
45 LATE = 1,
46 BOTH = 2
49 static modification_hook **hooks;
50 static modification_hook **indirect_hooks; /* parent struct modified etc */
51 static modification_hook **hooks_late;
52 static modification_hook **indirect_hooks_late; /* parent struct modified etc */
54 ALLOCATOR(modification_data, "modification data");
56 static int my_id;
57 static struct smatch_state *alloc_my_state(struct expression *expr, struct smatch_state *prev)
59 struct smatch_state *state;
60 struct modification_data *data;
61 char *name;
63 state = __alloc_smatch_state(0);
64 expr = strip_expr(expr);
65 name = expr_to_str(expr);
66 state->name = alloc_sname(name);
67 free_string(name);
69 data = __alloc_modification_data(0);
70 data->prev = prev;
71 data->cur = expr;
72 state->data = data;
74 return state;
77 void add_modification_hook(int owner, modification_hook *call_back)
79 hooks[owner] = call_back;
82 void add_indirect_modification_hook(int owner, modification_hook *call_back)
84 indirect_hooks[owner] = call_back;
87 void add_modification_hook_late(int owner, modification_hook *call_back)
89 hooks_late[owner] = call_back;
92 void add_indirect_modification_hook_late(int owner, modification_hook *call_back)
94 indirect_hooks_late[owner] = call_back;
97 static int matches(char *name, struct symbol *sym, struct sm_state *sm)
99 int len;
101 if (sym != sm->sym)
102 return match_none;
104 len = strlen(name);
105 if (strncmp(sm->name, name, len) == 0) {
106 if (sm->name[len] == '\0')
107 return match_exact;
108 if (sm->name[len] == '-' || sm->name[len] == '.')
109 return match_indirect;
111 if (sm->name[0] != '*')
112 return match_none;
113 if (strncmp(sm->name + 1, name, len) == 0) {
114 if (sm->name[len + 1] == '\0')
115 return match_indirect;
116 if (sm->name[len + 1] == '-' || sm->name[len + 1] == '.')
117 return match_indirect;
119 return match_none;
122 static void call_modification_hooks_name_sym(char *name, struct symbol *sym, struct expression *mod_expr, int late)
124 struct stree *stree;
125 struct sm_state *sm;
126 struct smatch_state *prev;
127 int match;
129 prev = get_state(my_id, name, sym);
130 set_state(my_id, name, sym, alloc_my_state(mod_expr, prev));
132 stree = __get_cur_stree();
134 FOR_EACH_SM(stree, sm) {
135 if (sm->owner > num_checks)
136 continue;
137 match = matches(name, sym, sm);
138 if (!match)
139 continue;
141 if (late == EARLY || late == BOTH) {
142 if (hooks[sm->owner])
143 (hooks[sm->owner])(sm, mod_expr);
144 if (match == match_indirect && indirect_hooks[sm->owner])
145 (indirect_hooks[sm->owner])(sm, mod_expr);
147 if (late == LATE || late == BOTH) {
148 if (hooks_late[sm->owner])
149 (hooks_late[sm->owner])(sm, mod_expr);
150 if (match == match_indirect && indirect_hooks_late[sm->owner])
151 (indirect_hooks_late[sm->owner])(sm, mod_expr);
154 } END_FOR_EACH_SM(sm);
157 static void call_modification_hooks(struct expression *expr, struct expression *mod_expr, int late)
159 char *name;
160 struct symbol *sym;
162 name = expr_to_known_chunk_sym(expr, &sym);
163 if (!name)
164 goto free;
165 call_modification_hooks_name_sym(name, sym, mod_expr, late);
166 free:
167 free_string(name);
170 static void db_param_add(struct expression *expr, int param, char *key, char *value)
172 struct expression *arg;
173 char *name;
174 struct symbol *sym;
176 while (expr->type == EXPR_ASSIGNMENT)
177 expr = strip_expr(expr->right);
178 if (expr->type != EXPR_CALL)
179 return;
181 arg = get_argument_from_call_expr(expr->args, param);
182 if (!arg)
183 return;
185 name = get_variable_from_key(arg, key, &sym);
186 if (!name || !sym)
187 goto free;
189 call_modification_hooks_name_sym(name, sym, expr, BOTH);
190 free:
191 free_string(name);
194 static void match_assign(struct expression *expr, int late)
196 call_modification_hooks(expr->left, expr, late);
199 static void unop_expr(struct expression *expr, int late)
201 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
202 return;
204 call_modification_hooks(expr->unop, expr, late);
207 static void match_call(struct expression *expr)
209 struct expression *arg, *tmp;
211 FOR_EACH_PTR(expr->args, arg) {
212 tmp = strip_expr(arg);
213 if (tmp->type == EXPR_PREOP && tmp->op == '&')
214 call_modification_hooks(tmp->unop, expr, BOTH);
215 else if (option_no_db)
216 call_modification_hooks(deref_expression(tmp), expr, BOTH);
217 } END_FOR_EACH_PTR(arg);
220 static void asm_expr(struct statement *stmt, int late)
222 struct expression *expr;
223 int state = 0;
225 FOR_EACH_PTR(stmt->asm_outputs, expr) {
226 switch (state) {
227 case 0: /* identifier */
228 case 1: /* constraint */
229 state++;
230 continue;
231 case 2: /* expression */
232 state = 0;
233 call_modification_hooks(expr, NULL, late);
234 continue;
236 } END_FOR_EACH_PTR(expr);
240 static void match_assign_early(struct expression *expr)
242 match_assign(expr, EARLY);
245 static void unop_expr_early(struct expression *expr)
247 unop_expr(expr, EARLY);
250 static void asm_expr_early(struct statement *stmt)
252 asm_expr(stmt, EARLY);
255 static void match_assign_late(struct expression *expr)
257 match_assign(expr, LATE);
260 static void unop_expr_late(struct expression *expr)
262 unop_expr(expr, LATE);
265 static void asm_expr_late(struct statement *stmt)
267 asm_expr(stmt, LATE);
270 static void scope_end(void *_sym)
272 struct symbol *sym = _sym;
273 struct expression *expr = symbol_expression(sym);
275 call_modification_hooks(expr, NULL, BOTH);
278 static void match_declaration(struct symbol *sym)
280 add_scope_hook(&scope_end, sym);
283 struct smatch_state *get_modification_state(struct expression *expr)
285 return get_state_expr(my_id, expr);
288 void register_modification_hooks(int id)
290 my_id = id;
292 hooks = malloc((num_checks + 1) * sizeof(*hooks));
293 memset(hooks, 0, (num_checks + 1) * sizeof(*hooks));
294 indirect_hooks = malloc((num_checks + 1) * sizeof(*hooks));
295 memset(indirect_hooks, 0, (num_checks + 1) * sizeof(*hooks));
296 hooks_late = malloc((num_checks + 1) * sizeof(*hooks));
297 memset(hooks_late, 0, (num_checks + 1) * sizeof(*hooks));
298 indirect_hooks_late = malloc((num_checks + 1) * sizeof(*hooks));
299 memset(indirect_hooks_late, 0, (num_checks + 1) * sizeof(*hooks));
301 add_hook(&match_assign_early, ASSIGNMENT_HOOK);
302 add_hook(&unop_expr_early, OP_HOOK);
303 add_hook(&asm_expr_early, ASM_HOOK);
306 void register_modification_hooks_late(int id)
308 add_hook(&match_call, FUNCTION_CALL_HOOK);
310 add_hook(&match_assign_late, ASSIGNMENT_HOOK);
311 add_hook(&unop_expr_late, OP_HOOK);
312 add_hook(&asm_expr_late, ASM_HOOK);
314 select_return_states_hook(PARAM_ADD, &db_param_add);
315 select_return_states_hook(PARAM_SET, &db_param_add);
316 add_hook(&match_declaration, DECLARATION_HOOK);