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 "scope.h" 19 #include "smatch.h" 20 #include "smatch_slist.h" 21 #include "smatch_extra.h" 22 23 static int my_id; 24 25 /* 26 * I'm going to store the states of local data at the end of each function. 27 * Then at the end of the file, I'll combine the possible range lists for 28 * each state and store the value in the on-disk database. 29 * 30 * One issue is that when I read the data back from the in-memory database at 31 * the end of the file, then I don't have access to type information. I'll just 32 * cast everything to "long long" for now, I guess. We'll see how that works. 33 */ 34 35 static char *db_vals; 36 static int get_vals(void *unused, int argc, char **argv, char **azColName) 37 { 38 db_vals = alloc_string(argv[0]); 39 return 0; 40 } 41 42 static int is_array_symbol(struct expression *expr) 43 { 44 struct symbol *type; 45 46 if (!expr || expr->type != EXPR_SYMBOL) 47 return 0; 48 type = get_type(expr); 49 if (!type) 50 return 0; 51 if (type->type == SYM_ARRAY) 52 return 1; 53 return 0; 54 } 55 56 int get_local_rl(struct expression *expr, struct range_list **rl) 57 { 58 char *name; 59 struct range_list *tmp; 60 61 if (!is_static(expr)) 62 return 0; 63 if (is_array_symbol(expr)) 64 return 0; 65 name = expr_to_var(expr); 66 if (!name) 67 return 0; 68 69 db_vals = NULL; 70 run_sql(get_vals, NULL, 71 "select value from local_values where file = '%s' and variable = '%s';", 72 get_filename(), name); 73 free_string(name); 74 if (!db_vals) 75 return 0; 76 str_to_rl(&llong_ctype, db_vals, &tmp); 77 *rl = cast_rl(get_type(expr), tmp); 78 free_string(db_vals); 79 80 return 1; 81 } 82 83 int get_local_max_helper(struct expression *expr, sval_t *sval) 84 { 85 struct range_list *rl; 86 87 if (!get_local_rl(expr, &rl)) 88 return 0; 89 *sval = rl_max(rl); 90 return 1; 91 } 92 93 int get_local_min_helper(struct expression *expr, sval_t *sval) 94 { 95 struct range_list *rl; 96 97 if (!get_local_rl(expr, &rl)) 98 return 0; 99 *sval = rl_min(rl); 100 return 1; 101 } 102 103 static struct smatch_state *unmatched_state(struct sm_state *sm) 104 { 105 return alloc_estate_empty(); 106 } 107 108 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state) 109 { 110 struct smatch_state *old; 111 struct smatch_state *new; 112 113 if (!sym || !(sym->ctype.modifiers & MOD_STATIC)) 114 return; 115 old = get_state(my_id, name, sym); 116 if (old) 117 new = merge_estates(old, state); 118 else 119 new = state; 120 set_state(my_id, name, sym, new); 121 } 122 123 static void process_states(void) 124 { 125 struct sm_state *sm; 126 struct smatch_state *extra; 127 struct range_list *rl; 128 129 FOR_EACH_SM(__get_cur_stree(), sm) { 130 if (sm->owner != my_id) 131 continue; 132 extra = get_state(SMATCH_EXTRA, sm->name, sm->sym); 133 if (extra && estate_rl(extra)) 134 rl = rl_intersection(estate_rl(sm->state), estate_rl(extra)); 135 else 136 rl = estate_rl(sm->state); 137 rl = cast_rl(&llong_ctype, rl); 138 mem_sql(NULL, NULL, 139 "insert into local_values values ('%s', '%s', '%s', %lu);", 140 get_filename(), sm->name, show_rl(rl), 141 (unsigned long)sm->sym); 142 } END_FOR_EACH_SM(sm); 143 } 144 145 static int get_initial_value_sym(struct symbol *sym, char *name, sval_t *sval) 146 { 147 struct expression *expr_symbol, *deref, *tmp; 148 char *member_name; 149 150 if (!sym) 151 return 0; 152 153 if (!sym->initializer) { 154 *sval = sval_type_val(&llong_ctype, 0); 155 return 1; 156 } 157 if (sym->initializer->type != EXPR_INITIALIZER) 158 return get_value(sym->initializer, sval); 159 160 expr_symbol = symbol_expression(sym); 161 FOR_EACH_PTR(sym->initializer->expr_list, tmp) { 162 if (tmp->type != EXPR_IDENTIFIER) /* how to handle arrays?? */ 163 continue; 164 deref = member_expression(expr_symbol, '.', tmp->expr_ident); 165 member_name = expr_to_var(deref); 166 if (!member_name) 167 continue; 168 if (strcmp(name, member_name) == 0) { 169 free_string(member_name); 170 return get_value(tmp->ident_expression, sval); 171 } 172 free_string(member_name); 173 } END_FOR_EACH_PTR(tmp); 174 175 return 0; 176 } 177 178 static char *cur_name; 179 static struct symbol *cur_symbol; 180 static struct range_list *cur_rl; 181 static void add_current_local(void) 182 { 183 sval_t initial; 184 185 if (!get_initial_value_sym(cur_symbol, cur_name, &initial)) { 186 free_string(cur_name); 187 cur_name = NULL; 188 cur_rl = NULL; 189 return; 190 } 191 add_range(&cur_rl, initial, initial); 192 if (!is_whole_rl(cur_rl)) 193 sql_insert_local_values(cur_name, show_rl(cur_rl)); 194 free_string(cur_name); 195 cur_name = NULL; 196 cur_rl = NULL; 197 } 198 199 static int save_final_values(void *unused, int argc, char **argv, char **azColName) 200 { 201 char *name = argv[0]; 202 char *sym_str = argv[1]; 203 char *value = argv[2]; 204 struct range_list *rl; 205 206 if (!cur_name) { 207 cur_name = alloc_string(name); 208 cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10); 209 } else if (strcmp(cur_name, name) != 0) { 210 add_current_local(); 211 cur_name = alloc_string(name); 212 cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10); 213 cur_rl = NULL; 214 } 215 216 str_to_rl(&llong_ctype, value, &rl); 217 cur_rl = rl_union(cur_rl, rl); 218 219 return 0; 220 } 221 222 static void match_end_file(struct symbol_list *sym_list) 223 { 224 mem_sql(save_final_values, NULL, 225 "select distinct variable, symbol, value from local_values order by variable;"); 226 if (cur_name) 227 add_current_local(); 228 } 229 230 void register_local_values(int id) 231 { 232 my_id = id; 233 234 if (!option_info) 235 return; 236 237 set_dynamic_states(my_id); 238 add_extra_mod_hook(&extra_mod_hook); 239 add_unmatched_state_hook(my_id, &unmatched_state); 240 add_merge_hook(my_id, &merge_estates); 241 all_return_states_hook(&process_states); 242 add_hook(match_end_file, END_FILE_HOOK); 243 mem_sql(NULL, NULL, "alter table local_values add column symbol integer;"); 244 }