]> Pileus Git - ~andy/linux/blobdiff - scripts/mod/modpost.c
Merge branch 'master'
[~andy/linux] / scripts / mod / modpost.c
index 663b1eff757b1bc184995c8f304b5b8cce57941f..cd00e9f0758995e5d027ff9dc96835256b10860c 100644 (file)
@@ -85,7 +85,7 @@ static struct module *new_module(char *modname)
 {
        struct module *mod;
        char *p, *s;
-       
+
        mod = NOFAIL(malloc(sizeof(*mod)));
        memset(mod, 0, sizeof(*mod));
        p = NOFAIL(strdup(modname));
@@ -191,7 +191,7 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod)
                s = new_symbol(name, mod);
        } else {
                if (!s->preloaded) {
-                       warn("%s: duplicate symbol '%s' previous definition "
+                       warn("%s: '%s' exported twice. Previous export "
                             "was in %s%s\n", mod->name, name,
                             s->module->name,
                             is_vmlinux(s->module->name) ?"":".ko");
@@ -320,9 +320,9 @@ static void parse_elf(struct elf_info *info, const char *filename)
                        continue;
 
                info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
-               info->symtab_stop  = (void *)hdr + sechdrs[i].sh_offset 
+               info->symtab_stop  = (void *)hdr + sechdrs[i].sh_offset
                                                 + sechdrs[i].sh_size;
-               info->strtab       = (void *)hdr + 
+               info->strtab       = (void *)hdr +
                                     sechdrs[sechdrs[i].sh_link].sh_offset;
        }
        if (!info->symtab_start) {
@@ -346,8 +346,8 @@ static void parse_elf_finish(struct elf_info *info)
        release_file(info->hdr, info->size);
 }
 
-#define CRC_PFX     "__crc_"
-#define KSYMTAB_PFX "__ksymtab_"
+#define CRC_PFX     MODULE_SYMBOL_PREFIX "__crc_"
+#define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_"
 
 static void handle_modversions(struct module *mod, struct elf_info *info,
                               Elf_Sym *sym, const char *symname)
@@ -387,15 +387,15 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
                        /* Ignore register directives. */
                        if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
                                break;
-                       if (symname[0] == '.') {
-                               char *munged = strdup(symname);
-                               munged[0] = '_';
-                               munged[1] = toupper(munged[1]);
-                               symname = munged;
-                       }
+                       if (symname[0] == '.') {
+                               char *munged = strdup(symname);
+                               munged[0] = '_';
+                               munged[1] = toupper(munged[1]);
+                               symname = munged;
+                       }
                }
 #endif
-               
+
                if (memcmp(symname, MODULE_SYMBOL_PREFIX,
                           strlen(MODULE_SYMBOL_PREFIX)) == 0)
                        mod->unres = alloc_symbol(symname +
@@ -458,13 +458,13 @@ static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
 static int strrcmp(const char *s, const char *sub)
 {
         int slen, sublen;
-       
+
        if (!s || !sub)
                return 1;
-       
+
        slen = strlen(s);
         sublen = strlen(sub);
-       
+
        if ((slen == 0) || (sublen == 0))
                return 1;
 
@@ -483,36 +483,38 @@ static int strrcmp(const char *s, const char *sub)
  *   this pattern.
  *   The pattern is identified by:
  *   tosec   = .init.data
- *   fromsec = .data
+ *   fromsec = .data*
  *   atsym   =__param*
- *   
+ *
  * 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
  *   warn here.
  *   the pattern is identified by:
- *   tosec   = .init.text | .exit.text
+ *   tosec   = .init.text | .exit.text | .init.data
  *   fromsec = .data
- *   atsym = *_driver, *_ops, *_probe, *probe_one
+ *   atsym = *_driver, *_template, *_sht, *_ops, *_probe, *probe_one
  **/
 static int secref_whitelist(const char *tosec, const char *fromsec,
-                         const char *atsym)
+                           const char *atsym)
 {
        int f1 = 1, f2 = 1;
        const char **s;
        const char *pat2sym[] = {
                "_driver",
+               "_template", /* scsi uses *_template a lot */
+               "_sht",      /* scsi also used *_sht to some extent */
                "_ops",
                "_probe",
                "_probe_one",
                NULL
        };
-       
+
        /* Check for pattern 1 */
        if (strcmp(tosec, ".init.data") != 0)
                f1 = 0;
-       if (strcmp(fromsec, ".data") != 0)
+       if (strncmp(fromsec, ".data", strlen(".data")) != 0)
                f1 = 0;
        if (strncmp(atsym, "__param", strlen("__param")) != 0)
                f1 = 0;
@@ -521,8 +523,9 @@ static int secref_whitelist(const char *tosec, const char *fromsec,
                return f1;
 
        /* Check for pattern 2 */
-       if ((strcmp(tosec, ".init.text") != 0) && 
-           (strcmp(tosec, ".exit.text") != 0))
+       if ((strcmp(tosec, ".init.text") != 0) &&
+           (strcmp(tosec, ".exit.text") != 0) &&
+           (strcmp(tosec, ".init.data") != 0))
                f2 = 0;
        if (strcmp(fromsec, ".data") != 0)
                f2 = 0;
@@ -558,7 +561,10 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
 }
 
 /*
- * Find symbols before or equal addr and after addr - in the section sec
+ * Find symbols before or equal addr and after addr - in the section sec.
+ * If we find two symbols with equal offset prefer one with a valid name.
+ * The ELF format may have a better way to detect what type of symbol
+ * it is, but this works for now.
  **/
 static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                                 const char *sec,
@@ -570,7 +576,7 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
        Elf_Addr afterdiff = ~0;
        const char *secstrings = (void *)hdr +
                                 elf->sechdrs[hdr->e_shstrndx].sh_offset;
-       
+
        *before = NULL;
        *after = NULL;
 
@@ -587,6 +593,12 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                                beforediff = addr - sym->st_value;
                                *before = sym;
                        }
+                       else if ((addr - sym->st_value) == beforediff) {
+                               /* equal offset, valid name? */
+                               const char *name = elf->strtab + sym->st_name;
+                               if (name && strlen(name))
+                                       *before = sym;
+                       }
                }
                else
                {
@@ -594,6 +606,12 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                                afterdiff = sym->st_value - addr;
                                *after = sym;
                        }
+                       else if ((sym->st_value - addr) == afterdiff) {
+                               /* equal offset, valid name? */
+                               const char *name = elf->strtab + sym->st_name;
+                               if (name && strlen(name))
+                                       *after = sym;
+                       }
                }
        }
 }
