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