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

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
↓ open down ↓ 14 lines elided ↑ open up ↑
  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      -static struct stree *used_stree;
  26      -static struct stree_stack *saved_stack;
  27      -
  28      -STATE(used);
  29      -
  30   25  int get_param_from_container_of(struct expression *expr)
  31   26  {
  32   27          struct expression *param_expr;
  33   28          struct symbol *type;
  34   29          sval_t sval;
  35   30          int param;
  36   31  
  37   32  
  38   33          type = get_type(expr);
  39   34          if (!type || type->type != SYM_PTR)
↓ open down ↓ 37 lines elided ↑ open up ↑
  77   72          if (sval.value < 0 || sval.value > 4096)
  78   73                  return -1;
  79   74  
  80   75          param_expr = get_assigned_expr(expr->left);
  81   76          if (!param_expr)
  82   77                  return -1;
  83   78  
  84   79          return sval.value;
  85   80  }
  86   81  
  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   82  static void print_returns_container_of(int return_id, char *return_ranges, struct expression *expr)
 203   83  {
 204   84          int offset;
 205   85          int param;
 206   86          char key[64];
 207   87          char value[64];
 208   88  
 209   89          param = get_param_from_container_of(expr);
 210   90          if (param < 0)
 211   91                  return;
↓ open down ↓ 2 lines elided ↑ open up ↑
 214   94                  return;
 215   95  
 216   96          snprintf(key, sizeof(key), "%d", param);
 217   97          snprintf(value, sizeof(value), "-%d", offset);
 218   98  
 219   99          /* no need to add it to return_implies because it's not really param_used */
 220  100          sql_insert_return_states(return_id, return_ranges, CONTAINER, -1,
 221  101                          key, value);
 222  102  }
 223  103  
 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  104  static int get_deref_count(struct expression *expr)
 253  105  {
 254  106          int cnt = 0;
 255  107  
 256  108          while (expr && expr->type == EXPR_DEREF) {
 257  109                  expr = expr->deref;
 258  110                  if (expr->type == EXPR_PREOP && expr->op == '*')
 259  111                          expr = expr->unop;
 260  112                  cnt++;
 261  113                  if (cnt > 100)
↓ open down ↓ 30 lines elided ↑ open up ↑
 292  144                  if (expr->type != EXPR_DEREF)
 293  145                          return -1;
 294  146                  expr = expr->deref;
 295  147                  if (expr->type == EXPR_PREOP && expr->op == '*')
 296  148                          expr = expr->unop;
 297  149          }
 298  150  
 299  151          return n;
 300  152  }
 301  153  
 302      -static char *get_shared_str(struct expression *container, struct expression *expr)
      154 +static char *get_shared_str(struct expression *expr, struct expression *container)
 303  155  {
 304  156          struct expression *one, *two;
 305      -        int cont, exp, min, ret, n;
      157 +        int exp, cont, min, ret, n;
 306  158          static char buf[48];
 307  159  
 308      -        cont = get_deref_count(container);
 309  160          exp = get_deref_count(expr);
 310      -        if (cont < 0 || exp < 0)
      161 +        cont = get_deref_count(container);
      162 +        if (exp < 0 || cont < 0)
 311  163                  return NULL;
 312  164  
 313      -        min = (cont < exp) ? cont : exp;
      165 +        min = (exp < cont) ? exp : cont;
 314  166          while (min >= 0) {
 315      -                one = get_partial_deref(container, cont - min);
 316      -                two = get_partial_deref(expr, exp - min);
      167 +                one = get_partial_deref(expr, exp - min);
      168 +                two = get_partial_deref(container, cont - min);
 317  169                  if (expr_equiv(one, two))
 318  170                          goto found;
 319  171                  min--;
 320  172          }
 321  173  
 322  174          return NULL;
 323  175  
 324  176  found:
 325      -        ret = partial_deref_to_offset_str(container, cont - min, '-', buf, sizeof(buf));
      177 +        ret = partial_deref_to_offset_str(expr, exp - min, '-', buf, sizeof(buf));
 326  178          if (ret < 0)
 327  179                  return NULL;
 328  180          n = ret;
 329      -        ret = partial_deref_to_offset_str(expr, exp - min, '+', buf + ret, sizeof(buf) - ret);
      181 +        ret = partial_deref_to_offset_str(container, cont - min, '+', buf + ret, sizeof(buf) - ret);
 330  182          if (ret < 0)
 331  183                  return NULL;
 332  184          n += ret;
 333  185          if (n >= sizeof(buf))
 334  186                  return NULL;
 335  187  
 336  188          return buf;
 337  189  }
 338  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 +
 339  218  char *get_container_name(struct expression *container, struct expression *expr)
 340  219  {
 341  220          struct symbol *container_sym, *sym;
 342  221          struct expression *tmp;
 343  222          static char buf[64];
 344      -        char *shared;
      223 +        char *ret, *shared;
 345  224          bool star;
 346  225          int cnt;
 347  226  
 348      -        container_sym = expr_to_sym(container);
      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 +
 349  234          sym = expr_to_sym(expr);
 350      -        if (container_sym && container_sym == sym)
      235 +        container_sym = expr_to_sym(container);
      236 +        if (sym && sym == container_sym)
 351  237                  goto found;
 352  238  
 353  239          cnt = 0;
 354      -        while ((tmp = get_assigned_expr(expr))) {
 355      -                expr = tmp;
      240 +        while ((tmp = get_assigned_expr(container))) {
      241 +                container = strip_expr(tmp);
 356  242                  if (cnt++ > 3)
 357  243                          break;
 358  244          }
 359  245  
 360  246          cnt = 0;
 361      -        while ((tmp = get_assigned_expr(container))) {
 362      -                container = tmp;
      247 +        while ((tmp = get_assigned_expr(expr))) {
      248 +                expr = strip_expr(tmp);
 363  249                  if (cnt++ > 3)
 364  250                          break;
 365  251          }
 366  252  
 367  253  found:
 368      -        expr = strip_expr(expr);
 369      -        star = true;
 370      -        if (expr->type == EXPR_PREOP && expr->op == '&') {
 371      -                expr = strip_expr(expr->unop);
      254 +
      255 +        if (container->type == EXPR_DEREF)
      256 +                star = true;
      257 +        else
 372  258                  star = false;
 373      -        }
 374  259  
 375      -        container_sym = expr_to_sym(container);
 376      -        if (!container_sym)
 377      -                return NULL;
      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 +
 378  265          sym = expr_to_sym(expr);
 379      -        if (!sym || container_sym != sym)
      266 +        if (!sym)
 380  267                  return NULL;
      268 +        container_sym = expr_to_sym(container);
      269 +        if (!container_sym || sym != container_sym)
      270 +                return NULL;
 381  271  
 382      -        shared = get_shared_str(container, expr);
      272 +        shared = get_shared_str(expr, container);
      273 +        if (!shared)
      274 +                return NULL;
 383  275          if (star)
 384  276                  snprintf(buf, sizeof(buf), "*(%s)", shared);
 385  277          else
 386  278                  snprintf(buf, sizeof(buf), "%s", shared);
 387  279  
 388  280          return buf;
 389  281  }
 390  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 +
 391  301  static void match_call(struct expression *call)
 392  302  {
 393      -        struct expression *fn, *arg;
      303 +        struct expression *fn, *arg, *tmp;
      304 +        bool found = false;
      305 +        int fn_param, param;
      306 +        char buf[32];
 394  307          char *name;
 395      -        int param;
 396  308  
 397  309          /*
 398  310           * We're trying to link the function with the parameter.  There are a
 399  311           * couple ways this can be passed:
 400  312           * foo->func(foo, ...);
 401  313           * foo->func(foo->x, ...);
 402  314           * foo->bar.func(&foo->bar, ...);
 403  315           * foo->bar->baz->func(foo, ...);
 404  316           *
 405  317           * So the method is basically to subtract the offsets until we get to
↓ open down ↓ 1 lines elided ↑ open up ↑
 407  319           *
 408  320           * If we're taking an address then the offset math is not stared,
 409  321           * otherwise it is.  Starred means dereferenced.
 410  322           */
 411  323          fn = strip_expr(call->fn);
 412  324  
 413  325          param = -1;
 414  326          FOR_EACH_PTR(call->args, arg) {
 415  327                  param++;
 416  328  
 417      -                name = get_container_name(fn, arg);
      329 +                name = get_container_name(arg, fn);
 418  330                  if (!name)
 419  331                          continue;
 420  332  
      333 +                found = true;
 421  334                  sql_insert_caller_info(call, CONTAINER, param, name, "$(-1)");
 422  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);
 423  362  }
 424  363  
 425  364  static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value)
 426  365  {
 427      -        set_state(param_id, name, sym, alloc_state_str(key));
      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));
 428  370  }
 429  371  
 430  372  struct db_info {
 431  373          struct symbol *arg;
 432  374          int prev_offset;
 433  375          struct range_list *rl;
 434  376          int star;
 435  377          struct stree *stree;
 436  378  };
 437  379  
