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 #include "smatch_extra.h"
21
22 static int my_id;
23 static int param_id;
24
25 static struct stree *used_stree;
26 static struct stree_stack *saved_stack;
27
28 STATE(used);
29
30 int get_param_from_container_of(struct expression *expr)
31 {
32 struct expression *param_expr;
33 struct symbol *type;
34 sval_t sval;
35 int param;
36
37
38 type = get_type(expr);
39 if (!type || type->type != SYM_PTR)
40 return -1;
41
42 expr = strip_expr(expr);
43 if (expr->type != EXPR_BINOP || expr->op != '-')
44 return -1;
45
46 if (!get_value(expr->right, &sval))
47 return -1;
48 if (sval.value < 0 || sval.value > 4096)
49 return -1;
67 type = get_type(expr);
68 if (!type || type->type != SYM_PTR)
69 return -1;
70
71 expr = strip_expr(expr);
72 if (expr->type != EXPR_BINOP || expr->op != '-')
73 return -1;
74
75 if (!get_value(expr->right, &sval))
76 return -1;
77 if (sval.value < 0 || sval.value > 4096)
78 return -1;
79
80 param_expr = get_assigned_expr(expr->left);
81 if (!param_expr)
82 return -1;
83
84 return sval.value;
85 }
86
87 static int get_container_arg(struct symbol *sym)
88 {
89 struct expression *__mptr;
90 int param;
91
92 if (!sym || !sym->ident)
93 return -1;
94
95 __mptr = get_assigned_expr_name_sym(sym->ident->name, sym);
96 param = get_param_from_container_of(__mptr);
97
98 return param;
99 }
100
101 static int get_container_offset(struct symbol *sym)
102 {
103 struct expression *__mptr;
104 int offset;
105
106 if (!sym || !sym->ident)
107 return -1;
108
109 __mptr = get_assigned_expr_name_sym(sym->ident->name, sym);
110 offset = get_offset_from_container_of(__mptr);
111
112 return offset;
113 }
114
115 static char *get_container_name_sm(struct sm_state *sm, int offset)
116 {
117 static char buf[256];
118 const char *name;
119
120 name = get_param_name(sm);
121 if (!name)
122 return NULL;
123
124 if (name[0] == '$')
125 snprintf(buf, sizeof(buf), "$(-%d)%s", offset, name + 1);
126 else if (name[0] == '*' || name[1] == '$')
127 snprintf(buf, sizeof(buf), "*$(-%d)%s", offset, name + 2);
128 else
129 return NULL;
130
131 return buf;
132 }
133
134 static void get_state_hook(int owner, const char *name, struct symbol *sym)
135 {
136 int arg;
137
138 if (!option_info)
139 return;
140 if (__in_fake_assign)
141 return;
142
143 arg = get_container_arg(sym);
144 if (arg >= 0)
145 set_state_stree(&used_stree, my_id, name, sym, &used);
146 }
147
148 static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused)
149 {
150 struct symbol *sym;
151 char *name;
152 int arg_nr;
153
154 name = get_variable_from_key(arg, key, &sym);
155 if (!name || !sym)
156 goto free;
157
158 arg_nr = get_container_arg(sym);
159 if (arg_nr >= 0)
160 set_state(my_id, name, sym, &used);
161 free:
162 free_string(name);
163 }
164
165 static void process_states(void)
166 {
167 struct sm_state *tmp;
168 int arg, offset;
169 const char *name;
170
171 FOR_EACH_SM(used_stree, tmp) {
172 arg = get_container_arg(tmp->sym);
173 offset = get_container_offset(tmp->sym);
174 if (arg < 0 || offset < 0)
175 continue;
176 name = get_container_name_sm(tmp, offset);
177 if (!name)
178 continue;
179 sql_insert_return_implies(CONTAINER, arg, name, "");
180 } END_FOR_EACH_SM(tmp);
181
182 free_stree(&used_stree);
183 }
184
185 static void match_function_def(struct symbol *sym)
186 {
187 free_stree(&used_stree);
188 }
189
190 static void match_save_states(struct expression *expr)
191 {
192 push_stree(&saved_stack, used_stree);
193 used_stree = NULL;
194 }
195
196 static void match_restore_states(struct expression *expr)
197 {
198 free_stree(&used_stree);
199 used_stree = pop_stree(&saved_stack);
200 }
201
202 static void print_returns_container_of(int return_id, char *return_ranges, struct expression *expr)
203 {
204 int offset;
205 int param;
206 char key[64];
207 char value[64];
208
209 param = get_param_from_container_of(expr);
210 if (param < 0)
211 return;
212 offset = get_offset_from_container_of(expr);
213 if (offset < 0)
214 return;
215
216 snprintf(key, sizeof(key), "%d", param);
217 snprintf(value, sizeof(value), "-%d", offset);
218
219 /* no need to add it to return_implies because it's not really param_used */
220 sql_insert_return_states(return_id, return_ranges, CONTAINER, -1,
221 key, value);
222 }
223
224 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
225 {
226 struct expression *call, *arg;
227 int offset;
228 char buf[64];
229
230 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
231 return;
232 call = strip_expr(expr->right);
233 if (call->type != EXPR_CALL)
234 return;
235 if (param != -1)
236 return;
237 param = atoi(key);
238 offset = atoi(value);
239
240 arg = get_argument_from_call_expr(call->args, param);
241 if (!arg)
242 return;
243 if (arg->type != EXPR_SYMBOL)
244 return;
245 param = get_param_num(arg);
246 if (param < 0)
247 return;
248 snprintf(buf, sizeof(buf), "$(%d)", offset);
249 sql_insert_return_implies(CONTAINER, param, buf, "");
250 }
251
252 static int get_deref_count(struct expression *expr)
253 {
254 int cnt = 0;
255
256 while (expr && expr->type == EXPR_DEREF) {
257 expr = expr->deref;
258 if (expr->type == EXPR_PREOP && expr->op == '*')
259 expr = expr->unop;
260 cnt++;
261 if (cnt > 100)
262 return -1;
263 }
264 return cnt;
265 }
266
267 static struct expression *get_partial_deref(struct expression *expr, int cnt)
268 {
269 while (--cnt >= 0) {
270 if (!expr || expr->type != EXPR_DEREF)
271 return expr;
282
283 if (cnt == 0)
284 return snprintf(buf, size, "%c0", op);
285
286 n = 0;
287 while (--cnt >= 0) {
288 offset = get_member_offset_from_deref(expr);
289 if (offset < 0)
290 return -1;
291 n += snprintf(buf + n, size - n, "%c%d", op, offset);
292 if (expr->type != EXPR_DEREF)
293 return -1;
294 expr = expr->deref;
295 if (expr->type == EXPR_PREOP && expr->op == '*')
296 expr = expr->unop;
297 }
298
299 return n;
300 }
301
302 static char *get_shared_str(struct expression *container, struct expression *expr)
303 {
304 struct expression *one, *two;
305 int cont, exp, min, ret, n;
306 static char buf[48];
307
308 cont = get_deref_count(container);
309 exp = get_deref_count(expr);
310 if (cont < 0 || exp < 0)
311 return NULL;
312
313 min = (cont < exp) ? cont : exp;
314 while (min >= 0) {
315 one = get_partial_deref(container, cont - min);
316 two = get_partial_deref(expr, exp - min);
317 if (expr_equiv(one, two))
318 goto found;
319 min--;
320 }
321
322 return NULL;
323
324 found:
325 ret = partial_deref_to_offset_str(container, cont - min, '-', buf, sizeof(buf));
326 if (ret < 0)
327 return NULL;
328 n = ret;
329 ret = partial_deref_to_offset_str(expr, exp - min, '+', buf + ret, sizeof(buf) - ret);
330 if (ret < 0)
331 return NULL;
332 n += ret;
333 if (n >= sizeof(buf))
334 return NULL;
335
336 return buf;
337 }
338
339 char *get_container_name(struct expression *container, struct expression *expr)
340 {
341 struct symbol *container_sym, *sym;
342 struct expression *tmp;
343 static char buf[64];
344 char *shared;
345 bool star;
346 int cnt;
347
348 container_sym = expr_to_sym(container);
349 sym = expr_to_sym(expr);
350 if (container_sym && container_sym == sym)
351 goto found;
352
353 cnt = 0;
354 while ((tmp = get_assigned_expr(expr))) {
355 expr = tmp;
356 if (cnt++ > 3)
357 break;
358 }
359
360 cnt = 0;
361 while ((tmp = get_assigned_expr(container))) {
362 container = tmp;
363 if (cnt++ > 3)
364 break;
365 }
366
367 found:
368 expr = strip_expr(expr);
369 star = true;
370 if (expr->type == EXPR_PREOP && expr->op == '&') {
371 expr = strip_expr(expr->unop);
372 star = false;
373 }
374
375 container_sym = expr_to_sym(container);
376 if (!container_sym)
377 return NULL;
378 sym = expr_to_sym(expr);
379 if (!sym || container_sym != sym)
380 return NULL;
381
382 shared = get_shared_str(container, expr);
383 if (star)
384 snprintf(buf, sizeof(buf), "*(%s)", shared);
385 else
386 snprintf(buf, sizeof(buf), "%s", shared);
387
388 return buf;
389 }
390
391 static void match_call(struct expression *call)
392 {
393 struct expression *fn, *arg;
394 char *name;
395 int param;
396
397 /*
398 * We're trying to link the function with the parameter. There are a
399 * couple ways this can be passed:
400 * foo->func(foo, ...);
401 * foo->func(foo->x, ...);
402 * foo->bar.func(&foo->bar, ...);
403 * foo->bar->baz->func(foo, ...);
404 *
405 * So the method is basically to subtract the offsets until we get to
406 * the common bit, then add the member offsets to get the parameter.
407 *
408 * If we're taking an address then the offset math is not stared,
409 * otherwise it is. Starred means dereferenced.
410 */
411 fn = strip_expr(call->fn);
412
413 param = -1;
414 FOR_EACH_PTR(call->args, arg) {
415 param++;
416
417 name = get_container_name(fn, arg);
418 if (!name)
419 continue;
420
421 sql_insert_caller_info(call, CONTAINER, param, name, "$(-1)");
422 } END_FOR_EACH_PTR(arg);
423 }
424
425 static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value)
426 {
427 set_state(param_id, name, sym, alloc_state_str(key));
428 }
429
430 struct db_info {
431 struct symbol *arg;
432 int prev_offset;
433 struct range_list *rl;
434 int star;
435 struct stree *stree;
436 };
437
438 static struct symbol *get_member_from_offset(struct symbol *sym, int offset)
439 {
440 struct symbol *type, *tmp;
441 int cur;
442
443 type = get_real_base_type(sym);
444 if (!type || type->type != SYM_PTR)
445 return NULL;
446 type = get_real_base_type(type);
447 if (!type || type->type != SYM_STRUCT)
478 {
479 struct symbol *member, *type;
480 const char *name;
481 static char fullname[256];
482
483 name = arg->ident->name;
484
485 type = get_real_base_type(arg);
486 if (!type || type->type != SYM_PTR)
487 return name;
488
489 type = get_real_base_type(type);
490 if (!type)
491 return NULL;
492 if (type->type != SYM_STRUCT) {
493 snprintf(fullname, sizeof(fullname), "*%s", name);
494 return fullname;
495 }
496
497 member = get_member_from_offset(arg, offset);
498 if (!member)
499 return NULL;
500
501 snprintf(fullname, sizeof(fullname), "%s->%s", name, member->ident->name);
502 return fullname;
503 }
504
505 static void set_param_value(struct stree **stree, struct symbol *arg, int offset, struct range_list *rl)
506 {
507 const char *name;
508
509 name = get_name_from_offset(arg, offset);
510 if (!name)
511 return;
512 set_state_stree(stree, SMATCH_EXTRA, name, arg, alloc_estate_rl(rl));
513 }
514
515 static int save_vals(void *_db_info, int argc, char **argv, char **azColName)
516 {
517 struct db_info *db_info = _db_info;
518 struct symbol *type;
588 }
589
590 if (db_info.prev_offset != -1)
591 set_param_value(&db_info.stree, arg, db_info.prev_offset, db_info.rl);
592
593 // FIXME: handle an offset correctly
594 if (!star && !arg_offset) {
595 sval_t sval;
596
597 sval.type = get_real_base_type(arg);
598 sval.uvalue = tag;
599 set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval));
600 }
601 return db_info.stree;
602 }
603
604 static void load_container_data(struct symbol *arg, const char *info)
605 {
606 mtag_t cur_tag, container_tag, arg_tag;
607 int container_offset, arg_offset;
608 char *p = (char *)info;
609 struct sm_state *sm;
610 struct stree *stree;
611 bool star = 0;
612
613 if (p[0] == '*') {
614 star = 1;
615 p += 2;
616 }
617
618 if (!get_toplevel_mtag(cur_func_sym, &cur_tag))
619 return;
620
621 while (true) {
622 container_offset = strtoul(p, &p, 0);
623 if (local_debug)
624 sm_msg("%s: cur_tag = %llu container_offset = %d",
625 __func__, cur_tag, container_offset);
626 if (!mtag_map_select_container(cur_tag, container_offset, &container_tag))
627 return;
628 cur_tag = container_tag;
629 if (local_debug)
630 sm_msg("%s: container_tag = %llu p = '%s'",
631 __func__, container_tag, p);
632 if (!p)
633 return;
634 if (p[0] != '-')
635 break;
636 p++;
637 }
658 free_stree(&stree);
659 }
660
661 static void handle_passed_container(struct symbol *sym)
662 {
663 struct symbol *arg;
664 struct smatch_state *state;
665
666 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
667 state = get_state(param_id, arg->ident->name, arg);
668 if (!state || state == &merged)
669 continue;
670 load_container_data(arg, state->name);
671 } END_FOR_EACH_PTR(arg);
672 }
673
674 void register_container_of(int id)
675 {
676 my_id = id;
677
678 add_hook(&match_function_def, FUNC_DEF_HOOK);
679
680 add_get_state_hook(&get_state_hook);
681
682 add_hook(&match_save_states, INLINE_FN_START);
683 add_hook(&match_restore_states, INLINE_FN_END);
684
685 select_return_implies_hook(CONTAINER, &set_param_used);
686 all_return_states_hook(&process_states);
687
688 add_split_return_callback(&print_returns_container_of);
689 select_return_states_hook(CONTAINER, &returns_container_of);
690
691 add_hook(&match_call, FUNCTION_CALL_HOOK);
692 }
693
694 void register_container_of2(int id)
695 {
696 param_id = id;
697
698 set_dynamic_states(param_id);
699 select_caller_info_hook(db_passed_container, CONTAINER);
700 add_merge_hook(param_id, &merge_str_state);
701 add_hook(&handle_passed_container, AFTER_DEF_HOOK);
702 }
703
|
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 #include "smatch_extra.h"
21
22 static int my_id;
23 static int param_id;
24
25 int get_param_from_container_of(struct expression *expr)
26 {
27 struct expression *param_expr;
28 struct symbol *type;
29 sval_t sval;
30 int param;
31
32
33 type = get_type(expr);
34 if (!type || type->type != SYM_PTR)
35 return -1;
36
37 expr = strip_expr(expr);
38 if (expr->type != EXPR_BINOP || expr->op != '-')
39 return -1;
40
41 if (!get_value(expr->right, &sval))
42 return -1;
43 if (sval.value < 0 || sval.value > 4096)
44 return -1;
62 type = get_type(expr);
63 if (!type || type->type != SYM_PTR)
64 return -1;
65
66 expr = strip_expr(expr);
67 if (expr->type != EXPR_BINOP || expr->op != '-')
68 return -1;
69
70 if (!get_value(expr->right, &sval))
71 return -1;
72 if (sval.value < 0 || sval.value > 4096)
73 return -1;
74
75 param_expr = get_assigned_expr(expr->left);
76 if (!param_expr)
77 return -1;
78
79 return sval.value;
80 }
81
82 static void print_returns_container_of(int return_id, char *return_ranges, struct expression *expr)
83 {
84 int offset;
85 int param;
86 char key[64];
87 char value[64];
88
89 param = get_param_from_container_of(expr);
90 if (param < 0)
91 return;
92 offset = get_offset_from_container_of(expr);
93 if (offset < 0)
94 return;
95
96 snprintf(key, sizeof(key), "%d", param);
97 snprintf(value, sizeof(value), "-%d", offset);
98
99 /* no need to add it to return_implies because it's not really param_used */
100 sql_insert_return_states(return_id, return_ranges, CONTAINER, -1,
101 key, value);
102 }
103
104 static int get_deref_count(struct expression *expr)
105 {
106 int cnt = 0;
107
108 while (expr && expr->type == EXPR_DEREF) {
109 expr = expr->deref;
110 if (expr->type == EXPR_PREOP && expr->op == '*')
111 expr = expr->unop;
112 cnt++;
113 if (cnt > 100)
114 return -1;
115 }
116 return cnt;
117 }
118
119 static struct expression *get_partial_deref(struct expression *expr, int cnt)
120 {
121 while (--cnt >= 0) {
122 if (!expr || expr->type != EXPR_DEREF)
123 return expr;
134
135 if (cnt == 0)
136 return snprintf(buf, size, "%c0", op);
137
138 n = 0;
139 while (--cnt >= 0) {
140 offset = get_member_offset_from_deref(expr);
141 if (offset < 0)
142 return -1;
143 n += snprintf(buf + n, size - n, "%c%d", op, offset);
144 if (expr->type != EXPR_DEREF)
145 return -1;
146 expr = expr->deref;
147 if (expr->type == EXPR_PREOP && expr->op == '*')
148 expr = expr->unop;
149 }
150
151 return n;
152 }
153
154 static char *get_shared_str(struct expression *expr, struct expression *container)
155 {
156 struct expression *one, *two;
157 int exp, cont, min, ret, n;
158 static char buf[48];
159
160 exp = get_deref_count(expr);
161 cont = get_deref_count(container);
162 if (exp < 0 || cont < 0)
163 return NULL;
164
165 min = (exp < cont) ? exp : cont;
166 while (min >= 0) {
167 one = get_partial_deref(expr, exp - min);
168 two = get_partial_deref(container, cont - min);
169 if (expr_equiv(one, two))
170 goto found;
171 min--;
172 }
173
174 return NULL;
175
176 found:
177 ret = partial_deref_to_offset_str(expr, exp - min, '-', buf, sizeof(buf));
178 if (ret < 0)
179 return NULL;
180 n = ret;
181 ret = partial_deref_to_offset_str(container, cont - min, '+', buf + ret, sizeof(buf) - ret);
182 if (ret < 0)
183 return NULL;
184 n += ret;
185 if (n >= sizeof(buf))
186 return NULL;
187
188 return buf;
189 }
190
191 static char *get_stored_container_name(struct expression *container,
192 struct expression *expr)
193 {
194 struct smatch_state *state;
195 static char buf[64];
196 char *p;
197 int param;
198
199 if (!container || container->type != EXPR_SYMBOL)
200 return NULL;
201 if (!expr || expr->type != EXPR_SYMBOL)
202 return NULL;
203 state = get_state_expr(param_id, expr);
204 if (!state)
205 return NULL;
206
207 snprintf(buf, sizeof(buf), "%s", state->name);
208 p = strchr(buf, '|');
209 if (!p)
210 return NULL;
211 *p = '\0';
212 param = atoi(p + 2);
213 if (get_param_sym_from_num(param) == container->symbol)
214 return buf;
215 return NULL;
216 }
217
218 char *get_container_name(struct expression *container, struct expression *expr)
219 {
220 struct symbol *container_sym, *sym;
221 struct expression *tmp;
222 static char buf[64];
223 char *ret, *shared;
224 bool star;
225 int cnt;
226
227 expr = strip_expr(expr);
228 container = strip_expr(container);
229
230 ret = get_stored_container_name(container, expr);
231 if (ret)
232 return ret;
233
234 sym = expr_to_sym(expr);
235 container_sym = expr_to_sym(container);
236 if (sym && sym == container_sym)
237 goto found;
238
239 cnt = 0;
240 while ((tmp = get_assigned_expr(container))) {
241 container = strip_expr(tmp);
242 if (cnt++ > 3)
243 break;
244 }
245
246 cnt = 0;
247 while ((tmp = get_assigned_expr(expr))) {
248 expr = strip_expr(tmp);
249 if (cnt++ > 3)
250 break;
251 }
252
253 found:
254
255 if (container->type == EXPR_DEREF)
256 star = true;
257 else
258 star = false;
259
260 if (container->type == EXPR_PREOP && container->op == '&')
261 container = strip_expr(container->unop);
262 if (expr->type == EXPR_PREOP && expr->op == '&')
263 expr = strip_expr(expr->unop);
264
265 sym = expr_to_sym(expr);
266 if (!sym)
267 return NULL;
268 container_sym = expr_to_sym(container);
269 if (!container_sym || sym != container_sym)
270 return NULL;
271
272 shared = get_shared_str(expr, container);
273 if (!shared)
274 return NULL;
275 if (star)
276 snprintf(buf, sizeof(buf), "*(%s)", shared);
277 else
278 snprintf(buf, sizeof(buf), "%s", shared);
279
280 return buf;
281 }
282
283 static bool is_fn_ptr(struct expression *expr)
284 {
285 struct symbol *type;
286
287 if (!expr)
288 return false;
289 if (expr->type != EXPR_SYMBOL && expr->type != EXPR_DEREF)
290 return false;
291
292 type = get_type(expr);
293 if (!type || type->type != SYM_PTR)
294 return false;
295 type = get_real_base_type(type);
296 if (!type || type->type != SYM_FN)
297 return false;
298 return true;
299 }
300
301 static void match_call(struct expression *call)
302 {
303 struct expression *fn, *arg, *tmp;
304 bool found = false;
305 int fn_param, param;
306 char buf[32];
307 char *name;
308
309 /*
310 * We're trying to link the function with the parameter. There are a
311 * couple ways this can be passed:
312 * foo->func(foo, ...);
313 * foo->func(foo->x, ...);
314 * foo->bar.func(&foo->bar, ...);
315 * foo->bar->baz->func(foo, ...);
316 *
317 * So the method is basically to subtract the offsets until we get to
318 * the common bit, then add the member offsets to get the parameter.
319 *
320 * If we're taking an address then the offset math is not stared,
321 * otherwise it is. Starred means dereferenced.
322 */
323 fn = strip_expr(call->fn);
324
325 param = -1;
326 FOR_EACH_PTR(call->args, arg) {
327 param++;
328
329 name = get_container_name(arg, fn);
330 if (!name)
331 continue;
332
333 found = true;
334 sql_insert_caller_info(call, CONTAINER, param, name, "$(-1)");
335 } END_FOR_EACH_PTR(arg);
336
337 if (found)
338 return;
339
340 fn_param = -1;
341 FOR_EACH_PTR(call->args, arg) {
342 fn_param++;
343 if (!is_fn_ptr(arg))
344 continue;
345 param = -1;
346 FOR_EACH_PTR(call->args, tmp) {
347 param++;
348
349 /* the function isn't it's own container */
350 if (arg == tmp)
351 continue;
352
353 name = get_container_name(tmp, arg);
354 if (!name)
355 continue;
356
357 snprintf(buf, sizeof(buf), "$%d", param);
358 sql_insert_caller_info(call, CONTAINER, fn_param, name, buf);
359 return;
360 } END_FOR_EACH_PTR(tmp);
361 } END_FOR_EACH_PTR(arg);
362 }
363
364 static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value)
365 {
366 char buf[64];
367
368 snprintf(buf, sizeof(buf), "%s|%s", key, value);
369 set_state(param_id, name, sym, alloc_state_str(buf));
370 }
371
372 struct db_info {
373 struct symbol *arg;
374 int prev_offset;
375 struct range_list *rl;
376 int star;
377 struct stree *stree;
378 };
379
380 static struct symbol *get_member_from_offset(struct symbol *sym, int offset)
381 {
382 struct symbol *type, *tmp;
383 int cur;
384
385 type = get_real_base_type(sym);
386 if (!type || type->type != SYM_PTR)
387 return NULL;
388 type = get_real_base_type(type);
389 if (!type || type->type != SYM_STRUCT)
420 {
421 struct symbol *member, *type;
422 const char *name;
423 static char fullname[256];
424
425 name = arg->ident->name;
426
427 type = get_real_base_type(arg);
428 if (!type || type->type != SYM_PTR)
429 return name;
430
431 type = get_real_base_type(type);
432 if (!type)
433 return NULL;
434 if (type->type != SYM_STRUCT) {
435 snprintf(fullname, sizeof(fullname), "*%s", name);
436 return fullname;
437 }
438
439 member = get_member_from_offset(arg, offset);
440 if (!member || !member->ident)
441 return NULL;
442
443 snprintf(fullname, sizeof(fullname), "%s->%s", name, member->ident->name);
444 return fullname;
445 }
446
447 static void set_param_value(struct stree **stree, struct symbol *arg, int offset, struct range_list *rl)
448 {
449 const char *name;
450
451 name = get_name_from_offset(arg, offset);
452 if (!name)
453 return;
454 set_state_stree(stree, SMATCH_EXTRA, name, arg, alloc_estate_rl(rl));
455 }
456
457 static int save_vals(void *_db_info, int argc, char **argv, char **azColName)
458 {
459 struct db_info *db_info = _db_info;
460 struct symbol *type;
530 }
531
532 if (db_info.prev_offset != -1)
533 set_param_value(&db_info.stree, arg, db_info.prev_offset, db_info.rl);
534
535 // FIXME: handle an offset correctly
536 if (!star && !arg_offset) {
537 sval_t sval;
538
539 sval.type = get_real_base_type(arg);
540 sval.uvalue = tag;
541 set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval));
542 }
543 return db_info.stree;
544 }
545
546 static void load_container_data(struct symbol *arg, const char *info)
547 {
548 mtag_t cur_tag, container_tag, arg_tag;
549 int container_offset, arg_offset;
550 struct sm_state *sm;
551 struct stree *stree;
552 char *p, *cont;
553 char copy[64];
554 bool star = 0;
555
556 snprintf(copy, sizeof(copy), "%s", info);
557 p = strchr(copy, '|');
558 if (!p)
559 return;
560 *p = '\0';
561 cont = p + 1;
562 p = copy;
563 if (p[0] == '*') {
564 star = 1;
565 p += 2;
566 }
567
568 if (strcmp(cont, "$(-1)") != 0)
569 return;
570
571 if (!get_toplevel_mtag(cur_func_sym, &cur_tag))
572 return;
573
574 while (true) {
575 container_offset = strtoul(p, &p, 0);
576 if (local_debug)
577 sm_msg("%s: cur_tag = %llu container_offset = %d",
578 __func__, cur_tag, container_offset);
579 if (!mtag_map_select_container(cur_tag, container_offset, &container_tag))
580 return;
581 cur_tag = container_tag;
582 if (local_debug)
583 sm_msg("%s: container_tag = %llu p = '%s'",
584 __func__, container_tag, p);
585 if (!p)
586 return;
587 if (p[0] != '-')
588 break;
589 p++;
590 }
611 free_stree(&stree);
612 }
613
614 static void handle_passed_container(struct symbol *sym)
615 {
616 struct symbol *arg;
617 struct smatch_state *state;
618
619 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
620 state = get_state(param_id, arg->ident->name, arg);
621 if (!state || state == &merged)
622 continue;
623 load_container_data(arg, state->name);
624 } END_FOR_EACH_PTR(arg);
625 }
626
627 void register_container_of(int id)
628 {
629 my_id = id;
630
631 add_split_return_callback(&print_returns_container_of);
632 add_hook(&match_call, FUNCTION_CALL_HOOK);
633 }
634
635 void register_container_of2(int id)
636 {
637 param_id = id;
638
639 set_dynamic_states(param_id);
640 select_caller_info_hook(db_passed_container, CONTAINER);
641 add_merge_hook(param_id, &merge_str_state);
642 add_hook(&handle_passed_container, AFTER_DEF_HOOK);
643 }
644
|