xref: /linux-6.15/scripts/mod/modpost.c (revision d8c1eb86)
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 
14b2e3e658SMathieu Desnoyers #define _GNU_SOURCE
15b2e3e658SMathieu Desnoyers #include <stdio.h>
161da177e4SLinus Torvalds #include <ctype.h>
175003bab8SAndrew Morton #include <string.h>
18712f9b46SRusty Russell #include <limits.h>
19d4ef1c30SRusty Russell #include <stdbool.h>
20eed380f3SGuenter Roeck #include <errno.h>
211da177e4SLinus Torvalds #include "modpost.h"
225a865c06SLinus Torvalds #include "../../include/generated/autoconf.h"
23b817f6feSSam Ravnborg #include "../../include/linux/license.h"
24b92021b0SRusty Russell #include "../../include/linux/export.h"
259e1b9b80SAlan Jenkins 
261da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
277a3ee753SMathias Krause static int modversions = 0;
281da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
297a3ee753SMathias Krause static int have_vmlinux = 0;
301da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
311da177e4SLinus Torvalds static int all_versions = 0;
32040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
33040fcc81SSam Ravnborg static int external_module = 0;
348d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
358d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
36c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
37c53ddacdSKirill Korotaev static int warn_unresolved = 0;
38bd5cbcedSRam Pai /* How a symbol is exported */
39588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
40588ccd73SSam Ravnborg static int sec_mismatch_verbose = 1;
4147490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
42eed380f3SGuenter Roeck /* ignore missing files */
43eed380f3SGuenter Roeck static int ignore_missing_files;
44588ccd73SSam Ravnborg 
45c96fca21SSam Ravnborg enum export {
46c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
47c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
48c96fca21SSam Ravnborg };
491da177e4SLinus Torvalds 
506d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
516d9a89eaSAndi Kleen 
526d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds 	va_list arglist;
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	va_start(arglist, fmt);
591da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
601da177e4SLinus Torvalds 	va_end(arglist);
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	exit(1);
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
656d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
661da177e4SLinus Torvalds {
671da177e4SLinus Torvalds 	va_list arglist;
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	va_start(arglist, fmt);
721da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
731da177e4SLinus Torvalds 	va_end(arglist);
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds 
766d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
772a116659SMatthew Wilcox {
782a116659SMatthew Wilcox 	va_list arglist;
792a116659SMatthew Wilcox 
802a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
812a116659SMatthew Wilcox 
822a116659SMatthew Wilcox 	va_start(arglist, fmt);
832a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
842a116659SMatthew Wilcox 	va_end(arglist);
852a116659SMatthew Wilcox }
862a116659SMatthew Wilcox 
87d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
88d4ef1c30SRusty Russell {
89d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
90d4ef1c30SRusty Russell 		return false;
91d4ef1c30SRusty Russell 
92d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
93d4ef1c30SRusty Russell }
94d4ef1c30SRusty Russell 
95040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
96040fcc81SSam Ravnborg {
97040fcc81SSam Ravnborg 	const char *myname;
98040fcc81SSam Ravnborg 
99df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
100df578e7dSSam Ravnborg 	if (myname)
101040fcc81SSam Ravnborg 		myname++;
102040fcc81SSam Ravnborg 	else
103040fcc81SSam Ravnborg 		myname = modname;
104040fcc81SSam Ravnborg 
105741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
106741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
107040fcc81SSam Ravnborg }
108040fcc81SSam Ravnborg 
1091da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1101da177e4SLinus Torvalds {
111df578e7dSSam Ravnborg 	if (!ptr)
1121da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
113df578e7dSSam Ravnborg 
1141da177e4SLinus Torvalds 	return ptr;
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds /* A list of all modules we processed */
1181da177e4SLinus Torvalds static struct module *modules;
1191da177e4SLinus Torvalds 
1205c3ead8cSSam Ravnborg static struct module *find_module(char *modname)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	struct module *mod;
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1251da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1261da177e4SLinus Torvalds 			break;
1271da177e4SLinus Torvalds 	return mod;
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds 
130d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1311da177e4SLinus Torvalds {
1321da177e4SLinus Torvalds 	struct module *mod;
133d4ef1c30SRusty Russell 	char *p;
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1361da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1371da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	/* strip trailing .o */
140d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
141d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
142258f7426SFrank Rowand 		mod->is_dot_o = 1;
143258f7426SFrank Rowand 	}
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	/* add to list */
1461da177e4SLinus Torvalds 	mod->name = p;
147b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1481da177e4SLinus Torvalds 	mod->next = modules;
1491da177e4SLinus Torvalds 	modules = mod;
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds 	return mod;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /* A hash of all exported symbols,
1551da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds struct symbol {
1601da177e4SLinus Torvalds 	struct symbol *next;
1611da177e4SLinus Torvalds 	struct module *module;
1621da177e4SLinus Torvalds 	unsigned int crc;
1631da177e4SLinus Torvalds 	int crc_valid;
1641da177e4SLinus Torvalds 	unsigned int weak:1;
165040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
166040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
167040fcc81SSam Ravnborg 				    *  (only for external modules) **/
168b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
169bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1701da177e4SLinus Torvalds 	char name[0];
1711da177e4SLinus Torvalds };
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1761da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1771da177e4SLinus Torvalds {
1781da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1791da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1821da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1831da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds 
1885c3ead8cSSam Ravnborg /**
1895c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1905c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1915c3ead8cSSam Ravnborg  **/
1925c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1935c3ead8cSSam Ravnborg 				   struct symbol *next)
1941da177e4SLinus Torvalds {
1951da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
1981da177e4SLinus Torvalds 	strcpy(s->name, name);
1991da177e4SLinus Torvalds 	s->weak = weak;
2001da177e4SLinus Torvalds 	s->next = next;
2011da177e4SLinus Torvalds 	return s;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds /* For the hash of exported symbols */
205bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
206bd5cbcedSRam Pai 				 enum export export)
2071da177e4SLinus Torvalds {
2081da177e4SLinus Torvalds 	unsigned int hash;
2091da177e4SLinus Torvalds 	struct symbol *new;
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2121da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2131da177e4SLinus Torvalds 	new->module = module;
214bd5cbcedSRam Pai 	new->export = export;
215040fcc81SSam Ravnborg 	return new;
2161da177e4SLinus Torvalds }
2171da177e4SLinus Torvalds 
2185c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2191da177e4SLinus Torvalds {
2201da177e4SLinus Torvalds 	struct symbol *s;
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2231da177e4SLinus Torvalds 	if (name[0] == '.')
2241da177e4SLinus Torvalds 		name++;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2271da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2281da177e4SLinus Torvalds 			return s;
2291da177e4SLinus Torvalds 	}
2301da177e4SLinus Torvalds 	return NULL;
2311da177e4SLinus Torvalds }
2321da177e4SLinus Torvalds 
2337a3ee753SMathias Krause static const struct {
234bd5cbcedSRam Pai 	const char *str;
235bd5cbcedSRam Pai 	enum export export;
236bd5cbcedSRam Pai } export_list[] = {
237bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
238c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
239bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
240c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
241bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
242bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
243bd5cbcedSRam Pai };
244bd5cbcedSRam Pai 
245bd5cbcedSRam Pai 
246bd5cbcedSRam Pai static const char *export_str(enum export ex)
247bd5cbcedSRam Pai {
248bd5cbcedSRam Pai 	return export_list[ex].str;
249bd5cbcedSRam Pai }
250bd5cbcedSRam Pai 
251bd5cbcedSRam Pai static enum export export_no(const char *s)
252bd5cbcedSRam Pai {
253bd5cbcedSRam Pai 	int i;
254df578e7dSSam Ravnborg 
255534b89a9SSam Ravnborg 	if (!s)
256534b89a9SSam Ravnborg 		return export_unknown;
257bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
258bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
259bd5cbcedSRam Pai 			return export_list[i].export;
260bd5cbcedSRam Pai 	}
261bd5cbcedSRam Pai 	return export_unknown;
262bd5cbcedSRam Pai }
263bd5cbcedSRam Pai 
26462a26356SAlessio Igor Bogani static const char *sec_name(struct elf_info *elf, int secindex);
26562a26356SAlessio Igor Bogani 
26662a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
26762a26356SAlessio Igor Bogani 
26862a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
26962a26356SAlessio Igor Bogani {
27062a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
27162a26356SAlessio Igor Bogani 
27262a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
27362a26356SAlessio Igor Bogani 		return export_plain;
27462a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
27562a26356SAlessio Igor Bogani 		return export_unused;
27662a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
27762a26356SAlessio Igor Bogani 		return export_gpl;
27862a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
27962a26356SAlessio Igor Bogani 		return export_unused_gpl;
28062a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
28162a26356SAlessio Igor Bogani 		return export_gpl_future;
28262a26356SAlessio Igor Bogani 	else
28362a26356SAlessio Igor Bogani 		return export_unknown;
28462a26356SAlessio Igor Bogani }
28562a26356SAlessio Igor Bogani 
2861ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
287bd5cbcedSRam Pai {
288bd5cbcedSRam Pai 	if (sec == elf->export_sec)
289bd5cbcedSRam Pai 		return export_plain;
290c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
291c96fca21SSam Ravnborg 		return export_unused;
292bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
293bd5cbcedSRam Pai 		return export_gpl;
294c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
295c96fca21SSam Ravnborg 		return export_unused_gpl;
296bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
297bd5cbcedSRam Pai 		return export_gpl_future;
298bd5cbcedSRam Pai 	else
299bd5cbcedSRam Pai 		return export_unknown;
300bd5cbcedSRam Pai }
301bd5cbcedSRam Pai 
3025c3ead8cSSam Ravnborg /**
3035c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3045c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3055c3ead8cSSam Ravnborg  **/
306bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod,
307bd5cbcedSRam Pai 				       enum export export)
3081da177e4SLinus Torvalds {
3091da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	if (!s) {
312bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3138e70c458SSam Ravnborg 	} else {
3148e70c458SSam Ravnborg 		if (!s->preloaded) {
3157b75b13cSSam Ravnborg 			warn("%s: '%s' exported twice. Previous export "
3168e70c458SSam Ravnborg 			     "was in %s%s\n", mod->name, name,
3178e70c458SSam Ravnborg 			     s->module->name,
3188e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ?"":".ko");
3194b21960fSTrent Piepho 		} else {
320baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3214b21960fSTrent Piepho 			s->module = mod;
3221da177e4SLinus Torvalds 		}
3231da177e4SLinus Torvalds 	}
3248e70c458SSam Ravnborg 	s->preloaded = 0;
325040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
326040fcc81SSam Ravnborg 	s->kernel    = 0;
327bd5cbcedSRam Pai 	s->export    = export;
328040fcc81SSam Ravnborg 	return s;
3291da177e4SLinus Torvalds }
3301da177e4SLinus Torvalds 
331040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
332bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
333040fcc81SSam Ravnborg {
334040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
335040fcc81SSam Ravnborg 
336b6568b1aSRusty Russell 	if (!s) {
337bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
338b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
339b6568b1aSRusty Russell 		s->preloaded = 1;
340b6568b1aSRusty Russell 	}
341040fcc81SSam Ravnborg 	s->crc = crc;
3421da177e4SLinus Torvalds 	s->crc_valid = 1;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
3455c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
3461da177e4SLinus Torvalds {
3471da177e4SLinus Torvalds 	struct stat st;
348eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
3491da177e4SLinus Torvalds 	int fd;
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
352eb3d5cc6SJesper Juhl 	if (fd < 0)
3531da177e4SLinus Torvalds 		return NULL;
354eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
355eb3d5cc6SJesper Juhl 		goto failed;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	*size = st.st_size;
3581da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
3591da177e4SLinus Torvalds 
360eb3d5cc6SJesper Juhl failed:
361eb3d5cc6SJesper Juhl 	close(fd);
3621da177e4SLinus Torvalds 	if (map == MAP_FAILED)
3631da177e4SLinus Torvalds 		return NULL;
3641da177e4SLinus Torvalds 	return map;
3651da177e4SLinus Torvalds }
3661da177e4SLinus Torvalds 
3675c3ead8cSSam Ravnborg /**
3685c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
3695c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
3705c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
3715c3ead8cSSam Ravnborg   **/
3725c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
3731da177e4SLinus Torvalds {
3741da177e4SLinus Torvalds 	static char line[4096];
3751da177e4SLinus Torvalds 	int skip = 1;
3761da177e4SLinus Torvalds 	size_t len = 0;
3771da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
3781da177e4SLinus Torvalds 	char *s = line;
3791da177e4SLinus Torvalds 
380df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
3811da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
3821da177e4SLinus Torvalds 			p++;
3831da177e4SLinus Torvalds 			continue;
3841da177e4SLinus Torvalds 		}
3851da177e4SLinus Torvalds 		skip = 0;
3861da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
3871da177e4SLinus Torvalds 			len++;
3881da177e4SLinus Torvalds 			*s++ = *p++;
3891da177e4SLinus Torvalds 			if (len > 4095)
3901da177e4SLinus Torvalds 				break; /* Too long, stop */
3911da177e4SLinus Torvalds 		} else {
3921da177e4SLinus Torvalds 			/* End of string */
3931da177e4SLinus Torvalds 			*s = '\0';
3941da177e4SLinus Torvalds 			return line;
3951da177e4SLinus Torvalds 		}
3961da177e4SLinus Torvalds 	}
3971da177e4SLinus Torvalds 	/* End of buffer */
3981da177e4SLinus Torvalds 	return NULL;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds 
4015c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4021da177e4SLinus Torvalds {
4031da177e4SLinus Torvalds 	munmap(file, size);
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds 
40685bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4071da177e4SLinus Torvalds {
4081da177e4SLinus Torvalds 	unsigned int i;
40985bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4101da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4111da177e4SLinus Torvalds 	Elf_Sym  *sym;
4121ce53adfSDenys Vlasenko 	const char *secstrings;
4131ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4161da177e4SLinus Torvalds 	if (!hdr) {
417eed380f3SGuenter Roeck 		if (ignore_missing_files) {
418eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
419eed380f3SGuenter Roeck 				strerror(errno));
420eed380f3SGuenter Roeck 			return 0;
421eed380f3SGuenter Roeck 		}
4221da177e4SLinus Torvalds 		perror(filename);
4236803dc0eSSam Ravnborg 		exit(1);
4241da177e4SLinus Torvalds 	}
4251da177e4SLinus Torvalds 	info->hdr = hdr;
42685bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
42785bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
42885bd2fddSSam Ravnborg 		return 0;
42985bd2fddSSam Ravnborg 	}
43085bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
43185bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
43285bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
43385bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
43485bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
43585bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
43685bd2fddSSam Ravnborg 		return 0;
43785bd2fddSSam Ravnborg 	}
4381da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
439ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
4407d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
4417d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
4427d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
4437d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
4447d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
4457d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
4467d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
4477d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
4487d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
4497d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
4507d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
4517d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
4521da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
4531da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
4541da177e4SLinus Torvalds 
455a83710e5SPetr Stetiar 	/* Check if file offset is correct */
456a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
457df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
458df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
459df578e7dSSam Ravnborg 		      filename, info->size);
460a83710e5SPetr Stetiar 		return 0;
461a83710e5SPetr Stetiar 	}
462a83710e5SPetr Stetiar 
4636845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
4641ce53adfSDenys Vlasenko 		/*
4651ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
4661ce53adfSDenys Vlasenko 		 * read count from .sh_size.
4671ce53adfSDenys Vlasenko 		 */
4681ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
4691ce53adfSDenys Vlasenko 	}
4701ce53adfSDenys Vlasenko 	else {
4711ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
4721ce53adfSDenys Vlasenko 	}
4731ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
4746845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
4751ce53adfSDenys Vlasenko 	}
4761ce53adfSDenys Vlasenko 	else {
4771ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
4781ce53adfSDenys Vlasenko 	}
4791ce53adfSDenys Vlasenko 
4801da177e4SLinus Torvalds 	/* Fix endianness in section headers */
4811ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
4827d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
4831da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
4847d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
4857d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
4861da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
4871da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
4881da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
489ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
4907d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
4917d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
4921da177e4SLinus Torvalds 	}
4931da177e4SLinus Torvalds 	/* Find symbol table. */
4941ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
4951ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
496bd5cbcedSRam Pai 		const char *secname;
49756fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
4981da177e4SLinus Torvalds 
49956fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
500df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
501df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
502df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
503df578e7dSSam Ravnborg 			      sizeof(*hdr));
50485bd2fddSSam Ravnborg 			return 0;
50585bd2fddSSam Ravnborg 		}
506bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
507bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
50856fc82c5STejun Heo 			if (nobits)
50956fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5101da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5111da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
512bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
513bd5cbcedSRam Pai 			info->export_sec = i;
514c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
515c96fca21SSam Ravnborg 			info->export_unused_sec = i;
516bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
517bd5cbcedSRam Pai 			info->export_gpl_sec = i;
518c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
519c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
520bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
521bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
522bd5cbcedSRam Pai 
5231ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5241ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
5251ce53adfSDenys Vlasenko 			symtab_idx = i;
5261ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
5271ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5281ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
5291ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5306845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
5311da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
5321ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
5331ce53adfSDenys Vlasenko 		}
5341ce53adfSDenys Vlasenko 
5351ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
5361ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
5371ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
5381ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
5391ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5401ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
5411ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5421ce53adfSDenys Vlasenko 		}
5431da177e4SLinus Torvalds 	}
544df578e7dSSam Ravnborg 	if (!info->symtab_start)
545cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
546df578e7dSSam Ravnborg 
5471da177e4SLinus Torvalds 	/* Fix endianness in symbols */
5481da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
5491da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
5501da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
5511da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
5521da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
5531da177e4SLinus Torvalds 	}
5541ce53adfSDenys Vlasenko 
5551ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
5561ce53adfSDenys Vlasenko 		Elf32_Word *p;
5576845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
5581ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
5596845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
5601ce53adfSDenys Vlasenko 			      symtab_idx);
5611ce53adfSDenys Vlasenko 		/* Fix endianness */
5621ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
5631ce53adfSDenys Vlasenko 		     p++)
5641ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
5651ce53adfSDenys Vlasenko 	}
5661ce53adfSDenys Vlasenko 
56785bd2fddSSam Ravnborg 	return 1;
5681da177e4SLinus Torvalds }
5691da177e4SLinus Torvalds 
5705c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
5711da177e4SLinus Torvalds {
5721da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds 
5754d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
5764d7365d6SSam Ravnborg {
5774d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
578b92021b0SRusty Russell 	if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0)
5794d7365d6SSam Ravnborg 		return 1;
5804d7365d6SSam Ravnborg 	/* ignore global offset table */
5814d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
5824d7365d6SSam Ravnborg 		return 1;
5834d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
5844d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
5854d7365d6SSam Ravnborg 		if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 ||
5864d7365d6SSam Ravnborg 		    strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 ||
5874d7365d6SSam Ravnborg 		    strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 ||
5888fe9c93eSAndreas Schwab 		    strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 ||
5898fe9c93eSAndreas Schwab 		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
5908fe9c93eSAndreas Schwab 		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
5914d7365d6SSam Ravnborg 			return 1;
5927fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
5937fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
5947fca5dc8SStephen Rothwell 		if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
5958fe9c93eSAndreas Schwab 		    strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
5968fe9c93eSAndreas Schwab 		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
597c153693dSAlan Modra 		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 ||
598c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
5997fca5dc8SStephen Rothwell 			return 1;
6004d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6014d7365d6SSam Ravnborg 	return 0;
6024d7365d6SSam Ravnborg }
6034d7365d6SSam Ravnborg 
604b92021b0SRusty Russell #define CRC_PFX     VMLINUX_SYMBOL_STR(__crc_)
605b92021b0SRusty Russell #define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_)
6061da177e4SLinus Torvalds 
6075c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6081da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6091da177e4SLinus Torvalds {
6101da177e4SLinus Torvalds 	unsigned int crc;
61162a26356SAlessio Igor Bogani 	enum export export;
612*d8c1eb86SNicholas Piggin 	bool is_crc = false;
61362a26356SAlessio Igor Bogani 
614258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
615258f7426SFrank Rowand 	    strncmp(symname, "__ksymtab", 9) == 0)
61662a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
61762a26356SAlessio Igor Bogani 	else
61862a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	/* CRC'd symbol */
6218d99513cSMichal Marek 	if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
622*d8c1eb86SNicholas Piggin 		is_crc = true;
6231da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
624bd5cbcedSRam Pai 		sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
625bd5cbcedSRam Pai 				export);
6261da177e4SLinus Torvalds 	}
627b5064654SAndi Kleen 
628b5064654SAndi Kleen 	switch (sym->st_shndx) {
629b5064654SAndi Kleen 	case SHN_COMMON:
630ef178f92SAndi Kleen 		if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) {
631ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
632ef178f92SAndi Kleen 		} else
633b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
6341da177e4SLinus Torvalds 		break;
6351da177e4SLinus Torvalds 	case SHN_UNDEF:
6361da177e4SLinus Torvalds 		/* undefined symbol */
6371da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
6381da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
6391da177e4SLinus Torvalds 			break;
6404d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
6411da177e4SLinus Torvalds 			break;
6428d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
6438d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
6448d529014SBen Colline /* add compatibility with older glibc */
6458d529014SBen Colline #ifndef STT_SPARC_REGISTER
6468d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
6478d529014SBen Colline #endif
6481da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
6491da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
6501da177e4SLinus Torvalds 			/* Ignore register directives. */
6518d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
6521da177e4SLinus Torvalds 				break;
6537caaeabbSAl Viro 			if (symname[0] == '.') {
6547caaeabbSAl Viro 				char *munged = strdup(symname);
6557caaeabbSAl Viro 				munged[0] = '_';
6567caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
6577caaeabbSAl Viro 				symname = munged;
6587caaeabbSAl Viro 			}
6591da177e4SLinus Torvalds 		}
6601da177e4SLinus Torvalds #endif
6611da177e4SLinus Torvalds 
662b92021b0SRusty Russell #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
663b92021b0SRusty Russell 		if (symname[0] != '_')
664b92021b0SRusty Russell 			break;
665b92021b0SRusty Russell 		else
666b92021b0SRusty Russell 			symname++;
667b92021b0SRusty Russell #endif
668*d8c1eb86SNicholas Piggin 		if (is_crc) {
669*d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
670*d8c1eb86SNicholas Piggin 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", symname + strlen(CRC_PFX), mod->name, e);
671*d8c1eb86SNicholas Piggin 		}
672b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
6731da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
6741da177e4SLinus Torvalds 					  mod->unres);
6751da177e4SLinus Torvalds 		break;
6761da177e4SLinus Torvalds 	default:
6771da177e4SLinus Torvalds 		/* All exported symbols */
6788d99513cSMichal Marek 		if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
679bd5cbcedSRam Pai 			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
680bd5cbcedSRam Pai 					export);
6811da177e4SLinus Torvalds 		}
682b92021b0SRusty Russell 		if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0)
6831da177e4SLinus Torvalds 			mod->has_init = 1;
684b92021b0SRusty Russell 		if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0)
6851da177e4SLinus Torvalds 			mod->has_cleanup = 1;
6861da177e4SLinus Torvalds 		break;
6871da177e4SLinus Torvalds 	}
6881da177e4SLinus Torvalds }
6891da177e4SLinus Torvalds 
6905c3ead8cSSam Ravnborg /**
6915c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
6925c3ead8cSSam Ravnborg  **/
6931da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
6941da177e4SLinus Torvalds {
6951da177e4SLinus Torvalds 	/* Skip non-zero chars */
6961da177e4SLinus Torvalds 	while (string[0]) {
6971da177e4SLinus Torvalds 		string++;
6981da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
6991da177e4SLinus Torvalds 			return NULL;
7001da177e4SLinus Torvalds 	}
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds 	/* Skip any zero padding. */
7031da177e4SLinus Torvalds 	while (!string[0]) {
7041da177e4SLinus Torvalds 		string++;
7051da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7061da177e4SLinus Torvalds 			return NULL;
7071da177e4SLinus Torvalds 	}
7081da177e4SLinus Torvalds 	return string;
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds 
711b817f6feSSam Ravnborg static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
712b817f6feSSam Ravnborg 			      const char *tag, char *info)
7131da177e4SLinus Torvalds {
7141da177e4SLinus Torvalds 	char *p;
7151da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
7161da177e4SLinus Torvalds 	unsigned long size = modinfo_len;
7171da177e4SLinus Torvalds 
718b817f6feSSam Ravnborg 	if (info) {
719b817f6feSSam Ravnborg 		size -= info - (char *)modinfo;
720b817f6feSSam Ravnborg 		modinfo = next_string(info, &size);
721b817f6feSSam Ravnborg 	}
722b817f6feSSam Ravnborg 
7231da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
7241da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7251da177e4SLinus Torvalds 			return p + taglen + 1;
7261da177e4SLinus Torvalds 	}
7271da177e4SLinus Torvalds 	return NULL;
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds 
730b817f6feSSam Ravnborg static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
731b817f6feSSam Ravnborg 			 const char *tag)
732b817f6feSSam Ravnborg 
733b817f6feSSam Ravnborg {
734b817f6feSSam Ravnborg 	return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
735b817f6feSSam Ravnborg }
736b817f6feSSam Ravnborg 
73793684d3bSSam Ravnborg /**
7384c8fbca5SSam Ravnborg  * Test if string s ends in string sub
7394c8fbca5SSam Ravnborg  * return 0 if match
7404c8fbca5SSam Ravnborg  **/
7414c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
7424c8fbca5SSam Ravnborg {
7434c8fbca5SSam Ravnborg 	int slen, sublen;
7444c8fbca5SSam Ravnborg 
7454c8fbca5SSam Ravnborg 	if (!s || !sub)
7464c8fbca5SSam Ravnborg 		return 1;
7474c8fbca5SSam Ravnborg 
7484c8fbca5SSam Ravnborg 	slen = strlen(s);
7494c8fbca5SSam Ravnborg 	sublen = strlen(sub);
7504c8fbca5SSam Ravnborg 
7514c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
7524c8fbca5SSam Ravnborg 		return 1;
7534c8fbca5SSam Ravnborg 
7544c8fbca5SSam Ravnborg 	if (sublen > slen)
7554c8fbca5SSam Ravnborg 		return 1;
7564c8fbca5SSam Ravnborg 
7574c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
7584c8fbca5SSam Ravnborg }
7594c8fbca5SSam Ravnborg 
760ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
761ff13f926SSam Ravnborg {
76258fb0d4fSSam Ravnborg 	if (sym)
763ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
76458fb0d4fSSam Ravnborg 	else
765f666751aSSam Ravnborg 		return "(unknown)";
766ff13f926SSam Ravnborg }
767ff13f926SSam Ravnborg 
7681ce53adfSDenys Vlasenko static const char *sec_name(struct elf_info *elf, int secindex)
769ff13f926SSam Ravnborg {
770ff13f926SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
771ff13f926SSam Ravnborg 	return (void *)elf->hdr +
7721ce53adfSDenys Vlasenko 		elf->sechdrs[elf->secindex_strings].sh_offset +
7731ce53adfSDenys Vlasenko 		sechdrs[secindex].sh_name;
774ff13f926SSam Ravnborg }
775ff13f926SSam Ravnborg 
776ff13f926SSam Ravnborg static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
777ff13f926SSam Ravnborg {
778ff13f926SSam Ravnborg 	return (void *)elf->hdr +
7791ce53adfSDenys Vlasenko 		elf->sechdrs[elf->secindex_strings].sh_offset +
780ff13f926SSam Ravnborg 		sechdr->sh_name;
781ff13f926SSam Ravnborg }
782ff13f926SSam Ravnborg 
78310668220SSam Ravnborg /* The pattern is an array of simple patterns.
78410668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
7856c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
78610668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
78709c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
78810668220SSam Ravnborg  */
7895c725138STrevor Keith static int match(const char *sym, const char * const pat[])
79010668220SSam Ravnborg {
79110668220SSam Ravnborg 	const char *p;
79210668220SSam Ravnborg 	while (*pat) {
79310668220SSam Ravnborg 		p = *pat++;
79410668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
79510668220SSam Ravnborg 
79609c20c03SPaul Gortmaker 		/* "*foo*" */
79709c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
79809c20c03SPaul Gortmaker 			char *here, *bare = strndup(p + 1, strlen(p) - 2);
79909c20c03SPaul Gortmaker 
80009c20c03SPaul Gortmaker 			here = strstr(sym, bare);
80109c20c03SPaul Gortmaker 			free(bare);
80209c20c03SPaul Gortmaker 			if (here != NULL)
80309c20c03SPaul Gortmaker 				return 1;
80409c20c03SPaul Gortmaker 		}
8056c5bd235SSam Ravnborg 		/* "*foo" */
80609c20c03SPaul Gortmaker 		else if (*p == '*') {
8076c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8086c5bd235SSam Ravnborg 				return 1;
8096c5bd235SSam Ravnborg 		}
81010668220SSam Ravnborg 		/* "foo*" */
8116c5bd235SSam Ravnborg 		else if (*endp == '*') {
81210668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
81310668220SSam Ravnborg 				return 1;
81410668220SSam Ravnborg 		}
81510668220SSam Ravnborg 		/* no wildcards */
81610668220SSam Ravnborg 		else {
81710668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
81810668220SSam Ravnborg 				return 1;
81910668220SSam Ravnborg 		}
82010668220SSam Ravnborg 	}
82110668220SSam Ravnborg 	/* no match */
82210668220SSam Ravnborg 	return 0;
82310668220SSam Ravnborg }
82410668220SSam Ravnborg 
82510668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8267a3ee753SMathias Krause static const char *const section_white_list[] =
8274391ed6aSSam Ravnborg {
8284391ed6aSSam Ravnborg 	".comment*",
8294391ed6aSSam Ravnborg 	".debug*",
8304d10c223SChen Gang 	".cranges",		/* sh64 */
8311121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
832019fca84SDavid Howells 	".GCC-command-line",	/* mn10300 */
83376b27645SJonathan Kliegman 	".GCC.command.line",	/* record-gcc-switches, non mn10300 */
8344391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8354391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8364391ed6aSSam Ravnborg 	".stab*",
8374391ed6aSSam Ravnborg 	".note*",
8384391ed6aSSam Ravnborg 	".got*",
8394391ed6aSSam Ravnborg 	".toc*",
840af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
841af42e970SMax Filippov 	".xt.lit",         /* xtensa */
842f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
843f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
844d1189c63SNoam Camus 	".cmem*",			/* EZchip */
845d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
846ef178f92SAndi Kleen 	".gnu.lto*",
8474391ed6aSSam Ravnborg 	NULL
8484391ed6aSSam Ravnborg };
84910668220SSam Ravnborg 
850e241a630SSam Ravnborg /*
851b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
852e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
853b614a697SAnders Kaseorg  * without "ax" / "aw".
854e241a630SSam Ravnborg  */
855b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
856b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
857e241a630SSam Ravnborg {
858b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
859e241a630SSam Ravnborg 
860b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
861b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
862b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
863b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
864b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
865e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
866e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
867e241a630SSam Ravnborg 		     modname, sec);
868e241a630SSam Ravnborg 	}
869e241a630SSam Ravnborg }
870e241a630SSam Ravnborg 
871e241a630SSam Ravnborg 
872e241a630SSam Ravnborg 
873eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
874a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
875a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
876eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
877a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
87810668220SSam Ravnborg 
879eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
880a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
881eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
882a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
88310668220SSam Ravnborg 
884bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
885a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
886a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
887a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
888bb15d8dbSSebastian Andrzej Siewior 
889e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
890e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
8914a31a229SUwe Kleine-König 
8924a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
8934a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
89410668220SSam Ravnborg 
895a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
896157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
8976727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
89852dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
899673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
900673c2c34SChris Metcalf 		".coldtext"
90110668220SSam Ravnborg 
902fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
903fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
904eb8f6890SSam Ravnborg 
905fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
906fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
907eb8f6890SSam Ravnborg 
90852dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
90952dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
91052dc0595SQuentin Casasnovas 
9116c5bd235SSam Ravnborg /* init data sections */
9127a3ee753SMathias Krause static const char *const init_data_sections[] =
9137a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9146c5bd235SSam Ravnborg 
9156c5bd235SSam Ravnborg /* all init sections */
9167a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9176c5bd235SSam Ravnborg 
9186c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9197a3ee753SMathias Krause static const char *const init_exit_sections[] =
920eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9216c5bd235SSam Ravnborg 
9224a3893d0SPaul Gortmaker /* all text sections */
9234a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9244a3893d0SPaul Gortmaker 
9256c5bd235SSam Ravnborg /* data section */
9267a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9276c5bd235SSam Ravnborg 
9286c5bd235SSam Ravnborg 
9296c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
930af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
931af92a82dSUwe Kleine-König 	"*driver",							\
932af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
933af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
934af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
935af92a82dSUwe Kleine-König 	"*_ops",							\
936af92a82dSUwe Kleine-König 	"*_probe",							\
937af92a82dSUwe Kleine-König 	"*_probe_one",							\
938af92a82dSUwe Kleine-König 	"*_console"
9396c5bd235SSam Ravnborg 
9407a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
9417a3ee753SMathias Krause static const char *const linker_symbols[] =
9426c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
9434a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
9446c5bd235SSam Ravnborg 
945588ccd73SSam Ravnborg enum mismatch {
946bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
947bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
948bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
949bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
950bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
951bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
952bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
953bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
954588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
95552dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
956588ccd73SSam Ravnborg };
957588ccd73SSam Ravnborg 
958e5d8f59aSQuentin Casasnovas /**
959e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
960e5d8f59aSQuentin Casasnovas  *
961e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
962e5d8f59aSQuentin Casasnovas  *
963e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
964e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
965e5d8f59aSQuentin Casasnovas  *
966e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
967e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
968e5d8f59aSQuentin Casasnovas  *
969e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
970e5d8f59aSQuentin Casasnovas  *
971e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
972e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
973e5d8f59aSQuentin Casasnovas  *
974e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
975e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
976e5d8f59aSQuentin Casasnovas  *
977e5d8f59aSQuentin Casasnovas  */
97810668220SSam Ravnborg struct sectioncheck {
97910668220SSam Ravnborg 	const char *fromsec[20];
980050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
981050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
982588ccd73SSam Ravnborg 	enum mismatch mismatch;
983af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
984644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
985644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
986644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
987644e8f14SQuentin Casasnovas 
98810668220SSam Ravnborg };
98910668220SSam Ravnborg 
99052dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
99152dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
99252dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
99352dc0595SQuentin Casasnovas 				     const char *fromsec);
99452dc0595SQuentin Casasnovas 
9957a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
99610668220SSam Ravnborg /* Do not reference init/exit code/data from
99710668220SSam Ravnborg  * normal code and data
99810668220SSam Ravnborg  */
99910668220SSam Ravnborg {
1000588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1001050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1002bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1003af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1004588ccd73SSam Ravnborg },
1005588ccd73SSam Ravnborg {
1006588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1007050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1008bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1009af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1010588ccd73SSam Ravnborg },
1011588ccd73SSam Ravnborg {
10120db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1013050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10140db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10150db25245SUwe Kleine-König 	.symbol_white_list = {
10160db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10170db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10180db25245SUwe Kleine-König 	},
10190db25245SUwe Kleine-König },
10200db25245SUwe Kleine-König {
1021588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1022050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1023bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1024af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1025588ccd73SSam Ravnborg },
1026588ccd73SSam Ravnborg {
1027588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1028050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1029bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1030af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1031eb8f6890SSam Ravnborg },
1032e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1033eb8f6890SSam Ravnborg {
10344a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1035050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1036bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1037af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1038eb8f6890SSam Ravnborg },
1039e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1040eb8f6890SSam Ravnborg {
10414a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1042050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1043bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1044af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
104510668220SSam Ravnborg },
104610668220SSam Ravnborg /* Do not use exit code/data from init code */
104710668220SSam Ravnborg {
1048eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1049050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1050bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1051af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
105210668220SSam Ravnborg },
105310668220SSam Ravnborg /* Do not use init code/data from exit code */
105410668220SSam Ravnborg {
1055eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1056050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1057bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1058af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
105910668220SSam Ravnborg },
1060bb15d8dbSSebastian Andrzej Siewior {
1061bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1062050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1063bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1064bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1065bb15d8dbSSebastian Andrzej Siewior },
106610668220SSam Ravnborg /* Do not export init/exit functions or data */
106710668220SSam Ravnborg {
106810668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1069050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1070af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1071af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
107252dc0595SQuentin Casasnovas },
107352dc0595SQuentin Casasnovas {
107452dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
107552dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
107652dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
107752dc0595SQuentin Casasnovas 	 */
107852dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
107952dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
108052dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
108152dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
108210668220SSam Ravnborg }
108310668220SSam Ravnborg };
108410668220SSam Ravnborg 
10850d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
10860d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
108710668220SSam Ravnborg {
108810668220SSam Ravnborg 	int i;
108910668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
109010668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
109110668220SSam Ravnborg 
1092c5c3439aSQuentin Casasnovas 	/*
1093c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1094c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1095c5c3439aSQuentin Casasnovas 	 * doesn't make much sense and causes build failures on parisc and
1096c5c3439aSQuentin Casasnovas 	 * mn10300 architectures.
1097c5c3439aSQuentin Casasnovas 	 */
1098c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1099c5c3439aSQuentin Casasnovas 		return NULL;
1100c5c3439aSQuentin Casasnovas 
110110668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1102050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1103050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11040d2a636eSUwe Kleine-König 				return check;
1105050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1106050e57fdSQuentin Casasnovas 				return check;
1107050e57fdSQuentin Casasnovas 		}
110810668220SSam Ravnborg 		check++;
110910668220SSam Ravnborg 	}
11100d2a636eSUwe Kleine-König 	return NULL;
111110668220SSam Ravnborg }
111210668220SSam Ravnborg 
11134c8fbca5SSam Ravnborg /**
11144c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11150e0d314eSSam Ravnborg  *
11164c8fbca5SSam Ravnborg  * Pattern 1:
11174c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11184c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11194c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11204c8fbca5SSam Ravnborg  *   this pattern.
11214c8fbca5SSam Ravnborg  *   The pattern is identified by:
11224c8fbca5SSam Ravnborg  *   tosec   = .init.data
11239209aed0SSam Ravnborg  *   fromsec = .data*
11244c8fbca5SSam Ravnborg  *   atsym   =__param*
11254c8fbca5SSam Ravnborg  *
11266a841528SRusty Russell  * Pattern 1a:
11276a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11286a841528SRusty Russell  *   The pattern is identified by:
11296a841528SRusty Russell  *   tosec   = .init.text
11306a841528SRusty Russell  *   fromsec = .data*
11316a841528SRusty Russell  *   atsym   = __param_ops_*
11326a841528SRusty Russell  *
11334c8fbca5SSam Ravnborg  * Pattern 2:
113472ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11354c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
11364c8fbca5SSam Ravnborg  *   the pattern is identified by:
113783cda2bbSSam Ravnborg  *   tosec   = init or exit section
113883cda2bbSSam Ravnborg  *   fromsec = data section
1139df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1140df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1141ee6a8545SVivek Goyal  *
1142ee6a8545SVivek Goyal  * Pattern 3:
1143c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
11449bf8cb9bSSam Ravnborg  *
11451d8af559SSam Ravnborg  * Pattern 4:
1146ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1147ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1148ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1149ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1150ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1151ee6a8545SVivek Goyal  *   This pattern is identified by
1152ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
11539bf8cb9bSSam Ravnborg  *
11544a3893d0SPaul Gortmaker  * Pattern 5:
11554a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
11564a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
11574a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
11584a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
11594a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
11604a3893d0SPaul Gortmaker  *   This pattern is identified by
11614a3893d0SPaul Gortmaker  *   tosec   = init section
11624a3893d0SPaul Gortmaker  *   fromsec = text section
11634a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
11644a3893d0SPaul Gortmaker  *
11654c8fbca5SSam Ravnborg  **/
1166af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1167af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
116858fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
11694c8fbca5SSam Ravnborg {
11704c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
11716c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
11726c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
117358fb0d4fSSam Ravnborg 	    (strncmp(fromsym, "__param", strlen("__param")) == 0))
117458fb0d4fSSam Ravnborg 		return 0;
11754c8fbca5SSam Ravnborg 
11766a841528SRusty Russell 	/* Check for pattern 1a */
11776a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
11786a841528SRusty Russell 	    match(fromsec, data_sections) &&
11796a841528SRusty Russell 	    (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0))
11806a841528SRusty Russell 		return 0;
11816a841528SRusty Russell 
11824c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
11836c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
11846c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1185af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
118658fb0d4fSSam Ravnborg 		return 0;
11874c8fbca5SSam Ravnborg 
11889bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
11896c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
11906c5bd235SSam Ravnborg 	    match(tosec, init_sections))
119158fb0d4fSSam Ravnborg 		return 0;
1192f8657e1bSVivek Goyal 
11931d8af559SSam Ravnborg 	/* Check for pattern 4 */
119458fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
119593659af1SSam Ravnborg 		return 0;
119658fb0d4fSSam Ravnborg 
11974a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
11984a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
11994a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12004a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12014a3893d0SPaul Gortmaker 		return 0;
12024a3893d0SPaul Gortmaker 
120358fb0d4fSSam Ravnborg 	return 1;
12044c8fbca5SSam Ravnborg }
12054c8fbca5SSam Ravnborg 
12064c8fbca5SSam Ravnborg /**
120793684d3bSSam Ravnborg  * Find symbol based on relocation record info.
120893684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
120993684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
121093684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
121193684d3bSSam Ravnborg  * based on section and address.
121293684d3bSSam Ravnborg  *  **/
12139ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
121493684d3bSSam Ravnborg 				Elf_Sym *relsym)
121593684d3bSSam Ravnborg {
121693684d3bSSam Ravnborg 	Elf_Sym *sym;
12179ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
12189ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
12199ad21c3fSSam Ravnborg 	Elf64_Sword d;
12201ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
122193684d3bSSam Ravnborg 
122293684d3bSSam Ravnborg 	if (relsym->st_name != 0)
122393684d3bSSam Ravnborg 		return relsym;
12241ce53adfSDenys Vlasenko 
12251ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
122693684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
12271ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
122893684d3bSSam Ravnborg 			continue;
1229ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1230ae4ac123SAtsushi Nemoto 			continue;
123193684d3bSSam Ravnborg 		if (sym->st_value == addr)
123293684d3bSSam Ravnborg 			return sym;
12339ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
12349ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
12359ad21c3fSSam Ravnborg 		if (d < 0)
12369ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
12379ad21c3fSSam Ravnborg 		if (d < distance) {
12389ad21c3fSSam Ravnborg 			distance = d;
12399ad21c3fSSam Ravnborg 			near = sym;
124093684d3bSSam Ravnborg 		}
12419ad21c3fSSam Ravnborg 	}
12429ad21c3fSSam Ravnborg 	/* We need a close match */
12439ad21c3fSSam Ravnborg 	if (distance < 20)
12449ad21c3fSSam Ravnborg 		return near;
12459ad21c3fSSam Ravnborg 	else
124693684d3bSSam Ravnborg 		return NULL;
124793684d3bSSam Ravnborg }
124893684d3bSSam Ravnborg 
1249da68d61fSDavid Brownell static inline int is_arm_mapping_symbol(const char *str)
1250da68d61fSDavid Brownell {
12516c34f1f5SKyle McMartin 	return str[0] == '$' && strchr("axtd", str[1])
1252da68d61fSDavid Brownell 	       && (str[2] == '\0' || str[2] == '.');
1253da68d61fSDavid Brownell }
1254da68d61fSDavid Brownell 
1255da68d61fSDavid Brownell /*
1256da68d61fSDavid Brownell  * If there's no name there, ignore it; likewise, ignore it if it's
1257da68d61fSDavid Brownell  * one of the magic symbols emitted used by current ARM tools.
1258da68d61fSDavid Brownell  *
1259da68d61fSDavid Brownell  * Otherwise if find_symbols_between() returns those symbols, they'll
1260da68d61fSDavid Brownell  * fail the whitelist tests and cause lots of false alarms ... fixable
1261da68d61fSDavid Brownell  * only by merging __exit and __init sections into __text, bloating
1262da68d61fSDavid Brownell  * the kernel (which is especially evil on embedded platforms).
1263da68d61fSDavid Brownell  */
1264da68d61fSDavid Brownell static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
1265da68d61fSDavid Brownell {
1266da68d61fSDavid Brownell 	const char *name = elf->strtab + sym->st_name;
1267da68d61fSDavid Brownell 
1268da68d61fSDavid Brownell 	if (!name || !strlen(name))
1269da68d61fSDavid Brownell 		return 0;
1270da68d61fSDavid Brownell 	return !is_arm_mapping_symbol(name);
1271da68d61fSDavid Brownell }
1272da68d61fSDavid Brownell 
1273b39927cfSSam Ravnborg /*
127443c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
127543c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
127643c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
127743c74d17SSam Ravnborg  * it is, but this works for now.
1278b39927cfSSam Ravnborg  **/
1279157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1280157c23c8SSam Ravnborg 				 const char *sec)
1281b39927cfSSam Ravnborg {
1282b39927cfSSam Ravnborg 	Elf_Sym *sym;
1283157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1284157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1285b39927cfSSam Ravnborg 
1286b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1287b39927cfSSam Ravnborg 		const char *symsec;
1288b39927cfSSam Ravnborg 
12891ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1290b39927cfSSam Ravnborg 			continue;
12911ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1292b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1293b39927cfSSam Ravnborg 			continue;
1294da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1295da68d61fSDavid Brownell 			continue;
1296b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1297157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1298157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1299157c23c8SSam Ravnborg 				near = sym;
1300157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1301157c23c8SSam Ravnborg 				near = sym;
130243c74d17SSam Ravnborg 			}
1303b39927cfSSam Ravnborg 		}
1304b39927cfSSam Ravnborg 	}
1305157c23c8SSam Ravnborg 	return near;
1306157c23c8SSam Ravnborg }
1307b39927cfSSam Ravnborg 
130858fb0d4fSSam Ravnborg /*
1309588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1310588ccd73SSam Ravnborg  * .init.text => __init
1311588ccd73SSam Ravnborg  * .memexitconst => __memconst
1312588ccd73SSam Ravnborg  * etc.
1313cbcf14a9SAndy Shevchenko  *
1314cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1315cbcf14a9SAndy Shevchenko  * method should free it after usage.
1316588ccd73SSam Ravnborg */
1317588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1318588ccd73SSam Ravnborg {
1319588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
1320588ccd73SSam Ravnborg 		char *p = malloc(20);
1321588ccd73SSam Ravnborg 		char *r = p;
1322588ccd73SSam Ravnborg 
1323588ccd73SSam Ravnborg 		*p++ = '_';
1324588ccd73SSam Ravnborg 		*p++ = '_';
1325588ccd73SSam Ravnborg 		if (*s == '.')
1326588ccd73SSam Ravnborg 			s++;
1327588ccd73SSam Ravnborg 		while (*s && *s != '.')
1328588ccd73SSam Ravnborg 			*p++ = *s++;
1329588ccd73SSam Ravnborg 		*p = '\0';
1330588ccd73SSam Ravnborg 		if (*s == '.')
1331588ccd73SSam Ravnborg 			s++;
1332588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1333588ccd73SSam Ravnborg 			strcat(p, "const ");
1334588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1335588ccd73SSam Ravnborg 			strcat(p, "data ");
1336588ccd73SSam Ravnborg 		else
1337588ccd73SSam Ravnborg 			strcat(p, " ");
1338cbcf14a9SAndy Shevchenko 		return r;
1339588ccd73SSam Ravnborg 	} else {
13405003bab8SAndrew Morton 		return strdup("");
1341588ccd73SSam Ravnborg 	}
1342588ccd73SSam Ravnborg }
1343588ccd73SSam Ravnborg 
1344588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1345588ccd73SSam Ravnborg {
1346588ccd73SSam Ravnborg 	if (sym)
1347588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1348588ccd73SSam Ravnborg 	else
1349f666751aSSam Ravnborg 		return -1;
1350588ccd73SSam Ravnborg }
1351588ccd73SSam Ravnborg 
135200759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
135300759c0eSRandy Dunlap {
135400759c0eSRandy Dunlap 	const char *const *s = list;
135500759c0eSRandy Dunlap 
135600759c0eSRandy Dunlap 	while (*s) {
135700759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
135800759c0eSRandy Dunlap 		s++;
135900759c0eSRandy Dunlap 		if (*s)
136000759c0eSRandy Dunlap 			fprintf(stderr, ", ");
136100759c0eSRandy Dunlap 	}
136200759c0eSRandy Dunlap 	fprintf(stderr, "\n");
136300759c0eSRandy Dunlap }
136400759c0eSRandy Dunlap 
1365356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1366356ad538SQuentin Casasnovas {
1367356ad538SQuentin Casasnovas 	switch (is_func) {
1368356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1369356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1370356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1371356ad538SQuentin Casasnovas 	}
1372356ad538SQuentin Casasnovas }
1373356ad538SQuentin Casasnovas 
1374588ccd73SSam Ravnborg /*
1375b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1376b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
13774c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
137858fb0d4fSSam Ravnborg  */
13790d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
13800d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
138158fb0d4fSSam Ravnborg 				const char *fromsec,
138258fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
138358fb0d4fSSam Ravnborg 				const char *fromsym,
1384588ccd73SSam Ravnborg 				int from_is_func,
1385588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1386588ccd73SSam Ravnborg 				int to_is_func)
1387b39927cfSSam Ravnborg {
1388588ccd73SSam Ravnborg 	const char *from, *from_p;
1389588ccd73SSam Ravnborg 	const char *to, *to_p;
139037ed19d5SAlexey Fomenko 	char *prl_from;
139137ed19d5SAlexey Fomenko 	char *prl_to;
1392f666751aSSam Ravnborg 
1393e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1394e5f95c8bSSam Ravnborg 	if (!sec_mismatch_verbose)
1395e5f95c8bSSam Ravnborg 		return;
1396e5f95c8bSSam Ravnborg 
1397356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1398356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1399356ad538SQuentin Casasnovas 
14007c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14017c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14027c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14037c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1404588ccd73SSam Ravnborg 
14050d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1406bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
140737ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
140837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1409588ccd73SSam Ravnborg 		fprintf(stderr,
1410588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1411588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1412588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1413588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
141437ed19d5SAlexey Fomenko 		prl_from, fromsym,
141537ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
141637ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
141737ed19d5SAlexey Fomenko 		free(prl_from);
141837ed19d5SAlexey Fomenko 		free(prl_to);
1419588ccd73SSam Ravnborg 		break;
1420bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
142137ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1422588ccd73SSam Ravnborg 		fprintf(stderr,
1423588ccd73SSam Ravnborg 		"The variable %s references\n"
1424588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1425588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
14268b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1427588ccd73SSam Ravnborg 		"or name the variable:\n",
142837ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
142900759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
143037ed19d5SAlexey Fomenko 		free(prl_to);
1431588ccd73SSam Ravnborg 		break;
143258fb0d4fSSam Ravnborg 	}
1433bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
143437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1435588ccd73SSam Ravnborg 		fprintf(stderr,
1436588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1437588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1438588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
143937ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
144037ed19d5SAlexey Fomenko 		free(prl_to);
1441588ccd73SSam Ravnborg 		break;
1442bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
144337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1444588ccd73SSam Ravnborg 		fprintf(stderr,
1445588ccd73SSam Ravnborg 		"The variable %s references\n"
1446588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1447588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1448588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1449588ccd73SSam Ravnborg 		"name the variable:\n",
145037ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
145100759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
145237ed19d5SAlexey Fomenko 		free(prl_to);
1453588ccd73SSam Ravnborg 		break;
1454588ccd73SSam Ravnborg 	}
1455bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1456bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
145737ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
145837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1459588ccd73SSam Ravnborg 		fprintf(stderr,
1460588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1461588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1462588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1463588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
146437ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
146537ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1466b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
146737ed19d5SAlexey Fomenko 		free(prl_from);
146837ed19d5SAlexey Fomenko 		free(prl_to);
1469588ccd73SSam Ravnborg 		break;
1470bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
147137ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
147237ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1473588ccd73SSam Ravnborg 		fprintf(stderr,
1474588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1475588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1476588ccd73SSam Ravnborg 		"This is often seen when error handling "
1477588ccd73SSam Ravnborg 		"in the init function\n"
1478588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1479588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1480588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
148137ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
148237ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
14835003bab8SAndrew Morton 		prl_to, tosym, to_p);
148437ed19d5SAlexey Fomenko 		free(prl_from);
148537ed19d5SAlexey Fomenko 		free(prl_to);
1486588ccd73SSam Ravnborg 		break;
1487bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
148837ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
148937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1490588ccd73SSam Ravnborg 		fprintf(stderr,
1491588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1492588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1493588ccd73SSam Ravnborg 		"This is often seen when error handling "
1494588ccd73SSam Ravnborg 		"in the exit function\n"
1495588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1496588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1497588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
149837ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
149937ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
150037ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
150137ed19d5SAlexey Fomenko 		free(prl_from);
150237ed19d5SAlexey Fomenko 		free(prl_to);
1503588ccd73SSam Ravnborg 		break;
1504588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
150537ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1506588ccd73SSam Ravnborg 		fprintf(stderr,
1507588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1508588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1509588ccd73SSam Ravnborg 		"or drop the export.\n",
151037ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
151137ed19d5SAlexey Fomenko 		free(prl_to);
1512588ccd73SSam Ravnborg 		break;
151352dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
151452dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
151552dc0595SQuentin Casasnovas 		      "we should never get here.");
151652dc0595SQuentin Casasnovas 		break;
1517588ccd73SSam Ravnborg 	}
1518588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
151958fb0d4fSSam Ravnborg }
152058fb0d4fSSam Ravnborg 
1521644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1522644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
152358fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
152458fb0d4fSSam Ravnborg {
152558fb0d4fSSam Ravnborg 	const char *tosec;
1526588ccd73SSam Ravnborg 	Elf_Sym *to;
1527588ccd73SSam Ravnborg 	Elf_Sym *from;
152858fb0d4fSSam Ravnborg 	const char *tosym;
1529588ccd73SSam Ravnborg 	const char *fromsym;
153058fb0d4fSSam Ravnborg 
1531588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1532588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
153358fb0d4fSSam Ravnborg 
153477ab21adSAndi Kleen 	if (!strncmp(fromsym, "reference___initcall",
153577ab21adSAndi Kleen 		     sizeof("reference___initcall")-1))
153677ab21adSAndi Kleen 		return;
153777ab21adSAndi Kleen 
1538c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1539c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1540c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1541c7a65e06SQuentin Casasnovas 
154258fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1543af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1544af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1545588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1546588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1547588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1548588ccd73SSam Ravnborg 				    is_function(to));
154958fb0d4fSSam Ravnborg 	}
1550b39927cfSSam Ravnborg }
1551644e8f14SQuentin Casasnovas 
155252dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
155352dc0595SQuentin Casasnovas {
155452dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
155552dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
155652dc0595SQuentin Casasnovas 
155752dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
155852dc0595SQuentin Casasnovas }
155952dc0595SQuentin Casasnovas 
156052dc0595SQuentin Casasnovas /*
156152dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
156252dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
156352dc0595SQuentin Casasnovas  */
156452dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1565e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
156652dc0595SQuentin Casasnovas {
156752dc0595SQuentin Casasnovas 	/*
156852dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
156952dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
157052dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
157152dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
157252dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
157352dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
157452dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
157552dc0595SQuentin Casasnovas 	 */
1576e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
157752dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
157852dc0595SQuentin Casasnovas }
1579e84048aaSQuentin Casasnovas 
158052dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
158152dc0595SQuentin Casasnovas {
1582d3df4de7SQuentin Casasnovas 	/*
1583d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1584d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1585d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1586d3df4de7SQuentin Casasnovas 	 */
1587d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
158852dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
158952dc0595SQuentin Casasnovas 
159052dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
159152dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
159252dc0595SQuentin Casasnovas }
159352dc0595SQuentin Casasnovas 
1594e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1595e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1596e84048aaSQuentin Casasnovas 
159752dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
159852dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
159952dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
160052dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
160152dc0595SQuentin Casasnovas {
160252dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
160352dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
160452dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
160552dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
160652dc0595SQuentin Casasnovas 	const char* from_pretty_name;
160752dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
160852dc0595SQuentin Casasnovas 	const char* to_pretty_name;
160952dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
161052dc0595SQuentin Casasnovas 
161152dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
161252dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
161352dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
161452dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
161552dc0595SQuentin Casasnovas 
161652dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
161752dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
161852dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
161952dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
162052dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
162152dc0595SQuentin Casasnovas 
162252dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
162352dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
162452dc0595SQuentin Casasnovas 		fprintf(stderr,
162552dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
162652dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
162752dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
162852dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
162952dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
163052dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
163152dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
163252dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
163352dc0595SQuentin Casasnovas }
163452dc0595SQuentin Casasnovas 
163552dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
163652dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
163752dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
163852dc0595SQuentin Casasnovas 				     const char *fromsec)
163952dc0595SQuentin Casasnovas {
164052dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
164152dc0595SQuentin Casasnovas 
164252dc0595SQuentin Casasnovas 	sec_mismatch_count++;
164352dc0595SQuentin Casasnovas 
164452dc0595SQuentin Casasnovas 	if (sec_mismatch_verbose)
164552dc0595SQuentin Casasnovas 		report_extable_warnings(modname, elf, mismatch, r, sym,
164652dc0595SQuentin Casasnovas 					fromsec, tosec);
164752dc0595SQuentin Casasnovas 
164852dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
164952dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
165052dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
165152dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
165252dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
165352dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
165452dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
165552dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
165652dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
165752dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
165852dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
165952dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
166052dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
166152dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
166252dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
166352dc0595SQuentin Casasnovas 		else
166452dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
166552dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
166652dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
166752dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
166852dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
166952dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
167052dc0595SQuentin Casasnovas 	}
167152dc0595SQuentin Casasnovas }
167252dc0595SQuentin Casasnovas 
1673644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1674644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1675644e8f14SQuentin Casasnovas {
1676644e8f14SQuentin Casasnovas 	const char *tosec = sec_name(elf, get_secindex(elf, sym));;
1677644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1678644e8f14SQuentin Casasnovas 
1679644e8f14SQuentin Casasnovas 	if (mismatch) {
1680644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1681644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1682644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1683644e8f14SQuentin Casasnovas 		else
1684644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1685644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1686644e8f14SQuentin Casasnovas 	}
1687b39927cfSSam Ravnborg }
1688b39927cfSSam Ravnborg 
1689ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
16905b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1691ae4ac123SAtsushi Nemoto {
1692ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
16936845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1694ae4ac123SAtsushi Nemoto 
1695ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1696731ece41SOlof Johansson 		r->r_offset;
1697ae4ac123SAtsushi Nemoto }
1698ae4ac123SAtsushi Nemoto 
16995b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1700ae4ac123SAtsushi Nemoto {
1701ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17025b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1703ae4ac123SAtsushi Nemoto 
1704ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1705ae4ac123SAtsushi Nemoto 	case R_386_32:
1706ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1707ae4ac123SAtsushi Nemoto 		break;
1708ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1709ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1710ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1711ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1712ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1713ae4ac123SAtsushi Nemoto 		break;
1714ae4ac123SAtsushi Nemoto 	}
1715ae4ac123SAtsushi Nemoto 	return 0;
1716ae4ac123SAtsushi Nemoto }
1717ae4ac123SAtsushi Nemoto 
17186e2e340bSTony Lindgren #ifndef R_ARM_CALL
17196e2e340bSTony Lindgren #define R_ARM_CALL	28
17206e2e340bSTony Lindgren #endif
17216e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17226e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17236e2e340bSTony Lindgren #endif
17246e2e340bSTony Lindgren 
1725c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1726c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1727c9698e5cSDavid A. Long #endif
1728c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1729c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1730c9698e5cSDavid A. Long #endif
1731c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1732c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1733c9698e5cSDavid A. Long #endif
1734c9698e5cSDavid A. Long 
17355b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
173656a974faSSam Ravnborg {
173756a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
173856a974faSSam Ravnborg 
173956a974faSSam Ravnborg 	switch (r_typ) {
174056a974faSSam Ravnborg 	case R_ARM_ABS32:
174156a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1742df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1743df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
174456a974faSSam Ravnborg 		break;
174556a974faSSam Ravnborg 	case R_ARM_PC24:
17466e2e340bSTony Lindgren 	case R_ARM_CALL:
17476e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1748c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1749c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1750c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
175156a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1752df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
17535b24c071SSam Ravnborg 			      sechdr->sh_offset +
17545b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
175556a974faSSam Ravnborg 		break;
175656a974faSSam Ravnborg 	default:
175756a974faSSam Ravnborg 		return 1;
175856a974faSSam Ravnborg 	}
175956a974faSSam Ravnborg 	return 0;
176056a974faSSam Ravnborg }
176156a974faSSam Ravnborg 
17625b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1763ae4ac123SAtsushi Nemoto {
1764ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17655b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1766ae4ac123SAtsushi Nemoto 	unsigned int inst;
1767ae4ac123SAtsushi Nemoto 
1768ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1769ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1770ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1771ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1772ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1773ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1774ae4ac123SAtsushi Nemoto 		break;
1775ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1776ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1777ae4ac123SAtsushi Nemoto 		break;
1778ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1779ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1780ae4ac123SAtsushi Nemoto 		break;
1781ae4ac123SAtsushi Nemoto 	}
1782ae4ac123SAtsushi Nemoto 	return 0;
1783ae4ac123SAtsushi Nemoto }
1784ae4ac123SAtsushi Nemoto 
17855b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
178610668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1787b39927cfSSam Ravnborg {
1788b39927cfSSam Ravnborg 	Elf_Sym  *sym;
17895b24c071SSam Ravnborg 	Elf_Rela *rela;
17902c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1791eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
17925b24c071SSam Ravnborg 	const char *fromsec;
17935b24c071SSam Ravnborg 
1794ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
17955b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
17965b24c071SSam Ravnborg 
1797ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
17985b24c071SSam Ravnborg 	fromsec += strlen(".rela");
17995b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1800b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18015b24c071SSam Ravnborg 		return;
1802e241a630SSam Ravnborg 
1803b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1804b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1805eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1806ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1807ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1808eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1809eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1810ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1811ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1812eae07ac6SAtsushi Nemoto 		} else {
1813601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1814eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1815eae07ac6SAtsushi Nemoto 		}
1816eae07ac6SAtsushi Nemoto #else
1817eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1818eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1819eae07ac6SAtsushi Nemoto #endif
182093684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1821eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1822b39927cfSSam Ravnborg 		/* Skip special sections */
18231ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1824b39927cfSSam Ravnborg 			continue;
1825e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1826e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
182758fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18282c1a51f3SAtsushi Nemoto 	}
18295b24c071SSam Ravnborg }
18305b24c071SSam Ravnborg 
18315b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
183210668220SSam Ravnborg 			Elf_Shdr *sechdr)
18335b24c071SSam Ravnborg {
18345b24c071SSam Ravnborg 	Elf_Sym *sym;
18352c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
18365b24c071SSam Ravnborg 	Elf_Rela r;
18375b24c071SSam Ravnborg 	unsigned int r_sym;
18385b24c071SSam Ravnborg 	const char *fromsec;
18395b24c071SSam Ravnborg 
1840ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
18415b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
18425b24c071SSam Ravnborg 
1843ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18445b24c071SSam Ravnborg 	fromsec += strlen(".rel");
18455b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1846b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18475b24c071SSam Ravnborg 		return;
18482c1a51f3SAtsushi Nemoto 
18492c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
18502c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1851eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1852ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1853ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1854eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1855eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1856ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1857ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1858eae07ac6SAtsushi Nemoto 		} else {
18592c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1860eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1861eae07ac6SAtsushi Nemoto 		}
1862eae07ac6SAtsushi Nemoto #else
1863eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1864eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1865eae07ac6SAtsushi Nemoto #endif
18662c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1867ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1868ae4ac123SAtsushi Nemoto 		case EM_386:
18695b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1870ae4ac123SAtsushi Nemoto 				continue;
1871ae4ac123SAtsushi Nemoto 			break;
187256a974faSSam Ravnborg 		case EM_ARM:
18735b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
187456a974faSSam Ravnborg 				continue;
187556a974faSSam Ravnborg 			break;
1876ae4ac123SAtsushi Nemoto 		case EM_MIPS:
18775b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1878ae4ac123SAtsushi Nemoto 				continue;
1879ae4ac123SAtsushi Nemoto 			break;
1880ae4ac123SAtsushi Nemoto 		}
1881eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
18822c1a51f3SAtsushi Nemoto 		/* Skip special sections */
18831ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
18842c1a51f3SAtsushi Nemoto 			continue;
1885e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1886e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
188758fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18882c1a51f3SAtsushi Nemoto 	}
1889b39927cfSSam Ravnborg }
18905b24c071SSam Ravnborg 
18915b24c071SSam Ravnborg /**
18925b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
18935b24c071SSam Ravnborg  * either when loaded or when used as built-in.
18945b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1895b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
18965b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
18975b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
189832be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
18995b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19005b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19015b24c071SSam Ravnborg  * be discarded and warns about it.
19025b24c071SSam Ravnborg  **/
19035b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
190410668220SSam Ravnborg 			  struct elf_info *elf)
19055b24c071SSam Ravnborg {
19065b24c071SSam Ravnborg 	int i;
19075b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19085b24c071SSam Ravnborg 
19095b24c071SSam Ravnborg 	/* Walk through all sections */
19101ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1911b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19125b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19135b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
191410668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19155b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
191610668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1917b39927cfSSam Ravnborg 	}
1918b39927cfSSam Ravnborg }
1919b39927cfSSam Ravnborg 
19207d02b490SAndi Kleen static char *remove_dot(char *s)
19217d02b490SAndi Kleen {
1922fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19237d02b490SAndi Kleen 
1924fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1925fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1926fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
19277d02b490SAndi Kleen 			s[n] = 0;
19287d02b490SAndi Kleen 	}
19297d02b490SAndi Kleen 	return s;
19307d02b490SAndi Kleen }
19317d02b490SAndi Kleen 
19325c3ead8cSSam Ravnborg static void read_symbols(char *modname)
19331da177e4SLinus Torvalds {
19341da177e4SLinus Torvalds 	const char *symname;
19351da177e4SLinus Torvalds 	char *version;
1936b817f6feSSam Ravnborg 	char *license;
19371da177e4SLinus Torvalds 	struct module *mod;
19381da177e4SLinus Torvalds 	struct elf_info info = { };
19391da177e4SLinus Torvalds 	Elf_Sym *sym;
19401da177e4SLinus Torvalds 
194185bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
194285bd2fddSSam Ravnborg 		return;
19431da177e4SLinus Torvalds 
19441da177e4SLinus Torvalds 	mod = new_module(modname);
19451da177e4SLinus Torvalds 
19461da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
19471da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
19481da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
19491da177e4SLinus Torvalds 		have_vmlinux = 1;
19501da177e4SLinus Torvalds 		mod->skip = 1;
19511da177e4SLinus Torvalds 	}
19521da177e4SLinus Torvalds 
1953b817f6feSSam Ravnborg 	license = get_modinfo(info.modinfo, info.modinfo_len, "license");
19542fa36568SSam Ravnborg 	if (info.modinfo && !license && !is_vmlinux(modname))
19552fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
1956eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
1957eed7d279SSam Ravnborg 		     "more information\n", modname);
1958b817f6feSSam Ravnborg 	while (license) {
1959b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
1960b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
1961b817f6feSSam Ravnborg 		else {
1962b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
1963b817f6feSSam Ravnborg 			break;
1964b817f6feSSam Ravnborg 		}
1965b817f6feSSam Ravnborg 		license = get_next_modinfo(info.modinfo, info.modinfo_len,
1966b817f6feSSam Ravnborg 					   "license", license);
1967b817f6feSSam Ravnborg 	}
1968b817f6feSSam Ravnborg 
19691da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
19707d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
19711da177e4SLinus Torvalds 
19721da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
19731da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
19741da177e4SLinus Torvalds 	}
1975d1f25e66SSam Ravnborg 	if (!is_vmlinux(modname) ||
197610668220SSam Ravnborg 	     (is_vmlinux(modname) && vmlinux_section_warnings))
197710668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
19781da177e4SLinus Torvalds 
19791da177e4SLinus Torvalds 	version = get_modinfo(info.modinfo, info.modinfo_len, "version");
19801da177e4SLinus Torvalds 	if (version)
19811da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
19821da177e4SLinus Torvalds 				       version - (char *)info.hdr);
19831da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
19841da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
19851da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
19861da177e4SLinus Torvalds 
19871da177e4SLinus Torvalds 	parse_elf_finish(&info);
19881da177e4SLinus Torvalds 
19898c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
19901da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
19911da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
19921da177e4SLinus Torvalds 	 * important anyhow */
19931da177e4SLinus Torvalds 	if (modversions)
19948c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
19951da177e4SLinus Torvalds }
19961da177e4SLinus Torvalds 
1997712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
1998712f9b46SRusty Russell {
1999712f9b46SRusty Russell 	FILE *in = stdin;
2000712f9b46SRusty Russell 	char fname[PATH_MAX];
2001712f9b46SRusty Russell 
2002712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2003712f9b46SRusty Russell 		in = fopen(filename, "r");
2004712f9b46SRusty Russell 		if (!in)
2005712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2006712f9b46SRusty Russell 	}
2007712f9b46SRusty Russell 
2008712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2009712f9b46SRusty Russell 		if (strends(fname, "\n"))
2010712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2011712f9b46SRusty Russell 		read_symbols(fname);
2012712f9b46SRusty Russell 	}
2013712f9b46SRusty Russell 
2014712f9b46SRusty Russell 	if (in != stdin)
2015712f9b46SRusty Russell 		fclose(in);
2016712f9b46SRusty Russell }
2017712f9b46SRusty Russell 
20181da177e4SLinus Torvalds #define SZ 500
20191da177e4SLinus Torvalds 
20201da177e4SLinus Torvalds /* We first write the generated file into memory using the
20211da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
20221da177e4SLinus Torvalds  * only update the later if anything changed */
20231da177e4SLinus Torvalds 
20245c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
20255c3ead8cSSam Ravnborg 						      const char *fmt, ...)
20261da177e4SLinus Torvalds {
20271da177e4SLinus Torvalds 	char tmp[SZ];
20281da177e4SLinus Torvalds 	int len;
20291da177e4SLinus Torvalds 	va_list ap;
20301da177e4SLinus Torvalds 
20311da177e4SLinus Torvalds 	va_start(ap, fmt);
20321da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
20337670f023SSam Ravnborg 	buf_write(buf, tmp, len);
20341da177e4SLinus Torvalds 	va_end(ap);
20351da177e4SLinus Torvalds }
20361da177e4SLinus Torvalds 
20375c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
20381da177e4SLinus Torvalds {
20391da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
20407670f023SSam Ravnborg 		buf->size += len + SZ;
20411da177e4SLinus Torvalds 		buf->p = realloc(buf->p, buf->size);
20421da177e4SLinus Torvalds 	}
20431da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
20441da177e4SLinus Torvalds 	buf->pos += len;
20451da177e4SLinus Torvalds }
20461da177e4SLinus Torvalds 
2047c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2048c96fca21SSam Ravnborg {
2049c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2050c96fca21SSam Ravnborg 
2051c96fca21SSam Ravnborg 	switch (exp) {
2052c96fca21SSam Ravnborg 	case export_gpl:
2053c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2054c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2055c96fca21SSam Ravnborg 		break;
2056c96fca21SSam Ravnborg 	case export_unused_gpl:
2057c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2058c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2059c96fca21SSam Ravnborg 		break;
2060c96fca21SSam Ravnborg 	case export_gpl_future:
2061c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2062c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2063c96fca21SSam Ravnborg 		break;
2064c96fca21SSam Ravnborg 	case export_plain:
2065c96fca21SSam Ravnborg 	case export_unused:
2066c96fca21SSam Ravnborg 	case export_unknown:
2067c96fca21SSam Ravnborg 		/* ignore */
2068c96fca21SSam Ravnborg 		break;
2069c96fca21SSam Ravnborg 	}
2070c96fca21SSam Ravnborg }
2071c96fca21SSam Ravnborg 
2072c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2073c96fca21SSam Ravnborg {
2074c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2075c96fca21SSam Ravnborg 
2076c96fca21SSam Ravnborg 	switch (exp) {
2077c96fca21SSam Ravnborg 	case export_unused:
2078c96fca21SSam Ravnborg 	case export_unused_gpl:
2079c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2080c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2081c96fca21SSam Ravnborg 		break;
2082c96fca21SSam Ravnborg 	default:
2083c96fca21SSam Ravnborg 		/* ignore */
2084c96fca21SSam Ravnborg 		break;
2085c96fca21SSam Ravnborg 	}
2086c96fca21SSam Ravnborg }
2087c96fca21SSam Ravnborg 
2088c96fca21SSam Ravnborg static void check_exports(struct module *mod)
2089b817f6feSSam Ravnborg {
2090b817f6feSSam Ravnborg 	struct symbol *s, *exp;
2091b817f6feSSam Ravnborg 
2092b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
20936449bd62SAndrew Morton 		const char *basename;
2094b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
2095b817f6feSSam Ravnborg 		if (!exp || exp->module == mod)
2096b817f6feSSam Ravnborg 			continue;
20976449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2098b817f6feSSam Ravnborg 		if (basename)
2099b817f6feSSam Ravnborg 			basename++;
2100c96fca21SSam Ravnborg 		else
2101c96fca21SSam Ravnborg 			basename = mod->name;
2102c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2103c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2104c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2105b817f6feSSam Ravnborg 	}
2106b817f6feSSam Ravnborg }
2107b817f6feSSam Ravnborg 
21085c3ead8cSSam Ravnborg /**
21095c3ead8cSSam Ravnborg  * Header for the generated file
21105c3ead8cSSam Ravnborg  **/
21115c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
21121da177e4SLinus Torvalds {
21131da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
21141da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
21151da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
21161da177e4SLinus Torvalds 	buf_printf(b, "\n");
21171da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
21181da177e4SLinus Torvalds 	buf_printf(b, "\n");
2119e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
21201da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
21213c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
21221da177e4SLinus Torvalds 	if (mod->has_init)
21233c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
21241da177e4SLinus Torvalds 	if (mod->has_cleanup)
21251da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
21263c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
21271da177e4SLinus Torvalds 			      "#endif\n");
21283c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
21291da177e4SLinus Torvalds 	buf_printf(b, "};\n");
21301da177e4SLinus Torvalds }
21311da177e4SLinus Torvalds 
21322449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
21332449b8baSBen Hutchings {
21342449b8baSBen Hutchings 	if (is_intree)
21352449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
21362449b8baSBen Hutchings }
21372449b8baSBen Hutchings 
21385c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2139a9860bf0SGreg Kroah-Hartman {
2140a9860bf0SGreg Kroah-Hartman 	static const char *staging_dir = "drivers/staging";
2141a9860bf0SGreg Kroah-Hartman 
2142a9860bf0SGreg Kroah-Hartman 	if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
2143a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2144a9860bf0SGreg Kroah-Hartman }
2145a9860bf0SGreg Kroah-Hartman 
21465cfb203aSTakashi Iwai /* In kernel, this size is defined in linux/module.h;
21475cfb203aSTakashi Iwai  * here we use Elf_Addr instead of long for covering cross-compile
21485cfb203aSTakashi Iwai  */
21495cfb203aSTakashi Iwai #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
21505cfb203aSTakashi Iwai 
21515c3ead8cSSam Ravnborg /**
21525c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
21535c3ead8cSSam Ravnborg  **/
2154c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
21551da177e4SLinus Torvalds {
21561da177e4SLinus Torvalds 	struct symbol *s, *exp;
2157c53ddacdSKirill Korotaev 	int err = 0;
21581da177e4SLinus Torvalds 
21591da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
21601da177e4SLinus Torvalds 		exp = find_symbol(s->name);
21611da177e4SLinus Torvalds 		if (!exp || exp->module == mod) {
2162c53ddacdSKirill Korotaev 			if (have_vmlinux && !s->weak) {
21632a116659SMatthew Wilcox 				if (warn_unresolved) {
2164cb80514dSSam Ravnborg 					warn("\"%s\" [%s.ko] undefined!\n",
2165cb80514dSSam Ravnborg 					     s->name, mod->name);
21662a116659SMatthew Wilcox 				} else {
21672a116659SMatthew Wilcox 					merror("\"%s\" [%s.ko] undefined!\n",
21682a116659SMatthew Wilcox 					       s->name, mod->name);
21692a116659SMatthew Wilcox 					err = 1;
21702a116659SMatthew Wilcox 				}
2171c53ddacdSKirill Korotaev 			}
21721da177e4SLinus Torvalds 			continue;
21731da177e4SLinus Torvalds 		}
21741da177e4SLinus Torvalds 		s->module = exp->module;
21751da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
21761da177e4SLinus Torvalds 		s->crc = exp->crc;
21771da177e4SLinus Torvalds 	}
21781da177e4SLinus Torvalds 
21791da177e4SLinus Torvalds 	if (!modversions)
2180c53ddacdSKirill Korotaev 		return err;
21811da177e4SLinus Torvalds 
21821da177e4SLinus Torvalds 	buf_printf(b, "\n");
21831da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
21843ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
21851da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
21861da177e4SLinus Torvalds 
21871da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2188df578e7dSSam Ravnborg 		if (!s->module)
21891da177e4SLinus Torvalds 			continue;
21901da177e4SLinus Torvalds 		if (!s->crc_valid) {
2191cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
21921da177e4SLinus Torvalds 				s->name, mod->name);
21931da177e4SLinus Torvalds 			continue;
21941da177e4SLinus Torvalds 		}
21955cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
21965cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
21975cfb203aSTakashi Iwai 			       s->name, mod->name);
21985cfb203aSTakashi Iwai 			err = 1;
21995cfb203aSTakashi Iwai 			break;
22005cfb203aSTakashi Iwai 		}
2201a53a11f3SJames Hogan 		buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n",
2202a4b6a77bSJames Hogan 			   s->crc, s->name);
22031da177e4SLinus Torvalds 	}
22041da177e4SLinus Torvalds 
22051da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2206c53ddacdSKirill Korotaev 
2207c53ddacdSKirill Korotaev 	return err;
22081da177e4SLinus Torvalds }
22091da177e4SLinus Torvalds 
22105c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod,
22115c3ead8cSSam Ravnborg 			struct module *modules)
22121da177e4SLinus Torvalds {
22131da177e4SLinus Torvalds 	struct symbol *s;
22141da177e4SLinus Torvalds 	struct module *m;
22151da177e4SLinus Torvalds 	int first = 1;
22161da177e4SLinus Torvalds 
2217df578e7dSSam Ravnborg 	for (m = modules; m; m = m->next)
22181da177e4SLinus Torvalds 		m->seen = is_vmlinux(m->name);
22191da177e4SLinus Torvalds 
22201da177e4SLinus Torvalds 	buf_printf(b, "\n");
22211da177e4SLinus Torvalds 	buf_printf(b, "static const char __module_depends[]\n");
22223ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22231da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
22241da177e4SLinus Torvalds 	buf_printf(b, "\"depends=");
22251da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2226a61b2dfdSSam Ravnborg 		const char *p;
22271da177e4SLinus Torvalds 		if (!s->module)
22281da177e4SLinus Torvalds 			continue;
22291da177e4SLinus Torvalds 
22301da177e4SLinus Torvalds 		if (s->module->seen)
22311da177e4SLinus Torvalds 			continue;
22321da177e4SLinus Torvalds 
22331da177e4SLinus Torvalds 		s->module->seen = 1;
2234df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2235df578e7dSSam Ravnborg 		if (p)
2236a61b2dfdSSam Ravnborg 			p++;
2237a61b2dfdSSam Ravnborg 		else
2238a61b2dfdSSam Ravnborg 			p = s->module->name;
2239a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
22401da177e4SLinus Torvalds 		first = 0;
22411da177e4SLinus Torvalds 	}
22421da177e4SLinus Torvalds 	buf_printf(b, "\";\n");
22431da177e4SLinus Torvalds }
22441da177e4SLinus Torvalds 
22455c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
22461da177e4SLinus Torvalds {
22471da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
22481da177e4SLinus Torvalds 		buf_printf(b, "\n");
22491da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
22501da177e4SLinus Torvalds 			   mod->srcversion);
22511da177e4SLinus Torvalds 	}
22521da177e4SLinus Torvalds }
22531da177e4SLinus Torvalds 
22545c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
22551da177e4SLinus Torvalds {
22561da177e4SLinus Torvalds 	char *tmp;
22571da177e4SLinus Torvalds 	FILE *file;
22581da177e4SLinus Torvalds 	struct stat st;
22591da177e4SLinus Torvalds 
22601da177e4SLinus Torvalds 	file = fopen(fname, "r");
22611da177e4SLinus Torvalds 	if (!file)
22621da177e4SLinus Torvalds 		goto write;
22631da177e4SLinus Torvalds 
22641da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
22651da177e4SLinus Torvalds 		goto close_write;
22661da177e4SLinus Torvalds 
22671da177e4SLinus Torvalds 	if (st.st_size != b->pos)
22681da177e4SLinus Torvalds 		goto close_write;
22691da177e4SLinus Torvalds 
22701da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
22711da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
22721da177e4SLinus Torvalds 		goto free_write;
22731da177e4SLinus Torvalds 
22741da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
22751da177e4SLinus Torvalds 		goto free_write;
22761da177e4SLinus Torvalds 
22771da177e4SLinus Torvalds 	free(tmp);
22781da177e4SLinus Torvalds 	fclose(file);
22791da177e4SLinus Torvalds 	return;
22801da177e4SLinus Torvalds 
22811da177e4SLinus Torvalds  free_write:
22821da177e4SLinus Torvalds 	free(tmp);
22831da177e4SLinus Torvalds  close_write:
22841da177e4SLinus Torvalds 	fclose(file);
22851da177e4SLinus Torvalds  write:
22861da177e4SLinus Torvalds 	file = fopen(fname, "w");
22871da177e4SLinus Torvalds 	if (!file) {
22881da177e4SLinus Torvalds 		perror(fname);
22891da177e4SLinus Torvalds 		exit(1);
22901da177e4SLinus Torvalds 	}
22911da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
22921da177e4SLinus Torvalds 		perror(fname);
22931da177e4SLinus Torvalds 		exit(1);
22941da177e4SLinus Torvalds 	}
22951da177e4SLinus Torvalds 	fclose(file);
22961da177e4SLinus Torvalds }
22971da177e4SLinus Torvalds 
2298bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2299534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2300bd5cbcedSRam Pai  **/
2301040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
23021da177e4SLinus Torvalds {
23031da177e4SLinus Torvalds 	unsigned long size, pos = 0;
23041da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
23051da177e4SLinus Torvalds 	char *line;
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds 	if (!file)
23081da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
23091da177e4SLinus Torvalds 		return;
23101da177e4SLinus Torvalds 
23111da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2312534b89a9SSam Ravnborg 		char *symname, *modname, *d, *export, *end;
23131da177e4SLinus Torvalds 		unsigned int crc;
23141da177e4SLinus Torvalds 		struct module *mod;
2315040fcc81SSam Ravnborg 		struct symbol *s;
23161da177e4SLinus Torvalds 
23171da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
23181da177e4SLinus Torvalds 			goto fail;
23191da177e4SLinus Torvalds 		*symname++ = '\0';
23201da177e4SLinus Torvalds 		if (!(modname = strchr(symname, '\t')))
23211da177e4SLinus Torvalds 			goto fail;
23221da177e4SLinus Torvalds 		*modname++ = '\0';
23239ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2324bd5cbcedSRam Pai 			*export++ = '\0';
2325534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2326534b89a9SSam Ravnborg 			*end = '\0';
23271da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
23281da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
23291da177e4SLinus Torvalds 			goto fail;
2330df578e7dSSam Ravnborg 		mod = find_module(modname);
2331df578e7dSSam Ravnborg 		if (!mod) {
2332df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
23331da177e4SLinus Torvalds 				have_vmlinux = 1;
23340fa3a88cSJan Beulich 			mod = new_module(modname);
23351da177e4SLinus Torvalds 			mod->skip = 1;
23361da177e4SLinus Torvalds 		}
2337bd5cbcedSRam Pai 		s = sym_add_exported(symname, mod, export_no(export));
2338040fcc81SSam Ravnborg 		s->kernel    = kernel;
23398e70c458SSam Ravnborg 		s->preloaded = 1;
2340bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
23411da177e4SLinus Torvalds 	}
23422ee41e62SChristian Engelmayer 	release_file(file, size);
23431da177e4SLinus Torvalds 	return;
23441da177e4SLinus Torvalds fail:
23452ee41e62SChristian Engelmayer 	release_file(file, size);
23461da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
23471da177e4SLinus Torvalds }
23481da177e4SLinus Torvalds 
2349040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2350040fcc81SSam Ravnborg  * For external modules only dump symbols
2351040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2352040fcc81SSam Ravnborg  **/
2353040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2354040fcc81SSam Ravnborg {
2355040fcc81SSam Ravnborg 	if (!external_module)
2356040fcc81SSam Ravnborg 		return 1;
2357040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2358040fcc81SSam Ravnborg 		return 0;
2359040fcc81SSam Ravnborg 	return 1;
2360040fcc81SSam Ravnborg }
2361040fcc81SSam Ravnborg 
23625c3ead8cSSam Ravnborg static void write_dump(const char *fname)
23631da177e4SLinus Torvalds {
23641da177e4SLinus Torvalds 	struct buffer buf = { };
23651da177e4SLinus Torvalds 	struct symbol *symbol;
23661da177e4SLinus Torvalds 	int n;
23671da177e4SLinus Torvalds 
23681da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
23691da177e4SLinus Torvalds 		symbol = symbolhash[n];
23701da177e4SLinus Torvalds 		while (symbol) {
2371040fcc81SSam Ravnborg 			if (dump_sym(symbol))
2372bd5cbcedSRam Pai 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
2373040fcc81SSam Ravnborg 					symbol->crc, symbol->name,
2374bd5cbcedSRam Pai 					symbol->module->name,
2375bd5cbcedSRam Pai 					export_str(symbol->export));
23761da177e4SLinus Torvalds 			symbol = symbol->next;
23771da177e4SLinus Torvalds 		}
23781da177e4SLinus Torvalds 	}
23791da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
23801da177e4SLinus Torvalds }
23811da177e4SLinus Torvalds 
23822d04b5aeSRichard Hacker struct ext_sym_list {
23832d04b5aeSRichard Hacker 	struct ext_sym_list *next;
23842d04b5aeSRichard Hacker 	const char *file;
23852d04b5aeSRichard Hacker };
23862d04b5aeSRichard Hacker 
23875c3ead8cSSam Ravnborg int main(int argc, char **argv)
23881da177e4SLinus Torvalds {
23891da177e4SLinus Torvalds 	struct module *mod;
23901da177e4SLinus Torvalds 	struct buffer buf = { };
2391040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2392712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
23931da177e4SLinus Torvalds 	int opt;
2394c53ddacdSKirill Korotaev 	int err;
23952d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
23962d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
23971da177e4SLinus Torvalds 
239847490ec1SNicolas Boichat 	while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:E")) != -1) {
23991da177e4SLinus Torvalds 		switch (opt) {
24001da177e4SLinus Torvalds 		case 'i':
2401040fcc81SSam Ravnborg 			kernel_read = optarg;
2402040fcc81SSam Ravnborg 			break;
2403040fcc81SSam Ravnborg 		case 'I':
2404040fcc81SSam Ravnborg 			module_read = optarg;
2405040fcc81SSam Ravnborg 			external_module = 1;
24061da177e4SLinus Torvalds 			break;
24072d04b5aeSRichard Hacker 		case 'e':
24082d04b5aeSRichard Hacker 			external_module = 1;
24092d04b5aeSRichard Hacker 			extsym_iter =
24102d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
24112d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
24122d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
24132d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
24142d04b5aeSRichard Hacker 			break;
24151da177e4SLinus Torvalds 		case 'm':
24161da177e4SLinus Torvalds 			modversions = 1;
24171da177e4SLinus Torvalds 			break;
2418eed380f3SGuenter Roeck 		case 'n':
2419eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2420eed380f3SGuenter Roeck 			break;
24211da177e4SLinus Torvalds 		case 'o':
24221da177e4SLinus Torvalds 			dump_write = optarg;
24231da177e4SLinus Torvalds 			break;
24241da177e4SLinus Torvalds 		case 'a':
24251da177e4SLinus Torvalds 			all_versions = 1;
24261da177e4SLinus Torvalds 			break;
24278d8d8289SSam Ravnborg 		case 's':
24288d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
24298d8d8289SSam Ravnborg 			break;
2430588ccd73SSam Ravnborg 		case 'S':
2431588ccd73SSam Ravnborg 			sec_mismatch_verbose = 0;
2432588ccd73SSam Ravnborg 			break;
2433712f9b46SRusty Russell 		case 'T':
2434712f9b46SRusty Russell 			files_source = optarg;
2435712f9b46SRusty Russell 			break;
2436c53ddacdSKirill Korotaev 		case 'w':
2437c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2438c53ddacdSKirill Korotaev 			break;
243947490ec1SNicolas Boichat 		case 'E':
244047490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
244147490ec1SNicolas Boichat 			break;
24421da177e4SLinus Torvalds 		default:
24431da177e4SLinus Torvalds 			exit(1);
24441da177e4SLinus Torvalds 		}
24451da177e4SLinus Torvalds 	}
24461da177e4SLinus Torvalds 
2447040fcc81SSam Ravnborg 	if (kernel_read)
2448040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2449040fcc81SSam Ravnborg 	if (module_read)
2450040fcc81SSam Ravnborg 		read_dump(module_read, 0);
24512d04b5aeSRichard Hacker 	while (extsym_start) {
24522d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
24532d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
24542d04b5aeSRichard Hacker 		free(extsym_start);
24552d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
24562d04b5aeSRichard Hacker 	}
24571da177e4SLinus Torvalds 
2458df578e7dSSam Ravnborg 	while (optind < argc)
24591da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
24601da177e4SLinus Torvalds 
2461712f9b46SRusty Russell 	if (files_source)
2462712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2463712f9b46SRusty Russell 
24641da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next) {
24651da177e4SLinus Torvalds 		if (mod->skip)
24661da177e4SLinus Torvalds 			continue;
2467c96fca21SSam Ravnborg 		check_exports(mod);
2468b817f6feSSam Ravnborg 	}
2469b817f6feSSam Ravnborg 
2470c53ddacdSKirill Korotaev 	err = 0;
2471c53ddacdSKirill Korotaev 
2472b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2473d93e1719SMathias Krause 		char fname[PATH_MAX];
2474666ab414SAndi Kleen 
2475b817f6feSSam Ravnborg 		if (mod->skip)
2476b817f6feSSam Ravnborg 			continue;
24771da177e4SLinus Torvalds 
24781da177e4SLinus Torvalds 		buf.pos = 0;
24791da177e4SLinus Torvalds 
24801da177e4SLinus Torvalds 		add_header(&buf, mod);
24812449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2482a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2483c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
24841da177e4SLinus Torvalds 		add_depends(&buf, mod, modules);
24851da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
24861da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
24871da177e4SLinus Torvalds 
24881da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
24891da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
24901da177e4SLinus Torvalds 	}
24911da177e4SLinus Torvalds 	if (dump_write)
24921da177e4SLinus Torvalds 		write_dump(dump_write);
249347490ec1SNicolas Boichat 	if (sec_mismatch_count) {
249447490ec1SNicolas Boichat 		if (!sec_mismatch_verbose) {
24957c0ac495SGeert Uytterhoeven 			warn("modpost: Found %d section mismatch(es).\n"
2496e5f95c8bSSam Ravnborg 			     "To see full details build your kernel with:\n"
2497e5f95c8bSSam Ravnborg 			     "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n",
2498e5f95c8bSSam Ravnborg 			     sec_mismatch_count);
249947490ec1SNicolas Boichat 		}
250047490ec1SNicolas Boichat 		if (sec_mismatch_fatal) {
250147490ec1SNicolas Boichat 			fatal("modpost: Section mismatches detected.\n"
250247490ec1SNicolas Boichat 			      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
250347490ec1SNicolas Boichat 		}
250447490ec1SNicolas Boichat 	}
25051da177e4SLinus Torvalds 
2506c53ddacdSKirill Korotaev 	return err;
25071da177e4SLinus Torvalds }
2508