linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / scripts / mod / modpost.c
index dfde0e8..b8b2a56 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Copyright 2003       Kai Germaschewski
  * Copyright 2002-2004  Rusty Russell, IBM Corporation
- * Copyright 2006       Sam Ravnborg
+ *
  * Based in part on module-init-tools/depmod.c,file2alias
  *
  * This software may be used and distributed according to the terms
@@ -13,7 +13,6 @@
 
 #include <ctype.h>
 #include "modpost.h"
-#include "../../include/linux/license.h"
 
 /* Are we using CONFIG_MODVERSIONS? */
 int modversions = 0;
@@ -21,15 +20,9 @@ int modversions = 0;
 int have_vmlinux = 0;
 /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
 static int all_versions = 0;
-/* If we are modposting external module set to 1 */
-static int external_module = 0;
-/* How a symbol is exported */
-enum export {
-       export_plain,      export_unused,     export_gpl,
-       export_unused_gpl, export_gpl_future, export_unknown
-};
 
-void fatal(const char *fmt, ...)
+void
+fatal(const char *fmt, ...)
 {
        va_list arglist;
 
@@ -42,7 +35,8 @@ void fatal(const char *fmt, ...)
        exit(1);
 }
 
-void warn(const char *fmt, ...)
+void
+warn(const char *fmt, ...)
 {
        va_list arglist;
 
@@ -53,18 +47,6 @@ void warn(const char *fmt, ...)
        va_end(arglist);
 }
 
-static int is_vmlinux(const char *modname)
-{
-       const char *myname;
-
-       if ((myname = strrchr(modname, '/')))
-               myname++;
-       else
-               myname = modname;
-
-       return strcmp(myname, "vmlinux") == 0;
-}
-
 void *do_nofail(void *ptr, const char *expr)
 {
        if (!ptr) {
@@ -77,7 +59,8 @@ void *do_nofail(void *ptr, const char *expr)
 
 static struct module *modules;
 
-static struct module *find_module(char *modname)
+struct module *
+find_module(char *modname)
 {
        struct module *mod;
 
@@ -87,11 +70,12 @@ static struct module *find_module(char *modname)
        return mod;
 }
 
-static struct module *new_module(char *modname)
+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));
@@ -103,7 +87,6 @@ static struct module *new_module(char *modname)
 
        /* add to list */
        mod->name = p;
-       mod->gpl_compatible = -1;
        mod->next = modules;
        modules = mod;
 
@@ -121,11 +104,6 @@ struct symbol {
        unsigned int crc;
        int crc_valid;
        unsigned int weak:1;
-       unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
-       unsigned int kernel:1;     /* 1 if symbol is from kernel
-                                   *  (only for external modules) **/
-       unsigned int preloaded:1;  /* 1 if symbol from Module.symvers */
-       enum export  export;       /* Type of export */
        char name[0];
 };
 
@@ -144,12 +122,11 @@ static inline unsigned int tdb_hash(const char *name)
        return (1103515243 * value + 12345);
 }
 
-/**
- * Allocate a new symbols for use in the hash of exported symbols or
- * the list of unresolved symbols per module
- **/
-static struct symbol *alloc_symbol(const char *name, unsigned int weak,
-                                  struct symbol *next)
+/* Allocate a new symbols for use in the hash of exported symbols or
+ * the list of unresolved symbols per module */
+
+struct symbol *
+alloc_symbol(const char *name, unsigned int weak, struct symbol *next)
 {
        struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
 
@@ -161,8 +138,9 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak,
 }
 
 /* For the hash of exported symbols */
-static struct symbol *new_symbol(const char *name, struct module *module,
-                                enum export export)
+
+void
+new_symbol(const char *name, struct module *module, unsigned int *crc)
 {
        unsigned int hash;
        struct symbol *new;
@@ -170,11 +148,14 @@ static struct symbol *new_symbol(const char *name, struct module *module,
        hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
        new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
        new->module = module;
-       new->export = export;
-       return new;
+       if (crc) {
+               new->crc = *crc;
+               new->crc_valid = 1;
+       }
 }
 
-static struct symbol *find_symbol(const char *name)
+struct symbol *
+find_symbol(const char *name)
 {
        struct symbol *s;
 
@@ -189,90 +170,25 @@ static struct symbol *find_symbol(const char *name)
        return NULL;
 }
 
-static struct {
-       const char *str;
-       enum export export;
-} export_list[] = {
-       { .str = "EXPORT_SYMBOL",            .export = export_plain },
-       { .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
-       { .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
-       { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
-       { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
-       { .str = "(unknown)",                .export = export_unknown },
-};
-
-
-static const char *export_str(enum export ex)
-{
-       return export_list[ex].str;
-}
-
-static enum export export_no(const char * s)
-{
-       int i;
-       if (!s)
-               return export_unknown;
-       for (i = 0; export_list[i].export != export_unknown; i++) {
-               if (strcmp(export_list[i].str, s) == 0)
-                       return export_list[i].export;
-       }
-       return export_unknown;
-}
-
-static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
-{
-       if (sec == elf->export_sec)
-               return export_plain;
-       else if (sec == elf->export_unused_sec)
-               return export_unused;
-       else if (sec == elf->export_gpl_sec)
-               return export_gpl;
-       else if (sec == elf->export_unused_gpl_sec)
-               return export_unused_gpl;
-       else if (sec == elf->export_gpl_future_sec)
-               return export_gpl_future;
-       else
-               return export_unknown;
-}
-
-/**
- * Add an exported symbol - it may have already been added without a
- * CRC, in this case just update the CRC
- **/
-static struct symbol *sym_add_exported(const char *name, struct module *mod,
-                                      enum export export)
+/* Add an exported symbol - it may have already been added without a
+ * CRC, in this case just update the CRC */
+void
+add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
 {
        struct symbol *s = find_symbol(name);
 
        if (!s) {
-               s = new_symbol(name, mod, export);
-       } else {
-               if (!s->preloaded) {
-                       warn("%s: '%s' exported twice. Previous export "
-                            "was in %s%s\n", mod->name, name,
-                            s->module->name,
-                            is_vmlinux(s->module->name) ?"":".ko");
-               }
+               new_symbol(name, module, crc);
+               return;
+       }
+       if (crc) {
+               s->crc = *crc;
+               s->crc_valid = 1;
        }
-       s->preloaded = 0;
-       s->vmlinux   = is_vmlinux(mod->name);
-       s->kernel    = 0;
-       s->export    = export;
-       return s;
-}
-
-static void sym_update_crc(const char *name, struct module *mod,
-                          unsigned int crc, enum export export)
-{
-       struct symbol *s = find_symbol(name);
-
-       if (!s)
-               s = new_symbol(name, mod, export);
-       s->crc = crc;
-       s->crc_valid = 1;
 }
 
-void *grab_file(const char *filename, unsigned long *size)
+void *
+grab_file(const char *filename, unsigned long *size)
 {
        struct stat st;
        void *map;
@@ -291,12 +207,13 @@ void *grab_file(const char *filename, unsigned long *size)
        return map;
 }
 
-/**
-  * Return a copy of the next line in a mmap'ed file.
-  * spaces in the beginning of the line is trimmed away.
-  * Return a pointer to a static buffer.
-  **/
-char* get_next_line(unsigned long *pos, void *file, unsigned long size)
+/*
+   Return a copy of the next line in a mmap'ed file.
+   spaces in the beginning of the line is trimmed away.
+   Return a pointer to a static buffer.
+*/
+char*
+get_next_line(unsigned long *pos, void *file, unsigned long size)
 {
        static char line[4096];
        int skip = 1;
@@ -326,12 +243,14 @@ char* get_next_line(unsigned long *pos, void *file, unsigned long size)
        return NULL;
 }
 
-void release_file(void *file, unsigned long size)
+void
+release_file(void *file, unsigned long size)
 {
        munmap(file, size);
 }
 
-static void parse_elf(struct elf_info *info, const char *filename)
+void
+parse_elf(struct elf_info *info, const char *filename)
 {
        unsigned int i;
        Elf_Ehdr *hdr = info->hdr;
@@ -341,7 +260,7 @@ static void parse_elf(struct elf_info *info, const char *filename)
        hdr = grab_file(filename, &info->size);
        if (!hdr) {
                perror(filename);
-               exit(1);
+               abort();
        }
        info->hdr = hdr;
        if (info->size < sizeof(*hdr))
@@ -367,36 +286,25 @@ static void parse_elf(struct elf_info *info, const char *filename)
        for (i = 1; i < hdr->e_shnum; i++) {
                const char *secstrings
                        = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-               const char *secname;
 
                if (sechdrs[i].sh_offset > info->size)
                        goto truncated;
-               secname = secstrings + sechdrs[i].sh_name;
-               if (strcmp(secname, ".modinfo") == 0) {
+               if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
                        info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
                        info->modinfo_len = sechdrs[i].sh_size;
-               } else if (strcmp(secname, "__ksymtab") == 0)
-                       info->export_sec = i;
-               else if (strcmp(secname, "__ksymtab_unused") == 0)
-                       info->export_unused_sec = i;
-               else if (strcmp(secname, "__ksymtab_gpl") == 0)
-                       info->export_gpl_sec = i;
-               else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
-                       info->export_unused_gpl_sec = i;
-               else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
-                       info->export_gpl_future_sec = i;
-
+               }
                if (sechdrs[i].sh_type != SHT_SYMTAB)
                        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) {
-               fatal("%s has no symtab?\n", filename);
+               fprintf(stderr, "modpost: %s no symtab?\n", filename);
+               abort();
        }
        /* Fix endianness in symbols */
        for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
@@ -408,33 +316,36 @@ static void parse_elf(struct elf_info *info, const char *filename)
        return;
 
  truncated:
-       fatal("%s is truncated.\n", filename);
+       fprintf(stderr, "modpost: %s is truncated.\n", filename);
+       abort();
 }
 
-static void parse_elf_finish(struct elf_info *info)
+void
+parse_elf_finish(struct elf_info *info)
 {
        release_file(info->hdr, info->size);
 }
 
-#define CRC_PFX     MODULE_SYMBOL_PREFIX "__crc_"
-#define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_"
+#define CRC_PFX     "__crc_"
+#define KSYMTAB_PFX "__ksymtab_"
 
-static void handle_modversions(struct module *mod, struct elf_info *info,
-                              Elf_Sym *sym, const char *symname)
+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);
 
        switch (sym->st_shndx) {
        case SHN_COMMON:
-               warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
+               fprintf(stderr, "*** Warning: \"%s\" [%s] is COMMON symbol\n",
+                       symname, mod->name);
                break;
        case SHN_ABS:
                /* CRC'd symbol */
                if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
                        crc = (unsigned int) sym->st_value;
-                       sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
-                                       export);
+                       add_exported_symbol(symname + strlen(CRC_PFX),
+                                           mod, &crc);
                }
                break;
        case SHN_UNDEF:
@@ -459,15 +370,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 +
@@ -478,8 +389,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
        default:
                /* All exported symbols */
                if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
-                       sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
-                                       export);
+                       add_exported_symbol(symname + strlen(KSYMTAB_PFX),
+                                           mod, NULL);
                }
                if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
                        mod->has_init = 1;
@@ -489,9 +400,20 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
        }
 }
 
-/**
- * Parse tag=value strings from .modinfo section
- **/
+int
+is_vmlinux(const char *modname)
+{
+       const char *myname;
+
+       if ((myname = strrchr(modname, '/')))
+               myname++;
+       else
+               myname = modname;
+
+       return strcmp(myname, "vmlinux") == 0;
+}
+
+/* Parse tag=value strings from .modinfo section */
 static char *next_string(char *string, unsigned long *secsize)
 {
        /* Skip non-zero chars */
@@ -510,18 +432,13 @@ static char *next_string(char *string, unsigned long *secsize)
        return string;
 }
 
-static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
-                             const char *tag, char *info)
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+                        const char *tag)
 {
        char *p;
        unsigned int taglen = strlen(tag);
        unsigned long size = modinfo_len;
 
-       if (info) {
-               size -= info - (char *)modinfo;
-               modinfo = next_string(info, &size);
-       }
-
        for (p = modinfo; p; p = next_string(p, &size)) {
                if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
                        return p + taglen + 1;
@@ -529,494 +446,11 @@ static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
        return NULL;
 }
 
-static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
-                        const char *tag)
-
-{
-       return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
-}
-
-/**
- * Test if string s ends in string sub
- * return 0 if match
- **/
-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;
-
-        if (sublen > slen)
-                return 1;
-
-        return memcmp(s + slen - sublen, sub, sublen);
-}
-
-/**
- * Whitelist to allow certain references to pass with no warning.
- * Pattern 1:
- *   If a module parameter is declared __initdata and permissions=0
- *   then this is legal despite the warning generated.
- *   We cannot see value of permissions here, so just ignore
- *   this pattern.
- *   The pattern is identified by:
- *   tosec   = .init.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 | .init.data
- *   fromsec = .data
- *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
- **/
-static int secref_whitelist(const char *tosec, const char *fromsec,
-                           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 (strncmp(fromsec, ".data", strlen(".data")) != 0)
-               f1 = 0;
-       if (strncmp(atsym, "__param", strlen("__param")) != 0)
-               f1 = 0;
-
-       if (f1)
-               return f1;
-
-       /* Check for pattern 2 */
-       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;
-
-       for (s = pat2sym; *s; s++)
-               if (strrcmp(atsym, *s) == 0)
-                       f1 = 1;
-
-       return f1 && f2;
-}
-
-/**
- * Find symbol based on relocation record info.
- * In some cases the symbol supplied is a valid symbol so
- * return refsym. If st_name != 0 we assume this is a valid symbol.
- * In other cases the symbol needs to be looked up in the symbol table
- * based on section and address.
- *  **/
-static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
-                               Elf_Sym *relsym)
-{
-       Elf_Sym *sym;
-
-       if (relsym->st_name != 0)
-               return relsym;
-       for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
-               if (sym->st_shndx != relsym->st_shndx)
-                       continue;
-               if (sym->st_value == addr)
-                       return sym;
-       }
-       return NULL;
-}
-
-/*
- * 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,
-                                Elf_Sym **before, Elf_Sym **after)
-{
-       Elf_Sym *sym;
-       Elf_Ehdr *hdr = elf->hdr;
-       Elf_Addr beforediff = ~0;
-       Elf_Addr afterdiff = ~0;
-       const char *secstrings = (void *)hdr +
-                                elf->sechdrs[hdr->e_shstrndx].sh_offset;
-
-       *before = NULL;
-       *after = NULL;
-
-       for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
-               const char *symsec;
-
-               if (sym->st_shndx >= SHN_LORESERVE)
-                       continue;
-               symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name;
-               if (strcmp(symsec, sec) != 0)
-                       continue;
-               if (sym->st_value <= addr) {
-                       if ((addr - sym->st_value) < beforediff) {
-                               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
-               {
-                       if ((sym->st_value - addr) < afterdiff) {
-                               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;
-                       }
-               }
-       }
-}
-
-/**
- * Print a warning about a section mismatch.
- * Try to find symbols near it so user can find it.
- * Check whitelist before warning - it may be a false positive.
- **/
-static void warn_sec_mismatch(const char *modname, const char *fromsec,
-                             struct elf_info *elf, Elf_Sym *sym, Elf_Rela r)
-{
-       const char *refsymname = "";
-       Elf_Sym *before, *after;
-       Elf_Sym *refsym;
-       Elf_Ehdr *hdr = elf->hdr;
-       Elf_Shdr *sechdrs = elf->sechdrs;
-       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);
-       if (refsym && strlen(elf->strtab + refsym->st_name))
-               refsymname = elf->strtab + refsym->st_name;
-
-       /* check whitelist - we may ignore it */
-       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",
-                    modname, secname, refsymname, fromsec,
-                    elf->strtab + before->st_name,
-                    (long long)r.r_offset,
-                    elf->strtab + after->st_name);
-       } else if (before) {
-               warn("%s - Section mismatch: reference to %s:%s from %s "
-                    "after '%s' (at offset 0x%llx)\n",
-                    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 + after->st_name,
-                    (long long)r.r_offset);
-       } else {
-               warn("%s - Section mismatch: reference to %s:%s from %s "
-                    "(offset 0x%llx)\n",
-                    modname, secname, fromsec, refsymname,
-                    (long long)r.r_offset);
-       }
-}
-
-/**
- * A module includes a number of sections that are discarded
- * either when loaded or when used as built-in.
- * For loaded modules all functions marked __init and all data
- * marked __initdata will be discarded when the module has been intialized.
- * Likewise for modules used built-in the sections marked __exit
- * are discarded because __exit marked function are supposed to be called
- * only when a moduel is unloaded which never happes for built-in modules.
- * The check_sec_ref() function traverses all relocation records
- * to find all references to a section that reference a section that will
- * be discarded and warns about it.
- **/
-static void check_sec_ref(struct module *mod, const char *modname,
-                         struct elf_info *elf,
-                         int section(const char*),
-                         int section_ref_ok(const char *))
-{
-       int i;
-       Elf_Sym  *sym;
-       Elf_Ehdr *hdr = elf->hdr;
-       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++) {
-               const char *name = secstrings + sechdrs[i].sh_name;
-               const char *secname;
-               Elf_Rela r;
-               unsigned int r_sym;
-               /* We want to process only relocation sections and not .init */
-               if (sechdrs[i].sh_type == SHT_RELA) {
-                       Elf_Rela *rela;
-                       Elf_Rela *start = (void *)hdr + sechdrs[i].sh_offset;
-                       Elf_Rela *stop  = (void*)start + sechdrs[i].sh_size;
-                       name += strlen(".rela");
-                       if (section_ref_ok(name))
-                               continue;
-
-                       for (rela = start; rela < stop; rela++) {
-                               r.r_offset = TO_NATIVE(rela->r_offset);
-#if KERNEL_ELFCLASS == ELFCLASS64
-                               if (hdr->e_machine == EM_MIPS) {
-                                       r_sym = ELF64_MIPS_R_SYM(rela->r_info);
-                                       r_sym = TO_NATIVE(r_sym);
-                               } else {
-                                       r.r_info = TO_NATIVE(rela->r_info);
-                                       r_sym = ELF_R_SYM(r.r_info);
-                               }
-#else
-                               r.r_info = TO_NATIVE(rela->r_info);
-                               r_sym = ELF_R_SYM(r.r_info);
-#endif
-                               r.r_addend = TO_NATIVE(rela->r_addend);
-                               sym = elf->symtab_start + r_sym;
-                               /* Skip special sections */
-                               if (sym->st_shndx >= SHN_LORESERVE)
-                                       continue;
-
-                               secname = secstrings +
-                                       sechdrs[sym->st_shndx].sh_name;
-                               if (section(secname))
-                                       warn_sec_mismatch(modname, name,
-                                                         elf, sym, r);
-                       }
-               } else if (sechdrs[i].sh_type == SHT_REL) {
-                       Elf_Rel *rel;
-                       Elf_Rel *start = (void *)hdr + sechdrs[i].sh_offset;
-                       Elf_Rel *stop  = (void*)start + sechdrs[i].sh_size;
-                       name += strlen(".rel");
-                       if (section_ref_ok(name))
-                               continue;
-
-                       for (rel = start; rel < stop; rel++) {
-                               r.r_offset = TO_NATIVE(rel->r_offset);
-#if KERNEL_ELFCLASS == ELFCLASS64
-                               if (hdr->e_machine == EM_MIPS) {
-                                       r_sym = ELF64_MIPS_R_SYM(rel->r_info);
-                                       r_sym = TO_NATIVE(r_sym);
-                               } else {
-                                       r.r_info = TO_NATIVE(rel->r_info);
-                                       r_sym = ELF_R_SYM(r.r_info);
-                               }
-#else
-                               r.r_info = TO_NATIVE(rel->r_info);
-                               r_sym = ELF_R_SYM(r.r_info);
-#endif
-                               r.r_addend = 0;
-                               sym = elf->symtab_start + r_sym;
-                               /* Skip special sections */
-                               if (sym->st_shndx >= SHN_LORESERVE)
-                                       continue;
-
-                               secname = secstrings +
-                                       sechdrs[sym->st_shndx].sh_name;
-                               if (section(secname))
-                                       warn_sec_mismatch(modname, name,
-                                                         elf, sym, r);
-                       }
-               }
-       }
-}
-
-/**
- * Functions used only during module init is marked __init and is stored in
- * a .init.text section. Likewise data is marked __initdata and stored in
- * a .init.data section.
- * If this section is one of these sections return 1
- * See include/linux/init.h for the details
- **/
-static int init_section(const char *name)
-{
-       if (strcmp(name, ".init") == 0)
-               return 1;
-       if (strncmp(name, ".init.", strlen(".init.")) == 0)
-               return 1;
-       return 0;
-}
-
-/**
- * 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,
- *
- * where vgacon_startup is __init.  If you want to wade through the false
- * positives, take out the check for rodata.
- **/
-static int init_section_ref_ok(const char *name)
-{
-       const char **s;
-       /* 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",
-               "__param",
-               "__ex_table",
-               ".fixup",
-               ".smp_locks",
-               ".plt",  /* seen on ARCH=um build on x86_64. Harmless */
-               NULL
-       };
-       /* Start of section names */
-       const char *namelist2[] = {
-               ".init.",
-               ".altinstructions",
-               ".eh_frame",
-               ".debug",
-               NULL
-       };
-       /* part of section name */
-       const char *namelist3 [] = {
-               ".unwind",  /* sample: IA_64.unwind.init.text */
-               NULL
-       };
-
-       for (s = namelist1; *s; s++)
-               if (strcmp(*s, name) == 0)
-                       return 1;
-       for (s = namelist2; *s; s++)
-               if (strncmp(*s, name, strlen(*s)) == 0)
-                       return 1;
-       for (s = namelist3; *s; s++)
-               if (strstr(name, *s) != NULL)
-                       return 1;
-       if (strrcmp(name, ".init") == 0)
-               return 1;
-       return 0;
-}
-
-/*
- * Functions used only during module exit is marked __exit and is stored in
- * a .exit.text section. Likewise data is marked __exitdata and stored in
- * a .exit.data section.
- * If this section is one of these sections return 1
- * See include/linux/init.h for the details
- **/
-static int exit_section(const char *name)
-{
-       if (strcmp(name, ".exit.text") == 0)
-               return 1;
-       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)
-{
-       const char **s;
-       /* Absolute section names */
-       const char *namelist1[] = {
-               ".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",
-               "__ex_table",
-               ".fixup",
-               ".smp_locks",
-               ".plt",  /* seen on ARCH=um build on x86_64. Harmless */
-               NULL
-       };
-       /* Start of section names */
-       const char *namelist2[] = {
-               ".debug",
-               NULL
-       };
-       /* part of section name */
-       const char *namelist3 [] = {
-               ".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++)
-               if (strncmp(*s, name, strlen(*s)) == 0)
-                       return 1;
-       for (s = namelist3; *s; s++)
-               if (strstr(name, *s) != NULL)
-                       return 1;
-       return 0;
-}
-
-static void read_symbols(char *modname)
+void
+read_symbols(char *modname)
 {
        const char *symname;
        char *version;
-       char *license;
        struct module *mod;
        struct elf_info info = { };
        Elf_Sym *sym;
@@ -1028,30 +462,18 @@ static void read_symbols(char *modname)
        /* When there's no vmlinux, don't print warnings about
         * unresolved symbols (since there'll be too many ;) */
        if (is_vmlinux(modname)) {
+               unsigned int fake_crc = 0;
                have_vmlinux = 1;
+               add_exported_symbol("struct_module", mod, &fake_crc);
                mod->skip = 1;
        }
 
-       license = get_modinfo(info.modinfo, info.modinfo_len, "license");
-       while (license) {
-               if (license_is_gpl_compatible(license))
-                       mod->gpl_compatible = 1;
-               else {
-                       mod->gpl_compatible = 0;
-                       break;
-               }
-               license = get_next_modinfo(info.modinfo, info.modinfo_len,
-                                          "license", license);
-       }
-
        for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
                symname = info.strtab + sym->st_name;
 
                handle_modversions(mod, &info, sym, symname);
                handle_moddevtable(mod, &info, sym, symname);
        }
-       check_sec_ref(mod, modname, &info, init_section, init_section_ref_ok);
-       check_sec_ref(mod, modname, &info, exit_section, exit_section_ref_ok);
 
        version = get_modinfo(info.modinfo, info.modinfo_len, "version");
        if (version)
@@ -1077,20 +499,21 @@ static void read_symbols(char *modname)
  * following helper, then compare to the file on disk and
  * only update the later if anything changed */
 
-void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
-                                                     const char *fmt, ...)
+void __attribute__((format(printf, 2, 3)))
+buf_printf(struct buffer *buf, const char *fmt, ...)
 {
        char tmp[SZ];
        int len;
        va_list ap;
-
+       
        va_start(ap, fmt);
        len = vsnprintf(tmp, SZ, fmt, ap);
        buf_write(buf, tmp, len);
        va_end(ap);
 }
 
-void buf_write(struct buffer *buf, const char *s, int len)
+void
+buf_write(struct buffer *buf, const char *s, int len)
 {
        if (buf->size - buf->pos < len) {
                buf->size += len + SZ;
@@ -1100,71 +523,10 @@ void buf_write(struct buffer *buf, const char *s, int len)
        buf->pos += len;
 }
 
-static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
-{
-       const char *e = is_vmlinux(m) ?"":".ko";
-
-       switch (exp) {
-       case export_gpl:
-               fatal("modpost: GPL-incompatible module %s%s "
-                     "uses GPL-only symbol '%s'\n", m, e, s);
-               break;
-       case export_unused_gpl:
-               fatal("modpost: GPL-incompatible module %s%s "
-                     "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
-               break;
-       case export_gpl_future:
-               warn("modpost: GPL-incompatible module %s%s "
-                     "uses future GPL-only symbol '%s'\n", m, e, s);
-               break;
-       case export_plain:
-       case export_unused:
-       case export_unknown:
-               /* ignore */
-               break;
-       }
-}
-
-static void check_for_unused(enum export exp, const char* m, const char* s)
-{
-       const char *e = is_vmlinux(m) ?"":".ko";
-
-       switch (exp) {
-       case export_unused:
-       case export_unused_gpl:
-               warn("modpost: module %s%s "
-                     "uses symbol '%s' marked UNUSED\n", m, e, s);
-               break;
-       default:
-               /* ignore */
-               break;
-       }
-}
-
-static void check_exports(struct module *mod)
-{
-       struct symbol *s, *exp;
-
-       for (s = mod->unres; s; s = s->next) {
-               const char *basename;
-               exp = find_symbol(s->name);
-               if (!exp || exp->module == mod)
-                       continue;
-               basename = strrchr(mod->name, '/');
-               if (basename)
-                       basename++;
-               else
-                       basename = mod->name;
-               if (!mod->gpl_compatible)
-                       check_for_gpl_usage(exp->export, basename, exp->name);
-               check_for_unused(exp->export, basename, exp->name);
-        }
-}
+/* Header for the generated file */
 
-/**
- * Header for the generated file
- **/
-static void add_header(struct buffer *b, struct module *mod)
+void
+add_header(struct buffer *b, struct module *mod)
 {
        buf_printf(b, "#include <linux/module.h>\n");
        buf_printf(b, "#include <linux/vermagic.h>\n");
@@ -1184,10 +546,10 @@ static void add_header(struct buffer *b, struct module *mod)
        buf_printf(b, "};\n");
 }
 
-/**
- * Record CRCs for unresolved symbols
- **/
-static void add_versions(struct buffer *b, struct module *mod)
+/* Record CRCs for unresolved symbols */
+
+void
+add_versions(struct buffer *b, struct module *mod)
 {
        struct symbol *s, *exp;
 
@@ -1195,8 +557,8 @@ static void add_versions(struct buffer *b, struct module *mod)
                exp = find_symbol(s->name);
                if (!exp || exp->module == mod) {
                        if (have_vmlinux && !s->weak)
-                               warn("\"%s\" [%s.ko] undefined!\n",
-                                    s->name, mod->name);
+                               fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
+                               "undefined!\n", s->name, mod->name);
                        continue;
                }
                s->module = exp->module;
@@ -1217,7 +579,8 @@ static void add_versions(struct buffer *b, struct module *mod)
                        continue;
                }
                if (!s->crc_valid) {
-                       warn("\"%s\" [%s.ko] has no CRC!\n",
+                       fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
+                               "has no CRC!\n",
                                s->name, mod->name);
                        continue;
                }
@@ -1227,8 +590,8 @@ static void add_versions(struct buffer *b, struct module *mod)
        buf_printf(b, "};\n");
 }
 
-static void add_depends(struct buffer *b, struct module *mod,
-                       struct module *modules)
+void
+add_depends(struct buffer *b, struct module *mod, struct module *modules)
 {
        struct symbol *s;
        struct module *m;
@@ -1258,7 +621,8 @@ static void add_depends(struct buffer *b, struct module *mod,
        buf_printf(b, "\";\n");
 }
 
-static void add_srcversion(struct buffer *b, struct module *mod)
+void
+add_srcversion(struct buffer *b, struct module *mod)
 {
        if (mod->srcversion[0]) {
                buf_printf(b, "\n");
@@ -1267,7 +631,8 @@ static void add_srcversion(struct buffer *b, struct module *mod)
        }
 }
 
-static void write_if_changed(struct buffer *b, const char *fname)
+void
+write_if_changed(struct buffer *b, const char *fname)
 {
        char *tmp;
        FILE *file;
@@ -1311,10 +676,8 @@ static void write_if_changed(struct buffer *b, const char *fname)
        fclose(file);
 }
 
-/* parse Module.symvers file. line format:
- * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
- **/
-static void read_dump(const char *fname, unsigned int kernel)
+void
+read_dump(const char *fname)
 {
        unsigned long size, pos = 0;
        void *file = grab_file(fname, &size);
@@ -1325,10 +688,9 @@ static void read_dump(const char *fname, unsigned int kernel)
                return;
 
        while ((line = get_next_line(&pos, file, size))) {
-               char *symname, *modname, *d, *export, *end;
+               char *symname, *modname, *d;
                unsigned int crc;
                struct module *mod;
-               struct symbol *s;
 
                if (!(symname = strchr(line, '\t')))
                        goto fail;
@@ -1336,10 +698,8 @@ static void read_dump(const char *fname, unsigned int kernel)
                if (!(modname = strchr(symname, '\t')))
                        goto fail;
                *modname++ = '\0';
-               if ((export = strchr(modname, '\t')) != NULL)
-                       *export++ = '\0';
-               if (export && ((end = strchr(export, '\t')) != NULL))
-                       *end = '\0';
+               if (strchr(modname, '\t'))
+                       goto fail;
                crc = strtoul(line, &d, 16);
                if (*symname == '\0' || *modname == '\0' || *d != '\0')
                        goto fail;
@@ -1351,30 +711,15 @@ static void read_dump(const char *fname, unsigned int kernel)
                        mod = new_module(NOFAIL(strdup(modname)));
                        mod->skip = 1;
                }
-               s = sym_add_exported(symname, mod, export_no(export));
-               s->kernel    = kernel;
-               s->preloaded = 1;
-               sym_update_crc(symname, mod, crc, export_no(export));
+               add_exported_symbol(symname, mod, &crc);
        }
        return;
 fail:
        fatal("parse error in symbol dump file\n");
 }
 
-/* For normal builds always dump all symbols.
- * For external modules only dump symbols
- * that are not read from kernel Module.symvers.
- **/
-static int dump_sym(struct symbol *sym)
-{
-       if (!external_module)
-               return 1;
-       if (sym->vmlinux || sym->kernel)
-               return 0;
-       return 1;
-}
-
-static void write_dump(const char *fname)
+void
+write_dump(const char *fname)
 {
        struct buffer buf = { };
        struct symbol *symbol;
@@ -1383,34 +728,34 @@ static void write_dump(const char *fname)
        for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
                symbol = symbolhash[n];
                while (symbol) {
-                       if (dump_sym(symbol))
-                               buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
-                                       symbol->crc, symbol->name,
-                                       symbol->module->name,
-                                       export_str(symbol->export));
+                       symbol = symbol->next;
+               }
+       }
+
+       for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+               symbol = symbolhash[n];
+               while (symbol) {
+                       buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
+                               symbol->name, symbol->module->name);
                        symbol = symbol->next;
                }
        }
        write_if_changed(&buf, fname);
 }
 
-int main(int argc, char **argv)
+int
+main(int argc, char **argv)
 {
        struct module *mod;
        struct buffer buf = { };
        char fname[SZ];
-       char *kernel_read = NULL, *module_read = NULL;
-       char *dump_write = NULL;
+       char *dump_read = NULL, *dump_write = NULL;
        int opt;
 
-       while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) {
+       while ((opt = getopt(argc, argv, "i:mo:a")) != -1) {
                switch(opt) {
                        case 'i':
-                               kernel_read = optarg;
-                               break;
-                       case 'I':
-                               module_read = optarg;
-                               external_module = 1;
+                               dump_read = optarg;
                                break;
                        case 'm':
                                modversions = 1;
@@ -1426,21 +771,13 @@ int main(int argc, char **argv)
                }
        }
 
-       if (kernel_read)
-               read_dump(kernel_read, 1);
-       if (module_read)
-               read_dump(module_read, 0);
+       if (dump_read)
+               read_dump(dump_read);
 
        while (optind < argc) {
                read_symbols(argv[optind++]);
        }
 
-       for (mod = modules; mod; mod = mod->next) {
-               if (mod->skip)
-                       continue;
-               check_exports(mod);
-       }
-
        for (mod = modules; mod; mod = mod->next) {
                if (mod->skip)
                        continue;
@@ -1462,3 +799,4 @@ int main(int argc, char **argv)
 
        return 0;
 }
+