1 /* 2 * Copyright (C) 2006 Dan Carpenter. 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 * You have a lists of states. kernel = locked, foo = NULL, ... 20 * When you hit an if {} else {} statement then you swap the list 21 * of states for a different list of states. The lists are stored 22 * on stacks. 23 * 24 * At the beginning of this file there are list of the stacks that 25 * we use. Each function in this file does something to one of 26 * of the stacks. 27 * 28 * So the smatch_flow.c understands code but it doesn't understand states. 29 * smatch_flow calls functions in this file. This file calls functions 30 * in smatch_slist.c which just has boring generic plumbing for handling 31 * state lists. But really it's this file where all the magic happens. 32 */ 33 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include "smatch.h" 37 #include "smatch_slist.h" 38 #include "smatch_extra.h" 39 40 struct smatch_state undefined = { .name = "undefined" }; 41 struct smatch_state ghost = { .name = "ghost" }; 42 struct smatch_state merged = { .name = "merged" }; 43 struct smatch_state true_state = { .name = "true" }; 44 struct smatch_state false_state = { .name = "false" }; 45 46 static struct stree *cur_stree; /* current states */ 47 static struct stree *fast_overlay; 48 49 static struct stree_stack *true_stack; /* states after a t/f branch */ 50 static struct stree_stack *false_stack; 51 static struct stree_stack *pre_cond_stack; /* states before a t/f branch */ 52 53 static struct stree_stack *cond_true_stack; /* states affected by a branch */ 54 static struct stree_stack *cond_false_stack; 55 56 static struct stree_stack *fake_cur_stree_stack; 57 static int read_only; 58 59 static struct stree_stack *break_stack; 60 static struct stree_stack *fake_break_stack; 61 static struct stree_stack *switch_stack; 62 static struct range_list_stack *remaining_cases; 63 static struct stree_stack *default_stack; 64 static struct stree_stack *continue_stack; 65 66 static struct named_stree_stack *goto_stack; 67 68 static struct ptr_list *backup; 69 70 int option_debug; 71 72 void __print_cur_stree(void) 73 { 74 __print_stree(cur_stree); 75 } 76 77 int unreachable(void) 78 { 79 if (!cur_stree) 80 return 1; 81 return 0; 82 } 83 84 void __set_cur_stree_readonly(void) 85 { 86 read_only++; 87 } 88 89 void __set_cur_stree_writable(void) 90 { 91 read_only--; 92 } 93 94 struct sm_state *set_state(int owner, const char *name, struct symbol *sym, struct smatch_state *state) 95 { 96 struct sm_state *ret; 97 98 if (!name || !state) 99 return NULL; 100 101 if (read_only) 102 sm_perror("cur_stree is read only."); 103 104 if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) { 105 struct smatch_state *s; 106 107 s = __get_state(owner, name, sym); 108 if (!s) 109 sm_msg("%s new [%s] '%s' %s", __func__, 110 check_name(owner), name, show_state(state)); 111 else 112 sm_msg("%s change [%s] '%s' %s => %s", 113 __func__, check_name(owner), name, show_state(s), 114 show_state(state)); 115 } 116 117 if (owner != -1 && unreachable()) 118 return NULL; 119 120 if (fake_cur_stree_stack) 121 set_state_stree_stack(&fake_cur_stree_stack, owner, name, sym, state); 122 123 ret = set_state_stree(&cur_stree, owner, name, sym, state); 124 125 return ret; 126 } 127 128 struct sm_state *set_state_expr(int owner, struct expression *expr, struct smatch_state *state) 129 { 130 char *name; 131 struct symbol *sym; 132 struct sm_state *ret = NULL; 133 134 expr = strip_expr(expr); 135 name = expr_to_var_sym(expr, &sym); 136 if (!name || !sym) 137 goto free; 138 ret = set_state(owner, name, sym, state); 139 free: 140 free_string(name); 141 return ret; 142 } 143 144 struct stree *__swap_cur_stree(struct stree *stree) 145 { 146 struct stree *orig = cur_stree; 147 148 cur_stree = stree; 149 return orig; 150 } 151 152 void __push_fake_cur_stree(void) 153 { 154 push_stree(&fake_cur_stree_stack, NULL); 155 __save_pre_cond_states(); 156 } 157 158 struct stree *__pop_fake_cur_stree(void) 159 { 160 if (!fake_cur_stree_stack) 161 sm_perror("popping too many fake cur strees."); 162 __use_pre_cond_states(); 163 return pop_stree(&fake_cur_stree_stack); 164 } 165 166 void __free_fake_cur_stree(void) 167 { 168 struct stree *stree; 169 170 stree = __pop_fake_cur_stree(); 171 free_stree(&stree); 172 } 173 174 void __set_fake_cur_stree_fast(struct stree *stree) 175 { 176 if (fast_overlay) { 177 sm_perror("cannot nest fast overlay"); 178 return; 179 } 180 fast_overlay = stree; 181 set_fast_math_only(); 182 } 183 184 void __pop_fake_cur_stree_fast(void) 185 { 186 fast_overlay = NULL; 187 clear_fast_math_only(); 188 } 189 190 void __merge_stree_into_cur(struct stree *stree) 191 { 192 struct sm_state *sm; 193 struct sm_state *orig; 194 struct sm_state *merged; 195 196 FOR_EACH_SM(stree, sm) { 197 orig = get_sm_state(sm->owner, sm->name, sm->sym); 198 if (orig) 199 merged = merge_sm_states(orig, sm); 200 else 201 merged = sm; 202 __set_sm(merged); 203 } END_FOR_EACH_SM(sm); 204 } 205 206 void __set_sm(struct sm_state *sm) 207 { 208 if (read_only) 209 sm_perror("cur_stree is read only."); 210 211 if (option_debug || 212 strcmp(check_name(sm->owner), option_debug_check) == 0) { 213 struct smatch_state *s; 214 215 s = __get_state(sm->owner, sm->name, sm->sym); 216 if (!s) 217 sm_msg("%s new %s", __func__, show_sm(sm)); 218 else 219 sm_msg("%s change %s (was %s)", __func__, show_sm(sm), 220 show_state(s)); 221 } 222 223 if (unreachable()) 224 return; 225 226 if (fake_cur_stree_stack) 227 overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm); 228 229 overwrite_sm_state_stree(&cur_stree, sm); 230 } 231 232 void __set_sm_cur_stree(struct sm_state *sm) 233 { 234 if (read_only) 235 sm_perror("cur_stree is read only."); 236 237 if (option_debug || 238 strcmp(check_name(sm->owner), option_debug_check) == 0) { 239 struct smatch_state *s; 240 241 s = __get_state(sm->owner, sm->name, sm->sym); 242 if (!s) 243 sm_msg("%s new %s", __func__, show_sm(sm)); 244 else 245 sm_msg("%s change %s (was %s)", 246 __func__, show_sm(sm), show_state(s)); 247 } 248 249 if (unreachable()) 250 return; 251 252 overwrite_sm_state_stree(&cur_stree, sm); 253 } 254 255 void __set_sm_fake_stree(struct sm_state *sm) 256 { 257 if (read_only) 258 sm_perror("cur_stree is read only."); 259 260 if (option_debug || 261 strcmp(check_name(sm->owner), option_debug_check) == 0) { 262 struct smatch_state *s; 263 264 s = __get_state(sm->owner, sm->name, sm->sym); 265 if (!s) 266 sm_msg("%s new %s", __func__, show_sm(sm)); 267 else 268 sm_msg("%s change %s (was %s)", 269 __func__, show_sm(sm), show_state(s)); 270 } 271 272 if (unreachable()) 273 return; 274 275 overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm); 276 } 277 278 279 typedef void (get_state_hook)(int owner, const char *name, struct symbol *sym); 280 DECLARE_PTR_LIST(fn_list, get_state_hook *); 281 static struct fn_list *get_state_hooks; 282 283 void add_get_state_hook(get_state_hook *fn) 284 { 285 get_state_hook **p = malloc(sizeof(get_state_hook *)); 286 *p = fn; 287 add_ptr_list(&get_state_hooks, p); 288 } 289 290 static void call_get_state_hooks(int owner, const char *name, struct symbol *sym) 291 { 292 static int recursion; 293 get_state_hook **fn; 294 295 if (recursion) 296 return; 297 recursion = 1; 298 299 FOR_EACH_PTR(get_state_hooks, fn) { 300 (*fn)(owner, name, sym); 301 } END_FOR_EACH_PTR(fn); 302 303 recursion = 0; 304 } 305 306 struct smatch_state *__get_state(int owner, const char *name, struct symbol *sym) 307 { 308 struct sm_state *sm; 309 310 sm = get_sm_state(owner, name, sym); 311 if (!sm) 312 return NULL; 313 return sm->state; 314 } 315 316 struct smatch_state *get_state(int owner, const char *name, struct symbol *sym) 317 { 318 call_get_state_hooks(owner, name, sym); 319 320 return __get_state(owner, name, sym); 321 } 322 323 struct smatch_state *get_state_expr(int owner, struct expression *expr) 324 { 325 char *name; 326 struct symbol *sym; 327 struct smatch_state *ret = NULL; 328 329 expr = strip_expr(expr); 330 name = expr_to_var_sym(expr, &sym); 331 if (!name || !sym) 332 goto free; 333 ret = get_state(owner, name, sym); 334 free: 335 free_string(name); 336 return ret; 337 } 338 339 struct state_list *get_possible_states(int owner, const char *name, struct symbol *sym) 340 { 341 struct sm_state *sms; 342 343 sms = get_sm_state_stree(cur_stree, owner, name, sym); 344 if (sms) 345 return sms->possible; 346 return NULL; 347 } 348 349 struct state_list *get_possible_states_expr(int owner, struct expression *expr) 350 { 351 char *name; 352 struct symbol *sym; 353 struct state_list *ret = NULL; 354 355 expr = strip_expr(expr); 356 name = expr_to_var_sym(expr, &sym); 357 if (!name || !sym) 358 goto free; 359 ret = get_possible_states(owner, name, sym); 360 free: 361 free_string(name); 362 return ret; 363 } 364 365 struct sm_state *get_sm_state(int owner, const char *name, struct symbol *sym) 366 { 367 struct sm_state *ret; 368 369 ret = get_sm_state_stree(fast_overlay, owner, name, sym); 370 if (ret) 371 return ret; 372 373 return get_sm_state_stree(cur_stree, owner, name, sym); 374 } 375 376 struct sm_state *get_sm_state_expr(int owner, struct expression *expr) 377 { 378 char *name; 379 struct symbol *sym; 380 struct sm_state *ret = NULL; 381 382 expr = strip_expr(expr); 383 name = expr_to_var_sym(expr, &sym); 384 if (!name || !sym) 385 goto free; 386 ret = get_sm_state(owner, name, sym); 387 free: 388 free_string(name); 389 return ret; 390 } 391 392 void delete_state(int owner, const char *name, struct symbol *sym) 393 { 394 delete_state_stree(&cur_stree, owner, name, sym); 395 if (cond_true_stack) { 396 delete_state_stree_stack(&pre_cond_stack, owner, name, sym); 397 delete_state_stree_stack(&cond_true_stack, owner, name, sym); 398 delete_state_stree_stack(&cond_false_stack, owner, name, sym); 399 } 400 } 401 402 void delete_state_expr(int owner, struct expression *expr) 403 { 404 char *name; 405 struct symbol *sym; 406 407 expr = strip_expr(expr); 408 name = expr_to_var_sym(expr, &sym); 409 if (!name || !sym) 410 goto free; 411 delete_state(owner, name, sym); 412 free: 413 free_string(name); 414 } 415 416 static void delete_all_states_stree_sym(struct stree **stree, struct symbol *sym) 417 { 418 struct state_list *slist = NULL; 419 struct sm_state *sm; 420 421 FOR_EACH_SM(*stree, sm) { 422 if (sm->sym == sym) 423 add_ptr_list(&slist, sm); 424 } END_FOR_EACH_SM(sm); 425 426 FOR_EACH_PTR(slist, sm) { 427 delete_state_stree(stree, sm->owner, sm->name, sm->sym); 428 } END_FOR_EACH_PTR(sm); 429 430 free_slist(&slist); 431 } 432 433 static void delete_all_states_stree_stack_sym(struct stree_stack **stack, struct symbol *sym) 434 { 435 struct stree *stree; 436 437 if (!*stack) 438 return; 439 440 stree = pop_stree(stack); 441 delete_all_states_stree_sym(&stree, sym); 442 push_stree(stack, stree); 443 } 444 445 void __delete_all_states_sym(struct symbol *sym) 446 { 447 delete_all_states_stree_sym(&cur_stree, sym); 448 449 delete_all_states_stree_stack_sym(&true_stack, sym); 450 delete_all_states_stree_stack_sym(&true_stack, sym); 451 delete_all_states_stree_stack_sym(&false_stack, sym); 452 delete_all_states_stree_stack_sym(&pre_cond_stack, sym); 453 delete_all_states_stree_stack_sym(&cond_true_stack, sym); 454 delete_all_states_stree_stack_sym(&cond_false_stack, sym); 455 delete_all_states_stree_stack_sym(&fake_cur_stree_stack, sym); 456 delete_all_states_stree_stack_sym(&break_stack, sym); 457 delete_all_states_stree_stack_sym(&fake_break_stack, sym); 458 delete_all_states_stree_stack_sym(&switch_stack, sym); 459 delete_all_states_stree_stack_sym(&continue_stack, sym); 460 461 /* 462 * deleting from the goto stack is problematic because we don't know 463 * if the label is in scope and also we need the value for --two-passes. 464 */ 465 } 466 467 struct stree *get_all_states_from_stree(int owner, struct stree *source) 468 { 469 struct stree *ret = NULL; 470 struct sm_state *tmp; 471 472 FOR_EACH_SM(source, tmp) { 473 if (tmp->owner == owner) 474 avl_insert(&ret, tmp); 475 } END_FOR_EACH_SM(tmp); 476 477 return ret; 478 } 479 480 struct stree *get_all_states_stree(int owner) 481 { 482 return get_all_states_from_stree(owner, cur_stree); 483 } 484 485 struct stree *__get_cur_stree(void) 486 { 487 return cur_stree; 488 } 489 490 int is_reachable(void) 491 { 492 if (cur_stree) 493 return 1; 494 return 0; 495 } 496 497 void set_true_false_states(int owner, const char *name, struct symbol *sym, 498 struct smatch_state *true_state, 499 struct smatch_state *false_state) 500 { 501 if (read_only) 502 sm_perror("cur_stree is read only."); 503 504 if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) { 505 struct smatch_state *tmp; 506 507 tmp = __get_state(owner, name, sym); 508 sm_msg("%s [%s] '%s'. Was %s. Now T:%s F:%s", __func__, 509 check_name(owner), name, show_state(tmp), 510 show_state(true_state), show_state(false_state)); 511 } 512 513 if (unreachable()) 514 return; 515 516 if (!cond_false_stack || !cond_true_stack) { 517 sm_perror("missing true/false stacks"); 518 return; 519 } 520 521 if (true_state) 522 set_state_stree_stack(&cond_true_stack, owner, name, sym, true_state); 523 if (false_state) 524 set_state_stree_stack(&cond_false_stack, owner, name, sym, false_state); 525 } 526 527 void set_true_false_states_expr(int owner, struct expression *expr, 528 struct smatch_state *true_state, 529 struct smatch_state *false_state) 530 { 531 char *name; 532 struct symbol *sym; 533 534 expr = strip_expr(expr); 535 name = expr_to_var_sym(expr, &sym); 536 if (!name || !sym) 537 goto free; 538 set_true_false_states(owner, name, sym, true_state, false_state); 539 free: 540 free_string(name); 541 } 542 543 void __set_true_false_sm(struct sm_state *true_sm, struct sm_state *false_sm) 544 { 545 int owner; 546 const char *name; 547 struct symbol *sym; 548 549 if (!true_sm && !false_sm) 550 return; 551 552 if (unreachable()) 553 return; 554 555 owner = true_sm ? true_sm->owner : false_sm->owner; 556 name = true_sm ? true_sm->name : false_sm->name; 557 sym = true_sm ? true_sm->sym : false_sm->sym; 558 if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) { 559 struct smatch_state *tmp; 560 561 tmp = __get_state(owner, name, sym); 562 sm_msg("%s [%s] '%s'. Was %s. Now T:%s F:%s", __func__, 563 check_name(owner), name, show_state(tmp), 564 show_state(true_sm ? true_sm->state : NULL), 565 show_state(false_sm ? false_sm->state : NULL)); 566 } 567 568 if (!cond_false_stack || !cond_true_stack) { 569 sm_perror("missing true/false stacks"); 570 return; 571 } 572 573 if (true_sm) 574 overwrite_sm_state_stree_stack(&cond_true_stack, true_sm); 575 if (false_sm) 576 overwrite_sm_state_stree_stack(&cond_false_stack, false_sm); 577 } 578 579 void nullify_path(void) 580 { 581 if (fake_cur_stree_stack) { 582 __free_fake_cur_stree(); 583 __push_fake_cur_stree(); 584 } 585 free_stree(&cur_stree); 586 } 587 588 void __match_nullify_path_hook(const char *fn, struct expression *expr, 589 void *unused) 590 { 591 nullify_path(); 592 } 593 594 /* 595 * At the start of every function we mark the path 596 * as unnull. That way there is always at least one state 597 * in the cur_stree until nullify_path is called. This 598 * is used in merge_slist() for the first null check. 599 */ 600 void __unnullify_path(void) 601 { 602 if (!cur_stree) 603 set_state(-1, "unnull_path", NULL, &true_state); 604 } 605 606 int __path_is_null(void) 607 { 608 if (cur_stree) 609 return 0; 610 return 1; 611 } 612 613 static void check_stree_stack_free(struct stree_stack **stack) 614 { 615 if (*stack) { 616 sm_perror("stack not empty"); 617 free_stack_and_strees(stack); 618 } 619 } 620 621 void save_all_states(void) 622 { 623 __add_ptr_list(&backup, cur_stree); 624 cur_stree = NULL; 625 626 __add_ptr_list(&backup, true_stack); 627 true_stack = NULL; 628 __add_ptr_list(&backup, false_stack); 629 false_stack = NULL; 630 __add_ptr_list(&backup, pre_cond_stack); 631 pre_cond_stack = NULL; 632 633 __add_ptr_list(&backup, cond_true_stack); 634 cond_true_stack = NULL; 635 __add_ptr_list(&backup, cond_false_stack); 636 cond_false_stack = NULL; 637 638 __add_ptr_list(&backup, fake_cur_stree_stack); 639 fake_cur_stree_stack = NULL; 640 641 __add_ptr_list(&backup, break_stack); 642 break_stack = NULL; 643 __add_ptr_list(&backup, fake_break_stack); 644 fake_break_stack = NULL; 645 646 __add_ptr_list(&backup, switch_stack); 647 switch_stack = NULL; 648 __add_ptr_list(&backup, remaining_cases); 649 remaining_cases = NULL; 650 __add_ptr_list(&backup, default_stack); 651 default_stack = NULL; 652 __add_ptr_list(&backup, continue_stack); 653 continue_stack = NULL; 654 655 __add_ptr_list(&backup, goto_stack); 656 goto_stack = NULL; 657 } 658 659 static void *pop_backup(void) 660 { 661 void *ret; 662 663 ret = last_ptr_list(backup); 664 delete_ptr_list_last(&backup); 665 return ret; 666 } 667 668 void restore_all_states(void) 669 { 670 goto_stack = pop_backup(); 671 672 continue_stack = pop_backup(); 673 default_stack = pop_backup(); 674 remaining_cases = pop_backup(); 675 switch_stack = pop_backup(); 676 fake_break_stack = pop_backup(); 677 break_stack = pop_backup(); 678 679 fake_cur_stree_stack = pop_backup(); 680 681 cond_false_stack = pop_backup(); 682 cond_true_stack = pop_backup(); 683 684 pre_cond_stack = pop_backup(); 685 false_stack = pop_backup(); 686 true_stack = pop_backup(); 687 688 cur_stree = pop_backup(); 689 } 690 691 void free_goto_stack(void) 692 { 693 struct named_stree *named_stree; 694 695 FOR_EACH_PTR(goto_stack, named_stree) { 696 free_stree(&named_stree->stree); 697 } END_FOR_EACH_PTR(named_stree); 698 __free_ptr_list((struct ptr_list **)&goto_stack); 699 } 700 701 void clear_all_states(void) 702 { 703 nullify_path(); 704 check_stree_stack_free(&true_stack); 705 check_stree_stack_free(&false_stack); 706 check_stree_stack_free(&pre_cond_stack); 707 check_stree_stack_free(&cond_true_stack); 708 check_stree_stack_free(&cond_false_stack); 709 check_stree_stack_free(&break_stack); 710 check_stree_stack_free(&fake_break_stack); 711 check_stree_stack_free(&switch_stack); 712 check_stree_stack_free(&continue_stack); 713 check_stree_stack_free(&fake_cur_stree_stack); 714 715 free_goto_stack(); 716 717 free_every_single_sm_state(); 718 free_tmp_expressions(); 719 } 720 721 void __push_cond_stacks(void) 722 { 723 push_stree(&cond_true_stack, NULL); 724 push_stree(&cond_false_stack, NULL); 725 __push_fake_cur_stree(); 726 } 727 728 void __fold_in_set_states(void) 729 { 730 struct stree *new_states; 731 struct sm_state *sm; 732 733 new_states = __pop_fake_cur_stree(); 734 FOR_EACH_SM(new_states, sm) { 735 __set_sm(sm); 736 __set_true_false_sm(sm, sm); 737 } END_FOR_EACH_SM(sm); 738 free_stree(&new_states); 739 } 740 741 void __free_set_states(void) 742 { 743 struct stree *new_states; 744 745 new_states = __pop_fake_cur_stree(); 746 free_stree(&new_states); 747 } 748 749 struct stree *__copy_cond_true_states(void) 750 { 751 struct stree *ret; 752 753 ret = pop_stree(&cond_true_stack); 754 push_stree(&cond_true_stack, clone_stree(ret)); 755 return ret; 756 } 757 758 struct stree *__copy_cond_false_states(void) 759 { 760 struct stree *ret; 761 762 ret = pop_stree(&cond_false_stack); 763 push_stree(&cond_false_stack, clone_stree(ret)); 764 return ret; 765 } 766 767 struct stree *__pop_cond_true_stack(void) 768 { 769 return pop_stree(&cond_true_stack); 770 } 771 772 struct stree *__pop_cond_false_stack(void) 773 { 774 return pop_stree(&cond_false_stack); 775 } 776 777 /* 778 * This combines the pre cond states with either the true or false states. 779 * For example: 780 * a = kmalloc() ; if (a !! foo(a) 781 * In the pre state a is possibly null. In the true state it is non null. 782 * In the false state it is null. Combine the pre and the false to get 783 * that when we call 'foo', 'a' is null. 784 */ 785 static void __use_cond_stack(struct stree_stack **stack) 786 { 787 struct stree *stree; 788 789 free_stree(&cur_stree); 790 791 cur_stree = pop_stree(&pre_cond_stack); 792 push_stree(&pre_cond_stack, clone_stree(cur_stree)); 793 794 stree = pop_stree(stack); 795 overwrite_stree(stree, &cur_stree); 796 push_stree(stack, stree); 797 } 798 799 void __use_pre_cond_states(void) 800 { 801 free_stree(&cur_stree); 802 cur_stree = pop_stree(&pre_cond_stack); 803 } 804 805 void __use_cond_true_states(void) 806 { 807 __use_cond_stack(&cond_true_stack); 808 } 809 810 void __use_cond_false_states(void) 811 { 812 __use_cond_stack(&cond_false_stack); 813 } 814 815 void __negate_cond_stacks(void) 816 { 817 struct stree *old_false, *old_true; 818 819 old_false = pop_stree(&cond_false_stack); 820 old_true = pop_stree(&cond_true_stack); 821 push_stree(&cond_false_stack, old_true); 822 push_stree(&cond_true_stack, old_false); 823 } 824 825 void __and_cond_states(void) 826 { 827 and_stree_stack(&cond_true_stack); 828 or_stree_stack(&pre_cond_stack, cur_stree, &cond_false_stack); 829 } 830 831 void __or_cond_states(void) 832 { 833 or_stree_stack(&pre_cond_stack, cur_stree, &cond_true_stack); 834 and_stree_stack(&cond_false_stack); 835 } 836 837 void __save_pre_cond_states(void) 838 { 839 push_stree(&pre_cond_stack, clone_stree(cur_stree)); 840 } 841 842 void __discard_pre_cond_states(void) 843 { 844 struct stree *tmp; 845 846 tmp = pop_stree(&pre_cond_stack); 847 free_stree(&tmp); 848 } 849 850 struct stree *__get_true_states(void) 851 { 852 return clone_stree(top_stree(cond_true_stack)); 853 } 854 855 struct stree *__get_false_states(void) 856 { 857 return clone_stree(top_stree(cond_false_stack)); 858 } 859 860 void __use_cond_states(void) 861 { 862 struct stree *pre, *pre_clone, *true_states, *false_states; 863 864 pre = pop_stree(&pre_cond_stack); 865 pre_clone = clone_stree(pre); 866 867 true_states = pop_stree(&cond_true_stack); 868 overwrite_stree(true_states, &pre); 869 free_stree(&true_states); 870 /* we use the true states right away */ 871 free_stree(&cur_stree); 872 cur_stree = pre; 873 874 false_states = pop_stree(&cond_false_stack); 875 overwrite_stree(false_states, &pre_clone); 876 free_stree(&false_states); 877 push_stree(&false_stack, pre_clone); 878 } 879 880 void __push_true_states(void) 881 { 882 push_stree(&true_stack, clone_stree(cur_stree)); 883 } 884 885 void __use_false_states(void) 886 { 887 free_stree(&cur_stree); 888 cur_stree = pop_stree(&false_stack); 889 } 890 891 void __discard_false_states(void) 892 { 893 struct stree *stree; 894 895 stree = pop_stree(&false_stack); 896 free_stree(&stree); 897 } 898 899 void __merge_false_states(void) 900 { 901 struct stree *stree; 902 903 stree = pop_stree(&false_stack); 904 merge_stree(&cur_stree, stree); 905 free_stree(&stree); 906 } 907 908 /* 909 * This function probably seemed common sensical when I wrote it but, oh wow, 910 * does it look subtle in retrospect. Say we set a state on one side of the if 911 * else path but not on the other, then what we should record in the fake stree 912 * is the merged state. 913 * 914 * This function relies on the fact that the we always set the cur_stree as well 915 * and we already have the infrastructure to merge things correctly into the 916 * cur_stree. 917 * 918 * So instead of merging fake strees together which is probably a lot of work, 919 * we just use it as a list of set states and look up the actual current values 920 * in the cur_stree. 921 * 922 */ 923 static void update_stree_with_merged(struct stree **stree) 924 { 925 struct state_list *slist = NULL; 926 struct sm_state *sm, *new; 927 928 FOR_EACH_SM(*stree, sm) { 929 new = get_sm_state(sm->owner, sm->name, sm->sym); 930 if (!new) /* This can happen if we go out of scope */ 931 continue; 932 add_ptr_list(&slist, new); 933 } END_FOR_EACH_SM(sm); 934 935 FOR_EACH_PTR(slist, sm) { 936 overwrite_sm_state_stree(stree, sm); 937 } END_FOR_EACH_PTR(sm); 938 939 free_slist(&slist); 940 } 941 942 static void update_fake_stree_with_merged(void) 943 { 944 struct stree *stree; 945 946 if (!fake_cur_stree_stack) 947 return; 948 stree = pop_stree(&fake_cur_stree_stack); 949 update_stree_with_merged(&stree); 950 push_stree(&fake_cur_stree_stack, stree); 951 } 952 953 void __merge_true_states(void) 954 { 955 struct stree *stree; 956 957 stree = pop_stree(&true_stack); 958 merge_stree(&cur_stree, stree); 959 update_fake_stree_with_merged(); 960 free_stree(&stree); 961 } 962 963 void __push_continues(void) 964 { 965 push_stree(&continue_stack, NULL); 966 } 967 968 void __discard_continues(void) 969 { 970 struct stree *stree; 971 972 stree = pop_stree(&continue_stack); 973 free_stree(&stree); 974 } 975 976 void __process_continues(void) 977 { 978 struct stree *stree; 979 980 stree = pop_stree(&continue_stack); 981 if (!stree) 982 stree = clone_stree(cur_stree); 983 else 984 merge_stree(&stree, cur_stree); 985 986 push_stree(&continue_stack, stree); 987 } 988 989 void __merge_continues(void) 990 { 991 struct stree *stree; 992 993 stree = pop_stree(&continue_stack); 994 merge_stree(&cur_stree, stree); 995 free_stree(&stree); 996 } 997 998 void __push_breaks(void) 999 { 1000 push_stree(&break_stack, NULL); 1001 if (fake_cur_stree_stack) 1002 push_stree(&fake_break_stack, NULL); 1003 } 1004 1005 void __process_breaks(void) 1006 { 1007 struct stree *stree; 1008 1009 stree = pop_stree(&break_stack); 1010 if (!stree) 1011 stree = clone_stree(cur_stree); 1012 else 1013 merge_stree(&stree, cur_stree); 1014 push_stree(&break_stack, stree); 1015 1016 if (!fake_cur_stree_stack) 1017 return; 1018 1019 stree = pop_stree(&fake_break_stack); 1020 if (!stree) 1021 stree = clone_stree(top_stree(fake_cur_stree_stack)); 1022 else 1023 merge_stree(&stree, top_stree(fake_cur_stree_stack)); 1024 push_stree(&fake_break_stack, stree); 1025 } 1026 1027 int __has_breaks(void) 1028 { 1029 struct stree *stree; 1030 int ret; 1031 1032 stree = pop_stree(&break_stack); 1033 ret = !!stree; 1034 push_stree(&break_stack, stree); 1035 return ret; 1036 } 1037 1038 void __merge_breaks(void) 1039 { 1040 struct stree *stree; 1041 struct sm_state *sm; 1042 1043 stree = pop_stree(&break_stack); 1044 merge_stree(&cur_stree, stree); 1045 free_stree(&stree); 1046 1047 if (!fake_cur_stree_stack) 1048 return; 1049 1050 stree = pop_stree(&fake_break_stack); 1051 update_stree_with_merged(&stree); 1052 FOR_EACH_SM(stree, sm) { 1053 overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm); 1054 } END_FOR_EACH_SM(sm); 1055 free_stree(&stree); 1056 } 1057 1058 void __use_breaks(void) 1059 { 1060 struct stree *stree; 1061 struct sm_state *sm; 1062 1063 free_stree(&cur_stree); 1064 cur_stree = pop_stree(&break_stack); 1065 1066 if (!fake_cur_stree_stack) 1067 return; 1068 stree = pop_stree(&fake_break_stack); 1069 FOR_EACH_SM(stree, sm) { 1070 overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm); 1071 } END_FOR_EACH_SM(sm); 1072 free_stree(&stree); 1073 1074 1075 } 1076 1077 void __save_switch_states(struct expression *switch_expr) 1078 { 1079 struct range_list *rl; 1080 1081 get_absolute_rl(switch_expr, &rl); 1082 1083 push_rl(&remaining_cases, rl); 1084 push_stree(&switch_stack, clone_stree(cur_stree)); 1085 } 1086 1087 int have_remaining_cases(void) 1088 { 1089 return !!top_rl(remaining_cases); 1090 } 1091 1092 void __merge_switches(struct expression *switch_expr, struct range_list *case_rl) 1093 { 1094 struct stree *stree; 1095 struct stree *implied_stree; 1096 1097 stree = pop_stree(&switch_stack); 1098 if (!stree) { 1099 /* 1100 * If the cur_stree was NULL before the start of the switch 1101 * statement then we don't want to unnullify it. 1102 * 1103 */ 1104 push_stree(&switch_stack, stree); 1105 return; 1106 } 1107 implied_stree = __implied_case_stree(switch_expr, case_rl, &remaining_cases, &stree); 1108 merge_stree(&cur_stree, implied_stree); 1109 free_stree(&implied_stree); 1110 push_stree(&switch_stack, stree); 1111 } 1112 1113 void __discard_switches(void) 1114 { 1115 struct stree *stree; 1116 1117 pop_rl(&remaining_cases); 1118 stree = pop_stree(&switch_stack); 1119 free_stree(&stree); 1120 } 1121 1122 void __push_default(void) 1123 { 1124 push_stree(&default_stack, NULL); 1125 } 1126 1127 void __set_default(void) 1128 { 1129 set_state_stree_stack(&default_stack, 0, "has_default", NULL, &true_state); 1130 } 1131 1132 int __pop_default(void) 1133 { 1134 struct stree *stree; 1135 1136 stree = pop_stree(&default_stack); 1137 if (stree) { 1138 free_stree(&stree); 1139 return 1; 1140 } 1141 return 0; 1142 } 1143 1144 static struct named_stree *alloc_named_stree(const char *name, struct symbol *sym, struct stree *stree) 1145 { 1146 struct named_stree *named_stree = __alloc_named_stree(0); 1147 1148 named_stree->name = (char *)name; 1149 named_stree->stree = stree; 1150 named_stree->sym = sym; 1151 return named_stree; 1152 } 1153 1154 void __save_gotos(const char *name, struct symbol *sym) 1155 { 1156 struct stree **stree; 1157 struct stree *clone; 1158 1159 stree = get_named_stree(goto_stack, name, sym); 1160 if (stree) { 1161 merge_stree(stree, cur_stree); 1162 return; 1163 } else { 1164 struct named_stree *named_stree; 1165 1166 clone = clone_stree(cur_stree); 1167 named_stree = alloc_named_stree(name, sym, clone); 1168 add_ptr_list(&goto_stack, named_stree); 1169 } 1170 } 1171 1172 void __merge_gotos(const char *name, struct symbol *sym) 1173 { 1174 struct stree **stree; 1175 1176 stree = get_named_stree(goto_stack, name, sym); 1177 if (stree) 1178 merge_stree(&cur_stree, *stree); 1179 } 1180