Print this page
12166 resync smatch to 0.6.1-rc1-il-3


   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