Print this page
11506 smatch resync


  33  *
  34  * Another place where we would maybe name the pointer is when they are passed
  35  * to the probe().  Because that's an important pointer, since there is one
  36  * per driver (sort of).
  37  *
  38  * My vision is that you could take a pointer and trace it back to a global.  So
  39  * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
  40  * tag.  You could follow that one back and so on.  Also when we pass a pointer
  41  * to a function that would be recorded as sort of a link or path or something.
  42  *
  43  */
  44 
  45 #include "smatch.h"
  46 #include "smatch_slist.h"
  47 #include "smatch_extra.h"
  48 
  49 #include <openssl/md5.h>
  50 
  51 static int my_id;
  52 
  53 static struct smatch_state *alloc_tag_state(mtag_t tag)
  54 {
  55         struct smatch_state *state;
  56         char buf[64];
  57 
  58         state = __alloc_smatch_state(0);
  59         snprintf(buf, sizeof(buf), "%lld", tag);
  60         state->name = alloc_sname(buf);
  61         state->data = malloc(sizeof(mtag_t));
  62         *(mtag_t *)state->data = tag;
  63 
  64         return state;
  65 }
  66 
  67 static mtag_t str_to_tag(const char *str)
  68 {
  69         unsigned char c[MD5_DIGEST_LENGTH];
  70         unsigned long long *tag = (unsigned long long *)&c;
  71         MD5_CTX mdContext;
  72         int len;
  73 
  74         len = strlen(str);
  75         MD5_Init(&mdContext);
  76         MD5_Update(&mdContext, str, len);
  77         MD5_Final(c, &mdContext);
  78 
  79         *tag &= ~MTAG_ALIAS_BIT;
  80         *tag &= ~MTAG_OFFSET_MASK;
  81 
  82         return *tag;
  83 }
  84 
  85 static void alloc_assign(const char *fn, struct expression *expr, void *unused)










  86 {

























  87         struct expression *left, *right;
  88         char *left_name, *right_name;
  89         struct symbol *left_sym;

  90         char buf[256];
  91         mtag_t tag;

  92 


  93 
  94         // FIXME:  This should only happen when the size is not a paramter of
  95         // the caller
  96         return;
  97 
  98         if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
  99                 return;
 100         left = strip_expr(expr->left);
 101         right = strip_expr(expr->right);
 102         if (right->type != EXPR_CALL || right->fn->type != EXPR_SYMBOL)
 103                 return;
 104 



 105         left_name = expr_to_str_sym(left, &left_sym);


 106         right_name = expr_to_str(right);
 107 
 108         snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
 109                  left_name, right_name);
 110         tag = str_to_tag(buf);


 111 
 112         sql_insert_mtag_about(tag, left_name, right_name);


 113 
 114         if (left_name && left_sym)
 115                 set_state(my_id, left_name, left_sym, alloc_tag_state(tag));
 116 
 117         free_string(left_name);
 118         free_string(right_name);


 119 }
 120 
 121 int get_string_mtag(struct expression *expr, mtag_t *tag)
 122 {
 123         mtag_t xor;
 124 
 125         if (expr->type != EXPR_STRING || !expr->string)
 126                 return 0;
 127 
 128         /* I was worried about collisions so I added a xor */
 129         xor = str_to_tag("__smatch string");
 130         *tag = str_to_tag(expr->string->data);
 131         *tag = *tag ^ xor;
 132 
 133         return 1;
 134 }
 135 
 136 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
 137 {
 138         char buf[256];
 139 
 140         if (!sym)
 141                 return 0;
 142 
 143         if (!sym->ident ||
 144             !(sym->ctype.modifiers & MOD_TOPLEVEL))
 145                 return 0;
 146 
 147         snprintf(buf, sizeof(buf), "%s %s",
 148                  (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
 149                  sym->ident->name);
 150         *tag = str_to_tag(buf);
 151         return 1;
 152 }
 153 
 154 int get_deref_mtag(struct expression *expr, mtag_t *tag)
 155 {
 156         mtag_t container_tag, member_tag;
 157         int offset;
 158 
 159         /*
 160          * I'm not totally sure what I'm doing...
 161          *
 162          * This is supposed to get something like "global_var->ptr", but I don't
 163          * feel like it's complete at all.
 164          *
 165          */
 166 
 167         if (!get_mtag(expr->unop, &container_tag))
 168                 return 0;
 169 
 170         offset = get_member_offset_from_deref(expr);
 171         if (offset < 0)
 172                 return 0;
 173 
 174         if (!mtag_map_select_tag(container_tag, -offset, &member_tag))
 175                 return 0;
 176 
 177         *tag = member_tag;
 178         return 1;
 179 }
 180 
 181 static void global_variable(struct symbol *sym)
 182 {
 183         mtag_t tag;
 184 
 185         if (!get_toplevel_mtag(sym, &tag))
 186                 return;
 187 
 188         sql_insert_mtag_about(tag,
 189                               sym->ident->name,
 190                               (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
 191 }
 192 
 193 static void db_returns_buf_size(struct expression *expr, int param, char *unused, char *math)
 194 {
 195         struct expression *call;
 196         struct range_list *rl;
 197 
 198         if (expr->type != EXPR_ASSIGNMENT)
 199                 return;
 200         call = strip_expr(expr->right);
 201 
 202         if (!parse_call_math_rl(call, math, &rl))
 203                 return;
 204 //      rl = cast_rl(&int_ctype, rl);
 205 //      set_state_expr(my_size_id, expr->left, alloc_estate_rl(rl));
 206 }
 207 
 208 static void db_returns_memory_tag(struct expression *expr, int param, char *key, char *value)
 209 {
 210         struct expression *call, *arg;
 211         mtag_t tag, alias;
 212         char *name;
 213         struct symbol *sym;
 214 
 215         call = strip_expr(expr);
 216         while (call->type == EXPR_ASSIGNMENT)
 217                 call = strip_expr(call->right);
 218         if (call->type != EXPR_CALL)
 219                 return;
 220 
 221         tag = strtoul(value, NULL, 10);
 222 
 223         if (!create_mtag_alias(tag, call, &alias))
 224                 return;
 225 
 226         arg = get_argument_from_call_expr(call->args, param);
 227         if (!arg)
 228                 return;
 229 
 230         name = get_variable_from_key(arg, key, &sym);
 231         if (!name || !sym)
 232                 goto free;
 233 
 234         set_state(my_id, name, sym, alloc_tag_state(alias));
 235 free:
 236         free_string(name);
 237 }
 238 
 239 static void match_call_info(struct expression *expr)
 240 {
 241         struct smatch_state *state;
 242         struct expression *arg;
 243         int i = -1;
 244 
 245         FOR_EACH_PTR(expr->args, arg) {
 246                 i++;
 247                 state = get_state_expr(my_id, arg);
 248                 if (!state || !state->data)
 249                         continue;
 250                 sql_insert_caller_info(expr, MEMORY_TAG, i, "$", state->name);
 251         } END_FOR_EACH_PTR(arg);
 252 }
 253 
 254 static void save_caller_info(const char *name, struct symbol *sym, char *key, char *value)
 255 {
 256         struct smatch_state *state;
 257         char fullname[256];
 258         mtag_t tag;
 259 
 260         if (strncmp(key, "$", 1) != 0)
 261                 return;
 262 
 263         tag = atoll(value);
 264         snprintf(fullname, 256, "%s%s", name, key + 1);
 265         state = alloc_tag_state(tag);
 266         set_state(my_id, fullname, sym, state);
 267 }
 268 
 269 static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
 270 {
 271         struct expression *array, *offset_expr;
 272         struct symbol *type;
 273         sval_t sval;

 274 
 275         if (!is_array(expr))
 276                 return 0;
 277 
 278         array = get_array_base(expr);
 279         if (!array)
 280                 return 0;
 281         type = get_type(array);
 282         if (!type || type->type != SYM_ARRAY)
 283                 return 0;
 284         type = get_real_base_type(type);
 285         if (!type_bytes(type))
 286                 return 0;
 287 
 288         if (!get_mtag(array, tag))
 289                 return 0;
 290 
 291         offset_expr = get_array_offset(expr);
 292         if (!get_value(offset_expr, &sval))
 293                 return 0;
 294         *offset = sval.value * type_bytes(type);
 295 
 296         return 1;
 297 }
 298 
 299 static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
 300 {
 301         struct smatch_state *state;
 302         struct symbol *type;
 303         sval_t sval;

 304 
 305         type = get_type(expr);
 306         if (!type_is_ptr(type))
 307                 return 0;
 308         state = get_extra_state(expr);
 309         if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
 310                 return 0;
 311 
 312         *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
 313         *offset = sval.uvalue & MTAG_OFFSET_MASK;
 314         return 1;



 315 }
 316 
 317 static int get_mtag_cnt;
 318 int get_mtag(struct expression *expr, mtag_t *tag)
 319 {
 320         struct smatch_state *state;
 321         int ret = 0;
 322 
 323         expr = strip_expr(expr);
 324         if (!expr)
 325                 return 0;
 326 
 327         if (get_mtag_cnt > 0)
 328                 return 0;
 329 
 330         get_mtag_cnt++;
 331 
 332         switch (expr->type) {
 333         case EXPR_STRING:
 334                 if (get_string_mtag(expr, tag)) {
 335                         ret = 1;
 336                         goto dec_cnt;
 337                 }
 338                 break;
 339         case EXPR_SYMBOL:
 340                 if (get_toplevel_mtag(expr->symbol, tag)) {
 341                         ret = 1;
 342                         goto dec_cnt;
 343                 }
 344                 break;
 345         case EXPR_DEREF:
 346                 if (get_deref_mtag(expr, tag)) {
 347                         ret = 1;
 348                         goto dec_cnt;
 349                 }
 350                 break;
 351         }
 352 
 353         state = get_state_expr(my_id, expr);
 354         if (!state)
 355                 goto dec_cnt;
 356         if (state->data) {
 357                 *tag = *(mtag_t *)state->data;
 358                 ret = 1;
 359                 goto dec_cnt;
 360         }
 361 
 362 dec_cnt:
 363         get_mtag_cnt--;
 364         return ret;
 365 }
 366 
 367 int get_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
 368 {
 369         int val;
 370 
 371         if (!expr)
 372                 return 0;
 373         if (expr->type == EXPR_PREOP && expr->op == '*')
 374                 return get_mtag_offset(expr->unop, tag, offset);
 375         if (get_implied_mtag_offset(expr, tag, offset))
 376                 return 1;
 377         if (!get_mtag(expr, tag))
 378                 return 0;
 379         expr = strip_expr(expr);
 380         if (expr->type == EXPR_SYMBOL) {
 381                 *offset = 0;
 382                 return 1;
 383         }
 384         val = get_member_offset_from_deref(expr);
 385         if (val < 0)
 386                 return 0;
 387         *offset = val;
 388         return 1;
 389 }
 390 
 391 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
 392 {
 393         char buf[256];
 394         int lines_from_start;
 395         char *str;
 396 
 397         /*
 398          * We need the alias to be unique.  It's not totally required that it
 399          * be the same from one DB build to then next, but it makes debugging
 400          * a bit simpler.
 401          *
 402          */
 403 
 404         if (!cur_func_sym)
 405                 return 0;
 406 
 407         lines_from_start = expr->pos.line - cur_func_sym->pos.line;
 408         str = expr_to_str(expr);
 409         snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
 410         free_string(str);
 411 
 412         *new = str_to_tag(buf);
 413         sql_insert_mtag_alias(tag, *new);
 414 
 415         return 1;
 416 }
 417 































 418 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
 419 {

 420         *offset = 0;
 421 



 422         expr = strip_expr(expr);
 423         if (!expr)
 424                 return 0;
 425 
 426         if (is_array(expr))
 427                 return get_array_mtag_offset(expr, tag, offset);
 428 
 429         if (expr->type ==  EXPR_DEREF) {
 430                 *offset = get_member_offset_from_deref(expr);
 431                 if (*offset < 0)






 432                         return 0;
 433                 return get_mtag(expr->deref, tag);

 434         }



 435 
 436         if (get_implied_mtag_offset(expr, tag, offset))



 437                 return 1;
 438 
 439         return get_mtag(expr, tag);








 440 }
 441 














 442 int get_mtag_sval(struct expression *expr, sval_t *sval)
 443 {
 444         struct symbol *type;
 445         mtag_t tag;
 446         int offset = 0;
 447 
 448         if (bits_in_pointer != 64)
 449                 return 0;
 450 
 451         expr = strip_expr(expr);
 452 
 453         type = get_type(expr);
 454         if (!type_is_ptr(type))
 455                 return 0;
 456         /*
 457          * There are only three options:
 458          *
 459          * 1) An array address:
 460          *    p = array;
 461          * 2) An address like so:
 462          *    p = &my_struct->member;
 463          * 3) A pointer:
 464          *    p = pointer;
 465          *
 466          */
 467 
 468         if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
 469                 goto found;
 470 
 471         if (type->type == SYM_ARRAY && get_toplevel_mtag(expr->symbol, &tag))


 472                 goto found;
 473 







 474         if (get_implied_mtag_offset(expr, &tag, &offset))
 475                 goto found;
 476 
 477         if (expr->type != EXPR_PREOP || expr->op != '&')
 478                 return 0;
 479         expr = strip_expr(expr->unop);
 480 
 481         if (!expr_to_mtag_offset(expr, &tag, &offset))
 482                 return 0;
 483         if (offset > MTAG_OFFSET_MASK)
 484                 offset = MTAG_OFFSET_MASK;
 485 
 486 found:
 487         sval->type = type;
 488         sval->uvalue = tag | offset;
 489 
 490         return 1;
 491 }
 492 
 493 static struct expression *remove_dereference(struct expression *expr)
 494 {
 495         expr = strip_expr(expr);
 496 
 497         if (expr->type == EXPR_PREOP && expr->op == '*')
 498                 return strip_expr(expr->unop);
 499         return preop_expression(expr, '&');
 500 }
 501 
 502 int get_mtag_addr_sval(struct expression *expr, sval_t *sval)
 503 {
 504         return get_mtag_sval(remove_dereference(expr), sval);
 505 }
 506 
 507 static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr)
 508 {
 509         struct sm_state *sm;
 510         char buf[256];
 511         const char *param_name;
 512         int param;
 513 
 514         FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
 515                 if (!sm->state->data)
 516                         continue;
 517 
 518                 param = get_param_num_from_sym(sm->sym);
 519                 if (param < 0)
 520                         continue;
 521                 param_name = get_param_name(sm);
 522                 if (!param_name)
 523                         continue;
 524                 if (strcmp(param_name, "$") == 0)
 525                         continue;
 526 
 527                 snprintf(buf, sizeof(buf), "%lld", *(mtag_t *)sm->state->data);
 528                 sql_insert_return_states(return_id, return_ranges, MEMORY_TAG, param, param_name, buf);
 529         } END_FOR_EACH_SM(sm);
 530 }
 531 
 532 void register_mtag(int id)
 533 {
 534         my_id = id;
 535 
 536 
 537         /*
 538          * The mtag stuff only works on 64 systems because we store the
 539          * information in the pointer itself.
 540          * bit 63   : set for alias mtags
 541          * bit 62-12: mtag hash
 542          * bit 11-0 : offset
 543          *
 544          */
 545         if (bits_in_pointer != 64)
 546                 return;
 547 
 548         add_hook(&global_variable, BASE_HOOK);
 549 
 550         add_function_assign_hook("kmalloc", &alloc_assign, NULL);
 551         add_function_assign_hook("kzalloc", &alloc_assign, NULL);
 552 
 553         select_return_states_hook(BUF_SIZE, &db_returns_buf_size);
 554 
 555         add_hook(&match_call_info, FUNCTION_CALL_HOOK);
 556         select_caller_info_hook(save_caller_info, MEMORY_TAG);
 557         add_split_return_callback(&print_stored_to_mtag);
 558         select_return_states_hook(MEMORY_TAG, db_returns_memory_tag);
 559 }


  33  *
  34  * Another place where we would maybe name the pointer is when they are passed
  35  * to the probe().  Because that's an important pointer, since there is one
  36  * per driver (sort of).
  37  *
  38  * My vision is that you could take a pointer and trace it back to a global.  So
  39  * I'm going to track that pointer_tag - 28 bytes takes you to another pointer
  40  * tag.  You could follow that one back and so on.  Also when we pass a pointer
  41  * to a function that would be recorded as sort of a link or path or something.
  42  *
  43  */
  44 
  45 #include "smatch.h"
  46 #include "smatch_slist.h"
  47 #include "smatch_extra.h"
  48 
  49 #include <openssl/md5.h>
  50 
  51 static int my_id;
  52 














  53 static mtag_t str_to_tag(const char *str)
  54 {
  55         unsigned char c[MD5_DIGEST_LENGTH];
  56         unsigned long long *tag = (unsigned long long *)&c;
  57         MD5_CTX mdContext;
  58         int len;
  59 
  60         len = strlen(str);
  61         MD5_Init(&mdContext);
  62         MD5_Update(&mdContext, str, len);
  63         MD5_Final(c, &mdContext);
  64 
  65         *tag &= ~MTAG_ALIAS_BIT;
  66         *tag &= ~MTAG_OFFSET_MASK;
  67 
  68         return *tag;
  69 }
  70 
  71 const struct {
  72         const char *name;
  73         int size_arg;
  74 } allocator_info[] = {
  75         { "kmalloc", 0 },
  76         { "kzalloc", 0 },
  77         { "devm_kmalloc", 1},
  78         { "devm_kzalloc", 1},
  79 };
  80 
  81 static bool is_mtag_call(struct expression *expr)
  82 {
  83         struct expression *arg;
  84         int i;
  85         sval_t sval;
  86 
  87         if (expr->type != EXPR_CALL ||
  88             expr->fn->type != EXPR_SYMBOL ||
  89             !expr->fn->symbol)
  90                 return false;
  91 
  92         for (i = 0; i < ARRAY_SIZE(allocator_info); i++) {
  93                 if (strcmp(expr->fn->symbol->ident->name, allocator_info[i].name) == 0)
  94                         break;
  95         }
  96         if (i == ARRAY_SIZE(allocator_info))
  97                 return false;
  98 
  99         arg = get_argument_from_call_expr(expr->args, allocator_info[i].size_arg);
 100         if (!get_implied_value(arg, &sval))
 101                 return false;
 102 
 103         return true;
 104 }
 105 
 106 struct smatch_state *swap_mtag_return(struct expression *expr, struct smatch_state *state)
 107 {
 108         struct expression *left, *right;
 109         char *left_name, *right_name;
 110         struct symbol *left_sym;
 111         struct range_list *rl;
 112         char buf[256];
 113         mtag_t tag;
 114         sval_t tag_sval;
 115 
 116         if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
 117                 return state;
 118 
 119         if (!estate_rl(state) || strcmp(state->name, "0,4096-ptr_max") != 0)
 120                 return state;

 121 


 122         left = strip_expr(expr->left);
 123         right = strip_expr(expr->right);


 124 
 125         if (!is_mtag_call(right))
 126                 return state;
 127 
 128         left_name = expr_to_str_sym(left, &left_sym);
 129         if (!left_name || !left_sym)
 130                 return state;
 131         right_name = expr_to_str(right);
 132 
 133         snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
 134                  left_name, right_name);
 135         tag = str_to_tag(buf);
 136         tag_sval.type = estate_type(state);
 137         tag_sval.uvalue = tag;
 138 
 139         rl = rl_filter(estate_rl(state), valid_ptr_rl);
 140         rl = clone_rl(rl);
 141         add_range(&rl, tag_sval, tag_sval);
 142 
 143         sql_insert_mtag_about(tag, left_name, buf);

 144 
 145         free_string(left_name);
 146         free_string(right_name);
 147 
 148         return alloc_estate_rl(rl);
 149 }
 150 
 151 int get_string_mtag(struct expression *expr, mtag_t *tag)
 152 {
 153         mtag_t xor;
 154 
 155         if (expr->type != EXPR_STRING || !expr->string)
 156                 return 0;
 157 
 158         /* I was worried about collisions so I added a xor */
 159         xor = str_to_tag("__smatch string");
 160         *tag = str_to_tag(expr->string->data);
 161         *tag = *tag ^ xor;
 162 
 163         return 1;
 164 }
 165 
 166 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
 167 {
 168         char buf[256];
 169 
 170         if (!sym)
 171                 return 0;
 172 
 173         if (!sym->ident ||
 174             !(sym->ctype.modifiers & MOD_TOPLEVEL))
 175                 return 0;
 176 
 177         snprintf(buf, sizeof(buf), "%s %s",
 178                  (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern",
 179                  sym->ident->name);
 180         *tag = str_to_tag(buf);
 181         return 1;
 182 }
 183 
 184 bool get_symbol_mtag(struct symbol *sym, mtag_t *tag)
 185 {
 186         char buf[256];

 187 
 188         if (!sym || !sym->ident)
 189                 return false;





 190 
 191         if (get_toplevel_mtag(sym, tag))
 192                 return true;
 193 
 194         if (get_param_num_from_sym(sym) >= 0)
 195                 return false;

 196 
 197         snprintf(buf, sizeof(buf), "%s %s %s",
 198                  get_filename(), get_function(), sym->ident->name);
 199         *tag = str_to_tag(buf);
 200         return true;

 201 }
 202 
 203 static void global_variable(struct symbol *sym)
 204 {
 205         mtag_t tag;
 206 
 207         if (!get_toplevel_mtag(sym, &tag))
 208                 return;
 209 
 210         sql_insert_mtag_about(tag,
 211                               sym->ident->name,
 212                               (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
 213 }
 214 












































































 215 static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
 216 {
 217         struct expression *array, *offset_expr;
 218         struct symbol *type;
 219         sval_t sval;
 220         int start_offset;
 221 
 222         if (!is_array(expr))
 223                 return 0;
 224 
 225         array = get_array_base(expr);
 226         if (!array)
 227                 return 0;
 228         type = get_type(array);
 229         if (!type || type->type != SYM_ARRAY)
 230                 return 0;
 231         type = get_real_base_type(type);
 232         if (!type_bytes(type))
 233                 return 0;
 234 
 235         if (!expr_to_mtag_offset(array, tag, &start_offset))
 236                 return 0;
 237 
 238         offset_expr = get_array_offset(expr);
 239         if (!get_value(offset_expr, &sval))
 240                 return 0;
 241         *offset = start_offset + sval.value * type_bytes(type);
 242 
 243         return 1;
 244 }
 245 
 246 struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl)
 247 {
 248         char buf[256];
 249         char *name;
 250         sval_t sval;
 251         mtag_t tag;
 252 
 253         if (!rl_to_sval(rl, &sval))
 254                 return rl;
 255         if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED)
 256                 return rl;


 257 
 258         name = expr_to_str(expr);
 259         snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name);
 260         free_string(name);
 261         tag = str_to_tag(buf);
 262         sval.value = tag;
 263         return alloc_rl(sval, sval);
 264 }
 265 










































































 266 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
 267 {
 268         char buf[256];
 269         int lines_from_start;
 270         char *str;
 271 
 272         /*
 273          * We need the alias to be unique.  It's not totally required that it
 274          * be the same from one DB build to then next, but it makes debugging
 275          * a bit simpler.
 276          *
 277          */
 278 
 279         if (!cur_func_sym)
 280                 return 0;
 281 
 282         lines_from_start = expr->pos.line - cur_func_sym->pos.line;
 283         str = expr_to_str(expr);
 284         snprintf(buf, sizeof(buf), "%lld %d %s", tag, lines_from_start, str);
 285         free_string(str);
 286 
 287         *new = str_to_tag(buf);
 288         sql_insert_mtag_alias(tag, *new);
 289 
 290         return 1;
 291 }
 292 
 293 static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
 294 {
 295         struct smatch_state *state;
 296         struct symbol *type;
 297         sval_t sval;
 298 
 299         type = get_type(expr);
 300         if (!type_is_ptr(type))
 301                 return 0;
 302         state = get_extra_state(expr);
 303         if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
 304                 return 0;
 305 
 306         *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
 307         *offset = sval.uvalue & MTAG_OFFSET_MASK;
 308         return 1;
 309 }
 310 
 311 /*
 312  * The point of this function is to give you the mtag and the offset so
 313  * you can look up the data in the DB.  It takes an expression.
 314  *
 315  * So say you give it "foo->bar".  Then it would give you the offset of "bar"
 316  * and the implied value of "foo".  Or if you lookup "*foo" then the offset is
 317  * zero and we look up the implied value of "foo.  But if the expression is
 318  * foo, then if "foo" is a global variable, then we get the mtag and the offset
 319  * is zero.  If "foo" is a local variable, then there is nothing to look up in
 320  * the mtag_data table because that's handled by smatch_extra.c to this returns
 321  * false.
 322  *
 323  */
 324 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
 325 {
 326         *tag = 0;
 327         *offset = 0;
 328 
 329         if (bits_in_pointer != 64)
 330                 return 0;
 331 
 332         expr = strip_expr(expr);
 333         if (!expr)
 334                 return 0;
 335 
 336         if (is_array(expr))
 337                 return get_array_mtag_offset(expr, tag, offset);
 338 
 339         if (expr->type == EXPR_PREOP && expr->op == '*') {
 340                 expr = strip_expr(expr->unop);
 341                 return get_implied_mtag_offset(expr, tag, offset);
 342         } else if (expr->type == EXPR_DEREF) {
 343                 int tmp, tmp_offset = 0;
 344 
 345                 while (expr->type == EXPR_DEREF) {
 346                         tmp = get_member_offset_from_deref(expr);
 347                         if (tmp < 0)
 348                                 return 0;
 349                         tmp_offset += tmp;
 350                         expr = expr->deref;
 351                 }
 352                 *offset = tmp_offset;
 353                 if (expr->type == EXPR_PREOP && expr->op == '*') {
 354                         expr = strip_expr(expr->unop);
 355 
 356                         if (get_implied_mtag_offset(expr, tag, &tmp_offset)) {
 357                                 // FIXME:  look it up recursively?
 358                                 if (tmp_offset)
 359                                         return 0;
 360                                 return 1;
 361                         }
 362                         return 0;
 363                 } else if (expr->type == EXPR_SYMBOL) {
 364                         return get_symbol_mtag(expr->symbol, tag);
 365                 }
 366                 return 0;
 367         } else if (expr->type == EXPR_SYMBOL) {
 368                 return get_symbol_mtag(expr->symbol, tag);
 369         }
 370         return 0;
 371 }
 372 
 373 /*
 374  * This function takes an address and returns an sval.  Let's take some
 375  * example things you might pass to it:
 376  * foo->bar:
 377  *   If we were only called from smatch_math, we wouldn't need to bother with
 378  *   this because it's already been looked up in smatch_extra.c but this is
 379  *   also called from other places so we have to check smatch_extra.c.
 380  * &foo
 381  *   If "foo" is global return the mtag for "foo".
 382  * &foo.bar
 383  *   If "foo" is global return the mtag for "foo" + the offset of ".bar".
 384  * It also handles string literals.
 385  *
 386  */
 387 int get_mtag_sval(struct expression *expr, sval_t *sval)
 388 {
 389         struct symbol *type;
 390         mtag_t tag;
 391         int offset = 0;
 392 
 393         if (bits_in_pointer != 64)
 394                 return 0;
 395 
 396         expr = strip_expr(expr);
 397 
 398         type = get_type(expr);
 399         if (!type_is_ptr(type))
 400                 return 0;
 401         /*
 402          * There are several options:
 403          *
 404          * If the expr is a string literal, that's an address/mtag.
 405          * SYM_ARRAY and SYM_FN are mtags.  There are "&foo" type addresses.
 406          * And there are saved pointers "p = &foo;"



 407          *
 408          */
 409 
 410         if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
 411                 goto found;
 412 
 413         if (expr->type == EXPR_SYMBOL &&
 414             (type->type == SYM_ARRAY || type->type == SYM_FN) &&
 415             get_toplevel_mtag(expr->symbol, &tag))
 416                 goto found;
 417 
 418         if (expr->type == EXPR_PREOP && expr->op == '&') {
 419                 expr = strip_expr(expr->unop);
 420                 if (expr_to_mtag_offset(expr, &tag, &offset))
 421                         goto found;
 422                 return 0;
 423         }
 424 
 425         if (get_implied_mtag_offset(expr, &tag, &offset))
 426                 goto found;
 427 

 428         return 0;
 429 found:
 430         if (offset >= MTAG_OFFSET_MASK)

 431                 return 0;


 432 

 433         sval->type = type;
 434         sval->uvalue = tag | offset;
 435 
 436         return 1;
 437 }
 438 







































 439 void register_mtag(int id)
 440 {
 441         my_id = id;
 442 
 443 
 444         /*
 445          * The mtag stuff only works on 64 systems because we store the
 446          * information in the pointer itself.
 447          * bit 63   : set for alias mtags
 448          * bit 62-12: mtag hash
 449          * bit 11-0 : offset
 450          *
 451          */


 452 
 453         add_hook(&global_variable, BASE_HOOK);










 454 }