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