diff options
Diffstat (limited to 'scripts/mod')
| -rw-r--r-- | scripts/mod/file2alias.c | 4 | ||||
| -rw-r--r-- | scripts/mod/modpost.c | 281 | ||||
| -rw-r--r-- | scripts/mod/modpost.h | 33 | 
3 files changed, 68 insertions, 250 deletions
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index cbd6b0f48b4e..80d973144fde 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1571,9 +1571,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,  		zeros = calloc(1, sym->st_size);  		symval = zeros;  	} else { -		symval = (void *)info->hdr -			+ info->sechdrs[get_secindex(info, sym)].sh_offset -			+ sym->st_value; +		symval = sym_get_data(info, sym);  	}  	/* First handle the "special" cases */ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 29474cee10b1..55e32af2e53f 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -321,13 +321,10 @@ static void *sym_get_data_by_offset(const struct elf_info *info,  {  	Elf_Shdr *sechdr = &info->sechdrs[secindex]; -	if (info->hdr->e_type != ET_REL) -		offset -= sechdr->sh_addr; -  	return (void *)info->hdr + sechdr->sh_offset + offset;  } -static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) +void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)  {  	return sym_get_data_by_offset(info, get_secindex(info, sym),  				      sym->st_value); @@ -339,8 +336,16 @@ static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)  				      sechdr->sh_name);  } -static const char *sec_name(const struct elf_info *info, int secindex) +static const char *sec_name(const struct elf_info *info, unsigned int secindex)  { +	/* +	 * If sym->st_shndx is a special section index, there is no +	 * corresponding section header. +	 * Return "" if the index is out of range of info->sechdrs[] array. +	 */ +	if (secindex >= info->num_sections) +		return ""; +  	return sech_name(info, &info->sechdrs[secindex]);  } @@ -466,6 +471,10 @@ static int parse_elf(struct elf_info *info, const char *filename)  	sechdrs = (void *)hdr + hdr->e_shoff;  	info->sechdrs = sechdrs; +	/* modpost only works for relocatable objects */ +	if (hdr->e_type != ET_REL) +		fatal("%s: not relocatable object.", filename); +  	/* Check if file offset is correct */  	if (hdr->e_shoff > info->size) {  		fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n", @@ -737,12 +746,18 @@ static bool match(const char *string, const char *const patterns[])  	return false;  } +/* useful to pass patterns to match() directly */ +#define PATTERNS(...) \ +	({ \ +		static const char *const patterns[] = {__VA_ARGS__, NULL}; \ +		patterns; \ +	}) +  /* sections that we do not want to do full section mismatch check on */  static const char *const section_white_list[] =  {  	".comment*",  	".debug*", -	".cranges",		/* sh64 */  	".zdebug*",		/* Compressed debug sections. */  	".GCC.command.line",	/* record-gcc-switches */  	".mdebug*",        /* alpha, score, mips etc. */ @@ -830,28 +845,12 @@ static const char *const init_data_sections[] =  /* all init sections */  static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; -/* All init and exit sections (code + data) */ -static const char *const init_exit_sections[] = -	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; -  /* all text sections */  static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };  /* data section */  static const char *const data_sections[] = { DATA_SECTIONS, NULL }; - -/* symbols in .data that may refer to init/exit sections */ -#define DEFAULT_SYMBOL_WHITE_LIST					\ -	"*driver",							\ -	"*_template", /* scsi uses *_template a lot */			\ -	"*_timer",    /* arm uses ops structures named _timer a lot */	\ -	"*_sht",      /* scsi also used *_sht to some extent */		\ -	"*_ops",							\ -	"*_probe",							\ -	"*_probe_one",							\ -	"*_console" -  static const char *const head_sections[] = { ".head.text*", NULL };  static const char *const linker_symbols[] =  	{ "__init_begin", "_sinittext", "_einittext", NULL }; @@ -883,9 +882,6 @@ enum mismatch {   *   * @mismatch: Type of mismatch.   * - * @symbol_white_list: Do not match a relocation to a symbol in this list - * even if it is targeting a section in @bad_to_sec. - *   * @handler: Specific handler to call when a match is found.  If NULL,   * default_mismatch_handler() will be called.   * @@ -895,7 +891,6 @@ struct sectioncheck {  	const char *bad_tosec[20];  	const char *good_tosec[20];  	enum mismatch mismatch; -	const char *symbol_white_list[20];  	void (*handler)(const char *modname, struct elf_info *elf,  			const struct sectioncheck* const mismatch,  			Elf_Rela *r, Elf_Sym *sym, const char *fromsec); @@ -915,75 +910,61 @@ static const struct sectioncheck sectioncheck[] = {  	.fromsec = { TEXT_SECTIONS, NULL },  	.bad_tosec = { ALL_INIT_SECTIONS, NULL },  	.mismatch = TEXT_TO_ANY_INIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  {  	.fromsec = { DATA_SECTIONS, NULL },  	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },  	.mismatch = DATA_TO_ANY_INIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  {  	.fromsec = { DATA_SECTIONS, NULL },  	.bad_tosec = { INIT_SECTIONS, NULL },  	.mismatch = DATA_TO_ANY_INIT, -	.symbol_white_list = { -		"*_template", "*_timer", "*_sht", "*_ops", -		"*_probe", "*_probe_one", "*_console", NULL -	},  },  {  	.fromsec = { TEXT_SECTIONS, NULL },  	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },  	.mismatch = TEXT_TO_ANY_EXIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  {  	.fromsec = { DATA_SECTIONS, NULL },  	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },  	.mismatch = DATA_TO_ANY_EXIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  /* Do not reference init code/data from meminit code/data */  {  	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },  	.bad_tosec = { INIT_SECTIONS, NULL },  	.mismatch = XXXINIT_TO_SOME_INIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  /* Do not reference exit code/data from memexit code/data */  {  	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },  	.bad_tosec = { EXIT_SECTIONS, NULL },  	.mismatch = XXXEXIT_TO_SOME_EXIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  /* Do not use exit code/data from init code */  {  	.fromsec = { ALL_INIT_SECTIONS, NULL },  	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },  	.mismatch = ANY_INIT_TO_ANY_EXIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  /* Do not use init code/data from exit code */  {  	.fromsec = { ALL_EXIT_SECTIONS, NULL },  	.bad_tosec = { ALL_INIT_SECTIONS, NULL },  	.mismatch = ANY_EXIT_TO_ANY_INIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  {  	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },  	.bad_tosec = { INIT_SECTIONS, NULL },  	.mismatch = ANY_INIT_TO_ANY_EXIT, -	.symbol_white_list = { NULL },  },  /* Do not export init/exit functions or data */  {  	.fromsec = { "___ksymtab*", NULL },  	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },  	.mismatch = EXPORT_TO_INIT_EXIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  },  {  	.fromsec = { "__ex_table", NULL }, @@ -1044,15 +1025,6 @@ static const struct sectioncheck *section_mismatch(   *   fromsec = .data*   *   atsym   = __param_ops_*   * - * Pattern 2: - *   Many drivers utilise a *driver container with references to - *   add, remove, probe functions etc. - *   the pattern is identified by: - *   tosec   = init or exit section - *   fromsec = data section - *   atsym = *driver, *_template, *_sht, *_ops, *_probe, - *           *probe_one, *_console, *_timer - *   * Pattern 3:   *   Whitelist all references from .head.text to any init section   * @@ -1101,10 +1073,22 @@ static int secref_whitelist(const struct sectioncheck *mismatch,  	    strstarts(fromsym, "__param_ops_"))  		return 0; -	/* Check for pattern 2 */ -	if (match(tosec, init_exit_sections) && -	    match(fromsec, data_sections) && -	    match(fromsym, mismatch->symbol_white_list)) +	/* symbols in data sections that may refer to any init/exit sections */ +	if (match(fromsec, PATTERNS(DATA_SECTIONS)) && +	    match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) && +	    match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot +				    "*_timer", // arm uses ops structures named _timer a lot +				    "*_sht", // scsi also used *_sht to some extent +				    "*_ops", +				    "*_probe", +				    "*_probe_one", +				    "*_console"))) +		return 0; + +	/* symbols in data sections that may refer to meminit/exit sections */ +	if (match(fromsec, PATTERNS(DATA_SECTIONS)) && +	    match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) && +	    match(fromsym, PATTERNS("*driver")))  		return 0;  	/* Check for pattern 3 */ @@ -1230,42 +1214,6 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,  	return near;  } -/* - * Convert a section name to the function/data attribute - * .init.text => __init - * .memexitconst => __memconst - * etc. - * - * The memory of returned value has been allocated on a heap. The user of this - * method should free it after usage. -*/ -static char *sec2annotation(const char *s) -{ -	if (match(s, init_exit_sections)) { -		char *p = NOFAIL(malloc(20)); -		char *r = p; - -		*p++ = '_'; -		*p++ = '_'; -		if (*s == '.') -			s++; -		while (*s && *s != '.') -			*p++ = *s++; -		*p = '\0'; -		if (*s == '.') -			s++; -		if (strstr(s, "rodata") != NULL) -			strcat(p, "const "); -		else if (strstr(s, "data") != NULL) -			strcat(p, "data "); -		else -			strcat(p, " "); -		return r; -	} else { -		return NOFAIL(strdup("")); -	} -} -  static int is_function(Elf_Sym *sym)  {  	if (sym) @@ -1274,19 +1222,6 @@ static int is_function(Elf_Sym *sym)  		return -1;  } -static void print_section_list(const char * const list[20]) -{ -	const char *const *s = list; - -	while (*s) { -		fprintf(stderr, "%s", *s); -		s++; -		if (*s) -			fprintf(stderr, ", "); -	} -	fprintf(stderr, "\n"); -} -  static inline void get_pretty_name(int is_func, const char** name, const char** name_p)  {  	switch (is_func) { @@ -1304,141 +1239,31 @@ static inline void get_pretty_name(int is_func, const char** name, const char**  static void report_sec_mismatch(const char *modname,  				const struct sectioncheck *mismatch,  				const char *fromsec, -				unsigned long long fromaddr,  				const char *fromsym, -				int from_is_func, -				const char *tosec, const char *tosym, -				int to_is_func) +				const char *tosec, const char *tosym)  { -	const char *from, *from_p; -	const char *to, *to_p; -	char *prl_from; -	char *prl_to; -  	sec_mismatch_count++; -	get_pretty_name(from_is_func, &from, &from_p); -	get_pretty_name(to_is_func, &to, &to_p); - -	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " -	     "to the %s %s:%s%s\n", -	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, -	     tosym, to_p); -  	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", -		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); -		fprintf(stderr, -		"The variable %s references\n" -		"the %s %s%s%s\n" -		"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, prl_to, tosym, to_p); -		print_section_list(mismatch->symbol_white_list); -		free(prl_to); -		break; -	} +	case DATA_TO_ANY_INIT:  	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, prl_to, tosym); -		free(prl_to); -		break; -	case DATA_TO_ANY_EXIT: { -		prl_to = sec2annotation(tosec); -		fprintf(stderr, -		"The variable %s references\n" -		"the %s %s%s%s\n" -		"If the reference is valid then annotate the\n" -		"variable with __exit* (see linux/init.h) or " -		"name the variable:\n", -		fromsym, to, prl_to, tosym, to_p); -		print_section_list(mismatch->symbol_white_list); -		free(prl_to); -		break; -	} +	case DATA_TO_ANY_EXIT:  	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, 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" -		"This is often seen when error handling " -		"in the init function\n" -		"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, 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" -		"This is often seen when error handling " -		"in the exit function\n" -		"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, prl_from, fromsym, from_p, -		to, prl_to, tosym, to_p, -		prl_to, tosym, to_p); -		free(prl_from); -		free(prl_to); +		warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n", +		     modname, fromsym, fromsec, tosym, tosec);  		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, prl_to, prl_to, tosym); -		free(prl_to); +		warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n", +		     modname, tosym, tosec);  		break;  	case EXTABLE_TO_NON_TEXT: -		fatal("There's a special handler for this mismatch type, " -		      "we should never get here."); +		fatal("There's a special handler for this mismatch type, we should never get here.\n");  		break;  	} -	fprintf(stderr, "\n");  }  static void default_mismatch_handler(const char *modname, struct elf_info *elf, @@ -1454,9 +1279,6 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,  	from = find_elf_symbol2(elf, r->r_offset, fromsec);  	fromsym = sym_name(elf, from); -	if (strstarts(fromsym, "reference___initcall")) -		return; -  	tosec = sec_name(elf, get_secindex(elf, sym));  	to = find_elf_symbol(elf, r->r_addend, sym);  	tosym = sym_name(elf, to); @@ -1465,9 +1287,7 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,  	if (secref_whitelist(mismatch,  			     fromsec, fromsym, tosec, tosym)) {  		report_sec_mismatch(modname, mismatch, -				    fromsec, r->r_offset, fromsym, -				    is_function(from), tosec, tosym, -				    is_function(to)); +				    fromsec, fromsym, tosec, tosym);  	}  } @@ -1623,9 +1443,6 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)  		break;  	case R_386_PC32:  		r->r_addend = TO_NATIVE(*location) + 4; -		/* For CONFIG_RELOCATABLE=y */ -		if (elf->hdr->e_type == ET_EXEC) -			r->r_addend += r->r_offset;  		break;  	}  	return 0; @@ -1718,8 +1535,7 @@ static void section_rela(const char *modname, struct elf_info *elf,  	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;  	Elf_Rela *stop  = (void *)start + sechdr->sh_size; -	fromsec = sech_name(elf, sechdr); -	fromsec += strlen(".rela"); +	fromsec = sec_name(elf, sechdr->sh_info);  	/* if from section (name) is know good then skip it */  	if (match(fromsec, section_white_list))  		return; @@ -1771,8 +1587,7 @@ static void section_rel(const char *modname, struct elf_info *elf,  	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;  	Elf_Rel *stop  = (void *)start + sechdr->sh_size; -	fromsec = sech_name(elf, sechdr); -	fromsec += strlen(".rel"); +	fromsec = sec_name(elf, sechdr->sh_info);  	/* if from section (name) is know good then skip it */  	if (match(fromsec, section_white_list))  		return; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 044bdfb894b7..1178f40a73f3 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -26,7 +26,6 @@  #define Elf_Shdr    Elf32_Shdr  #define Elf_Sym     Elf32_Sym  #define Elf_Addr    Elf32_Addr -#define Elf_Sword   Elf64_Sword  #define Elf_Section Elf32_Half  #define ELF_ST_BIND ELF32_ST_BIND  #define ELF_ST_TYPE ELF32_ST_TYPE @@ -41,7 +40,6 @@  #define Elf_Shdr    Elf64_Shdr  #define Elf_Sym     Elf64_Sym  #define Elf_Addr    Elf64_Addr -#define Elf_Sword   Elf64_Sxword  #define Elf_Section Elf64_Half  #define ELF_ST_BIND ELF64_ST_BIND  #define ELF_ST_TYPE ELF64_ST_TYPE @@ -158,22 +156,28 @@ static inline int is_shndx_special(unsigned int i)  	return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;  } -/* - * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of - * the way to -256..-1, to avoid conflicting with real section - * indices. - */ -#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) -  /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */  static inline unsigned int get_secindex(const struct elf_info *info,  					const Elf_Sym *sym)  { -	if (is_shndx_special(sym->st_shndx)) -		return SPECIAL(sym->st_shndx); -	if (sym->st_shndx != SHN_XINDEX) -		return sym->st_shndx; -	return info->symtab_shndx_start[sym - info->symtab_start]; +	unsigned int index = sym->st_shndx; + +	/* +	 * Elf{32,64}_Sym::st_shndx is 2 byte. Big section numbers are available +	 * in the .symtab_shndx section. +	 */ +	if (index == SHN_XINDEX) +		return info->symtab_shndx_start[sym - info->symtab_start]; + +	/* +	 * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of +	 * the way to UINT_MAX-255..UINT_MAX, to avoid conflicting with real +	 * section indices. +	 */ +	if (index >= SHN_LORESERVE && index <= SHN_HIRESERVE) +		return index - SHN_HIRESERVE - 1; + +	return index;  }  /* file2alias.c */ @@ -187,6 +191,7 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen);  /* from modpost.c */  char *read_text_file(const char *filename);  char *get_line(char **stringp); +void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym);  enum loglevel {  	LOG_WARN,  |