xref: /linux-6.15/scripts/mod/modpost.c (revision a3d0cb04)
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"
22b817f6feSSam Ravnborg #include "../../include/linux/license.h"
239e1b9b80SAlan Jenkins 
241da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
257a3ee753SMathias Krause static int modversions = 0;
261da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
277a3ee753SMathias Krause static int have_vmlinux = 0;
281da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
291da177e4SLinus Torvalds static int all_versions = 0;
30040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
31040fcc81SSam Ravnborg static int external_module = 0;
328d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
338d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
34c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
35c53ddacdSKirill Korotaev static int warn_unresolved = 0;
36bd5cbcedSRam Pai /* How a symbol is exported */
37588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
3847490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
39eed380f3SGuenter Roeck /* ignore missing files */
40eed380f3SGuenter Roeck static int ignore_missing_files;
41588ccd73SSam Ravnborg 
42c96fca21SSam Ravnborg enum export {
43c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
44c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
45c96fca21SSam Ravnborg };
461da177e4SLinus Torvalds 
474fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h;
484fd3e4efSWanlong Gao  * here we use Elf_Addr instead of long for covering cross-compile
494fd3e4efSWanlong Gao  */
504fd3e4efSWanlong Gao 
514fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
524fd3e4efSWanlong Gao 
536d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
546d9a89eaSAndi Kleen 
556d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds 	va_list arglist;
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	va_start(arglist, fmt);
621da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
631da177e4SLinus Torvalds 	va_end(arglist);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	exit(1);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
686d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	va_list arglist;
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	va_start(arglist, fmt);
751da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
761da177e4SLinus Torvalds 	va_end(arglist);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
796d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
802a116659SMatthew Wilcox {
812a116659SMatthew Wilcox 	va_list arglist;
822a116659SMatthew Wilcox 
832a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
842a116659SMatthew Wilcox 
852a116659SMatthew Wilcox 	va_start(arglist, fmt);
862a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
872a116659SMatthew Wilcox 	va_end(arglist);
882a116659SMatthew Wilcox }
892a116659SMatthew Wilcox 
90d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
91d4ef1c30SRusty Russell {
92d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
93d4ef1c30SRusty Russell 		return false;
94d4ef1c30SRusty Russell 
95d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
96d4ef1c30SRusty Russell }
97d4ef1c30SRusty Russell 
98040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
99040fcc81SSam Ravnborg {
100040fcc81SSam Ravnborg 	const char *myname;
101040fcc81SSam Ravnborg 
102df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
103df578e7dSSam Ravnborg 	if (myname)
104040fcc81SSam Ravnborg 		myname++;
105040fcc81SSam Ravnborg 	else
106040fcc81SSam Ravnborg 		myname = modname;
107040fcc81SSam Ravnborg 
108741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
109741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
110040fcc81SSam Ravnborg }
111040fcc81SSam Ravnborg 
1121da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1131da177e4SLinus Torvalds {
114df578e7dSSam Ravnborg 	if (!ptr)
1151da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
116df578e7dSSam Ravnborg 
1171da177e4SLinus Torvalds 	return ptr;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds /* A list of all modules we processed */
1211da177e4SLinus Torvalds static struct module *modules;
1221da177e4SLinus Torvalds 
1238b185743SMasahiro Yamada static struct module *find_module(const char *modname)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	struct module *mod;
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1281da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1291da177e4SLinus Torvalds 			break;
1301da177e4SLinus Torvalds 	return mod;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
133d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	struct module *mod;
136d4ef1c30SRusty Russell 	char *p;
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1391da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1401da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 	/* strip trailing .o */
143d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
144d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
145258f7426SFrank Rowand 		mod->is_dot_o = 1;
146258f7426SFrank Rowand 	}
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	/* add to list */
1491da177e4SLinus Torvalds 	mod->name = p;
150b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1511da177e4SLinus Torvalds 	mod->next = modules;
1521da177e4SLinus Torvalds 	modules = mod;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	return mod;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /* A hash of all exported symbols,
1581da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds struct symbol {
1631da177e4SLinus Torvalds 	struct symbol *next;
1641da177e4SLinus Torvalds 	struct module *module;
1651da177e4SLinus Torvalds 	unsigned int crc;
1661da177e4SLinus Torvalds 	int crc_valid;
1671da177e4SLinus Torvalds 	unsigned int weak:1;
168040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
169040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
170040fcc81SSam Ravnborg 				    *  (only for external modules) **/
171b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
17215bfc234SDenis Efremov 	unsigned int is_static:1;  /* 1 if symbol is not global */
173bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1741da177e4SLinus Torvalds 	char name[0];
1751da177e4SLinus Torvalds };
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1801da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1831da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1861da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1871da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1901da177e4SLinus Torvalds }
1911da177e4SLinus Torvalds 
1925c3ead8cSSam Ravnborg /**
1935c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1945c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1955c3ead8cSSam Ravnborg  **/
1965c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1975c3ead8cSSam Ravnborg 				   struct symbol *next)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
2021da177e4SLinus Torvalds 	strcpy(s->name, name);
2031da177e4SLinus Torvalds 	s->weak = weak;
2041da177e4SLinus Torvalds 	s->next = next;
20515bfc234SDenis Efremov 	s->is_static = 1;
2061da177e4SLinus Torvalds 	return s;
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /* For the hash of exported symbols */
210bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
211bd5cbcedSRam Pai 				 enum export export)
2121da177e4SLinus Torvalds {
2131da177e4SLinus Torvalds 	unsigned int hash;
2141da177e4SLinus Torvalds 	struct symbol *new;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2171da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2181da177e4SLinus Torvalds 	new->module = module;
219bd5cbcedSRam Pai 	new->export = export;
220040fcc81SSam Ravnborg 	return new;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
2235c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2241da177e4SLinus Torvalds {
2251da177e4SLinus Torvalds 	struct symbol *s;
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2281da177e4SLinus Torvalds 	if (name[0] == '.')
2291da177e4SLinus Torvalds 		name++;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2321da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2331da177e4SLinus Torvalds 			return s;
2341da177e4SLinus Torvalds 	}
2351da177e4SLinus Torvalds 	return NULL;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds 
2387a3ee753SMathias Krause static const struct {
239bd5cbcedSRam Pai 	const char *str;
240bd5cbcedSRam Pai 	enum export export;
241bd5cbcedSRam Pai } export_list[] = {
242bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
243c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
244bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
245c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
246bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
247bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
248bd5cbcedSRam Pai };
249bd5cbcedSRam Pai 
250bd5cbcedSRam Pai 
251bd5cbcedSRam Pai static const char *export_str(enum export ex)
252bd5cbcedSRam Pai {
253bd5cbcedSRam Pai 	return export_list[ex].str;
254bd5cbcedSRam Pai }
255bd5cbcedSRam Pai 
256bd5cbcedSRam Pai static enum export export_no(const char *s)
257bd5cbcedSRam Pai {
258bd5cbcedSRam Pai 	int i;
259df578e7dSSam Ravnborg 
260534b89a9SSam Ravnborg 	if (!s)
261534b89a9SSam Ravnborg 		return export_unknown;
262bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
263bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
264bd5cbcedSRam Pai 			return export_list[i].export;
265bd5cbcedSRam Pai 	}
266bd5cbcedSRam Pai 	return export_unknown;
267bd5cbcedSRam Pai }
268bd5cbcedSRam Pai 
2696124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
2706124c04cSMasahiro Yamada {
2716124c04cSMasahiro Yamada 	return (void *)elf->hdr +
2726124c04cSMasahiro Yamada 		elf->sechdrs[elf->secindex_strings].sh_offset +
2736124c04cSMasahiro Yamada 		sechdr->sh_name;
2746124c04cSMasahiro Yamada }
2756124c04cSMasahiro Yamada 
2766124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex)
2776124c04cSMasahiro Yamada {
2786124c04cSMasahiro Yamada 	return sech_name(elf, &elf->sechdrs[secindex]);
2796124c04cSMasahiro Yamada }
28062a26356SAlessio Igor Bogani 
28162a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
28262a26356SAlessio Igor Bogani 
28362a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
28462a26356SAlessio Igor Bogani {
28562a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
28662a26356SAlessio Igor Bogani 
28762a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
28862a26356SAlessio Igor Bogani 		return export_plain;
28962a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
29062a26356SAlessio Igor Bogani 		return export_unused;
29162a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
29262a26356SAlessio Igor Bogani 		return export_gpl;
29362a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
29462a26356SAlessio Igor Bogani 		return export_unused_gpl;
29562a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
29662a26356SAlessio Igor Bogani 		return export_gpl_future;
29762a26356SAlessio Igor Bogani 	else
29862a26356SAlessio Igor Bogani 		return export_unknown;
29962a26356SAlessio Igor Bogani }
30062a26356SAlessio Igor Bogani 
3011ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
302bd5cbcedSRam Pai {
303bd5cbcedSRam Pai 	if (sec == elf->export_sec)
304bd5cbcedSRam Pai 		return export_plain;
305c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
306c96fca21SSam Ravnborg 		return export_unused;
307bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
308bd5cbcedSRam Pai 		return export_gpl;
309c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
310c96fca21SSam Ravnborg 		return export_unused_gpl;
311bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
312bd5cbcedSRam Pai 		return export_gpl_future;
313bd5cbcedSRam Pai 	else
314bd5cbcedSRam Pai 		return export_unknown;
315bd5cbcedSRam Pai }
316bd5cbcedSRam Pai 
3175c3ead8cSSam Ravnborg /**
3185c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3195c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3205c3ead8cSSam Ravnborg  **/
321bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod,
322bd5cbcedSRam Pai 				       enum export export)
3231da177e4SLinus Torvalds {
3241da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 	if (!s) {
327bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3288e70c458SSam Ravnborg 	} else {
3298e70c458SSam Ravnborg 		if (!s->preloaded) {
3307b75b13cSSam Ravnborg 			warn("%s: '%s' exported twice. Previous export "
3318e70c458SSam Ravnborg 			     "was in %s%s\n", mod->name, name,
3328e70c458SSam Ravnborg 			     s->module->name,
3338e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ?"":".ko");
3344b21960fSTrent Piepho 		} else {
335baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3364b21960fSTrent Piepho 			s->module = mod;
3371da177e4SLinus Torvalds 		}
3381da177e4SLinus Torvalds 	}
3398e70c458SSam Ravnborg 	s->preloaded = 0;
340040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
341040fcc81SSam Ravnborg 	s->kernel    = 0;
342bd5cbcedSRam Pai 	s->export    = export;
343040fcc81SSam Ravnborg 	return s;
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds 
346040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
347bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
348040fcc81SSam Ravnborg {
349040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
350040fcc81SSam Ravnborg 
351b6568b1aSRusty Russell 	if (!s) {
352bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
353b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
354b6568b1aSRusty Russell 		s->preloaded = 1;
355b6568b1aSRusty Russell 	}
356040fcc81SSam Ravnborg 	s->crc = crc;
3571da177e4SLinus Torvalds 	s->crc_valid = 1;
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds 
3605c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
3611da177e4SLinus Torvalds {
3621da177e4SLinus Torvalds 	struct stat st;
363eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
3641da177e4SLinus Torvalds 	int fd;
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
367eb3d5cc6SJesper Juhl 	if (fd < 0)
3681da177e4SLinus Torvalds 		return NULL;
369eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
370eb3d5cc6SJesper Juhl 		goto failed;
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	*size = st.st_size;
3731da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
3741da177e4SLinus Torvalds 
375eb3d5cc6SJesper Juhl failed:
376eb3d5cc6SJesper Juhl 	close(fd);
3771da177e4SLinus Torvalds 	if (map == MAP_FAILED)
3781da177e4SLinus Torvalds 		return NULL;
3791da177e4SLinus Torvalds 	return map;
3801da177e4SLinus Torvalds }
3811da177e4SLinus Torvalds 
3825c3ead8cSSam Ravnborg /**
3835c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
3845c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
3855c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
3865c3ead8cSSam Ravnborg   **/
3875c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
3881da177e4SLinus Torvalds {
3891da177e4SLinus Torvalds 	static char line[4096];
3901da177e4SLinus Torvalds 	int skip = 1;
3911da177e4SLinus Torvalds 	size_t len = 0;
3921da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
3931da177e4SLinus Torvalds 	char *s = line;
3941da177e4SLinus Torvalds 
395df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
3961da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
3971da177e4SLinus Torvalds 			p++;
3981da177e4SLinus Torvalds 			continue;
3991da177e4SLinus Torvalds 		}
4001da177e4SLinus Torvalds 		skip = 0;
4011da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4021da177e4SLinus Torvalds 			len++;
4031da177e4SLinus Torvalds 			*s++ = *p++;
4041da177e4SLinus Torvalds 			if (len > 4095)
4051da177e4SLinus Torvalds 				break; /* Too long, stop */
4061da177e4SLinus Torvalds 		} else {
4071da177e4SLinus Torvalds 			/* End of string */
4081da177e4SLinus Torvalds 			*s = '\0';
4091da177e4SLinus Torvalds 			return line;
4101da177e4SLinus Torvalds 		}
4111da177e4SLinus Torvalds 	}
4121da177e4SLinus Torvalds 	/* End of buffer */
4131da177e4SLinus Torvalds 	return NULL;
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds 
4165c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4171da177e4SLinus Torvalds {
4181da177e4SLinus Torvalds 	munmap(file, size);
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds 
42185bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4221da177e4SLinus Torvalds {
4231da177e4SLinus Torvalds 	unsigned int i;
42485bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4251da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4261da177e4SLinus Torvalds 	Elf_Sym  *sym;
4271ce53adfSDenys Vlasenko 	const char *secstrings;
4281ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4291da177e4SLinus Torvalds 
4301da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4311da177e4SLinus Torvalds 	if (!hdr) {
432eed380f3SGuenter Roeck 		if (ignore_missing_files) {
433eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
434eed380f3SGuenter Roeck 				strerror(errno));
435eed380f3SGuenter Roeck 			return 0;
436eed380f3SGuenter Roeck 		}
4371da177e4SLinus Torvalds 		perror(filename);
4386803dc0eSSam Ravnborg 		exit(1);
4391da177e4SLinus Torvalds 	}
4401da177e4SLinus Torvalds 	info->hdr = hdr;
44185bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
44285bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
44385bd2fddSSam Ravnborg 		return 0;
44485bd2fddSSam Ravnborg 	}
44585bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
44685bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
44785bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
44885bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
44985bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
45085bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
45185bd2fddSSam Ravnborg 		return 0;
45285bd2fddSSam Ravnborg 	}
4531da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
454ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
4557d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
4567d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
4577d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
4587d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
4597d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
4607d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
4617d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
4627d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
4637d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
4647d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
4657d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
4667d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
4671da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
4681da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
4691da177e4SLinus Torvalds 
470a83710e5SPetr Stetiar 	/* Check if file offset is correct */
471a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
472df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
473df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
474df578e7dSSam Ravnborg 		      filename, info->size);
475a83710e5SPetr Stetiar 		return 0;
476a83710e5SPetr Stetiar 	}
477a83710e5SPetr Stetiar 
4786845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
4791ce53adfSDenys Vlasenko 		/*
4801ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
4811ce53adfSDenys Vlasenko 		 * read count from .sh_size.
4821ce53adfSDenys Vlasenko 		 */
4831ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
4841ce53adfSDenys Vlasenko 	}
4851ce53adfSDenys Vlasenko 	else {
4861ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
4871ce53adfSDenys Vlasenko 	}
4881ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
4896845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
4901ce53adfSDenys Vlasenko 	}
4911ce53adfSDenys Vlasenko 	else {
4921ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
4931ce53adfSDenys Vlasenko 	}
4941ce53adfSDenys Vlasenko 
4951da177e4SLinus Torvalds 	/* Fix endianness in section headers */
4961ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
4977d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
4981da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
4997d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
5007d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5011da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5021da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5031da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
504ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5057d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5067d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5071da177e4SLinus Torvalds 	}
5081da177e4SLinus Torvalds 	/* Find symbol table. */
5091ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5101ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
511bd5cbcedSRam Pai 		const char *secname;
51256fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5131da177e4SLinus Torvalds 
51456fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
515df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
516df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
517df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
518df578e7dSSam Ravnborg 			      sizeof(*hdr));
51985bd2fddSSam Ravnborg 			return 0;
52085bd2fddSSam Ravnborg 		}
521bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
522bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
52356fc82c5STejun Heo 			if (nobits)
52456fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5251da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5261da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
527bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
528bd5cbcedSRam Pai 			info->export_sec = i;
529c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
530c96fca21SSam Ravnborg 			info->export_unused_sec = i;
531bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
532bd5cbcedSRam Pai 			info->export_gpl_sec = i;
533c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
534c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
535bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
536bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
537bd5cbcedSRam Pai 
5381ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5391ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
5401ce53adfSDenys Vlasenko 			symtab_idx = i;
5411ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
5421ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5431ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
5441ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5456845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
5461da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
5471ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
5481ce53adfSDenys Vlasenko 		}
5491ce53adfSDenys Vlasenko 
5501ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
5511ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
5521ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
5531ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
5541ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5551ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
5561ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5571ce53adfSDenys Vlasenko 		}
5581da177e4SLinus Torvalds 	}
559df578e7dSSam Ravnborg 	if (!info->symtab_start)
560cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
561df578e7dSSam Ravnborg 
5621da177e4SLinus Torvalds 	/* Fix endianness in symbols */
5631da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
5641da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
5651da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
5661da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
5671da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
5681da177e4SLinus Torvalds 	}
5691ce53adfSDenys Vlasenko 
5701ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
5711ce53adfSDenys Vlasenko 		Elf32_Word *p;
5726845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
5731ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
5746845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
5751ce53adfSDenys Vlasenko 			      symtab_idx);
5761ce53adfSDenys Vlasenko 		/* Fix endianness */
5771ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
5781ce53adfSDenys Vlasenko 		     p++)
5791ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
5801ce53adfSDenys Vlasenko 	}
5811ce53adfSDenys Vlasenko 
58285bd2fddSSam Ravnborg 	return 1;
5831da177e4SLinus Torvalds }
5841da177e4SLinus Torvalds 
5855c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
5861da177e4SLinus Torvalds {
5871da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
5881da177e4SLinus Torvalds }
5891da177e4SLinus Torvalds 
5904d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
5914d7365d6SSam Ravnborg {
5924d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
593b2c5cdcfSMasahiro Yamada 	if (strcmp(symname, "__this_module") == 0)
5944d7365d6SSam Ravnborg 		return 1;
5954d7365d6SSam Ravnborg 	/* ignore global offset table */
5964d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
5974d7365d6SSam Ravnborg 		return 1;
5984d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
5994d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
600d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr_") ||
601d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr_") ||
602d62c4765SMasahiro Yamada 		    strstarts(symname, "_rest32gpr_") ||
603d62c4765SMasahiro Yamada 		    strstarts(symname, "_save32gpr_") ||
604d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
605d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_"))
6064d7365d6SSam Ravnborg 			return 1;
6077fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6087fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
609d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr0_") ||
610d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr0_") ||
611d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
612d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_") ||
613c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6147fca5dc8SStephen Rothwell 			return 1;
6154d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6164d7365d6SSam Ravnborg 	return 0;
6174d7365d6SSam Ravnborg }
6184d7365d6SSam Ravnborg 
6195c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6201da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6211da177e4SLinus Torvalds {
6221da177e4SLinus Torvalds 	unsigned int crc;
62362a26356SAlessio Igor Bogani 	enum export export;
624d8c1eb86SNicholas Piggin 	bool is_crc = false;
62562a26356SAlessio Igor Bogani 
626258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
627d62c4765SMasahiro Yamada 	    strstarts(symname, "__ksymtab"))
62862a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
62962a26356SAlessio Igor Bogani 	else
63062a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	/* CRC'd symbol */
633d62c4765SMasahiro Yamada 	if (strstarts(symname, "__crc_")) {
634d8c1eb86SNicholas Piggin 		is_crc = true;
6351da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
63656067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
63756067812SArd Biesheuvel 			unsigned int *crcp;
63856067812SArd Biesheuvel 
63956067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
64056067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
64156067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
64256067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
64356067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
64454a7151bSFredrik Noring 			crc = TO_NATIVE(*crcp);
64556067812SArd Biesheuvel 		}
646b2c5cdcfSMasahiro Yamada 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
647bd5cbcedSRam Pai 				export);
6481da177e4SLinus Torvalds 	}
649b5064654SAndi Kleen 
650b5064654SAndi Kleen 	switch (sym->st_shndx) {
651b5064654SAndi Kleen 	case SHN_COMMON:
652d62c4765SMasahiro Yamada 		if (strstarts(symname, "__gnu_lto_")) {
653ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
654ef178f92SAndi Kleen 		} else
655b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
6561da177e4SLinus Torvalds 		break;
6571da177e4SLinus Torvalds 	case SHN_UNDEF:
6581da177e4SLinus Torvalds 		/* undefined symbol */
6591da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
6601da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
6611da177e4SLinus Torvalds 			break;
6624d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
6631da177e4SLinus Torvalds 			break;
6648d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
6658d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
6668d529014SBen Colline /* add compatibility with older glibc */
6678d529014SBen Colline #ifndef STT_SPARC_REGISTER
6688d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
6698d529014SBen Colline #endif
6701da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
6711da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
6721da177e4SLinus Torvalds 			/* Ignore register directives. */
6738d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
6741da177e4SLinus Torvalds 				break;
6757caaeabbSAl Viro 			if (symname[0] == '.') {
6761f3aa900SRandy Dunlap 				char *munged = NOFAIL(strdup(symname));
6777caaeabbSAl Viro 				munged[0] = '_';
6787caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
6797caaeabbSAl Viro 				symname = munged;
6807caaeabbSAl Viro 			}
6811da177e4SLinus Torvalds 		}
6821da177e4SLinus Torvalds #endif
6831da177e4SLinus Torvalds 
684d8c1eb86SNicholas Piggin 		if (is_crc) {
685d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
686b2c5cdcfSMasahiro Yamada 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
687b2c5cdcfSMasahiro Yamada 			     symname + strlen("__crc_"), mod->name, e);
688d8c1eb86SNicholas Piggin 		}
689b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
6901da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
6911da177e4SLinus Torvalds 					  mod->unres);
6921da177e4SLinus Torvalds 		break;
6931da177e4SLinus Torvalds 	default:
6941da177e4SLinus Torvalds 		/* All exported symbols */
695d62c4765SMasahiro Yamada 		if (strstarts(symname, "__ksymtab_")) {
696b2c5cdcfSMasahiro Yamada 			sym_add_exported(symname + strlen("__ksymtab_"), mod,
697bd5cbcedSRam Pai 					export);
6981da177e4SLinus Torvalds 		}
699b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "init_module") == 0)
7001da177e4SLinus Torvalds 			mod->has_init = 1;
701b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "cleanup_module") == 0)
7021da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7031da177e4SLinus Torvalds 		break;
7041da177e4SLinus Torvalds 	}
7051da177e4SLinus Torvalds }
7061da177e4SLinus Torvalds 
7075c3ead8cSSam Ravnborg /**
7085c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7095c3ead8cSSam Ravnborg  **/
7101da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7111da177e4SLinus Torvalds {
7121da177e4SLinus Torvalds 	/* Skip non-zero chars */
7131da177e4SLinus Torvalds 	while (string[0]) {
7141da177e4SLinus Torvalds 		string++;
7151da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7161da177e4SLinus Torvalds 			return NULL;
7171da177e4SLinus Torvalds 	}
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 	/* Skip any zero padding. */
7201da177e4SLinus Torvalds 	while (!string[0]) {
7211da177e4SLinus Torvalds 		string++;
7221da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7231da177e4SLinus Torvalds 			return NULL;
7241da177e4SLinus Torvalds 	}
7251da177e4SLinus Torvalds 	return string;
7261da177e4SLinus Torvalds }
7271da177e4SLinus Torvalds 
728bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag,
729bca2cceeSMasahiro Yamada 			      char *prev)
7301da177e4SLinus Torvalds {
7311da177e4SLinus Torvalds 	char *p;
7321da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
733bca2cceeSMasahiro Yamada 	char *modinfo = info->modinfo;
734bca2cceeSMasahiro Yamada 	unsigned long size = info->modinfo_len;
7351da177e4SLinus Torvalds 
736bca2cceeSMasahiro Yamada 	if (prev) {
737bca2cceeSMasahiro Yamada 		size -= prev - modinfo;
738bca2cceeSMasahiro Yamada 		modinfo = next_string(prev, &size);
739b817f6feSSam Ravnborg 	}
740b817f6feSSam Ravnborg 
7411da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
7421da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7431da177e4SLinus Torvalds 			return p + taglen + 1;
7441da177e4SLinus Torvalds 	}
7451da177e4SLinus Torvalds 	return NULL;
7461da177e4SLinus Torvalds }
7471da177e4SLinus Torvalds 
748bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag)
749b817f6feSSam Ravnborg 
750b817f6feSSam Ravnborg {
751bca2cceeSMasahiro Yamada 	return get_next_modinfo(info, tag, NULL);
752b817f6feSSam Ravnborg }
753b817f6feSSam Ravnborg 
75493684d3bSSam Ravnborg /**
7554c8fbca5SSam Ravnborg  * Test if string s ends in string sub
7564c8fbca5SSam Ravnborg  * return 0 if match
7574c8fbca5SSam Ravnborg  **/
7584c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
7594c8fbca5SSam Ravnborg {
7604c8fbca5SSam Ravnborg 	int slen, sublen;
7614c8fbca5SSam Ravnborg 
7624c8fbca5SSam Ravnborg 	if (!s || !sub)
7634c8fbca5SSam Ravnborg 		return 1;
7644c8fbca5SSam Ravnborg 
7654c8fbca5SSam Ravnborg 	slen = strlen(s);
7664c8fbca5SSam Ravnborg 	sublen = strlen(sub);
7674c8fbca5SSam Ravnborg 
7684c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
7694c8fbca5SSam Ravnborg 		return 1;
7704c8fbca5SSam Ravnborg 
7714c8fbca5SSam Ravnborg 	if (sublen > slen)
7724c8fbca5SSam Ravnborg 		return 1;
7734c8fbca5SSam Ravnborg 
7744c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
7754c8fbca5SSam Ravnborg }
7764c8fbca5SSam Ravnborg 
777ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
778ff13f926SSam Ravnborg {
77958fb0d4fSSam Ravnborg 	if (sym)
780ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
78158fb0d4fSSam Ravnborg 	else
782f666751aSSam Ravnborg 		return "(unknown)";
783ff13f926SSam Ravnborg }
784ff13f926SSam Ravnborg 
78510668220SSam Ravnborg /* The pattern is an array of simple patterns.
78610668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
7876c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
78810668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
78909c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
79010668220SSam Ravnborg  */
7915c725138STrevor Keith static int match(const char *sym, const char * const pat[])
79210668220SSam Ravnborg {
79310668220SSam Ravnborg 	const char *p;
79410668220SSam Ravnborg 	while (*pat) {
79510668220SSam Ravnborg 		p = *pat++;
79610668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
79710668220SSam Ravnborg 
79809c20c03SPaul Gortmaker 		/* "*foo*" */
79909c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
8006f02bdfcSDenis Efremov 			char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
8016f02bdfcSDenis Efremov 			char *here = strstr(sym, bare);
80209c20c03SPaul Gortmaker 
80309c20c03SPaul Gortmaker 			free(bare);
80409c20c03SPaul Gortmaker 			if (here != NULL)
80509c20c03SPaul Gortmaker 				return 1;
80609c20c03SPaul Gortmaker 		}
8076c5bd235SSam Ravnborg 		/* "*foo" */
80809c20c03SPaul Gortmaker 		else if (*p == '*') {
8096c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8106c5bd235SSam Ravnborg 				return 1;
8116c5bd235SSam Ravnborg 		}
81210668220SSam Ravnborg 		/* "foo*" */
8136c5bd235SSam Ravnborg 		else if (*endp == '*') {
81410668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
81510668220SSam Ravnborg 				return 1;
81610668220SSam Ravnborg 		}
81710668220SSam Ravnborg 		/* no wildcards */
81810668220SSam Ravnborg 		else {
81910668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
82010668220SSam Ravnborg 				return 1;
82110668220SSam Ravnborg 		}
82210668220SSam Ravnborg 	}
82310668220SSam Ravnborg 	/* no match */
82410668220SSam Ravnborg 	return 0;
82510668220SSam Ravnborg }
82610668220SSam Ravnborg 
82710668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8287a3ee753SMathias Krause static const char *const section_white_list[] =
8294391ed6aSSam Ravnborg {
8304391ed6aSSam Ravnborg 	".comment*",
8314391ed6aSSam Ravnborg 	".debug*",
8324d10c223SChen Gang 	".cranges",		/* sh64 */
8331121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
834739d875dSDavid Howells 	".GCC.command.line",	/* record-gcc-switches */
8354391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8364391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8374391ed6aSSam Ravnborg 	".stab*",
8384391ed6aSSam Ravnborg 	".note*",
8394391ed6aSSam Ravnborg 	".got*",
8404391ed6aSSam Ravnborg 	".toc*",
841af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
842af42e970SMax Filippov 	".xt.lit",         /* xtensa */
843f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
844f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
845d1189c63SNoam Camus 	".cmem*",			/* EZchip */
846d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
847ef178f92SAndi Kleen 	".gnu.lto*",
848e390f9a9SJosh Poimboeuf 	".discard.*",
8494391ed6aSSam Ravnborg 	NULL
8504391ed6aSSam Ravnborg };
85110668220SSam Ravnborg 
852e241a630SSam Ravnborg /*
853b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
854e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
855b614a697SAnders Kaseorg  * without "ax" / "aw".
856e241a630SSam Ravnborg  */
857b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
858b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
859e241a630SSam Ravnborg {
860b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
861e241a630SSam Ravnborg 
862b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
863b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
864b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
865b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
866b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
867e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
868e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
869e241a630SSam Ravnborg 		     modname, sec);
870e241a630SSam Ravnborg 	}
871e241a630SSam Ravnborg }
872e241a630SSam Ravnborg 
873e241a630SSam Ravnborg 
874e241a630SSam Ravnborg 
875eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
876a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
877a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
878eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
879a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
88010668220SSam Ravnborg 
881eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
882a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
883eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
884a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
88510668220SSam Ravnborg 
886bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
887a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
888a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
889a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
890bb15d8dbSSebastian Andrzej Siewior 
891e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
892e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
8934a31a229SUwe Kleine-König 
8944a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
8954a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
89610668220SSam Ravnborg 
897a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
898157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
8996727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
90052dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
901673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
902673c2c34SChris Metcalf 		".coldtext"
90310668220SSam Ravnborg 
904fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
905fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
906eb8f6890SSam Ravnborg 
907fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
908fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
909eb8f6890SSam Ravnborg 
91052dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
91152dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
91252dc0595SQuentin Casasnovas 
9136c5bd235SSam Ravnborg /* init data sections */
9147a3ee753SMathias Krause static const char *const init_data_sections[] =
9157a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9166c5bd235SSam Ravnborg 
9176c5bd235SSam Ravnborg /* all init sections */
9187a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9196c5bd235SSam Ravnborg 
9206c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9217a3ee753SMathias Krause static const char *const init_exit_sections[] =
922eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9236c5bd235SSam Ravnborg 
9244a3893d0SPaul Gortmaker /* all text sections */
9254a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9264a3893d0SPaul Gortmaker 
9276c5bd235SSam Ravnborg /* data section */
9287a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9296c5bd235SSam Ravnborg 
9306c5bd235SSam Ravnborg 
9316c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
932af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
933af92a82dSUwe Kleine-König 	"*driver",							\
934af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
935af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
936af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
937af92a82dSUwe Kleine-König 	"*_ops",							\
938af92a82dSUwe Kleine-König 	"*_probe",							\
939af92a82dSUwe Kleine-König 	"*_probe_one",							\
940af92a82dSUwe Kleine-König 	"*_console"
9416c5bd235SSam Ravnborg 
9427a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
9437a3ee753SMathias Krause static const char *const linker_symbols[] =
9446c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
9454a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
9466c5bd235SSam Ravnborg 
947588ccd73SSam Ravnborg enum mismatch {
948bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
949bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
950bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
951bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
952bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
953bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
954bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
955bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
956588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
95752dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
958588ccd73SSam Ravnborg };
959588ccd73SSam Ravnborg 
960e5d8f59aSQuentin Casasnovas /**
961e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
962e5d8f59aSQuentin Casasnovas  *
963e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
964e5d8f59aSQuentin Casasnovas  *
965e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
966e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
967e5d8f59aSQuentin Casasnovas  *
968e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
969e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
970e5d8f59aSQuentin Casasnovas  *
971e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
972e5d8f59aSQuentin Casasnovas  *
973e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
974e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
975e5d8f59aSQuentin Casasnovas  *
976e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
977e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
978e5d8f59aSQuentin Casasnovas  *
979e5d8f59aSQuentin Casasnovas  */
98010668220SSam Ravnborg struct sectioncheck {
98110668220SSam Ravnborg 	const char *fromsec[20];
982050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
983050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
984588ccd73SSam Ravnborg 	enum mismatch mismatch;
985af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
986644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
987644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
988644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
989644e8f14SQuentin Casasnovas 
99010668220SSam Ravnborg };
99110668220SSam Ravnborg 
99252dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
99352dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
99452dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
99552dc0595SQuentin Casasnovas 				     const char *fromsec);
99652dc0595SQuentin Casasnovas 
9977a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
99810668220SSam Ravnborg /* Do not reference init/exit code/data from
99910668220SSam Ravnborg  * normal code and data
100010668220SSam Ravnborg  */
100110668220SSam Ravnborg {
1002588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1003050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1004bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1005af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1006588ccd73SSam Ravnborg },
1007588ccd73SSam Ravnborg {
1008588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1009050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1010bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1011af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1012588ccd73SSam Ravnborg },
1013588ccd73SSam Ravnborg {
10140db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1015050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10160db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10170db25245SUwe Kleine-König 	.symbol_white_list = {
10180db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10190db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10200db25245SUwe Kleine-König 	},
10210db25245SUwe Kleine-König },
10220db25245SUwe Kleine-König {
1023588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1024050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1025bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1026af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1027588ccd73SSam Ravnborg },
1028588ccd73SSam Ravnborg {
1029588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1030050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1031bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1032af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1033eb8f6890SSam Ravnborg },
1034e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1035eb8f6890SSam Ravnborg {
10364a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1037050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1038bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1039af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1040eb8f6890SSam Ravnborg },
1041e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1042eb8f6890SSam Ravnborg {
10434a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1044050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1045bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1046af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
104710668220SSam Ravnborg },
104810668220SSam Ravnborg /* Do not use exit code/data from init code */
104910668220SSam Ravnborg {
1050eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1051050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1052bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1053af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
105410668220SSam Ravnborg },
105510668220SSam Ravnborg /* Do not use init code/data from exit code */
105610668220SSam Ravnborg {
1057eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1058050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1059bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1060af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
106110668220SSam Ravnborg },
1062bb15d8dbSSebastian Andrzej Siewior {
1063bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1064050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1065bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1066bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1067bb15d8dbSSebastian Andrzej Siewior },
106810668220SSam Ravnborg /* Do not export init/exit functions or data */
106910668220SSam Ravnborg {
107010668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1071050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1072af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1073af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
107452dc0595SQuentin Casasnovas },
107552dc0595SQuentin Casasnovas {
107652dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
107752dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
107852dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
107952dc0595SQuentin Casasnovas 	 */
108052dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
108152dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
108252dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
108352dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
108410668220SSam Ravnborg }
108510668220SSam Ravnborg };
108610668220SSam Ravnborg 
10870d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
10880d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
108910668220SSam Ravnborg {
109010668220SSam Ravnborg 	int i;
109110668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
109210668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
109310668220SSam Ravnborg 
1094c5c3439aSQuentin Casasnovas 	/*
1095c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1096c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1097739d875dSDavid Howells 	 * doesn't make much sense and causes build failures on parisc
1098739d875dSDavid Howells 	 * architectures.
1099c5c3439aSQuentin Casasnovas 	 */
1100c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1101c5c3439aSQuentin Casasnovas 		return NULL;
1102c5c3439aSQuentin Casasnovas 
110310668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1104050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1105050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11060d2a636eSUwe Kleine-König 				return check;
1107050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1108050e57fdSQuentin Casasnovas 				return check;
1109050e57fdSQuentin Casasnovas 		}
111010668220SSam Ravnborg 		check++;
111110668220SSam Ravnborg 	}
11120d2a636eSUwe Kleine-König 	return NULL;
111310668220SSam Ravnborg }
111410668220SSam Ravnborg 
11154c8fbca5SSam Ravnborg /**
11164c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11170e0d314eSSam Ravnborg  *
11184c8fbca5SSam Ravnborg  * Pattern 1:
11194c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11204c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11214c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11224c8fbca5SSam Ravnborg  *   this pattern.
11234c8fbca5SSam Ravnborg  *   The pattern is identified by:
11244c8fbca5SSam Ravnborg  *   tosec   = .init.data
11259209aed0SSam Ravnborg  *   fromsec = .data*
11264c8fbca5SSam Ravnborg  *   atsym   =__param*
11274c8fbca5SSam Ravnborg  *
11286a841528SRusty Russell  * Pattern 1a:
11296a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11306a841528SRusty Russell  *   The pattern is identified by:
11316a841528SRusty Russell  *   tosec   = .init.text
11326a841528SRusty Russell  *   fromsec = .data*
11336a841528SRusty Russell  *   atsym   = __param_ops_*
11346a841528SRusty Russell  *
11354c8fbca5SSam Ravnborg  * Pattern 2:
113672ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11374c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
11384c8fbca5SSam Ravnborg  *   the pattern is identified by:
113983cda2bbSSam Ravnborg  *   tosec   = init or exit section
114083cda2bbSSam Ravnborg  *   fromsec = data section
1141df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1142df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1143ee6a8545SVivek Goyal  *
1144ee6a8545SVivek Goyal  * Pattern 3:
1145c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
11469bf8cb9bSSam Ravnborg  *
11471d8af559SSam Ravnborg  * Pattern 4:
1148ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1149ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1150ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1151ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1152ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1153ee6a8545SVivek Goyal  *   This pattern is identified by
1154ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
11559bf8cb9bSSam Ravnborg  *
11564a3893d0SPaul Gortmaker  * Pattern 5:
11574a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
11584a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
11594a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
11604a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
11614a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
11624a3893d0SPaul Gortmaker  *   This pattern is identified by
11634a3893d0SPaul Gortmaker  *   tosec   = init section
11644a3893d0SPaul Gortmaker  *   fromsec = text section
11654a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
11664a3893d0SPaul Gortmaker  *
1167a4d26f1aSPaul Walmsley  * Pattern 6:
1168a4d26f1aSPaul Walmsley  *   Hide section mismatch warnings for ELF local symbols.  The goal
1169a4d26f1aSPaul Walmsley  *   is to eliminate false positive modpost warnings caused by
1170a4d26f1aSPaul Walmsley  *   compiler-generated ELF local symbol names such as ".LANCHOR1".
1171a4d26f1aSPaul Walmsley  *   Autogenerated symbol names bypass modpost's "Pattern 2"
1172a4d26f1aSPaul Walmsley  *   whitelisting, which relies on pattern-matching against symbol
1173a4d26f1aSPaul Walmsley  *   names to work.  (One situation where gcc can autogenerate ELF
1174a4d26f1aSPaul Walmsley  *   local symbols is when "-fsection-anchors" is used.)
11754c8fbca5SSam Ravnborg  **/
1176af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1177af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
117858fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
11794c8fbca5SSam Ravnborg {
11804c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
11816c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
11826c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1183d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param"))
118458fb0d4fSSam Ravnborg 		return 0;
11854c8fbca5SSam Ravnborg 
11866a841528SRusty Russell 	/* Check for pattern 1a */
11876a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
11886a841528SRusty Russell 	    match(fromsec, data_sections) &&
1189d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param_ops_"))
11906a841528SRusty Russell 		return 0;
11916a841528SRusty Russell 
11924c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
11936c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
11946c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1195af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
119658fb0d4fSSam Ravnborg 		return 0;
11974c8fbca5SSam Ravnborg 
11989bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
11996c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
12006c5bd235SSam Ravnborg 	    match(tosec, init_sections))
120158fb0d4fSSam Ravnborg 		return 0;
1202f8657e1bSVivek Goyal 
12031d8af559SSam Ravnborg 	/* Check for pattern 4 */
120458fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
120593659af1SSam Ravnborg 		return 0;
120658fb0d4fSSam Ravnborg 
12074a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12084a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12094a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12104a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12114a3893d0SPaul Gortmaker 		return 0;
12124a3893d0SPaul Gortmaker 
1213a4d26f1aSPaul Walmsley 	/* Check for pattern 6 */
1214a4d26f1aSPaul Walmsley 	if (strstarts(fromsym, ".L"))
1215a4d26f1aSPaul Walmsley 		return 0;
1216a4d26f1aSPaul Walmsley 
121758fb0d4fSSam Ravnborg 	return 1;
12184c8fbca5SSam Ravnborg }
12194c8fbca5SSam Ravnborg 
12205818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str)
12215818c683SSami Tolvanen {
12225818c683SSami Tolvanen 	return str[0] == '$' && strchr("axtd", str[1])
12235818c683SSami Tolvanen 	       && (str[2] == '\0' || str[2] == '.');
12245818c683SSami Tolvanen }
12255818c683SSami Tolvanen 
12265818c683SSami Tolvanen /*
12275818c683SSami Tolvanen  * If there's no name there, ignore it; likewise, ignore it if it's
12285818c683SSami Tolvanen  * one of the magic symbols emitted used by current ARM tools.
12295818c683SSami Tolvanen  *
12305818c683SSami Tolvanen  * Otherwise if find_symbols_between() returns those symbols, they'll
12315818c683SSami Tolvanen  * fail the whitelist tests and cause lots of false alarms ... fixable
12325818c683SSami Tolvanen  * only by merging __exit and __init sections into __text, bloating
12335818c683SSami Tolvanen  * the kernel (which is especially evil on embedded platforms).
12345818c683SSami Tolvanen  */
12355818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
12365818c683SSami Tolvanen {
12375818c683SSami Tolvanen 	const char *name = elf->strtab + sym->st_name;
12385818c683SSami Tolvanen 
12395818c683SSami Tolvanen 	if (!name || !strlen(name))
12405818c683SSami Tolvanen 		return 0;
12415818c683SSami Tolvanen 	return !is_arm_mapping_symbol(name);
12425818c683SSami Tolvanen }
12435818c683SSami Tolvanen 
12444c8fbca5SSam Ravnborg /**
124593684d3bSSam Ravnborg  * Find symbol based on relocation record info.
124693684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
124793684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
124893684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
124993684d3bSSam Ravnborg  * based on section and address.
125093684d3bSSam Ravnborg  *  **/
12519ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
125293684d3bSSam Ravnborg 				Elf_Sym *relsym)
125393684d3bSSam Ravnborg {
125493684d3bSSam Ravnborg 	Elf_Sym *sym;
12559ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
12569ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
12579ad21c3fSSam Ravnborg 	Elf64_Sword d;
12581ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
125993684d3bSSam Ravnborg 
126093684d3bSSam Ravnborg 	if (relsym->st_name != 0)
126193684d3bSSam Ravnborg 		return relsym;
12621ce53adfSDenys Vlasenko 
12631ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
126493684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
12651ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
126693684d3bSSam Ravnborg 			continue;
1267ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1268ae4ac123SAtsushi Nemoto 			continue;
12695818c683SSami Tolvanen 		if (!is_valid_name(elf, sym))
12705818c683SSami Tolvanen 			continue;
127193684d3bSSam Ravnborg 		if (sym->st_value == addr)
127293684d3bSSam Ravnborg 			return sym;
12739ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
12749ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
12759ad21c3fSSam Ravnborg 		if (d < 0)
12769ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
12779ad21c3fSSam Ravnborg 		if (d < distance) {
12789ad21c3fSSam Ravnborg 			distance = d;
12799ad21c3fSSam Ravnborg 			near = sym;
128093684d3bSSam Ravnborg 		}
12819ad21c3fSSam Ravnborg 	}
12829ad21c3fSSam Ravnborg 	/* We need a close match */
12839ad21c3fSSam Ravnborg 	if (distance < 20)
12849ad21c3fSSam Ravnborg 		return near;
12859ad21c3fSSam Ravnborg 	else
128693684d3bSSam Ravnborg 		return NULL;
128793684d3bSSam Ravnborg }
128893684d3bSSam Ravnborg 
1289b39927cfSSam Ravnborg /*
129043c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
129143c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
129243c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
129343c74d17SSam Ravnborg  * it is, but this works for now.
1294b39927cfSSam Ravnborg  **/
1295157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1296157c23c8SSam Ravnborg 				 const char *sec)
1297b39927cfSSam Ravnborg {
1298b39927cfSSam Ravnborg 	Elf_Sym *sym;
1299157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1300157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1301b39927cfSSam Ravnborg 
1302b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1303b39927cfSSam Ravnborg 		const char *symsec;
1304b39927cfSSam Ravnborg 
13051ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1306b39927cfSSam Ravnborg 			continue;
13071ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1308b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1309b39927cfSSam Ravnborg 			continue;
1310da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1311da68d61fSDavid Brownell 			continue;
1312b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1313157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1314157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1315157c23c8SSam Ravnborg 				near = sym;
1316157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1317157c23c8SSam Ravnborg 				near = sym;
131843c74d17SSam Ravnborg 			}
1319b39927cfSSam Ravnborg 		}
1320b39927cfSSam Ravnborg 	}
1321157c23c8SSam Ravnborg 	return near;
1322157c23c8SSam Ravnborg }
1323b39927cfSSam Ravnborg 
132458fb0d4fSSam Ravnborg /*
1325588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1326588ccd73SSam Ravnborg  * .init.text => __init
1327588ccd73SSam Ravnborg  * .memexitconst => __memconst
1328588ccd73SSam Ravnborg  * etc.
1329cbcf14a9SAndy Shevchenko  *
1330cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1331cbcf14a9SAndy Shevchenko  * method should free it after usage.
1332588ccd73SSam Ravnborg */
1333588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1334588ccd73SSam Ravnborg {
1335588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
13361f3aa900SRandy Dunlap 		char *p = NOFAIL(malloc(20));
1337588ccd73SSam Ravnborg 		char *r = p;
1338588ccd73SSam Ravnborg 
1339588ccd73SSam Ravnborg 		*p++ = '_';
1340588ccd73SSam Ravnborg 		*p++ = '_';
1341588ccd73SSam Ravnborg 		if (*s == '.')
1342588ccd73SSam Ravnborg 			s++;
1343588ccd73SSam Ravnborg 		while (*s && *s != '.')
1344588ccd73SSam Ravnborg 			*p++ = *s++;
1345588ccd73SSam Ravnborg 		*p = '\0';
1346588ccd73SSam Ravnborg 		if (*s == '.')
1347588ccd73SSam Ravnborg 			s++;
1348588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1349588ccd73SSam Ravnborg 			strcat(p, "const ");
1350588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1351588ccd73SSam Ravnborg 			strcat(p, "data ");
1352588ccd73SSam Ravnborg 		else
1353588ccd73SSam Ravnborg 			strcat(p, " ");
1354cbcf14a9SAndy Shevchenko 		return r;
1355588ccd73SSam Ravnborg 	} else {
13561f3aa900SRandy Dunlap 		return NOFAIL(strdup(""));
1357588ccd73SSam Ravnborg 	}
1358588ccd73SSam Ravnborg }
1359588ccd73SSam Ravnborg 
1360588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1361588ccd73SSam Ravnborg {
1362588ccd73SSam Ravnborg 	if (sym)
1363588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1364588ccd73SSam Ravnborg 	else
1365f666751aSSam Ravnborg 		return -1;
1366588ccd73SSam Ravnborg }
1367588ccd73SSam Ravnborg 
136800759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
136900759c0eSRandy Dunlap {
137000759c0eSRandy Dunlap 	const char *const *s = list;
137100759c0eSRandy Dunlap 
137200759c0eSRandy Dunlap 	while (*s) {
137300759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
137400759c0eSRandy Dunlap 		s++;
137500759c0eSRandy Dunlap 		if (*s)
137600759c0eSRandy Dunlap 			fprintf(stderr, ", ");
137700759c0eSRandy Dunlap 	}
137800759c0eSRandy Dunlap 	fprintf(stderr, "\n");
137900759c0eSRandy Dunlap }
138000759c0eSRandy Dunlap 
1381356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1382356ad538SQuentin Casasnovas {
1383356ad538SQuentin Casasnovas 	switch (is_func) {
1384356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1385356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1386356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1387356ad538SQuentin Casasnovas 	}
1388356ad538SQuentin Casasnovas }
1389356ad538SQuentin Casasnovas 
1390588ccd73SSam Ravnborg /*
1391b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1392b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
13934c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
139458fb0d4fSSam Ravnborg  */
13950d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
13960d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
139758fb0d4fSSam Ravnborg 				const char *fromsec,
139858fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
139958fb0d4fSSam Ravnborg 				const char *fromsym,
1400588ccd73SSam Ravnborg 				int from_is_func,
1401588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1402588ccd73SSam Ravnborg 				int to_is_func)
1403b39927cfSSam Ravnborg {
1404588ccd73SSam Ravnborg 	const char *from, *from_p;
1405588ccd73SSam Ravnborg 	const char *to, *to_p;
140637ed19d5SAlexey Fomenko 	char *prl_from;
140737ed19d5SAlexey Fomenko 	char *prl_to;
1408f666751aSSam Ravnborg 
1409e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1410e5f95c8bSSam Ravnborg 
1411356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1412356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1413356ad538SQuentin Casasnovas 
14147c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14157c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14167c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14177c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1418588ccd73SSam Ravnborg 
14190d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1420bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
142137ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
142237ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1423588ccd73SSam Ravnborg 		fprintf(stderr,
1424588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1425588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1426588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1427588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
142837ed19d5SAlexey Fomenko 		prl_from, fromsym,
142937ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
143037ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
143137ed19d5SAlexey Fomenko 		free(prl_from);
143237ed19d5SAlexey Fomenko 		free(prl_to);
1433588ccd73SSam Ravnborg 		break;
1434bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
143537ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1436588ccd73SSam Ravnborg 		fprintf(stderr,
1437588ccd73SSam Ravnborg 		"The variable %s references\n"
1438588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1439588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
14408b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1441588ccd73SSam Ravnborg 		"or name the variable:\n",
144237ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
144300759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
144437ed19d5SAlexey Fomenko 		free(prl_to);
1445588ccd73SSam Ravnborg 		break;
144658fb0d4fSSam Ravnborg 	}
1447bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
144837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1449588ccd73SSam Ravnborg 		fprintf(stderr,
1450588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1451588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1452588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
145337ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
145437ed19d5SAlexey Fomenko 		free(prl_to);
1455588ccd73SSam Ravnborg 		break;
1456bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
145737ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1458588ccd73SSam Ravnborg 		fprintf(stderr,
1459588ccd73SSam Ravnborg 		"The variable %s references\n"
1460588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1461588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1462588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1463588ccd73SSam Ravnborg 		"name the variable:\n",
146437ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
146500759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
146637ed19d5SAlexey Fomenko 		free(prl_to);
1467588ccd73SSam Ravnborg 		break;
1468588ccd73SSam Ravnborg 	}
1469bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1470bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_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 		"If %s is only used by %s then\n"
1477588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
147837ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
147937ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1480b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
148137ed19d5SAlexey Fomenko 		free(prl_from);
148237ed19d5SAlexey Fomenko 		free(prl_to);
1483588ccd73SSam Ravnborg 		break;
1484bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
148537ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
148637ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1487588ccd73SSam Ravnborg 		fprintf(stderr,
1488588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1489588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1490588ccd73SSam Ravnborg 		"This is often seen when error handling "
1491588ccd73SSam Ravnborg 		"in the init function\n"
1492588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1493588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1494588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
149537ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
149637ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
14975003bab8SAndrew Morton 		prl_to, tosym, to_p);
149837ed19d5SAlexey Fomenko 		free(prl_from);
149937ed19d5SAlexey Fomenko 		free(prl_to);
1500588ccd73SSam Ravnborg 		break;
1501bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
150237ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
150337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1504588ccd73SSam Ravnborg 		fprintf(stderr,
1505588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1506588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1507588ccd73SSam Ravnborg 		"This is often seen when error handling "
1508588ccd73SSam Ravnborg 		"in the exit function\n"
1509588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1510588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1511588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
151237ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
151337ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
151437ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
151537ed19d5SAlexey Fomenko 		free(prl_from);
151637ed19d5SAlexey Fomenko 		free(prl_to);
1517588ccd73SSam Ravnborg 		break;
1518588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
151937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1520588ccd73SSam Ravnborg 		fprintf(stderr,
1521588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1522588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1523588ccd73SSam Ravnborg 		"or drop the export.\n",
152437ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
152537ed19d5SAlexey Fomenko 		free(prl_to);
1526588ccd73SSam Ravnborg 		break;
152752dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
152852dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
152952dc0595SQuentin Casasnovas 		      "we should never get here.");
153052dc0595SQuentin Casasnovas 		break;
1531588ccd73SSam Ravnborg 	}
1532588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
153358fb0d4fSSam Ravnborg }
153458fb0d4fSSam Ravnborg 
1535644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1536644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
153758fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
153858fb0d4fSSam Ravnborg {
153958fb0d4fSSam Ravnborg 	const char *tosec;
1540588ccd73SSam Ravnborg 	Elf_Sym *to;
1541588ccd73SSam Ravnborg 	Elf_Sym *from;
154258fb0d4fSSam Ravnborg 	const char *tosym;
1543588ccd73SSam Ravnborg 	const char *fromsym;
154458fb0d4fSSam Ravnborg 
1545588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1546588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
154758fb0d4fSSam Ravnborg 
1548d62c4765SMasahiro Yamada 	if (strstarts(fromsym, "reference___initcall"))
154977ab21adSAndi Kleen 		return;
155077ab21adSAndi Kleen 
1551c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1552c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1553c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1554c7a65e06SQuentin Casasnovas 
155558fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1556af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1557af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1558588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1559588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1560588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1561588ccd73SSam Ravnborg 				    is_function(to));
156258fb0d4fSSam Ravnborg 	}
1563b39927cfSSam Ravnborg }
1564644e8f14SQuentin Casasnovas 
156552dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
156652dc0595SQuentin Casasnovas {
156752dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
156852dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
156952dc0595SQuentin Casasnovas 
157052dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
157152dc0595SQuentin Casasnovas }
157252dc0595SQuentin Casasnovas 
157352dc0595SQuentin Casasnovas /*
157452dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
157552dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
157652dc0595SQuentin Casasnovas  */
157752dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1578e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
157952dc0595SQuentin Casasnovas {
158052dc0595SQuentin Casasnovas 	/*
158152dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
158252dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
158352dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
158452dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
158552dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
158652dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
158752dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
158852dc0595SQuentin Casasnovas 	 */
1589e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
159052dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
159152dc0595SQuentin Casasnovas }
1592e84048aaSQuentin Casasnovas 
159352dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
159452dc0595SQuentin Casasnovas {
1595d3df4de7SQuentin Casasnovas 	/*
1596d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1597d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1598d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1599d3df4de7SQuentin Casasnovas 	 */
1600d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
160152dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
160252dc0595SQuentin Casasnovas 
160352dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
160452dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
160552dc0595SQuentin Casasnovas }
160652dc0595SQuentin Casasnovas 
1607e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1608e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1609e84048aaSQuentin Casasnovas 
161052dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
161152dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
161252dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
161352dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
161452dc0595SQuentin Casasnovas {
161552dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
161652dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
161752dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
161852dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
161952dc0595SQuentin Casasnovas 	const char* from_pretty_name;
162052dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
162152dc0595SQuentin Casasnovas 	const char* to_pretty_name;
162252dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
162352dc0595SQuentin Casasnovas 
162452dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
162552dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
162652dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
162752dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
162852dc0595SQuentin Casasnovas 
162952dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
163052dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
163152dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
163252dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
163352dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
163452dc0595SQuentin Casasnovas 
163552dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
163652dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
163752dc0595SQuentin Casasnovas 		fprintf(stderr,
163852dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
163952dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
164052dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
164152dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
164252dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
164352dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
164452dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
164552dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
164652dc0595SQuentin Casasnovas }
164752dc0595SQuentin Casasnovas 
164852dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
164952dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
165052dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
165152dc0595SQuentin Casasnovas 				     const char *fromsec)
165252dc0595SQuentin Casasnovas {
165352dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
165452dc0595SQuentin Casasnovas 
165552dc0595SQuentin Casasnovas 	sec_mismatch_count++;
165652dc0595SQuentin Casasnovas 
165746c7dd56SMasahiro Yamada 	report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
165852dc0595SQuentin Casasnovas 
165952dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
166052dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
166152dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
166252dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
166352dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
166452dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
166552dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
166652dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
166752dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
166852dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
166952dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
167052dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
167152dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
167252dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
167352dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
167452dc0595SQuentin Casasnovas 		else
167552dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
167652dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
167752dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
167852dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
167952dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
168052dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
168152dc0595SQuentin Casasnovas 	}
168252dc0595SQuentin Casasnovas }
168352dc0595SQuentin Casasnovas 
1684644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1685644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1686644e8f14SQuentin Casasnovas {
16870cad61d7SLuis de Bethencourt 	const char *tosec = sec_name(elf, get_secindex(elf, sym));
1688644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1689644e8f14SQuentin Casasnovas 
1690644e8f14SQuentin Casasnovas 	if (mismatch) {
1691644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1692644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1693644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1694644e8f14SQuentin Casasnovas 		else
1695644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1696644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1697644e8f14SQuentin Casasnovas 	}
1698b39927cfSSam Ravnborg }
1699b39927cfSSam Ravnborg 
1700ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
17015b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1702ae4ac123SAtsushi Nemoto {
1703ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17046845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1705ae4ac123SAtsushi Nemoto 
1706ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1707731ece41SOlof Johansson 		r->r_offset;
1708ae4ac123SAtsushi Nemoto }
1709ae4ac123SAtsushi Nemoto 
17105b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1711ae4ac123SAtsushi Nemoto {
1712ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17135b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1714ae4ac123SAtsushi Nemoto 
1715ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1716ae4ac123SAtsushi Nemoto 	case R_386_32:
1717ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1718ae4ac123SAtsushi Nemoto 		break;
1719ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1720ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1721ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1722ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1723ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1724ae4ac123SAtsushi Nemoto 		break;
1725ae4ac123SAtsushi Nemoto 	}
1726ae4ac123SAtsushi Nemoto 	return 0;
1727ae4ac123SAtsushi Nemoto }
1728ae4ac123SAtsushi Nemoto 
17296e2e340bSTony Lindgren #ifndef R_ARM_CALL
17306e2e340bSTony Lindgren #define R_ARM_CALL	28
17316e2e340bSTony Lindgren #endif
17326e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17336e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17346e2e340bSTony Lindgren #endif
17356e2e340bSTony Lindgren 
1736c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1737c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1738c9698e5cSDavid A. Long #endif
1739c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1740c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1741c9698e5cSDavid A. Long #endif
1742c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1743c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1744c9698e5cSDavid A. Long #endif
1745c9698e5cSDavid A. Long 
17465b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
174756a974faSSam Ravnborg {
174856a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
174956a974faSSam Ravnborg 
175056a974faSSam Ravnborg 	switch (r_typ) {
175156a974faSSam Ravnborg 	case R_ARM_ABS32:
175256a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1753df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1754df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
175556a974faSSam Ravnborg 		break;
175656a974faSSam Ravnborg 	case R_ARM_PC24:
17576e2e340bSTony Lindgren 	case R_ARM_CALL:
17586e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1759c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1760c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1761c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
176256a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1763df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
17645b24c071SSam Ravnborg 			      sechdr->sh_offset +
17655b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
176656a974faSSam Ravnborg 		break;
176756a974faSSam Ravnborg 	default:
176856a974faSSam Ravnborg 		return 1;
176956a974faSSam Ravnborg 	}
177056a974faSSam Ravnborg 	return 0;
177156a974faSSam Ravnborg }
177256a974faSSam Ravnborg 
17735b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1774ae4ac123SAtsushi Nemoto {
1775ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17765b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1777ae4ac123SAtsushi Nemoto 	unsigned int inst;
1778ae4ac123SAtsushi Nemoto 
1779ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1780ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1781ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1782ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1783ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1784ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1785ae4ac123SAtsushi Nemoto 		break;
1786ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1787ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1788ae4ac123SAtsushi Nemoto 		break;
1789ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1790ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1791ae4ac123SAtsushi Nemoto 		break;
1792ae4ac123SAtsushi Nemoto 	}
1793ae4ac123SAtsushi Nemoto 	return 0;
1794ae4ac123SAtsushi Nemoto }
1795ae4ac123SAtsushi Nemoto 
17965b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
179710668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1798b39927cfSSam Ravnborg {
1799b39927cfSSam Ravnborg 	Elf_Sym  *sym;
18005b24c071SSam Ravnborg 	Elf_Rela *rela;
18012c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1802eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18035b24c071SSam Ravnborg 	const char *fromsec;
18045b24c071SSam Ravnborg 
1805ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18065b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18075b24c071SSam Ravnborg 
1808ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18095b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18105b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1811b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18125b24c071SSam Ravnborg 		return;
1813e241a630SSam Ravnborg 
1814b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1815b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1816eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1817ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1818ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1819eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1820eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1821ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1822ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1823eae07ac6SAtsushi Nemoto 		} else {
1824601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1825eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1826eae07ac6SAtsushi Nemoto 		}
1827eae07ac6SAtsushi Nemoto #else
1828eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1829eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1830eae07ac6SAtsushi Nemoto #endif
183193684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1832eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1833b39927cfSSam Ravnborg 		/* Skip special sections */
18341ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1835b39927cfSSam Ravnborg 			continue;
1836e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1837e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
183858fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18392c1a51f3SAtsushi Nemoto 	}
18405b24c071SSam Ravnborg }
18415b24c071SSam Ravnborg 
18425b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
184310668220SSam Ravnborg 			Elf_Shdr *sechdr)
18445b24c071SSam Ravnborg {
18455b24c071SSam Ravnborg 	Elf_Sym *sym;
18462c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
18475b24c071SSam Ravnborg 	Elf_Rela r;
18485b24c071SSam Ravnborg 	unsigned int r_sym;
18495b24c071SSam Ravnborg 	const char *fromsec;
18505b24c071SSam Ravnborg 
1851ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
18525b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
18535b24c071SSam Ravnborg 
1854ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18555b24c071SSam Ravnborg 	fromsec += strlen(".rel");
18565b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1857b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18585b24c071SSam Ravnborg 		return;
18592c1a51f3SAtsushi Nemoto 
18602c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
18612c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1862eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1863ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1864ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1865eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1866eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1867ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1868ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1869eae07ac6SAtsushi Nemoto 		} else {
18702c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1871eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1872eae07ac6SAtsushi Nemoto 		}
1873eae07ac6SAtsushi Nemoto #else
1874eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1875eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1876eae07ac6SAtsushi Nemoto #endif
18772c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1878ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1879ae4ac123SAtsushi Nemoto 		case EM_386:
18805b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1881ae4ac123SAtsushi Nemoto 				continue;
1882ae4ac123SAtsushi Nemoto 			break;
188356a974faSSam Ravnborg 		case EM_ARM:
18845b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
188556a974faSSam Ravnborg 				continue;
188656a974faSSam Ravnborg 			break;
1887ae4ac123SAtsushi Nemoto 		case EM_MIPS:
18885b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1889ae4ac123SAtsushi Nemoto 				continue;
1890ae4ac123SAtsushi Nemoto 			break;
1891ae4ac123SAtsushi Nemoto 		}
1892eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
18932c1a51f3SAtsushi Nemoto 		/* Skip special sections */
18941ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
18952c1a51f3SAtsushi Nemoto 			continue;
1896e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1897e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
189858fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18992c1a51f3SAtsushi Nemoto 	}
1900b39927cfSSam Ravnborg }
19015b24c071SSam Ravnborg 
19025b24c071SSam Ravnborg /**
19035b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19045b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19055b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1906b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19075b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19085b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
190932be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19105b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19115b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19125b24c071SSam Ravnborg  * be discarded and warns about it.
19135b24c071SSam Ravnborg  **/
19145b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
191510668220SSam Ravnborg 			  struct elf_info *elf)
19165b24c071SSam Ravnborg {
19175b24c071SSam Ravnborg 	int i;
19185b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19195b24c071SSam Ravnborg 
19205b24c071SSam Ravnborg 	/* Walk through all sections */
19211ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1922b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19235b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19245b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
192510668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19265b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
192710668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1928b39927cfSSam Ravnborg 	}
1929b39927cfSSam Ravnborg }
1930b39927cfSSam Ravnborg 
19317d02b490SAndi Kleen static char *remove_dot(char *s)
19327d02b490SAndi Kleen {
1933fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19347d02b490SAndi Kleen 
1935fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1936fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1937fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
19387d02b490SAndi Kleen 			s[n] = 0;
19397d02b490SAndi Kleen 	}
19407d02b490SAndi Kleen 	return s;
19417d02b490SAndi Kleen }
19427d02b490SAndi Kleen 
19438b185743SMasahiro Yamada static void read_symbols(const char *modname)
19441da177e4SLinus Torvalds {
19451da177e4SLinus Torvalds 	const char *symname;
19461da177e4SLinus Torvalds 	char *version;
1947b817f6feSSam Ravnborg 	char *license;
19481da177e4SLinus Torvalds 	struct module *mod;
19491da177e4SLinus Torvalds 	struct elf_info info = { };
19501da177e4SLinus Torvalds 	Elf_Sym *sym;
19511da177e4SLinus Torvalds 
195285bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
195385bd2fddSSam Ravnborg 		return;
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds 	mod = new_module(modname);
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
19581da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
19591da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
19601da177e4SLinus Torvalds 		have_vmlinux = 1;
19611da177e4SLinus Torvalds 		mod->skip = 1;
19621da177e4SLinus Torvalds 	}
19631da177e4SLinus Torvalds 
1964bca2cceeSMasahiro Yamada 	license = get_modinfo(&info, "license");
1965ba1029c9SRandy Dunlap 	if (!license && !is_vmlinux(modname))
19662fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
1967eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
1968eed7d279SSam Ravnborg 		     "more information\n", modname);
1969b817f6feSSam Ravnborg 	while (license) {
1970b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
1971b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
1972b817f6feSSam Ravnborg 		else {
1973b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
1974b817f6feSSam Ravnborg 			break;
1975b817f6feSSam Ravnborg 		}
1976bca2cceeSMasahiro Yamada 		license = get_next_modinfo(&info, "license", license);
1977b817f6feSSam Ravnborg 	}
1978b817f6feSSam Ravnborg 
19791da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
19807d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
19811da177e4SLinus Torvalds 
19821da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
19831da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
19841da177e4SLinus Torvalds 	}
198515bfc234SDenis Efremov 
198615bfc234SDenis Efremov 	// check for static EXPORT_SYMBOL_* functions && global vars
198715bfc234SDenis Efremov 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
198815bfc234SDenis Efremov 		unsigned char bind = ELF_ST_BIND(sym->st_info);
198915bfc234SDenis Efremov 
199015bfc234SDenis Efremov 		if (bind == STB_GLOBAL || bind == STB_WEAK) {
199115bfc234SDenis Efremov 			struct symbol *s =
199215bfc234SDenis Efremov 				find_symbol(remove_dot(info.strtab +
199315bfc234SDenis Efremov 						       sym->st_name));
199415bfc234SDenis Efremov 
199515bfc234SDenis Efremov 			if (s)
199615bfc234SDenis Efremov 				s->is_static = 0;
199715bfc234SDenis Efremov 		}
199815bfc234SDenis Efremov 	}
199915bfc234SDenis Efremov 
2000074a04f5SMasahiro Yamada 	if (!is_vmlinux(modname) || vmlinux_section_warnings)
200110668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
20021da177e4SLinus Torvalds 
2003bca2cceeSMasahiro Yamada 	version = get_modinfo(&info, "version");
20041da177e4SLinus Torvalds 	if (version)
20051da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
20061da177e4SLinus Torvalds 				       version - (char *)info.hdr);
20071da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
20081da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
20091da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
20101da177e4SLinus Torvalds 
20111da177e4SLinus Torvalds 	parse_elf_finish(&info);
20121da177e4SLinus Torvalds 
20138c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
20141da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
20151da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
20161da177e4SLinus Torvalds 	 * important anyhow */
20171da177e4SLinus Torvalds 	if (modversions)
20188c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
20191da177e4SLinus Torvalds }
20201da177e4SLinus Torvalds 
2021712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2022712f9b46SRusty Russell {
2023712f9b46SRusty Russell 	FILE *in = stdin;
2024712f9b46SRusty Russell 	char fname[PATH_MAX];
2025712f9b46SRusty Russell 
2026712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2027712f9b46SRusty Russell 		in = fopen(filename, "r");
2028712f9b46SRusty Russell 		if (!in)
2029712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2030712f9b46SRusty Russell 	}
2031712f9b46SRusty Russell 
2032712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2033712f9b46SRusty Russell 		if (strends(fname, "\n"))
2034712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2035712f9b46SRusty Russell 		read_symbols(fname);
2036712f9b46SRusty Russell 	}
2037712f9b46SRusty Russell 
2038712f9b46SRusty Russell 	if (in != stdin)
2039712f9b46SRusty Russell 		fclose(in);
2040712f9b46SRusty Russell }
2041712f9b46SRusty Russell 
20421da177e4SLinus Torvalds #define SZ 500
20431da177e4SLinus Torvalds 
20441da177e4SLinus Torvalds /* We first write the generated file into memory using the
20451da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
20461da177e4SLinus Torvalds  * only update the later if anything changed */
20471da177e4SLinus Torvalds 
20485c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
20495c3ead8cSSam Ravnborg 						      const char *fmt, ...)
20501da177e4SLinus Torvalds {
20511da177e4SLinus Torvalds 	char tmp[SZ];
20521da177e4SLinus Torvalds 	int len;
20531da177e4SLinus Torvalds 	va_list ap;
20541da177e4SLinus Torvalds 
20551da177e4SLinus Torvalds 	va_start(ap, fmt);
20561da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
20577670f023SSam Ravnborg 	buf_write(buf, tmp, len);
20581da177e4SLinus Torvalds 	va_end(ap);
20591da177e4SLinus Torvalds }
20601da177e4SLinus Torvalds 
20615c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
20621da177e4SLinus Torvalds {
20631da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
20647670f023SSam Ravnborg 		buf->size += len + SZ;
20651f3aa900SRandy Dunlap 		buf->p = NOFAIL(realloc(buf->p, buf->size));
20661da177e4SLinus Torvalds 	}
20671da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
20681da177e4SLinus Torvalds 	buf->pos += len;
20691da177e4SLinus Torvalds }
20701da177e4SLinus Torvalds 
2071c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2072c96fca21SSam Ravnborg {
2073c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2074c96fca21SSam Ravnborg 
2075c96fca21SSam Ravnborg 	switch (exp) {
2076c96fca21SSam Ravnborg 	case export_gpl:
2077c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2078c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2079c96fca21SSam Ravnborg 		break;
2080c96fca21SSam Ravnborg 	case export_unused_gpl:
2081c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2082c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2083c96fca21SSam Ravnborg 		break;
2084c96fca21SSam Ravnborg 	case export_gpl_future:
2085c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2086c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2087c96fca21SSam Ravnborg 		break;
2088c96fca21SSam Ravnborg 	case export_plain:
2089c96fca21SSam Ravnborg 	case export_unused:
2090c96fca21SSam Ravnborg 	case export_unknown:
2091c96fca21SSam Ravnborg 		/* ignore */
2092c96fca21SSam Ravnborg 		break;
2093c96fca21SSam Ravnborg 	}
2094c96fca21SSam Ravnborg }
2095c96fca21SSam Ravnborg 
2096c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2097c96fca21SSam Ravnborg {
2098c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2099c96fca21SSam Ravnborg 
2100c96fca21SSam Ravnborg 	switch (exp) {
2101c96fca21SSam Ravnborg 	case export_unused:
2102c96fca21SSam Ravnborg 	case export_unused_gpl:
2103c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2104c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2105c96fca21SSam Ravnborg 		break;
2106c96fca21SSam Ravnborg 	default:
2107c96fca21SSam Ravnborg 		/* ignore */
2108c96fca21SSam Ravnborg 		break;
2109c96fca21SSam Ravnborg 	}
2110c96fca21SSam Ravnborg }
2111c96fca21SSam Ravnborg 
21123b415288SMasahiro Yamada static int check_exports(struct module *mod)
2113b817f6feSSam Ravnborg {
2114b817f6feSSam Ravnborg 	struct symbol *s, *exp;
21153b415288SMasahiro Yamada 	int err = 0;
2116b817f6feSSam Ravnborg 
2117b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21186449bd62SAndrew Morton 		const char *basename;
2119b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
21203b415288SMasahiro Yamada 		if (!exp || exp->module == mod) {
21213b415288SMasahiro Yamada 			if (have_vmlinux && !s->weak) {
21223b415288SMasahiro Yamada 				if (warn_unresolved) {
21233b415288SMasahiro Yamada 					warn("\"%s\" [%s.ko] undefined!\n",
21243b415288SMasahiro Yamada 					     s->name, mod->name);
21253b415288SMasahiro Yamada 				} else {
21263b415288SMasahiro Yamada 					merror("\"%s\" [%s.ko] undefined!\n",
21273b415288SMasahiro Yamada 					       s->name, mod->name);
21283b415288SMasahiro Yamada 					err = 1;
21293b415288SMasahiro Yamada 				}
21303b415288SMasahiro Yamada 			}
2131b817f6feSSam Ravnborg 			continue;
21323b415288SMasahiro Yamada 		}
21336449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2134b817f6feSSam Ravnborg 		if (basename)
2135b817f6feSSam Ravnborg 			basename++;
2136c96fca21SSam Ravnborg 		else
2137c96fca21SSam Ravnborg 			basename = mod->name;
2138c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2139c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2140c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2141b817f6feSSam Ravnborg 	}
21423b415288SMasahiro Yamada 
21433b415288SMasahiro Yamada 	return err;
2144b817f6feSSam Ravnborg }
2145b817f6feSSam Ravnborg 
21464fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
21474fd3e4efSWanlong Gao {
21484fd3e4efSWanlong Gao 	const char *mod_name;
21494fd3e4efSWanlong Gao 
21504fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
21514fd3e4efSWanlong Gao 	if (mod_name == NULL)
21524fd3e4efSWanlong Gao 		mod_name = mod->name;
21534fd3e4efSWanlong Gao 	else
21544fd3e4efSWanlong Gao 		mod_name++;
21554fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
21564fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
21574fd3e4efSWanlong Gao 		return 1;
21584fd3e4efSWanlong Gao 	}
21594fd3e4efSWanlong Gao 
21604fd3e4efSWanlong Gao 	return 0;
21614fd3e4efSWanlong Gao }
21624fd3e4efSWanlong Gao 
21635c3ead8cSSam Ravnborg /**
21645c3ead8cSSam Ravnborg  * Header for the generated file
21655c3ead8cSSam Ravnborg  **/
21665c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
21671da177e4SLinus Torvalds {
21689afb719eSLaura Abbott 	buf_printf(b, "#include <linux/build-salt.h>\n");
21691da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
21701da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
21711da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
21721da177e4SLinus Torvalds 	buf_printf(b, "\n");
21739afb719eSLaura Abbott 	buf_printf(b, "BUILD_SALT;\n");
21749afb719eSLaura Abbott 	buf_printf(b, "\n");
21751da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
21763e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
21771da177e4SLinus Torvalds 	buf_printf(b, "\n");
2178e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
2179*a3d0cb04SMasahiro Yamada 	buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
21803c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
21811da177e4SLinus Torvalds 	if (mod->has_init)
21823c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
21831da177e4SLinus Torvalds 	if (mod->has_cleanup)
21841da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
21853c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
21861da177e4SLinus Torvalds 			      "#endif\n");
21873c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
21881da177e4SLinus Torvalds 	buf_printf(b, "};\n");
21891da177e4SLinus Torvalds }
21901da177e4SLinus Torvalds 
21912449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
21922449b8baSBen Hutchings {
21932449b8baSBen Hutchings 	if (is_intree)
21942449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
21952449b8baSBen Hutchings }
21962449b8baSBen Hutchings 
2197caf7501aSAndi Kleen /* Cannot check for assembler */
2198caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2199caf7501aSAndi Kleen {
2200e4f35891SWANG Chao 	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
2201caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2202caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2203caf7501aSAndi Kleen }
2204caf7501aSAndi Kleen 
22055c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2206a9860bf0SGreg Kroah-Hartman {
2207d62c4765SMasahiro Yamada 	if (strstarts(name, "drivers/staging"))
2208a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2209a9860bf0SGreg Kroah-Hartman }
2210a9860bf0SGreg Kroah-Hartman 
22115c3ead8cSSam Ravnborg /**
22125c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
22135c3ead8cSSam Ravnborg  **/
2214c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
22151da177e4SLinus Torvalds {
22161da177e4SLinus Torvalds 	struct symbol *s, *exp;
2217c53ddacdSKirill Korotaev 	int err = 0;
22181da177e4SLinus Torvalds 
22191da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
22201da177e4SLinus Torvalds 		exp = find_symbol(s->name);
22213b415288SMasahiro Yamada 		if (!exp || exp->module == mod)
22221da177e4SLinus Torvalds 			continue;
22231da177e4SLinus Torvalds 		s->module = exp->module;
22241da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
22251da177e4SLinus Torvalds 		s->crc = exp->crc;
22261da177e4SLinus Torvalds 	}
22271da177e4SLinus Torvalds 
22281da177e4SLinus Torvalds 	if (!modversions)
2229c53ddacdSKirill Korotaev 		return err;
22301da177e4SLinus Torvalds 
22311da177e4SLinus Torvalds 	buf_printf(b, "\n");
22321da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
2233*a3d0cb04SMasahiro Yamada 	buf_printf(b, "__used __section(__versions) = {\n");
22341da177e4SLinus Torvalds 
22351da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2236df578e7dSSam Ravnborg 		if (!s->module)
22371da177e4SLinus Torvalds 			continue;
22381da177e4SLinus Torvalds 		if (!s->crc_valid) {
2239cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
22401da177e4SLinus Torvalds 				s->name, mod->name);
22411da177e4SLinus Torvalds 			continue;
22421da177e4SLinus Torvalds 		}
22435cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
22445cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
22455cfb203aSTakashi Iwai 			       s->name, mod->name);
22465cfb203aSTakashi Iwai 			err = 1;
22475cfb203aSTakashi Iwai 			break;
22485cfb203aSTakashi Iwai 		}
2249b2c5cdcfSMasahiro Yamada 		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
2250a4b6a77bSJames Hogan 			   s->crc, s->name);
22511da177e4SLinus Torvalds 	}
22521da177e4SLinus Torvalds 
22531da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2254c53ddacdSKirill Korotaev 
2255c53ddacdSKirill Korotaev 	return err;
22561da177e4SLinus Torvalds }
22571da177e4SLinus Torvalds 
2258d2665ca8SMasahiro Yamada static void add_depends(struct buffer *b, struct module *mod)
22591da177e4SLinus Torvalds {
22601da177e4SLinus Torvalds 	struct symbol *s;
22611da177e4SLinus Torvalds 	int first = 1;
22621da177e4SLinus Torvalds 
2263d2665ca8SMasahiro Yamada 	/* Clear ->seen flag of modules that own symbols needed by this. */
2264d2665ca8SMasahiro Yamada 	for (s = mod->unres; s; s = s->next)
2265d2665ca8SMasahiro Yamada 		if (s->module)
2266d2665ca8SMasahiro Yamada 			s->module->seen = is_vmlinux(s->module->name);
22671da177e4SLinus Torvalds 
22681da177e4SLinus Torvalds 	buf_printf(b, "\n");
22696df7e1ecSMasahiro Yamada 	buf_printf(b, "MODULE_INFO(depends, \"");
22701da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2271a61b2dfdSSam Ravnborg 		const char *p;
22721da177e4SLinus Torvalds 		if (!s->module)
22731da177e4SLinus Torvalds 			continue;
22741da177e4SLinus Torvalds 
22751da177e4SLinus Torvalds 		if (s->module->seen)
22761da177e4SLinus Torvalds 			continue;
22771da177e4SLinus Torvalds 
22781da177e4SLinus Torvalds 		s->module->seen = 1;
2279df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2280df578e7dSSam Ravnborg 		if (p)
2281a61b2dfdSSam Ravnborg 			p++;
2282a61b2dfdSSam Ravnborg 		else
2283a61b2dfdSSam Ravnborg 			p = s->module->name;
2284a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
22851da177e4SLinus Torvalds 		first = 0;
22861da177e4SLinus Torvalds 	}
22876df7e1ecSMasahiro Yamada 	buf_printf(b, "\");\n");
22881da177e4SLinus Torvalds }
22891da177e4SLinus Torvalds 
22905c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
22911da177e4SLinus Torvalds {
22921da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
22931da177e4SLinus Torvalds 		buf_printf(b, "\n");
22941da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
22951da177e4SLinus Torvalds 			   mod->srcversion);
22961da177e4SLinus Torvalds 	}
22971da177e4SLinus Torvalds }
22981da177e4SLinus Torvalds 
22995c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
23001da177e4SLinus Torvalds {
23011da177e4SLinus Torvalds 	char *tmp;
23021da177e4SLinus Torvalds 	FILE *file;
23031da177e4SLinus Torvalds 	struct stat st;
23041da177e4SLinus Torvalds 
23051da177e4SLinus Torvalds 	file = fopen(fname, "r");
23061da177e4SLinus Torvalds 	if (!file)
23071da177e4SLinus Torvalds 		goto write;
23081da177e4SLinus Torvalds 
23091da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
23101da177e4SLinus Torvalds 		goto close_write;
23111da177e4SLinus Torvalds 
23121da177e4SLinus Torvalds 	if (st.st_size != b->pos)
23131da177e4SLinus Torvalds 		goto close_write;
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
23161da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
23171da177e4SLinus Torvalds 		goto free_write;
23181da177e4SLinus Torvalds 
23191da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
23201da177e4SLinus Torvalds 		goto free_write;
23211da177e4SLinus Torvalds 
23221da177e4SLinus Torvalds 	free(tmp);
23231da177e4SLinus Torvalds 	fclose(file);
23241da177e4SLinus Torvalds 	return;
23251da177e4SLinus Torvalds 
23261da177e4SLinus Torvalds  free_write:
23271da177e4SLinus Torvalds 	free(tmp);
23281da177e4SLinus Torvalds  close_write:
23291da177e4SLinus Torvalds 	fclose(file);
23301da177e4SLinus Torvalds  write:
23311da177e4SLinus Torvalds 	file = fopen(fname, "w");
23321da177e4SLinus Torvalds 	if (!file) {
23331da177e4SLinus Torvalds 		perror(fname);
23341da177e4SLinus Torvalds 		exit(1);
23351da177e4SLinus Torvalds 	}
23361da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
23371da177e4SLinus Torvalds 		perror(fname);
23381da177e4SLinus Torvalds 		exit(1);
23391da177e4SLinus Torvalds 	}
23401da177e4SLinus Torvalds 	fclose(file);
23411da177e4SLinus Torvalds }
23421da177e4SLinus Torvalds 
2343bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2344534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2345bd5cbcedSRam Pai  **/
2346040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
23471da177e4SLinus Torvalds {
23481da177e4SLinus Torvalds 	unsigned long size, pos = 0;
23491da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
23501da177e4SLinus Torvalds 	char *line;
23511da177e4SLinus Torvalds 
23521da177e4SLinus Torvalds 	if (!file)
23531da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
23541da177e4SLinus Torvalds 		return;
23551da177e4SLinus Torvalds 
23561da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2357534b89a9SSam Ravnborg 		char *symname, *modname, *d, *export, *end;
23581da177e4SLinus Torvalds 		unsigned int crc;
23591da177e4SLinus Torvalds 		struct module *mod;
2360040fcc81SSam Ravnborg 		struct symbol *s;
23611da177e4SLinus Torvalds 
23621da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
23631da177e4SLinus Torvalds 			goto fail;
23641da177e4SLinus Torvalds 		*symname++ = '\0';
23651da177e4SLinus Torvalds 		if (!(modname = strchr(symname, '\t')))
23661da177e4SLinus Torvalds 			goto fail;
23671da177e4SLinus Torvalds 		*modname++ = '\0';
23689ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2369bd5cbcedSRam Pai 			*export++ = '\0';
2370534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2371534b89a9SSam Ravnborg 			*end = '\0';
23721da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
23731da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
23741da177e4SLinus Torvalds 			goto fail;
2375df578e7dSSam Ravnborg 		mod = find_module(modname);
2376df578e7dSSam Ravnborg 		if (!mod) {
2377df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
23781da177e4SLinus Torvalds 				have_vmlinux = 1;
23790fa3a88cSJan Beulich 			mod = new_module(modname);
23801da177e4SLinus Torvalds 			mod->skip = 1;
23811da177e4SLinus Torvalds 		}
2382bd5cbcedSRam Pai 		s = sym_add_exported(symname, mod, export_no(export));
2383040fcc81SSam Ravnborg 		s->kernel    = kernel;
23848e70c458SSam Ravnborg 		s->preloaded = 1;
238515bfc234SDenis Efremov 		s->is_static = 0;
2386bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
23871da177e4SLinus Torvalds 	}
23882ee41e62SChristian Engelmayer 	release_file(file, size);
23891da177e4SLinus Torvalds 	return;
23901da177e4SLinus Torvalds fail:
23912ee41e62SChristian Engelmayer 	release_file(file, size);
23921da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
23931da177e4SLinus Torvalds }
23941da177e4SLinus Torvalds 
2395040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2396040fcc81SSam Ravnborg  * For external modules only dump symbols
2397040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2398040fcc81SSam Ravnborg  **/
2399040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2400040fcc81SSam Ravnborg {
2401040fcc81SSam Ravnborg 	if (!external_module)
2402040fcc81SSam Ravnborg 		return 1;
2403040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2404040fcc81SSam Ravnborg 		return 0;
2405040fcc81SSam Ravnborg 	return 1;
2406040fcc81SSam Ravnborg }
2407040fcc81SSam Ravnborg 
24085c3ead8cSSam Ravnborg static void write_dump(const char *fname)
24091da177e4SLinus Torvalds {
24101da177e4SLinus Torvalds 	struct buffer buf = { };
24111da177e4SLinus Torvalds 	struct symbol *symbol;
24121da177e4SLinus Torvalds 	int n;
24131da177e4SLinus Torvalds 
24141da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
24151da177e4SLinus Torvalds 		symbol = symbolhash[n];
24161da177e4SLinus Torvalds 		while (symbol) {
2417040fcc81SSam Ravnborg 			if (dump_sym(symbol))
2418bd5cbcedSRam Pai 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
2419040fcc81SSam Ravnborg 					symbol->crc, symbol->name,
2420bd5cbcedSRam Pai 					symbol->module->name,
2421bd5cbcedSRam Pai 					export_str(symbol->export));
24221da177e4SLinus Torvalds 			symbol = symbol->next;
24231da177e4SLinus Torvalds 		}
24241da177e4SLinus Torvalds 	}
24251da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2426c7d47f26SHeinrich Schuchardt 	free(buf.p);
24271da177e4SLinus Torvalds }
24281da177e4SLinus Torvalds 
24292d04b5aeSRichard Hacker struct ext_sym_list {
24302d04b5aeSRichard Hacker 	struct ext_sym_list *next;
24312d04b5aeSRichard Hacker 	const char *file;
24322d04b5aeSRichard Hacker };
24332d04b5aeSRichard Hacker 
24345c3ead8cSSam Ravnborg int main(int argc, char **argv)
24351da177e4SLinus Torvalds {
24361da177e4SLinus Torvalds 	struct module *mod;
24371da177e4SLinus Torvalds 	struct buffer buf = { };
2438040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2439712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
24401da177e4SLinus Torvalds 	int opt;
2441c53ddacdSKirill Korotaev 	int err;
244215bfc234SDenis Efremov 	int n;
24432d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
24442d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
24451da177e4SLinus Torvalds 
244646c7dd56SMasahiro Yamada 	while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awE")) != -1) {
24471da177e4SLinus Torvalds 		switch (opt) {
24481da177e4SLinus Torvalds 		case 'i':
2449040fcc81SSam Ravnborg 			kernel_read = optarg;
2450040fcc81SSam Ravnborg 			break;
2451040fcc81SSam Ravnborg 		case 'I':
2452040fcc81SSam Ravnborg 			module_read = optarg;
2453040fcc81SSam Ravnborg 			external_module = 1;
24541da177e4SLinus Torvalds 			break;
24552d04b5aeSRichard Hacker 		case 'e':
24562d04b5aeSRichard Hacker 			external_module = 1;
24572d04b5aeSRichard Hacker 			extsym_iter =
24582d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
24592d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
24602d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
24612d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
24622d04b5aeSRichard Hacker 			break;
24631da177e4SLinus Torvalds 		case 'm':
24641da177e4SLinus Torvalds 			modversions = 1;
24651da177e4SLinus Torvalds 			break;
2466eed380f3SGuenter Roeck 		case 'n':
2467eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2468eed380f3SGuenter Roeck 			break;
24691da177e4SLinus Torvalds 		case 'o':
24701da177e4SLinus Torvalds 			dump_write = optarg;
24711da177e4SLinus Torvalds 			break;
24721da177e4SLinus Torvalds 		case 'a':
24731da177e4SLinus Torvalds 			all_versions = 1;
24741da177e4SLinus Torvalds 			break;
24758d8d8289SSam Ravnborg 		case 's':
24768d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
24778d8d8289SSam Ravnborg 			break;
2478712f9b46SRusty Russell 		case 'T':
2479712f9b46SRusty Russell 			files_source = optarg;
2480712f9b46SRusty Russell 			break;
2481c53ddacdSKirill Korotaev 		case 'w':
2482c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2483c53ddacdSKirill Korotaev 			break;
248447490ec1SNicolas Boichat 		case 'E':
248547490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
248647490ec1SNicolas Boichat 			break;
24871da177e4SLinus Torvalds 		default:
24881da177e4SLinus Torvalds 			exit(1);
24891da177e4SLinus Torvalds 		}
24901da177e4SLinus Torvalds 	}
24911da177e4SLinus Torvalds 
2492040fcc81SSam Ravnborg 	if (kernel_read)
2493040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2494040fcc81SSam Ravnborg 	if (module_read)
2495040fcc81SSam Ravnborg 		read_dump(module_read, 0);
24962d04b5aeSRichard Hacker 	while (extsym_start) {
24972d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
24982d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
24992d04b5aeSRichard Hacker 		free(extsym_start);
25002d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
25012d04b5aeSRichard Hacker 	}
25021da177e4SLinus Torvalds 
2503df578e7dSSam Ravnborg 	while (optind < argc)
25041da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
25051da177e4SLinus Torvalds 
2506712f9b46SRusty Russell 	if (files_source)
2507712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2508712f9b46SRusty Russell 
2509c53ddacdSKirill Korotaev 	err = 0;
2510c53ddacdSKirill Korotaev 
2511b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2512d93e1719SMathias Krause 		char fname[PATH_MAX];
2513666ab414SAndi Kleen 
2514b817f6feSSam Ravnborg 		if (mod->skip)
2515b817f6feSSam Ravnborg 			continue;
25161da177e4SLinus Torvalds 
25171da177e4SLinus Torvalds 		buf.pos = 0;
25181da177e4SLinus Torvalds 
25194fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
25203b415288SMasahiro Yamada 		err |= check_exports(mod);
25211da177e4SLinus Torvalds 		add_header(&buf, mod);
25222449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2523caf7501aSAndi Kleen 		add_retpoline(&buf);
2524a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2525c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
2526d2665ca8SMasahiro Yamada 		add_depends(&buf, mod);
25271da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
25281da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
25291da177e4SLinus Torvalds 
25301da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
25311da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
25321da177e4SLinus Torvalds 	}
25331da177e4SLinus Torvalds 	if (dump_write)
25341da177e4SLinus Torvalds 		write_dump(dump_write);
253546c7dd56SMasahiro Yamada 	if (sec_mismatch_count && sec_mismatch_fatal)
253647490ec1SNicolas Boichat 		fatal("modpost: Section mismatches detected.\n"
253747490ec1SNicolas Boichat 		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
253815bfc234SDenis Efremov 	for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
253915bfc234SDenis Efremov 		struct symbol *s = symbolhash[n];
254015bfc234SDenis Efremov 
254115bfc234SDenis Efremov 		while (s) {
254215bfc234SDenis Efremov 			if (s->is_static)
254315bfc234SDenis Efremov 				warn("\"%s\" [%s] is a static %s\n",
254415bfc234SDenis Efremov 				     s->name, s->module->name,
254515bfc234SDenis Efremov 				     export_str(s->export));
254615bfc234SDenis Efremov 
254715bfc234SDenis Efremov 			s = s->next;
254815bfc234SDenis Efremov 		}
254915bfc234SDenis Efremov 	}
255015bfc234SDenis Efremov 
2551c7d47f26SHeinrich Schuchardt 	free(buf.p);
25521da177e4SLinus Torvalds 
2553c53ddacdSKirill Korotaev 	return err;
25541da177e4SLinus Torvalds }
2555