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