diff options
Diffstat (limited to 'scripts/mod')
| -rw-r--r-- | scripts/mod/modpost.c | 258 | ||||
| -rw-r--r-- | scripts/mod/modpost.h | 10 |
2 files changed, 268 insertions, 0 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index d901095ea8..a7360c379c 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
| @@ -451,6 +451,262 @@ static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | |||
| 451 | return NULL; | 451 | return NULL; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | /* | ||
| 455 | * Find symbols before or equal addr and after addr - in the section sec | ||
| 456 | **/ | ||
| 457 | static void find_symbols_between(struct elf_info *elf, Elf_Addr addr, | ||
| 458 | const char *sec, | ||
| 459 | Elf_Sym **before, Elf_Sym **after) | ||
| 460 | { | ||
| 461 | Elf_Sym *sym; | ||
| 462 | Elf_Ehdr *hdr = elf->hdr; | ||
| 463 | Elf_Addr beforediff = ~0; | ||
| 464 | Elf_Addr afterdiff = ~0; | ||
| 465 | const char *secstrings = (void *)hdr + | ||
| 466 | elf->sechdrs[hdr->e_shstrndx].sh_offset; | ||
| 467 | |||
| 468 | *before = NULL; | ||
| 469 | *after = NULL; | ||
| 470 | |||
| 471 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { | ||
| 472 | const char *symsec; | ||
| 473 | |||
| 474 | if (sym->st_shndx >= SHN_LORESERVE) | ||
| 475 | continue; | ||
| 476 | symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name; | ||
| 477 | if (strcmp(symsec, sec) != 0) | ||
| 478 | continue; | ||
| 479 | if (sym->st_value <= addr) { | ||
| 480 | if ((addr - sym->st_value) < beforediff) { | ||
| 481 | beforediff = addr - sym->st_value; | ||
| 482 | *before = sym; | ||
| 483 | } | ||
| 484 | } | ||
| 485 | else | ||
| 486 | { | ||
| 487 | if ((sym->st_value - addr) < afterdiff) { | ||
| 488 | afterdiff = sym->st_value - addr; | ||
| 489 | *after = sym; | ||
| 490 | } | ||
| 491 | } | ||
| 492 | } | ||
| 493 | } | ||
| 494 | |||
| 495 | /** | ||
| 496 | * Print a warning about a section mismatch. | ||
| 497 | * Try to find symbols near it so user can find it. | ||
| 498 | **/ | ||
| 499 | static void warn_sec_mismatch(const char *modname, const char *fromsec, | ||
| 500 | struct elf_info *elf, Elf_Sym *sym, Elf_Rela r) | ||
| 501 | { | ||
| 502 | Elf_Sym *before; | ||
| 503 | Elf_Sym *after; | ||
| 504 | Elf_Ehdr *hdr = elf->hdr; | ||
| 505 | Elf_Shdr *sechdrs = elf->sechdrs; | ||
| 506 | const char *secstrings = (void *)hdr + | ||
| 507 | sechdrs[hdr->e_shstrndx].sh_offset; | ||
| 508 | const char *secname = secstrings + sechdrs[sym->st_shndx].sh_name; | ||
| 509 | |||
| 510 | find_symbols_between(elf, r.r_offset, fromsec, &before, &after); | ||
| 511 | |||
| 512 | if (before && after) { | ||
| 513 | warn("%s - Section mismatch: reference to %s from %s " | ||
| 514 | "between '%s' (at offset 0x%lx) and '%s'\n", | ||
| 515 | modname, secname, fromsec, | ||
| 516 | elf->strtab + before->st_name, | ||
| 517 | (long)(r.r_offset - before->st_value), | ||
| 518 | elf->strtab + after->st_name); | ||
| 519 | } else if (before) { | ||
| 520 | warn("%s - Section mismatch: reference to %s from %s " | ||
| 521 | "after '%s' (at offset 0x%lx)\n", | ||
| 522 | modname, secname, fromsec, | ||
| 523 | elf->strtab + before->st_name, | ||
| 524 | (long)(r.r_offset - before->st_value)); | ||
| 525 | } else if (after) { | ||
| 526 | warn("%s - Section mismatch: reference to %s from %s " | ||
| 527 | "before '%s' (at offset -0x%lx)\n", | ||
| 528 | modname, secname, fromsec, | ||
| 529 | elf->strtab + before->st_name, | ||
| 530 | (long)(before->st_value - r.r_offset)); | ||
| 531 | } else { | ||
| 532 | warn("%s - Section mismatch: reference to %s from %s " | ||
| 533 | "(offset 0x%lx)\n", | ||
| 534 | modname, secname, fromsec, (long)r.r_offset); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | /** | ||
| 539 | * A module includes a number of sections that are discarded | ||
| 540 | * either when loaded or when used as built-in. | ||
| 541 | * For loaded modules all functions marked __init and all data | ||
| 542 | * marked __initdata will be discarded when the module has been intialized. | ||
| 543 | * Likewise for modules used built-in the sections marked __exit | ||
| 544 | * are discarded because __exit marked function are supposed to be called | ||
| 545 | * only when a moduel is unloaded which never happes for built-in modules. | ||
| 546 | * The check_sec_ref() function traverses all relocation records | ||
| 547 | * to find all references to a section that reference a section that will | ||
| 548 | * be discarded and warns about it. | ||
| 549 | **/ | ||
| 550 | static void check_sec_ref(struct module *mod, const char *modname, | ||
| 551 | struct elf_info *elf, | ||
| 552 | int section(const char*), | ||
| 553 | int section_ref_ok(const char *)) | ||
| 554 | { | ||
| 555 | int i; | ||
| 556 | Elf_Sym *sym; | ||
| 557 | Elf_Ehdr *hdr = elf->hdr; | ||
| 558 | Elf_Shdr *sechdrs = elf->sechdrs; | ||
| 559 | const char *secstrings = (void *)hdr + | ||
| 560 | sechdrs[hdr->e_shstrndx].sh_offset; | ||
| 561 | |||
| 562 | /* Walk through all sections */ | ||
| 563 | for (i = 0; i < hdr->e_shnum; i++) { | ||
| 564 | const char *name = secstrings + sechdrs[i].sh_name + | ||
| 565 | strlen(".rela"); | ||
| 566 | /* We want to process only relocation sections and not .init */ | ||
| 567 | if (section_ref_ok(name) || (sechdrs[i].sh_type != SHT_RELA)) | ||
| 568 | continue; | ||
| 569 | Elf_Rela *rela; | ||
| 570 | Elf_Rela *start = (void *)hdr + sechdrs[i].sh_offset; | ||
| 571 | Elf_Rela *stop = (void*)start + sechdrs[i].sh_size; | ||
| 572 | |||
| 573 | for (rela = start; rela < stop; rela++) { | ||
| 574 | Elf_Rela r; | ||
| 575 | const char *secname; | ||
| 576 | r.r_offset = TO_NATIVE(rela->r_offset); | ||
| 577 | r.r_info = TO_NATIVE(rela->r_info); | ||
| 578 | sym = elf->symtab_start + ELF_R_SYM(r.r_info); | ||
| 579 | secname = secstrings + sechdrs[sym->st_shndx].sh_name; | ||
| 580 | /* Skip special sections */ | ||
| 581 | if (sym->st_shndx >= SHN_LORESERVE) | ||
| 582 | continue; | ||
| 583 | |||
| 584 | if (section(secname)) | ||
| 585 | warn_sec_mismatch(modname, name, elf, sym, r); | ||
| 586 | } | ||
| 587 | } | ||
| 588 | } | ||
| 589 | |||
| 590 | /** | ||
| 591 | * Functions used only during module init is marked __init and is stored in | ||
| 592 | * a .init.text section. Likewise data is marked __initdata and stored in | ||
| 593 | * a .init.data section. | ||
| 594 | * If this section is one of these sections return 1 | ||
| 595 | * See include/linux/init.h for the details | ||
| 596 | **/ | ||
| 597 | static int init_section(const char *name) | ||
| 598 | { | ||
| 599 | if (strcmp(name, ".init") == 0) | ||
| 600 | return 1; | ||
| 601 | if (strncmp(name, ".init.", strlen(".init.")) == 0) | ||
| 602 | return 1; | ||
| 603 | return 0; | ||
| 604 | } | ||
| 605 | |||
| 606 | /** | ||
| 607 | * Identify sections from which references to a .init section is OK. | ||
| 608 | * | ||
| 609 | * Unfortunately references to read only data that referenced .init | ||
| 610 | * sections had to be excluded. Almost all of these are false | ||
| 611 | * positives, they are created by gcc. The downside of excluding rodata | ||
| 612 | * is that there really are some user references from rodata to | ||
| 613 | * init code, e.g. drivers/video/vgacon.c: | ||
| 614 | * | ||
| 615 | * const struct consw vga_con = { | ||
| 616 | * con_startup: vgacon_startup, | ||
| 617 | * | ||
| 618 | * where vgacon_startup is __init. If you want to wade through the false | ||
| 619 | * positives, take out the check for rodata. | ||
| 620 | **/ | ||
| 621 | static int init_section_ref_ok(const char *name) | ||
| 622 | { | ||
| 623 | const char **s; | ||
| 624 | /* Absolute section names */ | ||
| 625 | const char *namelist1[] = { | ||
| 626 | ".init", | ||
| 627 | ".stab", | ||
| 628 | ".rodata", | ||
| 629 | ".text.lock", | ||
| 630 | ".pci_fixup_header", | ||
| 631 | ".pci_fixup_final", | ||
| 632 | ".pdr", | ||
| 633 | "__param", | ||
| 634 | NULL | ||
| 635 | }; | ||
| 636 | /* Start of section names */ | ||
| 637 | const char *namelist2[] = { | ||
| 638 | ".init.", | ||
| 639 | ".altinstructions", | ||
| 640 | ".eh_frame", | ||
| 641 | ".debug", | ||
| 642 | NULL | ||
| 643 | }; | ||
| 644 | |||
| 645 | for (s = namelist1; *s; s++) | ||
| 646 | if (strcmp(*s, name) == 0) | ||
| 647 | return 1; | ||
| 648 | for (s = namelist2; *s; s++) | ||
| 649 | if (strncmp(*s, name, strlen(*s)) == 0) | ||
| 650 | return 1; | ||
| 651 | return 0; | ||
| 652 | } | ||
| 653 | |||
| 654 | /* | ||
| 655 | * Functions used only during module exit is marked __exit and is stored in | ||
| 656 | * a .exit.text section. Likewise data is marked __exitdata and stored in | ||
| 657 | * a .exit.data section. | ||
| 658 | * If this section is one of these sections return 1 | ||
| 659 | * See include/linux/init.h for the details | ||
| 660 | **/ | ||
| 661 | static int exit_section(const char *name) | ||
| 662 | { | ||
| 663 | if (strcmp(name, ".exit.text") == 0) | ||
| 664 | return 1; | ||
| 665 | if (strcmp(name, ".exit.data") == 0) | ||
| 666 | return 1; | ||
| 667 | return 0; | ||
| 668 | |||
| 669 | } | ||
| 670 | |||
