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 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 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 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 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 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 140 static void free_var_sym(struct var_sym *vs) 141 { 142 free_string(vs->var); 143 __free_var_sym(vs); 144 } 145 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 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 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 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 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 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 228 void free_var_sym_list(struct var_sym_list **list) 229 { 230 __free_ptr_list((struct ptr_list **)list); 231 } 232 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