1*1f5207b7SJohn Levon /*
2*1f5207b7SJohn Levon  * Copyright (C) 2013 Oracle.
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 #include "smatch.h"
19*1f5207b7SJohn Levon 
20*1f5207b7SJohn Levon ALLOCATOR(var_sym, "var_sym structs");
21*1f5207b7SJohn Levon 
alloc_var_sym(const char * var,struct symbol * sym)22*1f5207b7SJohn Levon struct var_sym *alloc_var_sym(const char *var, struct symbol *sym)
23*1f5207b7SJohn Levon {
24*1f5207b7SJohn Levon 	struct var_sym *tmp;
25*1f5207b7SJohn Levon 
26*1f5207b7SJohn Levon 	tmp = __alloc_var_sym(0);
27*1f5207b7SJohn Levon 	tmp->var = alloc_string(var);
28*1f5207b7SJohn Levon 	tmp->sym = sym;
29*1f5207b7SJohn Levon 	return tmp;
30*1f5207b7SJohn Levon }
31*1f5207b7SJohn Levon 
expr_to_vsl(struct expression * expr)32*1f5207b7SJohn Levon struct var_sym_list *expr_to_vsl(struct expression *expr)
33*1f5207b7SJohn Levon {
34*1f5207b7SJohn Levon 	struct expression *unop;
35*1f5207b7SJohn Levon 	struct var_sym_list *ret = NULL;
36*1f5207b7SJohn Levon 	char *var;
37*1f5207b7SJohn Levon 	struct symbol *sym;
38*1f5207b7SJohn Levon 
39*1f5207b7SJohn Levon 	expr = strip_expr(expr);
40*1f5207b7SJohn Levon 	if (!expr)
41*1f5207b7SJohn Levon 		return NULL;
42*1f5207b7SJohn Levon 
43*1f5207b7SJohn Levon 	if ((expr->type == EXPR_PREOP && expr->op == '*')) {
44*1f5207b7SJohn Levon 		unop = strip_expr(expr->unop);
45*1f5207b7SJohn Levon 
46*1f5207b7SJohn Levon 		if (unop->type == EXPR_SYMBOL)
47*1f5207b7SJohn Levon 			goto one_var;
48*1f5207b7SJohn Levon 		return expr_to_vsl(unop);
49*1f5207b7SJohn Levon 	}
50*1f5207b7SJohn Levon 
51*1f5207b7SJohn Levon 	if (expr->type == EXPR_BINOP ||
52*1f5207b7SJohn Levon 	    expr->type == EXPR_LOGICAL ||
53*1f5207b7SJohn Levon 	    expr->type == EXPR_COMPARE) {
54*1f5207b7SJohn Levon 		struct var_sym_list *left, *right;
55*1f5207b7SJohn Levon 
56*1f5207b7SJohn Levon 		left = expr_to_vsl(expr->left);
57*1f5207b7SJohn Levon 		right = expr_to_vsl(expr->right);
58*1f5207b7SJohn Levon 		ret = combine_var_sym_lists(left, right);
59*1f5207b7SJohn Levon 		free_var_syms_and_list(&left);
60*1f5207b7SJohn Levon 		free_var_syms_and_list(&right);
61*1f5207b7SJohn Levon 		return ret;
62*1f5207b7SJohn Levon 	}
63*1f5207b7SJohn Levon 
64*1f5207b7SJohn Levon 	if (expr->type == EXPR_DEREF)
65*1f5207b7SJohn Levon 		return expr_to_vsl(expr->deref);
66*1f5207b7SJohn Levon 
67*1f5207b7SJohn Levon one_var:
68*1f5207b7SJohn Levon 	var = expr_to_var_sym(expr, &sym);
69*1f5207b7SJohn Levon 	if (!var || !sym) {
70*1f5207b7SJohn Levon 		free_string(var);
71*1f5207b7SJohn Levon 		return NULL;
72*1f5207b7SJohn Levon 	}
73*1f5207b7SJohn Levon 	add_var_sym(&ret, var, sym);
74*1f5207b7SJohn Levon 	return ret;
75*1f5207b7SJohn Levon }
76*1f5207b7SJohn Levon 
cmp_var_sym(const struct var_sym * a,const struct var_sym * b)77*1f5207b7SJohn Levon int cmp_var_sym(const struct var_sym *a, const struct var_sym *b)
78*1f5207b7SJohn Levon {
79*1f5207b7SJohn Levon 	int ret;
80*1f5207b7SJohn Levon 
81*1f5207b7SJohn Levon 	if (a == b)
82*1f5207b7SJohn Levon 		return 0;
83*1f5207b7SJohn Levon 	if (!b)
84*1f5207b7SJohn Levon 		return -1;
85*1f5207b7SJohn Levon 	if (!a)
86*1f5207b7SJohn Levon 		return 1;
87*1f5207b7SJohn Levon 
88*1f5207b7SJohn Levon 	ret = strcmp(a->var, b->var);
89*1f5207b7SJohn Levon 	if (ret < 0)
90*1f5207b7SJohn Levon 		return -1;
91*1f5207b7SJohn Levon 	if (ret > 0)
92*1f5207b7SJohn Levon 		return 1;
93*1f5207b7SJohn Levon 
94*1f5207b7SJohn Levon 	if (!b->sym && a->sym)
95*1f5207b7SJohn Levon 		return -1;
96*1f5207b7SJohn Levon 	if (!a->sym && b->sym)
97*1f5207b7SJohn Levon 		return 1;
98*1f5207b7SJohn Levon 	if (a->sym < b->sym)
99*1f5207b7SJohn Levon 		return -1;
100*1f5207b7SJohn Levon 	if (a->sym > b->sym)
101*1f5207b7SJohn Levon 		return 1;
102*1f5207b7SJohn Levon 
103*1f5207b7SJohn Levon 	return 0;
104*1f5207b7SJohn Levon }
105*1f5207b7SJohn Levon 
add_var_sym(struct var_sym_list ** list,const char * var,struct symbol * sym)106*1f5207b7SJohn Levon void add_var_sym(struct var_sym_list **list, const char *var, struct symbol *sym)
107*1f5207b7SJohn Levon {
108*1f5207b7SJohn Levon 	struct var_sym *tmp, *new;
109*1f5207b7SJohn Levon 
110*1f5207b7SJohn Levon 	if (in_var_sym_list(*list, var, sym))
111*1f5207b7SJohn Levon 		return;
112*1f5207b7SJohn Levon 	new = alloc_var_sym(var, sym);
113*1f5207b7SJohn Levon 
114*1f5207b7SJohn Levon 	FOR_EACH_PTR(*list, tmp) {
115*1f5207b7SJohn Levon 		if (cmp_var_sym(tmp, new) < 0)
116*1f5207b7SJohn Levon 			continue;
117*1f5207b7SJohn Levon 		else if (cmp_var_sym(tmp, new) == 0) {
118*1f5207b7SJohn Levon 			return;
119*1f5207b7SJohn Levon 		} else {
120*1f5207b7SJohn Levon 			INSERT_CURRENT(new, tmp);
121*1f5207b7SJohn Levon 			return;
122*1f5207b7SJohn Levon 		}
123*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
124*1f5207b7SJohn Levon 	add_ptr_list(list, new);
125*1f5207b7SJohn Levon }
126*1f5207b7SJohn Levon 
add_var_sym_expr(struct var_sym_list ** list,struct expression * expr)127*1f5207b7SJohn Levon void add_var_sym_expr(struct var_sym_list **list, struct expression *expr)
128*1f5207b7SJohn Levon {
129*1f5207b7SJohn Levon 	char *var;
130*1f5207b7SJohn Levon 	struct symbol *sym;
131*1f5207b7SJohn Levon 
132*1f5207b7SJohn Levon 	var = expr_to_var_sym(expr, &sym);
133*1f5207b7SJohn Levon 	if (!var || !sym)
134*1f5207b7SJohn Levon 		goto free;
135*1f5207b7SJohn Levon 	add_var_sym(list, var, sym);
136*1f5207b7SJohn Levon free:
137*1f5207b7SJohn Levon 	free_string(var);
138*1f5207b7SJohn Levon }
139*1f5207b7SJohn Levon 
free_var_sym(struct var_sym * vs)140*1f5207b7SJohn Levon static void free_var_sym(struct var_sym *vs)
141*1f5207b7SJohn Levon {
142*1f5207b7SJohn Levon 	free_string(vs->var);
143*1f5207b7SJohn Levon 	__free_var_sym(vs);
144*1f5207b7SJohn Levon }
145*1f5207b7SJohn Levon 
del_var_sym(struct var_sym_list ** list,const char * var,struct symbol * sym)146*1f5207b7SJohn Levon void del_var_sym(struct var_sym_list **list, const char *var, struct symbol *sym)
147*1f5207b7SJohn Levon {
148*1f5207b7SJohn Levon 	struct var_sym *tmp;
149*1f5207b7SJohn Levon 
150*1f5207b7SJohn Levon 	FOR_EACH_PTR(*list, tmp) {
151*1f5207b7SJohn Levon 		if (tmp->sym == sym && strcmp(tmp->var, var) == 0) {
152*1f5207b7SJohn Levon 			DELETE_CURRENT_PTR(tmp);
153*1f5207b7SJohn Levon 			free_var_sym(tmp);
154*1f5207b7SJohn Levon 			return;
155*1f5207b7SJohn Levon 		}
156*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
157*1f5207b7SJohn Levon }
158*1f5207b7SJohn Levon 
in_var_sym_list(struct var_sym_list * list,const char * var,struct symbol * sym)159*1f5207b7SJohn Levon int in_var_sym_list(struct var_sym_list *list, const char *var, struct symbol *sym)
160*1f5207b7SJohn Levon {
161*1f5207b7SJohn Levon 	struct var_sym *tmp;
162*1f5207b7SJohn Levon 
163*1f5207b7SJohn Levon 	FOR_EACH_PTR(list, tmp) {
164*1f5207b7SJohn Levon 		if (tmp->sym == sym && strcmp(tmp->var, var) == 0)
165*1f5207b7SJohn Levon 			return 1;
166*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
167*1f5207b7SJohn Levon 	return 0;
168*1f5207b7SJohn Levon }
169*1f5207b7SJohn Levon 
clone_var_sym_list(struct var_sym_list * from_vsl)170*1f5207b7SJohn Levon struct var_sym_list *clone_var_sym_list(struct var_sym_list *from_vsl)
171*1f5207b7SJohn Levon {
172*1f5207b7SJohn Levon 	struct var_sym *tmp, *clone_vs;
173*1f5207b7SJohn Levon 	struct var_sym_list *to_vsl = NULL;
174*1f5207b7SJohn Levon 
175*1f5207b7SJohn Levon 	FOR_EACH_PTR(from_vsl, tmp) {
176*1f5207b7SJohn Levon 		clone_vs = alloc_var_sym(tmp->var, tmp->sym);
177*1f5207b7SJohn Levon 		add_ptr_list(&to_vsl, clone_vs);
178*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
179*1f5207b7SJohn Levon 	return to_vsl;
180*1f5207b7SJohn Levon }
181*1f5207b7SJohn Levon 
merge_var_sym_list(struct var_sym_list ** dest,struct var_sym_list * src)182*1f5207b7SJohn Levon void merge_var_sym_list(struct var_sym_list **dest, struct var_sym_list *src)
183*1f5207b7SJohn Levon {
184*1f5207b7SJohn Levon 	struct var_sym *tmp;
185*1f5207b7SJohn Levon 
186*1f5207b7SJohn Levon 	FOR_EACH_PTR(src, tmp) {
187*1f5207b7SJohn Levon 		add_var_sym(dest, tmp->var, tmp->sym);
188*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
189*1f5207b7SJohn Levon }
190*1f5207b7SJohn Levon 
combine_var_sym_lists(struct var_sym_list * one,struct var_sym_list * two)191*1f5207b7SJohn Levon struct var_sym_list *combine_var_sym_lists(struct var_sym_list *one, struct var_sym_list *two)
192*1f5207b7SJohn Levon {
193*1f5207b7SJohn Levon 	struct var_sym_list *to_vsl;
194*1f5207b7SJohn Levon 
195*1f5207b7SJohn Levon 	to_vsl = clone_var_sym_list(one);
196*1f5207b7SJohn Levon 	merge_var_sym_list(&to_vsl, two);
197*1f5207b7SJohn Levon 	return to_vsl;
198*1f5207b7SJohn Levon }
199*1f5207b7SJohn Levon 
var_sym_lists_equiv(struct var_sym_list * one,struct var_sym_list * two)200*1f5207b7SJohn Levon int var_sym_lists_equiv(struct var_sym_list *one, struct var_sym_list *two)
201*1f5207b7SJohn Levon {
202*1f5207b7SJohn Levon 	struct var_sym *one_tmp, *two_tmp;
203*1f5207b7SJohn Levon 
204*1f5207b7SJohn Levon 	if (one == two)
205*1f5207b7SJohn Levon 		return 1;
206*1f5207b7SJohn Levon 
207*1f5207b7SJohn Levon 	if (ptr_list_size((struct ptr_list *)one) != ptr_list_size((struct ptr_list *)two))
208*1f5207b7SJohn Levon 		return 0;
209*1f5207b7SJohn Levon 
210*1f5207b7SJohn Levon 	PREPARE_PTR_LIST(one, one_tmp);
211*1f5207b7SJohn Levon 	PREPARE_PTR_LIST(two, two_tmp);
212*1f5207b7SJohn Levon 	for (;;) {
213*1f5207b7SJohn Levon 		if (!one_tmp && !two_tmp)
214*1f5207b7SJohn Levon 			return 1;
215*1f5207b7SJohn Levon 		if (one_tmp->sym != two_tmp->sym)
216*1f5207b7SJohn Levon 			return 0;
217*1f5207b7SJohn Levon 		if (strcmp(one_tmp->var, two_tmp->var) != 0)
218*1f5207b7SJohn Levon 			return 0;
219*1f5207b7SJohn Levon 		NEXT_PTR_LIST(one_tmp);
220*1f5207b7SJohn Levon 		NEXT_PTR_LIST(two_tmp);
221*1f5207b7SJohn Levon 	}
222*1f5207b7SJohn Levon 	FINISH_PTR_LIST(two_tmp);
223*1f5207b7SJohn Levon 	FINISH_PTR_LIST(one_tmp);
224*1f5207b7SJohn Levon 
225*1f5207b7SJohn Levon 	return 1;
226*1f5207b7SJohn Levon }
227*1f5207b7SJohn Levon 
free_var_sym_list(struct var_sym_list ** list)228*1f5207b7SJohn Levon void free_var_sym_list(struct var_sym_list **list)
229*1f5207b7SJohn Levon {
230*1f5207b7SJohn Levon 	__free_ptr_list((struct ptr_list **)list);
231*1f5207b7SJohn Levon }
232*1f5207b7SJohn Levon 
free_var_syms_and_list(struct var_sym_list ** list)233*1f5207b7SJohn Levon void free_var_syms_and_list(struct var_sym_list **list)
234*1f5207b7SJohn Levon {
235*1f5207b7SJohn Levon 	struct var_sym *tmp;
236*1f5207b7SJohn Levon 
237*1f5207b7SJohn Levon 	FOR_EACH_PTR(*list, tmp) {
238*1f5207b7SJohn Levon 		free_var_sym(tmp);
239*1f5207b7SJohn Levon 	} END_FOR_EACH_PTR(tmp);
240*1f5207b7SJohn Levon 	free_var_sym_list(list);
241*1f5207b7SJohn Levon }
242*1f5207b7SJohn Levon 
243