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 238