1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2009 Dan Carpenter.
3*1f5207b7SJohn Levon  *
4*1f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
5*1f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
6*1f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
7*1f5207b7SJohn Levon  * of the License, or (at your option) any later version.
8*1f5207b7SJohn Levon  *
9*1f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
10*1f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*1f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*1f5207b7SJohn Levon  * GNU General Public License for more details.
13*1f5207b7SJohn Levon  *
14*1f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
15*1f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16*1f5207b7SJohn Levon  */
17*1f5207b7SJohn Levon 
18*1f5207b7SJohn Levon /*
19*1f5207b7SJohn Levon  * There are a number of ways that variables are modified:
20*1f5207b7SJohn Levon  * 1) assignment
21*1f5207b7SJohn Levon  * 2) increment/decrement
22*1f5207b7SJohn Levon  * 3) assembly
23*1f5207b7SJohn Levon  * 4) inside functions.
24*1f5207b7SJohn Levon  *
25*1f5207b7SJohn Levon  * For setting stuff inside a function then, of course, it's more accurate if
26*1f5207b7SJohn Levon  * you have the cross function database built.  Otherwise we are super
27*1f5207b7SJohn Levon  * aggressive about marking things as modified and if you have "frob(foo);" then
28*1f5207b7SJohn Levon  * we assume "foo->bar" is modified.
29*1f5207b7SJohn Levon  */
30*1f5207b7SJohn Levon 
31*1f5207b7SJohn Levon #include <stdlib.h>
32*1f5207b7SJohn Levon #include <stdio.h>
33*1f5207b7SJohn Levon #include "smatch.h"
34*1f5207b7SJohn Levon #include "smatch_extra.h"
35*1f5207b7SJohn Levon #include "smatch_slist.h"
36*1f5207b7SJohn Levon 
37*1f5207b7SJohn Levon enum {
38*1f5207b7SJohn Levon 	EARLY = 0,
39*1f5207b7SJohn Levon 	LATE = 1,
40*1f5207b7SJohn Levon 	BOTH = 2
41*1f5207b7SJohn Levon };
42*1f5207b7SJohn Levon 
43*1f5207b7SJohn Levon static modification_hook **hooks;
44*1f5207b7SJohn Levon static modification_hook **hooks_late;
45*1f5207b7SJohn Levon 
46*1f5207b7SJohn Levon ALLOCATOR(modification_data, "modification data");
47*1f5207b7SJohn Levon 
48*1f5207b7SJohn Levon static int my_id;
49*1f5207b7SJohn Levon static struct smatch_state *alloc_my_state(struct expression *expr, struct smatch_state *prev)
50*1f5207b7SJohn Levon {
51*1f5207b7SJohn Levon 	struct smatch_state *state;
52*1f5207b7SJohn Levon 	struct modification_data *data;
53*1f5207b7SJohn Levon 	char *name;
54*1f5207b7SJohn Levon 
55*1f5207b7SJohn Levon 	state = __alloc_smatch_state(0);
56*1f5207b7SJohn Levon 	expr = strip_expr(expr);
57*1f5207b7SJohn Levon 	name = expr_to_str(expr);
58*1f5207b7SJohn Levon 	state->name = alloc_sname(name);
59*1f5207b7SJohn Levon 	free_string(name);
60*1f5207b7SJohn Levon 
61*1f5207b7SJohn Levon 	data = __alloc_modification_data(0);
62*1f5207b7SJohn Levon 	data->prev = prev;
63*1f5207b7SJohn Levon 	data->cur = expr;
64*1f5207b7SJohn Levon 	state->data = data;
65*1f5207b7SJohn Levon 
66*1f5207b7SJohn Levon 	return state;
67*1f5207b7SJohn Levon }
68*1f5207b7SJohn Levon 
69*1f5207b7SJohn Levon void add_modification_hook(int owner, modification_hook *call_back)
70*1f5207b7SJohn Levon {
71*1f5207b7SJohn Levon 	if (hooks[owner])
72*1f5207b7SJohn Levon 		sm_fatal("multiple modification hooks for %s", check_name(owner));
73*1f5207b7SJohn Levon 	hooks[owner] = call_back;
74*1f5207b7SJohn Levon }
75*1f5207b7SJohn Levon 
76*1f5207b7SJohn Levon void add_modification_hook_late(int owner, modification_hook *call_back)
77*1f5207b7SJohn Levon {
78*1f5207b7SJohn Levon 	if (hooks_late[owner])
79*1f5207b7SJohn Levon 		sm_fatal("multiple late modification hooks for %s", check_name(owner));
80*1f5207b7SJohn Levon 	hooks_late[owner] = call_back;
81*1f5207b7SJohn Levon }
82*1f5207b7SJohn Levon 
83*1f5207b7SJohn Levon static int matches(char *name, struct symbol *sym, struct sm_state *sm)
84*1f5207b7SJohn Levon {
85*1f5207b7SJohn Levon 	int len;
86*1f5207b7SJohn Levon 
87*1f5207b7SJohn Levon 	if (sym != sm->sym)
88*1f5207b7SJohn Levon 		return false;
89*1f5207b7SJohn Levon 
90*1f5207b7SJohn Levon 	len = strlen(name);
91*1f5207b7SJohn Levon 	if (strncmp(sm->name, name, len) == 0) {
92*1f5207b7SJohn Levon 		if (sm->name[len] == '\0')
93*1f5207b7SJohn Levon 			return true;
94*1f5207b7SJohn Levon 		if (sm->name[len] == '-' || sm->name[len] == '.')
95*1f5207b7SJohn Levon 			return true;
96*1f5207b7SJohn Levon 	}
97*1f5207b7SJohn Levon 	if (sm->name[0] != '*')
98*1f5207b7SJohn Levon 		return false;
99*1f5207b7SJohn Levon 	if (strncmp(sm->name + 1, name, len) == 0) {
100*1f5207b7SJohn Levon 		if (sm->name[len + 1] == '\0')
101*1f5207b7SJohn Levon 			return true;
102*1f5207b7SJohn Levon 		if (sm->name[len + 1] == '-' || sm->name[len + 1] == '.')
103*1f5207b7SJohn Levon 			return true;
104*1f5207b7SJohn Levon 	}
105*1f5207b7SJohn Levon 	return false;
106*1f5207b7SJohn Levon }
107*1f5207b7SJohn Levon 
108*1f5207b7SJohn Levon static void call_modification_hooks_name_sym(char *name, struct symbol *sym, struct expression *mod_expr, int late)
109*1f5207b7SJohn Levon {
110*1f5207b7SJohn Levon 	struct sm_state *sm;
111*1f5207b7SJohn Levon 	struct smatch_state *prev;
112*1f5207b7SJohn Levon 	int match;
113*1f5207b7SJohn Levon 
114*1f5207b7SJohn Levon 	prev = get_state(my_id, name, sym);
115*1f5207b7SJohn Levon 
116*1f5207b7SJohn Levon 	if (cur_func_sym && !__in_fake_assign)
117*1f5207b7SJohn Levon 		set_state(my_id, name, sym, alloc_my_state(mod_expr, prev));
118*1f5207b7SJohn Levon 
119*1f5207b7SJohn Levon 	FOR_EACH_SM(__get_cur_stree(), sm) {
120*1f5207b7SJohn Levon 		if (sm->owner > num_checks)
121*1f5207b7SJohn Levon 			continue;
122*1f5207b7SJohn Levon 		match = matches(name, sym, sm);
123*1f5207b7SJohn Levon 		if (!match)
124*1f5207b7SJohn Levon 			continue;
125*1f5207b7SJohn Levon 
126*1f5207b7SJohn Levon 		if (late == EARLY || late == BOTH) {
127*1f5207b7SJohn Levon 			if (hooks[sm->owner])
128*1f5207b7SJohn Levon 				(hooks[sm->owner])(sm, mod_expr);
129*1f5207b7SJohn Levon 		}
130*1f5207b7SJohn Levon 		if (late == LATE || late == BOTH) {
131*1f5207b7SJohn Levon 			if (hooks_late[sm->owner])
132*1f5207b7SJohn Levon 				(hooks_late[sm->owner])(sm, mod_expr);
133*1f5207b7SJohn Levon 		}
134*1f5207b7SJohn Levon 
135*1f5207b7SJohn Levon 	} END_FOR_EACH_SM(sm);
136*1f5207b7SJohn Levon }
137*1f5207b7SJohn Levon 
138*1f5207b7SJohn Levon static void call_modification_hooks(struct expression *expr, struct expression *mod_expr, int late)
139*1f5207b7SJohn Levon {
140*1f5207b7SJohn Levon 	char *name;
141*1f5207b7SJohn Levon 	struct symbol *sym;
142*1f5207b7SJohn Levon 
143*1f5207b7SJohn Levon 	if (late == LATE)
144*1f5207b7SJohn Levon 		update_mtag_data(expr);
145*1f5207b7SJohn Levon 
146*1f5207b7SJohn Levon 	name = expr_to_known_chunk_sym(expr, &sym);
147*1f5207b7SJohn Levon 	if (!name)
148*1f5207b7SJohn Levon 		goto free;
149*1f5207b7SJohn Levon 	call_modification_hooks_name_sym(name, sym, mod_expr, late);
150*1f5207b7SJohn Levon free:
151*1f5207b7SJohn Levon 	free_string(name);
152*1f5207b7SJohn Levon }
153*1f5207b7SJohn Levon 
154*1f5207b7SJohn Levon static void db_param_add(struct expression *expr, int param, char *key, char *value)
155*1f5207b7SJohn Levon {
156*1f5207b7SJohn Levon 	struct expression *arg, *gen_expr;
157*1f5207b7SJohn Levon 	char *name, *other_name;
158*1f5207b7SJohn Levon 	struct symbol *sym, *other_sym;
159*1f5207b7SJohn Levon 
160*1f5207b7SJohn Levon 	while (expr->type == EXPR_ASSIGNMENT)
161*1f5207b7SJohn Levon 		expr = strip_expr(expr->right);
162*1f5207b7SJohn Levon 	if (expr->type != EXPR_CALL)
163*1f5207b7SJohn Levon 		return;
164*1f5207b7SJohn Levon 
165*1f5207b7SJohn Levon 	arg = get_argument_from_call_expr(expr->args, param);
166*1f5207b7SJohn Levon 	if (!arg)
167*1f5207b7SJohn Levon 		return;
168*1f5207b7SJohn Levon 
169*1f5207b7SJohn Levon 	gen_expr = gen_expression_from_key(arg, key);
170*1f5207b7SJohn Levon 	if (gen_expr)
171*1f5207b7SJohn Levon 		update_mtag_data(gen_expr);
172*1f5207b7SJohn Levon 
173*1f5207b7SJohn Levon 	name = get_variable_from_key(arg, key, &sym);
174*1f5207b7SJohn Levon 	if (!name || !sym)
175*1f5207b7SJohn Levon 		goto free;
176*1f5207b7SJohn Levon 
177*1f5207b7SJohn Levon 	__in_fake_assign++;
178*1f5207b7SJohn Levon 	call_modification_hooks_name_sym(name, sym, expr, BOTH);
179*1f5207b7SJohn Levon 	__in_fake_assign--;
180*1f5207b7SJohn Levon 
181*1f5207b7SJohn Levon 	other_name = map_long_to_short_name_sym(name, sym, &other_sym);
182*1f5207b7SJohn Levon 	if (other_name) {
183*1f5207b7SJohn Levon 		__in_fake_assign++;
184*1f5207b7SJohn Levon 		call_modification_hooks_name_sym(other_name, other_sym, expr, BOTH);
185*1f5207b7SJohn Levon 		__in_fake_assign--;
186*1f5207b7SJohn Levon 		free_string(other_name);
187*1f5207b7SJohn Levon 	}
188*1f5207b7SJohn Levon 
189*1f5207b7SJohn Levon free:
190*1f5207b7SJohn Levon 	free_string(name);
191*1f5207b7SJohn Levon }
192*1f5207b7SJohn Levon 
193*1f5207b7SJohn Levon static void match_assign(struct expression *expr, int late)
194*1f5207b7SJohn Levon {
195*1f5207b7SJohn Levon 	call_modification_hooks(expr->left, expr, late);
196*1f5207b7SJohn Levon }
197*1f5207b7SJohn Levon 
198*1f5207b7SJohn Levon static void unop_expr(struct expression *expr, int late)
199*1f5207b7SJohn Levon {
200*1f5207b7SJohn Levon 	if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
201*1f5207b7SJohn Levon 		return;
202*1f5207b7SJohn Levon 
203*1f5207b7SJohn Levon 	call_modification_hooks(expr->unop, expr, late);
204*1f5207b7SJohn Levon }
205*1f5207b7SJohn Levon 
206*1f5207b7SJohn Levon static void match_call(struct expression *expr)
207*1f5207b7SJohn Levon {
208*1f5207b7SJohn Levon 	struct expression *arg, *tmp;
209*1f5207b7SJohn Levon 
210*1f5207b7SJohn Levon 	/* If we have the DB then trust the DB */
211*1f5207b7SJohn Levon 	if (!option_no_db)
212*1f5207b7SJohn Levon 		return;
213*1f5207b7SJohn Levon 
214*1f5207b7SJohn Levon 	FOR_EACH_PTR(expr->args, arg) {
215*1f5207b7SJohn Levon 		tmp = strip_expr(arg);
216*1f5207b7SJohn Levon 		if (tmp->type == EXPR_PREOP && tmp->op == '&')
217*1f5207b7SJohn Levon 			call_modification_hooks(tmp->unop, expr, BOTH);
218*1f5207b7SJohn Levon 		else
219*1f5207b7SJohn Levon 			call_modification_hooks(deref_expression(tmp), expr, BOTH);
220*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(arg);
221*1f5207b7SJohn Levon }
222*1f5207b7SJohn Levon 
223*1f5207b7SJohn Levon static void asm_expr(struct statement *stmt, int late)
224*1f5207b7SJohn Levon {
225*1f5207b7SJohn Levon 	struct expression *expr;
226*1f5207b7SJohn Levon 	int state = 0;
227*1f5207b7SJohn Levon 
228*1f5207b7SJohn Levon 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
229*1f5207b7SJohn Levon 		switch (state) {
230*1f5207b7SJohn Levon 		case 0: /* identifier */
231*1f5207b7SJohn Levon 		case 1: /* constraint */
232*1f5207b7SJohn Levon 			state++;
233*1f5207b7SJohn Levon 			continue;
234*1f5207b7SJohn Levon 		case 2: /* expression */
235*1f5207b7SJohn Levon 			state = 0;
236*1f5207b7SJohn Levon 			call_modification_hooks(expr, NULL, late);
237*1f5207b7SJohn Levon 			continue;
238*1f5207b7SJohn Levon 		}
239*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(expr);
240*1f5207b7SJohn Levon }
241*1f5207b7SJohn Levon 
242*1f5207b7SJohn Levon 
243*1f5207b7SJohn Levon static void match_assign_early(struct expression *expr)
244*1f5207b7SJohn Levon {
245*1f5207b7SJohn Levon 	match_assign(expr, EARLY);
246*1f5207b7SJohn Levon }
247*1f5207b7SJohn Levon 
248*1f5207b7SJohn Levon static void unop_expr_early(struct expression *expr)
249*1f5207b7SJohn Levon {
250*1f5207b7SJohn Levon 	unop_expr(expr, EARLY);
251*1f5207b7SJohn Levon }
252*1f5207b7SJohn Levon 
253*1f5207b7SJohn Levon static void asm_expr_early(struct statement *stmt)
254*1f5207b7SJohn Levon {
255*1f5207b7SJohn Levon 	asm_expr(stmt, EARLY);
256*1f5207b7SJohn Levon }
257*1f5207b7SJohn Levon 
258*1f5207b7SJohn Levon static void match_assign_late(struct expression *expr)
259*1f5207b7SJohn Levon {
260*1f5207b7SJohn Levon 	match_assign(expr, LATE);
261*1f5207b7SJohn Levon }
262*1f5207b7SJohn Levon 
263*1f5207b7SJohn Levon static void unop_expr_late(struct expression *expr)
264*1f5207b7SJohn Levon {
265*1f5207b7SJohn Levon 	unop_expr(expr, LATE);
266*1f5207b7SJohn Levon }
267*1f5207b7SJohn Levon 
268*1f5207b7SJohn Levon static void asm_expr_late(struct statement *stmt)
269*1f5207b7SJohn Levon {
270*1f5207b7SJohn Levon 	asm_expr(stmt, LATE);
271*1f5207b7SJohn Levon }
272*1f5207b7SJohn Levon 
273*1f5207b7SJohn Levon struct smatch_state *get_modification_state(struct expression *expr)
274*1f5207b7SJohn Levon {
275*1f5207b7SJohn Levon 	return get_state_expr(my_id, expr);
276*1f5207b7SJohn Levon }
277*1f5207b7SJohn Levon 
278*1f5207b7SJohn Levon void register_modification_hooks(int id)
279*1f5207b7SJohn Levon {
280*1f5207b7SJohn Levon 	my_id = id;
281*1f5207b7SJohn Levon 
282*1f5207b7SJohn Levon 	hooks = malloc((num_checks + 1) * sizeof(*hooks));
283*1f5207b7SJohn Levon 	memset(hooks, 0, (num_checks + 1) * sizeof(*hooks));
284*1f5207b7SJohn Levon 	hooks_late = malloc((num_checks + 1) * sizeof(*hooks));
285*1f5207b7SJohn Levon 	memset(hooks_late, 0, (num_checks + 1) * sizeof(*hooks));
286*1f5207b7SJohn Levon 
287*1f5207b7SJohn Levon 	add_hook(&match_assign_early, ASSIGNMENT_HOOK);
288*1f5207b7SJohn Levon 	add_hook(&unop_expr_early, OP_HOOK);
289*1f5207b7SJohn Levon 	add_hook(&asm_expr_early, ASM_HOOK);
290*1f5207b7SJohn Levon }
291*1f5207b7SJohn Levon 
292*1f5207b7SJohn Levon void register_modification_hooks_late(int id)
293*1f5207b7SJohn Levon {
294*1f5207b7SJohn Levon 	add_hook(&match_call, FUNCTION_CALL_HOOK);
295*1f5207b7SJohn Levon 
296*1f5207b7SJohn Levon 	select_return_states_hook(PARAM_ADD, &db_param_add);
297*1f5207b7SJohn Levon 	select_return_states_hook(PARAM_SET, &db_param_add);
298*1f5207b7SJohn Levon 
299*1f5207b7SJohn Levon 	add_hook(&match_assign_late, ASSIGNMENT_HOOK_AFTER);
300*1f5207b7SJohn Levon 	add_hook(&unop_expr_late, OP_HOOK);
301*1f5207b7SJohn Levon 	add_hook(&asm_expr_late, ASM_HOOK);
302*1f5207b7SJohn Levon }
303*1f5207b7SJohn Levon 
304