diff options
Diffstat (limited to 'scripts/mod')
| -rw-r--r-- | scripts/mod/file2alias.c | 5 | ||||
| -rw-r--r-- | scripts/mod/modpost.c | 198 | ||||
| -rw-r--r-- | scripts/mod/modpost.h | 9 | 
3 files changed, 185 insertions, 27 deletions
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index e17a29ae2e97..c91eba751804 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -36,6 +36,11 @@ typedef uint16_t	__u16;  typedef unsigned char	__u8;  typedef struct {  	__u8 b[16]; +} guid_t; + +/* backwards compatibility, don't use in new code */ +typedef struct { +	__u8 b[16];  } uuid_le;  typedef struct {  	__u8 b[16]; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index f277e116e0eb..3961941e8e7a 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -38,6 +38,8 @@ static int sec_mismatch_count = 0;  static int sec_mismatch_fatal = 0;  /* ignore missing files */  static int ignore_missing_files; +/* write namespace dependencies */ +static int write_namespace_deps;  enum export {  	export_plain,      export_unused,     export_gpl, @@ -164,11 +166,13 @@ struct symbol {  	struct module *module;  	unsigned int crc;  	int crc_valid; +	const char *namespace;  	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) **/  	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */ +	unsigned int is_static:1;  /* 1 if symbol is not global */  	enum export  export;       /* Type of export */  	char name[0];  }; @@ -201,6 +205,7 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak,  	strcpy(s->name, name);  	s->weak = weak;  	s->next = next; +	s->is_static = 1;  	return s;  } @@ -233,6 +238,37 @@ static struct symbol *find_symbol(const char *name)  	return NULL;  } +static bool contains_namespace(struct namespace_list *list, +			       const char *namespace) +{ +	struct namespace_list *ns_entry; + +	for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next) +		if (strcmp(ns_entry->namespace, namespace) == 0) +			return true; + +	return false; +} + +static void add_namespace(struct namespace_list **list, const char *namespace) +{ +	struct namespace_list *ns_entry; + +	if (!contains_namespace(*list, namespace)) { +		ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) + +					 strlen(namespace) + 1)); +		strcpy(ns_entry->namespace, namespace); +		ns_entry->next = *list; +		*list = ns_entry; +	} +} + +static bool module_imports_namespace(struct module *module, +				     const char *namespace) +{ +	return contains_namespace(module->imported_namespaces, namespace); +} +  static const struct {  	const char *str;  	enum export export; @@ -312,23 +348,39 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)  		return export_unknown;  } +static const char *sym_extract_namespace(const char **symname) +{ +	size_t n; +	char *dupsymname; + +	n = strcspn(*symname, "."); +	if (n < strlen(*symname) - 1) { +		dupsymname = NOFAIL(strdup(*symname)); +		dupsymname[n] = '\0'; +		*symname = dupsymname; +		return dupsymname + n + 1; +	} + +	return NULL; +} +  /**   * Add an exported symbol - it may have already been added without a   * CRC, in this case just update the CRC   **/ -static struct symbol *sym_add_exported(const char *name, struct module *mod, -				       enum export export) +static struct symbol *sym_add_exported(const char *name, const char *namespace, +				       struct module *mod, enum export export)  {  	struct symbol *s = find_symbol(name);  	if (!s) {  		s = new_symbol(name, mod, export); +		s->namespace = namespace;  	} else {  		if (!s->preloaded) { -			warn("%s: '%s' exported twice. Previous export " -			     "was in %s%s\n", mod->name, name, -			     s->module->name, -			     is_vmlinux(s->module->name) ?"":".ko"); +			warn("%s: '%s' exported twice. Previous export was in %s%s\n", +			     mod->name, name, s->module->name, +			     is_vmlinux(s->module->name) ? "" : ".ko");  		} else {  			/* In case Module.symvers was out of date */  			s->module = mod; @@ -620,6 +672,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,  	unsigned int crc;  	enum export export;  	bool is_crc = false; +	const char *name, *namespace;  	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&  	    strstarts(symname, "__ksymtab")) @@ -691,8 +744,9 @@ static void handle_modversions(struct module *mod, struct elf_info *info,  	default:  		/* All exported symbols */  		if (strstarts(symname, "__ksymtab_")) { -			sym_add_exported(symname + strlen("__ksymtab_"), mod, -					export); +			name = symname + strlen("__ksymtab_"); +			namespace = sym_extract_namespace(&name); +			sym_add_exported(name, namespace, mod, export);  		}  		if (strcmp(symname, "init_module") == 0)  			mod->has_init = 1; @@ -795,9 +849,9 @@ static int match(const char *sym, const char * const pat[])  		/* "*foo*" */  		if (*p == '*' && *endp == '*') { -			char *here, *bare = strndup(p + 1, strlen(p) - 2); +			char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2)); +			char *here = strstr(sym, bare); -			here = strstr(sym, bare);  			free(bare);  			if (here != NULL)  				return 1; @@ -1943,6 +1997,7 @@ static void read_symbols(const char *modname)  	const char *symname;  	char *version;  	char *license; +	char *namespace;  	struct module *mod;  	struct elf_info info = { };  	Elf_Sym *sym; @@ -1974,12 +2029,33 @@ static void read_symbols(const char *modname)  		license = get_next_modinfo(&info, "license", license);  	} +	namespace = get_modinfo(&info, "import_ns"); +	while (namespace) { +		add_namespace(&mod->imported_namespaces, namespace); +		namespace = get_next_modinfo(&info, "import_ns", namespace); +	} +  	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {  		symname = remove_dot(info.strtab + sym->st_name);  		handle_modversions(mod, &info, sym, symname);  		handle_moddevtable(mod, &info, sym, symname);  	} + +	// check for static EXPORT_SYMBOL_* functions && global vars +	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { +		unsigned char bind = ELF_ST_BIND(sym->st_info); + +		if (bind == STB_GLOBAL || bind == STB_WEAK) { +			struct symbol *s = +				find_symbol(remove_dot(info.strtab + +						       sym->st_name)); + +			if (s) +				s->is_static = 0; +		} +	} +  	if (!is_vmlinux(modname) || vmlinux_section_warnings)  		check_sec_ref(mod, modname, &info); @@ -2118,6 +2194,18 @@ static int check_exports(struct module *mod)  			basename++;  		else  			basename = mod->name; + +		if (exp->namespace) { +			add_namespace(&mod->required_namespaces, +				      exp->namespace); + +			if (!write_namespace_deps && +			    !module_imports_namespace(mod, exp->namespace)) { +				warn("module %s uses symbol %s from namespace %s, but does not import it.\n", +				     basename, exp->name, exp->namespace); +			} +		} +  		if (!mod->gpl_compatible)  			check_for_gpl_usage(exp->export, basename, exp->name);  		check_for_unused(exp->export, basename, exp->name); @@ -2159,7 +2247,7 @@ static void add_header(struct buffer *b, struct module *mod)  	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");  	buf_printf(b, "\n");  	buf_printf(b, "__visible struct module __this_module\n"); -	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); +	buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");  	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");  	if (mod->has_init)  		buf_printf(b, "\t.init = init_module,\n"); @@ -2213,8 +2301,7 @@ static int add_versions(struct buffer *b, struct module *mod)  	buf_printf(b, "\n");  	buf_printf(b, "static const struct modversion_info ____versions[]\n"); -	buf_printf(b, "__used\n"); -	buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); +	buf_printf(b, "__used __section(__versions) = {\n");  	for (s = mod->unres; s; s = s->next) {  		if (!s->module) @@ -2250,10 +2337,7 @@ static void add_depends(struct buffer *b, struct module *mod)  			s->module->seen = is_vmlinux(s->module->name);  	buf_printf(b, "\n"); -	buf_printf(b, "static const char __module_depends[]\n"); -	buf_printf(b, "__used\n"); -	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); -	buf_printf(b, "\"depends="); +	buf_printf(b, "MODULE_INFO(depends, \"");  	for (s = mod->unres; s; s = s->next) {  		const char *p;  		if (!s->module) @@ -2271,7 +2355,7 @@ static void add_depends(struct buffer *b, struct module *mod)  		buf_printf(b, "%s%s", first ? "" : ",", p);  		first = 0;  	} -	buf_printf(b, "\";\n"); +	buf_printf(b, "\");\n");  }  static void add_srcversion(struct buffer *b, struct module *mod) @@ -2341,7 +2425,7 @@ static void read_dump(const char *fname, unsigned int kernel)  		return;  	while ((line = get_next_line(&pos, file, size))) { -		char *symname, *modname, *d, *export, *end; +		char *symname, *namespace, *modname, *d, *export, *end;  		unsigned int crc;  		struct module *mod;  		struct symbol *s; @@ -2349,7 +2433,10 @@ static void read_dump(const char *fname, unsigned int kernel)  		if (!(symname = strchr(line, '\t')))  			goto fail;  		*symname++ = '\0'; -		if (!(modname = strchr(symname, '\t'))) +		if (!(namespace = strchr(symname, '\t'))) +			goto fail; +		*namespace++ = '\0'; +		if (!(modname = strchr(namespace, '\t')))  			goto fail;  		*modname++ = '\0';  		if ((export = strchr(modname, '\t')) != NULL) @@ -2366,9 +2453,11 @@ static void read_dump(const char *fname, unsigned int kernel)  			mod = new_module(modname);  			mod->skip = 1;  		} -		s = sym_add_exported(symname, mod, export_no(export)); +		s = sym_add_exported(symname, namespace, mod, +				     export_no(export));  		s->kernel    = kernel;  		s->preloaded = 1; +		s->is_static = 0;  		sym_update_crc(symname, mod, crc, export_no(export));  	}  	release_file(file, size); @@ -2395,16 +2484,20 @@ static void write_dump(const char *fname)  {  	struct buffer buf = { };  	struct symbol *symbol; +	const char *namespace;  	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)); +			if (dump_sym(symbol)) { +				namespace = symbol->namespace; +				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n", +					   symbol->crc, symbol->name, +					   namespace ? namespace : "", +					   symbol->module->name, +					   export_str(symbol->export)); +			}  			symbol = symbol->next;  		}  	} @@ -2412,6 +2505,31 @@ static void write_dump(const char *fname)  	free(buf.p);  } +static void write_namespace_deps_files(void) +{ +	struct module *mod; +	struct namespace_list *ns; +	struct buffer ns_deps_buf = {}; + +	for (mod = modules; mod; mod = mod->next) { +		char fname[PATH_MAX]; + +		if (mod->skip) +			continue; + +		ns_deps_buf.pos = 0; + +		for (ns = mod->required_namespaces; ns; ns = ns->next) +			buf_printf(&ns_deps_buf, "%s\n", ns->namespace); + +		if (ns_deps_buf.pos == 0) +			continue; + +		sprintf(fname, "%s.ns_deps", mod->name); +		write_if_changed(&ns_deps_buf, fname); +	} +} +  struct ext_sym_list {  	struct ext_sym_list *next;  	const char *file; @@ -2425,10 +2543,11 @@ int main(int argc, char **argv)  	char *dump_write = NULL, *files_source = NULL;  	int opt;  	int err; +	int n;  	struct ext_sym_list *extsym_iter;  	struct ext_sym_list *extsym_start = NULL; -	while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awE")) != -1) { +	while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {  		switch (opt) {  		case 'i':  			kernel_read = optarg; @@ -2469,6 +2588,9 @@ int main(int argc, char **argv)  		case 'E':  			sec_mismatch_fatal = 1;  			break; +		case 'd': +			write_namespace_deps = 1; +			break;  		default:  			exit(1);  		} @@ -2503,6 +2625,9 @@ int main(int argc, char **argv)  		err |= check_modname_len(mod);  		err |= check_exports(mod); +		if (write_namespace_deps) +			continue; +  		add_header(&buf, mod);  		add_intree_flag(&buf, !external_module);  		add_retpoline(&buf); @@ -2515,11 +2640,30 @@ int main(int argc, char **argv)  		sprintf(fname, "%s.mod.c", mod->name);  		write_if_changed(&buf, fname);  	} + +	if (write_namespace_deps) { +		write_namespace_deps_files(); +		return 0; +	} +  	if (dump_write)  		write_dump(dump_write);  	if (sec_mismatch_count && sec_mismatch_fatal)  		fatal("modpost: Section mismatches detected.\n"  		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); +	for (n = 0; n < SYMBOL_HASH_SIZE; n++) { +		struct symbol *s = symbolhash[n]; + +		while (s) { +			if (s->is_static) +				warn("\"%s\" [%s] is a static %s\n", +				     s->name, s->module->name, +				     export_str(s->export)); + +			s = s->next; +		} +	} +  	free(buf.p);  	return err; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 8453d6ac2f77..92a926d375d2 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -109,6 +109,11 @@ buf_printf(struct buffer *buf, const char *fmt, ...);  void  buf_write(struct buffer *buf, const char *s, int len); +struct namespace_list { +	struct namespace_list *next; +	char namespace[0]; +}; +  struct module {  	struct module *next;  	const char *name; @@ -121,6 +126,10 @@ struct module {  	struct buffer dev_table_buf;  	char	     srcversion[25];  	int is_dot_o; +	// Required namespace dependencies +	struct namespace_list *required_namespaces; +	// Actual imported namespaces +	struct namespace_list *imported_namespaces;  };  struct elf_info {  |