Print this page
12724 update smatch to 0.6.1-rc1-il-5

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/smatch/src/smatch_db.c
          +++ new/usr/src/tools/smatch/src/smatch_db.c
↓ open down ↓ 42 lines elided ↑ open up ↑
  43   43  DECLARE_PTR_LIST(callback_list, struct def_callback);
  44   44  static struct callback_list *select_caller_info_callbacks;
  45   45  
  46   46  struct member_info_callback {
  47   47          int owner;
  48   48          void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm);
  49   49  };
  50   50  ALLOCATOR(member_info_callback, "caller_info callbacks");
  51   51  DECLARE_PTR_LIST(member_info_cb_list, struct member_info_callback);
  52   52  static struct member_info_cb_list *member_callbacks;
       53 +static struct member_info_cb_list *member_callbacks_new;
  53   54  
  54   55  struct returned_state_callback {
  55   56          void (*callback)(int return_id, char *return_ranges, struct expression *return_expr);
  56   57  };
  57   58  ALLOCATOR(returned_state_callback, "returned state callbacks");
  58   59  DECLARE_PTR_LIST(returned_state_cb_list, struct returned_state_callback);
  59   60  static struct returned_state_cb_list *returned_state_callbacks;
  60   61  
  61   62  struct returned_member_callback {
  62   63          int owner;
↓ open down ↓ 108 lines elided ↑ open up ↑
 171  172                          count++;
 172  173          } END_FOR_EACH_SM(sm);
 173  174          return count;
 174  175  }
 175  176  
 176  177  void db_ignore_states(int id)
 177  178  {
 178  179          use_states[id] = 0;
 179  180  }
 180  181  
      182 +unsigned long long __fn_mtag;
      183 +static void set_fn_mtag(struct symbol *sym)
      184 +{
      185 +        char buf[128];
      186 +
      187 +        if (cur_func_sym->ctype.modifiers & MOD_STATIC)
      188 +                snprintf(buf, sizeof(buf), "%s %s", get_base_file(), get_function());
      189 +        else
      190 +                snprintf(buf, sizeof(buf), "extern %s", get_function());
      191 +
      192 +        __fn_mtag = str_to_mtag(buf);
      193 +}
      194 +
 181  195  void sql_insert_return_states(int return_id, const char *return_ranges,
 182  196                  int type, int param, const char *key, const char *value)
 183  197  {
      198 +        unsigned long long id;
      199 +
      200 +
 184  201          if (key && strlen(key) >= 80)
 185  202                  return;
      203 +        if (__inline_fn)
      204 +                id = (unsigned long)__inline_fn;
      205 +        else
      206 +                id = __fn_mtag;
      207 +
 186  208          return_ranges = replace_return_ranges(return_ranges);
 187      -        sql_insert(return_states, "'%s', '%s', %lu, %d, '%s', %d, %d, %d, '%s', '%s'",
 188      -                   get_base_file(), get_function(), (unsigned long)__inline_fn,
 189      -                   return_id, return_ranges, fn_static(), type, param, key, value);
      209 +        sql_insert(return_states, "'%s', '%s', %llu, %d, '%s', %d, %d, %d, '%s', '%s'",
      210 +                   get_base_file(), get_function(), id, return_id,
      211 +                   return_ranges, fn_static(), type, param, key, value);
 190  212  }
 191  213  
 192  214  static struct string_list *common_funcs;
 193  215  static int is_common_function(const char *fn)
 194  216  {
 195  217          char *tmp;
 196  218  
 197  219          if (!fn)
 198  220                  return 0;
 199  221  
↓ open down ↓ 165 lines elided ↑ open up ↑
 365  387  
 366  388          sql_insert(fn_data_link, "'%s', '%s', %d, %d, %d, '%s', '%s'",
 367  389                     (fn->symbol->ctype.modifiers & MOD_STATIC) ? get_base_file() : "extern",
 368  390                     fn->symbol->ident->name,
 369  391                     !!(fn->symbol->ctype.modifiers & MOD_STATIC),
 370  392                     type, param, key, value);
 371  393  }
 372  394  
 373  395  void sql_insert_mtag_about(mtag_t tag, const char *left_name, const char *right_name)
 374  396  {
 375      -        sql_insert(mtag_about, "%lld, '%s', '%s', %d, '%s', '%s'",
 376      -                   tag, get_filename(), get_function(), get_lineno(), left_name, right_name);
      397 +        sql_insert_cache(mtag_about, "%lld, '%s', '%s', %d, '%s', '%s'",
      398 +                         tag, get_filename(), get_function(), get_lineno(),
      399 +                         left_name, right_name);
 377  400  }
 378  401  
 379      -void sql_insert_mtag_map(mtag_t tag, int offset, mtag_t container)
      402 +void sql_insert_mtag_info(mtag_t tag, int type, const char *value)
 380  403  {
 381      -        sql_insert(mtag_map, "%lld, %d, %lld", tag, offset, container);
      404 +        sql_insert_cache(mtag_info, "'%s', %lld, %d, '%s'", get_filename(), tag, type, value);
 382  405  }
 383  406  
      407 +void sql_insert_mtag_map(mtag_t container, int container_offset, mtag_t tag, int tag_offset)
      408 +{
      409 +        sql_insert(mtag_map, "%lld, %d, %lld, %d", container, container_offset, tag, tag_offset);
      410 +}
      411 +
 384  412  void sql_insert_mtag_alias(mtag_t orig, mtag_t alias)
 385  413  {
 386  414          sql_insert(mtag_alias, "%lld, %lld", orig, alias);
 387  415  }
 388  416  
 389  417  static int save_mtag(void *_tag, int argc, char **argv, char **azColName)
 390  418  {
 391  419          mtag_t *saved_tag = _tag;
 392  420          mtag_t new_tag;
 393  421  
 394  422          new_tag = strtoll(argv[0], NULL, 10);
 395  423  
 396  424          if (!*saved_tag)
 397  425                  *saved_tag = new_tag;
 398  426          else if (*saved_tag != new_tag)
 399  427                  *saved_tag = -1ULL;
 400  428  
 401  429          return 0;
 402  430  }
 403  431  
 404      -int mtag_map_select_container(mtag_t tag, int offset, mtag_t *container)
      432 +int mtag_map_select_container(mtag_t tag, int container_offset, mtag_t *container)
 405  433  {
 406  434          mtag_t tmp = 0;
 407  435  
 408  436          run_sql(save_mtag, &tmp,
 409      -                "select container from mtag_map where tag = %lld and offset = %d;",
 410      -                tag, offset);
      437 +                "select container from mtag_map where tag = %lld and container_offset = %d and tag_offset = 0;",
      438 +                tag, container_offset);
 411  439  
 412  440          if (tmp == 0 || tmp == -1ULL)
 413  441                  return 0;
 414  442          *container = tmp;
 415  443          return 1;
 416  444  }
 417  445  
 418  446  int mtag_map_select_tag(mtag_t container, int offset, mtag_t *tag)
 419  447  {
 420  448          mtag_t tmp = 0;
 421  449  
 422  450          run_sql(save_mtag, &tmp,
 423      -                "select tag from mtag_map where container = %lld and offset = %d;",
      451 +                "select tag from mtag_map where container = %lld and container_offset = %d;",
 424  452                  container, offset);
 425  453  
 426  454          if (tmp == 0 || tmp == -1ULL)
 427  455                  return 0;
 428  456          *tag = tmp;
 429  457          return 1;
 430  458  }
 431  459  
 432  460  char *get_static_filter(struct symbol *sym)
 433  461  {
↓ open down ↓ 181 lines elided ↑ open up ↑
 615  643   */
 616  644  void add_member_info_callback(int owner, void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
 617  645  {
 618  646          struct member_info_callback *member_callback = __alloc_member_info_callback(0);
 619  647  
 620  648          member_callback->owner = owner;
 621  649          member_callback->callback = callback;
 622  650          add_ptr_list(&member_callbacks, member_callback);
 623  651  }
 624  652  
      653 +void add_caller_info_callback(int owner, void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
      654 +{
      655 +        struct member_info_callback *member_callback = __alloc_member_info_callback(0);
      656 +
      657 +        member_callback->owner = owner;
      658 +        member_callback->callback = callback;
      659 +        add_ptr_list(&member_callbacks_new, member_callback);
      660 +}
      661 +
 625  662  void add_split_return_callback(void (*fn)(int return_id, char *return_ranges, struct expression *returned_expr))
 626  663  {
 627  664          struct returned_state_callback *callback = __alloc_returned_state_callback(0);
 628  665  
 629  666          callback->callback = fn;
 630  667          add_ptr_list(&returned_state_callbacks, callback);
 631  668  }
 632  669  
 633  670  void add_returned_member_callback(int owner, void (*callback)(int return_id, char *return_ranges, struct expression *expr, char *printed_name, struct smatch_state *state))
 634  671  {
↓ open down ↓ 209 lines elided ↑ open up ↑
 844  881                           sm_name + len);
 845  882          }
 846  883  
 847  884          ret = alloc_sname(buf);
 848  885  free:
 849  886          free_string(name);
 850  887          return ret;
 851  888  }
 852  889  
 853  890  static void print_struct_members(struct expression *call, struct expression *expr, int param, struct stree *stree,
 854      -        void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
      891 +        void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm),
      892 +        bool new)
 855  893  {
 856  894          struct sm_state *sm;
 857  895          const char *sm_name;
 858  896          char *name;
 859  897          struct symbol *sym;
 860  898          int len;
 861  899          char printed_name[256];
 862  900          int is_address = 0;
 863  901          bool add_star;
 864  902          struct symbol *type;
↓ open down ↓ 19 lines elided ↑ open up ↑
 884  922                  if (sm->sym != sym)
 885  923                          continue;
 886  924                  sm_name = sm->name;
 887  925                  add_star = false;
 888  926                  if (sm_name[0] == '*') {
 889  927                          add_star = true;
 890  928                          sm_name++;
 891  929                  }
 892  930                  // FIXME: simplify?
 893  931                  if (!add_star && strcmp(name, sm_name) == 0) {
 894      -                        if (is_address)
      932 +                        if (is_address) {
 895  933                                  snprintf(printed_name, sizeof(printed_name), "*$");
 896      -                        else /* these are already handled. fixme: handle them here */
 897      -                                continue;
      934 +                        } else {
      935 +                                if (new)
      936 +                                        snprintf(printed_name, sizeof(printed_name), "$");
      937 +                                else
      938 +                                        continue;
      939 +                        }
 898  940                  } else if (add_star && strcmp(name, sm_name) == 0) {
 899  941                          snprintf(printed_name, sizeof(printed_name), "%s*$",
 900  942                                   is_address ? "*" : "");
 901  943                  } else if (strncmp(name, sm_name, len) == 0) {
 902  944                          if (sm_name[len] != '.' && sm_name[len] != '-')
 903  945                                  continue;
 904      -                        if (is_address)
      946 +                        if (is_address && sm_name[len] == '.') {
 905  947                                  snprintf(printed_name, sizeof(printed_name),
 906  948                                           "%s$->%s", add_star ? "*" : "",
 907  949                                           sm_name + len + 1);
 908      -                        else
      950 +                        } else if (is_address && sm_name[len] == '-') {
 909  951                                  snprintf(printed_name, sizeof(printed_name),
      952 +                                         "%s(*$)%s", add_star ? "*" : "",
      953 +                                         sm_name + len);
      954 +                        } else {
      955 +                                snprintf(printed_name, sizeof(printed_name),
 910  956                                           "%s$%s", add_star ? "*" : "",
 911  957                                           sm_name + len);
      958 +                        }
 912  959                  } else {
 913  960                          continue;
 914  961                  }
 915  962                  if (is_recursive_member(printed_name))
 916  963                          continue;
 917  964                  callback(call, param, printed_name, sm);
 918  965          } END_FOR_EACH_SM(sm);
 919  966  free:
 920  967          free_string(name);
 921  968  }
↓ open down ↓ 7 lines elided ↑ open up ↑
 929  976          int i;
 930  977  
 931  978          name = get_fnptr_name(call->fn);
 932  979          if (!name)
 933  980                  return;
 934  981  
 935  982          FOR_EACH_PTR(member_callbacks, cb) {
 936  983                  stree = get_all_states_stree(cb->owner);
 937  984                  i = 0;
 938  985                  FOR_EACH_PTR(call->args, arg) {
 939      -                        print_struct_members(call, arg, i, stree, cb->callback);
      986 +                        print_struct_members(call, arg, i, stree, cb->callback, 0);
 940  987                          i++;
 941  988                  } END_FOR_EACH_PTR(arg);
 942  989                  free_stree(&stree);
 943  990          } END_FOR_EACH_PTR(cb);
 944  991  
 945  992          free_string(name);
 946  993  }
 947  994  
      995 +static void match_call_info_new(struct expression *call)
      996 +{
      997 +        struct member_info_callback *cb;
      998 +        struct expression *arg;
      999 +        struct stree *stree;
     1000 +        char *name;
     1001 +        int i;
     1002 +
     1003 +        name = get_fnptr_name(call->fn);
     1004 +        if (!name)
     1005 +                return;
     1006 +
     1007 +        FOR_EACH_PTR(member_callbacks_new, cb) {
     1008 +                stree = get_all_states_stree(cb->owner);
     1009 +                i = 0;
     1010 +                FOR_EACH_PTR(call->args, arg) {
     1011 +                        print_struct_members(call, arg, i, stree, cb->callback, 1);
     1012 +                        i++;
     1013 +                } END_FOR_EACH_PTR(arg);
     1014 +                free_stree(&stree);
     1015 +        } END_FOR_EACH_PTR(cb);
     1016 +
     1017 +        free_string(name);
     1018 +}
     1019 +
 948 1020  static int get_param(int param, char **name, struct symbol **sym)
 949 1021  {
 950 1022          struct symbol *arg;
 951 1023          int i;
 952 1024  
 953 1025          i = 0;
 954 1026          FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
 955 1027                  /*
 956 1028                   * this is a temporary hack to work around a bug (I think in sparse?)
 957 1029                   * 2.6.37-rc1:fs/reiserfs/journal.o
↓ open down ↓ 141 lines elided ↑ open up ↑
1099 1171  static void match_data_from_db(struct symbol *sym)
1100 1172  {
1101 1173          struct select_caller_info_data data = { .prev_func_id = -1 };
1102 1174          struct sm_state *sm;
1103 1175          struct stree *stree;
1104 1176          struct timeval end_time;
1105 1177  
1106 1178          if (!sym || !sym->ident)
1107 1179                  return;
1108 1180  
     1181 +        set_fn_mtag(sym);
1109 1182          gettimeofday(&data.start_time, NULL);
1110 1183  
1111 1184          __push_fake_cur_stree();
1112 1185          __unnullify_path();
1113 1186  
1114 1187          if (!__inline_fn) {
1115 1188                  char *ptr;
1116 1189  
1117 1190                  if (sym->ctype.modifiers & MOD_STATIC)
1118 1191                          get_ptr_names(get_base_file(), sym->ident->name);
↓ open down ↓ 443 lines elided ↑ open up ↑
1562 1635  
1563 1636          free_slist(&already_handled);
1564 1637  
1565 1638          return ret;
1566 1639  }
1567 1640  
1568 1641  static int call_return_state_hooks_split_possible(struct expression *expr)
1569 1642  {
1570 1643          struct sm_state *sm;
1571 1644  
1572      -        if (!expr || expr_equal_to_param(expr, -1))
     1645 +        if (!expr)
1573 1646                  return 0;
1574 1647  
1575 1648          sm = get_sm_state_expr(SMATCH_EXTRA, expr);
1576 1649          return split_possible_helper(sm, expr);
1577 1650  }
1578 1651  
1579 1652  static bool has_possible_negative(struct sm_state *sm)
1580 1653  {
1581 1654          struct sm_state *tmp;
1582 1655  
↓ open down ↓ 117 lines elided ↑ open up ↑
1700 1773          sm = get_sm_state_expr(SMATCH_EXTRA, expr);
1701 1774          if (!sm)
1702 1775                  return 0;
1703 1776          if (ptr_list_size((struct ptr_list *)sm->possible) == 1)
1704 1777                  return 0;
1705 1778          state = sm->state;
1706 1779          if (!estate_rl(state))
1707 1780                  return 0;
1708 1781          if (estate_min(state).value == 0 && estate_max(state).value == 0)
1709 1782                  return 0;
     1783 +        if (has_possible_negative(sm))
     1784 +                return 0;
1710 1785          if (!has_separate_zero_null(sm))
1711 1786                  return 0;
1712 1787  
1713 1788          nr_states = get_db_state_count();
1714 1789          if (option_info && nr_states >= 1500)
1715 1790                  return 0;
1716 1791  
1717 1792          rl = estate_rl(state);
1718 1793  
1719 1794          __push_fake_cur_stree();
↓ open down ↓ 293 lines elided ↑ open up ↑
2013 2088                  return orig;
2014 2089  
2015 2090          last_stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
2016 2091          if (!last_stmt || last_stmt->type == STMT_LABEL)
2017 2092                  last_stmt = last_stmt->label_statement;
2018 2093          if (!last_stmt || last_stmt->type != STMT_EXPRESSION)
2019 2094                  return orig;
2020 2095          return strip_expr(last_stmt->expression);
2021 2096  }
2022 2097  
     2098 +static bool is_kernel_error_path(struct expression *expr)
     2099 +{
     2100 +        struct range_list *rl;
     2101 +
     2102 +        /*
     2103 +         * Splitting up returns requires resources.  It also requires resources
     2104 +         * for the caller.  It doesn't seem worth it to split anything up.
     2105 +         */
     2106 +        if (!get_implied_rl(expr, &rl))
     2107 +                return false;
     2108 +        if (rl_type(rl) != &int_ctype)
     2109 +                return false;
     2110 +        if (rl_min(rl).value >= -4095 &&
     2111 +            rl_max(rl).value < 0)
     2112 +                return true;
     2113 +        return false;
     2114 +}
     2115 +
