1 /* 2 * Copyright (C) 2013 Oracle. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt 16 */ 17 18 /* 19 * The plan here is to save all the possible values store to a given struct 20 * member. 21 * 22 * We will load all the values in to the function_type_val table first then 23 * run a script on that and load all the resulting values into the type_val 24 * table. 25 * 26 * So in this file we want to take the union of everything assigned to the 27 * struct member and insert it into the function_type_val at the end. 28 * 29 * You would think that we could use smatch_modification_hooks.c or 30 * extra_modification_hook() here to get the information here but in the end we 31 * need to code everything again a third time. 32 * 33 */ 34 35 #include "smatch.h" 36 #include "smatch_slist.h" 37 #include "smatch_extra.h" 38 39 static int my_id; 40 41 struct stree_stack *fn_type_val_stack; 42 struct stree *fn_type_val; 43 struct stree *global_type_val; 44 45 static int get_vals(void *_db_vals, int argc, char **argv, char **azColName) 46 { 47 char **db_vals = _db_vals; 48 49 *db_vals = alloc_string(argv[0]); 50 return 0; 51 } 52 53 static void match_inline_start(struct expression *expr) 54 { 55 push_stree(&fn_type_val_stack, fn_type_val); 56 fn_type_val = NULL; 57 } 58 59 static void match_inline_end(struct expression *expr) 60 { 61 free_stree(&fn_type_val); 62 fn_type_val = pop_stree(&fn_type_val_stack); 63 } 64 65 struct expr_rl { 66 struct expression *expr; 67 struct range_list *rl; 68 }; 69 static struct expr_rl cached_results[10]; 70 static int res_idx; 71 72 static int get_cached(struct expression *expr, struct range_list **rl, int *ret) 73 { 74 int i; 75 76 *ret = 0; 77 78 for (i = 0; i < ARRAY_SIZE(cached_results); i++) { 79 if (expr == cached_results[i].expr) { 80 if (cached_results[i].rl) { 81 *rl = clone_rl(cached_results[i].rl); 82 *ret = 1; 83 } 84 return 1; 85 } 86 } 87 88 return 0; 89 } 90 91 int get_db_type_rl(struct expression *expr, struct range_list **rl) 92 { 93 char *db_vals = NULL; 94 char *member; 95 struct range_list *tmp; 96 struct symbol *type; 97 int ret; 98 99 if (get_cached(expr, rl, &ret)) 100 return ret; 101 102 member = get_member_name(expr); 103 if (!member) 104 return 0; 105 106 res_idx = (res_idx + 1) % ARRAY_SIZE(cached_results); 107 cached_results[res_idx].expr = expr; 108 cached_results[res_idx].rl = NULL; 109 110 run_sql(get_vals, &db_vals, 111 "select value from type_value where type = '%s';", member); 112 free_string(member); 113 if (!db_vals) 114 return 0; 115 type = get_type(expr); 116 str_to_rl(type, db_vals, &tmp); 117 free_string(db_vals); 118 if (is_whole_rl(tmp)) 119 return 0; 120 121 *rl = tmp; 122 cached_results[res_idx].rl = clone_rl(tmp); 123 124 return 1; 125 } 126 127 static void add_type_val(char *member, struct range_list *rl) 128 { 129 struct smatch_state *old, *add, *new; 130 131 member = alloc_string(member); 132 old = get_state_stree(fn_type_val, my_id, member, NULL); 133 add = alloc_estate_rl(rl); 134 if (old) 135 new = merge_estates(old, add); 136 else 137 new = add; 138 set_state_stree(&fn_type_val, my_id, member, NULL, new); 139 } 140 141 static void add_fake_type_val(char *member, struct range_list *rl, int ignore) 142 { 143 struct smatch_state *old, *add, *new; 144 145 member = alloc_string(member); 146 old = get_state_stree(fn_type_val, my_id, member, NULL); 147 if (old && strcmp(old->name, "min-max") == 0) 148 return; 149 if (ignore && old && strcmp(old->name, "ignore") == 0) 150 return; 151 add = alloc_estate_rl(rl); 152 if (old) { 153 new = merge_estates(old, add); 154 } else { 155 new = add; 156 if (ignore) 157 new->name = alloc_string("ignore"); 158 else 159 new->name = alloc_string("min-max"); 160 } 161 set_state_stree(&fn_type_val, my_id, member, NULL, new); 162 } 163 164 static void add_global_type_val(char *member, struct range_list *rl) 165 { 166 struct smatch_state *old, *add, *new; 167 168 member = alloc_string(member); 169 old = get_state_stree(global_type_val, my_id, member, NULL); 170 add = alloc_estate_rl(rl); 171 if (old) 172 new = merge_estates(old, add); 173 else 174 new = add; 175 new = clone_estate_perm(new); 176 set_state_stree_perm(&global_type_val, my_id, member, NULL, new); 177 } 178 179 static int has_link_cb(void *has_link, int argc, char **argv, char **azColName) 180 { 181 *(int *)has_link = 1; 182 return 0; 183 } 184 185 static int is_ignored_fake_assignment(void) 186 { 187 struct expression *expr; 188 struct symbol *type; 189 char *member_name; 190 int has_link = 0; 191 192 expr = get_faked_expression(); 193 if (!expr || expr->type != EXPR_ASSIGNMENT) 194 return 0; 195 if (!is_void_pointer(expr->right)) 196 return 0; 197 member_name = get_member_name(expr->right); 198 if (!member_name) 199 return 0; 200 201 type = get_type(expr->left); 202 if (!type || type->type != SYM_PTR) 203 return 0; 204 type = get_real_base_type(type); 205 if (!type || type->type != SYM_STRUCT) 206 return 0; 207 208 run_sql(has_link_cb, &has_link, 209 "select * from data_info where type = %d and data = '%s' and value = '%s';", 210 TYPE_LINK, member_name, type_to_str(type)); 211 return has_link; 212 } 213 214 static int is_container_of(void) 215 { 216 /* We already check the macro name in is_ignored_macro() */ 217 struct expression *expr; 218 int offset; 219 220 expr = get_faked_expression(); 221 if (!expr || expr->type != EXPR_ASSIGNMENT) 222 return 0; 223 224 offset = get_offset_from_container_of(expr->right); 225 if (offset < 0) 226 return 0; 227 return 1; 228 } 229 230 static int is_ignored_macro(void) 231 { 232 struct expression *expr; 233 char *name; 234 235 expr = get_faked_expression(); 236 if (!expr || expr->type != EXPR_ASSIGNMENT) 237 return 0; 238 name = get_macro_name(expr->right->pos); 239 if (!name) 240 return 0; 241 if (strcmp(name, "container_of") == 0) 242 return 1; 243 if (strcmp(name, "rb_entry") == 0) 244 return 1; 245 if (strcmp(name, "list_entry") == 0) 246 return 1; 247 if (strcmp(name, "list_first_entry") == 0) 248 return 1; 249 if (strcmp(name, "hlist_entry") == 0) 250 return 1; 251 if (strstr(name, "for_each")) 252 return 1; 253 return 0; 254 } 255 256 static int is_ignored_function(void) 257 { 258 struct expression *expr; 259 260 expr = get_faked_expression(); 261 if (!expr || expr->type != EXPR_ASSIGNMENT) 262 return 0; 263 expr = strip_expr(expr->right); 264 if (!expr || expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL) 265 return 0; 266 267 if (sym_name_is("kmalloc", expr->fn)) 268 return 1; 269 if (sym_name_is("netdev_priv", expr->fn)) 270 return 1; 271 if (sym_name_is("dev_get_drvdata", expr->fn)) 272 return 1; 273 274 return 0; 275 } 276 277 static int is_uncasted_pointer_assign(void) 278 { 279 struct expression *expr; 280 struct symbol *left_type, *right_type; 281 282 expr = get_faked_expression(); 283 if (!expr) 284 return 0; 285 if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) { 286 if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT) 287 return 1; 288 } 289 if (expr->type != EXPR_ASSIGNMENT) 290 return 0; 291 left_type = get_type(expr->left); 292 right_type = get_type(expr->right); 293 294 if (!left_type || !right_type) 295 return 0; 296 297 if (left_type->type != SYM_PTR && 298 left_type->type != SYM_ARRAY) 299 return 0; 300 if (right_type->type != SYM_PTR && 301 right_type->type != SYM_ARRAY) 302 return 0; 303 left_type = get_real_base_type(left_type); 304 right_type = get_real_base_type(right_type); 305 306 if (left_type == right_type) 307 return 1; 308 return 0; 309 } 310 311 static int set_param_type(void *_type_str, int argc, char **argv, char **azColName) 312 { 313 char **type_str = _type_str; 314 static char type_buf[128]; 315 316 if (*type_str) { 317 if (strcmp(*type_str, argv[0]) == 0) 318 return 0; 319 strncpy(type_buf, "unknown", sizeof(type_buf)); 320 return 0; 321 } 322 strncpy(type_buf, argv[0], sizeof(type_buf)); 323 *type_str = type_buf; 324 325 return 0; 326 } 327 328 static char *db_get_parameter_type(int param) 329 { 330 char *ret = NULL; 331 332 if (!cur_func_sym) 333 return NULL; 334 335 run_sql(set_param_type, &ret, 336 "select value from fn_data_link where " 337 "file = '%s' and function = '%s' and static = %d and type = %d and parameter = %d and key = '$';", 338 (cur_func_sym->ctype.modifiers & MOD_STATIC) ? get_base_file() : "extern", 339 cur_func_sym->ident->name, 340 !!(cur_func_sym->ctype.modifiers & MOD_STATIC), 341 PASSES_TYPE, param); 342 343 return ret; 344 } 345 346 static int is_uncasted_fn_param_from_db(void) 347 { 348 struct expression *expr, *right; 349 struct symbol *left_type; 350 char left_type_name[128]; 351 int param; 352 char *right_type_name; 353 static struct expression *prev_expr; 354 static int prev_ans; 355 356 expr = get_faked_expression(); 357 358 if (expr == prev_expr) 359 return prev_ans; 360 prev_expr = expr; 361 prev_ans = 0; 362 363 if (!expr || expr->type != EXPR_ASSIGNMENT) 364 return 0; 365 left_type = get_type(expr->left); 366 if (!left_type || left_type->type != SYM_PTR) 367 return 0; 368 left_type = get_real_base_type(left_type); 369 if (!left_type || left_type->type != SYM_STRUCT) 370 return 0; 371 snprintf(left_type_name, sizeof(left_type_name), "%s", type_to_str(left_type)); 372 373 right = strip_expr(expr->right); 374 param = get_param_num(right); 375 if (param < 0) 376 return 0; 377 right_type_name = db_get_parameter_type(param); 378 if (!right_type_name) 379 return 0; 380 381 if (strcmp(right_type_name, left_type_name) == 0) { 382 prev_ans = 1; 383 return 1; 384 } 385 386 return 0; 387 } 388 389 static void match_assign_value(struct expression *expr) 390 { 391 char *member, *right_member; 392 struct range_list *rl; 393 struct symbol *type; 394 395 if (!cur_func_sym) 396 return; 397 398 type = get_type(expr->left); 399 if (type && type->type == SYM_STRUCT) 400 return; 401 402 member = get_member_name(expr->left); 403 if (!member) 404 return; 405 406 /* if we're saying foo->mtu = bar->mtu then that doesn't add information */ 407 right_member = get_member_name(expr->right); 408 if (right_member && strcmp(right_member, member) == 0) 409 goto free; 410 411 if (is_fake_call(expr->right)) { 412 if (is_ignored_macro()) 413 goto free; 414 if (is_ignored_function()) 415 goto free; 416 if (is_uncasted_pointer_assign()) 417 goto free; 418 if (is_uncasted_fn_param_from_db()) 419 goto free; 420 if (is_container_of()) 421 goto free; 422 add_fake_type_val(member, alloc_whole_rl(get_type(expr->left)), is_ignored_fake_assignment()); 423 goto free; 424 } 425 426 if (expr->op == '=') { 427 get_absolute_rl(expr->right, &rl); 428 rl = cast_rl(type, rl); 429 } else { 430 /* 431 * This is a bit cheating. We order it so this will already be set 432 * by smatch_extra.c and we just look up the value. 433 */ 434 get_absolute_rl(expr->left, &rl); 435 } 436 add_type_val(member, rl); 437 free: 438 free_string(right_member); 439 free_string(member); 440 } 441 442 /* 443 * If we too: int *p = &my_struct->member then abandon all hope of tracking 444 * my_struct->member. 445 */ 446 static void match_assign_pointer(struct expression *expr) 447 { 448 struct expression *right; 449 char *member; 450 struct range_list *rl; 451 struct symbol *type; 452 453 right = strip_expr(expr->right); 454 if (right->type != EXPR_PREOP || right->op != '&') 455 return; 456 right = strip_expr(right->unop); 457 458 member = get_member_name(right); 459 if (!member) 460 return; 461 type = get_type(right); 462 rl = alloc_whole_rl(type); 463 add_type_val(member, rl); 464 free_string(member); 465 } 466 467 static void match_global_assign(struct expression *expr) 468 { 469 char *member; 470 struct range_list *rl; 471 struct symbol *type; 472 473 type = get_type(expr->left); 474 if (type && (type->type == SYM_ARRAY || type->type == SYM_STRUCT)) 475 return; 476 member = get_member_name(expr->left); 477 if (!member) 478 return; 479 get_absolute_rl(expr->right, &rl); 480 rl = cast_rl(type, rl); 481 add_global_type_val(member, rl); 482 free_string(member); 483 } 484 485 static void unop_expr(struct expression *expr) 486 { 487 struct range_list *rl; 488 char *member; 489 490 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT) 491 return; 492 493 expr = strip_expr(expr->unop); 494 member = get_member_name(expr); 495 if (!member) 496 return; 497 rl = alloc_whole_rl(get_type(expr)); 498 add_type_val(member, rl); 499 free_string(member); 500 } 501 502 static void asm_expr(struct statement *stmt) 503 { 504 struct expression *expr; 505 struct range_list *rl; 506 char *member; 507 int state = 0; 508 509 FOR_EACH_PTR(stmt->asm_outputs, expr) { 510 switch (state) { 511 case 0: /* identifier */ 512 case 1: /* constraint */ 513 state++; 514 continue; 515 case 2: /* expression */ 516 state = 0; 517 member = get_member_name(expr); 518 if (!member) 519 continue; 520 rl = alloc_whole_rl(get_type(expr)); 521 add_type_val(member, rl); 522 free_string(member); 523 continue; 524 } 525 } END_FOR_EACH_PTR(expr); 526 } 527 528 static void db_param_add(struct expression *expr, int param, char *key, char *value) 529 { 530 struct expression *arg; 531 struct symbol *type; 532 struct range_list *rl; 533 char *member; 534 535 if (strcmp(key, "*$") != 0) 536 return; 537 538 while (expr->type == EXPR_ASSIGNMENT) 539 expr = strip_expr(expr->right); 540 if (expr->type != EXPR_CALL) 541 return; 542 543 arg = get_argument_from_call_expr(expr->args, param); 544 arg = strip_expr(arg); 545 if (!arg) 546 return; 547 type = get_member_type_from_key(arg, key); 548 if (arg->type != EXPR_PREOP || arg->op != '&') 549 return; 550 arg = strip_expr(arg->unop); 551 552 member = get_member_name(arg); 553 if (!member) 554 return; 555 call_results_to_rl(expr, type, value, &rl); 556 add_type_val(member, rl); 557 free_string(member); 558 } 559 560 static void match_end_func_info(struct symbol *sym) 561 { 562 struct sm_state *sm; 563 564 FOR_EACH_SM(fn_type_val, sm) { 565 sql_insert_function_type_value(sm->name, sm->state->name); 566 } END_FOR_EACH_SM(sm); 567 } 568 569 static void clear_cache(struct symbol *sym) 570 { 571 memset(cached_results, 0, sizeof(cached_results)); 572 } 573 574 static void match_after_func(struct symbol *sym) 575 { 576 free_stree(&fn_type_val); 577 } 578 579 static void match_end_file(struct symbol_list *sym_list) 580 { 581 struct sm_state *sm; 582 583 FOR_EACH_SM(global_type_val, sm) { 584 sql_insert_function_type_value(sm->name, sm->state->name); 585 } END_FOR_EACH_SM(sm); 586 } 587 588 void register_type_val(int id) 589 { 590 my_id = id; 591 add_hook(&clear_cache, AFTER_FUNC_HOOK); 592 593 if (!option_info) 594 return; 595 596 add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER); 597 add_hook(&match_assign_pointer, ASSIGNMENT_HOOK); 598 add_hook(&unop_expr, OP_HOOK); 599 add_hook(&asm_expr, ASM_HOOK); 600 select_return_states_hook(PARAM_ADD, &db_param_add); 601 select_return_states_hook(PARAM_SET, &db_param_add); 602 603 604 add_hook(&match_inline_start, INLINE_FN_START); 605 add_hook(&match_inline_end, INLINE_FN_END); 606 607 add_hook(&match_end_func_info, END_FUNC_HOOK); 608 add_hook(&match_after_func, AFTER_FUNC_HOOK); 609 610 add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK); 611 add_hook(&match_end_file, END_FILE_HOOK); 612 } 613