11f5207b7SJohn Levon /* 21f5207b7SJohn Levon * Copyright (C) 2013 Oracle. 31f5207b7SJohn Levon * 41f5207b7SJohn Levon * This program is free software; you can redistribute it and/or 51f5207b7SJohn Levon * modify it under the terms of the GNU General Public License 61f5207b7SJohn Levon * as published by the Free Software Foundation; either version 2 71f5207b7SJohn Levon * of the License, or (at your option) any later version. 81f5207b7SJohn Levon * 91f5207b7SJohn Levon * This program is distributed in the hope that it will be useful, 101f5207b7SJohn Levon * but WITHOUT ANY WARRANTY; without even the implied warranty of 111f5207b7SJohn Levon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121f5207b7SJohn Levon * GNU General Public License for more details. 131f5207b7SJohn Levon * 141f5207b7SJohn Levon * You should have received a copy of the GNU General Public License 151f5207b7SJohn Levon * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 161f5207b7SJohn Levon */ 171f5207b7SJohn Levon 181f5207b7SJohn Levon /* 191f5207b7SJohn Levon * The plan here is to save all the possible values store to a given struct 201f5207b7SJohn Levon * member. 211f5207b7SJohn Levon * 221f5207b7SJohn Levon * We will load all the values in to the function_type_val table first then 231f5207b7SJohn Levon * run a script on that and load all the resulting values into the type_val 241f5207b7SJohn Levon * table. 251f5207b7SJohn Levon * 261f5207b7SJohn Levon * So in this file we want to take the union of everything assigned to the 271f5207b7SJohn Levon * struct member and insert it into the function_type_val at the end. 281f5207b7SJohn Levon * 291f5207b7SJohn Levon * You would think that we could use smatch_modification_hooks.c or 301f5207b7SJohn Levon * extra_modification_hook() here to get the information here but in the end we 311f5207b7SJohn Levon * need to code everything again a third time. 321f5207b7SJohn Levon * 331f5207b7SJohn Levon */ 341f5207b7SJohn Levon 351f5207b7SJohn Levon #include "smatch.h" 361f5207b7SJohn Levon #include "smatch_slist.h" 371f5207b7SJohn Levon #include "smatch_extra.h" 381f5207b7SJohn Levon 391f5207b7SJohn Levon static int my_id; 401f5207b7SJohn Levon 411f5207b7SJohn Levon struct stree_stack *fn_type_val_stack; 421f5207b7SJohn Levon struct stree *fn_type_val; 431f5207b7SJohn Levon struct stree *global_type_val; 441f5207b7SJohn Levon 451f5207b7SJohn Levon static int get_vals(void *_db_vals, int argc, char **argv, char **azColName) 461f5207b7SJohn Levon { 471f5207b7SJohn Levon char **db_vals = _db_vals; 481f5207b7SJohn Levon 491f5207b7SJohn Levon *db_vals = alloc_string(argv[0]); 501f5207b7SJohn Levon return 0; 511f5207b7SJohn Levon } 521f5207b7SJohn Levon 531f5207b7SJohn Levon static void match_inline_start(struct expression *expr) 541f5207b7SJohn Levon { 551f5207b7SJohn Levon push_stree(&fn_type_val_stack, fn_type_val); 561f5207b7SJohn Levon fn_type_val = NULL; 571f5207b7SJohn Levon } 581f5207b7SJohn Levon 591f5207b7SJohn Levon static void match_inline_end(struct expression *expr) 601f5207b7SJohn Levon { 611f5207b7SJohn Levon free_stree(&fn_type_val); 621f5207b7SJohn Levon fn_type_val = pop_stree(&fn_type_val_stack); 631f5207b7SJohn Levon } 641f5207b7SJohn Levon 651f5207b7SJohn Levon struct expr_rl { 661f5207b7SJohn Levon struct expression *expr; 671f5207b7SJohn Levon struct range_list *rl; 681f5207b7SJohn Levon }; 691f5207b7SJohn Levon static struct expr_rl cached_results[10]; 701f5207b7SJohn Levon static int res_idx; 711f5207b7SJohn Levon 721f5207b7SJohn Levon static int get_cached(struct expression *expr, struct range_list **rl, int *ret) 731f5207b7SJohn Levon { 741f5207b7SJohn Levon int i; 751f5207b7SJohn Levon 761f5207b7SJohn Levon *ret = 0; 771f5207b7SJohn Levon 781f5207b7SJohn Levon for (i = 0; i < ARRAY_SIZE(cached_results); i++) { 791f5207b7SJohn Levon if (expr == cached_results[i].expr) { 801f5207b7SJohn Levon if (cached_results[i].rl) { 811f5207b7SJohn Levon *rl = clone_rl(cached_results[i].rl); 821f5207b7SJohn Levon *ret = 1; 831f5207b7SJohn Levon } 841f5207b7SJohn Levon return 1; 851f5207b7SJohn Levon } 861f5207b7SJohn Levon } 871f5207b7SJohn Levon 881f5207b7SJohn Levon return 0; 891f5207b7SJohn Levon } 901f5207b7SJohn Levon 911f5207b7SJohn Levon int get_db_type_rl(struct expression *expr, struct range_list **rl) 921f5207b7SJohn Levon { 931f5207b7SJohn Levon char *db_vals = NULL; 941f5207b7SJohn Levon char *member; 951f5207b7SJohn Levon struct range_list *tmp; 961f5207b7SJohn Levon struct symbol *type; 971f5207b7SJohn Levon int ret; 981f5207b7SJohn Levon 991f5207b7SJohn Levon if (get_cached(expr, rl, &ret)) 1001f5207b7SJohn Levon return ret; 1011f5207b7SJohn Levon 1021f5207b7SJohn Levon member = get_member_name(expr); 1031f5207b7SJohn Levon if (!member) 1041f5207b7SJohn Levon return 0; 1051f5207b7SJohn Levon 1061f5207b7SJohn Levon res_idx = (res_idx + 1) % ARRAY_SIZE(cached_results); 1071f5207b7SJohn Levon cached_results[res_idx].expr = expr; 1081f5207b7SJohn Levon cached_results[res_idx].rl = NULL; 1091f5207b7SJohn Levon 1101f5207b7SJohn Levon run_sql(get_vals, &db_vals, 1111f5207b7SJohn Levon "select value from type_value where type = '%s';", member); 1121f5207b7SJohn Levon free_string(member); 1131f5207b7SJohn Levon if (!db_vals) 1141f5207b7SJohn Levon return 0; 1151f5207b7SJohn Levon type = get_type(expr); 1161f5207b7SJohn Levon str_to_rl(type, db_vals, &tmp); 1171f5207b7SJohn Levon free_string(db_vals); 1181f5207b7SJohn Levon if (is_whole_rl(tmp)) 1191f5207b7SJohn Levon return 0; 1201f5207b7SJohn Levon 1211f5207b7SJohn Levon *rl = tmp; 1221f5207b7SJohn Levon cached_results[res_idx].rl = clone_rl(tmp); 1231f5207b7SJohn Levon 1241f5207b7SJohn Levon return 1; 1251f5207b7SJohn Levon } 1261f5207b7SJohn Levon 1271f5207b7SJohn Levon static void add_type_val(char *member, struct range_list *rl) 1281f5207b7SJohn Levon { 1291f5207b7SJohn Levon struct smatch_state *old, *add, *new; 1301f5207b7SJohn Levon 1311f5207b7SJohn Levon member = alloc_string(member); 1321f5207b7SJohn Levon old = get_state_stree(fn_type_val, my_id, member, NULL); 1331f5207b7SJohn Levon add = alloc_estate_rl(rl); 1341f5207b7SJohn Levon if (old) 1351f5207b7SJohn Levon new = merge_estates(old, add); 1361f5207b7SJohn Levon else 1371f5207b7SJohn Levon new = add; 1381f5207b7SJohn Levon set_state_stree(&fn_type_val, my_id, member, NULL, new); 1391f5207b7SJohn Levon } 1401f5207b7SJohn Levon 1411f5207b7SJohn Levon static void add_fake_type_val(char *member, struct range_list *rl, int ignore) 1421f5207b7SJohn Levon { 1431f5207b7SJohn Levon struct smatch_state *old, *add, *new; 1441f5207b7SJohn Levon 1451f5207b7SJohn Levon member = alloc_string(member); 1461f5207b7SJohn Levon old = get_state_stree(fn_type_val, my_id, member, NULL); 1471f5207b7SJohn Levon if (old && strcmp(old->name, "min-max") == 0) 1481f5207b7SJohn Levon return; 1491f5207b7SJohn Levon if (ignore && old && strcmp(old->name, "ignore") == 0) 1501f5207b7SJohn Levon return; 1511f5207b7SJohn Levon add = alloc_estate_rl(rl); 1521f5207b7SJohn Levon if (old) { 1531f5207b7SJohn Levon new = merge_estates(old, add); 1541f5207b7SJohn Levon } else { 1551f5207b7SJohn Levon new = add; 1561f5207b7SJohn Levon if (ignore) 1571f5207b7SJohn Levon new->name = alloc_string("ignore"); 1581f5207b7SJohn Levon else 1591f5207b7SJohn Levon new->name = alloc_string("min-max"); 1601f5207b7SJohn Levon } 1611f5207b7SJohn Levon set_state_stree(&fn_type_val, my_id, member, NULL, new); 1621f5207b7SJohn Levon } 1631f5207b7SJohn Levon 1641f5207b7SJohn Levon static void add_global_type_val(char *member, struct range_list *rl) 1651f5207b7SJohn Levon { 1661f5207b7SJohn Levon struct smatch_state *old, *add, *new; 1671f5207b7SJohn Levon 1681f5207b7SJohn Levon member = alloc_string(member); 1691f5207b7SJohn Levon old = get_state_stree(global_type_val, my_id, member, NULL); 1701f5207b7SJohn Levon add = alloc_estate_rl(rl); 1711f5207b7SJohn Levon if (old) 1721f5207b7SJohn Levon new = merge_estates(old, add); 1731f5207b7SJohn Levon else 1741f5207b7SJohn Levon new = add; 1751f5207b7SJohn Levon new = clone_estate_perm(new); 1761f5207b7SJohn Levon set_state_stree_perm(&global_type_val, my_id, member, NULL, new); 1771f5207b7SJohn Levon } 1781f5207b7SJohn Levon 1791f5207b7SJohn Levon static int has_link_cb(void *has_link, int argc, char **argv, char **azColName) 1801f5207b7SJohn Levon { 1811f5207b7SJohn Levon *(int *)has_link = 1; 1821f5207b7SJohn Levon return 0; 1831f5207b7SJohn Levon } 1841f5207b7SJohn Levon 1851f5207b7SJohn Levon static int is_ignored_fake_assignment(void) 1861f5207b7SJohn Levon { 1871f5207b7SJohn Levon struct expression *expr; 1881f5207b7SJohn Levon struct symbol *type; 1891f5207b7SJohn Levon char *member_name; 1901f5207b7SJohn Levon int has_link = 0; 1911f5207b7SJohn Levon 1921f5207b7SJohn Levon expr = get_faked_expression(); 1931f5207b7SJohn Levon if (!expr || expr->type != EXPR_ASSIGNMENT) 1941f5207b7SJohn Levon return 0; 1951f5207b7SJohn Levon if (!is_void_pointer(expr->right)) 1961f5207b7SJohn Levon return 0; 1971f5207b7SJohn Levon member_name = get_member_name(expr->right); 1981f5207b7SJohn Levon if (!member_name) 1991f5207b7SJohn Levon return 0; 2001f5207b7SJohn Levon 2011f5207b7SJohn Levon type = get_type(expr->left); 2021f5207b7SJohn Levon if (!type || type->type != SYM_PTR) 2031f5207b7SJohn Levon return 0; 2041f5207b7SJohn Levon type = get_real_base_type(type); 2051f5207b7SJohn Levon if (!type || type->type != SYM_STRUCT) 2061f5207b7SJohn Levon return 0; 2071f5207b7SJohn Levon 2081f5207b7SJohn Levon run_sql(has_link_cb, &has_link, 2091f5207b7SJohn Levon "select * from data_info where type = %d and data = '%s' and value = '%s';", 2101f5207b7SJohn Levon TYPE_LINK, member_name, type_to_str(type)); 2111f5207b7SJohn Levon return has_link; 2121f5207b7SJohn Levon } 2131f5207b7SJohn Levon 2141f5207b7SJohn Levon static int is_container_of(void) 2151f5207b7SJohn Levon { 2161f5207b7SJohn Levon /* We already check the macro name in is_ignored_macro() */ 2171f5207b7SJohn Levon struct expression *expr; 2181f5207b7SJohn Levon int offset; 2191f5207b7SJohn Levon 2201f5207b7SJohn Levon expr = get_faked_expression(); 2211f5207b7SJohn Levon if (!expr || expr->type != EXPR_ASSIGNMENT) 2221f5207b7SJohn Levon return 0; 2231f5207b7SJohn Levon 2241f5207b7SJohn Levon offset = get_offset_from_container_of(expr->right); 2251f5207b7SJohn Levon if (offset < 0) 2261f5207b7SJohn Levon return 0; 2271f5207b7SJohn Levon return 1; 2281f5207b7SJohn Levon } 2291f5207b7SJohn Levon 230*c85f09ccSJohn Levon static bool is_driver_data(void) 2311f5207b7SJohn Levon { 232*c85f09ccSJohn Levon static struct expression *prev_expr; 2331f5207b7SJohn Levon struct expression *expr; 2341f5207b7SJohn Levon char *name; 235*c85f09ccSJohn Levon static bool prev_ret; 236*c85f09ccSJohn Levon bool ret = false; 2371f5207b7SJohn Levon 2381f5207b7SJohn Levon expr = get_faked_expression(); 2391f5207b7SJohn Levon if (!expr || expr->type != EXPR_ASSIGNMENT) 240*c85f09ccSJohn Levon return false; 241*c85f09ccSJohn Levon 242*c85f09ccSJohn Levon if (expr == prev_expr) 243*c85f09ccSJohn Levon return prev_ret; 244*c85f09ccSJohn Levon prev_expr = expr; 245*c85f09ccSJohn Levon 246*c85f09ccSJohn Levon name = expr_to_str(expr->right); 247*c85f09ccSJohn Levon if (!name) { 248*c85f09ccSJohn Levon prev_ret = false; 249*c85f09ccSJohn Levon return false; 250*c85f09ccSJohn Levon } 251*c85f09ccSJohn Levon 252*c85f09ccSJohn Levon if (strstr(name, "get_drvdata(") || 253*c85f09ccSJohn Levon strstr(name, "dev.driver_data") || 254*c85f09ccSJohn Levon strstr(name, "dev->driver_data")) 255*c85f09ccSJohn Levon ret = true; 256*c85f09ccSJohn Levon 257*c85f09ccSJohn Levon free_string(name); 258*c85f09ccSJohn Levon 259*c85f09ccSJohn Levon prev_ret = ret; 260*c85f09ccSJohn Levon return ret; 261*c85f09ccSJohn Levon } 262*c85f09ccSJohn Levon 263*c85f09ccSJohn Levon static int is_ignored_macro(void) 264*c85f09ccSJohn Levon { 265*c85f09ccSJohn Levon struct expression *expr; 266*c85f09ccSJohn Levon char *name; 267*c85f09ccSJohn Levon 268*c85f09ccSJohn Levon expr = get_faked_expression(); 269*c85f09ccSJohn Levon if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=') 2701f5207b7SJohn Levon return 0; 2711f5207b7SJohn Levon name = get_macro_name(expr->right->pos); 2721f5207b7SJohn Levon if (!name) 2731f5207b7SJohn Levon return 0; 2741f5207b7SJohn Levon if (strcmp(name, "container_of") == 0) 2751f5207b7SJohn Levon return 1; 2761f5207b7SJohn Levon if (strcmp(name, "rb_entry") == 0) 2771f5207b7SJohn Levon return 1; 2781f5207b7SJohn Levon if (strcmp(name, "list_entry") == 0) 2791f5207b7SJohn Levon return 1; 2801f5207b7SJohn Levon if (strcmp(name, "list_first_entry") == 0) 2811f5207b7SJohn Levon return 1; 2821f5207b7SJohn Levon if (strcmp(name, "hlist_entry") == 0) 2831f5207b7SJohn Levon return 1; 284*c85f09ccSJohn Levon if (strcmp(name, "per_cpu_ptr") == 0) 285*c85f09ccSJohn Levon return 1; 286*c85f09ccSJohn Levon if (strcmp(name, "raw_cpu_ptr") == 0) 287*c85f09ccSJohn Levon return 1; 288*c85f09ccSJohn Levon if (strcmp(name, "this_cpu_ptr") == 0) 289*c85f09ccSJohn Levon return 1; 290*c85f09ccSJohn Levon 291*c85f09ccSJohn Levon if (strcmp(name, "TRACE_EVENT") == 0) 292*c85f09ccSJohn Levon return 1; 293*c85f09ccSJohn Levon if (strcmp(name, "DECLARE_EVENT_CLASS") == 0) 294*c85f09ccSJohn Levon return 1; 295*c85f09ccSJohn Levon if (strcmp(name, "DEFINE_EVENT") == 0) 296*c85f09ccSJohn Levon return 1; 297*c85f09ccSJohn Levon 2981f5207b7SJohn Levon if (strstr(name, "for_each")) 2991f5207b7SJohn Levon return 1; 3001f5207b7SJohn Levon return 0; 3011f5207b7SJohn Levon } 3021f5207b7SJohn Levon 3031f5207b7SJohn Levon static int is_ignored_function(void) 3041f5207b7SJohn Levon { 3051f5207b7SJohn Levon struct expression *expr; 3061f5207b7SJohn Levon 3071f5207b7SJohn Levon expr = get_faked_expression(); 3081f5207b7SJohn Levon if (!expr || expr->type != EXPR_ASSIGNMENT) 3091f5207b7SJohn Levon return 0; 3101f5207b7SJohn Levon expr = strip_expr(expr->right); 3111f5207b7SJohn Levon if (!expr || expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL) 3121f5207b7SJohn Levon return 0; 3131f5207b7SJohn Levon 3141f5207b7SJohn Levon if (sym_name_is("kmalloc", expr->fn)) 3151f5207b7SJohn Levon return 1; 316*c85f09ccSJohn Levon if (sym_name_is("vmalloc", expr->fn)) 317*c85f09ccSJohn Levon return 1; 318*c85f09ccSJohn Levon if (sym_name_is("kvmalloc", expr->fn)) 319*c85f09ccSJohn Levon return 1; 320*c85f09ccSJohn Levon if (sym_name_is("kmalloc_array", expr->fn)) 321*c85f09ccSJohn Levon return 1; 322*c85f09ccSJohn Levon if (sym_name_is("vmalloc_array", expr->fn)) 323*c85f09ccSJohn Levon return 1; 324*c85f09ccSJohn Levon if (sym_name_is("kvmalloc_array", expr->fn)) 325*c85f09ccSJohn Levon return 1; 326*c85f09ccSJohn Levon 327*c85f09ccSJohn Levon if (sym_name_is("mmu_memory_cache_alloc", expr->fn)) 328*c85f09ccSJohn Levon return 1; 329*c85f09ccSJohn Levon if (sym_name_is("kmem_alloc", expr->fn)) 330*c85f09ccSJohn Levon return 1; 331*c85f09ccSJohn Levon if (sym_name_is("alloc_pages", expr->fn)) 332*c85f09ccSJohn Levon return 1; 333*c85f09ccSJohn Levon 3341f5207b7SJohn Levon if (sym_name_is("netdev_priv", expr->fn)) 3351f5207b7SJohn Levon return 1; 3361f5207b7SJohn Levon if (sym_name_is("dev_get_drvdata", expr->fn)) 3371f5207b7SJohn Levon return 1; 338*c85f09ccSJohn Levon if (sym_name_is("i2c_get_clientdata", expr->fn)) 339*c85f09ccSJohn Levon return 1; 3401f5207b7SJohn Levon 3411f5207b7SJohn Levon return 0; 3421f5207b7SJohn Levon } 3431f5207b7SJohn Levon 3441f5207b7SJohn Levon static int is_uncasted_pointer_assign(void) 3451f5207b7SJohn Levon { 3461f5207b7SJohn Levon struct expression *expr; 3471f5207b7SJohn Levon struct symbol *left_type, *right_type; 3481f5207b7SJohn Levon 3491f5207b7SJohn Levon expr = get_faked_expression(); 3501f5207b7SJohn Levon if (!expr) 3511f5207b7SJohn Levon return 0; 3521f5207b7SJohn Levon if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) { 3531f5207b7SJohn Levon if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT) 3541f5207b7SJohn Levon return 1; 3551f5207b7SJohn Levon } 3561f5207b7SJohn Levon if (expr->type != EXPR_ASSIGNMENT) 3571f5207b7SJohn Levon return 0; 3581f5207b7SJohn Levon left_type = get_type(expr->left); 3591f5207b7SJohn Levon right_type = get_type(expr->right); 3601f5207b7SJohn Levon 3611f5207b7SJohn Levon if (!left_type || !right_type) 3621f5207b7SJohn Levon return 0; 3631f5207b7SJohn Levon 364*c85f09ccSJohn Levon if (left_type->type == SYM_STRUCT && left_type == right_type) 365*c85f09ccSJohn Levon return 1; 366*c85f09ccSJohn Levon 3671f5207b7SJohn Levon if (left_type->type != SYM_PTR && 3681f5207b7SJohn Levon left_type->type != SYM_ARRAY) 3691f5207b7SJohn Levon return 0; 3701f5207b7SJohn Levon if (right_type->type != SYM_PTR && 3711f5207b7SJohn Levon right_type->type != SYM_ARRAY) 3721f5207b7SJohn Levon return 0; 3731f5207b7SJohn Levon left_type = get_real_base_type(left_type); 3741f5207b7SJohn Levon right_type = get_real_base_type(right_type); 3751f5207b7SJohn Levon 3761f5207b7SJohn Levon if (left_type == right_type) 3771f5207b7SJohn Levon return 1; 3781f5207b7SJohn Levon return 0; 3791f5207b7SJohn Levon } 3801f5207b7SJohn Levon 3811f5207b7SJohn Levon static int set_param_type(void *_type_str, int argc, char **argv, char **azColName) 3821f5207b7SJohn Levon { 3831f5207b7SJohn Levon char **type_str = _type_str; 3841f5207b7SJohn Levon static char type_buf[128]; 3851f5207b7SJohn Levon 3861f5207b7SJohn Levon if (*type_str) { 3871f5207b7SJohn Levon if (strcmp(*type_str, argv[0]) == 0) 3881f5207b7SJohn Levon return 0; 3891f5207b7SJohn Levon strncpy(type_buf, "unknown", sizeof(type_buf)); 3901f5207b7SJohn Levon return 0; 3911f5207b7SJohn Levon } 3921f5207b7SJohn Levon strncpy(type_buf, argv[0], sizeof(type_buf)); 3931f5207b7SJohn Levon *type_str = type_buf; 3941f5207b7SJohn Levon 3951f5207b7SJohn Levon return 0; 3961f5207b7SJohn Levon } 3971f5207b7SJohn Levon 3981f5207b7SJohn Levon static char *db_get_parameter_type(int param) 3991f5207b7SJohn Levon { 4001f5207b7SJohn Levon char *ret = NULL; 4011f5207b7SJohn Levon 4021f5207b7SJohn Levon if (!cur_func_sym) 4031f5207b7SJohn Levon return NULL; 4041f5207b7SJohn Levon 4051f5207b7SJohn Levon run_sql(set_param_type, &ret, 4061f5207b7SJohn Levon "select value from fn_data_link where " 4071f5207b7SJohn Levon "file = '%s' and function = '%s' and static = %d and type = %d and parameter = %d and key = '$';", 4081f5207b7SJohn Levon (cur_func_sym->ctype.modifiers & MOD_STATIC) ? get_base_file() : "extern", 4091f5207b7SJohn Levon cur_func_sym->ident->name, 4101f5207b7SJohn Levon !!(cur_func_sym->ctype.modifiers & MOD_STATIC), 4111f5207b7SJohn Levon PASSES_TYPE, param); 4121f5207b7SJohn Levon 4131f5207b7SJohn Levon return ret; 4141f5207b7SJohn Levon } 4151f5207b7SJohn Levon 4161f5207b7SJohn Levon static int is_uncasted_fn_param_from_db(void) 4171f5207b7SJohn Levon { 4181f5207b7SJohn Levon struct expression *expr, *right; 4191f5207b7SJohn Levon struct symbol *left_type; 4201f5207b7SJohn Levon char left_type_name[128]; 4211f5207b7SJohn Levon int param; 4221f5207b7SJohn Levon char *right_type_name; 4231f5207b7SJohn Levon static struct expression *prev_expr; 4241f5207b7SJohn Levon static int prev_ans; 4251f5207b7SJohn Levon 4261f5207b7SJohn Levon expr = get_faked_expression(); 4271f5207b7SJohn Levon 4281f5207b7SJohn Levon if (expr == prev_expr) 4291f5207b7SJohn Levon return prev_ans; 4301f5207b7SJohn Levon prev_expr = expr; 4311f5207b7SJohn Levon prev_ans = 0; 4321f5207b7SJohn Levon 4331f5207b7SJohn Levon if (!expr || expr->type != EXPR_ASSIGNMENT) 4341f5207b7SJohn Levon return 0; 4351f5207b7SJohn Levon left_type = get_type(expr->left); 4361f5207b7SJohn Levon if (!left_type || left_type->type != SYM_PTR) 4371f5207b7SJohn Levon return 0; 4381f5207b7SJohn Levon left_type = get_real_base_type(left_type); 4391f5207b7SJohn Levon if (!left_type || left_type->type != SYM_STRUCT) 4401f5207b7SJohn Levon return 0; 4411f5207b7SJohn Levon snprintf(left_type_name, sizeof(left_type_name), "%s", type_to_str(left_type)); 4421f5207b7SJohn Levon 4431f5207b7SJohn Levon right = strip_expr(expr->right); 4441f5207b7SJohn Levon param = get_param_num(right); 4451f5207b7SJohn Levon if (param < 0) 4461f5207b7SJohn Levon return 0; 4471f5207b7SJohn Levon right_type_name = db_get_parameter_type(param); 4481f5207b7SJohn Levon if (!right_type_name) 4491f5207b7SJohn Levon return 0; 4501f5207b7SJohn Levon 4511f5207b7SJohn Levon if (strcmp(right_type_name, left_type_name) == 0) { 4521f5207b7SJohn Levon prev_ans = 1; 4531f5207b7SJohn Levon return 1; 4541f5207b7SJohn Levon } 4551f5207b7SJohn Levon 4561f5207b7SJohn Levon return 0; 4571f5207b7SJohn Levon } 4581f5207b7SJohn Levon 4591f5207b7SJohn Levon static void match_assign_value(struct expression *expr) 4601f5207b7SJohn Levon { 4611f5207b7SJohn Levon char *member, *right_member; 4621f5207b7SJohn Levon struct range_list *rl; 4631f5207b7SJohn Levon struct symbol *type; 4641f5207b7SJohn Levon 4651f5207b7SJohn Levon if (!cur_func_sym) 4661f5207b7SJohn Levon return; 4671f5207b7SJohn Levon 4681f5207b7SJohn Levon type = get_type(expr->left); 469*c85f09ccSJohn Levon if (type && type->type == SYM_STRUCT) 470*c85f09ccSJohn Levon return; 4711f5207b7SJohn Levon member = get_member_name(expr->left); 4721f5207b7SJohn Levon if (!member) 4731f5207b7SJohn Levon return; 4741f5207b7SJohn Levon 4751f5207b7SJohn Levon /* if we're saying foo->mtu = bar->mtu then that doesn't add information */ 4761f5207b7SJohn Levon right_member = get_member_name(expr->right); 4771f5207b7SJohn Levon if (right_member && strcmp(right_member, member) == 0) 4781f5207b7SJohn Levon goto free; 4791f5207b7SJohn Levon 4801f5207b7SJohn Levon if (is_fake_call(expr->right)) { 4811f5207b7SJohn Levon if (is_ignored_macro()) 4821f5207b7SJohn Levon goto free; 4831f5207b7SJohn Levon if (is_ignored_function()) 4841f5207b7SJohn Levon goto free; 4851f5207b7SJohn Levon if (is_uncasted_pointer_assign()) 4861f5207b7SJohn Levon goto free; 4871f5207b7SJohn Levon if (is_uncasted_fn_param_from_db()) 4881f5207b7SJohn Levon goto free; 4891f5207b7SJohn Levon if (is_container_of()) 4901f5207b7SJohn Levon goto free; 491*c85f09ccSJohn Levon if (is_driver_data()) 492*c85f09ccSJohn Levon goto free; 4931f5207b7SJohn Levon add_fake_type_val(member, alloc_whole_rl(get_type(expr->left)), is_ignored_fake_assignment()); 4941f5207b7SJohn Levon goto free; 4951f5207b7SJohn Levon } 4961f5207b7SJohn Levon 4971f5207b7SJohn Levon if (expr->op == '=') { 4981f5207b7SJohn Levon get_absolute_rl(expr->right, &rl); 4991f5207b7SJohn Levon rl = cast_rl(type, rl); 5001f5207b7SJohn Levon } else { 5011f5207b7SJohn Levon /* 5021f5207b7SJohn Levon * This is a bit cheating. We order it so this will already be set 5031f5207b7SJohn Levon * by smatch_extra.c and we just look up the value. 5041f5207b7SJohn Levon */ 5051f5207b7SJohn Levon get_absolute_rl(expr->left, &rl); 5061f5207b7SJohn Levon } 5071f5207b7SJohn Levon add_type_val(member, rl); 5081f5207b7SJohn Levon free: 5091f5207b7SJohn Levon free_string(right_member); 5101f5207b7SJohn Levon free_string(member); 5111f5207b7SJohn Levon } 5121f5207b7SJohn Levon 5131f5207b7SJohn Levon /* 5141f5207b7SJohn Levon * If we too: int *p = &my_struct->member then abandon all hope of tracking 5151f5207b7SJohn Levon * my_struct->member. 5161f5207b7SJohn Levon */ 5171f5207b7SJohn Levon static void match_assign_pointer(struct expression *expr) 5181f5207b7SJohn Levon { 5191f5207b7SJohn Levon struct expression *right; 5201f5207b7SJohn Levon char *member; 5211f5207b7SJohn Levon struct range_list *rl; 5221f5207b7SJohn Levon struct symbol *type; 5231f5207b7SJohn Levon 5241f5207b7SJohn Levon right = strip_expr(expr->right); 5251f5207b7SJohn Levon if (right->type != EXPR_PREOP || right->op != '&') 5261f5207b7SJohn Levon return; 5271f5207b7SJohn Levon right = strip_expr(right->unop); 5281f5207b7SJohn Levon 5291f5207b7SJohn Levon member = get_member_name(right); 5301f5207b7SJohn Levon if (!member) 5311f5207b7SJohn Levon return; 5321f5207b7SJohn Levon type = get_type(right); 5331f5207b7SJohn Levon rl = alloc_whole_rl(type); 5341f5207b7SJohn Levon add_type_val(member, rl); 5351f5207b7SJohn Levon free_string(member); 5361f5207b7SJohn Levon } 5371f5207b7SJohn Levon 5381f5207b7SJohn Levon static void match_global_assign(struct expression *expr) 5391f5207b7SJohn Levon { 5401f5207b7SJohn Levon char *member; 5411f5207b7SJohn Levon struct range_list *rl; 5421f5207b7SJohn Levon struct symbol *type; 5431f5207b7SJohn Levon 5441f5207b7SJohn Levon type = get_type(expr->left); 5451f5207b7SJohn Levon if (type && (type->type == SYM_ARRAY || type->type == SYM_STRUCT)) 5461f5207b7SJohn Levon return; 5471f5207b7SJohn Levon member = get_member_name(expr->left); 5481f5207b7SJohn Levon if (!member) 5491f5207b7SJohn Levon return; 5501f5207b7SJohn Levon get_absolute_rl(expr->right, &rl); 5511f5207b7SJohn Levon rl = cast_rl(type, rl); 5521f5207b7SJohn Levon add_global_type_val(member, rl); 5531f5207b7SJohn Levon free_string(member); 5541f5207b7SJohn Levon } 5551f5207b7SJohn Levon 5561f5207b7SJohn Levon static void unop_expr(struct expression *expr) 5571f5207b7SJohn Levon { 5581f5207b7SJohn Levon struct range_list *rl; 5591f5207b7SJohn Levon char *member; 5601f5207b7SJohn Levon 5611f5207b7SJohn Levon if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT) 5621f5207b7SJohn Levon return; 5631f5207b7SJohn Levon 5641f5207b7SJohn Levon expr = strip_expr(expr->unop); 5651f5207b7SJohn Levon member = get_member_name(expr); 5661f5207b7SJohn Levon if (!member) 5671f5207b7SJohn Levon return; 5681f5207b7SJohn Levon rl = alloc_whole_rl(get_type(expr)); 5691f5207b7SJohn Levon add_type_val(member, rl); 5701f5207b7SJohn Levon free_string(member); 5711f5207b7SJohn Levon } 5721f5207b7SJohn Levon 5731f5207b7SJohn Levon static void asm_expr(struct statement *stmt) 5741f5207b7SJohn Levon { 5751f5207b7SJohn Levon struct expression *expr; 5761f5207b7SJohn Levon struct range_list *rl; 5771f5207b7SJohn Levon char *member; 5781f5207b7SJohn Levon 5791f5207b7SJohn Levon FOR_EACH_PTR(stmt->asm_outputs, expr) { 580*c85f09ccSJohn Levon member = get_member_name(expr->expr); 581*c85f09ccSJohn Levon if (!member) 5821f5207b7SJohn Levon continue; 583*c85f09ccSJohn Levon rl = alloc_whole_rl(get_type(expr->expr)); 584*c85f09ccSJohn Levon add_type_val(member, rl); 585*c85f09ccSJohn Levon free_string(member); 5861f5207b7SJohn Levon } END_FOR_EACH_PTR(expr); 5871f5207b7SJohn Levon } 5881f5207b7SJohn Levon 5891f5207b7SJohn Levon static void db_param_add(struct expression *expr, int param, char *key, char *value) 5901f5207b7SJohn Levon { 5911f5207b7SJohn Levon struct expression *arg; 5921f5207b7SJohn Levon struct symbol *type; 5931f5207b7SJohn Levon struct range_list *rl; 5941f5207b7SJohn Levon char *member; 5951f5207b7SJohn Levon 5961f5207b7SJohn Levon if (strcmp(key, "*$") != 0) 5971f5207b7SJohn Levon return; 5981f5207b7SJohn Levon 5991f5207b7SJohn Levon while (expr->type == EXPR_ASSIGNMENT) 6001f5207b7SJohn Levon expr = strip_expr(expr->right); 6011f5207b7SJohn Levon if (expr->type != EXPR_CALL) 6021f5207b7SJohn Levon return; 6031f5207b7SJohn Levon 6041f5207b7SJohn Levon arg = get_argument_from_call_expr(expr->args, param); 6051f5207b7SJohn Levon arg = strip_expr(arg); 6061f5207b7SJohn Levon if (!arg) 6071f5207b7SJohn Levon return; 6081f5207b7SJohn Levon type = get_member_type_from_key(arg, key); 609*c85f09ccSJohn Levon /* 610*c85f09ccSJohn Levon * The situation here is that say we memset() a void pointer to zero 611*c85f09ccSJohn Levon * then that's returned to the called as "*$ = 0;" but on the caller's 612*c85f09ccSJohn Levon * side it's not void, it's a struct. 613*c85f09ccSJohn Levon * 614*c85f09ccSJohn Levon * So the question is should we be passing that slightly bogus 615*c85f09ccSJohn Levon * information back to the caller? Maybe, maybe not, but either way we 616*c85f09ccSJohn Levon * are not going to record it here because a struct can't be zero. 617*c85f09ccSJohn Levon * 618*c85f09ccSJohn Levon */ 619*c85f09ccSJohn Levon if (type && type->type == SYM_STRUCT) 620*c85f09ccSJohn Levon return; 621*c85f09ccSJohn Levon 6221f5207b7SJohn Levon if (arg->type != EXPR_PREOP || arg->op != '&') 6231f5207b7SJohn Levon return; 6241f5207b7SJohn Levon arg = strip_expr(arg->unop); 6251f5207b7SJohn Levon 6261f5207b7SJohn Levon member = get_member_name(arg); 6271f5207b7SJohn Levon if (!member) 6281f5207b7SJohn Levon return; 6291f5207b7SJohn Levon call_results_to_rl(expr, type, value, &rl); 6301f5207b7SJohn Levon add_type_val(member, rl); 6311f5207b7SJohn Levon free_string(member); 6321f5207b7SJohn Levon } 6331f5207b7SJohn Levon 6341f5207b7SJohn Levon static void match_end_func_info(struct symbol *sym) 6351f5207b7SJohn Levon { 6361f5207b7SJohn Levon struct sm_state *sm; 6371f5207b7SJohn Levon 6381f5207b7SJohn Levon FOR_EACH_SM(fn_type_val, sm) { 6391f5207b7SJohn Levon sql_insert_function_type_value(sm->name, sm->state->name); 6401f5207b7SJohn Levon } END_FOR_EACH_SM(sm); 6411f5207b7SJohn Levon } 6421f5207b7SJohn Levon 6431f5207b7SJohn Levon static void clear_cache(struct symbol *sym) 6441f5207b7SJohn Levon { 6451f5207b7SJohn Levon memset(cached_results, 0, sizeof(cached_results)); 6461f5207b7SJohn Levon } 6471f5207b7SJohn Levon 6481f5207b7SJohn Levon static void match_after_func(struct symbol *sym) 6491f5207b7SJohn Levon { 6501f5207b7SJohn Levon free_stree(&fn_type_val); 6511f5207b7SJohn Levon } 6521f5207b7SJohn Levon 6531f5207b7SJohn Levon static void match_end_file(struct symbol_list *sym_list) 6541f5207b7SJohn Levon { 6551f5207b7SJohn Levon struct sm_state *sm; 6561f5207b7SJohn Levon 6571f5207b7SJohn Levon FOR_EACH_SM(global_type_val, sm) { 6581f5207b7SJohn Levon sql_insert_function_type_value(sm->name, sm->state->name); 6591f5207b7SJohn Levon } END_FOR_EACH_SM(sm); 6601f5207b7SJohn Levon } 6611f5207b7SJohn Levon 6621f5207b7SJohn Levon void register_type_val(int id) 6631f5207b7SJohn Levon { 6641f5207b7SJohn Levon my_id = id; 6651f5207b7SJohn Levon add_hook(&clear_cache, AFTER_FUNC_HOOK); 6661f5207b7SJohn Levon 6671f5207b7SJohn Levon if (!option_info) 6681f5207b7SJohn Levon return; 6691f5207b7SJohn Levon 6701f5207b7SJohn Levon add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER); 6711f5207b7SJohn Levon add_hook(&match_assign_pointer, ASSIGNMENT_HOOK); 6721f5207b7SJohn Levon add_hook(&unop_expr, OP_HOOK); 6731f5207b7SJohn Levon add_hook(&asm_expr, ASM_HOOK); 6741f5207b7SJohn Levon select_return_states_hook(PARAM_ADD, &db_param_add); 6751f5207b7SJohn Levon select_return_states_hook(PARAM_SET, &db_param_add); 6761f5207b7SJohn Levon 6771f5207b7SJohn Levon 6781f5207b7SJohn Levon add_hook(&match_inline_start, INLINE_FN_START); 6791f5207b7SJohn Levon add_hook(&match_inline_end, INLINE_FN_END); 6801f5207b7SJohn Levon 6811f5207b7SJohn Levon add_hook(&match_end_func_info, END_FUNC_HOOK); 6821f5207b7SJohn Levon add_hook(&match_after_func, AFTER_FUNC_HOOK); 6831f5207b7SJohn Levon 6841f5207b7SJohn Levon add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK); 6851f5207b7SJohn Levon add_hook(&match_end_file, END_FILE_HOOK); 6861f5207b7SJohn Levon } 687