2023 2116  static void call_return_state_hooks(struct expression *expr)
2024 2117  {
2025 2118          struct returned_state_callback *cb;
2026 2119          struct range_list *ret_rl;
2027 2120          const char *return_ranges;
2028 2121          int nr_states;
2029 2122          sval_t sval;
2030 2123  
2031 2124          if (__path_is_null())
2032 2125                  return;
↓ open down ↓ 4 lines elided ↑ open up ↑
2037 2130          if (is_impossible_path())
2038 2131                  goto vanilla;
2039 2132  
2040 2133          if (expr && (expr->type == EXPR_COMPARE ||
2041 2134                       !get_implied_value(expr, &sval)) &&
2042 2135              (is_condition(expr) || is_boolean(expr))) {
2043 2136                  call_return_state_hooks_compare(expr);
2044 2137                  return;
2045 2138          } else if (call_return_state_hooks_conditional(expr)) {
2046 2139                  return;
     2140 +        } else if (is_kernel_error_path(expr)) {
     2141 +                goto vanilla;
2047 2142          } else if (call_return_state_hooks_split_possible(expr)) {
2048 2143                  return;
2049 2144          } else if (split_positive_from_negative(expr)) {
2050 2145                  return;
2051 2146          } else if (call_return_state_hooks_split_null_non_null_zero(expr)) {
2052 2147                  return;
2053 2148          } else if (call_return_state_hooks_split_success_fail(expr)) {
2054 2149                  return;
2055 2150          } else if (splitable_function_call(expr)) {
2056 2151                  return;
↓ open down ↓ 101 lines elided ↑ open up ↑
2158 2253                  "db/function_type_value.schema",
2159 2254                  "db/type_value.schema",
2160 2255                  "db/function_type.schema",
2161 2256                  "db/data_info.schema",
2162 2257                  "db/parameter_name.schema",
2163 2258                  "db/constraints.schema",
2164 2259                  "db/constraints_required.schema",
2165 2260                  "db/fn_ptr_data_link.schema",
2166 2261                  "db/fn_data_link.schema",
2167 2262                  "db/mtag_about.schema",
     2263 +                "db/mtag_info.schema",
2168 2264                  "db/mtag_map.schema",
2169 2265                  "db/mtag_data.schema",
2170 2266                  "db/mtag_alias.schema",
2171 2267          };
2172 2268          static char buf[4096];
2173 2269          int fd;
2174 2270          int ret;
2175 2271          int i;
2176 2272  
2177 2273          rc = sqlite3_open(":memory:", &mem_db);
↓ open down ↓ 27 lines elided ↑ open up ↑
2205 2301  }
2206 2302  
2207 2303  static void init_cachedb(void)
2208 2304  {
2209 2305          char *err = NULL;
2210 2306          int rc;
2211 2307          const char *schema_files[] = {
2212 2308                  "db/call_implies.schema",
2213 2309                  "db/return_implies.schema",
2214 2310                  "db/type_info.schema",
     2311 +                "db/mtag_about.schema",
2215 2312                  "db/mtag_data.schema",
     2313 +                "db/mtag_info.schema",
2216 2314                  "db/sink_info.schema",
2217 2315          };
2218 2316          static char buf[4096];
2219 2317          int fd;
2220 2318          int ret;
2221 2319          int i;
2222 2320  
2223 2321          rc = sqlite3_open(":memory:", &cache_db);
2224 2322          if (rc != SQLITE_OK) {
2225 2323                  sm_ierror("starting In-Memory database.");
↓ open down ↓ 44 lines elided ↑ open up ↑
2270 2368          p += snprintf(p, 4096 - (p - buf), ");");
2271 2369          if (p - buf > 4096)
2272 2370                  return 0;
2273 2371  
2274 2372          sm_msg("SQL: %s", buf);
2275 2373          return 0;
2276 2374  }
2277 2375  
2278 2376  static void dump_cache(struct symbol_list *sym_list)
2279 2377  {
     2378 +        const char *cache_tables[] = {
     2379 +                "type_info", "return_implies", "call_implies", "mtag_data",
     2380 +                "mtag_info", "mtag_about", "sink_info",
     2381 +        };
     2382 +        char buf[64];
     2383 +        int i;
     2384 +
2280 2385          if (!option_info)
2281 2386                  return;
2282      -        cache_sql(&save_cache_data, (char *)"type_info", "select * from type_info;");
2283      -        cache_sql(&save_cache_data, (char *)"return_implies", "select * from return_implies;");
2284      -        cache_sql(&save_cache_data, (char *)"call_implies", "select * from call_implies;");
2285      -        cache_sql(&save_cache_data, (char *)"mtag_data", "select * from mtag_data;");
2286      -        cache_sql(&save_cache_data, (char *)"sink_info", "select * from sink_info;");
     2387 +
     2388 +        for (i = 0; i < ARRAY_SIZE(cache_tables); i++) {
     2389 +                snprintf(buf, sizeof(buf), "select * from %s;", cache_tables[i]);
     2390 +                cache_sql(&save_cache_data, (char *)cache_tables[i], buf);
     2391 +        }
2287 2392  }
2288 2393  
2289 2394  void open_smatch_db(char *db_file)
2290 2395  {
2291 2396          int rc;
2292 2397  
2293 2398          if (option_no_db)
2294 2399                  return;
2295 2400  
2296 2401          use_states = malloc(num_checks + 1);
↓ open down ↓ 125 lines elided ↑ open up ↑
2422 2527  
2423 2528                  replace_table[i++] = func;
2424 2529                  replace_table[i++] = orig;
2425 2530                  replace_table[i++] = new;
2426 2531          }
2427 2532  }
2428 2533  
2429 2534  void register_definition_db_callbacks(int id)
2430 2535  {
2431 2536          add_hook(&match_call_info, FUNCTION_CALL_HOOK);
     2537 +        add_hook(&match_call_info_new, FUNCTION_CALL_HOOK);
2432 2538          add_split_return_callback(match_return_info);
2433 2539          add_split_return_callback(print_returned_struct_members);
2434 2540          add_hook(&call_return_state_hooks, RETURN_HOOK);
2435 2541          add_hook(&match_end_func_info, END_FUNC_HOOK);
2436 2542          add_hook(&match_after_func, AFTER_FUNC_HOOK);
2437 2543  
2438 2544          add_hook(&match_data_from_db, FUNC_DEF_HOOK);
2439 2545          add_hook(&match_call_implies, FUNC_DEF_HOOK);
2440 2546          add_hook(&match_return_implies, CALL_HOOK_AFTER_INLINE);
2441 2547  
↓ open down ↓ 44 lines elided ↑ open up ↑
2486 2592  
2487 2593          arg = get_argument_from_call_expr(expr->args, param);
2488 2594          if (!arg)
2489 2595                  return NULL;
2490 2596  
2491 2597          return get_variable_from_key(arg, key, sym);
2492 2598  }
2493 2599  
2494 2600  char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
2495 2601  {
     2602 +        struct symbol *type;
2496 2603          char buf[256];
2497 2604          char *tmp;
2498 2605          int star_cnt = 0;
     2606 +        bool add_dot = false;
2499 2607  
2500 2608          if (!arg)
2501 2609                  return NULL;
2502 2610  
2503 2611          arg = strip_expr(arg);
2504 2612  
2505 2613          if (strcmp(key, "$") == 0)
2506 2614                  return expr_to_var_sym(arg, sym);
2507 2615  
2508 2616          if (strcmp(key, "*$") == 0) {
↓ open down ↓ 3 lines elided ↑ open up ↑
2512 2620                  } else {
2513 2621                          tmp = expr_to_var_sym(arg, sym);
2514 2622                          if (!tmp)
2515 2623                                  return NULL;
2516 2624                          snprintf(buf, sizeof(buf), "*%s", tmp);
2517 2625                          free_string(tmp);
2518 2626                          return alloc_string(buf);
2519 2627                  }
2520 2628          }
2521 2629  
     2630 +        if (strncmp(key, "(*$)", 4) == 0) {
     2631 +                char buf[64];
     2632 +
     2633 +                if (arg->type == EXPR_PREOP && arg->op == '&') {
     2634 +                        arg = strip_expr(arg->unop);
     2635 +                        snprintf(buf, sizeof(buf), "$%s", key + 4);
     2636 +                        return get_variable_from_key(arg, buf, sym);
     2637 +                } else {
     2638 +                        tmp = expr_to_var_sym(arg, sym);
     2639 +                        if (!tmp)
     2640 +                                return NULL;
     2641 +                        snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
     2642 +                        free_string(tmp);
     2643 +                        return alloc_string(buf);
     2644 +                }
     2645 +        }
     2646 +
