1 /*
   2  * Copyright (C) 2015 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 #include "smatch.h"
  19 #include "smatch_slist.h"
  20 
  21 static int my_id;
  22 
  23 static struct stree *used_stree;
  24 static struct stree_stack *saved_stack;
  25 
  26 STATE(used);
  27 
  28 static void get_state_hook(int owner, const char *name, struct symbol *sym)
  29 {
  30         int arg;
  31 
  32         if (!option_info)
  33                 return;
  34 
  35         if (__in_fake_assign || __in_fake_parameter_assign || __in_function_def || __in_unmatched_hook)
  36                 return;
  37 
  38         arg = get_param_num_from_sym(sym);
  39         if (arg < 0)
  40                 return;
  41         if (param_was_set_var_sym(name, sym))
  42                 return;
  43         set_state_stree(&used_stree, my_id, name, sym, &used);
  44 }
  45 
  46 static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused)
  47 {
  48         struct symbol *sym;
  49         char *name;
  50         int arg_nr;
  51 
  52         if (!option_info)
  53                 return;
  54 
  55         name = get_variable_from_key(arg, key, &sym);
  56         if (!name || !sym)
  57                 goto free;
  58 
  59         arg_nr = get_param_num_from_sym(sym);
  60         if (arg_nr < 0)
  61                 goto free;
  62         if (param_was_set_var_sym(name, sym))
  63                 goto free;
  64         set_state_stree(&used_stree, my_id, name, sym, &used);
  65 free:
  66         free_string(name);
  67 }
  68 
  69 static void process_states(void)
  70 {
  71         struct sm_state *tmp;
  72         int arg;
  73         const char *name;
  74 
  75         FOR_EACH_SM(used_stree, tmp) {
  76                 arg = get_param_num_from_sym(tmp->sym);
  77                 if (arg < 0)
  78                         continue;
  79                 name = get_param_name(tmp);
  80                 if (!name)
  81                         continue;
  82                 if (is_recursive_member(name))
  83                         continue;
  84 
  85                 if (is_ignored_kernel_data(name))
  86                         continue;
  87 
  88                 sql_insert_return_implies(PARAM_USED, arg, name, "");
  89         } END_FOR_EACH_SM(tmp);
  90 
  91         free_stree(&used_stree);
  92 }
  93 
  94 static void match_function_def(struct symbol *sym)
  95 {
  96         free_stree(&used_stree);
  97 }
  98 
  99 static void match_save_states(struct expression *expr)
 100 {
 101         push_stree(&saved_stack, used_stree);
 102         used_stree = NULL;
 103 }
 104 
 105 static void match_restore_states(struct expression *expr)
 106 {
 107         free_stree(&used_stree);
 108         used_stree = pop_stree(&saved_stack);
 109 }
 110 
 111 void register_param_used(int id)
 112 {
 113         my_id = id;
 114 
 115         add_hook(&match_function_def, FUNC_DEF_HOOK);
 116 
 117         add_get_state_hook(&get_state_hook);
 118 
 119         add_hook(&match_save_states, INLINE_FN_START);
 120         add_hook(&match_restore_states, INLINE_FN_END);
 121 
 122         select_return_implies_hook(PARAM_USED, &set_param_used);
 123         all_return_states_hook(&process_states);
 124 }