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