diff options
| -rw-r--r-- | scripts/mod/modpost.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index de0a9ee1de16..663b1eff757b 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
| @@ -452,6 +452,89 @@ static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | |||
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | /** | 454 | /** |
| 455 | * Test if string s ends in string sub | ||
| 456 | * return 0 if match | ||
| 457 | **/ | ||
| 458 | static int strrcmp(const char *s, const char *sub) | ||
| 459 | { | ||
| 460 | int slen, sublen; | ||
| 461 | |||
| 462 | if (!s || !sub) | ||
| 463 | return 1; | ||
| 464 | |||
| 465 | slen = strlen(s); | ||
| 466 | sublen = strlen(sub); | ||
| 467 | |||
| 468 | if ((slen == 0) || (sublen == 0)) | ||
| 469 | return 1; | ||
| 470 | |||
| 471 | if (sublen > slen) | ||
| 472 | return 1; | ||
| 473 | |||
| 474 | return memcmp(s + slen - sublen, sub, sublen); | ||
| 475 | } | ||
| 476 | |||
| 477 | /** | ||
| 478 | * Whitelist to allow certain references to pass with no warning. | ||
| 479 | * Pattern 1: | ||
| 480 | * If a module parameter is declared __initdata and permissions=0 | ||
| 481 | * then this is legal despite the warning generated. | ||
| 482 | * We cannot see value of permissions here, so just ignore | ||
| 483 | * this pattern. | ||
| 484 | * The pattern is identified by: | ||
| 485 | * tosec = .init.data | ||
| 486 | * fromsec = .data | ||
| 487 | * atsym =__param* | ||
| 488 | * | ||
| 489 | * Pattern 2: | ||
| 490 | * Many drivers utilise a *_driver container with references to | ||
| 491 | * add, remove, probe functions etc. | ||
| 492 | * These functions may often be marked __init and we do not want to | ||
| 493 | * warn here. | ||
| 494 | * the pattern is identified by: | ||
| 495 | * tosec = .init.text | .exit.text | ||
| 496 | * fromsec = .data | ||
| 497 | * atsym = *_driver, *_ops, *_probe, *probe_one | ||
| 498 | **/ | ||
| 499 | static int secref_whitelist(const char *tosec, const char *fromsec, | ||
| 500 | const char *atsym) | ||
| 501 | { | ||
| 502 | int f1 = 1, f2 = 1; | ||
| 503 | const char **s; | ||
| 504 | const char *pat2sym[] = { | ||
| 505 | "_driver", | ||
| 506 | "_ops", | ||
| 507 | "_probe", | ||
| 508 | "_probe_one", | ||
| 509 | NULL | ||
| 510 | }; | ||
| 511 | |||
| 512 | /* Check for pattern 1 */ | ||
| 513 | if (strcmp(tosec, ".init.data") != 0) | ||
| 514 | f1 = 0; | ||
| 515 | if (strcmp(fromsec, ".data") != 0) | ||
| 516 | f1 = 0; | ||
| 517 | if (strncmp(atsym, "__param", strlen("__param")) != 0) | ||
| 518 | f1 = 0; | ||
| 519 | |||
| 520 | if (f1) | ||
| 521 | return f1; | ||
| 522 | |||
| 523 | /* Check for pattern 2 */ | ||
| 524 | if ((strcmp(tosec, ".init.text") != 0) && | ||
| 525 | (strcmp(tosec, ".exit.text") != 0)) | ||
| 526 | f2 = 0; | ||
| 527 | if (strcmp(fromsec, ".data") != 0) | ||
| 528 | f2 = 0; | ||
| 529 | |||
| 530 | for (s = pat2sym; *s; s++) | ||
| 531 | if (strrcmp(atsym, *s) == 0) | ||
| 532 | f1 = 1; | ||
| 533 | |||
| 534 | return f1 && f2; | ||
| 535 | } | ||
| 536 | |||
| 537 | /** | ||
| 455 | * Find symbol based on relocation record info. | 538 | * Find symbol based on relocation record info. |
| 456 | * In some cases the symbol supplied is a valid symbol so | 539 | * In some cases the symbol supplied is a valid symbol so |
| 457 | * return refsym. If st_name != 0 we assume this is a valid symbol. | 540 | * return refsym. If st_name != 0 we assume this is a valid symbol. |
| @@ -518,6 +601,7 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr, | |||
| 518 | /** | 601 | /** |
| 519 | * Print a warning about a section mismatch. | 602 | * Print a warning about a section mismatch. |
| 520 | * Try to find symbols near it so user can find it. | 603 | * Try to find symbols near it so user can find it. |
| 604 | * Check whitelist before warning - it may be a false positive. | ||
| 521 | **/ | 605 | **/ |
| 522 | static void warn_sec_mismatch(const char *modname, const char *fromsec, | 606 | static void warn_sec_mismatch(const char *modname, const char *fromsec, |
| 523 | struct elf_info *elf, Elf_Sym *sym, Elf_Rela r) | 607 | struct elf_info *elf, Elf_Sym *sym, Elf_Rela r) |
| @@ -536,6 +620,11 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec, | |||
| 536 | refsym = find_elf_symbol(elf, r.r_addend, sym); | 620 | refsym = find_elf_symbol(elf, r.r_addend, sym); |
| 537 | if (refsym && strlen(elf->strtab + refsym->st_name)) | 621 | if (refsym && strlen(elf->strtab + refsym->st_name)) |
| 538 | refsymname = elf->strtab + refsym->st_name; | 622 | refsymname = elf->strtab + refsym->st_name; |
| 623 | |||
| 624 | /* check whitelist - we may ignore it */ | ||
| 625 | if (before && | ||
| 626 | secref_whitelist(secname, fromsec, elf->strtab + before->st_name)) | ||
| 627 | return; | ||
| 539 | 628 | ||
| 540 | if (before && after) { | 629 | if (before && after) { |
| 541 | warn("%s - Section mismatch: reference to %s:%s from %s " | 630 | warn("%s - Section mismatch: reference to %s:%s from %s " |
