flow: remove the call_split_expr() function
[smatch.git] / smatch_modification_hooks.c
blob548d5e2ed5253ea81ae50d63eb46669c8535d7ad
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 EARLY = 0,
39 LATE = 1,
40 BOTH = 2
43 static modification_hook **hooks;
44 static modification_hook **hooks_late;
46 ALLOCATOR(modification_data, "modification data");
48 static int my_id;
49 static struct smatch_state *alloc_my_state(struct expression *expr, struct smatch_state *prev)
51 struct smatch_state *state;
52 struct modification_data *data;
53 char *name;
55 state = __alloc_smatch_state(0);
56 expr = strip_expr(expr);
57 name = expr_to_str(expr);
58 state->name = alloc_sname(name);
59 free_string(name);
61 data = __alloc_modification_data(0);
62 data->prev = prev;
63 data->cur = expr;
64 state->data = data;
66 return state;
69 void add_modification_hook(int owner, modification_hook *call_back)
71 hooks[owner] = call_back;
74 void add_modification_hook_late(int owner, modification_hook *call_back)
76 hooks_late[owner] = call_back;
79 static int matches(char *name, struct symbol *sym, struct sm_state *sm)
81 int len;
83 if (sym != sm->sym)
84 return false;
86 len = strlen(name);
87 if (strncmp(sm->name, name, len) == 0) {
88 if (sm->name[len] == '\0')
89 return true;
90 if (sm->name[len] == '-' || sm->name[len] == '.')
91 return true;
93 if (sm->name[0] != '*')
94 return false;
95 if (strncmp(sm->name + 1, name, len) == 0) {
96 if (sm->name[len + 1] == '\0')
97 return true;
98 if (sm->name[len + 1] == '-' || sm->name[len + 1] == '.')
99 return true;
101 return false;
104 static void call_modification_hooks_name_sym(char *name, struct symbol *sym, struct expression *mod_expr, int late)
106 struct sm_state *sm;
107 struct smatch_state *prev;
108 int match;
110 prev = get_state(my_id, name, sym);
112 if (cur_func_sym && !__in_fake_assign)
113 set_state(my_id, name, sym, alloc_my_state(mod_expr, prev));
115 FOR_EACH_SM(__get_cur_stree(), sm) {
116 if (sm->owner > num_checks)
117 continue;
118 match = matches(name, sym, sm);
119 if (!match)
120 continue;
122 if (late == EARLY || late == BOTH) {
123 if (hooks[sm->owner])
124 (hooks[sm->owner])(sm, mod_expr);
126 if (late == LATE || late == BOTH) {
127 if (hooks_late[sm->owner])
128 (hooks_late[sm->owner])(sm, mod_expr);
131 } END_FOR_EACH_SM(sm);
134 static void call_modification_hooks(struct expression *expr, struct expression *mod_expr, int late)
136 char *name;
137 struct symbol *sym;
139 if (late == LATE)
140 update_mtag_data(expr);
142 name = expr_to_known_chunk_sym(expr, &sym);
143 if (!name)
144 goto free;
145 call_modification_hooks_name_sym(name, sym, mod_expr, late);
146 free:
147 free_string(name);
150 static void db_param_add(struct expression *expr, int param, char *key, char *value)
152 struct expression *arg, *gen_expr;
153 char *name, *other_name;
154 struct symbol *sym, *other_sym;
156 while (expr->type == EXPR_ASSIGNMENT)
157 expr = strip_expr(expr->right);
158 if (expr->type != EXPR_CALL)
159 return;
161 arg = get_argument_from_call_expr(expr->args, param);
162 if (!arg)
163 return;
165 gen_expr = gen_expression_from_key(arg, key);
166 if (gen_expr)
167 update_mtag_data(gen_expr);
169 name = get_variable_from_key(arg, key, &sym);
170 if (!name || !sym)
171 goto free;
173 __in_fake_assign++;
174 call_modification_hooks_name_sym(name, sym, expr, BOTH);
175 __in_fake_assign--;
177 other_name = map_long_to_short_name_sym(name, sym, &other_sym);
178 if (other_name) {
179 __in_fake_assign++;
180 call_modification_hooks_name_sym(other_name, other_sym, expr, BOTH);
181 __in_fake_assign--;
182 free_string(other_name);
185 free:
186 free_string(name);
189 static void match_assign(struct expression *expr, int late)
191 call_modification_hooks(expr->left, expr, late);
194 static void unop_expr(struct expression *expr, int late)
196 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
197 return;
199 call_modification_hooks(expr->unop, expr, late);
202 static void match_call(struct expression *expr)
204 struct expression *arg, *tmp;
206 FOR_EACH_PTR(expr->args, arg) {
207 tmp = strip_expr(arg);
208 if (tmp->type == EXPR_PREOP && tmp->op == '&')
209 call_modification_hooks(tmp->unop, expr, BOTH);
210 else if (option_no_db)
211 call_modification_hooks(deref_expression(tmp), expr, BOTH);
212 } END_FOR_EACH_PTR(arg);
215 static void asm_expr(struct statement *stmt, int late)
217 struct expression *expr;
218 int state = 0;
220 FOR_EACH_PTR(stmt->asm_outputs, expr) {
221 switch (state) {
222 case 0: /* identifier */
223 case 1: /* constraint */
224 state++;
225 continue;
226 case 2: /* expression */
227 state = 0;
228 call_modification_hooks(expr, NULL, late);
229 continue;
231 } END_FOR_EACH_PTR(expr);
235 static void match_assign_early(struct expression *expr)
237 match_assign(expr, EARLY);
240 static void unop_expr_early(struct expression *expr)
242 unop_expr(expr, EARLY);
245 static void asm_expr_early(struct statement *stmt)
247 asm_expr(stmt, EARLY);
250 static void match_assign_late(struct expression *expr)
252 match_assign(expr, LATE);
255 static void unop_expr_late(struct expression *expr)
257 unop_expr(expr, LATE);
260 static void asm_expr_late(struct statement *stmt)
262 asm_expr(stmt, LATE);
265 struct smatch_state *get_modification_state(struct expression *expr)
267 return get_state_expr(my_id, expr);
270 void register_modification_hooks(int id)
272 my_id = id;
274 hooks = malloc((num_checks + 1) * sizeof(*hooks));
275 memset(hooks, 0, (num_checks + 1) * sizeof(*hooks));
276 hooks_late = malloc((num_checks + 1) * sizeof(*hooks));
277 memset(hooks_late, 0, (num_checks + 1) * sizeof(*hooks));
279 add_hook(&match_assign_early, ASSIGNMENT_HOOK);
280 add_hook(&unop_expr_early, OP_HOOK);
281 add_hook(&asm_expr_early, ASM_HOOK);
284 void register_modification_hooks_late(int id)
286 add_hook(&match_call, FUNCTION_CALL_HOOK);
288 select_return_states_hook(PARAM_ADD, &db_param_add);
289 select_return_states_hook(PARAM_SET, &db_param_add);
291 add_hook(&match_assign_late, ASSIGNMENT_HOOK_AFTER);
292 add_hook(&unop_expr_late, OP_HOOK);
293 add_hook(&asm_expr_late, ASM_HOOK);