1 /*
   2  * Copyright (C) 2017 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  * Take a look at request_threaded_irq().  It takes thread_fn and dev_id.  Then
  20  * it does:
  21  *
  22  *      action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
  23  *      action->thread_fn = thread_fn;
  24  *      action->dev_id = dev_id;
  25  *
  26  * It doesn't ever pass action back to the higher levels, but instead registers
  27  * it with the lower levels.
  28  *
  29  * The kzalloc() allocation creates a new mtag.  We don't know at this point
  30  * what "thread_fn" and "dev_id" are because they come from many different
  31  * sources.
  32  *
  33  * So what we do is we pass the information back to the callers that thread_fn
  34  * and dev_id are stored as a specific mtag data.  Then when the callers *do*
  35  * know what values are passed they create an mtag_alias.  An mtag_alias is a
  36  * many to one relationship.  Then they store that in mtag_data using the
  37  * mtag_alias.
  38  *
  39  */
  40 
  41 #include "smatch.h"
  42 #include "smatch_extra.h"
  43 #include "smatch_slist.h"
  44 
  45 static int my_id;
  46 
  47 struct tag_assign_info {
  48         mtag_t tag;
  49         int offset;
  50 };
  51 ALLOCATOR(tag_assign_info, "tag name offset");
  52 
  53 static struct smatch_state *alloc_tag_data_state(mtag_t tag, char *name, int offset)
  54 {
  55         struct smatch_state *state;
  56         struct tag_assign_info *data;
  57 
  58         data = __alloc_tag_assign_info(0);
  59         data->tag = tag;
  60         data->offset = offset;
  61 
  62         state = __alloc_smatch_state(0);
  63         state->name = alloc_sname(name);
  64         state->data = data;
  65         return state;
  66 }
  67 
  68 struct smatch_state *merge_tag_info(struct smatch_state *s1, struct smatch_state *s2)
  69 {
  70         /* Basically ignore undefined states */
  71         if (s1 == &undefined)
  72                 return s2;
  73         if (s2 == &undefined)
  74                 return s1;
  75 
  76         return &merged;
  77 }
  78 
  79 static void match_assign(struct expression *expr)
  80 {
  81         struct expression *left;
  82         struct symbol *right_sym;
  83         char *name;
  84         mtag_t tag;
  85         int offset;
  86         int param;
  87 
  88         if (expr->op != '=')
  89                 return;
  90         left = strip_expr(expr->left);
  91         right_sym = expr_to_sym(expr->right);
  92         if (!right_sym)
  93                 return;
  94 
  95         param = get_param_num_from_sym(right_sym);
  96         if (param < 0)
  97                 return;
  98         // FIXME:  modify param_has_filter_data() to take a name/sym
  99         if (!expr_to_mtag_offset(left, &tag, &offset))
 100                 return;
 101         name = expr_to_str(left);
 102         if (!name)
 103                 return;
 104         set_state_expr(my_id, expr->right, alloc_tag_data_state(tag, name, offset));
 105         free_string(name);
 106 }
 107 
 108 #if 0
 109 static void save_mtag_to_map(struct expression *expr, mtag_t tag, int offset, int param, char *key, char *value)
 110 {
 111         struct expression *arg, *gen_expr;
 112         mtag_t arg_tag;
 113 
 114         arg = get_argument_from_call_expr(expr->args, param);
 115         if (!arg)
 116                 return;
 117 
 118         gen_expr = gen_expression_from_key(arg, key);
 119         if (!gen_expr)
 120                 return;
 121 
 122         if (!get_mtag(gen_expr, &arg_tag))
 123                 arg_tag = 0;
 124 
 125         if (local_debug)
 126                 sm_msg("finding mtag for '%s' %lld", expr_to_str(gen_expr), arg_tag);
 127 }
 128 #endif
 129 
 130 static void propogate_assignment(struct expression *expr, mtag_t tag, int offset, int param, char *key)
 131 {
 132         struct expression *arg;
 133         int orig_param;
 134         char buf[32];
 135         char *name;
 136         struct symbol *sym;
 137 
 138         arg = get_argument_from_call_expr(expr->args, param);
 139         if (!arg)
 140                 return;
 141         name = get_variable_from_key(arg, key, &sym);
 142         if (!name || !sym)
 143                 goto free;
 144 
 145         orig_param = get_param_num_from_sym(sym);
 146         if (orig_param < 0)
 147                 goto free;
 148 
 149         snprintf(buf, sizeof(buf), "$->[%d]", offset);
 150         set_state(my_id, name, sym, alloc_tag_data_state(tag, buf, offset));
 151 free:
 152         free_string(name);
 153 }
 154 
 155 static void assign_to_alias(struct expression *expr, int param, mtag_t tag, int offset, char *key)
 156 {
 157         struct expression *arg, *gen_expr;
 158         struct range_list *rl;
 159         mtag_t arg_tag;
 160         mtag_t alias;
 161 
 162         arg = get_argument_from_call_expr(expr->args, param);
 163         if (!arg)
 164                 return;
 165 
 166         gen_expr = gen_expression_from_key(arg, key);
 167         if (!gen_expr)
 168                 return;
 169 
 170         get_absolute_rl(gen_expr, &rl);
 171 
 172         if (!create_mtag_alias(tag, expr, &alias))
 173                 return;
 174 
 175 //      insert_mtag_data(alias, offset, rl);
 176 
 177         if (get_mtag(gen_expr, &arg_tag))
 178                 sql_insert_mtag_map(arg_tag, -offset, alias);
 179 }
 180 
 181 static void call_does_mtag_assign(struct expression *expr, int param, char *key, char *value)
 182 {
 183         char *p;
 184         mtag_t tag;
 185         int offset;
 186 
 187         while (expr->type == EXPR_ASSIGNMENT)
 188                 expr = strip_expr(expr->right);
 189         if (expr->type != EXPR_CALL)
 190                 return;
 191 
 192         tag = strtoul(value, NULL, 10);
 193         p = strchr(value, '+');
 194         if (!p)
 195                 return;
 196         offset = atoi(p + 1);
 197 
 198 //      save_mtag_to_map(expr, tag, offset, param, key, value);
 199         propogate_assignment(expr, tag, offset, param, key);
 200         assign_to_alias(expr, param, tag, offset, key);
 201 }
 202 
 203 static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr)
 204 {
 205         struct sm_state *sm;
 206         struct tag_assign_info *data;
 207         char buf[256];
 208         const char *param_name;
 209         int param;
 210 
 211         FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
 212                 if (!sm->state->data)
 213                         continue;
 214 
 215                 param = get_param_num_from_sym(sm->sym);
 216                 if (param < 0)
 217                         continue;
 218                 param_name = get_param_name(sm);
 219                 if (!param_name)
 220                         continue;
 221 
 222                 data = sm->state->data;
 223                 snprintf(buf, sizeof(buf), "%lld+%d", data->tag, data->offset);
 224                 sql_insert_return_states(return_id, return_ranges, MTAG_ASSIGN, param, param_name, buf);
 225         } END_FOR_EACH_SM(sm);
 226 }
 227 
 228 void register_param_to_mtag_data(int id)
 229 {
 230         my_id = id;
 231 
 232         add_hook(&match_assign, ASSIGNMENT_HOOK);
 233         select_return_states_hook(MTAG_ASSIGN, &call_does_mtag_assign);
 234         add_merge_hook(my_id, &merge_tag_info);
 235         add_split_return_callback(&print_stored_to_mtag);
 236 }
 237