db: add a comment and do some white space changes
[smatch.git] / smatch_container_of.c
blob7b6685cf69288249b203ed546aa74521255982cf
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
18 #include "smatch.h"
19 #include "smatch_slist.h"
21 static int my_id;
23 static struct stree *used_stree;
24 static struct stree_stack *saved_stack;
26 STATE(used);
28 int get_param_from_container_of(struct expression *expr)
30 struct expression *param_expr;
31 struct symbol *type;
32 sval_t sval;
33 int param;
36 type = get_type(expr);
37 if (!type || type->type != SYM_PTR)
38 return -1;
40 expr = strip_expr(expr);
41 if (expr->type != EXPR_BINOP || expr->op != '-')
42 return -1;
44 if (!get_value(expr->right, &sval))
45 return -1;
46 if (sval.value < 0 || sval.value > 4096)
47 return -1;
49 param_expr = get_assigned_expr(expr->left);
50 if (!param_expr)
51 return -1;
52 param = get_param_num(param_expr);
53 if (param < 0)
54 return -1;
56 return param;
59 int get_offset_from_container_of(struct expression *expr)
61 struct expression *param_expr;
62 struct symbol *type;
63 sval_t sval;
64 int param;
67 type = get_type(expr);
68 if (!type || type->type != SYM_PTR)
69 return -1;
71 expr = strip_expr(expr);
72 if (expr->type != EXPR_BINOP || expr->op != '-')
73 return -1;
75 if (!get_value(expr->right, &sval))
76 return -1;
77 if (sval.value < 0 || sval.value > 4096)
78 return -1;
80 param_expr = get_assigned_expr(expr->left);
81 if (!param_expr)
82 return -1;
83 param = get_param_num(param_expr);
84 if (param < 0)
85 return -1;
87 return sval.value;
90 static int get_container_arg(struct symbol *sym)
92 struct expression *__mptr;
93 int param;
95 if (!sym || !sym->ident)
96 return -1;
98 __mptr = get_assigned_expr_name_sym(sym->ident->name, sym);
99 param = get_param_from_container_of(__mptr);
101 return param;
104 static int get_container_offset(struct symbol *sym)
106 struct expression *__mptr;
107 int offset;
109 if (!sym || !sym->ident)
110 return -1;
112 __mptr = get_assigned_expr_name_sym(sym->ident->name, sym);
113 offset = get_offset_from_container_of(__mptr);
115 return offset;
118 static char *get_container_name(struct sm_state *sm, int offset)
120 static char buf[256];
121 const char *name;
123 name = get_param_name(sm);
124 if (!name)
125 return NULL;
127 if (name[0] == '$')
128 snprintf(buf, sizeof(buf), "$(-%d)%s", offset, name + 1);
129 else if (name[0] == '*' || name[1] == '$')
130 snprintf(buf, sizeof(buf), "*$(-%d)%s", offset, name + 2);
131 else
132 return NULL;
134 return buf;
137 static void get_state_hook(int owner, const char *name, struct symbol *sym)
139 int arg;
141 if (!option_info)
142 return;
143 if (__in_fake_assign)
144 return;
146 arg = get_container_arg(sym);
147 if (arg >= 0)
148 set_state_stree(&used_stree, my_id, name, sym, &used);
151 static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused)
153 struct symbol *sym;
154 char *name;
155 int arg_nr;
157 name = get_variable_from_key(arg, key, &sym);
158 if (!name || !sym)
159 goto free;
161 arg_nr = get_container_arg(sym);
162 if (arg_nr >= 0)
163 set_state(my_id, name, sym, &used);
164 free:
165 free_string(name);
168 static void process_states(void)
170 struct sm_state *tmp;
171 int arg, offset;
172 const char *name;
174 FOR_EACH_SM(used_stree, tmp) {
175 arg = get_container_arg(tmp->sym);
176 offset = get_container_offset(tmp->sym);
177 if (arg < 0 || offset < 0)
178 continue;
179 name = get_container_name(tmp, offset);
180 if (!name)
181 continue;
182 sql_insert_call_implies(PARAM_USED, arg, name, "");
183 } END_FOR_EACH_SM(tmp);
185 free_stree(&used_stree);
188 static void match_function_def(struct symbol *sym)
190 free_stree(&used_stree);
193 static void match_save_states(struct expression *expr)
195 push_stree(&saved_stack, used_stree);
196 used_stree = NULL;
199 static void match_restore_states(struct expression *expr)
201 free_stree(&used_stree);
202 used_stree = pop_stree(&saved_stack);
205 static void print_returns_container_of(int return_id, char *return_ranges, struct expression *expr)
207 int offset;
208 int param;
209 char key[64];
210 char value[64];
212 param = get_param_from_container_of(expr);
213 if (param < 0)
214 return;
215 offset = get_offset_from_container_of(expr);
216 if (offset < 0)
217 return;
219 snprintf(key, sizeof(key), "%d", param);
220 snprintf(value, sizeof(value), "-%d", offset);
222 sql_insert_return_states(return_id, return_ranges, CONTAINER, -1,
223 key, value);
226 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
228 struct expression *call, *arg;
229 int offset;
230 char buf[64];
232 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
233 return;
234 call = strip_expr(expr->right);
235 if (call->type != EXPR_CALL)
236 return;
237 if (param != -1)
238 return;
239 param = atoi(key);
240 offset = atoi(value);
242 arg = get_argument_from_call_expr(call->args, param);
243 if (!arg)
244 return;
245 if (arg->type != EXPR_SYMBOL)
246 return;
247 param = get_param_num(arg);
248 if (param < 0)
249 return;
250 snprintf(buf, sizeof(buf), "$(%d)", offset);
251 sql_insert_call_implies(PARAM_USED, param, buf, "");
254 void register_container_of(int id)
256 my_id = id;
258 add_hook(&match_function_def, FUNC_DEF_HOOK);
260 add_get_state_hook(&get_state_hook);
262 add_hook(&match_save_states, INLINE_FN_START);
263 add_hook(&match_restore_states, INLINE_FN_END);
265 select_call_implies_hook(PARAM_USED, &set_param_used);
266 all_return_states_hook(&process_states);
268 add_split_return_callback(&print_returns_container_of);
269 select_return_states_hook(CONTAINER, &returns_container_of);