1 /*
   2  * Copyright (C) 2009 Dan Carpenter.
   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  * This is not a check.  It just saves an struct expression pointer 
  20  * whenever something is assigned.  This can be used later on by other scripts.
  21  */
  22 
  23 #include "smatch.h"
  24 #include "smatch_slist.h"
  25 #include "smatch_extra.h"
  26 
  27 int check_assigned_expr_id;
  28 static int my_id;
  29 static int link_id;
  30 
  31 static struct expression *skip_mod;
  32 
  33 static void undef(struct sm_state *sm, struct expression *mod_expr)
  34 {
  35         if (mod_expr == skip_mod)
  36                 return;
  37         set_state(my_id, sm->name, sm->sym, &undefined);
  38 }
  39 
  40 struct expression *get_assigned_expr(struct expression *expr)
  41 {
  42         struct smatch_state *state;
  43 
  44         state = get_state_expr(my_id, expr);
  45         if (!state)
  46                 return NULL;
  47         return (struct expression *)state->data;
  48 }
  49 
  50 struct expression *get_assigned_expr_name_sym(const char *name, struct symbol *sym)
  51 {
  52         struct smatch_state *state;
  53 
  54         state = get_state(my_id, name, sym);
  55         if (!state)
  56                 return NULL;
  57         return (struct expression *)state->data;
  58 }
  59 
  60 static void match_assignment(struct expression *expr)
  61 {
  62         static struct expression *ignored_expr;
  63         struct symbol *left_sym, *right_sym;
  64         char *left_name = NULL;
  65         char *right_name = NULL;
  66 
  67         if (expr->op != '=')
  68                 return;
  69         if (is_fake_call(expr->right))
  70                 return;
  71         if (__in_fake_struct_assign) {
  72                 struct range_list *rl;
  73 
  74                 if (!get_implied_rl(expr->right, &rl))
  75                         return;
  76                 if (is_whole_rl(rl))
  77                         return;
  78         }
  79 
  80         if (expr->left == ignored_expr)
  81                 return;
  82         ignored_expr = NULL;
  83         if (__in_fake_parameter_assign)
  84                 ignored_expr = expr->left;
  85 
  86         left_name = expr_to_var_sym(expr->left, &left_sym);
  87         if (!left_name || !left_sym)
  88                 goto free;
  89         set_state(my_id, left_name, left_sym, alloc_state_expr(strip_expr(expr->right)));
  90 
  91         right_name = expr_to_var_sym(expr->right, &right_sym);
  92         if (!right_name || !right_sym)
  93                 goto free;
  94 
  95         store_link(link_id, right_name, right_sym, left_name, left_sym);
  96 
  97 free:
  98         free_string(left_name);
  99         free_string(right_name);
 100 }
 101 
 102 static void record_param_assignment(struct expression *expr, int param, char *key, char *value)
 103 {
 104         struct expression *arg, *right;
 105         struct symbol *sym;
 106         char *name;
 107         char *p;
 108         int right_param;
 109 
 110         while (expr->type == EXPR_ASSIGNMENT)
 111                 expr = strip_expr(expr->right);
 112         if (!expr || expr->type != EXPR_CALL)
 113                 return;
 114 
 115         p = strstr(value, "[$");
 116         if (!p)
 117                 return;
 118 
 119         p += 2;
 120         right_param = strtol(p, &p, 10);
 121         if (*p != ']')
 122                 return;
 123 
 124         arg = get_argument_from_call_expr(expr->args, param);
 125         right = get_argument_from_call_expr(expr->args, right_param);
 126         if (!right || !arg)
 127                 return;
 128         name = get_variable_from_key(arg, key, &sym);
 129         if (!name || !sym)
 130                 goto free;
 131 
 132         skip_mod = expr;
 133         set_state(my_id, name, sym, alloc_state_expr(right));
 134 free:
 135         free_string(name);
 136 }
 137 
 138 void register_assigned_expr(int id)
 139 {
 140         my_id = check_assigned_expr_id = id;
 141         set_dynamic_states(check_assigned_expr_id);
 142         add_hook(&match_assignment, ASSIGNMENT_HOOK_AFTER);
 143         add_modification_hook(my_id, &undef);
 144         select_return_states_hook(PARAM_SET, &record_param_assignment);
 145 }
 146 
 147 void register_assigned_expr_links(int id)
 148 {
 149         link_id = id;
 150         set_dynamic_states(link_id);
 151         db_ignore_states(link_id);
 152         set_up_link_functions(my_id, link_id);
 153 }
 154