Commit bd5cbced authored by Ram Pai's avatar Ram Pai Committed by Sam Ravnborg

kbuild: export-type enhancement to modpost.c

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: default avatarAndreas Gruenbacher <agruen@suse.de>
Signed-off-by: default avatarRam Pai <linuxram@us.ibm.com>
Signed-off-by: default avatarAvantika Mathur <mathur@us.ibm.com>
Signed-off-by: default avatarValdis Kletnieks <valdis.kletnieks@vt.edu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarSam Ravnborg <sam@ravnborg.org>
parent 031ecc6d
...@@ -22,6 +22,8 @@ int have_vmlinux = 0; ...@@ -22,6 +22,8 @@ int have_vmlinux = 0;
static int all_versions = 0; static int all_versions = 0;
/* If we are modposting external module set to 1 */ /* If we are modposting external module set to 1 */
static int external_module = 0; 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, ...) void fatal(const char *fmt, ...)
{ {
...@@ -118,6 +120,7 @@ struct symbol { ...@@ -118,6 +120,7 @@ struct symbol {
unsigned int kernel:1; /* 1 if symbol is from kernel unsigned int kernel:1; /* 1 if symbol is from kernel
* (only for external modules) **/ * (only for external modules) **/
unsigned int preloaded:1; /* 1 if symbol from Module.symvers */ unsigned int preloaded:1; /* 1 if symbol from Module.symvers */
enum export export; /* Type of export */
char name[0]; char name[0];
}; };
...@@ -153,7 +156,8 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak, ...@@ -153,7 +156,8 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak,
} }
/* For the hash of exported symbols */ /* 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; unsigned int hash;
struct symbol *new; struct symbol *new;
...@@ -161,6 +165,7 @@ static struct symbol *new_symbol(const char *name, struct module *module) ...@@ -161,6 +165,7 @@ static struct symbol *new_symbol(const char *name, struct module *module)
hash = tdb_hash(name) % SYMBOL_HASH_SIZE; hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
new->module = module; new->module = module;
new->export = export;
return new; return new;
} }
...@@ -179,16 +184,55 @@ static struct symbol *find_symbol(const char *name) ...@@ -179,16 +184,55 @@ static struct symbol *find_symbol(const char *name)
return NULL; 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 * Add an exported symbol - it may have already been added without a
* CRC, in this case just update the CRC * 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); struct symbol *s = find_symbol(name);
if (!s) { if (!s) {
s = new_symbol(name, mod); s = new_symbol(name, mod, export);
} else { } else {
if (!s->preloaded) { if (!s->preloaded) {
warn("%s: '%s' exported twice. Previous export " warn("%s: '%s' exported twice. Previous export "
...@@ -200,16 +244,17 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod) ...@@ -200,16 +244,17 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod)
s->preloaded = 0; s->preloaded = 0;
s->vmlinux = is_vmlinux(mod->name); s->vmlinux = is_vmlinux(mod->name);
s->kernel = 0; s->kernel = 0;
s->export = export;
return s; return s;
} }
static void sym_update_crc(const char *name, struct module *mod, 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); struct symbol *s = find_symbol(name);
if (!s) if (!s)
s = new_symbol(name, mod); s = new_symbol(name, mod, export);
s->crc = crc; s->crc = crc;
s->crc_valid = 1; s->crc_valid = 1;
} }
...@@ -309,13 +354,21 @@ static void parse_elf(struct elf_info *info, const char *filename) ...@@ -309,13 +354,21 @@ static void parse_elf(struct elf_info *info, const char *filename)
for (i = 1; i < hdr->e_shnum; i++) { for (i = 1; i < hdr->e_shnum; i++) {
const char *secstrings const char *secstrings
= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
const char *secname;
if (sechdrs[i].sh_offset > info->size) if (sechdrs[i].sh_offset > info->size)
goto truncated; 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 = (void *)hdr + sechdrs[i].sh_offset;
info->modinfo_len = sechdrs[i].sh_size; 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) if (sechdrs[i].sh_type != SHT_SYMTAB)
continue; continue;
...@@ -353,6 +406,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, ...@@ -353,6 +406,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname) Elf_Sym *sym, const char *symname)
{ {
unsigned int crc; unsigned int crc;
enum export export = export_from_sec(info, sym->st_shndx);
switch (sym->st_shndx) { switch (sym->st_shndx) {
case SHN_COMMON: case SHN_COMMON:
...@@ -362,7 +416,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, ...@@ -362,7 +416,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
/* CRC'd symbol */ /* CRC'd symbol */
if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
crc = (unsigned int) sym->st_value; 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; break;
case SHN_UNDEF: case SHN_UNDEF:
...@@ -406,7 +461,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, ...@@ -406,7 +461,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
default: default:
/* All exported symbols */ /* All exported symbols */
if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { 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) if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
mod->has_init = 1; mod->has_init = 1;
...@@ -1146,6 +1202,9 @@ static void write_if_changed(struct buffer *b, const char *fname) ...@@ -1146,6 +1202,9 @@ static void write_if_changed(struct buffer *b, const char *fname)
fclose(file); 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) static void read_dump(const char *fname, unsigned int kernel)
{ {
unsigned long size, pos = 0; unsigned long size, pos = 0;
...@@ -1157,7 +1216,7 @@ static void read_dump(const char *fname, unsigned int kernel) ...@@ -1157,7 +1216,7 @@ static void read_dump(const char *fname, unsigned int kernel)
return; return;
while ((line = get_next_line(&pos, file, size))) { while ((line = get_next_line(&pos, file, size))) {
char *symname, *modname, *d; char *symname, *modname, *d, *export;
unsigned int crc; unsigned int crc;
struct module *mod; struct module *mod;
struct symbol *s; struct symbol *s;
...@@ -1168,8 +1227,9 @@ static void read_dump(const char *fname, unsigned int kernel) ...@@ -1168,8 +1227,9 @@ static void read_dump(const char *fname, unsigned int kernel)
if (!(modname = strchr(symname, '\t'))) if (!(modname = strchr(symname, '\t')))
goto fail; goto fail;
*modname++ = '\0'; *modname++ = '\0';
if (strchr(modname, '\t')) if (!(export = strchr(modname, '\t')))
goto fail; *export++ = '\0';
crc = strtoul(line, &d, 16); crc = strtoul(line, &d, 16);
if (*symname == '\0' || *modname == '\0' || *d != '\0') if (*symname == '\0' || *modname == '\0' || *d != '\0')
goto fail; goto fail;
...@@ -1181,10 +1241,10 @@ static void read_dump(const char *fname, unsigned int kernel) ...@@ -1181,10 +1241,10 @@ static void read_dump(const char *fname, unsigned int kernel)
mod = new_module(NOFAIL(strdup(modname))); mod = new_module(NOFAIL(strdup(modname)));
mod->skip = 1; mod->skip = 1;
} }
s = sym_add_exported(symname, mod); s = sym_add_exported(symname, mod, export_no(export));
s->kernel = kernel; s->kernel = kernel;
s->preloaded = 1; s->preloaded = 1;
sym_update_crc(symname, mod, crc); sym_update_crc(symname, mod, crc, export_no(export));
} }
return; return;
fail: fail:
...@@ -1214,9 +1274,10 @@ static void write_dump(const char *fname) ...@@ -1214,9 +1274,10 @@ static void write_dump(const char *fname)
symbol = symbolhash[n]; symbol = symbolhash[n];
while (symbol) { while (symbol) {
if (dump_sym(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->crc, symbol->name,
symbol->module->name); symbol->module->name,
export_str(symbol->export));
symbol = symbol->next; symbol = symbol->next;
} }
} }
......
...@@ -115,6 +115,9 @@ struct elf_info { ...@@ -115,6 +115,9 @@ struct elf_info {
Elf_Shdr *sechdrs; Elf_Shdr *sechdrs;
Elf_Sym *symtab_start; Elf_Sym *symtab_start;
Elf_Sym *symtab_stop; Elf_Sym *symtab_stop;
Elf_Section export_sec;
Elf_Section export_gpl_sec;
Elf_Section export_gpl_future_sec;
const char *strtab; const char *strtab;
char *modinfo; char *modinfo;
unsigned int modinfo_len; unsigned int modinfo_len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment