Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_container_of.c
+++ new/usr/src/tools/smatch/src/smatch_container_of.c
1 1 /*
2 2 * Copyright (C) 2017 Oracle.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 #include "smatch.h"
19 19 #include "smatch_slist.h"
20 20 #include "smatch_extra.h"
21 21
22 22 static int my_id;
23 23 static int param_id;
24 24
25 25 static struct stree *used_stree;
26 26 static struct stree_stack *saved_stack;
27 27
28 28 STATE(used);
29 29
30 30 int get_param_from_container_of(struct expression *expr)
31 31 {
32 32 struct expression *param_expr;
33 33 struct symbol *type;
34 34 sval_t sval;
35 35 int param;
36 36
37 37
38 38 type = get_type(expr);
39 39 if (!type || type->type != SYM_PTR)
40 40 return -1;
41 41
42 42 expr = strip_expr(expr);
43 43 if (expr->type != EXPR_BINOP || expr->op != '-')
44 44 return -1;
45 45
46 46 if (!get_value(expr->right, &sval))
47 47 return -1;
48 48 if (sval.value < 0 || sval.value > 4096)
49 49 return -1;
50 50
51 51 param_expr = get_assigned_expr(expr->left);
52 52 if (!param_expr)
53 53 return -1;
54 54 param = get_param_num(param_expr);
55 55 if (param < 0)
56 56 return -1;
57 57
58 58 return param;
59 59 }
60 60
61 61 int get_offset_from_container_of(struct expression *expr)
62 62 {
63 63 struct expression *param_expr;
64 64 struct symbol *type;
65 65 sval_t sval;
66 66
67 67 type = get_type(expr);
68 68 if (!type || type->type != SYM_PTR)
69 69 return -1;
70 70
71 71 expr = strip_expr(expr);
72 72 if (expr->type != EXPR_BINOP || expr->op != '-')
73 73 return -1;
74 74
75 75 if (!get_value(expr->right, &sval))
76 76 return -1;
77 77 if (sval.value < 0 || sval.value > 4096)
78 78 return -1;
79 79
80 80 param_expr = get_assigned_expr(expr->left);
81 81 if (!param_expr)
82 82 return -1;
83 83
84 84 return sval.value;
85 85 }
86 86
87 87 static int get_container_arg(struct symbol *sym)
88 88 {
89 89 struct expression *__mptr;
90 90 int param;
91 91
92 92 if (!sym || !sym->ident)
93 93 return -1;
94 94
95 95 __mptr = get_assigned_expr_name_sym(sym->ident->name, sym);
96 96 param = get_param_from_container_of(__mptr);
97 97
98 98 return param;
99 99 }
100 100
101 101 static int get_container_offset(struct symbol *sym)
102 102 {
103 103 struct expression *__mptr;
104 104 int offset;
↓ open down ↓ |
104 lines elided |
↑ open up ↑ |
105 105
106 106 if (!sym || !sym->ident)
107 107 return -1;
108 108
109 109 __mptr = get_assigned_expr_name_sym(sym->ident->name, sym);
110 110 offset = get_offset_from_container_of(__mptr);
111 111
112 112 return offset;
113 113 }
114 114
115 -static char *get_container_name(struct sm_state *sm, int offset)
115 +static char *get_container_name_sm(struct sm_state *sm, int offset)
116 116 {
117 117 static char buf[256];
118 118 const char *name;
119 119
120 120 name = get_param_name(sm);
121 121 if (!name)
122 122 return NULL;
123 123
124 124 if (name[0] == '$')
125 125 snprintf(buf, sizeof(buf), "$(-%d)%s", offset, name + 1);
126 126 else if (name[0] == '*' || name[1] == '$')
127 127 snprintf(buf, sizeof(buf), "*$(-%d)%s", offset, name + 2);
128 128 else
129 129 return NULL;
130 130
131 131 return buf;
132 132 }
133 133
134 134 static void get_state_hook(int owner, const char *name, struct symbol *sym)
135 135 {
136 136 int arg;
137 137
138 138 if (!option_info)
139 139 return;
140 140 if (__in_fake_assign)
141 141 return;
142 142
143 143 arg = get_container_arg(sym);
144 144 if (arg >= 0)
145 145 set_state_stree(&used_stree, my_id, name, sym, &used);
146 146 }
147 147
148 148 static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused)
149 149 {
150 150 struct symbol *sym;
151 151 char *name;
152 152 int arg_nr;
153 153
154 154 name = get_variable_from_key(arg, key, &sym);
155 155 if (!name || !sym)
156 156 goto free;
157 157
158 158 arg_nr = get_container_arg(sym);
159 159 if (arg_nr >= 0)
160 160 set_state(my_id, name, sym, &used);
161 161 free:
162 162 free_string(name);
163 163 }
164 164
165 165 static void process_states(void)
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
166 166 {
167 167 struct sm_state *tmp;
168 168 int arg, offset;
169 169 const char *name;
170 170
171 171 FOR_EACH_SM(used_stree, tmp) {
172 172 arg = get_container_arg(tmp->sym);
173 173 offset = get_container_offset(tmp->sym);
174 174 if (arg < 0 || offset < 0)
175 175 continue;
176 - name = get_container_name(tmp, offset);
176 + name = get_container_name_sm(tmp, offset);
177 177 if (!name)
178 178 continue;
179 179 sql_insert_return_implies(CONTAINER, arg, name, "");
180 180 } END_FOR_EACH_SM(tmp);
181 181
182 182 free_stree(&used_stree);
183 183 }
184 184
185 185 static void match_function_def(struct symbol *sym)
186 186 {
187 187 free_stree(&used_stree);
188 188 }
189 189
190 190 static void match_save_states(struct expression *expr)
191 191 {
192 192 push_stree(&saved_stack, used_stree);
193 193 used_stree = NULL;
194 194 }
195 195
196 196 static void match_restore_states(struct expression *expr)
197 197 {
198 198 free_stree(&used_stree);
199 199 used_stree = pop_stree(&saved_stack);
200 200 }
201 201
202 202 static void print_returns_container_of(int return_id, char *return_ranges, struct expression *expr)
203 203 {
204 204 int offset;
205 205 int param;
206 206 char key[64];
207 207 char value[64];
208 208
209 209 param = get_param_from_container_of(expr);
210 210 if (param < 0)
211 211 return;
212 212 offset = get_offset_from_container_of(expr);
213 213 if (offset < 0)
214 214 return;
215 215
216 216 snprintf(key, sizeof(key), "%d", param);
217 217 snprintf(value, sizeof(value), "-%d", offset);
218 218
219 219 /* no need to add it to return_implies because it's not really param_used */
220 220 sql_insert_return_states(return_id, return_ranges, CONTAINER, -1,
221 221 key, value);
222 222 }
223 223
224 224 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
225 225 {
226 226 struct expression *call, *arg;
227 227 int offset;
228 228 char buf[64];
229 229
230 230 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
231 231 return;
232 232 call = strip_expr(expr->right);
233 233 if (call->type != EXPR_CALL)
234 234 return;
235 235 if (param != -1)
236 236 return;
237 237 param = atoi(key);
238 238 offset = atoi(value);
239 239
240 240 arg = get_argument_from_call_expr(call->args, param);
241 241 if (!arg)
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
242 242 return;
243 243 if (arg->type != EXPR_SYMBOL)
244 244 return;
245 245 param = get_param_num(arg);
246 246 if (param < 0)
247 247 return;
248 248 snprintf(buf, sizeof(buf), "$(%d)", offset);
249 249 sql_insert_return_implies(CONTAINER, param, buf, "");
250 250 }
251 251
252 -static int get_shared_cnt(const char *one, const char *two)
252 +static int get_deref_count(struct expression *expr)
253 253 {
254 - int i;
255 - int on_end = false;
254 + int cnt = 0;
256 255
257 - i = 0;
258 - while (true) {
259 - if (!one[i] || !two[i]) {
260 - on_end = true;
261 - break;
262 - }
263 - if (one[i] != two[i])
264 - break;
265 - i++;
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;
266 263 }
267 - if (i == 0)
268 - return 0;
269 - i--;
270 - while (i > 0 && (one[i] == '>' || one[i] == '-' || one[i] == '.')) {
271 - on_end = true;
272 - i--;
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;
272 + expr = expr->deref;
273 + if (expr->type == EXPR_PREOP && expr->op == '*')
274 + expr = expr->unop;
273 275 }
274 - if (!on_end)
275 - return 0;
276 + return expr;
277 +}
276 278
277 - return i + 1;
279 +static int partial_deref_to_offset_str(struct expression *expr, int cnt, char op, char *buf, int size)
280 +{
281 + int n, offset;
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;
278 300 }
279 301
280 -static int build_offset_str(struct expression *expr, const char *name,
281 - int shared, char *buf, int size, int op)
302 +static char *get_shared_str(struct expression *container, struct expression *expr)
282 303 {
283 - int chop = 0;
284 - int offset;
285 - int i;
304 + struct expression *one, *two;
305 + int cont, exp, min, ret, n;
306 + static char buf[48];
286 307
287 - i = shared;
288 - while (name[i]) {
289 - if (name[i] == '.' || name[i] == '-')
290 - chop++;
291 - i++;
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--;
292 320 }
293 321
294 - // FIXME: Handle more chops
295 - if (chop > 1)
296 - return 0;
322 + return NULL;
297 323
298 - if (chop == 0) {
299 - offset = 0;
300 - } else {
301 - offset = get_member_offset_from_deref(expr);
302 - if (offset < 0)
303 - return 0;
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;
304 358 }
305 359
306 - snprintf(buf, size, "%c%d", (op == '+') ? '+' : '-', offset);
307 - return 1;
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;
308 389 }
309 390
310 391 static void match_call(struct expression *call)
311 392 {
312 393 struct expression *fn, *arg;
313 - char *fn_name, *arg_name;
314 - int param, shared;
315 - char minus_str[64];
316 - char plus_str[64];
317 - char offset_str[64];
318 - bool star;
394 + char *name;
395 + int param;
319 396
320 397 /*
321 398 * We're trying to link the function with the parameter. There are a
322 399 * couple ways this can be passed:
323 400 * foo->func(foo, ...);
324 401 * foo->func(foo->x, ...);
325 402 * foo->bar.func(&foo->bar, ...);
326 403 * foo->bar->baz->func(foo, ...);
327 404 *
328 405 * So the method is basically to subtract the offsets until we get to
329 406 * the common bit, then add the member offsets to get the parameter.
330 407 *
331 408 * If we're taking an address then the offset math is not stared,
332 409 * otherwise it is. Starred means dereferenced.
333 410 */
334 411 fn = strip_expr(call->fn);
335 - fn_name = expr_to_var(fn);
336 - if (!fn_name)
337 - return;
338 412
339 413 param = -1;
340 414 FOR_EACH_PTR(call->args, arg) {
341 415 param++;
342 416
343 - arg = strip_expr(arg);
344 - star = true;
345 - if (arg->type == EXPR_PREOP && arg->op == '&') {
346 - arg = strip_expr(arg->unop);
347 - star = false;
348 - }
349 -
350 - arg_name = expr_to_var(arg);
351 - if (!arg_name)
417 + name = get_container_name(fn, arg);
418 + if (!name)
352 419 continue;
353 - shared = get_shared_cnt(fn_name, arg_name);
354 - if (!shared)
355 - goto free_arg_name;
356 - if (!build_offset_str(fn, fn_name, shared, minus_str, sizeof(minus_str), '-'))
357 - goto free_arg_name;
358 - if (!build_offset_str(arg, arg_name, shared, plus_str, sizeof(plus_str), '+'))
359 - goto free_arg_name;
360 - if (star)
361 - snprintf(offset_str, sizeof(offset_str), "*(%s%s)", minus_str, plus_str);
362 - else
363 - snprintf(offset_str, sizeof(offset_str), "%s%s", minus_str, plus_str);
364 - sql_insert_caller_info(call, CONTAINER, param, offset_str, "$(-1)");
365 -free_arg_name:
366 - free_string(arg_name);
367 - } END_FOR_EACH_PTR(arg);
368 420
369 - free_string(fn_name);
421 + sql_insert_caller_info(call, CONTAINER, param, name, "$(-1)");
422 + } END_FOR_EACH_PTR(arg);
370 423 }
371 424
372 425 static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value)
373 426 {
374 - sval_t offset = {
375 - .type = &int_ctype,
376 - };
377 - const char *arg_offset;
378 - int star = 0;
379 - int val;
380 -
381 - if (key[0] == '*') {
382 - star = 1;
383 - key += 2;
384 - }
385 -
386 - val = atoi(key);
387 - if (val < -4095 || val > 0)
388 - return;
389 - offset.value = -val;
390 - arg_offset = strchr(key, '+');
391 - if (!arg_offset)
392 - return;
393 - val = atoi(arg_offset + 1);
394 - if (val > 4095 || val < 0)
395 - return;
396 - offset.value |= val << 16;
397 - if (star)
398 - offset.value |= 1ULL << 31;
399 -
400 - set_state(param_id, name, sym, alloc_estate_sval(offset));
427 + set_state(param_id, name, sym, alloc_state_str(key));
401 428 }
402 429
403 430 struct db_info {
404 431 struct symbol *arg;
405 432 int prev_offset;
406 433 struct range_list *rl;
407 434 int star;
408 435 struct stree *stree;
409 436 };
410 437
411 438 static struct symbol *get_member_from_offset(struct symbol *sym, int offset)
412 439 {
413 440 struct symbol *type, *tmp;
414 441 int cur;
415 442
416 443 type = get_real_base_type(sym);
417 444 if (!type || type->type != SYM_PTR)
418 445 return NULL;
419 446 type = get_real_base_type(type);
420 447 if (!type || type->type != SYM_STRUCT)
421 448 return NULL;
422 449
423 450 cur = 0;
424 451 FOR_EACH_PTR(type->symbol_list, tmp) {
425 452 cur = ALIGN(cur, tmp->ctype.alignment);
426 453 if (offset == cur)
427 454 return tmp;
428 455 cur += type_bytes(tmp);
429 456 } END_FOR_EACH_PTR(tmp);
430 457 return NULL;
431 458 }
432 459
433 460 static struct symbol *get_member_type_from_offset(struct symbol *sym, int offset)
434 461 {
435 462 struct symbol *base_type;
436 463 struct symbol *member;
437 464
438 465 base_type = get_real_base_type(sym);
439 466 if (base_type && base_type->type == SYM_PTR)
440 467 base_type = get_real_base_type(base_type);
441 468 if (offset == 0 && base_type && base_type->type == SYM_BASETYPE)
442 469 return base_type;
443 470
444 471 member = get_member_from_offset(sym, offset);
445 472 if (!member)
446 473 return NULL;
447 474 return get_real_base_type(member);
448 475 }
449 476
450 477 static const char *get_name_from_offset(struct symbol *arg, int offset)
451 478 {
452 479 struct symbol *member, *type;
453 480 const char *name;
454 481 static char fullname[256];
455 482
456 483 name = arg->ident->name;
457 484
458 485 type = get_real_base_type(arg);
459 486 if (!type || type->type != SYM_PTR)
460 487 return name;
461 488
462 489 type = get_real_base_type(type);
463 490 if (!type)
464 491 return NULL;
465 492 if (type->type != SYM_STRUCT) {
466 493 snprintf(fullname, sizeof(fullname), "*%s", name);
467 494 return fullname;
468 495 }
469 496
470 497 member = get_member_from_offset(arg, offset);
471 498 if (!member)
472 499 return NULL;
473 500
474 501 snprintf(fullname, sizeof(fullname), "%s->%s", name, member->ident->name);
475 502 return fullname;
476 503 }
477 504
478 505 static void set_param_value(struct stree **stree, struct symbol *arg, int offset, struct range_list *rl)
479 506 {
480 507 const char *name;
481 508
482 509 name = get_name_from_offset(arg, offset);
483 510 if (!name)
484 511 return;
485 512 set_state_stree(stree, SMATCH_EXTRA, name, arg, alloc_estate_rl(rl));
486 513 }
487 514
488 515 static int save_vals(void *_db_info, int argc, char **argv, char **azColName)
489 516 {
490 517 struct db_info *db_info = _db_info;
491 518 struct symbol *type;
492 519 struct range_list *rl;
493 520 int offset = 0;
494 521 const char *value;
495 522
496 523 if (argc == 2) {
497 524 offset = atoi(argv[0]);
498 525 value = argv[1];
499 526 } else {
500 527 value = argv[0];
501 528 }
502 529
503 530 if (db_info->prev_offset != -1 &&
504 531 db_info->prev_offset != offset) {
505 532 set_param_value(&db_info->stree, db_info->arg, db_info->prev_offset, db_info->rl);
506 533 db_info->rl = NULL;
507 534 }
508 535
509 536 db_info->prev_offset = offset;
510 537
511 538 type = get_real_base_type(db_info->arg);
512 539 if (db_info->star)
513 540 goto found_type;
514 541 if (type->type != SYM_PTR)
515 542 return 0;
516 543 type = get_real_base_type(type);
517 544 if (type->type == SYM_BASETYPE)
518 545 goto found_type;
519 546 type = get_member_type_from_offset(db_info->arg, offset);
520 547 found_type:
521 548 str_to_rl(type, (char *)value, &rl);
522 549 if (db_info->rl)
523 550 db_info->rl = rl_union(db_info->rl, rl);
524 551 else
525 552 db_info->rl = rl;
526 553
527 554 return 0;
528 555 }
529 556
530 557 static struct stree *load_tag_info_sym(mtag_t tag, struct symbol *arg, int arg_offset, int star)
531 558 {
532 559 struct db_info db_info = {
533 560 .arg = arg,
534 561 .prev_offset = -1,
535 562 .star = star,
536 563 };
537 564 struct symbol *type;
538 565
539 566 if (!tag || !arg->ident)
540 567 return NULL;
541 568
542 569 type = get_real_base_type(arg);
543 570 if (!type)
544 571 return NULL;
545 572 if (!star) {
546 573 if (type->type != SYM_PTR)
547 574 return NULL;
548 575 type = get_real_base_type(type);
549 576 if (!type)
550 577 return NULL;
551 578 }
552 579
553 580 if (star || type->type == SYM_BASETYPE) {
554 581 run_sql(save_vals, &db_info,
555 582 "select value from mtag_data where tag = %lld and offset = %d and type = %d;",
556 583 tag, arg_offset, DATA_VALUE);
557 584 } else { /* presumably the parameter is a struct pointer */
558 585 run_sql(save_vals, &db_info,
559 586 "select offset, value from mtag_data where tag = %lld and type = %d;",
560 587 tag, DATA_VALUE);
561 588 }
562 589
563 590 if (db_info.prev_offset != -1)
564 591 set_param_value(&db_info.stree, arg, db_info.prev_offset, db_info.rl);
565 592
566 593 // FIXME: handle an offset correctly
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
567 594 if (!star && !arg_offset) {
568 595 sval_t sval;
569 596
570 597 sval.type = get_real_base_type(arg);
571 598 sval.uvalue = tag;
572 599 set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval));
573 600 }
574 601 return db_info.stree;
575 602 }
576 603
577 -static void handle_passed_container(struct symbol *sym)
604 +static void load_container_data(struct symbol *arg, const char *info)
578 605 {
579 - struct symbol *arg;
580 - struct smatch_state *state;
606 + mtag_t cur_tag, container_tag, arg_tag;
607 + int container_offset, arg_offset;
608 + char *p = (char *)info;
581 609 struct sm_state *sm;
582 610 struct stree *stree;
583 - mtag_t fn_tag, container_tag, arg_tag;
584 - sval_t offset;
585 - int container_offset, arg_offset;
586 - int star;
611 + bool star = 0;
587 612
588 - FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
589 - state = get_state(param_id, arg->ident->name, arg);
590 - if (state)
591 - goto found;
592 - } END_FOR_EACH_PTR(arg);
613 + if (p[0] == '*') {
614 + star = 1;
615 + p += 2;
616 + }
593 617
594 - return;
595 -found:
596 - if (!estate_get_single_value(state, &offset))
618 + if (!get_toplevel_mtag(cur_func_sym, &cur_tag))
597 619 return;
598 - container_offset = -(offset.value & 0xffff);
599 - arg_offset = (offset.value & 0xfff0000) >> 16;
600 - star = !!(offset.value & (1ULL << 31));
601 620
602 - if (!get_toplevel_mtag(cur_func_sym, &fn_tag))
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 + }
638 +
639 + if (p[0] != '+')
603 640 return;
604 - if (!mtag_map_select_container(fn_tag, container_offset, &container_tag))
641 +
642 + p++;
643 + arg_offset = strtoul(p, &p, 0);
644 + if (p && *p && *p != ')')
605 645 return;
646 +
606 647 if (!arg_offset || star) {
607 648 arg_tag = container_tag;
608 649 } else {
609 650 if (!mtag_map_select_tag(container_tag, -arg_offset, &arg_tag))
610 651 return;
611 652 }
612 653
613 654 stree = load_tag_info_sym(arg_tag, arg, arg_offset, star);
614 655 FOR_EACH_SM(stree, sm) {
615 656 set_state(sm->owner, sm->name, sm->sym, sm->state);
616 657 } END_FOR_EACH_SM(sm);
617 658 free_stree(&stree);
618 659 }
619 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 +
620 674 void register_container_of(int id)
621 675 {
622 676 my_id = id;
623 677
624 678 add_hook(&match_function_def, FUNC_DEF_HOOK);
625 679
626 680 add_get_state_hook(&get_state_hook);
627 681
628 682 add_hook(&match_save_states, INLINE_FN_START);
629 683 add_hook(&match_restore_states, INLINE_FN_END);
630 684
631 685 select_return_implies_hook(CONTAINER, &set_param_used);
632 686 all_return_states_hook(&process_states);
633 687
634 688 add_split_return_callback(&print_returns_container_of);
635 689 select_return_states_hook(CONTAINER, &returns_container_of);
636 690
637 691 add_hook(&match_call, FUNCTION_CALL_HOOK);
638 692 }
639 693
640 -static struct smatch_state *unmatched_state(struct sm_state *sm)
641 -{
642 - return alloc_estate_whole(estate_type(sm->state));
643 -}
644 -
645 694 void register_container_of2(int id)
646 695 {
647 696 param_id = id;
648 697
698 + set_dynamic_states(param_id);
649 699 select_caller_info_hook(db_passed_container, CONTAINER);
700 + add_merge_hook(param_id, &merge_str_state);
650 701 add_hook(&handle_passed_container, AFTER_DEF_HOOK);
651 - add_unmatched_state_hook(param_id, &unmatched_state);
652 - add_merge_hook(param_id, &merge_estates);
653 702 }
654 703
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX