[PARISC] rename *_ANY_ID to PA_*_ANY_ID in the exported header
[safe/jmp/linux-2.6] / scripts / mod / modpost.c
index d03c9ff..47bef62 100644 (file)
@@ -23,8 +23,13 @@ int have_vmlinux = 0;
 static int all_versions = 0;
 /* If we are modposting external module set to 1 */
 static int external_module = 0;
+/* Only warn about unresolved symbols */
+static int warn_unresolved = 0;
 /* How a symbol is exported */
-enum export {export_plain, export_gpl, export_gpl_future, export_unknown};
+enum export {
+       export_plain,      export_unused,     export_gpl,
+       export_unused_gpl, export_gpl_future, export_unknown
+};
 
 void fatal(const char *fmt, ...)
 {
@@ -191,7 +196,9 @@ static struct {
        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 },
 };
@@ -205,6 +212,8 @@ static const char *export_str(enum export ex)
 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;
@@ -216,8 +225,12 @@ 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
@@ -330,7 +343,7 @@ static void parse_elf(struct elf_info *info, const char *filename)
        hdr = grab_file(filename, &info->size);
        if (!hdr) {
                perror(filename);
-               abort();
+               exit(1);
        }
        info->hdr = hdr;
        if (info->size < sizeof(*hdr))
@@ -366,8 +379,12 @@ static void parse_elf(struct elf_info *info, const char *filename)
                        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;
 
@@ -565,9 +582,19 @@ static int strrcmp(const char *s, const char *sub)
  *   tosec   = .init.text | .exit.text | .init.data
  *   fromsec = .data
  *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
+ *
+ * Pattern 3:
+ *   Some symbols belong to init section but still it is ok to reference
+ *   these from non-init sections as these symbols don't have any memory
+ *   allocated for them and symbol address and value are same. So even
+ *   if init section is freed, its ok to reference those symbols.
+ *   For ex. symbols marking the init section boundaries.
+ *   This pattern is identified by
+ *   refsymname = __init_begin, _sinittext, _einittext
  **/
-static int secref_whitelist(const char *tosec, const char *fromsec,
-                           const char *atsym)
+static int secref_whitelist(const char *modname, const char *tosec,
+                           const char *fromsec, const char *atsym,
+                           const char *refsymname)
 {
        int f1 = 1, f2 = 1;
        const char **s;
@@ -578,6 +605,14 @@ static int secref_whitelist(const char *tosec, const char *fromsec,
                "_ops",
                "_probe",
                "_probe_one",
+               "_console",
+               NULL
+       };
+
+       const char *pat3refsym[] = {
+               "__init_begin",
+               "_sinittext",
+               "_einittext",
                NULL
        };
 
@@ -603,8 +638,21 @@ static int secref_whitelist(const char *tosec, const char *fromsec,
        for (s = pat2sym; *s; s++)
                if (strrcmp(atsym, *s) == 0)
                        f1 = 1;
+       if (f1 && f2)
+               return 1;
+
+       /* Whitelist all references from .pci_fixup section if vmlinux */
+       if (is_vmlinux(modname)) {
+               if ((strcmp(fromsec, ".pci_fixup") == 0) &&
+                   (strcmp(tosec, ".init.text") == 0))
+               return 1;
 
-       return f1 && f2;
+               /* Check for pattern 3 */
+               for (s = pat3refsym; *s; s++)
+                       if (strcmp(refsymname, *s) == 0)
+                               return 1;
+       }
+       return 0;
 }
 
 /**
@@ -711,7 +759,8 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
 
        /* check whitelist - we may ignore it */
        if (before &&
-           secref_whitelist(secname, fromsec, elf->strtab + before->st_name))
+           secref_whitelist(modname, secname, fromsec,
+                            elf->strtab + before->st_name, refsymname))
                return;
 
        if (before && after) {
@@ -884,15 +933,20 @@ static int init_section_ref_ok(const char *name)
                ".opd",   /* see comment [OPD] at exit_section_ref_ok() */
                ".toc1",  /* used by ppc64 */
                ".stab",
-               ".rodata",
+               ".data.rel.ro", /* used by parisc64 */
+               ".parainstructions",
                ".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 */
+               "__ftr_fixup",          /* powerpc cpu feature fixup */
+               "__fw_ftr_fixup",       /* powerpc firmware feature fixup */
                NULL
        };
        /* Start of section names */
@@ -901,6 +955,8 @@ static int init_section_ref_ok(const char *name)
                ".altinstructions",
                ".eh_frame",
                ".debug",
+               ".parainstructions",
+               ".rodata",
                NULL
        };
        /* part of section name */
@@ -918,6 +974,8 @@ static int init_section_ref_ok(const char *name)
        for (s = namelist3; *s; s++)
                if (strstr(name, *s) != NULL)
                        return 1;
+       if (strrcmp(name, ".init") == 0)
+               return 1;
        return 0;
 }
 
@@ -963,7 +1021,10 @@ static int exit_section_ref_ok(const char *name)
                "__bug_table", /* used by powerpc for BUG() */
                ".exitcall.exit",
                ".eh_frame",
+               ".parainstructions",
                ".stab",
+               "__ex_table",
+               ".fixup",
                ".smp_locks",
                ".plt",  /* seen on ARCH=um build on x86_64. Harmless */
                NULL
@@ -1079,38 +1140,64 @@ void buf_write(struct buffer *buf, const char *s, int len)
        buf->pos += len;
 }
 
-void check_license(struct module *mod)
+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;
-               if (mod->gpl_compatible == 1) {
-                       /* GPL-compatible modules may use all symbols */
-                       continue;
-               }
                exp = find_symbol(s->name);
                if (!exp || exp->module == mod)
                        continue;
                basename = strrchr(mod->name, '/');
                if (basename)
                        basename++;
-               switch (exp->export) {
-                       case export_gpl:
-                               fatal("modpost: GPL-incompatible module %s "
-                                     "uses GPL-only symbol '%s'\n",
-                                basename ? basename : mod->name,
-                               exp->name);
-                               break;
-                       case export_gpl_future:
-                               warn("modpost: GPL-incompatible module %s "
-                                     "uses future GPL-only symbol '%s'\n",
-                                     basename ? basename : mod->name,
-                                     exp->name);
-                               break;
-                       case export_plain: /* ignore */ break;
-                       case export_unknown: /* ignore */ break;
-               }
+               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);
         }
 }
 
@@ -1140,16 +1227,19 @@ static void add_header(struct buffer *b, struct module *mod)
 /**
  * Record CRCs for unresolved symbols
  **/
-static void add_versions(struct buffer *b, struct module *mod)
+static int add_versions(struct buffer *b, struct module *mod)
 {
        struct symbol *s, *exp;
+       int err = 0;
 
        for (s = mod->unres; s; s = s->next) {
                exp = find_symbol(s->name);
                if (!exp || exp->module == mod) {
-                       if (have_vmlinux && !s->weak)
+                       if (have_vmlinux && !s->weak) {
                                warn("\"%s\" [%s.ko] undefined!\n",
                                     s->name, mod->name);
+                               err = warn_unresolved ? 0 : 1;
+                       }
                        continue;
                }
                s->module = exp->module;
@@ -1158,7 +1248,7 @@ static void add_versions(struct buffer *b, struct module *mod)
        }
 
        if (!modversions)
-               return;
+               return err;
 
        buf_printf(b, "\n");
        buf_printf(b, "static const struct modversion_info ____versions[]\n");
@@ -1178,6 +1268,8 @@ static void add_versions(struct buffer *b, struct module *mod)
        }
 
        buf_printf(b, "};\n");
+
+       return err;
 }
 
 static void add_depends(struct buffer *b, struct module *mod,
@@ -1265,7 +1357,7 @@ static void write_if_changed(struct buffer *b, const char *fname)
 }
 
 /* parse Module.symvers file. line format:
- * 0x12345678<tab>symbol<tab>module[<tab>export]
+ * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
  **/
 static void read_dump(const char *fname, unsigned int kernel)
 {
@@ -1278,7 +1370,7 @@ static void read_dump(const char *fname, unsigned int kernel)
                return;
 
        while ((line = get_next_line(&pos, file, size))) {
-               char *symname, *modname, *d, *export;
+               char *symname, *modname, *d, *export, *end;
                unsigned int crc;
                struct module *mod;
                struct symbol *s;
@@ -1291,7 +1383,8 @@ static void read_dump(const char *fname, unsigned int kernel)
                *modname++ = '\0';
                if ((export = strchr(modname, '\t')) != NULL)
                        *export++ = '\0';
-
+               if (export && ((end = strchr(export, '\t')) != NULL))
+                       *end = '\0';
                crc = strtoul(line, &d, 16);
                if (*symname == '\0' || *modname == '\0' || *d != '\0')
                        goto fail;
@@ -1354,8 +1447,9 @@ int main(int argc, char **argv)
        char *kernel_read = NULL, *module_read = NULL;
        char *dump_write = NULL;
        int opt;
+       int err;
 
-       while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) {
+       while ((opt = getopt(argc, argv, "i:I:mo:aw")) != -1) {
                switch(opt) {
                        case 'i':
                                kernel_read = optarg;
@@ -1373,6 +1467,9 @@ int main(int argc, char **argv)
                        case 'a':
                                all_versions = 1;
                                break;
+                       case 'w':
+                               warn_unresolved = 1;
+                               break;
                        default:
                                exit(1);
                }
@@ -1390,9 +1487,11 @@ int main(int argc, char **argv)
        for (mod = modules; mod; mod = mod->next) {
                if (mod->skip)
                        continue;
-               check_license(mod);
+               check_exports(mod);
        }
 
+       err = 0;
+
        for (mod = modules; mod; mod = mod->next) {
                if (mod->skip)
                        continue;
@@ -1400,7 +1499,7 @@ int main(int argc, char **argv)
                buf.pos = 0;
 
                add_header(&buf, mod);
-               add_versions(&buf, mod);
+               err |= add_versions(&buf, mod);
                add_depends(&buf, mod, modules);
                add_moddevtable(&buf, mod);
                add_srcversion(&buf, mod);
@@ -1412,5 +1511,5 @@ int main(int argc, char **argv)
        if (dump_write)
                write_dump(dump_write);
 
-       return 0;
+       return err;
 }