kbuild: export-type enhancement to modpost.c
Ram Pai [Fri, 9 Jun 2006 05:12:53 +0000 (22:12 -0700)]
This patch provides the ability to identify the export-type of each
exported symbols in Module.symvers.

NOTE: It updates the Module.symvers file with the additional
information as shown below.

0x0f8b92af      platform_device_add_resources   vmlinux EXPORT_SYMBOL_GPL
0xcf7efb2a      ethtool_op_set_tx_csum          vmlinux EXPORT_SYMBOL

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Avantika Mathur <mathur@us.ibm.com>
Signed-off-by: Valdis Kletnieks <valdis.kletnieks@vt.edu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

scripts/mod/modpost.c
scripts/mod/modpost.h

index a70f5dd..ba2e4fc 100644 (file)
@@ -22,6 +22,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, ...)
 {
@@ -118,6 +120,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 +156,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 +165,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 +184,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 +244,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;
 }
@@ -309,13 +354,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 +406,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 +416,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 +461,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;
@@ -1146,6 +1202,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;
@@ -1157,7 +1216,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;
@@ -1168,8 +1227,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')))
+                       *export++ = '\0';
+
                crc = strtoul(line, &d, 16);
                if (*symname == '\0' || *modname == '\0' || *d != '\0')
                        goto fail;
@@ -1181,10 +1241,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:
@@ -1214,9 +1274,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;
                }
        }
index 861d866..f7ee3a3 100644 (file)
@@ -115,6 +115,9 @@ struct elf_info {
        Elf_Shdr     *sechdrs;
        Elf_Sym      *symtab_start;
        Elf_Sym      *symtab_stop;
+       Elf_Section  export_sec;
+       Elf_Section  export_gpl_sec;
+       Elf_Section  export_gpl_future_sec;
        const char   *strtab;
        char         *modinfo;
        unsigned int modinfo_len;