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 bool is_ignored_macro(struct expression *expr) 73 { 74 char *macro; 75 76 macro = get_macro_name(expr->pos); 77 if (!macro) 78 return false; 79 if (strcmp(macro, "EXPORT_SYMBOL") == 0) 80 return true; 81 return false; 82 } 83 84 static void insert_mtag_data(mtag_t tag, int offset, struct range_list *rl) 85 { 86 rl = clone_rl_permanent(rl); 87 88 mem_sql(NULL, NULL, "delete from mtag_data where tag = %lld and offset = %d and type = %d", 89 tag, offset, DATA_VALUE); 90 mem_sql(NULL, NULL, "insert into mtag_data values (%lld, %d, %d, '%lu');", 91 tag, offset, DATA_VALUE, (unsigned long)rl); 92 } 93 94 static bool invalid_type(struct symbol *type) 95 { 96 if (!type) 97 return true; 98 if (type == &void_ctype) 99 return true; 100 if (type->type == SYM_STRUCT || 101 type->type == SYM_ARRAY || 102 type->type == SYM_UNION) 103 return true; 104 return false; 105 } 106 107 void update_mtag_data(struct expression *expr, struct smatch_state *state) 108 { 109 struct range_list *orig, *new; 110 struct symbol *type; 111 char *name; 112 mtag_t tag; 113 int offset; 114 115 if (!expr) 116 return; 117 if (is_local_variable(expr)) 118 return; 119 if (is_ignored_macro(expr)) 120 return; 121 name = expr_to_var(expr); 122 if (is_kernel_param(name)) { 123 free_string(name); 124 return; 125 } 126 free_string(name); 127 128 if (!expr_to_mtag_offset(expr, &tag, &offset)) 129 return; 130 131 type = get_type(expr); 132 if (offset == 0 && invalid_type(type)) 133 return; 134 135 orig = select_orig(tag, offset); 136 new = rl_union(orig, estate_rl(state)); 137 insert_mtag_data(tag, offset, new); 138 } 139 140 static void match_global_assign(struct expression *expr) 141 { 142 struct range_list *rl; 143 mtag_t tag; 144 int offset; 145 char *name; 146 147 if (is_ignored_macro(expr)) 148 return; 149 name = expr_to_var(expr->left); 150 if (is_kernel_param(name)) { 151 free_string(name); 152 return; 153 } 154 free_string(name); 155 156 if (!expr_to_mtag_offset(expr->left, &tag, &offset)) 157 return; 158 159 get_absolute_rl(expr->right, &rl); 160 insert_mtag_data(tag, offset, rl); 161 } 162 163 static int save_mtag_data(void *_unused, int argc, char **argv, char **azColName) 164 { 165 struct range_list *rl; 166 167 if (argc != 4) { 168 sm_msg("Error saving mtag data"); 169 return 0; 170 } 171 if (!option_info) 172 return 0; 173 174 rl = (struct range_list *)strtoul(argv[3], NULL, 10); 175 sm_msg("SQL: insert into mtag_data values ('%s', '%s', '%s', '%s');", 176 argv[0], argv[1], argv[2], show_rl(rl)); 177 178 return 0; 179 } 180 181 static void match_end_file(struct symbol_list *sym_list) 182 { 183 mem_sql(&save_mtag_data, NULL, "select * from mtag_data where type = %d;", 184 DATA_VALUE); 185 } 186 187 struct db_info { 188 struct symbol *type; 189 struct range_list *rl; 190 }; 191 192 static int get_vals(void *_db_info, int argc, char **argv, char **azColName) 193 { 194 struct db_info *db_info = _db_info; 195 struct range_list *tmp; 196 197 str_to_rl(db_info->type, argv[0], &tmp); 198 if (db_info->rl) 199 db_info->rl = rl_union(db_info->rl, tmp); 200 else 201 db_info->rl = tmp; 202 203 return 0; 204 } 205 206 struct db_cache_results { 207 mtag_t tag; 208 struct range_list *rl; 209 }; 210 static struct db_cache_results cached_results[8]; 211 212 static int get_rl_from_mtag_offset(mtag_t tag, int offset, struct symbol *type, struct range_list **rl) 213 { 214 struct db_info db_info = {}; 215 mtag_t merged = tag | offset; 216 static int idx; 217 int ret; 218 int i; 219 220 for (i = 0; i < ARRAY_SIZE(cached_results); i++) { 221 if (merged == cached_results[i].tag) { 222 if (cached_results[i].rl) { 223 *rl = cached_results[i].rl; 224 return 1; 225 } 226 return 0; 227 } 228 } 229 230 db_info.type = type; 231 232 run_sql(get_vals, &db_info, 233 "select value from mtag_data where tag = %lld and offset = %d and type = %d;", 234 tag, offset, DATA_VALUE); 235 if (!db_info.rl || is_whole_rl(db_info.rl)) { 236 db_info.rl = NULL; 237 ret = 0; 238 goto update_cache; 239 } 240 241 *rl = db_info.rl; 242 ret = 1; 243 244 update_cache: 245 cached_results[idx].tag = merged; 246 cached_results[idx].rl = db_info.rl; 247 idx = (idx + 1) % ARRAY_SIZE(cached_results); 248 249 return ret; 250 } 251 252 static void clear_cache(struct symbol *sym) 253 { 254 memset(cached_results, 0, sizeof(cached_results)); 255 } 256 257 int get_mtag_rl(struct expression *expr, struct range_list **rl) 258 { 259 struct symbol *type; 260 mtag_t tag; 261 int offset; 262 263 if (is_local_variable(expr)) 264 return 0; 265 if (!expr_to_mtag_offset(expr, &tag, &offset)) 266 return 0; 267 if (offset >= MTAG_OFFSET_MASK) 268 return 0; 269 270 type = get_type(expr); 271 if (invalid_type(type)) 272 return 0; 273 274 return get_rl_from_mtag_offset(tag, offset, type, rl); 275 } 276 277 void register_mtag_data(int id) 278 { 279 my_id = id; 280 281 add_hook(&clear_cache, FUNC_DEF_HOOK); 282 283 // if (!option_info) 284 // return; 285 add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK); 286 add_hook(&match_end_file, END_FILE_HOOK); 287 } 288