@@ -614,7 +632,7 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
        const char *secstrings = (void *)hdr +
                                 sechdrs[hdr->e_shstrndx].sh_offset;
        const char *secname = secstrings + sechdrs[sym->st_shndx].sh_name;
-       
+
        find_symbols_between(elf, r.r_offset, fromsec, &before, &after);
 
        refsym = find_elf_symbol(elf, r.r_addend, sym);
@@ -622,10 +640,10 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
                refsymname = elf->strtab + refsym->st_name;
 
        /* check whitelist - we may ignore it */
-       if (before && 
+       if (before &&
            secref_whitelist(secname, fromsec, elf->strtab + before->st_name))
                return;
-       
+
        if (before && after) {
                warn("%s - Section mismatch: reference to %s:%s from %s "
                     "between '%s' (at offset 0x%llx) and '%s'\n",
@@ -636,14 +654,14 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
        } else if (before) {
                warn("%s - Section mismatch: reference to %s:%s from %s "
                     "after '%s' (at offset 0x%llx)\n",
-                    modname, secname, refsymname, fromsec, 
+                    modname, secname, refsymname, fromsec,
                     elf->strtab + before->st_name,
                     (long long)r.r_offset);
        } else if (after) {
                warn("%s - Section mismatch: reference to %s:%s from %s "
                     "before '%s' (at offset -0x%llx)\n",
-                    modname, secname, refsymname, fromsec, 
-                    elf->strtab + before->st_name,
+                    modname, secname, refsymname, fromsec,
+                    elf->strtab + after->st_name,
                     (long long)r.r_offset);
        } else {
                warn("%s - Section mismatch: reference to %s:%s from %s "
@@ -676,7 +694,7 @@ static void check_sec_ref(struct module *mod, const char *modname,
        Elf_Shdr *sechdrs = elf->sechdrs;
        const char *secstrings = (void *)hdr +
                                 sechdrs[hdr->e_shstrndx].sh_offset;
-               
+
        /* Walk through all sections */
        for (i = 0; i < hdr->e_shnum; i++) {
                Elf_Rela *rela;
@@ -724,13 +742,13 @@ static int init_section(const char *name)
 
 /**
  * Identify sections from which references to a .init section is OK.
- * 
+ *
  * Unfortunately references to read only data that referenced .init
  * sections had to be excluded. Almost all of these are false
  * positives, they are created by gcc. The downside of excluding rodata
  * is that there really are some user references from rodata to
  * init code, e.g. drivers/video/vgacon.c:
- * 
+ *
  * const struct consw vga_con = {
  *        con_startup:            vgacon_startup,
  *
@@ -743,9 +761,12 @@ static int init_section_ref_ok(const char *name)
        /* Absolute section names */
        const char *namelist1[] = {
                ".init",
+               ".opd",   /* see comment [OPD] at exit_section_ref_ok() */
+               ".toc1",  /* used by ppc64 */
                ".stab",
                ".rodata",
                ".text.lock",
+               "__bug_table", /* used by powerpc for BUG() */
                ".pci_fixup_header",
                ".pci_fixup_final",
                ".pdr",
@@ -769,11 +790,11 @@ static int init_section_ref_ok(const char *name)
        for (s = namelist1; *s; s++)
                if (strcmp(*s, name) == 0)
                        return 1;
-       for (s = namelist2; *s; s++)    
+       for (s = namelist2; *s; s++)
                if (strncmp(*s, name, strlen(*s)) == 0)
                        return 1;
-       for (s = namelist3; *s; s++)    
-               if (strstr(*s, name) != NULL)
+       for (s = namelist3; *s; s++)
+               if (strstr(name, *s) != NULL)
                        return 1;
        return 0;
 }
@@ -792,16 +813,17 @@ static int exit_section(const char *name)
        if (strcmp(name, ".exit.data") == 0)
                return 1;
        return 0;
-       
+
 }
 
 /*
  * Identify sections from which references to a .exit section is OK.
- * 
+ *
  * [OPD] Keith Ownes <kaos@sgi.com> commented:
  * For our future {in}sanity, add a comment that this is the ppc .opd
  * section, not the ia64 .opd section.
  * ia64 .opd should not point to discarded sections.
+ * [.rodata] like for .init.text we ignore .rodata references -same reason
  **/
 static int exit_section_ref_ok(const char *name)
 {
@@ -811,9 +833,12 @@ static int exit_section_ref_ok(const char *name)
                ".exit.text",
                ".exit.data",
                ".init.text",
+               ".rodata",
                ".opd", /* See comment [OPD] */
+               ".toc1",  /* used by ppc64 */
                ".altinstructions",
                ".pdr",
+               "__bug_table", /* used by powerpc for BUG() */
                ".exitcall.exit",
                ".eh_frame",
                ".stab",
@@ -829,15 +854,15 @@ static int exit_section_ref_ok(const char *name)
                ".unwind",  /* Sample: IA_64.unwind.exit.text */
                NULL
        };
-       
+
        for (s = namelist1; *s; s++)
                if (strcmp(*s, name) == 0)
                        return 1;
-       for (s = namelist2; *s; s++)    
+       for (s = namelist2; *s; s++)
                if (strncmp(*s, name, strlen(*s)) == 0)
                        return 1;
-       for (s = namelist3; *s; s++)    
-               if (strstr(*s, name) != NULL)
+       for (s = namelist3; *s; s++)
+               if (strstr(name, *s) != NULL)
                        return 1;
        return 0;
 }
@@ -900,22 +925,17 @@ void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
        char tmp[SZ];
        int len;
        va_list ap;
-       
+
        va_start(ap, fmt);
        len = vsnprintf(tmp, SZ, fmt, ap);
-       if (buf->size - buf->pos < len + 1) {
-               buf->size += 128;
-               buf->p = realloc(buf->p, buf->size);
-       }
-       strncpy(buf->p + buf->pos, tmp, len + 1);
-       buf->pos += len;
+       buf_write(buf, tmp, len);
        va_end(ap);
 }
 
 void buf_write(struct buffer *buf, const char *s, int len)
 {
        if (buf->size - buf->pos < len) {
-               buf->size += len;
+               buf->size += len + SZ;
                buf->p = realloc(buf->p, buf->size);
        }
        strncpy(buf->p + buf->pos, s, len);
@@ -1129,7 +1149,7 @@ static int dump_sym(struct symbol *sym)
                return 0;
        return 1;
 }
-               
+
 static void write_dump(const char *fname)
 {
        struct buffer buf = { };
@@ -1141,7 +1161,7 @@ static void write_dump(const char *fname)
                while (symbol) {
                        if (dump_sym(symbol))
                                buf_printf(&buf, "0x%08x\t%s\t%s\n",
-                                       symbol->crc, symbol->name, 
+                                       symbol->crc, symbol->name,
                                        symbol->module->name);
                        symbol = symbol->next;
                }