diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-04-12 02:21:00 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-04-12 02:21:00 -0700 |
| commit | 0d61fc5ea78015def4d2fcf9b598ecfe25210cdd (patch) | |
| tree | a45aa0f67c6bbd200dc2a328e560042810307b1b /scripts/modpost.c | |
| parent | f2eb250f07ba4695c2474cb8b6edbf64b5457d65 (diff) | |
| parent | eb880e5457f8b4a61ff7fd36d47dd14fe51cb030 (diff) | |
Merge bk://bk.arm.linux.org.uk/linux-2.6-rmk
into ppc970.osdl.org:/home/torvalds/v2.6/linux
Diffstat (limited to 'scripts/modpost.c')
| -rw-r--r-- | scripts/modpost.c | 176 |
1 files changed, 147 insertions, 29 deletions
diff --git a/scripts/modpost.c b/scripts/modpost.c index a0976fcb9982..523e302cf89e 100644 --- a/scripts/modpost.c +++ b/scripts/modpost.c @@ -16,7 +16,7 @@ /* Are we using CONFIG_MODVERSIONS? */ int modversions = 0; -/* Do we have vmlinux? */ +/* Warn about undefined symbols? (do so if we have vmlinux) */ int have_vmlinux = 0; void @@ -59,6 +59,17 @@ void *do_nofail(void *ptr, const char *file, int line, const char *expr) static struct module *modules; struct module * +find_module(char *modname) +{ + struct module *mod; + + for (mod = modules; mod; mod = mod->next) + if (strcmp(mod->name, modname) == 0) + break; + return mod; +} + +struct module * new_module(char *modname) { struct module *mod; @@ -113,12 +124,13 @@ static inline unsigned int tdb_hash(const char *name) * the list of unresolved symbols per module */ struct symbol * -alloc_symbol(const char *name) +alloc_symbol(const char *name, struct symbol *next) { struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); memset(s, 0, sizeof(*s)); strcpy(s->name, name); + s->next = next; return s; } @@ -128,17 +140,15 @@ void new_symbol(const char *name, struct module *module, unsigned int *crc) { unsigned int hash; - struct symbol *new = alloc_symbol(name); + struct symbol *new; + hash = tdb_hash(name) % SYMBOL_HASH_SIZE; + new = symbolhash[hash] = alloc_symbol(name, symbolhash[hash]); new->module = module; if (crc) { new->crc = *crc; new->crc_valid = 1; } - - hash = tdb_hash(name) % SYMBOL_HASH_SIZE; - new->next = symbolhash[hash]; - symbolhash[hash] = new; } struct symbol * @@ -165,7 +175,7 @@ add_exported_symbol(const char *name, struct module *module, unsigned int *crc) struct symbol *s = find_symbol(name); if (!s) { - new_symbol(name, modules, crc); + new_symbol(name, module, crc); return; } if (crc) { @@ -182,7 +192,7 @@ grab_file(const char *filename, unsigned long *size) int fd; fd = open(filename, O_RDONLY); - if (fstat(fd, &st) != 0) + if (fd < 0 || fstat(fd, &st) != 0) return NULL; *size = st.st_size; @@ -319,7 +329,6 @@ void handle_modversions(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname) { - struct symbol *s; unsigned int crc; switch (sym->st_shndx) { @@ -343,6 +352,9 @@ handle_modversions(struct module *mod, struct elf_info *info, /* ignore global offset table */ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) break; + /* ignore __this_module, it will be resolved shortly */ + if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) + break; #ifdef STT_REGISTER if (info->hdr->e_machine == EM_SPARC || info->hdr->e_machine == EM_SPARCV9) { @@ -353,13 +365,10 @@ handle_modversions(struct module *mod, struct elf_info *info, #endif if (memcmp(symname, MODULE_SYMBOL_PREFIX, - strlen(MODULE_SYMBOL_PREFIX)) == 0) { - s = alloc_symbol(symname + - strlen(MODULE_SYMBOL_PREFIX)); - /* add to list */ - s->next = mod->unres; - mod->unres = s; - } + strlen(MODULE_SYMBOL_PREFIX)) == 0) + mod->unres = alloc_symbol(symname + + strlen(MODULE_SYMBOL_PREFIX), + mod->unres); break; default: /* All exported symbols */ @@ -390,17 +399,24 @@ read_symbols(char *modname) const char *symname; struct module *mod; struct elf_info info = { }; - struct symbol *s; Elf_Sym *sym; - /* When there's no vmlinux, don't print warnings about - * unresolved symbols (since there'll be too many ;) */ - have_vmlinux = is_vmlinux(modname); - parse_elf(&info, modname); mod = new_module(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; + /* May not have this if !CONFIG_MODULE_UNLOAD: fake it. + If it appears, we'll get the real CRC. */ + add_exported_symbol("cleanup_module", mod, &fake_crc); + add_exported_symbol("struct_module", mod, &fake_crc); + mod->skip = 1; + } + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { symname = info.strtab + sym->st_name; @@ -416,10 +432,12 @@ read_symbols(char *modname) * the automatic versioning doesn't pick it up, but it's really * important anyhow */ if (modversions) { - s = alloc_symbol("struct_module"); - /* add to list */ - s->next = mod->unres; - mod->unres = s; + mod->unres = alloc_symbol("struct_module", mod->unres); + + /* Always version init_module and cleanup_module, in + * case module doesn't have its own. */ + mod->unres = alloc_symbol("init_module", mod->unres); + mod->unres = alloc_symbol("cleanup_module", mod->unres); } } @@ -468,6 +486,15 @@ add_header(struct buffer *b) buf_printf(b, "#include <linux/compiler.h>\n"); buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); + buf_printf(b, "\n"); + buf_printf(b, "struct module __this_module\n"); + buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); + buf_printf(b, " .name = __stringify(KBUILD_MODNAME),\n"); + buf_printf(b, " .init = init_module,\n"); + buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"); + buf_printf(b, " .exit = cleanup_module,\n"); + buf_printf(b, "#endif\n"); + buf_printf(b, "};\n"); } /* Record CRCs for unresolved symbols */ @@ -590,19 +617,106 @@ write_if_changed(struct buffer *b, const char *fname) fclose(file); } +void +read_dump(const char *fname) +{ + unsigned long size, pos = 0; + void *file = grab_file(fname, &size); + char *line; + + if (!file) { + perror(fname); + abort(); + } + + while ((line = get_next_line(&pos, file, size))) { + char *symname, *modname, *d; + unsigned int crc; + struct module *mod; + + if (!(symname = strchr(line, '\t'))) + goto fail; + *symname++ = '\0'; + if (!(modname = strchr(symname, '\t'))) + goto fail; + *modname++ = '\0'; + if (strchr(modname, '\t')) + goto fail; + crc = strtoul(line, &d, 16); + if (*symname == '\0' || *modname == '\0' || *d != '\0') + goto fail; + + if (!(mod = find_module(modname))) { + if (is_vmlinux(modname)) { + modversions = 1; + have_vmlinux = 1; + } + mod = new_module(NOFAIL(strdup(modname))); + mod->skip = 1; + } + add_exported_symbol(symname, mod, &crc); + } + return; +fail: + fatal("parse error in symbol dump file\n"); +} + +void +write_dump(const char *fname) +{ + struct buffer buf = { }; + struct symbol *symbol; + int n; + + 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); + symbol = symbol->next; + } + } + write_if_changed(&buf, fname); +} + int main(int argc, char **argv) { struct module *mod; struct buffer buf = { }; char fname[SZ]; + char *dump_read = NULL, *dump_write = NULL; + int opt; + + while ((opt = getopt(argc, argv, "i:o:")) != -1) { + switch(opt) { + case 'i': + dump_read = optarg; + break; + case 'o': + dump_write = optarg; + break; + default: + exit(1); + } + } - for (; argv[1]; argv++) { - read_symbols(argv[1]); + if (dump_read) + read_dump(dump_read); + + while (optind < argc) { + read_symbols(argv[optind++]); } for (mod = modules; mod; mod = mod->next) { - if (is_vmlinux(mod->name)) + if (mod->skip) continue; buf.pos = 0; @@ -615,6 +729,10 @@ main(int argc, char **argv) sprintf(fname, "%s.mod.c", mod->name); write_if_changed(&buf, fname); } + + if (dump_write) + write_dump(dump_write); + return 0; } |
