1 /* 2 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 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/licenses/>. 16 */ 17 18 /* 19 * objtool check: 20 * 21 * This command analyzes every .o file and ensures the validity of its stack 22 * trace metadata. It enforces a set of rules on asm code and C inline 23 * assembly code so that stack traces can be reliable. 24 * 25 * For more information, see tools/objtool/Documentation/stack-validation.txt. 26 */ 27 28 #include <string.h> 29 #include <subcmd/parse-options.h> 30 31 #include "builtin.h" 32 #include "elf.h" 33 #include "special.h" 34 #include "arch.h" 35 #include "warn.h" 36 37 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 38 39 #define STATE_FP_SAVED 0x1 40 #define STATE_FP_SETUP 0x2 41 #define STATE_FENTRY 0x4 42 43 struct instruction { 44 struct list_head list; 45 struct section *sec; 46 unsigned long offset; 47 unsigned int len, state; 48 unsigned char type; 49 unsigned long immediate; 50 bool alt_group, visited; 51 struct symbol *call_dest; 52 struct instruction *jump_dest; 53 struct list_head alts; 54 }; 55 56 struct alternative { 57 struct list_head list; 58 struct instruction *insn; 59 }; 60 61 struct objtool_file { 62 struct elf *elf; 63 struct list_head insn_list; 64 struct section *rodata; 65 }; 66 67 const char *objname; 68 static bool nofp; 69 70 static struct instruction *find_insn(struct objtool_file *file, 71 struct section *sec, unsigned long offset) 72 { 73 struct instruction *insn; 74 75 list_for_each_entry(insn, &file->insn_list, list) 76 if (insn->sec == sec && insn->offset == offset) 77 return insn; 78 79 return NULL; 80 } 81 82 static struct instruction *next_insn_same_sec(struct objtool_file *file, 83 struct instruction *insn) 84 { 85 struct instruction *next = list_next_entry(insn, list); 86 87 if (&next->list == &file->insn_list || next->sec != insn->sec) 88 return NULL; 89 90 return next; 91 } 92 93 #define for_each_insn(file, insn) \ 94 list_for_each_entry(insn, &file->insn_list, list) 95 96 #define func_for_each_insn(file, func, insn) \ 97 for (insn = find_insn(file, func->sec, func->offset); \ 98 insn && &insn->list != &file->insn_list && \ 99 insn->sec == func->sec && \ 100 insn->offset < func->offset + func->len; \ 101 insn = list_next_entry(insn, list)) 102 103 #define sec_for_each_insn_from(file, insn) \ 104 for (; insn; insn = next_insn_same_sec(file, insn)) 105 106 107 /* 108 * Check if the function has been manually whitelisted with the 109 * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted 110 * due to its use of a context switching instruction. 111 */ 112 static bool ignore_func(struct objtool_file *file, struct symbol *func) 113 { 114 struct section *macro_sec; 115 struct rela *rela; 116 struct instruction *insn; 117 118 /* check for STACK_FRAME_NON_STANDARD */ 119 macro_sec = find_section_by_name(file->elf, "__func_stack_frame_non_standard"); 120 if (macro_sec && macro_sec->rela) 121 list_for_each_entry(rela, ¯o_sec->rela->rela_list, list) 122 if (rela->sym->sec == func->sec && 123 rela->addend == func->offset) 124 return true; 125 126 /* check if it has a context switching instruction */ 127 func_for_each_insn(file, func, insn) 128 if (insn->type == INSN_CONTEXT_SWITCH) 129 return true; 130 131 return false; 132 } 133 134 /* 135 * This checks to see if the given function is a "noreturn" function. 136 * 137 * For global functions which are outside the scope of this object file, we 138 * have to keep a manual list of them. 139 * 140 * For local functions, we have to detect them manually by simply looking for 141 * the lack of a return instruction. 142 * 143 * Returns: 144 * -1: error 145 * 0: no dead end 146 * 1: dead end 147 */ 148 static int __dead_end_function(struct objtool_file *file, struct symbol *func, 149 int recursion) 150 { 151 int i; 152 struct instruction *insn; 153 bool empty = true; 154 155 /* 156 * Unfortunately these have to be hard coded because the noreturn 157 * attribute isn't provided in ELF data. 158 */ 159 static const char * const global_noreturns[] = { 160 "__stack_chk_fail", 161 "panic", 162 "do_exit", 163 "__module_put_and_exit", 164 "complete_and_exit", 165 "kvm_spurious_fault", 166 "__reiserfs_panic", 167 "lbug_with_loc" 168 }; 169 170 if (func->bind == STB_WEAK) 171 return 0; 172 173 if (func->bind == STB_GLOBAL) 174 for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) 175 if (!strcmp(func->name, global_noreturns[i])) 176 return 1; 177 178 if (!func->sec) 179 return 0; 180 181 func_for_each_insn(file, func, insn) { 182 empty = false; 183 184 if (insn->type == INSN_RETURN) 185 return 0; 186 } 187 188 if (empty) 189 return 0; 190 191 /* 192 * A function can have a sibling call instead of a return. In that 193 * case, the function's dead-end status depends on whether the target 194 * of the sibling call returns. 195 */ 196 func_for_each_insn(file, func, insn) { 197 if (insn->sec != func->sec || 198 insn->offset >= func->offset + func->len) 199 break; 200 201 if (insn->type == INSN_JUMP_UNCONDITIONAL) { 202 struct instruction *dest = insn->jump_dest; 203 struct symbol *dest_func; 204 205 if (!dest) 206 /* sibling call to another file */ 207 return 0; 208 209 if (dest->sec != func->sec || 210 dest->offset < func->offset || 211 dest->offset >= func->offset + func->len) { 212 /* local sibling call */ 213 dest_func = find_symbol_by_offset(dest->sec, 214 dest->offset); 215 if (!dest_func) 216 continue; 217 218 if (recursion == 5) { 219 WARN_FUNC("infinite recursion (objtool bug!)", 220 dest->sec, dest->offset); 221 return -1; 222 } 223 224 return __dead_end_function(file, dest_func, 225 recursion + 1); 226 } 227 } 228 229 if (insn->type == INSN_JUMP_DYNAMIC) 230 /* sibling call */ 231 return 0; 232 } 233 234 return 1; 235 } 236 237 static int dead_end_function(struct objtool_file *file, struct symbol *func) 238 { 239 return __dead_end_function(file, func, 0); 240 } 241 242 /* 243 * Call the arch-specific instruction decoder for all the instructions and add 244 * them to the global instruction list. 245 */ 246 static int decode_instructions(struct objtool_file *file) 247 { 248 struct section *sec; 249 unsigned long offset; 250 struct instruction *insn; 251 int ret; 252 253 list_for_each_entry(sec, &file->elf->sections, list) { 254 255 if (!(sec->sh.sh_flags & SHF_EXECINSTR)) 256 continue; 257 258 for (offset = 0; offset < sec->len; offset += insn->len) { 259 insn = malloc(sizeof(*insn)); 260 memset(insn, 0, sizeof(*insn)); 261 262 INIT_LIST_HEAD(&insn->alts); 263 insn->sec = sec; 264 insn->offset = offset; 265 266 ret = arch_decode_instruction(file->elf, sec, offset, 267 sec->len - offset, 268 &insn->len, &insn->type, 269 &insn->immediate); 270 if (ret) 271 return ret; 272 273 if (!insn->type || insn->type > INSN_LAST) { 274 WARN_FUNC("invalid instruction type %d", 275 insn->sec, insn->offset, insn->type); 276 return -1; 277 } 278 279 list_add_tail(&insn->list, &file->insn_list); 280 } 281 } 282 283 return 0; 284 } 285 286 /* 287 * Warnings shouldn't be reported for ignored functions. 288 */ 289 static void add_ignores(struct objtool_file *file) 290 { 291 struct instruction *insn; 292 struct section *sec; 293 struct symbol *func; 294 295 list_for_each_entry(sec, &file->elf->sections, list) { 296 list_for_each_entry(func, &sec->symbol_list, list) { 297 if (func->type != STT_FUNC) 298 continue; 299 300 if (!ignore_func(file, func)) 301 continue; 302 303 func_for_each_insn(file, func, insn) 304 insn->visited = true; 305 } 306 } 307 } 308 309 /* 310 * Find the destination instructions for all jumps. 311 */ 312 static int add_jump_destinations(struct objtool_file *file) 313 { 314 struct instruction *insn; 315 struct rela *rela; 316 struct section *dest_sec; 317 unsigned long dest_off; 318 319 for_each_insn(file, insn) { 320 if (insn->type != INSN_JUMP_CONDITIONAL && 321 insn->type != INSN_JUMP_UNCONDITIONAL) 322 continue; 323 324 /* skip ignores */ 325 if (insn->visited) 326 continue; 327 328 rela = find_rela_by_dest_range(insn->sec, insn->offset, 329 insn->len); 330 if (!rela) { 331 dest_sec = insn->sec; 332 dest_off = insn->offset + insn->len + insn->immediate; 333 } else if (rela->sym->type == STT_SECTION) { 334 dest_sec = rela->sym->sec; 335 dest_off = rela->addend + 4; 336 } else if (rela->sym->sec->idx) { 337 dest_sec = rela->sym->sec; 338 dest_off = rela->sym->sym.st_value + rela->addend + 4; 339 } else { 340 /* sibling call */ 341 insn->jump_dest = 0; 342 continue; 343 } 344 345 insn->jump_dest = find_insn(file, dest_sec, dest_off); 346 if (!insn->jump_dest) { 347 348 /* 349 * This is a special case where an alt instruction 350 * jumps past the end of the section. These are 351 * handled later in handle_group_alt(). 352 */ 353 if (!strcmp(insn->sec->name, ".altinstr_replacement")) 354 continue; 355 356 WARN_FUNC("can't find jump dest instruction at %s+0x%lx", 357 insn->sec, insn->offset, dest_sec->name, 358 dest_off); 359 return -1; 360 } 361 } 362 363 return 0; 364 } 365 366 /* 367 * Find the destination instructions for all calls. 368 */ 369 static int add_call_destinations(struct objtool_file *file) 370 { 371 struct instruction *insn; 372 unsigned long dest_off; 373 struct rela *rela; 374 375 for_each_insn(file, insn) { 376 if (insn->type != INSN_CALL) 377 continue; 378 379 rela = find_rela_by_dest_range(insn->sec, insn->offset, 380 insn->len); 381 if (!rela) { 382 dest_off = insn->offset + insn->len + insn->immediate; 383 insn->call_dest = find_symbol_by_offset(insn->sec, 384 dest_off); 385 if (!insn->call_dest) { 386 WARN_FUNC("can't find call dest symbol at offset 0x%lx", 387 insn->sec, insn->offset, dest_off); 388 return -1; 389 } 390 } else if (rela->sym->type == STT_SECTION) { 391 insn->call_dest = find_symbol_by_offset(rela->sym->sec, 392 rela->addend+4); 393 if (!insn->call_dest || 394 insn->call_dest->type != STT_FUNC) { 395 WARN_FUNC("can't find call dest symbol at %s+0x%x", 396 insn->sec, insn->offset, 397 rela->sym->sec->name, 398 rela->addend + 4); 399 return -1; 400 } 401 } else 402 insn->call_dest = rela->sym; 403 } 404 405 return 0; 406 } 407 408 /* 409 * The .alternatives section requires some extra special care, over and above 410 * what other special sections require: 411 * 412 * 1. Because alternatives are patched in-place, we need to insert a fake jump 413 * instruction at the end so that validate_branch() skips all the original 414 * replaced instructions when validating the new instruction path. 415 * 416 * 2. An added wrinkle is that the new instruction length might be zero. In 417 * that case the old instructions are replaced with noops. We simulate that 418 * by creating a fake jump as the only new instruction. 419 * 420 * 3. In some cases, the alternative section includes an instruction which 421 * conditionally jumps to the _end_ of the entry. We have to modify these 422 * jumps' destinations to point back to .text rather than the end of the 423 * entry in .altinstr_replacement. 424 * 425 * 4. It has been requested that we don't validate the !POPCNT feature path 426 * which is a "very very small percentage of machines". 427 */ 428 static int handle_group_alt(struct objtool_file *file, 429 struct special_alt *special_alt, 430 struct instruction *orig_insn, 431 struct instruction **new_insn) 432 { 433 struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; 434 unsigned long dest_off; 435 436 last_orig_insn = NULL; 437 insn = orig_insn; 438 sec_for_each_insn_from(file, insn) { 439 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) 440 break; 441 442 if (special_alt->skip_orig) 443 insn->type = INSN_NOP; 444 445 insn->alt_group = true; 446 last_orig_insn = insn; 447 } 448 449 if (!next_insn_same_sec(file, last_orig_insn)) { 450 WARN("%s: don't know how to handle alternatives at end of section", 451 special_alt->orig_sec->name); 452 return -1; 453 } 454 455 fake_jump = malloc(sizeof(*fake_jump)); 456 if (!fake_jump) { 457 WARN("malloc failed"); 458 return -1; 459 } 460 memset(fake_jump, 0, sizeof(*fake_jump)); 461 INIT_LIST_HEAD(&fake_jump->alts); 462 fake_jump->sec = special_alt->new_sec; 463 fake_jump->offset = -1; 464 fake_jump->type = INSN_JUMP_UNCONDITIONAL; 465 fake_jump->jump_dest = list_next_entry(last_orig_insn, list); 466 467 if (!special_alt->new_len) { 468 *new_insn = fake_jump; 469 return 0; 470 } 471 472 last_new_insn = NULL; 473 insn = *new_insn; 474 sec_for_each_insn_from(file, insn) { 475 if (insn->offset >= special_alt->new_off + special_alt->new_len) 476 break; 477 478 last_new_insn = insn; 479 480 if (insn->type != INSN_JUMP_CONDITIONAL && 481 insn->type != INSN_JUMP_UNCONDITIONAL) 482 continue; 483 484 if (!insn->immediate) 485 continue; 486 487 dest_off = insn->offset + insn->len + insn->immediate; 488 if (dest_off == special_alt->new_off + special_alt->new_len) 489 insn->jump_dest = fake_jump; 490 491 if (!insn->jump_dest) { 492 WARN_FUNC("can't find alternative jump destination", 493 insn->sec, insn->offset); 494 return -1; 495 } 496 } 497 498 if (!last_new_insn) { 499 WARN_FUNC("can't find last new alternative instruction", 500 special_alt->new_sec, special_alt->new_off); 501 return -1; 502 } 503 504 list_add(&fake_jump->list, &last_new_insn->list); 505 506 return 0; 507 } 508 509 /* 510 * A jump table entry can either convert a nop to a jump or a jump to a nop. 511 * If the original instruction is a jump, make the alt entry an effective nop 512 * by just skipping the original instruction. 513 */ 514 static int handle_jump_alt(struct objtool_file *file, 515 struct special_alt *special_alt, 516 struct instruction *orig_insn, 517 struct instruction **new_insn) 518 { 519 if (orig_insn->type == INSN_NOP) 520 return 0; 521 522 if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { 523 WARN_FUNC("unsupported instruction at jump label", 524 orig_insn->sec, orig_insn->offset); 525 return -1; 526 } 527 528 *new_insn = list_next_entry(orig_insn, list); 529 return 0; 530 } 531 532 /* 533 * Read all the special sections which have alternate instructions which can be 534 * patched in or redirected to at runtime. Each instruction having alternate 535 * instruction(s) has them added to its insn->alts list, which will be 536 * traversed in validate_branch(). 537 */ 538 static int add_special_section_alts(struct objtool_file *file) 539 { 540 struct list_head special_alts; 541 struct instruction *orig_insn, *new_insn; 542 struct special_alt *special_alt, *tmp; 543 struct alternative *alt; 544 int ret; 545 546 ret = special_get_alts(file->elf, &special_alts); 547 if (ret) 548 return ret; 549 550 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { 551 alt = malloc(sizeof(*alt)); 552 if (!alt) { 553 WARN("malloc failed"); 554 ret = -1; 555 goto out; 556 } 557 558 orig_insn = find_insn(file, special_alt->orig_sec, 559 special_alt->orig_off); 560 if (!orig_insn) { 561 WARN_FUNC("special: can't find orig instruction", 562 special_alt->orig_sec, special_alt->orig_off); 563 ret = -1; 564 goto out; 565 } 566 567 new_insn = NULL; 568 if (!special_alt->group || special_alt->new_len) { 569 new_insn = find_insn(file, special_alt->new_sec, 570 special_alt->new_off); 571 if (!new_insn) { 572 WARN_FUNC("special: can't find new instruction", 573 special_alt->new_sec, 574 special_alt->new_off); 575 ret = -1; 576 goto out; 577 } 578 } 579 580 if (special_alt->group) { 581 ret = handle_group_alt(file, special_alt, orig_insn, 582 &new_insn); 583 if (ret) 584 goto out; 585 } else if (special_alt->jump_or_nop) { 586 ret = handle_jump_alt(file, special_alt, orig_insn, 587 &new_insn); 588 if (ret) 589 goto out; 590 } 591 592 alt->insn = new_insn; 593 list_add_tail(&alt->list, &orig_insn->alts); 594 595 list_del(&special_alt->list); 596 free(special_alt); 597 } 598 599 out: 600 return ret; 601 } 602 603 static int add_switch_table(struct objtool_file *file, struct symbol *func, 604 struct instruction *insn, struct rela *table, 605 struct rela *next_table) 606 { 607 struct rela *rela = table; 608 struct instruction *alt_insn; 609 struct alternative *alt; 610 611 list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { 612 if (rela == next_table) 613 break; 614 615 if (rela->sym->sec != insn->sec || 616 rela->addend <= func->offset || 617 rela->addend >= func->offset + func->len) 618 break; 619 620 alt_insn = find_insn(file, insn->sec, rela->addend); 621 if (!alt_insn) { 622 WARN("%s: can't find instruction at %s+0x%x", 623 file->rodata->rela->name, insn->sec->name, 624 rela->addend); 625 return -1; 626 } 627 628 alt = malloc(sizeof(*alt)); 629 if (!alt) { 630 WARN("malloc failed"); 631 return -1; 632 } 633 634 alt->insn = alt_insn; 635 list_add_tail(&alt->list, &insn->alts); 636 } 637 638 return 0; 639 } 640 641 static int add_func_switch_tables(struct objtool_file *file, 642 struct symbol *func) 643 { 644 struct instruction *insn, *prev_jump; 645 struct rela *text_rela, *rodata_rela, *prev_rela; 646 int ret; 647 648 prev_jump = NULL; 649 650 func_for_each_insn(file, func, insn) { 651 if (insn->type != INSN_JUMP_DYNAMIC) 652 continue; 653 654 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, 655 insn->len); 656 if (!text_rela || text_rela->sym != file->rodata->sym) 657 continue; 658 659 /* common case: jmpq *[addr](,%rax,8) */ 660 rodata_rela = find_rela_by_dest(file->rodata, 661 text_rela->addend); 662 663 /* 664 * TODO: Document where this is needed, or get rid of it. 665 * 666 * rare case: jmpq *[addr](%rip) 667 */ 668 if (!rodata_rela) 669 rodata_rela = find_rela_by_dest(file->rodata, 670 text_rela->addend + 4); 671 672 if (!rodata_rela) 673 continue; 674 675 /* 676 * We found a switch table, but we don't know yet how big it 677 * is. Don't add it until we reach the end of the function or 678 * the beginning of another switch table in the same function. 679 */ 680 if (prev_jump) { 681 ret = add_switch_table(file, func, prev_jump, prev_rela, 682 rodata_rela); 683 if (ret) 684 return ret; 685 } 686 687 prev_jump = insn; 688 prev_rela = rodata_rela; 689 } 690 691 if (prev_jump) { 692 ret = add_switch_table(file, func, prev_jump, prev_rela, NULL); 693 if (ret) 694 return ret; 695 } 696 697 return 0; 698 } 699 700 /* 701 * For some switch statements, gcc generates a jump table in the .rodata 702 * section which contains a list of addresses within the function to jump to. 703 * This finds these jump tables and adds them to the insn->alts lists. 704 */ 705 static int add_switch_table_alts(struct objtool_file *file) 706 { 707 struct section *sec; 708 struct symbol *func; 709 int ret; 710 711 if (!file->rodata || !file->rodata->rela) 712 return 0; 713 714 list_for_each_entry(sec, &file->elf->sections, list) { 715 list_for_each_entry(func, &sec->symbol_list, list) { 716 if (func->type != STT_FUNC) 717 continue; 718 719 ret = add_func_switch_tables(file, func); 720 if (ret) 721 return ret; 722 } 723 } 724 725 return 0; 726 } 727 728 static int decode_sections(struct objtool_file *file) 729 { 730 int ret; 731 732 file->rodata = find_section_by_name(file->elf, ".rodata"); 733 734 ret = decode_instructions(file); 735 if (ret) 736 return ret; 737 738 add_ignores(file); 739 740 ret = add_jump_destinations(file); 741 if (ret) 742 return ret; 743 744 ret = add_call_destinations(file); 745 if (ret) 746 return ret; 747 748 ret = add_special_section_alts(file); 749 if (ret) 750 return ret; 751 752 ret = add_switch_table_alts(file); 753 if (ret) 754 return ret; 755 756 return 0; 757 } 758 759 static bool is_fentry_call(struct instruction *insn) 760 { 761 if (insn->type == INSN_CALL && 762 insn->call_dest->type == STT_NOTYPE && 763 !strcmp(insn->call_dest->name, "__fentry__")) 764 return true; 765 766 return false; 767 } 768 769 static bool has_modified_stack_frame(struct instruction *insn) 770 { 771 return (insn->state & STATE_FP_SAVED) || 772 (insn->state & STATE_FP_SETUP); 773 } 774 775 static bool has_valid_stack_frame(struct instruction *insn) 776 { 777 return (insn->state & STATE_FP_SAVED) && 778 (insn->state & STATE_FP_SETUP); 779 } 780 781 static unsigned int frame_state(unsigned long state) 782 { 783 return (state & (STATE_FP_SAVED | STATE_FP_SETUP)); 784 } 785 786 /* 787 * Follow the branch starting at the given instruction, and recursively follow 788 * any other branches (jumps). Meanwhile, track the frame pointer state at 789 * each instruction and validate all the rules described in 790 * tools/objtool/Documentation/stack-validation.txt. 791 */ 792 static int validate_branch(struct objtool_file *file, 793 struct instruction *first, unsigned char first_state) 794 { 795 struct alternative *alt; 796 struct instruction *insn; 797 struct section *sec; 798 unsigned char state; 799 int ret, warnings = 0; 800 801 insn = first; 802 sec = insn->sec; 803 state = first_state; 804 805 if (insn->alt_group && list_empty(&insn->alts)) { 806 WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", 807 sec, insn->offset); 808 warnings++; 809 } 810 811 while (1) { 812 if (insn->visited) { 813 if (frame_state(insn->state) != frame_state(state)) { 814 WARN_FUNC("frame pointer state mismatch", 815 sec, insn->offset); 816 warnings++; 817 } 818 819 return warnings; 820 } 821 822 /* 823 * Catch a rare case where a noreturn function falls through to 824 * the next function. 825 */ 826 if (is_fentry_call(insn) && (state & STATE_FENTRY)) 827 return warnings; 828 829 insn->visited = true; 830 insn->state = state; 831 832 list_for_each_entry(alt, &insn->alts, list) { 833 ret = validate_branch(file, alt->insn, state); 834 warnings += ret; 835 } 836 837 switch (insn->type) { 838 839 case INSN_FP_SAVE: 840 if (!nofp) { 841 if (state & STATE_FP_SAVED) { 842 WARN_FUNC("duplicate frame pointer save", 843 sec, insn->offset); 844 warnings++; 845 } 846 state |= STATE_FP_SAVED; 847 } 848 break; 849 850 case INSN_FP_SETUP: 851 if (!nofp) { 852 if (state & STATE_FP_SETUP) { 853 WARN_FUNC("duplicate frame pointer setup", 854 sec, insn->offset); 855 warnings++; 856 } 857 state |= STATE_FP_SETUP; 858 } 859 break; 860 861 case INSN_FP_RESTORE: 862 if (!nofp) { 863 if (has_valid_stack_frame(insn)) 864 state &= ~STATE_FP_SETUP; 865 866 state &= ~STATE_FP_SAVED; 867 } 868 break; 869 870 case INSN_RETURN: 871 if (!nofp && has_modified_stack_frame(insn)) { 872 WARN_FUNC("return without frame pointer restore", 873 sec, insn->offset); 874 warnings++; 875 } 876 return warnings; 877 878 case INSN_CALL: 879 if (is_fentry_call(insn)) { 880 state |= STATE_FENTRY; 881 break; 882 } 883 884 ret = dead_end_function(file, insn->call_dest); 885 if (ret == 1) 886 return warnings; 887 if (ret == -1) 888 warnings++; 889 890 /* fallthrough */ 891 case INSN_CALL_DYNAMIC: 892 if (!nofp && !has_valid_stack_frame(insn)) { 893 WARN_FUNC("call without frame pointer save/setup", 894 sec, insn->offset); 895 warnings++; 896 } 897 break; 898 899 case INSN_JUMP_CONDITIONAL: 900 case INSN_JUMP_UNCONDITIONAL: 901 if (insn->jump_dest) { 902 ret = validate_branch(file, insn->jump_dest, 903 state); 904 warnings += ret; 905 } else if (has_modified_stack_frame(insn)) { 906 WARN_FUNC("sibling call from callable instruction with changed frame pointer", 907 sec, insn->offset); 908 warnings++; 909 } /* else it's a sibling call */ 910 911 if (insn->type == INSN_JUMP_UNCONDITIONAL) 912 return warnings; 913 914 break; 915 916 case INSN_JUMP_DYNAMIC: 917 if (list_empty(&insn->alts) && 918 has_modified_stack_frame(insn)) { 919 WARN_FUNC("sibling call from callable instruction with changed frame pointer", 920 sec, insn->offset); 921 warnings++; 922 } 923 924 return warnings; 925 926 case INSN_BUG: 927 return warnings; 928 929 default: 930 break; 931 } 932 933 insn = next_insn_same_sec(file, insn); 934 if (!insn) { 935 WARN("%s: unexpected end of section", sec->name); 936 warnings++; 937 return warnings; 938 } 939 } 940 941 return warnings; 942 } 943 944 static bool is_gcov_insn(struct instruction *insn) 945 { 946 struct rela *rela; 947 struct section *sec; 948 struct symbol *sym; 949 unsigned long offset; 950 951 rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); 952 if (!rela) 953 return false; 954 955 if (rela->sym->type != STT_SECTION) 956 return false; 957 958 sec = rela->sym->sec; 959 offset = rela->addend + insn->offset + insn->len - rela->offset; 960 961 list_for_each_entry(sym, &sec->symbol_list, list) { 962 if (sym->type != STT_OBJECT) 963 continue; 964 965 if (offset >= sym->offset && offset < sym->offset + sym->len) 966 return (!memcmp(sym->name, "__gcov0.", 8)); 967 } 968 969 return false; 970 } 971 972 static bool is_kasan_insn(struct instruction *insn) 973 { 974 return (insn->type == INSN_CALL && 975 !strcmp(insn->call_dest->name, "__asan_handle_no_return")); 976 } 977 978 static bool is_ubsan_insn(struct instruction *insn) 979 { 980 return (insn->type == INSN_CALL && 981 !strcmp(insn->call_dest->name, 982 "__ubsan_handle_builtin_unreachable")); 983 } 984 985 static bool ignore_unreachable_insn(struct symbol *func, 986 struct instruction *insn) 987 { 988 int i; 989 990 if (insn->type == INSN_NOP) 991 return true; 992 993 if (is_gcov_insn(insn)) 994 return true; 995 996 /* 997 * Check if this (or a subsequent) instruction is related to 998 * CONFIG_UBSAN or CONFIG_KASAN. 999 * 1000 * End the search at 5 instructions to avoid going into the weeds. 1001 */ 1002 for (i = 0; i < 5; i++) { 1003 1004 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) 1005 return true; 1006 1007 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { 1008 insn = insn->jump_dest; 1009 continue; 1010 } 1011 1012 if (insn->offset + insn->len >= func->offset + func->len) 1013 break; 1014 insn = list_next_entry(insn, list); 1015 } 1016 1017 return false; 1018 } 1019 1020 static int validate_functions(struct objtool_file *file) 1021 { 1022 struct section *sec; 1023 struct symbol *func; 1024 struct instruction *insn; 1025 int ret, warnings = 0; 1026 1027 list_for_each_entry(sec, &file->elf->sections, list) { 1028 list_for_each_entry(func, &sec->symbol_list, list) { 1029 if (func->type != STT_FUNC) 1030 continue; 1031 1032 insn = find_insn(file, sec, func->offset); 1033 if (!insn) { 1034 WARN("%s(): can't find starting instruction", 1035 func->name); 1036 warnings++; 1037 continue; 1038 } 1039 1040 ret = validate_branch(file, insn, 0); 1041 warnings += ret; 1042 } 1043 } 1044 1045 list_for_each_entry(sec, &file->elf->sections, list) { 1046 list_for_each_entry(func, &sec->symbol_list, list) { 1047 if (func->type != STT_FUNC) 1048 continue; 1049 1050 func_for_each_insn(file, func, insn) { 1051 if (insn->visited) 1052 continue; 1053 1054 if (!ignore_unreachable_insn(func, insn)) { 1055 WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); 1056 warnings++; 1057 } 1058 1059 insn->visited = true; 1060 } 1061 } 1062 } 1063 1064 return warnings; 1065 } 1066 1067 static int validate_uncallable_instructions(struct objtool_file *file) 1068 { 1069 struct instruction *insn; 1070 int warnings = 0; 1071 1072 for_each_insn(file, insn) { 1073 if (!insn->visited && insn->type == INSN_RETURN) { 1074 WARN_FUNC("return instruction outside of a callable function", 1075 insn->sec, insn->offset); 1076 warnings++; 1077 } 1078 } 1079 1080 return warnings; 1081 } 1082 1083 static void cleanup(struct objtool_file *file) 1084 { 1085 struct instruction *insn, *tmpinsn; 1086 struct alternative *alt, *tmpalt; 1087 1088 list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { 1089 list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { 1090 list_del(&alt->list); 1091 free(alt); 1092 } 1093 list_del(&insn->list); 1094 free(insn); 1095 } 1096 elf_close(file->elf); 1097 } 1098 1099 const char * const check_usage[] = { 1100 "objtool check [<options>] file.o", 1101 NULL, 1102 }; 1103 1104 int cmd_check(int argc, const char **argv) 1105 { 1106 struct objtool_file file; 1107 int ret, warnings = 0; 1108 1109 const struct option options[] = { 1110 OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), 1111 OPT_END(), 1112 }; 1113 1114 argc = parse_options(argc, argv, options, check_usage, 0); 1115 1116 if (argc != 1) 1117 usage_with_options(check_usage, options); 1118 1119 objname = argv[0]; 1120 1121 file.elf = elf_open(objname); 1122 if (!file.elf) { 1123 fprintf(stderr, "error reading elf file %s\n", objname); 1124 return 1; 1125 } 1126 1127 INIT_LIST_HEAD(&file.insn_list); 1128 1129 ret = decode_sections(&file); 1130 if (ret < 0) 1131 goto out; 1132 warnings += ret; 1133 1134 ret = validate_functions(&file); 1135 if (ret < 0) 1136 goto out; 1137 warnings += ret; 1138 1139 ret = validate_uncallable_instructions(&file); 1140 if (ret < 0) 1141 goto out; 1142 warnings += ret; 1143 1144 out: 1145 cleanup(&file); 1146 1147 /* ignore warnings for now until we get all the code cleaned up */ 1148 if (ret || warnings) 1149 return 0; 1150 return 0; 1151 } 1152