1 /* 2 * Copyright (C) 2016 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 /* 19 * What we're doing here is saving all the possible values for static variables. 20 * Later on we might do globals as well. 21 * 22 */ 23 24 #include "smatch.h" 25 #include "smatch_slist.h" 26 #include "smatch_extra.h" 27 28 static int my_id; 29 static struct stree *vals; 30 31 static int save_rl(void *_rl, int argc, char **argv, char **azColName) 32 { 33 unsigned long *rl = _rl; 34 35 *rl = strtoul(argv[0], NULL, 10); 36 return 0; 37 } 38 39 static struct range_list *select_orig(mtag_t tag, int offset) 40 { 41 struct range_list *rl = NULL; 42 43 mem_sql(&save_rl, &rl, "select value from mtag_data where tag = %lld and offset = %d;", 44 tag, offset); 45 return rl; 46 } 47 48 static int is_kernel_param(const char *name) 49 { 50 struct sm_state *tmp; 51 char buf[256]; 52 53 /* 54 * I'm ignoring these because otherwise Smatch thinks that kernel 55 * parameters are always set to the default. 56 * 57 */ 58 59 if (option_project != PROJ_KERNEL) 60 return 0; 61 62 snprintf(buf, sizeof(buf), "__param_%s.arg", name); 63 64 FOR_EACH_SM(vals, tmp) { 65 if (strcmp(tmp->name, buf) == 0) 66 return 1; 67 } END_FOR_EACH_SM(tmp); 68 69 return 0; 70 } 71 72 static void insert_mtag_data(mtag_t tag, int offset, struct range_list *rl) 73 { 74 rl = clone_rl_permanent(rl); 75 76 mem_sql(NULL, NULL, "delete from mtag_data where tag = %lld and offset = %d and type = %d", 77 tag, offset, DATA_VALUE); 78 mem_sql(NULL, NULL, "insert into mtag_data values (%lld, %d, %d, '%lu');", 79 tag, offset, DATA_VALUE, (unsigned long)rl); 80 } 81 82 void update_mtag_data(struct expression *expr) 83 { 84 struct range_list *orig, *new, *rl; 85 struct symbol *type; 86 char *name; 87 mtag_t tag; 88 int offset; 89 90 name = expr_to_var(expr); 91 if (is_kernel_param(name)) { 92 free_string(name); 93 return; 94 } 95 free_string(name); 96 97 if (!expr_to_mtag_offset(expr, &tag, &offset)) 98 return; 99 100 type = get_type(expr); 101 if ((offset == 0) && 102 (!type || type == &void_ctype || 103 type->type == SYM_STRUCT || type->type == SYM_UNION || type->type == SYM_ARRAY)) 104 return; 105 106 get_absolute_rl(expr, &rl); 107 108 orig = select_orig(tag, offset); 109 new = rl_union(orig, rl); 110 insert_mtag_data(tag, offset, new); 111 } 112 113 static void match_global_assign(struct expression *expr) 114 { 115 struct range_list *rl; 116 mtag_t tag; 117 int offset; 118 char *name; 119 120 name = expr_to_var(expr->left); 121 if (is_kernel_param(name)) { 122 free_string(name); 123 return; 124 } 125 free_string(name); 126 127 if (!expr_to_mtag_offset(expr->left, &tag, &offset)) 128 return; 129 130 get_absolute_rl(expr->right, &rl); 131 insert_mtag_data(tag, offset, rl); 132 } 133 134 static int save_mtag_data(void *_unused, int argc, char **argv, char **azColName) 135 { 136 struct range_list *rl; 137 138 if (argc != 4) { 139 sm_msg("Error saving mtag data"); 140 return 0; 141 } 142 if (!option_info) 143 return 0; 144 145 rl = (struct range_list *)strtoul(argv[3], NULL, 10); 146 sm_msg("SQL: insert into mtag_data values ('%s', '%s', '%s', '%s');", 147 argv[0], argv[1], argv[2], show_rl(rl)); 148 149 return 0; 150 } 151 152 static void match_end_file(struct symbol_list *sym_list) 153 { 154 mem_sql(&save_mtag_data, NULL, "select * from mtag_data where type = %d;", 155 DATA_VALUE); 156 } 157 158 struct db_info { 159 struct symbol *type; 160 struct range_list *rl; 161 }; 162 163 static int get_vals(void *_db_info, int argc, char **argv, char **azColName) 164 { 165 struct db_info *db_info = _db_info; 166 struct range_list *tmp; 167 168 str_to_rl(db_info->type, argv[0], &tmp); 169 if (db_info->rl) 170 db_info->rl = rl_union(db_info->rl, tmp); 171 else 172 db_info->rl = tmp; 173 174 return 0; 175 } 176 177 struct db_cache_results { 178 mtag_t tag; 179 struct range_list *rl; 180 }; 181 static struct db_cache_results cached_results[8]; 182 183 static int get_rl_from_mtag_offset(mtag_t tag, int offset, struct symbol *type, struct range_list **rl) 184 { 185 struct db_info db_info = {}; 186 mtag_t merged = tag | offset; 187 static int idx; 188 int ret; 189 int i; 190 191 if (!type || type == &void_ctype || 192 (type->type == SYM_STRUCT || type->type == SYM_ARRAY || type->type == SYM_UNION)) 193 return 0; 194 195 for (i = 0; i < ARRAY_SIZE(cached_results); i++) { 196 if (merged == cached_results[i].tag) { 197 if (cached_results[i].rl) { 198 *rl = cached_results[i].rl; 199 return 1; 200 } 201 return 0; 202 } 203 } 204 205 db_info.type = type; 206 207 run_sql(get_vals, &db_info, 208 "select value from mtag_data where tag = %lld and offset = %d and type = %d;", 209 tag, offset, DATA_VALUE); 210 if (!db_info.rl || is_whole_rl(db_info.rl)) { 211 db_info.rl = NULL; 212 ret = 0; 213 goto update_cache; 214 } 215 216 *rl = db_info.rl; 217 ret = 1; 218 219 update_cache: 220 cached_results[idx].tag = merged; 221 cached_results[idx].rl = db_info.rl; 222 idx = (idx + 1) % ARRAY_SIZE(cached_results); 223 224 return ret; 225 } 226 227 static void clear_cache(struct symbol *sym) 228 { 229 memset(cached_results, 0, sizeof(cached_results)); 230 } 231 232 int get_mtag_rl(struct expression *expr, struct range_list **rl) 233 { 234 struct symbol *type; 235 mtag_t tag; 236 int offset; 237 238 if (!expr_to_mtag_offset(expr, &tag, &offset)) 239 return 0; 240 if (offset >= MTAG_OFFSET_MASK) 241 return 0; 242 243 type = get_type(expr); 244 if (!type) 245 return 0; 246 247 return get_rl_from_mtag_offset(tag, offset, type, rl); 248 } 249 250 void register_mtag_data(int id) 251 { 252 my_id = id; 253 254 add_hook(&clear_cache, FUNC_DEF_HOOK); 255 256 // if (!option_info) 257 // return; 258 add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK); 259 add_hook(&match_end_file, END_FILE_HOOK); 260 } 261