xref: /linux-6.15/scripts/mod/modpost.c (revision 3ff6eecc)
11da177e4SLinus Torvalds /* Postprocess module symbol versions
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright 2003       Kai Germaschewski
41da177e4SLinus Torvalds  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5df578e7dSSam Ravnborg  * Copyright 2006-2008  Sam Ravnborg
61da177e4SLinus Torvalds  * Based in part on module-init-tools/depmod.c,file2alias
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds  * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Usage: modpost vmlinux module1.o module2.o ...
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <ctype.h>
151da177e4SLinus Torvalds #include "modpost.h"
16b817f6feSSam Ravnborg #include "../../include/linux/license.h"
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
191da177e4SLinus Torvalds int modversions = 0;
201da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
211da177e4SLinus Torvalds int have_vmlinux = 0;
221da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
231da177e4SLinus Torvalds static int all_versions = 0;
24040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
25040fcc81SSam Ravnborg static int external_module = 0;
268d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
278d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
28c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
29c53ddacdSKirill Korotaev static int warn_unresolved = 0;
30bd5cbcedSRam Pai /* How a symbol is exported */
31c96fca21SSam Ravnborg enum export {
32c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
33c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
34c96fca21SSam Ravnborg };
351da177e4SLinus Torvalds 
366d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
376d9a89eaSAndi Kleen 
386d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
391da177e4SLinus Torvalds {
401da177e4SLinus Torvalds 	va_list arglist;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds 	va_start(arglist, fmt);
451da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
461da177e4SLinus Torvalds 	va_end(arglist);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	exit(1);
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds 
516d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
521da177e4SLinus Torvalds {
531da177e4SLinus Torvalds 	va_list arglist;
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 	va_start(arglist, fmt);
581da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
591da177e4SLinus Torvalds 	va_end(arglist);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds 
626d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
632a116659SMatthew Wilcox {
642a116659SMatthew Wilcox 	va_list arglist;
652a116659SMatthew Wilcox 
662a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
672a116659SMatthew Wilcox 
682a116659SMatthew Wilcox 	va_start(arglist, fmt);
692a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
702a116659SMatthew Wilcox 	va_end(arglist);
712a116659SMatthew Wilcox }
722a116659SMatthew Wilcox 
73040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
74040fcc81SSam Ravnborg {
75040fcc81SSam Ravnborg 	const char *myname;
76040fcc81SSam Ravnborg 
77df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
78df578e7dSSam Ravnborg 	if (myname)
79040fcc81SSam Ravnborg 		myname++;
80040fcc81SSam Ravnborg 	else
81040fcc81SSam Ravnborg 		myname = modname;
82040fcc81SSam Ravnborg 
83741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
84741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
85040fcc81SSam Ravnborg }
86040fcc81SSam Ravnborg 
871da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
881da177e4SLinus Torvalds {
89df578e7dSSam Ravnborg 	if (!ptr)
901da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
91df578e7dSSam Ravnborg 
921da177e4SLinus Torvalds 	return ptr;
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds /* A list of all modules we processed */
961da177e4SLinus Torvalds static struct module *modules;
971da177e4SLinus Torvalds 
985c3ead8cSSam Ravnborg static struct module *find_module(char *modname)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	struct module *mod;
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1031da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1041da177e4SLinus Torvalds 			break;
1051da177e4SLinus Torvalds 	return mod;
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds 
1085c3ead8cSSam Ravnborg static struct module *new_module(char *modname)
1091da177e4SLinus Torvalds {
1101da177e4SLinus Torvalds 	struct module *mod;
1111da177e4SLinus Torvalds 	char *p, *s;
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1141da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1151da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 	/* strip trailing .o */
118df578e7dSSam Ravnborg 	s = strrchr(p, '.');
119df578e7dSSam Ravnborg 	if (s != NULL)
1201da177e4SLinus Torvalds 		if (strcmp(s, ".o") == 0)
1211da177e4SLinus Torvalds 			*s = '\0';
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 	/* add to list */
1241da177e4SLinus Torvalds 	mod->name = p;
125b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1261da177e4SLinus Torvalds 	mod->next = modules;
1271da177e4SLinus Torvalds 	modules = mod;
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds 	return mod;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds /* A hash of all exported symbols,
1331da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds struct symbol {
1381da177e4SLinus Torvalds 	struct symbol *next;
1391da177e4SLinus Torvalds 	struct module *module;
1401da177e4SLinus Torvalds 	unsigned int crc;
1411da177e4SLinus Torvalds 	int crc_valid;
1421da177e4SLinus Torvalds 	unsigned int weak:1;
143040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
144040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
145040fcc81SSam Ravnborg 				    *  (only for external modules) **/
1468e70c458SSam Ravnborg 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers */
147bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1481da177e4SLinus Torvalds 	char name[0];
1491da177e4SLinus Torvalds };
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1541da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1571da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1601da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1611da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds 
1665c3ead8cSSam Ravnborg /**
1675c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1685c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1695c3ead8cSSam Ravnborg  **/
1705c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1715c3ead8cSSam Ravnborg 				   struct symbol *next)
1721da177e4SLinus Torvalds {
1731da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
1761da177e4SLinus Torvalds 	strcpy(s->name, name);
1771da177e4SLinus Torvalds 	s->weak = weak;
1781da177e4SLinus Torvalds 	s->next = next;
1791da177e4SLinus Torvalds 	return s;
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds /* For the hash of exported symbols */
183bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
184bd5cbcedSRam Pai 				 enum export export)
1851da177e4SLinus Torvalds {
1861da177e4SLinus Torvalds 	unsigned int hash;
1871da177e4SLinus Torvalds 	struct symbol *new;
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
1901da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
1911da177e4SLinus Torvalds 	new->module = module;
192bd5cbcedSRam Pai 	new->export = export;
193040fcc81SSam Ravnborg 	return new;
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
1965c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds 	struct symbol *s;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2011da177e4SLinus Torvalds 	if (name[0] == '.')
2021da177e4SLinus Torvalds 		name++;
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2051da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2061da177e4SLinus Torvalds 			return s;
2071da177e4SLinus Torvalds 	}
2081da177e4SLinus Torvalds 	return NULL;
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds 
211bd5cbcedSRam Pai static struct {
212bd5cbcedSRam Pai 	const char *str;
213bd5cbcedSRam Pai 	enum export export;
214bd5cbcedSRam Pai } export_list[] = {
215bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
216c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
217bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
218c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
219bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
220bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
221bd5cbcedSRam Pai };
222bd5cbcedSRam Pai 
223bd5cbcedSRam Pai 
224bd5cbcedSRam Pai static const char *export_str(enum export ex)
225bd5cbcedSRam Pai {
226bd5cbcedSRam Pai 	return export_list[ex].str;
227bd5cbcedSRam Pai }
228bd5cbcedSRam Pai 
229bd5cbcedSRam Pai static enum export export_no(const char *s)
230bd5cbcedSRam Pai {
231bd5cbcedSRam Pai 	int i;
232df578e7dSSam Ravnborg 
233534b89a9SSam Ravnborg 	if (!s)
234534b89a9SSam Ravnborg 		return export_unknown;
235bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
236bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
237bd5cbcedSRam Pai 			return export_list[i].export;
238bd5cbcedSRam Pai 	}
239bd5cbcedSRam Pai 	return export_unknown;
240bd5cbcedSRam Pai }
241bd5cbcedSRam Pai 
242bd5cbcedSRam Pai static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
243bd5cbcedSRam Pai {
244bd5cbcedSRam Pai 	if (sec == elf->export_sec)
245bd5cbcedSRam Pai 		return export_plain;
246c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
247c96fca21SSam Ravnborg 		return export_unused;
248bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
249bd5cbcedSRam Pai 		return export_gpl;
250c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
251c96fca21SSam Ravnborg 		return export_unused_gpl;
252bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
253bd5cbcedSRam Pai 		return export_gpl_future;
254bd5cbcedSRam Pai 	else
255bd5cbcedSRam Pai 		return export_unknown;
256bd5cbcedSRam Pai }
257bd5cbcedSRam Pai 
2585c3ead8cSSam Ravnborg /**
2595c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
2605c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
2615c3ead8cSSam Ravnborg  **/
262bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod,
263bd5cbcedSRam Pai 				       enum export export)
2641da177e4SLinus Torvalds {
2651da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	if (!s) {
268bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
2698e70c458SSam Ravnborg 	} else {
2708e70c458SSam Ravnborg 		if (!s->preloaded) {
2717b75b13cSSam Ravnborg 			warn("%s: '%s' exported twice. Previous export "
2728e70c458SSam Ravnborg 			     "was in %s%s\n", mod->name, name,
2738e70c458SSam Ravnborg 			     s->module->name,
2748e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ?"":".ko");
2754b21960fSTrent Piepho 		} else {
2764b21960fSTrent Piepho 			/* In case Modules.symvers was out of date */
2774b21960fSTrent Piepho 			s->module = mod;
2781da177e4SLinus Torvalds 		}
2791da177e4SLinus Torvalds 	}
2808e70c458SSam Ravnborg 	s->preloaded = 0;
281040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
282040fcc81SSam Ravnborg 	s->kernel    = 0;
283bd5cbcedSRam Pai 	s->export    = export;
284040fcc81SSam Ravnborg 	return s;
2851da177e4SLinus Torvalds }
2861da177e4SLinus Torvalds 
287040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
288bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
289040fcc81SSam Ravnborg {
290040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
291040fcc81SSam Ravnborg 
292040fcc81SSam Ravnborg 	if (!s)
293bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
294040fcc81SSam Ravnborg 	s->crc = crc;
2951da177e4SLinus Torvalds 	s->crc_valid = 1;
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds 
2985c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
2991da177e4SLinus Torvalds {
3001da177e4SLinus Torvalds 	struct stat st;
3011da177e4SLinus Torvalds 	void *map;
3021da177e4SLinus Torvalds 	int fd;
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
3051da177e4SLinus Torvalds 	if (fd < 0 || fstat(fd, &st) != 0)
3061da177e4SLinus Torvalds 		return NULL;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	*size = st.st_size;
3091da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
3101da177e4SLinus Torvalds 	close(fd);
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	if (map == MAP_FAILED)
3131da177e4SLinus Torvalds 		return NULL;
3141da177e4SLinus Torvalds 	return map;
3151da177e4SLinus Torvalds }
3161da177e4SLinus Torvalds 
3175c3ead8cSSam Ravnborg /**
3185c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
3195c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
3205c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
3215c3ead8cSSam Ravnborg   **/
3225c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
3231da177e4SLinus Torvalds {
3241da177e4SLinus Torvalds 	static char line[4096];
3251da177e4SLinus Torvalds 	int skip = 1;
3261da177e4SLinus Torvalds 	size_t len = 0;
3271da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
3281da177e4SLinus Torvalds 	char *s = line;
3291da177e4SLinus Torvalds 
330df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
3311da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
3321da177e4SLinus Torvalds 			p++;
3331da177e4SLinus Torvalds 			continue;
3341da177e4SLinus Torvalds 		}
3351da177e4SLinus Torvalds 		skip = 0;
3361da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
3371da177e4SLinus Torvalds 			len++;
3381da177e4SLinus Torvalds 			*s++ = *p++;
3391da177e4SLinus Torvalds 			if (len > 4095)
3401da177e4SLinus Torvalds 				break; /* Too long, stop */
3411da177e4SLinus Torvalds 		} else {
3421da177e4SLinus Torvalds 			/* End of string */
3431da177e4SLinus Torvalds 			*s = '\0';
3441da177e4SLinus Torvalds 			return line;
3451da177e4SLinus Torvalds 		}
3461da177e4SLinus Torvalds 	}
3471da177e4SLinus Torvalds 	/* End of buffer */
3481da177e4SLinus Torvalds 	return NULL;
3491da177e4SLinus Torvalds }
3501da177e4SLinus Torvalds 
3515c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
3521da177e4SLinus Torvalds {
3531da177e4SLinus Torvalds 	munmap(file, size);
3541da177e4SLinus Torvalds }
3551da177e4SLinus Torvalds 
35685bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
3571da177e4SLinus Torvalds {
3581da177e4SLinus Torvalds 	unsigned int i;
35985bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
3601da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
3611da177e4SLinus Torvalds 	Elf_Sym  *sym;
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
3641da177e4SLinus Torvalds 	if (!hdr) {
3651da177e4SLinus Torvalds 		perror(filename);
3666803dc0eSSam Ravnborg 		exit(1);
3671da177e4SLinus Torvalds 	}
3681da177e4SLinus Torvalds 	info->hdr = hdr;
36985bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
37085bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
37185bd2fddSSam Ravnborg 		return 0;
37285bd2fddSSam Ravnborg 	}
37385bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
37485bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
37585bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
37685bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
37785bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
37885bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
37985bd2fddSSam Ravnborg 		return 0;
38085bd2fddSSam Ravnborg 	}
3811da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
3821da177e4SLinus Torvalds 	hdr->e_shoff    = TO_NATIVE(hdr->e_shoff);
3831da177e4SLinus Torvalds 	hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
3841da177e4SLinus Torvalds 	hdr->e_shnum    = TO_NATIVE(hdr->e_shnum);
3851da177e4SLinus Torvalds 	hdr->e_machine  = TO_NATIVE(hdr->e_machine);
386ae4ac123SAtsushi Nemoto 	hdr->e_type     = TO_NATIVE(hdr->e_type);
3871da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
3881da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
3891da177e4SLinus Torvalds 
390a83710e5SPetr Stetiar 	/* Check if file offset is correct */
391a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
392df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
393df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
394df578e7dSSam Ravnborg 		      filename, info->size);
395a83710e5SPetr Stetiar 		return 0;
396a83710e5SPetr Stetiar 	}
397a83710e5SPetr Stetiar 
3981da177e4SLinus Torvalds 	/* Fix endianness in section headers */
3991da177e4SLinus Torvalds 	for (i = 0; i < hdr->e_shnum; i++) {
4001da177e4SLinus Torvalds 		sechdrs[i].sh_type   = TO_NATIVE(sechdrs[i].sh_type);
4011da177e4SLinus Torvalds 		sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
4021da177e4SLinus Torvalds 		sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
4031da177e4SLinus Torvalds 		sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
4041da177e4SLinus Torvalds 		sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
405ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info   = TO_NATIVE(sechdrs[i].sh_info);
406ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_addr   = TO_NATIVE(sechdrs[i].sh_addr);
4071da177e4SLinus Torvalds 	}
4081da177e4SLinus Torvalds 	/* Find symbol table. */
4091da177e4SLinus Torvalds 	for (i = 1; i < hdr->e_shnum; i++) {
4101da177e4SLinus Torvalds 		const char *secstrings
4111da177e4SLinus Torvalds 			= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
412bd5cbcedSRam Pai 		const char *secname;
4131da177e4SLinus Torvalds 
41485bd2fddSSam Ravnborg 		if (sechdrs[i].sh_offset > info->size) {
415df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
416df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
417df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
418df578e7dSSam Ravnborg 			      sizeof(*hdr));
41985bd2fddSSam Ravnborg 			return 0;
42085bd2fddSSam Ravnborg 		}
421bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
422bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
4231da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
4241da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
425bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
426bd5cbcedSRam Pai 			info->export_sec = i;
427c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
428c96fca21SSam Ravnborg 			info->export_unused_sec = i;
429bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
430bd5cbcedSRam Pai 			info->export_gpl_sec = i;
431c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
432c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
433bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
434bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
435bd5cbcedSRam Pai 
4361da177e4SLinus Torvalds 		if (sechdrs[i].sh_type != SHT_SYMTAB)
4371da177e4SLinus Torvalds 			continue;
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 		info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
4401da177e4SLinus Torvalds 		info->symtab_stop  = (void *)hdr + sechdrs[i].sh_offset
4411da177e4SLinus Torvalds 			                         + sechdrs[i].sh_size;
4421da177e4SLinus Torvalds 		info->strtab       = (void *)hdr +
4431da177e4SLinus Torvalds 			             sechdrs[sechdrs[i].sh_link].sh_offset;
4441da177e4SLinus Torvalds 	}
445df578e7dSSam Ravnborg 	if (!info->symtab_start)
446cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
447df578e7dSSam Ravnborg 
4481da177e4SLinus Torvalds 	/* Fix endianness in symbols */
4491da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
4501da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
4511da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
4521da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
4531da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
4541da177e4SLinus Torvalds 	}
45585bd2fddSSam Ravnborg 	return 1;
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
4585c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
4591da177e4SLinus Torvalds {
4601da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
4611da177e4SLinus Torvalds }
4621da177e4SLinus Torvalds 
463f7b05e64SLuke Yang #define CRC_PFX     MODULE_SYMBOL_PREFIX "__crc_"
464f7b05e64SLuke Yang #define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_"
4651da177e4SLinus Torvalds 
4665c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
4671da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
4681da177e4SLinus Torvalds {
4691da177e4SLinus Torvalds 	unsigned int crc;
470bd5cbcedSRam Pai 	enum export export = export_from_sec(info, sym->st_shndx);
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	switch (sym->st_shndx) {
4731da177e4SLinus Torvalds 	case SHN_COMMON:
474cb80514dSSam Ravnborg 		warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
4751da177e4SLinus Torvalds 		break;
4761da177e4SLinus Torvalds 	case SHN_ABS:
4771da177e4SLinus Torvalds 		/* CRC'd symbol */
4781da177e4SLinus Torvalds 		if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
4791da177e4SLinus Torvalds 			crc = (unsigned int) sym->st_value;
480bd5cbcedSRam Pai 			sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
481bd5cbcedSRam Pai 					export);
4821da177e4SLinus Torvalds 		}
4831da177e4SLinus Torvalds 		break;
4841da177e4SLinus Torvalds 	case SHN_UNDEF:
4851da177e4SLinus Torvalds 		/* undefined symbol */
4861da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
4871da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
4881da177e4SLinus Torvalds 			break;
4891da177e4SLinus Torvalds 		/* ignore global offset table */
4901da177e4SLinus Torvalds 		if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
4911da177e4SLinus Torvalds 			break;
4921da177e4SLinus Torvalds 		/* ignore __this_module, it will be resolved shortly */
4931da177e4SLinus Torvalds 		if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0)
4941da177e4SLinus Torvalds 			break;
4958d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
4968d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
4978d529014SBen Colline /* add compatibility with older glibc */
4988d529014SBen Colline #ifndef STT_SPARC_REGISTER
4998d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
5008d529014SBen Colline #endif
5011da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
5021da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
5031da177e4SLinus Torvalds 			/* Ignore register directives. */
5048d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
5051da177e4SLinus Torvalds 				break;
5067caaeabbSAl Viro 			if (symname[0] == '.') {
5077caaeabbSAl Viro 				char *munged = strdup(symname);
5087caaeabbSAl Viro 				munged[0] = '_';
5097caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
5107caaeabbSAl Viro 				symname = munged;
5117caaeabbSAl Viro 			}
5121da177e4SLinus Torvalds 		}
5131da177e4SLinus Torvalds #endif
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 		if (memcmp(symname, MODULE_SYMBOL_PREFIX,
516df578e7dSSam Ravnborg 			   strlen(MODULE_SYMBOL_PREFIX)) == 0) {
517df578e7dSSam Ravnborg 			mod->unres =
518df578e7dSSam Ravnborg 			  alloc_symbol(symname +
5191da177e4SLinus Torvalds 			               strlen(MODULE_SYMBOL_PREFIX),
5201da177e4SLinus Torvalds 			               ELF_ST_BIND(sym->st_info) == STB_WEAK,
5211da177e4SLinus Torvalds 			               mod->unres);
522df578e7dSSam Ravnborg 		}
5231da177e4SLinus Torvalds 		break;
5241da177e4SLinus Torvalds 	default:
5251da177e4SLinus Torvalds 		/* All exported symbols */
5261da177e4SLinus Torvalds 		if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
527bd5cbcedSRam Pai 			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
528bd5cbcedSRam Pai 					export);
5291da177e4SLinus Torvalds 		}
5301da177e4SLinus Torvalds 		if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
5311da177e4SLinus Torvalds 			mod->has_init = 1;
5321da177e4SLinus Torvalds 		if (strcmp(symname, MODULE_SYMBOL_PREFIX "cleanup_module") == 0)
5331da177e4SLinus Torvalds 			mod->has_cleanup = 1;
5341da177e4SLinus Torvalds 		break;
5351da177e4SLinus Torvalds 	}
5361da177e4SLinus Torvalds }
5371da177e4SLinus Torvalds 
5385c3ead8cSSam Ravnborg /**
5395c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
5405c3ead8cSSam Ravnborg  **/
5411da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
5421da177e4SLinus Torvalds {
5431da177e4SLinus Torvalds 	/* Skip non-zero chars */
5441da177e4SLinus Torvalds 	while (string[0]) {
5451da177e4SLinus Torvalds 		string++;
5461da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
5471da177e4SLinus Torvalds 			return NULL;
5481da177e4SLinus Torvalds 	}
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	/* Skip any zero padding. */
5511da177e4SLinus Torvalds 	while (!string[0]) {
5521da177e4SLinus Torvalds 		string++;
5531da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
5541da177e4SLinus Torvalds 			return NULL;
5551da177e4SLinus Torvalds 	}
5561da177e4SLinus Torvalds 	return string;
5571da177e4SLinus Torvalds }
5581da177e4SLinus Torvalds 
559b817f6feSSam Ravnborg static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
560b817f6feSSam Ravnborg 			      const char *tag, char *info)
5611da177e4SLinus Torvalds {
5621da177e4SLinus Torvalds 	char *p;
5631da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
5641da177e4SLinus Torvalds 	unsigned long size = modinfo_len;
5651da177e4SLinus Torvalds 
566b817f6feSSam Ravnborg 	if (info) {
567b817f6feSSam Ravnborg 		size -= info - (char *)modinfo;
568b817f6feSSam Ravnborg 		modinfo = next_string(info, &size);
569b817f6feSSam Ravnborg 	}
570b817f6feSSam Ravnborg 
5711da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
5721da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
5731da177e4SLinus Torvalds 			return p + taglen + 1;
5741da177e4SLinus Torvalds 	}
5751da177e4SLinus Torvalds 	return NULL;
5761da177e4SLinus Torvalds }
5771da177e4SLinus Torvalds 
578b817f6feSSam Ravnborg static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
579b817f6feSSam Ravnborg 			 const char *tag)
580b817f6feSSam Ravnborg 
581b817f6feSSam Ravnborg {
582b817f6feSSam Ravnborg 	return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
583b817f6feSSam Ravnborg }
584b817f6feSSam Ravnborg 
58593684d3bSSam Ravnborg /**
5864c8fbca5SSam Ravnborg  * Test if string s ends in string sub
5874c8fbca5SSam Ravnborg  * return 0 if match
5884c8fbca5SSam Ravnborg  **/
5894c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
5904c8fbca5SSam Ravnborg {
5914c8fbca5SSam Ravnborg 	int slen, sublen;
5924c8fbca5SSam Ravnborg 
5934c8fbca5SSam Ravnborg 	if (!s || !sub)
5944c8fbca5SSam Ravnborg 		return 1;
5954c8fbca5SSam Ravnborg 
5964c8fbca5SSam Ravnborg 	slen = strlen(s);
5974c8fbca5SSam Ravnborg 	sublen = strlen(sub);
5984c8fbca5SSam Ravnborg 
5994c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
6004c8fbca5SSam Ravnborg 		return 1;
6014c8fbca5SSam Ravnborg 
6024c8fbca5SSam Ravnborg 	if (sublen > slen)
6034c8fbca5SSam Ravnborg 		return 1;
6044c8fbca5SSam Ravnborg 
6054c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
6064c8fbca5SSam Ravnborg }
6074c8fbca5SSam Ravnborg 
608ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
609ff13f926SSam Ravnborg {
61058fb0d4fSSam Ravnborg 	if (sym)
611ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
61258fb0d4fSSam Ravnborg 	else
61358fb0d4fSSam Ravnborg 		return "";
614ff13f926SSam Ravnborg }
615ff13f926SSam Ravnborg 
616ff13f926SSam Ravnborg static const char *sec_name(struct elf_info *elf, int shndx)
617ff13f926SSam Ravnborg {
618ff13f926SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
619ff13f926SSam Ravnborg 	return (void *)elf->hdr +
620ff13f926SSam Ravnborg 	        elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
621ff13f926SSam Ravnborg 	        sechdrs[shndx].sh_name;
622ff13f926SSam Ravnborg }
623ff13f926SSam Ravnborg 
624ff13f926SSam Ravnborg static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
625ff13f926SSam Ravnborg {
626ff13f926SSam Ravnborg 	return (void *)elf->hdr +
627ff13f926SSam Ravnborg 	        elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
628ff13f926SSam Ravnborg 	        sechdr->sh_name;
629ff13f926SSam Ravnborg }
630ff13f926SSam Ravnborg 
63110668220SSam Ravnborg /* if sym is empty or point to a string
63210668220SSam Ravnborg  * like ".[0-9]+" then return 1.
63310668220SSam Ravnborg  * This is the optional prefix added by ld to some sections
63410668220SSam Ravnborg  */
63510668220SSam Ravnborg static int number_prefix(const char *sym)
63610668220SSam Ravnborg {
63710668220SSam Ravnborg 	if (*sym++ == '\0')
63810668220SSam Ravnborg 		return 1;
63910668220SSam Ravnborg 	if (*sym != '.')
64010668220SSam Ravnborg 		return 0;
64110668220SSam Ravnborg 	do {
64210668220SSam Ravnborg 		char c = *sym++;
64310668220SSam Ravnborg 		if (c < '0' || c > '9')
64410668220SSam Ravnborg 			return 0;
64510668220SSam Ravnborg 	} while (*sym);
64610668220SSam Ravnborg 	return 1;
64710668220SSam Ravnborg }
64810668220SSam Ravnborg 
64910668220SSam Ravnborg /* The pattern is an array of simple patterns.
65010668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
6516c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
65210668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
65310668220SSam Ravnborg  * "foo$" will match a string equal to "foo" or "foo.1"
65410668220SSam Ravnborg  *   where the '1' can be any number including several digits.
65510668220SSam Ravnborg  *   The $ syntax is for sections where ld append a dot number
65610668220SSam Ravnborg  *   to make section name unique.
65710668220SSam Ravnborg  */
65810668220SSam Ravnborg int match(const char *sym, const char * const pat[])
65910668220SSam Ravnborg {
66010668220SSam Ravnborg 	const char *p;
66110668220SSam Ravnborg 	while (*pat) {
66210668220SSam Ravnborg 		p = *pat++;
66310668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
66410668220SSam Ravnborg 
6656c5bd235SSam Ravnborg 		/* "*foo" */
6666c5bd235SSam Ravnborg 		if (*p == '*') {
6676c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
6686c5bd235SSam Ravnborg 				return 1;
6696c5bd235SSam Ravnborg 		}
67010668220SSam Ravnborg 		/* "foo*" */
6716c5bd235SSam Ravnborg 		else if (*endp == '*') {
67210668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
67310668220SSam Ravnborg 				return 1;
67410668220SSam Ravnborg 		}
67510668220SSam Ravnborg 		/* "foo$" */
67610668220SSam Ravnborg 		else if (*endp == '$') {
67710668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0) {
67810668220SSam Ravnborg 				if (number_prefix(sym + strlen(p) - 1))
67910668220SSam Ravnborg 					return 1;
68010668220SSam Ravnborg 			}
68110668220SSam Ravnborg 		}
68210668220SSam Ravnborg 		/* no wildcards */
68310668220SSam Ravnborg 		else {
68410668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
68510668220SSam Ravnborg 				return 1;
68610668220SSam Ravnborg 		}
68710668220SSam Ravnborg 	}
68810668220SSam Ravnborg 	/* no match */
68910668220SSam Ravnborg 	return 0;
69010668220SSam Ravnborg }
69110668220SSam Ravnborg 
69210668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
69310668220SSam Ravnborg static const char *section_white_list[] =
69410668220SSam Ravnborg 	{ ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL };
69510668220SSam Ravnborg 
696eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
697eb8f6890SSam Ravnborg 	".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$"
698eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
699eb8f6890SSam Ravnborg 	".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$"
70010668220SSam Ravnborg 
701eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
702eb8f6890SSam Ravnborg 	".init.text$", ".devinit.text$", ".cpuinit.text$", ".meminit.text$"
703eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
704eb8f6890SSam Ravnborg 	".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$"
70510668220SSam Ravnborg 
706eb8f6890SSam Ravnborg #define ALL_INIT_SECTIONS ALL_INIT_DATA_SECTIONS, ALL_INIT_TEXT_SECTIONS
707eb8f6890SSam Ravnborg #define ALL_EXIT_SECTIONS ALL_EXIT_DATA_SECTIONS, ALL_EXIT_TEXT_SECTIONS
70810668220SSam Ravnborg 
7096c5bd235SSam Ravnborg #define DATA_SECTIONS ".data$", ".data.rel$"
71010668220SSam Ravnborg #define TEXT_SECTIONS ".text$"
71110668220SSam Ravnborg 
712eb8f6890SSam Ravnborg #define INIT_SECTIONS      ".init.data$", ".init.text$"
713eb8f6890SSam Ravnborg #define DEV_INIT_SECTIONS  ".devinit.data$", ".devinit.text$"
714eb8f6890SSam Ravnborg #define CPU_INIT_SECTIONS  ".cpuinit.data$", ".cpuinit.text$"
715eb8f6890SSam Ravnborg #define MEM_INIT_SECTIONS  ".meminit.data$", ".meminit.text$"
716eb8f6890SSam Ravnborg 
717eb8f6890SSam Ravnborg #define EXIT_SECTIONS      ".exit.data$", ".exit.text$"
718eb8f6890SSam Ravnborg #define DEV_EXIT_SECTIONS  ".devexit.data$", ".devexit.text$"
719eb8f6890SSam Ravnborg #define CPU_EXIT_SECTIONS  ".cpuexit.data$", ".cpuexit.text$"
720eb8f6890SSam Ravnborg #define MEM_EXIT_SECTIONS  ".memexit.data$", ".memexit.text$"
721eb8f6890SSam Ravnborg 
7226c5bd235SSam Ravnborg /* init data sections */
723eb8f6890SSam Ravnborg static const char *init_data_sections[] = { ALL_INIT_DATA_SECTIONS, NULL };
7246c5bd235SSam Ravnborg 
7256c5bd235SSam Ravnborg /* all init sections */
726eb8f6890SSam Ravnborg static const char *init_sections[] = { ALL_INIT_SECTIONS, NULL };
7276c5bd235SSam Ravnborg 
7286c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
7296c5bd235SSam Ravnborg static const char *init_exit_sections[] =
730eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
7316c5bd235SSam Ravnborg 
7326c5bd235SSam Ravnborg /* data section */
7336c5bd235SSam Ravnborg static const char *data_sections[] = { DATA_SECTIONS, NULL };
7346c5bd235SSam Ravnborg 
7356c5bd235SSam Ravnborg /* sections that may refer to an init/exit section with no warning */
7366c5bd235SSam Ravnborg static const char *initref_sections[] =
7376c5bd235SSam Ravnborg {
7386c5bd235SSam Ravnborg 	".text.init.refok*",
7396c5bd235SSam Ravnborg 	".exit.text.refok*",
7406c5bd235SSam Ravnborg 	".data.init.refok*",
7416c5bd235SSam Ravnborg 	NULL
7426c5bd235SSam Ravnborg };
7436c5bd235SSam Ravnborg 
7446c5bd235SSam Ravnborg 
7456c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
7466c5bd235SSam Ravnborg static const char *symbol_white_list[] =
7476c5bd235SSam Ravnborg {
7486c5bd235SSam Ravnborg 	"*driver",
7496c5bd235SSam Ravnborg 	"*_template", /* scsi uses *_template a lot */
7506c5bd235SSam Ravnborg 	"*_timer",    /* arm uses ops structures named _timer a lot */
7516c5bd235SSam Ravnborg 	"*_sht",      /* scsi also used *_sht to some extent */
7526c5bd235SSam Ravnborg 	"*_ops",
7536c5bd235SSam Ravnborg 	"*_probe",
7546c5bd235SSam Ravnborg 	"*_probe_one",
7556c5bd235SSam Ravnborg 	"*_console",
7566c5bd235SSam Ravnborg 	NULL
7576c5bd235SSam Ravnborg };
7586c5bd235SSam Ravnborg 
7596c5bd235SSam Ravnborg static const char *head_sections[] = { ".head.text*", NULL };
7606c5bd235SSam Ravnborg static const char *linker_symbols[] =
7616c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
7626c5bd235SSam Ravnborg 
76310668220SSam Ravnborg struct sectioncheck {
76410668220SSam Ravnborg 	const char *fromsec[20];
76510668220SSam Ravnborg 	const char *tosec[20];
76610668220SSam Ravnborg };
76710668220SSam Ravnborg 
76810668220SSam Ravnborg const struct sectioncheck sectioncheck[] = {
76910668220SSam Ravnborg /* Do not reference init/exit code/data from
77010668220SSam Ravnborg  * normal code and data
77110668220SSam Ravnborg  */
77210668220SSam Ravnborg {
77310668220SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, DATA_SECTIONS, NULL },
774eb8f6890SSam Ravnborg 	.tosec   = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }
775eb8f6890SSam Ravnborg },
776eb8f6890SSam Ravnborg /* Do not reference init code/data from devinit/cpuinit/meminit code/data */
777eb8f6890SSam Ravnborg {
778eb8f6890SSam Ravnborg 	.fromsec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS, NULL },
779eb8f6890SSam Ravnborg 	.tosec   = { INIT_SECTIONS, NULL }
780eb8f6890SSam Ravnborg },
781eb8f6890SSam Ravnborg /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */
782eb8f6890SSam Ravnborg {
783eb8f6890SSam Ravnborg 	.fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL },
784eb8f6890SSam Ravnborg 	.tosec   = { EXIT_SECTIONS, NULL }
78510668220SSam Ravnborg },
78610668220SSam Ravnborg /* Do not use exit code/data from init code */
78710668220SSam Ravnborg {
788eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
789eb8f6890SSam Ravnborg 	.tosec   = { ALL_EXIT_SECTIONS, NULL },
79010668220SSam Ravnborg },
79110668220SSam Ravnborg /* Do not use init code/data from exit code */
79210668220SSam Ravnborg {
793eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
794eb8f6890SSam Ravnborg 	.tosec   = { ALL_INIT_SECTIONS, NULL }
79510668220SSam Ravnborg },
79610668220SSam Ravnborg /* Do not export init/exit functions or data */
79710668220SSam Ravnborg {
79810668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
799eb8f6890SSam Ravnborg 	.tosec   = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }
80010668220SSam Ravnborg }
80110668220SSam Ravnborg };
80210668220SSam Ravnborg 
80310668220SSam Ravnborg static int section_mismatch(const char *fromsec, const char *tosec)
80410668220SSam Ravnborg {
80510668220SSam Ravnborg 	int i;
80610668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
80710668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
80810668220SSam Ravnborg 
80910668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
81010668220SSam Ravnborg 		if (match(fromsec, check->fromsec) &&
81110668220SSam Ravnborg 		    match(tosec, check->tosec))
81210668220SSam Ravnborg 			return 1;
81310668220SSam Ravnborg 		check++;
81410668220SSam Ravnborg 	}
81510668220SSam Ravnborg 	return 0;
81610668220SSam Ravnborg }
81710668220SSam Ravnborg 
8184c8fbca5SSam Ravnborg /**
8194c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
8200e0d314eSSam Ravnborg  *
8210e0d314eSSam Ravnborg  * Pattern 0:
8220e0d314eSSam Ravnborg  *   Do not warn if funtion/data are marked with __init_refok/__initdata_refok.
8230e0d314eSSam Ravnborg  *   The pattern is identified by:
824cb7e51d8SSam Ravnborg  *   fromsec = .text.init.refok* | .data.init.refok*
8250e0d314eSSam Ravnborg  *
8264c8fbca5SSam Ravnborg  * Pattern 1:
8274c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
8284c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
8294c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
8304c8fbca5SSam Ravnborg  *   this pattern.
8314c8fbca5SSam Ravnborg  *   The pattern is identified by:
8324c8fbca5SSam Ravnborg  *   tosec   = .init.data
8339209aed0SSam Ravnborg  *   fromsec = .data*
8344c8fbca5SSam Ravnborg  *   atsym   =__param*
8354c8fbca5SSam Ravnborg  *
8364c8fbca5SSam Ravnborg  * Pattern 2:
83772ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
8384c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
8394c8fbca5SSam Ravnborg  *   These functions may often be marked __init and we do not want to
8404c8fbca5SSam Ravnborg  *   warn here.
8414c8fbca5SSam Ravnborg  *   the pattern is identified by:
84283cda2bbSSam Ravnborg  *   tosec   = init or exit section
84383cda2bbSSam Ravnborg  *   fromsec = data section
844df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
845df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
846ee6a8545SVivek Goyal  *
847ee6a8545SVivek Goyal  * Pattern 3:
8489bf8cb9bSSam Ravnborg  *   Whitelist all refereces from .text.head to .init.data
8499bf8cb9bSSam Ravnborg  *   Whitelist all refereces from .text.head to .init.text
8509bf8cb9bSSam Ravnborg  *
8511d8af559SSam Ravnborg  * Pattern 4:
852ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
853ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
854ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
855ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
856ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
857ee6a8545SVivek Goyal  *   This pattern is identified by
858ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
8599bf8cb9bSSam Ravnborg  *
8604c8fbca5SSam Ravnborg  **/
86158fb0d4fSSam Ravnborg static int secref_whitelist(const char *fromsec, const char *fromsym,
86258fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
8634c8fbca5SSam Ravnborg {
8640e0d314eSSam Ravnborg 	/* Check for pattern 0 */
8656c5bd235SSam Ravnborg 	if (match(fromsec, initref_sections))
86658fb0d4fSSam Ravnborg 		return 0;
8670e0d314eSSam Ravnborg 
8684c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
8696c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
8706c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
87158fb0d4fSSam Ravnborg 	    (strncmp(fromsym, "__param", strlen("__param")) == 0))
87258fb0d4fSSam Ravnborg 		return 0;
8734c8fbca5SSam Ravnborg 
8744c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
8756c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
8766c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
87758fb0d4fSSam Ravnborg 	    match(fromsym, symbol_white_list))
87858fb0d4fSSam Ravnborg 		return 0;
8794c8fbca5SSam Ravnborg 
8809bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
8816c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
8826c5bd235SSam Ravnborg 	    match(tosec, init_sections))
88358fb0d4fSSam Ravnborg 		return 0;
884f8657e1bSVivek Goyal 
8851d8af559SSam Ravnborg 	/* Check for pattern 4 */
88658fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
88793659af1SSam Ravnborg 		return 0;
88858fb0d4fSSam Ravnborg 
88958fb0d4fSSam Ravnborg 	return 1;
8904c8fbca5SSam Ravnborg }
8914c8fbca5SSam Ravnborg 
8924c8fbca5SSam Ravnborg /**
89393684d3bSSam Ravnborg  * Find symbol based on relocation record info.
89493684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
89593684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
89693684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
89793684d3bSSam Ravnborg  * based on section and address.
89893684d3bSSam Ravnborg  *  **/
8999ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
90093684d3bSSam Ravnborg 				Elf_Sym *relsym)
90193684d3bSSam Ravnborg {
90293684d3bSSam Ravnborg 	Elf_Sym *sym;
9039ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
9049ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
9059ad21c3fSSam Ravnborg 	Elf64_Sword d;
90693684d3bSSam Ravnborg 
90793684d3bSSam Ravnborg 	if (relsym->st_name != 0)
90893684d3bSSam Ravnborg 		return relsym;
90993684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
91093684d3bSSam Ravnborg 		if (sym->st_shndx != relsym->st_shndx)
91193684d3bSSam Ravnborg 			continue;
912ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
913ae4ac123SAtsushi Nemoto 			continue;
91493684d3bSSam Ravnborg 		if (sym->st_value == addr)
91593684d3bSSam Ravnborg 			return sym;
9169ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
9179ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
9189ad21c3fSSam Ravnborg 		if (d < 0)
9199ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
9209ad21c3fSSam Ravnborg 		if (d < distance) {
9219ad21c3fSSam Ravnborg 			distance = d;
9229ad21c3fSSam Ravnborg 			near = sym;
92393684d3bSSam Ravnborg 		}
9249ad21c3fSSam Ravnborg 	}
9259ad21c3fSSam Ravnborg 	/* We need a close match */
9269ad21c3fSSam Ravnborg 	if (distance < 20)
9279ad21c3fSSam Ravnborg 		return near;
9289ad21c3fSSam Ravnborg 	else
92993684d3bSSam Ravnborg 		return NULL;
93093684d3bSSam Ravnborg }
93193684d3bSSam Ravnborg 
932da68d61fSDavid Brownell static inline int is_arm_mapping_symbol(const char *str)
933da68d61fSDavid Brownell {
934da68d61fSDavid Brownell 	return str[0] == '$' && strchr("atd", str[1])
935da68d61fSDavid Brownell 	       && (str[2] == '\0' || str[2] == '.');
936da68d61fSDavid Brownell }
937da68d61fSDavid Brownell 
938da68d61fSDavid Brownell /*
939da68d61fSDavid Brownell  * If there's no name there, ignore it; likewise, ignore it if it's
940da68d61fSDavid Brownell  * one of the magic symbols emitted used by current ARM tools.
941da68d61fSDavid Brownell  *
942da68d61fSDavid Brownell  * Otherwise if find_symbols_between() returns those symbols, they'll
943da68d61fSDavid Brownell  * fail the whitelist tests and cause lots of false alarms ... fixable
944da68d61fSDavid Brownell  * only by merging __exit and __init sections into __text, bloating
945da68d61fSDavid Brownell  * the kernel (which is especially evil on embedded platforms).
946da68d61fSDavid Brownell  */
947da68d61fSDavid Brownell static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
948da68d61fSDavid Brownell {
949da68d61fSDavid Brownell 	const char *name = elf->strtab + sym->st_name;
950da68d61fSDavid Brownell 
951da68d61fSDavid Brownell 	if (!name || !strlen(name))
952da68d61fSDavid Brownell 		return 0;
953da68d61fSDavid Brownell 	return !is_arm_mapping_symbol(name);
954da68d61fSDavid Brownell }
955da68d61fSDavid Brownell 
956b39927cfSSam Ravnborg /*
95743c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
95843c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
95943c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
96043c74d17SSam Ravnborg  * it is, but this works for now.
961b39927cfSSam Ravnborg  **/
962157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
963157c23c8SSam Ravnborg 				 const char *sec)
964b39927cfSSam Ravnborg {
965b39927cfSSam Ravnborg 	Elf_Sym *sym;
966157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
967157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
968b39927cfSSam Ravnborg 
969b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
970b39927cfSSam Ravnborg 		const char *symsec;
971b39927cfSSam Ravnborg 
972b39927cfSSam Ravnborg 		if (sym->st_shndx >= SHN_LORESERVE)
973b39927cfSSam Ravnborg 			continue;
974ff13f926SSam Ravnborg 		symsec = sec_name(elf, sym->st_shndx);
975b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
976b39927cfSSam Ravnborg 			continue;
977da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
978da68d61fSDavid Brownell 			continue;
979b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
980157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
981157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
982157c23c8SSam Ravnborg 				near = sym;
983157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
984157c23c8SSam Ravnborg 				near = sym;
98543c74d17SSam Ravnborg 			}
986b39927cfSSam Ravnborg 		}
987b39927cfSSam Ravnborg 	}
988157c23c8SSam Ravnborg 	return near;
989157c23c8SSam Ravnborg }
990b39927cfSSam Ravnborg 
99158fb0d4fSSam Ravnborg /*
992b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
993b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
9944c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
99558fb0d4fSSam Ravnborg  */
99658fb0d4fSSam Ravnborg static void report_sec_mismatch(const char *modname,
99758fb0d4fSSam Ravnborg                                 const char *fromsec,
99858fb0d4fSSam Ravnborg                                 unsigned long long fromaddr,
99958fb0d4fSSam Ravnborg                                 const char *fromsym,
100058fb0d4fSSam Ravnborg                                 const char *tosec, const char *tosym)
1001b39927cfSSam Ravnborg {
100258fb0d4fSSam Ravnborg 	if (strlen(tosym)) {
100325601209SRussell King 		warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
1004157c23c8SSam Ravnborg 		     "in '%s'\n",
100558fb0d4fSSam Ravnborg 		     modname, fromsec, fromaddr,
100658fb0d4fSSam Ravnborg 		     tosec, tosym, fromsym);
1007b39927cfSSam Ravnborg 	} else {
100825601209SRussell King 		warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s\n",
100958fb0d4fSSam Ravnborg 		     modname, fromsec, fromaddr,
101058fb0d4fSSam Ravnborg 		     tosec, tosym);
101158fb0d4fSSam Ravnborg 	}
101258fb0d4fSSam Ravnborg }
101358fb0d4fSSam Ravnborg 
101458fb0d4fSSam Ravnborg static void check_section_mismatch(const char *modname, struct elf_info *elf,
101558fb0d4fSSam Ravnborg                                    Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
101658fb0d4fSSam Ravnborg {
101758fb0d4fSSam Ravnborg 	const char *tosec;
101858fb0d4fSSam Ravnborg 
101958fb0d4fSSam Ravnborg 	tosec = sec_name(elf, sym->st_shndx);
102058fb0d4fSSam Ravnborg 	if (section_mismatch(fromsec, tosec)) {
102158fb0d4fSSam Ravnborg 		const char *fromsym;
102258fb0d4fSSam Ravnborg 		const char *tosym;
102358fb0d4fSSam Ravnborg 
102458fb0d4fSSam Ravnborg 		fromsym = sym_name(elf,
102558fb0d4fSSam Ravnborg 		          find_elf_symbol2(elf, r->r_offset, fromsec));
102658fb0d4fSSam Ravnborg 		tosym = sym_name(elf,
102758fb0d4fSSam Ravnborg 		        find_elf_symbol(elf, r->r_addend, sym));
102858fb0d4fSSam Ravnborg 
102958fb0d4fSSam Ravnborg 		/* check whitelist - we may ignore it */
103058fb0d4fSSam Ravnborg 		if (secref_whitelist(fromsec, fromsym, tosec, tosym)) {
103158fb0d4fSSam Ravnborg 			report_sec_mismatch(modname, fromsec, r->r_offset,
103258fb0d4fSSam Ravnborg 			                    fromsym, tosec, tosym);
103358fb0d4fSSam Ravnborg 		}
1034b39927cfSSam Ravnborg 	}
1035b39927cfSSam Ravnborg }
1036b39927cfSSam Ravnborg 
1037ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
10385b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1039ae4ac123SAtsushi Nemoto {
1040ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
10415b24c071SSam Ravnborg 	int section = sechdr->sh_info;
1042ae4ac123SAtsushi Nemoto 
1043ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1044ae4ac123SAtsushi Nemoto 		(r->r_offset - sechdrs[section].sh_addr);
1045ae4ac123SAtsushi Nemoto }
1046ae4ac123SAtsushi Nemoto 
10475b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1048ae4ac123SAtsushi Nemoto {
1049ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
10505b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1051ae4ac123SAtsushi Nemoto 
1052ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1053ae4ac123SAtsushi Nemoto 	case R_386_32:
1054ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1055ae4ac123SAtsushi Nemoto 		break;
1056ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1057ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1058ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1059ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1060ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1061ae4ac123SAtsushi Nemoto 		break;
1062ae4ac123SAtsushi Nemoto 	}
1063ae4ac123SAtsushi Nemoto 	return 0;
1064ae4ac123SAtsushi Nemoto }
1065ae4ac123SAtsushi Nemoto 
10665b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
106756a974faSSam Ravnborg {
106856a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
106956a974faSSam Ravnborg 
107056a974faSSam Ravnborg 	switch (r_typ) {
107156a974faSSam Ravnborg 	case R_ARM_ABS32:
107256a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1073df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1074df578e7dSSam Ravnborg 		              (elf->symtab_start + ELF_R_SYM(r->r_info));
107556a974faSSam Ravnborg 		break;
107656a974faSSam Ravnborg 	case R_ARM_PC24:
107756a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1078df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
10795b24c071SSam Ravnborg 		              sechdr->sh_offset +
10805b24c071SSam Ravnborg 		              (r->r_offset - sechdr->sh_addr));
108156a974faSSam Ravnborg 		break;
108256a974faSSam Ravnborg 	default:
108356a974faSSam Ravnborg 		return 1;
108456a974faSSam Ravnborg 	}
108556a974faSSam Ravnborg 	return 0;
108656a974faSSam Ravnborg }
108756a974faSSam Ravnborg 
10885b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1089ae4ac123SAtsushi Nemoto {
1090ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
10915b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1092ae4ac123SAtsushi Nemoto 	unsigned int inst;
1093ae4ac123SAtsushi Nemoto 
1094ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1095ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1096ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1097ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1098ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1099ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1100ae4ac123SAtsushi Nemoto 		break;
1101ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1102ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1103ae4ac123SAtsushi Nemoto 		break;
1104ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1105ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1106ae4ac123SAtsushi Nemoto 		break;
1107ae4ac123SAtsushi Nemoto 	}
1108ae4ac123SAtsushi Nemoto 	return 0;
1109ae4ac123SAtsushi Nemoto }
1110ae4ac123SAtsushi Nemoto 
11115b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
111210668220SSam Ravnborg                          Elf_Shdr *sechdr)
1113b39927cfSSam Ravnborg {
1114b39927cfSSam Ravnborg 	Elf_Sym  *sym;
11155b24c071SSam Ravnborg 	Elf_Rela *rela;
11162c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1117eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
11185b24c071SSam Ravnborg 	const char *fromsec;
11195b24c071SSam Ravnborg 
1120ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
11215b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
11225b24c071SSam Ravnborg 
1123ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
11245b24c071SSam Ravnborg 	fromsec += strlen(".rela");
11255b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
112610668220SSam Ravnborg 	if (match(fromsec, section_white_list))
11275b24c071SSam Ravnborg 		return;
1128b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1129b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1130eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1131ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1132ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1133eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1134eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1135ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1136ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1137eae07ac6SAtsushi Nemoto 		} else {
1138601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1139eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1140eae07ac6SAtsushi Nemoto 		}
1141eae07ac6SAtsushi Nemoto #else
1142eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1143eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1144eae07ac6SAtsushi Nemoto #endif
114593684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1146eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1147b39927cfSSam Ravnborg 		/* Skip special sections */
1148b39927cfSSam Ravnborg 		if (sym->st_shndx >= SHN_LORESERVE)
1149b39927cfSSam Ravnborg 			continue;
115058fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
11512c1a51f3SAtsushi Nemoto 	}
11525b24c071SSam Ravnborg }
11535b24c071SSam Ravnborg 
11545b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
115510668220SSam Ravnborg                         Elf_Shdr *sechdr)
11565b24c071SSam Ravnborg {
11575b24c071SSam Ravnborg 	Elf_Sym *sym;
11582c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
11595b24c071SSam Ravnborg 	Elf_Rela r;
11605b24c071SSam Ravnborg 	unsigned int r_sym;
11615b24c071SSam Ravnborg 	const char *fromsec;
11625b24c071SSam Ravnborg 
1163ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
11645b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
11655b24c071SSam Ravnborg 
1166ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
11675b24c071SSam Ravnborg 	fromsec += strlen(".rel");
11685b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
116910668220SSam Ravnborg 	if (match(fromsec, section_white_list))
11705b24c071SSam Ravnborg 		return;
11712c1a51f3SAtsushi Nemoto 
11722c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
11732c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1174eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1175ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1176ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1177eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1178eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1179ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1180ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1181eae07ac6SAtsushi Nemoto 		} else {
11822c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1183eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1184eae07ac6SAtsushi Nemoto 		}
1185eae07ac6SAtsushi Nemoto #else
1186eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1187eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1188eae07ac6SAtsushi Nemoto #endif
11892c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1190ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1191ae4ac123SAtsushi Nemoto 		case EM_386:
11925b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1193ae4ac123SAtsushi Nemoto 				continue;
1194ae4ac123SAtsushi Nemoto 			break;
119556a974faSSam Ravnborg 		case EM_ARM:
11965b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
119756a974faSSam Ravnborg 				continue;
119856a974faSSam Ravnborg 			break;
1199ae4ac123SAtsushi Nemoto 		case EM_MIPS:
12005b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1201ae4ac123SAtsushi Nemoto 				continue;
1202ae4ac123SAtsushi Nemoto 			break;
1203ae4ac123SAtsushi Nemoto 		}
1204eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
12052c1a51f3SAtsushi Nemoto 		/* Skip special sections */
12062c1a51f3SAtsushi Nemoto 		if (sym->st_shndx >= SHN_LORESERVE)
12072c1a51f3SAtsushi Nemoto 			continue;
120858fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
12092c1a51f3SAtsushi Nemoto 	}
1210b39927cfSSam Ravnborg }
12115b24c071SSam Ravnborg 
12125b24c071SSam Ravnborg /**
12135b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
12145b24c071SSam Ravnborg  * either when loaded or when used as built-in.
12155b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
12165b24c071SSam Ravnborg  * marked __initdata will be discarded when the module has been intialized.
12175b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
12185b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
12195b24c071SSam Ravnborg  * only when a moduel is unloaded which never happes for built-in modules.
12205b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
12215b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
12225b24c071SSam Ravnborg  * be discarded and warns about it.
12235b24c071SSam Ravnborg  **/
12245b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
122510668220SSam Ravnborg                           struct elf_info *elf)
12265b24c071SSam Ravnborg {
12275b24c071SSam Ravnborg 	int i;
12285b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
12295b24c071SSam Ravnborg 
12305b24c071SSam Ravnborg 	/* Walk through all sections */
1231ff13f926SSam Ravnborg 	for (i = 0; i < elf->hdr->e_shnum; i++) {
12325b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
12335b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
123410668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
12355b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
123610668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1237b39927cfSSam Ravnborg 	}
1238b39927cfSSam Ravnborg }
1239b39927cfSSam Ravnborg 
12405c3ead8cSSam Ravnborg static void read_symbols(char *modname)
12411da177e4SLinus Torvalds {
12421da177e4SLinus Torvalds 	const char *symname;
12431da177e4SLinus Torvalds 	char *version;
1244b817f6feSSam Ravnborg 	char *license;
12451da177e4SLinus Torvalds 	struct module *mod;
12461da177e4SLinus Torvalds 	struct elf_info info = { };
12471da177e4SLinus Torvalds 	Elf_Sym *sym;
12481da177e4SLinus Torvalds 
124985bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
125085bd2fddSSam Ravnborg 		return;
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 	mod = new_module(modname);
12531da177e4SLinus Torvalds 
12541da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
12551da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
12561da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
12571da177e4SLinus Torvalds 		have_vmlinux = 1;
12581da177e4SLinus Torvalds 		mod->skip = 1;
12591da177e4SLinus Torvalds 	}
12601da177e4SLinus Torvalds 
1261b817f6feSSam Ravnborg 	license = get_modinfo(info.modinfo, info.modinfo_len, "license");
1262b817f6feSSam Ravnborg 	while (license) {
1263b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
1264b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
1265b817f6feSSam Ravnborg 		else {
1266b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
1267b817f6feSSam Ravnborg 			break;
1268b817f6feSSam Ravnborg 		}
1269b817f6feSSam Ravnborg 		license = get_next_modinfo(info.modinfo, info.modinfo_len,
1270b817f6feSSam Ravnborg 					   "license", license);
1271b817f6feSSam Ravnborg 	}
1272b817f6feSSam Ravnborg 
12731da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
12741da177e4SLinus Torvalds 		symname = info.strtab + sym->st_name;
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
12771da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
12781da177e4SLinus Torvalds 	}
1279d1f25e66SSam Ravnborg 	if (!is_vmlinux(modname) ||
128010668220SSam Ravnborg 	     (is_vmlinux(modname) && vmlinux_section_warnings))
128110668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
12821da177e4SLinus Torvalds 
12831da177e4SLinus Torvalds 	version = get_modinfo(info.modinfo, info.modinfo_len, "version");
12841da177e4SLinus Torvalds 	if (version)
12851da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
12861da177e4SLinus Torvalds 				       version - (char *)info.hdr);
12871da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
12881da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
12891da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
12901da177e4SLinus Torvalds 
12911da177e4SLinus Torvalds 	parse_elf_finish(&info);
12921da177e4SLinus Torvalds 
12931da177e4SLinus Torvalds 	/* Our trick to get versioning for struct_module - it's
12941da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
12951da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
12961da177e4SLinus Torvalds 	 * important anyhow */
12971da177e4SLinus Torvalds 	if (modversions)
12981da177e4SLinus Torvalds 		mod->unres = alloc_symbol("struct_module", 0, mod->unres);
12991da177e4SLinus Torvalds }
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds #define SZ 500
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds /* We first write the generated file into memory using the
13041da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
13051da177e4SLinus Torvalds  * only update the later if anything changed */
13061da177e4SLinus Torvalds 
13075c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
13085c3ead8cSSam Ravnborg 						      const char *fmt, ...)
13091da177e4SLinus Torvalds {
13101da177e4SLinus Torvalds 	char tmp[SZ];
13111da177e4SLinus Torvalds 	int len;
13121da177e4SLinus Torvalds 	va_list ap;
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 	va_start(ap, fmt);
13151da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
13167670f023SSam Ravnborg 	buf_write(buf, tmp, len);
13171da177e4SLinus Torvalds 	va_end(ap);
13181da177e4SLinus Torvalds }
13191da177e4SLinus Torvalds 
13205c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
13211da177e4SLinus Torvalds {
13221da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
13237670f023SSam Ravnborg 		buf->size += len + SZ;
13241da177e4SLinus Torvalds 		buf->p = realloc(buf->p, buf->size);
13251da177e4SLinus Torvalds 	}
13261da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
13271da177e4SLinus Torvalds 	buf->pos += len;
13281da177e4SLinus Torvalds }
13291da177e4SLinus Torvalds 
1330c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
1331c96fca21SSam Ravnborg {
1332c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
1333c96fca21SSam Ravnborg 
1334c96fca21SSam Ravnborg 	switch (exp) {
1335c96fca21SSam Ravnborg 	case export_gpl:
1336c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
1337c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
1338c96fca21SSam Ravnborg 		break;
1339c96fca21SSam Ravnborg 	case export_unused_gpl:
1340c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
1341c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
1342c96fca21SSam Ravnborg 		break;
1343c96fca21SSam Ravnborg 	case export_gpl_future:
1344c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
1345c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
1346c96fca21SSam Ravnborg 		break;
1347c96fca21SSam Ravnborg 	case export_plain:
1348c96fca21SSam Ravnborg 	case export_unused:
1349c96fca21SSam Ravnborg 	case export_unknown:
1350c96fca21SSam Ravnborg 		/* ignore */
1351c96fca21SSam Ravnborg 		break;
1352c96fca21SSam Ravnborg 	}
1353c96fca21SSam Ravnborg }
1354c96fca21SSam Ravnborg 
1355c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
1356c96fca21SSam Ravnborg {
1357c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
1358c96fca21SSam Ravnborg 
1359c96fca21SSam Ravnborg 	switch (exp) {
1360c96fca21SSam Ravnborg 	case export_unused:
1361c96fca21SSam Ravnborg 	case export_unused_gpl:
1362c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
1363c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
1364c96fca21SSam Ravnborg 		break;
1365c96fca21SSam Ravnborg 	default:
1366c96fca21SSam Ravnborg 		/* ignore */
1367c96fca21SSam Ravnborg 		break;
1368c96fca21SSam Ravnborg 	}
1369c96fca21SSam Ravnborg }
1370c96fca21SSam Ravnborg 
1371c96fca21SSam Ravnborg static void check_exports(struct module *mod)
1372b817f6feSSam Ravnborg {
1373b817f6feSSam Ravnborg 	struct symbol *s, *exp;
1374b817f6feSSam Ravnborg 
1375b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
13766449bd62SAndrew Morton 		const char *basename;
1377b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
1378b817f6feSSam Ravnborg 		if (!exp || exp->module == mod)
1379b817f6feSSam Ravnborg 			continue;
13806449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
1381b817f6feSSam Ravnborg 		if (basename)
1382b817f6feSSam Ravnborg 			basename++;
1383c96fca21SSam Ravnborg 		else
1384c96fca21SSam Ravnborg 			basename = mod->name;
1385c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
1386c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
1387c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
1388b817f6feSSam Ravnborg 	}
1389b817f6feSSam Ravnborg }
1390b817f6feSSam Ravnborg 
13915c3ead8cSSam Ravnborg /**
13925c3ead8cSSam Ravnborg  * Header for the generated file
13935c3ead8cSSam Ravnborg  **/
13945c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
13951da177e4SLinus Torvalds {
13961da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
13971da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
13981da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
13991da177e4SLinus Torvalds 	buf_printf(b, "\n");
14001da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
14011da177e4SLinus Torvalds 	buf_printf(b, "\n");
14021da177e4SLinus Torvalds 	buf_printf(b, "struct module __this_module\n");
14031da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
1404f83b5e32SUstyugov Roman 	buf_printf(b, " .name = KBUILD_MODNAME,\n");
14051da177e4SLinus Torvalds 	if (mod->has_init)
14061da177e4SLinus Torvalds 		buf_printf(b, " .init = init_module,\n");
14071da177e4SLinus Torvalds 	if (mod->has_cleanup)
14081da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
14091da177e4SLinus Torvalds 			      " .exit = cleanup_module,\n"
14101da177e4SLinus Torvalds 			      "#endif\n");
1411e61a1c1cSRoman Zippel 	buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
14121da177e4SLinus Torvalds 	buf_printf(b, "};\n");
14131da177e4SLinus Torvalds }
14141da177e4SLinus Torvalds 
14155c3ead8cSSam Ravnborg /**
14165c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
14175c3ead8cSSam Ravnborg  **/
1418c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
14191da177e4SLinus Torvalds {
14201da177e4SLinus Torvalds 	struct symbol *s, *exp;
1421c53ddacdSKirill Korotaev 	int err = 0;
14221da177e4SLinus Torvalds 
14231da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
14241da177e4SLinus Torvalds 		exp = find_symbol(s->name);
14251da177e4SLinus Torvalds 		if (!exp || exp->module == mod) {
1426c53ddacdSKirill Korotaev 			if (have_vmlinux && !s->weak) {
14272a116659SMatthew Wilcox 				if (warn_unresolved) {
1428cb80514dSSam Ravnborg 					warn("\"%s\" [%s.ko] undefined!\n",
1429cb80514dSSam Ravnborg 					     s->name, mod->name);
14302a116659SMatthew Wilcox 				} else {
14312a116659SMatthew Wilcox 					merror("\"%s\" [%s.ko] undefined!\n",
14322a116659SMatthew Wilcox 					          s->name, mod->name);
14332a116659SMatthew Wilcox 					err = 1;
14342a116659SMatthew Wilcox 				}
1435c53ddacdSKirill Korotaev 			}
14361da177e4SLinus Torvalds 			continue;
14371da177e4SLinus Torvalds 		}
14381da177e4SLinus Torvalds 		s->module = exp->module;
14391da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
14401da177e4SLinus Torvalds 		s->crc = exp->crc;
14411da177e4SLinus Torvalds 	}
14421da177e4SLinus Torvalds 
14431da177e4SLinus Torvalds 	if (!modversions)
1444c53ddacdSKirill Korotaev 		return err;
14451da177e4SLinus Torvalds 
14461da177e4SLinus Torvalds 	buf_printf(b, "\n");
14471da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
1448*3ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
14491da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
14501da177e4SLinus Torvalds 
14511da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
1452df578e7dSSam Ravnborg 		if (!s->module)
14531da177e4SLinus Torvalds 			continue;
14541da177e4SLinus Torvalds 		if (!s->crc_valid) {
1455cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
14561da177e4SLinus Torvalds 				s->name, mod->name);
14571da177e4SLinus Torvalds 			continue;
14581da177e4SLinus Torvalds 		}
14591da177e4SLinus Torvalds 		buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name);
14601da177e4SLinus Torvalds 	}
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 	buf_printf(b, "};\n");
1463c53ddacdSKirill Korotaev 
1464c53ddacdSKirill Korotaev 	return err;
14651da177e4SLinus Torvalds }
14661da177e4SLinus Torvalds 
14675c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod,
14685c3ead8cSSam Ravnborg 			struct module *modules)
14691da177e4SLinus Torvalds {
14701da177e4SLinus Torvalds 	struct symbol *s;
14711da177e4SLinus Torvalds 	struct module *m;
14721da177e4SLinus Torvalds 	int first = 1;
14731da177e4SLinus Torvalds 
1474df578e7dSSam Ravnborg 	for (m = modules; m; m = m->next)
14751da177e4SLinus Torvalds 		m->seen = is_vmlinux(m->name);
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds 	buf_printf(b, "\n");
14781da177e4SLinus Torvalds 	buf_printf(b, "static const char __module_depends[]\n");
1479*3ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
14801da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
14811da177e4SLinus Torvalds 	buf_printf(b, "\"depends=");
14821da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
1483a61b2dfdSSam Ravnborg 		const char *p;
14841da177e4SLinus Torvalds 		if (!s->module)
14851da177e4SLinus Torvalds 			continue;
14861da177e4SLinus Torvalds 
14871da177e4SLinus Torvalds 		if (s->module->seen)
14881da177e4SLinus Torvalds 			continue;
14891da177e4SLinus Torvalds 
14901da177e4SLinus Torvalds 		s->module->seen = 1;
1491df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
1492df578e7dSSam Ravnborg 		if (p)
1493a61b2dfdSSam Ravnborg 			p++;
1494a61b2dfdSSam Ravnborg 		else
1495a61b2dfdSSam Ravnborg 			p = s->module->name;
1496a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
14971da177e4SLinus Torvalds 		first = 0;
14981da177e4SLinus Torvalds 	}
14991da177e4SLinus Torvalds 	buf_printf(b, "\";\n");
15001da177e4SLinus Torvalds }
15011da177e4SLinus Torvalds 
15025c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
15031da177e4SLinus Torvalds {
15041da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
15051da177e4SLinus Torvalds 		buf_printf(b, "\n");
15061da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
15071da177e4SLinus Torvalds 			   mod->srcversion);
15081da177e4SLinus Torvalds 	}
15091da177e4SLinus Torvalds }
15101da177e4SLinus Torvalds 
15115c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
15121da177e4SLinus Torvalds {
15131da177e4SLinus Torvalds 	char *tmp;
15141da177e4SLinus Torvalds 	FILE *file;
15151da177e4SLinus Torvalds 	struct stat st;
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds 	file = fopen(fname, "r");
15181da177e4SLinus Torvalds 	if (!file)
15191da177e4SLinus Torvalds 		goto write;
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
15221da177e4SLinus Torvalds 		goto close_write;
15231da177e4SLinus Torvalds 
15241da177e4SLinus Torvalds 	if (st.st_size != b->pos)
15251da177e4SLinus Torvalds 		goto close_write;
15261da177e4SLinus Torvalds 
15271da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
15281da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
15291da177e4SLinus Torvalds 		goto free_write;
15301da177e4SLinus Torvalds 
15311da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
15321da177e4SLinus Torvalds 		goto free_write;
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds 	free(tmp);
15351da177e4SLinus Torvalds 	fclose(file);
15361da177e4SLinus Torvalds 	return;
15371da177e4SLinus Torvalds 
15381da177e4SLinus Torvalds  free_write:
15391da177e4SLinus Torvalds 	free(tmp);
15401da177e4SLinus Torvalds  close_write:
15411da177e4SLinus Torvalds 	fclose(file);
15421da177e4SLinus Torvalds  write:
15431da177e4SLinus Torvalds 	file = fopen(fname, "w");
15441da177e4SLinus Torvalds 	if (!file) {
15451da177e4SLinus Torvalds 		perror(fname);
15461da177e4SLinus Torvalds 		exit(1);
15471da177e4SLinus Torvalds 	}
15481da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
15491da177e4SLinus Torvalds 		perror(fname);
15501da177e4SLinus Torvalds 		exit(1);
15511da177e4SLinus Torvalds 	}
15521da177e4SLinus Torvalds 	fclose(file);
15531da177e4SLinus Torvalds }
15541da177e4SLinus Torvalds 
1555bd5cbcedSRam Pai /* parse Module.symvers file. line format:
1556534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
1557bd5cbcedSRam Pai  **/
1558040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
15591da177e4SLinus Torvalds {
15601da177e4SLinus Torvalds 	unsigned long size, pos = 0;
15611da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
15621da177e4SLinus Torvalds 	char *line;
15631da177e4SLinus Torvalds 
15641da177e4SLinus Torvalds 	if (!file)
15651da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
15661da177e4SLinus Torvalds 		return;
15671da177e4SLinus Torvalds 
15681da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
1569534b89a9SSam Ravnborg 		char *symname, *modname, *d, *export, *end;
15701da177e4SLinus Torvalds 		unsigned int crc;
15711da177e4SLinus Torvalds 		struct module *mod;
1572040fcc81SSam Ravnborg 		struct symbol *s;
15731da177e4SLinus Torvalds 
15741da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
15751da177e4SLinus Torvalds 			goto fail;
15761da177e4SLinus Torvalds 		*symname++ = '\0';
15771da177e4SLinus Torvalds 		if (!(modname = strchr(symname, '\t')))
15781da177e4SLinus Torvalds 			goto fail;
15791da177e4SLinus Torvalds 		*modname++ = '\0';
15809ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
1581bd5cbcedSRam Pai 			*export++ = '\0';
1582534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
1583534b89a9SSam Ravnborg 			*end = '\0';
15841da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
15851da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
15861da177e4SLinus Torvalds 			goto fail;
1587df578e7dSSam Ravnborg 		mod = find_module(modname);
1588df578e7dSSam Ravnborg 		if (!mod) {
1589df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
15901da177e4SLinus Torvalds 				have_vmlinux = 1;
15911da177e4SLinus Torvalds 			mod = new_module(NOFAIL(strdup(modname)));
15921da177e4SLinus Torvalds 			mod->skip = 1;
15931da177e4SLinus Torvalds 		}
1594bd5cbcedSRam Pai 		s = sym_add_exported(symname, mod, export_no(export));
1595040fcc81SSam Ravnborg 		s->kernel    = kernel;
15968e70c458SSam Ravnborg 		s->preloaded = 1;
1597bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
15981da177e4SLinus Torvalds 	}
15991da177e4SLinus Torvalds 	return;
16001da177e4SLinus Torvalds fail:
16011da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
16021da177e4SLinus Torvalds }
16031da177e4SLinus Torvalds 
1604040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
1605040fcc81SSam Ravnborg  * For external modules only dump symbols
1606040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
1607040fcc81SSam Ravnborg  **/
1608040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
1609040fcc81SSam Ravnborg {
1610040fcc81SSam Ravnborg 	if (!external_module)
1611040fcc81SSam Ravnborg 		return 1;
1612040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
1613040fcc81SSam Ravnborg 		return 0;
1614040fcc81SSam Ravnborg 	return 1;
1615040fcc81SSam Ravnborg }
1616040fcc81SSam Ravnborg 
16175c3ead8cSSam Ravnborg static void write_dump(const char *fname)
16181da177e4SLinus Torvalds {
16191da177e4SLinus Torvalds 	struct buffer buf = { };
16201da177e4SLinus Torvalds 	struct symbol *symbol;
16211da177e4SLinus Torvalds 	int n;
16221da177e4SLinus Torvalds 
16231da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
16241da177e4SLinus Torvalds 		symbol = symbolhash[n];
16251da177e4SLinus Torvalds 		while (symbol) {
1626040fcc81SSam Ravnborg 			if (dump_sym(symbol))
1627bd5cbcedSRam Pai 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
1628040fcc81SSam Ravnborg 					symbol->crc, symbol->name,
1629bd5cbcedSRam Pai 					symbol->module->name,
1630bd5cbcedSRam Pai 					export_str(symbol->export));
16311da177e4SLinus Torvalds 			symbol = symbol->next;
16321da177e4SLinus Torvalds 		}
16331da177e4SLinus Torvalds 	}
16341da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
16351da177e4SLinus Torvalds }
16361da177e4SLinus Torvalds 
16375c3ead8cSSam Ravnborg int main(int argc, char **argv)
16381da177e4SLinus Torvalds {
16391da177e4SLinus Torvalds 	struct module *mod;
16401da177e4SLinus Torvalds 	struct buffer buf = { };
1641040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
1642040fcc81SSam Ravnborg 	char *dump_write = NULL;
16431da177e4SLinus Torvalds 	int opt;
1644c53ddacdSKirill Korotaev 	int err;
16451da177e4SLinus Torvalds 
16468d8d8289SSam Ravnborg 	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
16471da177e4SLinus Torvalds 		switch (opt) {
16481da177e4SLinus Torvalds 		case 'i':
1649040fcc81SSam Ravnborg 			kernel_read = optarg;
1650040fcc81SSam Ravnborg 			break;
1651040fcc81SSam Ravnborg 		case 'I':
1652040fcc81SSam Ravnborg 			module_read = optarg;
1653040fcc81SSam Ravnborg 			external_module = 1;
16541da177e4SLinus Torvalds 			break;
16551da177e4SLinus Torvalds 		case 'm':
16561da177e4SLinus Torvalds 			modversions = 1;
16571da177e4SLinus Torvalds 			break;
16581da177e4SLinus Torvalds 		case 'o':
16591da177e4SLinus Torvalds 			dump_write = optarg;
16601da177e4SLinus Torvalds 			break;
16611da177e4SLinus Torvalds 		case 'a':
16621da177e4SLinus Torvalds 			all_versions = 1;
16631da177e4SLinus Torvalds 			break;
16648d8d8289SSam Ravnborg 		case 's':
16658d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
16668d8d8289SSam Ravnborg 			break;
1667c53ddacdSKirill Korotaev 		case 'w':
1668c53ddacdSKirill Korotaev 			warn_unresolved = 1;
1669c53ddacdSKirill Korotaev 			break;
16701da177e4SLinus Torvalds 		default:
16711da177e4SLinus Torvalds 			exit(1);
16721da177e4SLinus Torvalds 		}
16731da177e4SLinus Torvalds 	}
16741da177e4SLinus Torvalds 
1675040fcc81SSam Ravnborg 	if (kernel_read)
1676040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
1677040fcc81SSam Ravnborg 	if (module_read)
1678040fcc81SSam Ravnborg 		read_dump(module_read, 0);
16791da177e4SLinus Torvalds 
1680df578e7dSSam Ravnborg 	while (optind < argc)
16811da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
16821da177e4SLinus Torvalds 
16831da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next) {
16841da177e4SLinus Torvalds 		if (mod->skip)
16851da177e4SLinus Torvalds 			continue;
1686c96fca21SSam Ravnborg 		check_exports(mod);
1687b817f6feSSam Ravnborg 	}
1688b817f6feSSam Ravnborg 
1689c53ddacdSKirill Korotaev 	err = 0;
1690c53ddacdSKirill Korotaev 
1691b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
1692666ab414SAndi Kleen 		char fname[strlen(mod->name) + 10];
1693666ab414SAndi Kleen 
1694b817f6feSSam Ravnborg 		if (mod->skip)
1695b817f6feSSam Ravnborg 			continue;
16961da177e4SLinus Torvalds 
16971da177e4SLinus Torvalds 		buf.pos = 0;
16981da177e4SLinus Torvalds 
16991da177e4SLinus Torvalds 		add_header(&buf, mod);
1700c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
17011da177e4SLinus Torvalds 		add_depends(&buf, mod, modules);
17021da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
17031da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
17041da177e4SLinus Torvalds 
17051da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
17061da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
17071da177e4SLinus Torvalds 	}
17081da177e4SLinus Torvalds 
17091da177e4SLinus Torvalds 	if (dump_write)
17101da177e4SLinus Torvalds 		write_dump(dump_write);
17111da177e4SLinus Torvalds 
1712c53ddacdSKirill Korotaev 	return err;
17131da177e4SLinus Torvalds }
1714