Print this page
11506 smatch resync


  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(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 {


 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(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)


 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_shared_cnt(const char *one, const char *two)
 253 {
 254         int i;
 255         int on_end = false;
 256 
 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++;








 266         }
 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--;















 273         }
 274         if (!on_end)
 275                 return 0;
 276 
 277         return i + 1;
 278 }
 279 
 280 static int build_offset_str(struct expression *expr, const char *name,
 281                             int shared, char *buf, int size, int op)
 282 {
 283         int chop = 0;
 284         int offset;
 285         int i;
 286 
 287         i = shared;
 288         while (name[i]) {
 289                 if (name[i] == '.' || name[i] == '-')
 290                         chop++;
 291                 i++;







 292         }
 293 
 294         // FIXME:  Handle more chops
 295         if (chop > 1)
 296                 return 0;
 297 
 298         if (chop == 0) {
 299                 offset = 0;
 300         } else {
 301                 offset = get_member_offset_from_deref(expr);
 302                 if (offset < 0)
 303                         return 0;




























 304         }
 305 
 306         snprintf(buf, size, "%c%d", (op == '+') ? '+' : '-', offset);
 307         return 1;



























 308 }
 309 
 310 static void match_call(struct expression *call)
 311 {
 312         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;
 319 
 320         /*
 321          * We're trying to link the function with the parameter.  There are a
 322          * couple ways this can be passed:
 323          * foo->func(foo, ...);
 324          * foo->func(foo->x, ...);
 325          * foo->bar.func(&foo->bar, ...);
 326          * foo->bar->baz->func(foo, ...);
 327          *
 328          * So the method is basically to subtract the offsets until we get to
 329          * the common bit, then add the member offsets to get the parameter.
 330          *
 331          * If we're taking an address then the offset math is not stared,
 332          * otherwise it is.  Starred means dereferenced.
 333          */
 334         fn = strip_expr(call->fn);
 335         fn_name = expr_to_var(fn);
 336         if (!fn_name)
 337                 return;
 338 
 339         param = -1;
 340         FOR_EACH_PTR(call->args, arg) {
 341                 param++;
 342 
 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)
 352                         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 
 369         free_string(fn_name);

 370 }
 371 
 372 static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value)
 373 {
 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));
 401 }
 402 
 403 struct db_info {
 404         struct symbol *arg;
 405         int prev_offset;
 406         struct range_list *rl;
 407         int star;
 408         struct stree *stree;
 409 };
 410 
 411 static struct symbol *get_member_from_offset(struct symbol *sym, int offset)
 412 {
 413         struct symbol *type, *tmp;
 414         int cur;
 415 
 416         type = get_real_base_type(sym);
 417         if (!type || type->type != SYM_PTR)
 418                 return NULL;
 419         type = get_real_base_type(type);
 420         if (!type || type->type != SYM_STRUCT)


 557         } else {  /* presumably the parameter is a struct pointer */
 558                 run_sql(save_vals, &db_info,
 559                         "select offset, value from mtag_data where tag = %lld and type = %d;",
 560                         tag, DATA_VALUE);
 561         }
 562 
 563         if (db_info.prev_offset != -1)
 564                 set_param_value(&db_info.stree, arg, db_info.prev_offset, db_info.rl);
 565 
 566         // FIXME: handle an offset correctly
 567         if (!star && !arg_offset) {
 568                 sval_t sval;
 569 
 570                 sval.type = get_real_base_type(arg);
 571                 sval.uvalue = tag;
 572                 set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval));
 573         }
 574         return db_info.stree;
 575 }
 576 
 577 static void handle_passed_container(struct symbol *sym)
 578 {
 579         struct symbol *arg;
 580         struct smatch_state *state;

 581         struct sm_state *sm;
 582         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;
 587 
 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);
 593 

 594         return;
 595 found:
 596         if (!estate_get_single_value(state, &offset))





 597                 return;
 598         container_offset = -(offset.value & 0xffff);
 599         arg_offset = (offset.value & 0xfff0000) >> 16;
 600         star = !!(offset.value & (1ULL << 31));







 601 
 602         if (!get_toplevel_mtag(cur_func_sym, &fn_tag))
 603                 return;
 604         if (!mtag_map_select_container(fn_tag, container_offset, &container_tag))



 605                 return;

 606         if (!arg_offset || star) {
 607                 arg_tag = container_tag;
 608         } else {
 609                 if (!mtag_map_select_tag(container_tag, -arg_offset, &arg_tag))
 610                         return;
 611         }
 612 
 613         stree = load_tag_info_sym(arg_tag, arg, arg_offset, star);
 614         FOR_EACH_SM(stree, sm) {
 615                 set_state(sm->owner, sm->name, sm->sym, sm->state);
 616         } END_FOR_EACH_SM(sm);
 617         free_stree(&stree);
 618 }
 619 













 620 void register_container_of(int id)
 621 {
 622         my_id = id;
 623 
 624         add_hook(&match_function_def, FUNC_DEF_HOOK);
 625 
 626         add_get_state_hook(&get_state_hook);
 627 
 628         add_hook(&match_save_states, INLINE_FN_START);
 629         add_hook(&match_restore_states, INLINE_FN_END);
 630 
 631         select_return_implies_hook(CONTAINER, &set_param_used);
 632         all_return_states_hook(&process_states);
 633 
 634         add_split_return_callback(&print_returns_container_of);
 635         select_return_states_hook(CONTAINER, &returns_container_of);
 636 
 637         add_hook(&match_call, FUNCTION_CALL_HOOK);
 638 }
 639 
 640 static struct smatch_state *unmatched_state(struct sm_state *sm)
 641 {
 642         return alloc_estate_whole(estate_type(sm->state));
 643 }
 644 
 645 void register_container_of2(int id)
 646 {
 647         param_id = id;
 648 

 649         select_caller_info_hook(db_passed_container, CONTAINER);

 650         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 }
 654 


  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 {


 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)


 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;
 272                 expr = expr->deref;
 273                 if (expr->type == EXPR_PREOP && expr->op == '*')
 274                         expr = expr->unop;
 275         }
 276         return expr;
 277 }
 278 
 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;
 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)


 584         } else {  /* presumably the parameter is a struct pointer */
 585                 run_sql(save_vals, &db_info,
 586                         "select offset, value from mtag_data where tag = %lld and type = %d;",
 587                         tag, DATA_VALUE);
 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         }
 638 
 639         if (p[0] != '+')
 640                 return;
 641 
 642         p++;
 643         arg_offset = strtoul(p, &p, 0);
 644         if (p && *p && *p != ')')
 645                 return;
 646 
 647         if (!arg_offset || star) {
 648                 arg_tag = container_tag;
 649         } else {
 650                 if (!mtag_map_select_tag(container_tag, -arg_offset, &arg_tag))
 651                         return;
 652         }
 653 
 654         stree = load_tag_info_sym(arg_tag, arg, arg_offset, star);
 655         FOR_EACH_SM(stree, sm) {
 656                 set_state(sm->owner, sm->name, sm->sym, sm->state);
 657         } END_FOR_EACH_SM(sm);
 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