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