📄 modpost.c
字号:
strlen(MODULE_SYMBOL_PREFIX), mod->unres); break; default: /* All exported symbols */ if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { add_exported_symbol(symname + strlen(KSYMTAB_PFX), mod, NULL); } if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) mod->has_init = 1; if (strcmp(symname, MODULE_SYMBOL_PREFIX "cleanup_module") == 0) mod->has_cleanup = 1; break; }}intis_vmlinux(const char *modname){ const char *myname; if ((myname = strrchr(modname, '/'))) myname++; else myname = modname; return strcmp(myname, "vmlinux") == 0;}voidread_symbols(char *modname){ const char *symname; struct module *mod; struct elf_info info = { }; Elf_Sym *sym; 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; 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; handle_modversions(mod, &info, sym, symname); handle_moddevtable(mod, &info, sym, symname); } maybe_frob_version(modname, info.modinfo, info.modinfo_len, (void *)info.modinfo - (void *)info.hdr); parse_elf_finish(&info); /* Our trick to get versioning for struct_module - it's * never passed as an argument to an exported function, so * the automatic versioning doesn't pick it up, but it's really * important anyhow */ if (modversions) mod->unres = alloc_symbol("struct_module", mod->unres);}#define SZ 500/* We first write the generated file into memory using the * following helper, then compare to the file on disk and * only update the later if anything changed */void __attribute__((format(printf, 2, 3)))buf_printf(struct buffer *buf, const char *fmt, ...){ char tmp[SZ]; int len; va_list ap; va_start(ap, fmt); len = vsnprintf(tmp, SZ, fmt, ap); if (buf->size - buf->pos < len + 1) { buf->size += 128; buf->p = realloc(buf->p, buf->size); } strncpy(buf->p + buf->pos, tmp, len + 1); buf->pos += len; va_end(ap);}voidbuf_write(struct buffer *buf, const char *s, int len){ if (buf->size - buf->pos < len) { buf->size += len; buf->p = realloc(buf->p, buf->size); } strncpy(buf->p + buf->pos, s, len); buf->pos += len;}/* Header for the generated file */voidadd_header(struct buffer *b, struct module *mod){ buf_printf(b, "#include <linux/module.h>\n"); buf_printf(b, "#include <linux/vermagic.h>\n"); 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, "#undef unix\n"); /* We have a module called "unix" */ 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"); if (mod->has_init) buf_printf(b, " .init = init_module,\n"); if (mod->has_cleanup) buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" " .exit = cleanup_module,\n" "#endif\n"); buf_printf(b, "};\n");}/* Record CRCs for unresolved symbols */voidadd_versions(struct buffer *b, struct module *mod){ struct symbol *s, *exp; for (s = mod->unres; s; s = s->next) { exp = find_symbol(s->name); if (!exp || exp->module == mod) { if (have_vmlinux) fprintf(stderr, "*** Warning: \"%s\" [%s.ko] " "undefined!\n", s->name, mod->name); continue; } s->module = exp->module; s->crc_valid = exp->crc_valid; s->crc = exp->crc; } if (!modversions) return; buf_printf(b, "\n"); buf_printf(b, "static const struct modversion_info ____versions[]\n"); buf_printf(b, "__attribute_used__\n"); buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); for (s = mod->unres; s; s = s->next) { if (!s->module) { continue; } if (!s->crc_valid) { fprintf(stderr, "*** Warning: \"%s\" [%s.ko] " "has no CRC!\n", s->name, mod->name); continue; } buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name); } buf_printf(b, "};\n");}voidadd_depends(struct buffer *b, struct module *mod, struct module *modules){ struct symbol *s; struct module *m; int first = 1; for (m = modules; m; m = m->next) { m->seen = is_vmlinux(m->name); } buf_printf(b, "\n"); buf_printf(b, "static const char __module_depends[]\n"); buf_printf(b, "__attribute_used__\n"); buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); buf_printf(b, "\"depends="); for (s = mod->unres; s; s = s->next) { if (!s->module) continue; if (s->module->seen) continue; s->module->seen = 1; buf_printf(b, "%s%s", first ? "" : ",", strrchr(s->module->name, '/') + 1); first = 0; } buf_printf(b, "\";\n");}voidwrite_if_changed(struct buffer *b, const char *fname){ char *tmp; FILE *file; struct stat st; file = fopen(fname, "r"); if (!file) goto write; if (fstat(fileno(file), &st) < 0) goto close_write; if (st.st_size != b->pos) goto close_write; tmp = NOFAIL(malloc(b->pos)); if (fread(tmp, 1, b->pos, file) != b->pos) goto free_write; if (memcmp(tmp, b->p, b->pos) != 0) goto free_write; free(tmp); fclose(file); return; free_write: free(tmp); close_write: fclose(file); write: file = fopen(fname, "w"); if (!file) { perror(fname); exit(1); } if (fwrite(b->p, 1, b->pos, file) != b->pos) { perror(fname); exit(1); } fclose(file);}voidread_dump(const char *fname){ unsigned long size, pos = 0; void *file = grab_file(fname, &size); char *line; if (!file) /* No symbol versions, silently ignore */ return; 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)) { 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");}voidwrite_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);}intmain(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:mo:")) != -1) { switch(opt) { case 'i': dump_read = optarg; break; case 'm': modversions = 1; break; case 'o': dump_write = optarg; break; default: exit(1); } } if (dump_read) read_dump(dump_read); while (optind < argc) { read_symbols(argv[optind++]); } for (mod = modules; mod; mod = mod->next) { if (mod->skip) continue; buf.pos = 0; add_header(&buf, mod); add_versions(&buf, mod); add_depends(&buf, mod, modules); add_moddevtable(&buf, mod); sprintf(fname, "%s.mod.c", mod->name); write_if_changed(&buf, fname); } if (dump_write) write_dump(dump_write); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -