diff options
author | Sam Ravnborg <sam@mars.ravnborg.org> | 2006-02-26 16:18:11 -0500 |
---|---|---|
committer | Sam Ravnborg <sam@mars.ravnborg.org> | 2006-02-26 16:18:11 -0500 |
commit | 4c8fbca5836aaafd165aa8732d92ab5d4f3a6841 (patch) | |
tree | f4a9d7f73a92d540ebf4a53e36ed19d160e2a4de /scripts/mod | |
parent | cc006288fb538005a14ca4297250abbf0beeb0b9 (diff) |
kbuild: whitelist false section mismatch warnings
In several cases the section mismatch check triggered false warnings.
Following patch introduce a whitelist to 'false positives' are not warned of.
Two types of patterns are recognised:
1) Typical case when a module parameter is _initdata
2) When a function pointer is assigned to a driver structure
In both patterns we rely on the actual name of the variable assigned
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Diffstat (limited to 'scripts/mod')
-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 " |