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 if (is_local_variable(left)) 92 return; 93 right_sym = expr_to_sym(expr->right); 94 if (!right_sym) 95 return; 96 97 param = get_param_num_from_sym(right_sym); 98 if (param < 0) 99 return; 100 // FIXME: modify param_has_filter_data() to take a name/sym 101 if (!expr_to_mtag_offset(left, &tag, &offset)) 102 return; 103 name = expr_to_str(left); 104 if (!name) 105 return; 106 set_state_expr(my_id, expr->right, alloc_tag_data_state(tag, name, offset)); 107 free_string(name); 108 } 109 110 static void propogate_assignment(struct expression *expr, mtag_t tag, int offset, int param, char *key) 111 { 112 struct expression *arg; 113 int orig_param; 114 char buf[32]; 115 char *name; 116 struct symbol *sym; 117 118 arg = get_argument_from_call_expr(expr->args, param); 119 if (!arg) 120 return; 121 name = get_variable_from_key(arg, key, &sym); 122 if (!name || !sym) 123 goto free; 124 125 orig_param = get_param_num_from_sym(sym); 126 if (orig_param < 0) 127 goto free; 128 129 snprintf(buf, sizeof(buf), "$->[%d]", offset); 130 set_state(my_id, name, sym, alloc_tag_data_state(tag, buf, offset)); 131 free: 132 free_string(name); 133 } 134 135 static void assign_to_alias(struct expression *expr, int param, mtag_t tag, int offset, char *key) 136 { 137 struct expression *arg, *gen_expr; 138 struct range_list *rl; 139 mtag_t arg_tag; 140 mtag_t alias; 141 int arg_offset; 142 143 arg = get_argument_from_call_expr(expr->args, param); 144 if (!arg) 145 return; 146 147 gen_expr = gen_expression_from_key(arg, key); 148 if (!gen_expr) 149 return; 150 151 get_absolute_rl(gen_expr, &rl); 152 153 if (!create_mtag_alias(tag, expr, &alias)) 154 return; 155 156 // insert_mtag_data(alias, offset, rl); 157 158 // FIXME: is arg_offset handled correctly? 159 if (expr_to_mtag_offset(gen_expr, &arg_tag, &arg_offset) && arg_offset == 0) 160 sql_insert_mtag_map(arg_tag, -offset, alias); 161 } 162 163 static void call_does_mtag_assign(struct expression *expr, int param, char *key, char *value) 164 { 165 char *p; 166 mtag_t tag; 167 int offset; 168 169 while (expr->type == EXPR_ASSIGNMENT) 170 expr = strip_expr(expr->right); 171 if (expr->type != EXPR_CALL) 172 return; 173 174 tag = strtoul(value, NULL, 10); 175 p = strchr(value, '+'); 176 if (!p) 177 return; 178 offset = atoi(p + 1); 179 180 // save_mtag_to_map(expr, tag, offset, param, key, value); 181 propogate_assignment(expr, tag, offset, param, key); 182 assign_to_alias(expr, param, tag, offset, key); 183 } 184 185 static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr) 186 { 187 struct sm_state *sm; 188 struct tag_assign_info *data; 189 char buf[256]; 190 const char *param_name; 191 int param; 192 193 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { 194 if (!sm->state->data) 195 continue; 196 197 param = get_param_num_from_sym(sm->sym); 198 if (param < 0) 199 continue; 200 param_name = get_param_name(sm); 201 if (!param_name) 202 continue; 203 204 data = sm->state->data; 205 snprintf(buf, sizeof(buf), "%lld+%d", data->tag, data->offset); 206 sql_insert_return_states(return_id, return_ranges, MTAG_ASSIGN, param, param_name, buf); 207 } END_FOR_EACH_SM(sm); 208 } 209 210 void register_param_to_mtag_data(int id) 211 { 212 my_id = id; 213 214 set_dynamic_states(my_id); 215 add_hook(&match_assign, ASSIGNMENT_HOOK); 216 select_return_states_hook(MTAG_ASSIGN, &call_does_mtag_assign); 217 add_merge_hook(my_id, &merge_tag_info); 218 add_split_return_callback(&print_stored_to_mtag); 219 } 220 221