scripts/mod/modpost.c: fix memory leak
[sfrench/cifs-2.6.git] / scripts / mod / modpost.c
index f6127b9f5acac16c10842fee3c53445fddfacd2a..1ce655dde99efd4357db4b62b1a9ff98f0d8fadd 100644 (file)
@@ -253,7 +253,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 +373,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 +419,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 +452,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 +481,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 +512,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;
 }
 
@@ -519,7 +566,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:
@@ -661,19 +708,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
@@ -1052,11 +1099,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;
@@ -1118,9 +1168,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))
@@ -1195,6 +1245,8 @@ static void report_sec_mismatch(const char *modname,
 {
        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;
@@ -1218,16 +1270,21 @@ static void report_sec_mismatch(const char *modname,
 
        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_ANY_INIT: {
+               prl_to = sec2annotation(tosec);
                const char *const *s = mismatch->symbol_white_list;
                fprintf(stderr,
                "The variable %s references\n"
@@ -1235,20 +1292,24 @@ static void report_sec_mismatch(const char *modname,
                "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_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_ANY_EXIT: {
+               prl_to = sec2annotation(tosec);
                const char *const *s = mismatch->symbol_white_list;
                fprintf(stderr,
                "The variable %s references\n"
@@ -1256,24 +1317,31 @@ static void report_sec_mismatch(const char *modname,
                "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_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 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"
@@ -1282,11 +1350,15 @@ static void report_sec_mismatch(const char *modname,
                "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,
+               from, prl_from, fromsym, from_p,
+               to, prl_to, tosym, to_p,
                sec2annotation(tosec), tosym, to_p);
+               free(prl_from);
+               free(prl_to);
                break;
        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"
@@ -1295,16 +1367,20 @@ static void report_sec_mismatch(const char *modname,
                "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);
+               tosym, prl_to, prl_to, tosym);
+               free(prl_to);
                break;
        }
        fprintf(stderr, "\n");
@@ -1316,7 +1392,7 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
        const char *tosec;
        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) {
                Elf_Sym *to;
@@ -1344,7 +1420,7 @@ 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;
@@ -1452,7 +1528,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);
        }
@@ -1510,7 +1586,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);
        }
@@ -1535,7 +1611,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)