test_bit: add test_and_set_bit()
[smatch.git] / smatch_param_to_mtag_data.c
blobec647317e705b1b3d4311b32b63a839ec57a6b44
1 /*
2 * Copyright (C) 2017 Oracle.
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.
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.
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
19 * Take a look at request_threaded_irq(). It takes thread_fn and dev_id. Then
20 * it does:
22 * action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
23 * action->thread_fn = thread_fn;
24 * action->dev_id = dev_id;
26 * It doesn't ever pass action back to the higher levels, but instead registers
27 * it with the lower levels.
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.
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.
41 #include "smatch.h"
42 #include "smatch_extra.h"
43 #include "smatch_slist.h"
45 static int my_id;
47 struct tag_assign_info {
48 mtag_t tag;
49 int offset;
51 ALLOCATOR(tag_assign_info, "tag name offset");
53 static struct smatch_state *alloc_tag_data_state(mtag_t tag, char *name, int offset)
55 struct smatch_state *state;
56 struct tag_assign_info *data;
58 data = __alloc_tag_assign_info(0);
59 data->tag = tag;
60 data->offset = offset;
62 state = __alloc_smatch_state(0);
63 state->name = alloc_sname(name);
64 state->data = data;
65 return state;
68 struct smatch_state *merge_tag_info(struct smatch_state *s1, struct smatch_state *s2)
70 /* Basically ignore undefined states */
71 if (s1 == &undefined)
72 return s2;
73 if (s2 == &undefined)
74 return s1;
76 return &merged;
79 static void match_assign(struct expression *expr)
81 struct expression *left;
82 struct symbol *right_sym;
83 char *name;
84 mtag_t tag;
85 int offset;
86 int param;
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;
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);
108 #if 0
109 static void save_mtag_to_map(struct expression *expr, mtag_t tag, int offset, int param, char *key, char *value)
111 struct expression *arg, *gen_expr;
112 mtag_t arg_tag;
114 arg = get_argument_from_call_expr(expr->args, param);
115 if (!arg)
116 return;
118 gen_expr = gen_expression_from_key(arg, key);
119 if (!gen_expr)
120 return;
122 if (!get_mtag(gen_expr, &arg_tag))
123 arg_tag = 0;
125 if (local_debug)
126 sm_msg("finding mtag for '%s' %lld", expr_to_str(gen_expr), arg_tag);
128 #endif
130 static void propogate_assignment(struct expression *expr, mtag_t tag, int offset, int param, char *key)
132 struct expression *arg;
133 int orig_param;
134 char buf[32];
135 char *name;
136 struct symbol *sym;
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;
145 orig_param = get_param_num_from_sym(sym);
146 if (orig_param < 0)
147 goto free;
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);
155 static void assign_to_alias(struct expression *expr, int param, mtag_t tag, int offset, char *key)
157 struct expression *arg, *gen_expr;
158 struct range_list *rl;
159 mtag_t arg_tag;
160 mtag_t alias;
162 arg = get_argument_from_call_expr(expr->args, param);
163 if (!arg)
164 return;
166 gen_expr = gen_expression_from_key(arg, key);
167 if (!gen_expr)
168 return;
170 get_absolute_rl(gen_expr, &rl);
172 if (!create_mtag_alias(tag, expr, &alias))
173 return;
175 // insert_mtag_data(alias, offset, rl);
177 if (get_mtag(gen_expr, &arg_tag))
178 sql_insert_mtag_map(arg_tag, -offset, alias);
181 static void call_does_mtag_assign(struct expression *expr, int param, char *key, char *value)
183 char *p;
184 mtag_t tag;
185 int offset;
187 while (expr->type == EXPR_ASSIGNMENT)
188 expr = strip_expr(expr->right);
189 if (expr->type != EXPR_CALL)
190 return;
192 tag = strtoul(value, NULL, 10);
193 p = strchr(value, '+');
194 if (!p)
195 return;
196 offset = atoi(p + 1);
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);
203 static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr)
205 struct sm_state *sm;
206 struct tag_assign_info *data;
207 char buf[256];
208 const char *param_name;
209 int param;
211 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
212 if (!sm->state->data)
213 continue;
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;
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);
228 void register_param_to_mtag_data(int id)
230 my_id = id;
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);