↓ open down ↓ 50 lines elided ↑ open up ↑
 488  430  
 489  431          type = get_real_base_type(type);
 490  432          if (!type)
 491  433                  return NULL;
 492  434          if (type->type != SYM_STRUCT) {
 493  435                  snprintf(fullname, sizeof(fullname), "*%s", name);
 494  436                  return fullname;
 495  437          }
 496  438  
 497  439          member = get_member_from_offset(arg, offset);
 498      -        if (!member)
      440 +        if (!member || !member->ident)
 499  441                  return NULL;
 500  442  
 501  443          snprintf(fullname, sizeof(fullname), "%s->%s", name, member->ident->name);
 502  444          return fullname;
 503  445  }
 504  446  
 505  447  static void set_param_value(struct stree **stree, struct symbol *arg, int offset, struct range_list *rl)
 506  448  {
 507  449          const char *name;
 508  450  
↓ open down ↓ 89 lines elided ↑ open up ↑
 598  540                  sval.uvalue = tag;
 599  541                  set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval));
 600  542          }
 601  543          return db_info.stree;
 602  544  }
 603  545  
 604  546  static void load_container_data(struct symbol *arg, const char *info)
 605  547  {
 606  548          mtag_t cur_tag, container_tag, arg_tag;
 607  549          int container_offset, arg_offset;
 608      -        char *p = (char *)info;
 609  550          struct sm_state *sm;
 610  551          struct stree *stree;
      552 +        char *p, *cont;
      553 +        char copy[64];
 611  554          bool star = 0;
 612  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;
 613  563          if (p[0] == '*') {
 614  564                  star = 1;
 615  565                  p += 2;
 616  566          }
 617  567  
      568 +        if (strcmp(cont, "$(-1)") != 0)
      569 +                return;
      570 +
 618  571          if (!get_toplevel_mtag(cur_func_sym, &cur_tag))
 619  572                  return;
 620  573  
 621  574          while (true) {
 622  575                  container_offset = strtoul(p, &p, 0);
 623  576                  if (local_debug)
 624  577                          sm_msg("%s: cur_tag = %llu container_offset = %d",
 625  578                                 __func__, cur_tag, container_offset);
 626  579                  if (!mtag_map_select_container(cur_tag, container_offset, &container_tag))
 627  580                          return;
↓ open down ↓ 40 lines elided ↑ open up ↑
 668  621                  if (!state || state == &merged)
 669  622                          continue;
 670  623                  load_container_data(arg, state->name);
 671  624          } END_FOR_EACH_PTR(arg);
 672  625  }
 673  626  
 674  627  void register_container_of(int id)
 675  628  {
 676  629          my_id = id;
 677  630  
 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  631          add_split_return_callback(&print_returns_container_of);
 689      -        select_return_states_hook(CONTAINER, &returns_container_of);
 690      -
 691  632          add_hook(&match_call, FUNCTION_CALL_HOOK);
 692  633  }
 693  634  
 694  635  void register_container_of2(int id)
 695  636  {
 696  637          param_id = id;
 697  638  
 698  639          set_dynamic_states(param_id);
 699  640          select_caller_info_hook(db_passed_container, CONTAINER);
 700  641          add_merge_hook(param_id, &merge_str_state);
 701  642          add_hook(&handle_passed_container, AFTER_DEF_HOOK);
 702  643  }
 703  644  
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX