kbuild: replace abort() with exit(1)
[powerpc.git] / scripts / mod / modpost.c
index 0b92ddf..0dd1617 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <ctype.h>
 #include "modpost.h"
+#include "../../include/linux/license.h"
 
 /* Are we using CONFIG_MODVERSIONS? */
 int modversions = 0;
@@ -22,6 +23,8 @@ int have_vmlinux = 0;
 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_gpl, export_gpl_future, export_unknown};
 
 void fatal(const char *fmt, ...)
 {
@@ -97,6 +100,7 @@ static struct module *new_module(char *modname)
 
        /* add to list */
        mod->name = p;
+       mod->gpl_compatible = -1;
        mod->next = modules;
        modules = mod;
 
@@ -118,6 +122,7 @@ struct symbol {
        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];
 };
 
@@ -153,7 +158,8 @@ 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)
+static struct symbol *new_symbol(const char *name, struct module *module,
+                                enum export export)
 {
        unsigned int hash;
        struct symbol *new;
@@ -161,6 +167,7 @@ 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;
 }
 
@@ -179,16 +186,55 @@ 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_SYMBOL_GPL",        .export = export_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;
+       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_gpl_sec)
+               return export_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)
+static struct symbol *sym_add_exported(const char *name, struct module *mod,
+                                      enum export export)
 {
        struct symbol *s = find_symbol(name);
 
        if (!s) {
-               s = new_symbol(name, mod);
+               s = new_symbol(name, mod, export);
        } else {
                if (!s->preloaded) {
                        warn("%s: '%s' exported twice. Previous export "
@@ -200,16 +246,17 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod)
        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)
+                          unsigned int crc, enum export export)
 {
        struct symbol *s = find_symbol(name);
 
        if (!s)
-               s = new_symbol(name, mod);
+               s = new_symbol(name, mod, export);
        s->crc = crc;
        s->crc_valid = 1;
 }
@@ -283,7 +330,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))
@@ -309,13 +356,21 @@ 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;
-               if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
+               secname = secstrings + sechdrs[i].sh_name;
+               if (strcmp(secname, ".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_gpl") == 0)
+                       info->export_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;
 
@@ -353,6 +408,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);
 
        switch (sym->st_shndx) {
        case SHN_COMMON:
@@ -362,7 +418,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
                /* 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);
+                       sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
+                                       export);
                }
                break;
        case SHN_UNDEF:
@@ -406,7 +463,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);
+                       sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
+                                       export);
                }
                if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
                        mod->has_init = 1;
@@ -437,13 +495,18 @@ static char *next_string(char *string, unsigned long *secsize)
        return string;
 }
 
-static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
-                        const char *tag)
+static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
+                             const char *tag, char *info)
 {
        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;
@@ -451,6 +514,13 @@ static char *get_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
@@ -487,22 +557,24 @@ static int strrcmp(const char *s, const char *sub)
  *   atsym   =__param*
  *
  * Pattern 2:
- *   Many drivers utilise a *_driver container with references to
+ *   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",
+               "driver",
+               "_template", /* scsi uses *_template a lot */
+               "_sht",      /* scsi also used *_sht to some extent */
                "_ops",
                "_probe",
                "_probe_one",
@@ -522,7 +594,8 @@ static int secref_whitelist(const char *tosec, const char *fromsec,
 
        /* Check for pattern 2 */
        if ((strcmp(tosec, ".init.text") != 0) &&
-           (strcmp(tosec, ".exit.text") != 0))
+           (strcmp(tosec, ".exit.text") != 0) &&
+           (strcmp(tosec, ".init.data") != 0))
                f2 = 0;
        if (strcmp(fromsec, ".data") != 0)
                f2 = 0;
@@ -658,7 +731,7 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
                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,
+                    elf->strtab + after->st_name,
                     (long long)r.r_offset);
        } else {
                warn("%s - Section mismatch: reference to %s:%s from %s "
@@ -694,29 +767,79 @@ static void check_sec_ref(struct module *mod, const char *modname,
 
        /* Walk through all sections */
        for (i = 0; i < hdr->e_shnum; i++) {
-               Elf_Rela *rela;
-               Elf_Rela *start = (void *)hdr + sechdrs[i].sh_offset;
-               Elf_Rela *stop  = (void*)start + sechdrs[i].sh_size;
-               const char *name = secstrings + sechdrs[i].sh_name +
-                                               strlen(".rela");
+               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 (section_ref_ok(name) || (sechdrs[i].sh_type != SHT_RELA))
-                       continue;
+               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++) {
-                       Elf_Rela r;
-                       const char *secname;
-                       r.r_offset = TO_NATIVE(rela->r_offset);
-                       r.r_info   = TO_NATIVE(rela->r_info);
-                       r.r_addend = TO_NATIVE(rela->r_addend);
-                       sym = elf->symtab_start + ELF_R_SYM(r.r_info);
-                       /* Skip special sections */
-                       if (sym->st_shndx >= SHN_LORESERVE)
+                       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;
 
-                       secname = secstrings + sechdrs[sym->st_shndx].sh_name;
-                       if (section(secname))
-                               warn_sec_mismatch(modname, name, elf, sym, r);
+                       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);
+                       }
                }
        }
 }
@@ -768,6 +891,10 @@ static int init_section_ref_ok(const char *name)
                ".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 */
@@ -793,6 +920,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;
 }
 
@@ -820,6 +949,7 @@ static int exit_section(const char *name)
  * 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)
 {
@@ -829,6 +959,7 @@ 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",
@@ -837,6 +968,10 @@ static int exit_section_ref_ok(const char *name)
                ".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 */
@@ -866,6 +1001,7 @@ static void read_symbols(char *modname)
 {
        const char *symname;
        char *version;
+       char *license;
        struct module *mod;
        struct elf_info info = { };
        Elf_Sym *sym;
@@ -881,6 +1017,18 @@ static void read_symbols(char *modname)
                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;
 
@@ -937,6 +1085,41 @@ void buf_write(struct buffer *buf, const char *s, int len)
        buf->pos += len;
 }
 
+void check_license(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;
+               }
+        }
+}
+
 /**
  * Header for the generated file
  **/
@@ -1087,6 +1270,9 @@ 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]
+ **/
 static void read_dump(const char *fname, unsigned int kernel)
 {
        unsigned long size, pos = 0;
@@ -1098,7 +1284,7 @@ static void read_dump(const char *fname, unsigned int kernel)
                return;
 
        while ((line = get_next_line(&pos, file, size))) {
-               char *symname, *modname, *d;
+               char *symname, *modname, *d, *export;
                unsigned int crc;
                struct module *mod;
                struct symbol *s;
@@ -1109,8 +1295,9 @@ static void read_dump(const char *fname, unsigned int kernel)
                if (!(modname = strchr(symname, '\t')))
                        goto fail;
                *modname++ = '\0';
-               if (strchr(modname, '\t'))
-                       goto fail;
+               if ((export = strchr(modname, '\t')) != NULL)
+                       *export++ = '\0';
+
                crc = strtoul(line, &d, 16);
                if (*symname == '\0' || *modname == '\0' || *d != '\0')
                        goto fail;
@@ -1122,10 +1309,10 @@ 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);
+               s = sym_add_exported(symname, mod, export_no(export));
                s->kernel    = kernel;
                s->preloaded = 1;
-               sym_update_crc(symname, mod, crc);
+               sym_update_crc(symname, mod, crc, export_no(export));
        }
        return;
 fail:
@@ -1155,9 +1342,10 @@ static void write_dump(const char *fname)
                symbol = symbolhash[n];
                while (symbol) {
                        if (dump_sym(symbol))
-                               buf_printf(&buf, "0x%08x\t%s\t%s\n",
+                               buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
                                        symbol->crc, symbol->name,
-                                       symbol->module->name);
+                                       symbol->module->name,
+                                       export_str(symbol->export));
                        symbol = symbol->next;
                }
        }
@@ -1205,6 +1393,12 @@ int main(int argc, char **argv)
                read_symbols(argv[optind++]);
        }
 
+       for (mod = modules; mod; mod = mod->next) {
+               if (mod->skip)
+                       continue;
+               check_license(mod);
+       }
+
        for (mod = modules; mod; mod = mod->next) {
                if (mod->skip)
                        continue;