diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-08-16 18:42:58 +0100 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-08-16 18:42:58 +0100 |
commit | e4862f2f6f5653dfb67f3ba2b6f0bc74516ed51a (patch) | |
tree | 1db5a0540a4eecfad9b7daee476b985e82ddc810 /scripts/mod/modpost.c | |
parent | ec62dbd7eb8e3dddb221da89ecbcea0fc3dee8c1 (diff) | |
parent | b2c1e07b81a126e5846dfc3d36f559d861df59f4 (diff) |
Merge branch 'for-2.6.36' into for-2.6.37
Fairly simple conflicts, the most serious ones are the i.MX ones which I
suspect now need another rename.
Conflicts:
arch/arm/mach-mx2/clock_imx27.c
arch/arm/mach-mx2/devices.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom2.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/pxa/spitz.c
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 334 |
1 files changed, 227 insertions, 107 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 20923613467..1ec7158b6c1 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -14,6 +14,7 @@ #define _GNU_SOURCE #include <stdio.h> #include <ctype.h> +#include <string.h> #include "modpost.h" #include "../../include/generated/autoconf.h" #include "../../include/linux/license.h" @@ -253,7 +254,7 @@ static enum export export_no(const char *s) return export_unknown; } -static enum export export_from_sec(struct elf_info *elf, Elf_Section sec) +static enum export export_from_sec(struct elf_info *elf, unsigned int sec) { if (sec == elf->export_sec) return export_plain; @@ -373,6 +374,8 @@ static int parse_elf(struct elf_info *info, const char *filename) Elf_Ehdr *hdr; Elf_Shdr *sechdrs; Elf_Sym *sym; + const char *secstrings; + unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; hdr = grab_file(filename, &info->size); if (!hdr) { @@ -417,8 +420,27 @@ static int parse_elf(struct elf_info *info, const char *filename) return 0; } + if (hdr->e_shnum == 0) { + /* + * There are more than 64k sections, + * read count from .sh_size. + * note: it doesn't need shndx2secindex() + */ + info->num_sections = TO_NATIVE(sechdrs[0].sh_size); + } + else { + info->num_sections = hdr->e_shnum; + } + if (hdr->e_shstrndx == SHN_XINDEX) { + info->secindex_strings = + shndx2secindex(TO_NATIVE(sechdrs[0].sh_link)); + } + else { + info->secindex_strings = hdr->e_shstrndx; + } + /* Fix endianness in section headers */ - for (i = 0; i < hdr->e_shnum; i++) { + for (i = 0; i < info->num_sections; i++) { sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); @@ -431,9 +453,8 @@ static int parse_elf(struct elf_info *info, const char *filename) sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); } /* Find symbol table. */ - for (i = 1; i < hdr->e_shnum; i++) { - const char *secstrings - = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; + for (i = 1; i < info->num_sections; i++) { const char *secname; int nobits = sechdrs[i].sh_type == SHT_NOBITS; @@ -461,14 +482,26 @@ static int parse_elf(struct elf_info *info, const char *filename) else if (strcmp(secname, "__ksymtab_gpl_future") == 0) info->export_gpl_future_sec = i; - if (sechdrs[i].sh_type != SHT_SYMTAB) - continue; + if (sechdrs[i].sh_type == SHT_SYMTAB) { + unsigned int sh_link_idx; + symtab_idx = i; + info->symtab_start = (void *)hdr + + sechdrs[i].sh_offset; + info->symtab_stop = (void *)hdr + + sechdrs[i].sh_offset + sechdrs[i].sh_size; + sh_link_idx = shndx2secindex(sechdrs[i].sh_link); + info->strtab = (void *)hdr + + sechdrs[sh_link_idx].sh_offset; + } - info->symtab_start = (void *)hdr + sechdrs[i].sh_offset; - info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset - + sechdrs[i].sh_size; - info->strtab = (void *)hdr + - sechdrs[sechdrs[i].sh_link].sh_offset; + /* 32bit section no. table? ("more than 64k sections") */ + if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { + symtab_shndx_idx = i; + info->symtab_shndx_start = (void *)hdr + + sechdrs[i].sh_offset; + info->symtab_shndx_stop = (void *)hdr + + sechdrs[i].sh_offset + sechdrs[i].sh_size; + } } if (!info->symtab_start) fatal("%s has no symtab?\n", filename); @@ -480,6 +513,21 @@ static int parse_elf(struct elf_info *info, const char *filename) sym->st_value = TO_NATIVE(sym->st_value); sym->st_size = TO_NATIVE(sym->st_size); } + + if (symtab_shndx_idx != ~0U) { + Elf32_Word *p; + if (symtab_idx != + shndx2secindex(sechdrs[symtab_shndx_idx].sh_link)) + fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", + filename, + shndx2secindex(sechdrs[symtab_shndx_idx].sh_link), + symtab_idx); + /* Fix endianness */ + for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; + p++) + *p = TO_NATIVE(*p); + } + return 1; } @@ -503,6 +551,11 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0) return 1; + if (info->hdr->e_machine == EM_PPC64) + /* Special register function linked on all modules during final link of .ko */ + if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || + strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0) + return 1; /* Do not ignore this symbol */ return 0; } @@ -514,7 +567,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname) { unsigned int crc; - enum export export = export_from_sec(info, sym->st_shndx); + enum export export = export_from_sec(info, get_secindex(info, sym)); switch (sym->st_shndx) { case SHN_COMMON: @@ -656,19 +709,19 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) return "(unknown)"; } -static const char *sec_name(struct elf_info *elf, int shndx) +static const char *sec_name(struct elf_info *elf, int secindex) { Elf_Shdr *sechdrs = elf->sechdrs; return (void *)elf->hdr + - elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + - sechdrs[shndx].sh_name; + elf->sechdrs[elf->secindex_strings].sh_offset + + sechdrs[secindex].sh_name; } static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) { return (void *)elf->hdr + - elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + - sechdr->sh_name; + elf->sechdrs[elf->secindex_strings].sh_offset + + sechdr->sh_name; } /* if sym is empty or point to a string @@ -737,6 +790,7 @@ static const char *section_white_list[] = { ".comment*", ".debug*", + ".GCC-command-line", /* mn10300 */ ".mdebug*", /* alpha, score, mips etc. */ ".pdr", /* alpha, score, mips etc. */ ".stab*", @@ -781,10 +835,13 @@ static void check_section(const char *modname, struct elf_info *elf, #define ALL_EXIT_TEXT_SECTIONS \ ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" -#define ALL_INIT_SECTIONS INIT_SECTIONS, DEV_INIT_SECTIONS, \ - CPU_INIT_SECTIONS, MEM_INIT_SECTIONS -#define ALL_EXIT_SECTIONS EXIT_SECTIONS, DEV_EXIT_SECTIONS, \ - CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS +#define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \ + MEM_INIT_SECTIONS +#define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \ + MEM_EXIT_SECTIONS + +#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS +#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS #define DATA_SECTIONS ".data$", ".data.rel$" #define TEXT_SECTIONS ".text$" @@ -814,33 +871,29 @@ static const char *data_sections[] = { DATA_SECTIONS, NULL }; /* symbols in .data that may refer to init/exit sections */ -static const char *symbol_white_list[] = -{ - "*driver", - "*_template", /* scsi uses *_template a lot */ - "*_timer", /* arm uses ops structures named _timer a lot */ - "*_sht", /* scsi also used *_sht to some extent */ - "*_ops", - "*_probe", - "*_probe_one", - "*_console", - NULL -}; +#define DEFAULT_SYMBOL_WHITE_LIST \ + "*driver", \ + "*_template", /* scsi uses *_template a lot */ \ + "*_timer", /* arm uses ops structures named _timer a lot */ \ + "*_sht", /* scsi also used *_sht to some extent */ \ + "*_ops", \ + "*_probe", \ + "*_probe_one", \ + "*_console" static const char *head_sections[] = { ".head.text*", NULL }; static const char *linker_symbols[] = { "__init_begin", "_sinittext", "_einittext", NULL }; enum mismatch { - NO_MISMATCH, - TEXT_TO_INIT, - DATA_TO_INIT, - TEXT_TO_EXIT, - DATA_TO_EXIT, - XXXINIT_TO_INIT, - XXXEXIT_TO_EXIT, - INIT_TO_EXIT, - EXIT_TO_INIT, + TEXT_TO_ANY_INIT, + DATA_TO_ANY_INIT, + TEXT_TO_ANY_EXIT, + DATA_TO_ANY_EXIT, + XXXINIT_TO_SOME_INIT, + XXXEXIT_TO_SOME_EXIT, + ANY_INIT_TO_ANY_EXIT, + ANY_EXIT_TO_ANY_INIT, EXPORT_TO_INIT_EXIT, }; @@ -848,6 +901,7 @@ struct sectioncheck { const char *fromsec[20]; const char *tosec[20]; enum mismatch mismatch; + const char *symbol_white_list[20]; }; const struct sectioncheck sectioncheck[] = { @@ -857,80 +911,103 @@ const struct sectioncheck sectioncheck[] = { { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_INIT, + .mismatch = TEXT_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, - .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = DATA_TO_INIT, + .tosec = { ALL_XXXINIT_SECTIONS, NULL }, + .mismatch = DATA_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, +}, +{ + .fromsec = { DATA_SECTIONS, NULL }, + .tosec = { INIT_SECTIONS, NULL }, + .mismatch = DATA_TO_ANY_INIT, + .symbol_white_list = { + "*_template", "*_timer", "*_sht", "*_ops", + "*_probe", "*_probe_one", "*_console", NULL + }, }, { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_EXIT, + .mismatch = TEXT_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = DATA_TO_EXIT, + .mismatch = DATA_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference init code/data from devinit/cpuinit/meminit code/data */ { - .fromsec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS, NULL }, + .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .tosec = { INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference cpuinit code/data from meminit code/data */ { .fromsec = { MEM_INIT_SECTIONS, NULL }, .tosec = { CPU_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference meminit code/data from cpuinit code/data */ { .fromsec = { CPU_INIT_SECTIONS, NULL }, .tosec = { MEM_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ { - .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL }, + .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference cpuexit code/data from memexit code/data */ { .fromsec = { MEM_EXIT_SECTIONS, NULL }, .tosec = { CPU_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference memexit code/data from cpuexit code/data */ { .fromsec = { CPU_EXIT_SECTIONS, NULL }, .tosec = { MEM_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = INIT_TO_EXIT, + .mismatch = ANY_INIT_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use init code/data from exit code */ { .fromsec = { ALL_EXIT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = EXIT_TO_INIT, + .mismatch = ANY_EXIT_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not export init/exit functions or data */ { .fromsec = { "__ksymtab*", NULL }, .tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, - .mismatch = EXPORT_TO_INIT_EXIT + .mismatch = EXPORT_TO_INIT_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, } }; -static int section_mismatch(const char *fromsec, const char *tosec) +static const struct sectioncheck *section_mismatch( + const char *fromsec, const char *tosec) { int i; int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); @@ -939,10 +1016,10 @@ static int section_mismatch(const char *fromsec, const char *tosec) for (i = 0; i < elems; i++) { if (match(fromsec, check->fromsec) && match(tosec, check->tosec)) - return check->mismatch; + return check; check++; } - return NO_MISMATCH; + return NULL; } /** @@ -958,10 +1035,17 @@ static int section_mismatch(const char *fromsec, const char *tosec) * fromsec = .data* * atsym =__param* * + * Pattern 1a: + * module_param_call() ops can refer to __init set function if permissions=0 + * The pattern is identified by: + * tosec = .init.text + * fromsec = .data* + * atsym = __param_ops_* + * * Pattern 2: * Many drivers utilise a *driver container with references to * add, remove, probe functions etc. - * These functions may often be marked __init and we do not want to + * These functions may often be marked __devinit and we do not want to * warn here. * the pattern is identified by: * tosec = init or exit section @@ -982,7 +1066,8 @@ static int section_mismatch(const char *fromsec, const char *tosec) * refsymname = __init_begin, _sinittext, _einittext * **/ -static int secref_whitelist(const char *fromsec, const char *fromsym, +static int secref_whitelist(const struct sectioncheck *mismatch, + const char *fromsec, const char *fromsym, const char *tosec, const char *tosym) { /* Check for pattern 1 */ @@ -991,10 +1076,16 @@ static int secref_whitelist(const char *fromsec, const char *fromsym, (strncmp(fromsym, "__param", strlen("__param")) == 0)) return 0; + /* Check for pattern 1a */ + if (strcmp(tosec, ".init.text") == 0 && + match(fromsec, data_sections) && + (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0)) + return 0; + /* Check for pattern 2 */ if (match(tosec, init_exit_sections) && match(fromsec, data_sections) && - match(fromsym, symbol_white_list)) + match(fromsym, mismatch->symbol_white_list)) return 0; /* Check for pattern 3 */ @@ -1023,11 +1114,14 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, Elf_Sym *near = NULL; Elf64_Sword distance = 20; Elf64_Sword d; + unsigned int relsym_secindex; if (relsym->st_name != 0) return relsym; + + relsym_secindex = get_secindex(elf, relsym); for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { - if (sym->st_shndx != relsym->st_shndx) + if (get_secindex(elf, sym) != relsym_secindex) continue; if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) continue; @@ -1089,9 +1183,9 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { const char *symsec; - if (sym->st_shndx >= SHN_LORESERVE) + if (is_shndx_special(sym->st_shndx)) continue; - symsec = sec_name(elf, sym->st_shndx); + symsec = sec_name(elf, get_secindex(elf, sym)); if (strcmp(symsec, sec) != 0) continue; if (!is_valid_name(elf, sym)) @@ -1138,7 +1232,7 @@ static char *sec2annotation(const char *s) strcat(p, " "); return r; /* we leak her but we do not care */ } else { - return ""; + return strdup(""); } } @@ -1155,7 +1249,8 @@ static int is_function(Elf_Sym *sym) * Try to find symbols near it so user can find it. * Check whitelist before warning - it may be a false positive. */ -static void report_sec_mismatch(const char *modname, enum mismatch mismatch, +static void report_sec_mismatch(const char *modname, + const struct sectioncheck *mismatch, const char *fromsec, unsigned long long fromaddr, const char *fromsym, @@ -1165,6 +1260,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, { const char *from, *from_p; const char *to, *to_p; + char *prl_from; + char *prl_to; switch (from_is_func) { case 0: from = "variable"; from_p = ""; break; @@ -1186,64 +1283,80 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, tosym, to_p); - switch (mismatch) { - case TEXT_TO_INIT: + switch (mismatch->mismatch) { + case TEXT_TO_ANY_INIT: + prl_from = sec2annotation(fromsec); + prl_to = sec2annotation(tosec); fprintf(stderr, "The function %s%s() references\n" "the %s %s%s%s.\n" "This is often because %s lacks a %s\n" "annotation or the annotation of %s is wrong.\n", - sec2annotation(fromsec), fromsym, - to, sec2annotation(tosec), tosym, to_p, - fromsym, sec2annotation(tosec), tosym); + prl_from, fromsym, + to, prl_to, tosym, to_p, + fromsym, prl_to, tosym); + free(prl_from); + free(prl_to); break; - case DATA_TO_INIT: { - const char **s = symbol_white_list; + case DATA_TO_ANY_INIT: { + prl_to = sec2annotation(tosec); + const char *const *s = mismatch->symbol_white_list; fprintf(stderr, "The variable %s references\n" "the %s %s%s%s\n" "If the reference is valid then annotate the\n" "variable with __init* or __refdata (see linux/init.h) " "or name the variable:\n", - fromsym, to, sec2annotation(tosec), tosym, to_p); + fromsym, to, prl_to, tosym, to_p); while (*s) fprintf(stderr, "%s, ", *s++); fprintf(stderr, "\n"); + free(prl_to); break; } - case TEXT_TO_EXIT: + case TEXT_TO_ANY_EXIT: + prl_to = sec2annotation(tosec); fprintf(stderr, "The function %s() references a %s in an exit section.\n" "Often the %s %s%s has valid usage outside the exit section\n" "and the fix is to remove the %sannotation of %s.\n", - fromsym, to, to, tosym, to_p, sec2annotation(tosec), tosym); + fromsym, to, to, tosym, to_p, prl_to, tosym); + free(prl_to); break; - case DATA_TO_EXIT: { - const char **s = symbol_white_list; + case DATA_TO_ANY_EXIT: { + prl_to = sec2annotation(tosec); + const char *const *s = mismatch->symbol_white_list; fprintf(stderr, "The variable %s references\n" "the %s %s%s%s\n" "If the reference is valid then annotate the\n" "variable with __exit* (see linux/init.h) or " "name the variable:\n", - fromsym, to, sec2annotation(tosec), tosym, to_p); + fromsym, to, prl_to, tosym, to_p); while (*s) fprintf(stderr, "%s, ", *s++); fprintf(stderr, "\n"); + free(prl_to); break; } - case XXXINIT_TO_INIT: - case XXXEXIT_TO_EXIT: + case XXXINIT_TO_SOME_INIT: + case XXXEXIT_TO_SOME_EXIT: + prl_from = sec2annotation(fromsec); + prl_to = sec2annotation(tosec); fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" "If %s is only used by %s then\n" "annotate %s with a matching annotation.\n", - from, sec2annotation(fromsec), fromsym, from_p, - to, sec2annotation(tosec), tosym, to_p, + from, prl_from, fromsym, from_p, + to, prl_to, tosym, to_p, tosym, fromsym, tosym); + free(prl_from); + free(prl_to); break; - case INIT_TO_EXIT: + case ANY_INIT_TO_ANY_EXIT: + prl_from = sec2annotation(fromsec); + prl_to = sec2annotation(tosec); fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" @@ -1252,11 +1365,15 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, "uses functionality in the exit path.\n" "The fix is often to remove the %sannotation of\n" "%s%s so it may be used outside an exit section.\n", - from, sec2annotation(fromsec), fromsym, from_p, - to, sec2annotation(tosec), tosym, to_p, - sec2annotation(tosec), tosym, to_p); + from, prl_from, fromsym, from_p, + to, prl_to, tosym, to_p, + prl_to, tosym, to_p); + free(prl_from); + free(prl_to); break; - case EXIT_TO_INIT: + case ANY_EXIT_TO_ANY_INIT: + prl_from = sec2annotation(fromsec); + prl_to = sec2annotation(tosec); fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" @@ -1265,18 +1382,20 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, "uses functionality in the init path.\n" "The fix is often to remove the %sannotation of\n" "%s%s so it may be used outside an init section.\n", - from, sec2annotation(fromsec), fromsym, from_p, - to, sec2annotation(tosec), tosym, to_p, - sec2annotation(tosec), tosym, to_p); + from, prl_from, fromsym, from_p, + to, prl_to, tosym, to_p, + prl_to, tosym, to_p); + free(prl_from); + free(prl_to); break; case EXPORT_TO_INIT_EXIT: + prl_to = sec2annotation(tosec); fprintf(stderr, "The symbol %s is exported and annotated %s\n" "Fix this by removing the %sannotation of %s " "or drop the export.\n", - tosym, sec2annotation(tosec), sec2annotation(tosec), tosym); - case NO_MISMATCH: - /* To get warnings on missing members */ + tosym, prl_to, prl_to, tosym); + free(prl_to); break; } fprintf(stderr, "\n"); @@ -1286,11 +1405,11 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, Elf_Rela *r, Elf_Sym *sym, const char *fromsec) { const char *tosec; - enum mismatch mismatch; + const struct sectioncheck *mismatch; - tosec = sec_name(elf, sym->st_shndx); + tosec = sec_name(elf, get_secindex(elf, sym)); mismatch = section_mismatch(fromsec, tosec); - if (mismatch != NO_MISMATCH) { + if (mismatch) { Elf_Sym *to; Elf_Sym *from; const char *tosym; @@ -1302,7 +1421,8 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, tosym = sym_name(elf, to); /* check whitelist - we may ignore it */ - if (secref_whitelist(fromsec, fromsym, tosec, tosym)) { + if (secref_whitelist(mismatch, + fromsec, fromsym, tosec, tosym)) { report_sec_mismatch(modname, mismatch, fromsec, r->r_offset, fromsym, is_function(from), tosec, tosym, @@ -1315,10 +1435,10 @@ static unsigned int *reloc_location(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) { Elf_Shdr *sechdrs = elf->sechdrs; - int section = sechdr->sh_info; + int section = shndx2secindex(sechdr->sh_info); return (void *)elf->hdr + sechdrs[section].sh_offset + - (r->r_offset - sechdrs[section].sh_addr); + r->r_offset - sechdrs[section].sh_addr; } static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) @@ -1423,7 +1543,7 @@ static void section_rela(const char *modname, struct elf_info *elf, r.r_addend = TO_NATIVE(rela->r_addend); sym = elf->symtab_start + r_sym; /* Skip special sections */ - if (sym->st_shndx >= SHN_LORESERVE) + if (is_shndx_special(sym->st_shndx)) continue; check_section_mismatch(modname, elf, &r, sym, fromsec); } @@ -1481,7 +1601,7 @@ static void section_rel(const char *modname, struct elf_info *elf, } sym = elf->symtab_start + r_sym; /* Skip special sections */ - if (sym->st_shndx >= SHN_LORESERVE) + if (is_shndx_special(sym->st_shndx)) continue; check_section_mismatch(modname, elf, &r, sym, fromsec); } @@ -1506,7 +1626,7 @@ static void check_sec_ref(struct module *mod, const char *modname, Elf_Shdr *sechdrs = elf->sechdrs; /* Walk through all sections */ - for (i = 0; i < elf->hdr->e_shnum; i++) { + for (i = 0; i < elf->num_sections; i++) { check_section(modname, elf, &elf->sechdrs[i]); /* We want to process only relocation sections and not .init */ if (sechdrs[i].sh_type == SHT_RELA) |