⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modpost.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	const char *namelist3 [] = {		".unwind",  /* Sample: IA_64.unwind.exit.text */		NULL	};	for (s = namelist1; *s; s++)		if (strcmp(*s, name) == 0)			return 1;	for (s = namelist2; *s; s++)		if (strncmp(*s, name, strlen(*s)) == 0)			return 1;	for (s = namelist3; *s; s++)		if (strstr(name, *s) != NULL)			return 1;	return 0;}/* * Identify sections from which references to a .init section is OK. * * Unfortunately references to read only data that referenced .init * sections had to be excluded. Almost all of these are false * positives, they are created by gcc. The downside of excluding rodata * is that there really are some user references from rodata to * init code, e.g. drivers/video/vgacon.c: * * const struct consw vga_con = { *        con_startup:            vgacon_startup, * * where vgacon_startup is __init.  If you want to wade through the false * positives, take out the check for rodata. */static int init_section_ref_ok(const char *name){	const char **s;	/* Absolute section names */	const char *namelist1[] = {		"__dbe_table",		/* MIPS generate these */		"__ftr_fixup",		/* powerpc cpu feature fixup */		"__fw_ftr_fixup",	/* powerpc firmware feature fixup */		"__param",		".data.rel.ro",		/* used by parisc64 */		".init",		".text.lock",		NULL	};	/* Start of section names */	const char *namelist2[] = {		".init.",		".pci_fixup",		".rodata",		NULL	};	if (initexit_section_ref_ok(name))		return 1;	for (s = namelist1; *s; s++)		if (strcmp(*s, name) == 0)			return 1;	for (s = namelist2; *s; s++)		if (strncmp(*s, name, strlen(*s)) == 0)			return 1;	/* If section name ends with ".init" we allow references	 * as is the case with .initcallN.init, .early_param.init, .taglist.init etc	 */	if (strrcmp(name, ".init") == 0)		return 1;	return 0;}/* * Identify sections from which references to a .exit section is OK. */static int exit_section_ref_ok(const char *name){	const char **s;	/* Absolute section names */	const char *namelist1[] = {		".exit.data",		".exit.text",		".exitcall.exit",		".rodata",		NULL	};	if (initexit_section_ref_ok(name))		return 1;	for (s = namelist1; *s; s++)		if (strcmp(*s, name) == 0)			return 1;	return 0;}static void read_symbols(char *modname){	const char *symname;	char *version;	char *license;	struct module *mod;	struct elf_info info = { };	Elf_Sym *sym;	if (!parse_elf(&info, modname))		return;	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)) {		have_vmlinux = 1;		mod->skip = 1;	}	license = get_modinfo(info.modinfo, info.modinfo_len, "license");	while (license) {		if (license_is_gpl_compatible(license))			mod->gpl_compatible = 1;		else {			mod->gpl_compatible = 0;			break;		}		license = get_next_modinfo(info.modinfo, info.modinfo_len,					   "license", license);	}	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);	}	if (is_vmlinux(modname) && vmlinux_section_warnings) {		check_sec_ref(mod, modname, &info, init_section, init_section_ref_ok);		check_sec_ref(mod, modname, &info, exit_section, exit_section_ref_ok);	}	version = get_modinfo(info.modinfo, info.modinfo_len, "version");	if (version)		maybe_frob_rcs_version(modname, version, info.modinfo,				       version - (char *)info.hdr);	if (version || (all_versions && !is_vmlinux(modname)))		get_src_version(modname, mod->srcversion,				sizeof(mod->srcversion)-1);	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", 0, 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);	buf_write(buf, tmp, len);	va_end(ap);}void buf_write(struct buffer *buf, const char *s, int len){	if (buf->size - buf->pos < len) {		buf->size += len + SZ;		buf->p = realloc(buf->p, buf->size);	}	strncpy(buf->p + buf->pos, s, len);	buf->pos += len;}static void check_for_gpl_usage(enum export exp, const char *m, const char *s){	const char *e = is_vmlinux(m) ?"":".ko";	switch (exp) {	case export_gpl:		fatal("modpost: GPL-incompatible module %s%s "		      "uses GPL-only symbol '%s'\n", m, e, s);		break;	case export_unused_gpl:		fatal("modpost: GPL-incompatible module %s%s "		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);		break;	case export_gpl_future:		warn("modpost: GPL-incompatible module %s%s "		      "uses future GPL-only symbol '%s'\n", m, e, s);		break;	case export_plain:	case export_unused:	case export_unknown:		/* ignore */		break;	}}static void check_for_unused(enum export exp, const char* m, const char* s){	const char *e = is_vmlinux(m) ?"":".ko";	switch (exp) {	case export_unused:	case export_unused_gpl:		warn("modpost: module %s%s "		      "uses symbol '%s' marked UNUSED\n", m, e, s);		break;	default:		/* ignore */		break;	}}static void check_exports(struct module *mod){	struct symbol *s, *exp;	for (s = mod->unres; s; s = s->next) {		const char *basename;		exp = find_symbol(s->name);		if (!exp || exp->module == mod)			continue;		basename = strrchr(mod->name, '/');		if (basename)			basename++;		else			basename = mod->name;		if (!mod->gpl_compatible)			check_for_gpl_usage(exp->export, basename, exp->name);		check_for_unused(exp->export, basename, exp->name);        }}/** * Header for the generated file **/static void add_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, "struct module __this_module\n");	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");	buf_printf(b, " .name = 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, " .arch = MODULE_ARCH_INIT,\n");	buf_printf(b, "};\n");}/** * Record CRCs for unresolved symbols **/static int add_versions(struct buffer *b, struct module *mod){	struct symbol *s, *exp;	int err = 0;	for (s = mod->unres; s; s = s->next) {		exp = find_symbol(s->name);		if (!exp || exp->module == mod) {			if (have_vmlinux && !s->weak) {				if (warn_unresolved) {					warn("\"%s\" [%s.ko] undefined!\n",					     s->name, mod->name);				} else {					merror("\"%s\" [%s.ko] undefined!\n",					          s->name, mod->name);					err = 1;				}			}			continue;		}		s->module = exp->module;		s->crc_valid = exp->crc_valid;		s->crc = exp->crc;	}	if (!modversions)		return err;	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) {			warn("\"%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");	return err;}static void add_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) {		const char *p;		if (!s->module)			continue;		if (s->module->seen)			continue;		s->module->seen = 1;		if ((p = strrchr(s->module->name, '/')) != NULL)			p++;		else			p = s->module->name;		buf_printf(b, "%s%s", first ? "" : ",", p);		first = 0;	}	buf_printf(b, "\";\n");}static void add_srcversion(struct buffer *b, struct module *mod){	if (mod->srcversion[0]) {		buf_printf(b, "\n");		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",			   mod->srcversion);	}}static void write_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);}/* parse Module.symvers file. line format: * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] **/static void read_dump(const char *fname, unsigned int kernel){	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, *export, *end;		unsigned int crc;		struct module *mod;		struct symbol *s;		if (!(symname = strchr(line, '\t')))			goto fail;		*symname++ = '\0';		if (!(modname = strchr(symname, '\t')))			goto fail;		*modname++ = '\0';		if ((export = strchr(modname, '\t')) != NULL)			*export++ = '\0';		if (export && ((end = strchr(export, '\t')) != NULL))			*end = '\0';		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;		}		s = sym_add_exported(symname, mod, export_no(export));		s->kernel    = kernel;		s->preloaded = 1;		sym_update_crc(symname, mod, crc, export_no(export));	}	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 = { };	struct symbol *symbol;	int n;	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {		symbol = symbolhash[n];		while (symbol) {			if (dump_sym(symbol))				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",					symbol->crc, symbol->name,					symbol->module->name,					export_str(symbol->export));			symbol = symbol->next;		}	}	write_if_changed(&buf, fname);}int main(int argc, char **argv){	struct module *mod;	struct buffer buf = { };	char fname[SZ];	char *kernel_read = NULL, *module_read = NULL;	char *dump_write = NULL;	int opt;	int err;	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {		switch(opt) {			case 'i':				kernel_read = optarg;				break;			case 'I':				module_read = optarg;				external_module = 1;				break;			case 'm':				modversions = 1;				break;			case 'o':				dump_write = optarg;				break;			case 'a':				all_versions = 1;				break;			case 's':				vmlinux_section_warnings = 0;				break;			case 'w':				warn_unresolved = 1;				break;			default:				exit(1);		}	}	if (kernel_read)		read_dump(kernel_read, 1);	if (module_read)		read_dump(module_read, 0);	while (optind < argc) {		read_symbols(argv[optind++]);	}	for (mod = modules; mod; mod = mod->next) {		if (mod->skip)			continue;		check_exports(mod);	}	err = 0;	for (mod = modules; mod; mod = mod->next) {		if (mod->skip)			continue;		buf.pos = 0;		add_header(&buf, mod);		err |= add_versions(&buf, mod);		add_depends(&buf, mod, modules);		add_moddevtable(&buf, mod);		add_srcversion(&buf, mod);		sprintf(fname, "%s.mod.c", mod->name);		write_if_changed(&buf, fname);	}	if (dump_write)		write_dump(dump_write);	return err;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -