diff options
author | Sam Ravnborg <sam@mars.ravnborg.org> | 2006-01-28 22:15:55 +0100 |
---|---|---|
committer | Sam Ravnborg <sam@mars.ravnborg.org> | 2006-02-19 09:51:18 +0100 |
commit | 040fcc819a2e7783a570f4bdcdd1f2a7f5f06837 (patch) | |
tree | 58a6cb2e7394c589c8ef49b308512c83af0c7087 /scripts/mod | |
parent | 5c3ead8c72788d36d34c9f1689fb529d1339b405 (diff) | |
download | linux-3.10-040fcc819a2e7783a570f4bdcdd1f2a7f5f06837.tar.gz linux-3.10-040fcc819a2e7783a570f4bdcdd1f2a7f5f06837.tar.bz2 linux-3.10-040fcc819a2e7783a570f4bdcdd1f2a7f5f06837.zip |
kbuild: improved modversioning support for external modules
With following patch a second option is enabled to obtain
symbol information from a second external module when a
external module is build.
The recommended approach is to use a common kbuild file but
that may be impractical in certain cases.
With this patch one can copy over a Module.symvers from one
external module to make symbols (and symbol versions) available
for another external module.
Updated documentation in Documentation/kbuild/modules.txt
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Diffstat (limited to 'scripts/mod')
-rw-r--r-- | scripts/mod/modpost.c | 123 |
1 files changed, 73 insertions, 50 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 4a2f2e38d27..976adf152db 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -20,6 +20,8 @@ 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; void fatal(const char *fmt, ...) { @@ -45,6 +47,18 @@ 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) { @@ -100,6 +114,9 @@ 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) **/ char name[0]; }; @@ -135,8 +152,7 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak, } /* For the hash of exported symbols */ -static void new_symbol(const char *name, struct module *module, - unsigned int *crc) +static struct symbol *new_symbol(const char *name, struct module *module) { unsigned int hash; struct symbol *new; @@ -144,10 +160,7 @@ static void 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; - if (crc) { - new->crc = *crc; - new->crc_valid = 1; - } + return new; } static struct symbol *find_symbol(const char *name) @@ -169,19 +182,27 @@ static struct symbol *find_symbol(const char *name) * Add an exported symbol - it may have already been added without a * CRC, in this case just update the CRC **/ -static void add_exported_symbol(const char *name, struct module *module, - unsigned int *crc) +static struct symbol *sym_add_exported(const char *name, struct module *mod) { struct symbol *s = find_symbol(name); - if (!s) { - new_symbol(name, module, crc); - return; - } - if (crc) { - s->crc = *crc; - s->crc_valid = 1; - } + if (!s) + s = new_symbol(name, mod); + + s->vmlinux = is_vmlinux(mod->name); + s->kernel = 0; + return s; +} + +static void sym_update_crc(const char *name, struct module *mod, + unsigned int crc) +{ + struct symbol *s = find_symbol(name); + + if (!s) + s = new_symbol(name, mod); + s->crc = crc; + s->crc_valid = 1; } void *grab_file(const char *filename, unsigned long *size) @@ -332,8 +353,7 @@ 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; - add_exported_symbol(symname + strlen(CRC_PFX), - mod, &crc); + sym_update_crc(symname + strlen(CRC_PFX), mod, crc); } break; case SHN_UNDEF: @@ -377,8 +397,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, default: /* All exported symbols */ if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { - add_exported_symbol(symname + strlen(KSYMTAB_PFX), - mod, NULL); + sym_add_exported(symname + strlen(KSYMTAB_PFX), mod); } if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) mod->has_init = 1; @@ -388,18 +407,6 @@ static void handle_modversions(struct module *mod, struct elf_info *info, } } -static 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 **/ @@ -450,9 +457,7 @@ 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; } @@ -665,7 +670,7 @@ static void write_if_changed(struct buffer *b, const char *fname) fclose(file); } -static void read_dump(const char *fname) +static void read_dump(const char *fname, unsigned int kernel) { unsigned long size, pos = 0; void *file = grab_file(fname, &size); @@ -679,6 +684,7 @@ static void read_dump(const char *fname) char *symname, *modname, *d; unsigned int crc; struct module *mod; + struct symbol *s; if (!(symname = strchr(line, '\t'))) goto fail; @@ -699,13 +705,28 @@ static void read_dump(const char *fname) mod = new_module(NOFAIL(strdup(modname))); mod->skip = 1; } - add_exported_symbol(symname, mod, &crc); + s = sym_add_exported(symname, mod); + s->kernel = kernel; + sym_update_crc(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) { struct buffer buf = { }; @@ -715,15 +736,10 @@ static void write_dump(const char *fname) for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { symbol = symbolhash[n]; while (symbol) { - 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); + if (dump_sym(symbol)) + buf_printf(&buf, "0x%08x\t%s\t%s\n", + symbol->crc, symbol->name, + symbol->module->name); symbol = symbol->next; } } @@ -735,13 +751,18 @@ int main(int argc, char **argv) struct module *mod; struct buffer buf = { }; char fname[SZ]; - char *dump_read = NULL, *dump_write = NULL; + char *kernel_read = NULL, *module_read = NULL; + char *dump_write = NULL; int opt; - while ((opt = getopt(argc, argv, "i:mo:a")) != -1) { + while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) { switch(opt) { case 'i': - dump_read = optarg; + kernel_read = optarg; + break; + case 'I': + module_read = optarg; + external_module = 1; break; case 'm': modversions = 1; @@ -757,8 +778,10 @@ int main(int argc, char **argv) } } - if (dump_read) - read_dump(dump_read); + if (kernel_read) + read_dump(kernel_read, 1); + if (module_read) + read_dump(module_read, 0); while (optind < argc) { read_symbols(argv[optind++]); |