2522 2647          while (key[0] == '*') {
2523 2648                  star_cnt++;
2524 2649                  key++;
2525 2650          }
2526 2651  
2527      -        if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt) {
     2652 +        /*
     2653 +         * FIXME:  This is a hack.
     2654 +         * We should be able to parse expressions like (*$)->foo and *$->foo.
     2655 +         */
     2656 +        type = get_type(arg);
     2657 +        if (is_struct_ptr(type))
     2658 +                add_dot = true;
     2659 +
     2660 +        if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
2528 2661                  arg = strip_expr(arg->unop);
2529 2662                  star_cnt--;
2530 2663          }
2531 2664  
2532 2665          if (arg->type == EXPR_PREOP && arg->op == '&') {
2533 2666                  arg = strip_expr(arg->unop);
2534 2667                  tmp = expr_to_var_sym(arg, sym);
2535 2668                  if (!tmp)
2536 2669                          return NULL;
2537 2670                  snprintf(buf, sizeof(buf), "%.*s%s.%s",
↓ open down ↓ 28 lines elided ↑ open up ↑
2566 2699  
2567 2700          while (state_name[0] == '*') {
2568 2701                  star_cnt++;
2569 2702                  state_name++;
2570 2703          }
2571 2704  
2572 2705          /* ten out of ten stars! */
2573 2706          if (star_cnt > 10)
2574 2707                  return NULL;
2575 2708  
     2709 +        if (strncmp(state_name, "(*", 2) == 0 &&
     2710 +            strncmp(state_name + 2, param_name, name_len) == 0 &&
     2711 +            state_name[name_len + 2] == ')') {
     2712 +                snprintf(buf, sizeof(buf), "%.*s(*$)%s", star_cnt, "**********",
     2713 +                         state_name + name_len + 3);
     2714 +                return alloc_sname(buf);
     2715 +        }
     2716 +
2576 2717          if (strcmp(state_name, param_name) == 0) {
2577 2718                  snprintf(buf, sizeof(buf), "%.*s$", star_cnt, "**********");
2578 2719                  return alloc_sname(buf);
2579 2720          }
2580 2721  
2581 2722          if (state_name[name_len] == '-' && /* check for '-' from "->" */
2582 2723              strncmp(state_name, param_name, name_len) == 0) {
2583 2724                  snprintf(buf, sizeof(buf), "%.*s$%s", star_cnt, "**********", state_name + name_len);
2584 2725                  return alloc_sname(buf);
2585 2726          }
↓ open down ↓ 92 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX