forked from mirrors/linux
		
	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: Andreas Gruenbacher <agruen@suse.de> Signed-off-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Avantika Mathur <mathur@us.ibm.com> Signed-off-by: Valdis Kletnieks <valdis.kletnieks@vt.edu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
This commit is contained in:
		
							parent
							
								
									031ecc6de7
								
							
						
					
					
						commit
						bd5cbcedf4
					
				
					 2 changed files with 80 additions and 16 deletions
				
			
		|  | @ -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 { | ||||||
| 	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, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* 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) | ||||||
| 	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) | ||||||
| 	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) | ||||||
| 	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) | ||||||
| 	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, | ||||||
| 			       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, | ||||||
| 		/* 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, | ||||||
| 	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) | ||||||
| 	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) | ||||||
| 		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) | ||||||
| 		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) | ||||||
| 			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) | ||||||
| 		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 { | ||||||
| 	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; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Ram Pai
						Ram Pai