diff options
Diffstat (limited to 'scripts/mod/modpost.c')
| -rw-r--r-- | scripts/mod/modpost.c | 175 | 
1 files changed, 133 insertions, 42 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index f6127b9f5ac..1ec7158b6c1 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -14,6 +14,7 @@  #define _GNU_SOURCE  #include <stdio.h>  #include <ctype.h> +#include <string.h>  #include "modpost.h"  #include "../../include/generated/autoconf.h"  #include "../../include/linux/license.h" @@ -253,7 +254,7 @@ static enum export export_no(const char *s)  	return export_unknown;  } -static enum export export_from_sec(struct elf_info *elf, Elf_Section sec) +static enum export export_from_sec(struct elf_info *elf, unsigned int sec)  {  	if (sec == elf->export_sec)  		return export_plain; @@ -373,6 +374,8 @@ static int parse_elf(struct elf_info *info, const char *filename)  	Elf_Ehdr *hdr;  	Elf_Shdr *sechdrs;  	Elf_Sym  *sym; +	const char *secstrings; +	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;  	hdr = grab_file(filename, &info->size);  	if (!hdr) { @@ -417,8 +420,27 @@ static int parse_elf(struct elf_info *info, const char *filename)  		return 0;  	} +	if (hdr->e_shnum == 0) { +		/* +		 * There are more than 64k sections, +		 * read count from .sh_size. +		 * note: it doesn't need shndx2secindex() +		 */ +		info->num_sections = TO_NATIVE(sechdrs[0].sh_size); +	} +	else { +		info->num_sections = hdr->e_shnum; +	} +	if (hdr->e_shstrndx == SHN_XINDEX) { +		info->secindex_strings = +		    shndx2secindex(TO_NATIVE(sechdrs[0].sh_link)); +	} +	else { +		info->secindex_strings = hdr->e_shstrndx; +	} +  	/* Fix endianness in section headers */ -	for (i = 0; i < hdr->e_shnum; i++) { +	for (i = 0; i < info->num_sections; i++) {  		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);  		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);  		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags); @@ -431,9 +453,8 @@ static int parse_elf(struct elf_info *info, const char *filename)  		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);  	}  	/* Find symbol table. */ -	for (i = 1; i < hdr->e_shnum; i++) { -		const char *secstrings -			= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; +	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; +	for (i = 1; i < info->num_sections; i++) {  		const char *secname;  		int nobits = sechdrs[i].sh_type == SHT_NOBITS; @@ -461,14 +482,26 @@ static int parse_elf(struct elf_info *info, const char *filename)  		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)  			info->export_gpl_future_sec = i; -		if (sechdrs[i].sh_type != SHT_SYMTAB) -			continue; +		if (sechdrs[i].sh_type == SHT_SYMTAB) { +			unsigned int sh_link_idx; +			symtab_idx = i; +			info->symtab_start = (void *)hdr + +			    sechdrs[i].sh_offset; +			info->symtab_stop  = (void *)hdr + +			    sechdrs[i].sh_offset + sechdrs[i].sh_size; +			sh_link_idx = shndx2secindex(sechdrs[i].sh_link); +			info->strtab       = (void *)hdr + +			    sechdrs[sh_link_idx].sh_offset; +		} -		info->symtab_start = (void *)hdr + sechdrs[i].sh_offset; -		info->symtab_stop  = (void *)hdr + sechdrs[i].sh_offset -			                         + sechdrs[i].sh_size; -		info->strtab       = (void *)hdr + -			             sechdrs[sechdrs[i].sh_link].sh_offset; +		/* 32bit section no. table? ("more than 64k sections") */ +		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { +			symtab_shndx_idx = i; +			info->symtab_shndx_start = (void *)hdr + +			    sechdrs[i].sh_offset; +			info->symtab_shndx_stop  = (void *)hdr + +			    sechdrs[i].sh_offset + sechdrs[i].sh_size; +		}  	}  	if (!info->symtab_start)  		fatal("%s has no symtab?\n", filename); @@ -480,6 +513,21 @@ static int parse_elf(struct elf_info *info, const char *filename)  		sym->st_value = TO_NATIVE(sym->st_value);  		sym->st_size  = TO_NATIVE(sym->st_size);  	} + +	if (symtab_shndx_idx != ~0U) { +		Elf32_Word *p; +		if (symtab_idx != +		    shndx2secindex(sechdrs[symtab_shndx_idx].sh_link)) +			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", +			      filename, +			      shndx2secindex(sechdrs[symtab_shndx_idx].sh_link), +			      symtab_idx); +		/* Fix endianness */ +		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; +		     p++) +			*p = TO_NATIVE(*p); +	} +  	return 1;  } @@ -519,7 +567,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,  			       Elf_Sym *sym, const char *symname)  {  	unsigned int crc; -	enum export export = export_from_sec(info, sym->st_shndx); +	enum export export = export_from_sec(info, get_secindex(info, sym));  	switch (sym->st_shndx) {  	case SHN_COMMON: @@ -661,19 +709,19 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)  		return "(unknown)";  } -static const char *sec_name(struct elf_info *elf, int shndx) +static const char *sec_name(struct elf_info *elf, int secindex)  {  	Elf_Shdr *sechdrs = elf->sechdrs;  	return (void *)elf->hdr + -	        elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + -	        sechdrs[shndx].sh_name; +		elf->sechdrs[elf->secindex_strings].sh_offset + +		sechdrs[secindex].sh_name;  }  static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)  {  	return (void *)elf->hdr + -	        elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + -	        sechdr->sh_name; +		elf->sechdrs[elf->secindex_strings].sh_offset + +		sechdr->sh_name;  }  /* if sym is empty or point to a string @@ -742,6 +790,7 @@ static const char *section_white_list[] =  {  	".comment*",  	".debug*", +	".GCC-command-line",	/* mn10300 */  	".mdebug*",        /* alpha, score, mips etc. */  	".pdr",            /* alpha, score, mips etc. */  	".stab*", @@ -986,6 +1035,13 @@ static const struct sectioncheck *section_mismatch(   *   fromsec = .data*   *   atsym   =__param*   * + * Pattern 1a: + *   module_param_call() ops can refer to __init set function if permissions=0 + *   The pattern is identified by: + *   tosec   = .init.text + *   fromsec = .data* + *   atsym   = __param_ops_* + *   * Pattern 2:   *   Many drivers utilise a *driver container with references to   *   add, remove, probe functions etc. @@ -1020,6 +1076,12 @@ static int secref_whitelist(const struct sectioncheck *mismatch,  	    (strncmp(fromsym, "__param", strlen("__param")) == 0))  		return 0; +	/* Check for pattern 1a */ +	if (strcmp(tosec, ".init.text") == 0 && +	    match(fromsec, data_sections) && +	    (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0)) +		return 0; +  	/* Check for pattern 2 */  	if (match(tosec, init_exit_sections) &&  	    match(fromsec, data_sections) && @@ -1052,11 +1114,14 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,  	Elf_Sym *near = NULL;  	Elf64_Sword distance = 20;  	Elf64_Sword d; +	unsigned int relsym_secindex;  	if (relsym->st_name != 0)  		return relsym; + +	relsym_secindex = get_secindex(elf, relsym);  	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { -		if (sym->st_shndx != relsym->st_shndx) +		if (get_secindex(elf, sym) != relsym_secindex)  			continue;  		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)  			continue; @@ -1118,9 +1183,9 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,  	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {  		const char *symsec; -		if (sym->st_shndx >= SHN_LORESERVE) +		if (is_shndx_special(sym->st_shndx))  			continue; -		symsec = sec_name(elf, sym->st_shndx); +		symsec = sec_name(elf, get_secindex(elf, sym));  		if (strcmp(symsec, sec) != 0)  			continue;  		if (!is_valid_name(elf, sym)) @@ -1167,7 +1232,7 @@ static char *sec2annotation(const char *s)  			strcat(p, " ");  		return r; /* we leak her but we do not care */  	} else { -		return ""; +		return strdup("");  	}  } @@ -1195,6 +1260,8 @@ static void report_sec_mismatch(const char *modname,  {  	const char *from, *from_p;  	const char *to, *to_p; +	char *prl_from; +	char *prl_to;  	switch (from_is_func) {  	case 0: from = "variable"; from_p = "";   break; @@ -1218,16 +1285,21 @@ static void report_sec_mismatch(const char *modname,  	switch (mismatch->mismatch) {  	case TEXT_TO_ANY_INIT: +		prl_from = sec2annotation(fromsec); +		prl_to = sec2annotation(tosec);  		fprintf(stderr,  		"The function %s%s() references\n"  		"the %s %s%s%s.\n"  		"This is often because %s lacks a %s\n"  		"annotation or the annotation of %s is wrong.\n", -		sec2annotation(fromsec), fromsym, -		to, sec2annotation(tosec), tosym, to_p, -		fromsym, sec2annotation(tosec), tosym); +		prl_from, fromsym, +		to, prl_to, tosym, to_p, +		fromsym, prl_to, tosym); +		free(prl_from); +		free(prl_to);  		break;  	case DATA_TO_ANY_INIT: { +		prl_to = sec2annotation(tosec);  		const char *const *s = mismatch->symbol_white_list;  		fprintf(stderr,  		"The variable %s references\n" @@ -1235,20 +1307,24 @@ static void report_sec_mismatch(const char *modname,  		"If the reference is valid then annotate the\n"  		"variable with __init* or __refdata (see linux/init.h) "  		"or name the variable:\n", -		fromsym, to, sec2annotation(tosec), tosym, to_p); +		fromsym, to, prl_to, tosym, to_p);  		while (*s)  			fprintf(stderr, "%s, ", *s++);  		fprintf(stderr, "\n"); +		free(prl_to);  		break;  	}  	case TEXT_TO_ANY_EXIT: +		prl_to = sec2annotation(tosec);  		fprintf(stderr,  		"The function %s() references a %s in an exit section.\n"  		"Often the %s %s%s has valid usage outside the exit section\n"  		"and the fix is to remove the %sannotation of %s.\n", -		fromsym, to, to, tosym, to_p, sec2annotation(tosec), tosym); +		fromsym, to, to, tosym, to_p, prl_to, tosym); +		free(prl_to);  		break;  	case DATA_TO_ANY_EXIT: { +		prl_to = sec2annotation(tosec);  		const char *const *s = mismatch->symbol_white_list;  		fprintf(stderr,  		"The variable %s references\n" @@ -1256,24 +1332,31 @@ static void report_sec_mismatch(const char *modname,  		"If the reference is valid then annotate the\n"  		"variable with __exit* (see linux/init.h) or "  		"name the variable:\n", -		fromsym, to, sec2annotation(tosec), tosym, to_p); +		fromsym, to, prl_to, tosym, to_p);  		while (*s)  			fprintf(stderr, "%s, ", *s++);  		fprintf(stderr, "\n"); +		free(prl_to);  		break;  	}  	case XXXINIT_TO_SOME_INIT:  	case XXXEXIT_TO_SOME_EXIT: +		prl_from = sec2annotation(fromsec); +		prl_to = sec2annotation(tosec);  		fprintf(stderr,  		"The %s %s%s%s references\n"  		"a %s %s%s%s.\n"  		"If %s is only used by %s then\n"  		"annotate %s with a matching annotation.\n", -		from, sec2annotation(fromsec), fromsym, from_p, -		to, sec2annotation(tosec), tosym, to_p, +		from, prl_from, fromsym, from_p, +		to, prl_to, tosym, to_p,  		tosym, fromsym, tosym); +		free(prl_from); +		free(prl_to);  		break;  	case ANY_INIT_TO_ANY_EXIT: +		prl_from = sec2annotation(fromsec); +		prl_to = sec2annotation(tosec);  		fprintf(stderr,  		"The %s %s%s%s references\n"  		"a %s %s%s%s.\n" @@ -1282,11 +1365,15 @@ static void report_sec_mismatch(const char *modname,  		"uses functionality in the exit path.\n"  		"The fix is often to remove the %sannotation of\n"  		"%s%s so it may be used outside an exit section.\n", -		from, sec2annotation(fromsec), fromsym, from_p, -		to, sec2annotation(tosec), tosym, to_p, -		sec2annotation(tosec), tosym, to_p); +		from, prl_from, fromsym, from_p, +		to, prl_to, tosym, to_p, +		prl_to, tosym, to_p); +		free(prl_from); +		free(prl_to);  		break;  	case ANY_EXIT_TO_ANY_INIT: +		prl_from = sec2annotation(fromsec); +		prl_to = sec2annotation(tosec);  		fprintf(stderr,  		"The %s %s%s%s references\n"  		"a %s %s%s%s.\n" @@ -1295,16 +1382,20 @@ static void report_sec_mismatch(const char *modname,  		"uses functionality in the init path.\n"  		"The fix is often to remove the %sannotation of\n"  		"%s%s so it may be used outside an init section.\n", -		from, sec2annotation(fromsec), fromsym, from_p, -		to, sec2annotation(tosec), tosym, to_p, -		sec2annotation(tosec), tosym, to_p); +		from, prl_from, fromsym, from_p, +		to, prl_to, tosym, to_p, +		prl_to, tosym, to_p); +		free(prl_from); +		free(prl_to);  		break;  	case EXPORT_TO_INIT_EXIT: +		prl_to = sec2annotation(tosec);  		fprintf(stderr,  		"The symbol %s is exported and annotated %s\n"  		"Fix this by removing the %sannotation of %s "  		"or drop the export.\n", -		tosym, sec2annotation(tosec), sec2annotation(tosec), tosym); +		tosym, prl_to, prl_to, tosym); +		free(prl_to);  		break;  	}  	fprintf(stderr, "\n"); @@ -1316,7 +1407,7 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,  	const char *tosec;  	const struct sectioncheck *mismatch; -	tosec = sec_name(elf, sym->st_shndx); +	tosec = sec_name(elf, get_secindex(elf, sym));  	mismatch = section_mismatch(fromsec, tosec);  	if (mismatch) {  		Elf_Sym *to; @@ -1344,7 +1435,7 @@ static unsigned int *reloc_location(struct elf_info *elf,  				    Elf_Shdr *sechdr, Elf_Rela *r)  {  	Elf_Shdr *sechdrs = elf->sechdrs; -	int section = sechdr->sh_info; +	int section = shndx2secindex(sechdr->sh_info);  	return (void *)elf->hdr + sechdrs[section].sh_offset +  		r->r_offset - sechdrs[section].sh_addr; @@ -1452,7 +1543,7 @@ static void section_rela(const char *modname, struct elf_info *elf,  		r.r_addend = TO_NATIVE(rela->r_addend);  		sym = elf->symtab_start + r_sym;  		/* Skip special sections */ -		if (sym->st_shndx >= SHN_LORESERVE) +		if (is_shndx_special(sym->st_shndx))  			continue;  		check_section_mismatch(modname, elf, &r, sym, fromsec);  	} @@ -1510,7 +1601,7 @@ static void section_rel(const char *modname, struct elf_info *elf,  		}  		sym = elf->symtab_start + r_sym;  		/* Skip special sections */ -		if (sym->st_shndx >= SHN_LORESERVE) +		if (is_shndx_special(sym->st_shndx))  			continue;  		check_section_mismatch(modname, elf, &r, sym, fromsec);  	} @@ -1535,7 +1626,7 @@ static void check_sec_ref(struct module *mod, const char *modname,  	Elf_Shdr *sechdrs = elf->sechdrs;  	/* Walk through all sections */ -	for (i = 0; i < elf->hdr->e_shnum; i++) { +	for (i = 0; i < elf->num_sections; i++) {  		check_section(modname, elf, &elf->sechdrs[i]);  		/* We want to process only relocation sections and not .init */  		if (sechdrs[i].sh_type == SHT_RELA)  | 
