xref: /linux-6.15/scripts/mod/modpost.c (revision caf7501a)
11da177e4SLinus Torvalds /* Postprocess module symbol versions
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright 2003       Kai Germaschewski
41da177e4SLinus Torvalds  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5df578e7dSSam Ravnborg  * Copyright 2006-2008  Sam Ravnborg
61da177e4SLinus Torvalds  * Based in part on module-init-tools/depmod.c,file2alias
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds  * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Usage: modpost vmlinux module1.o module2.o ...
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
14b2e3e658SMathieu Desnoyers #define _GNU_SOURCE
15b2e3e658SMathieu Desnoyers #include <stdio.h>
161da177e4SLinus Torvalds #include <ctype.h>
175003bab8SAndrew Morton #include <string.h>
18712f9b46SRusty Russell #include <limits.h>
19d4ef1c30SRusty Russell #include <stdbool.h>
20eed380f3SGuenter Roeck #include <errno.h>
211da177e4SLinus Torvalds #include "modpost.h"
225a865c06SLinus Torvalds #include "../../include/generated/autoconf.h"
23b817f6feSSam Ravnborg #include "../../include/linux/license.h"
24b92021b0SRusty Russell #include "../../include/linux/export.h"
259e1b9b80SAlan Jenkins 
261da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
277a3ee753SMathias Krause static int modversions = 0;
281da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
297a3ee753SMathias Krause static int have_vmlinux = 0;
301da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
311da177e4SLinus Torvalds static int all_versions = 0;
32040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
33040fcc81SSam Ravnborg static int external_module = 0;
348d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
358d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
36c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
37c53ddacdSKirill Korotaev static int warn_unresolved = 0;
38bd5cbcedSRam Pai /* How a symbol is exported */
39588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
40588ccd73SSam Ravnborg static int sec_mismatch_verbose = 1;
4147490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
42eed380f3SGuenter Roeck /* ignore missing files */
43eed380f3SGuenter Roeck static int ignore_missing_files;
44588ccd73SSam Ravnborg 
45c96fca21SSam Ravnborg enum export {
46c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
47c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
48c96fca21SSam Ravnborg };
491da177e4SLinus Torvalds 
504fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h;
514fd3e4efSWanlong Gao  * here we use Elf_Addr instead of long for covering cross-compile
524fd3e4efSWanlong Gao  */
534fd3e4efSWanlong Gao 
544fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
554fd3e4efSWanlong Gao 
566d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
576d9a89eaSAndi Kleen 
586d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
591da177e4SLinus Torvalds {
601da177e4SLinus Torvalds 	va_list arglist;
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	va_start(arglist, fmt);
651da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
661da177e4SLinus Torvalds 	va_end(arglist);
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	exit(1);
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
716d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	va_list arglist;
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	va_start(arglist, fmt);
781da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
791da177e4SLinus Torvalds 	va_end(arglist);
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
826d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
832a116659SMatthew Wilcox {
842a116659SMatthew Wilcox 	va_list arglist;
852a116659SMatthew Wilcox 
862a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
872a116659SMatthew Wilcox 
882a116659SMatthew Wilcox 	va_start(arglist, fmt);
892a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
902a116659SMatthew Wilcox 	va_end(arglist);
912a116659SMatthew Wilcox }
922a116659SMatthew Wilcox 
93d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
94d4ef1c30SRusty Russell {
95d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
96d4ef1c30SRusty Russell 		return false;
97d4ef1c30SRusty Russell 
98d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
99d4ef1c30SRusty Russell }
100d4ef1c30SRusty Russell 
101040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
102040fcc81SSam Ravnborg {
103040fcc81SSam Ravnborg 	const char *myname;
104040fcc81SSam Ravnborg 
105df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
106df578e7dSSam Ravnborg 	if (myname)
107040fcc81SSam Ravnborg 		myname++;
108040fcc81SSam Ravnborg 	else
109040fcc81SSam Ravnborg 		myname = modname;
110040fcc81SSam Ravnborg 
111741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
112741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
113040fcc81SSam Ravnborg }
114040fcc81SSam Ravnborg 
1151da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1161da177e4SLinus Torvalds {
117df578e7dSSam Ravnborg 	if (!ptr)
1181da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
119df578e7dSSam Ravnborg 
1201da177e4SLinus Torvalds 	return ptr;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds /* A list of all modules we processed */
1241da177e4SLinus Torvalds static struct module *modules;
1251da177e4SLinus Torvalds 
1265c3ead8cSSam Ravnborg static struct module *find_module(char *modname)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds 	struct module *mod;
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1311da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1321da177e4SLinus Torvalds 			break;
1331da177e4SLinus Torvalds 	return mod;
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds 
136d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1371da177e4SLinus Torvalds {
1381da177e4SLinus Torvalds 	struct module *mod;
139d4ef1c30SRusty Russell 	char *p;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1421da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1431da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	/* strip trailing .o */
146d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
147d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
148258f7426SFrank Rowand 		mod->is_dot_o = 1;
149258f7426SFrank Rowand 	}
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds 	/* add to list */
1521da177e4SLinus Torvalds 	mod->name = p;
153b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1541da177e4SLinus Torvalds 	mod->next = modules;
1551da177e4SLinus Torvalds 	modules = mod;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	return mod;
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /* A hash of all exported symbols,
1611da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds struct symbol {
1661da177e4SLinus Torvalds 	struct symbol *next;
1671da177e4SLinus Torvalds 	struct module *module;
1681da177e4SLinus Torvalds 	unsigned int crc;
1691da177e4SLinus Torvalds 	int crc_valid;
1701da177e4SLinus Torvalds 	unsigned int weak:1;
171040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
172040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
173040fcc81SSam Ravnborg 				    *  (only for external modules) **/
174b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
175bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1761da177e4SLinus Torvalds 	char name[0];
1771da177e4SLinus Torvalds };
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1821da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1831da177e4SLinus Torvalds {
1841da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1851da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1881da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1891da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
1945c3ead8cSSam Ravnborg /**
1955c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1965c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1975c3ead8cSSam Ravnborg  **/
1985c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1995c3ead8cSSam Ravnborg 				   struct symbol *next)
2001da177e4SLinus Torvalds {
2011da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
2041da177e4SLinus Torvalds 	strcpy(s->name, name);
2051da177e4SLinus Torvalds 	s->weak = weak;
2061da177e4SLinus Torvalds 	s->next = next;
2071da177e4SLinus Torvalds 	return s;
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /* For the hash of exported symbols */
211bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
212bd5cbcedSRam Pai 				 enum export export)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	unsigned int hash;
2151da177e4SLinus Torvalds 	struct symbol *new;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2181da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2191da177e4SLinus Torvalds 	new->module = module;
220bd5cbcedSRam Pai 	new->export = export;
221040fcc81SSam Ravnborg 	return new;
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds 
2245c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	struct symbol *s;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2291da177e4SLinus Torvalds 	if (name[0] == '.')
2301da177e4SLinus Torvalds 		name++;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2331da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2341da177e4SLinus Torvalds 			return s;
2351da177e4SLinus Torvalds 	}
2361da177e4SLinus Torvalds 	return NULL;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds 
2397a3ee753SMathias Krause static const struct {
240bd5cbcedSRam Pai 	const char *str;
241bd5cbcedSRam Pai 	enum export export;
242bd5cbcedSRam Pai } export_list[] = {
243bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
244c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
245bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
246c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
247bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
248bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
249bd5cbcedSRam Pai };
250bd5cbcedSRam Pai 
251bd5cbcedSRam Pai 
252bd5cbcedSRam Pai static const char *export_str(enum export ex)
253bd5cbcedSRam Pai {
254bd5cbcedSRam Pai 	return export_list[ex].str;
255bd5cbcedSRam Pai }
256bd5cbcedSRam Pai 
257bd5cbcedSRam Pai static enum export export_no(const char *s)
258bd5cbcedSRam Pai {
259bd5cbcedSRam Pai 	int i;
260df578e7dSSam Ravnborg 
261534b89a9SSam Ravnborg 	if (!s)
262534b89a9SSam Ravnborg 		return export_unknown;
263bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
264bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
265bd5cbcedSRam Pai 			return export_list[i].export;
266bd5cbcedSRam Pai 	}
267bd5cbcedSRam Pai 	return export_unknown;
268bd5cbcedSRam Pai }
269bd5cbcedSRam Pai 
2706124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
2716124c04cSMasahiro Yamada {
2726124c04cSMasahiro Yamada 	return (void *)elf->hdr +
2736124c04cSMasahiro Yamada 		elf->sechdrs[elf->secindex_strings].sh_offset +
2746124c04cSMasahiro Yamada 		sechdr->sh_name;
2756124c04cSMasahiro Yamada }
2766124c04cSMasahiro Yamada 
2776124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex)
2786124c04cSMasahiro Yamada {
2796124c04cSMasahiro Yamada 	return sech_name(elf, &elf->sechdrs[secindex]);
2806124c04cSMasahiro Yamada }
28162a26356SAlessio Igor Bogani 
28262a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
28362a26356SAlessio Igor Bogani 
28462a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
28562a26356SAlessio Igor Bogani {
28662a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
28762a26356SAlessio Igor Bogani 
28862a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
28962a26356SAlessio Igor Bogani 		return export_plain;
29062a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
29162a26356SAlessio Igor Bogani 		return export_unused;
29262a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
29362a26356SAlessio Igor Bogani 		return export_gpl;
29462a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
29562a26356SAlessio Igor Bogani 		return export_unused_gpl;
29662a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
29762a26356SAlessio Igor Bogani 		return export_gpl_future;
29862a26356SAlessio Igor Bogani 	else
29962a26356SAlessio Igor Bogani 		return export_unknown;
30062a26356SAlessio Igor Bogani }
30162a26356SAlessio Igor Bogani 
3021ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
303bd5cbcedSRam Pai {
304bd5cbcedSRam Pai 	if (sec == elf->export_sec)
305bd5cbcedSRam Pai 		return export_plain;
306c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
307c96fca21SSam Ravnborg 		return export_unused;
308bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
309bd5cbcedSRam Pai 		return export_gpl;
310c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
311c96fca21SSam Ravnborg 		return export_unused_gpl;
312bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
313bd5cbcedSRam Pai 		return export_gpl_future;
314bd5cbcedSRam Pai 	else
315bd5cbcedSRam Pai 		return export_unknown;
316bd5cbcedSRam Pai }
317bd5cbcedSRam Pai 
3185c3ead8cSSam Ravnborg /**
3195c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3205c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3215c3ead8cSSam Ravnborg  **/
322bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod,
323bd5cbcedSRam Pai 				       enum export export)
3241da177e4SLinus Torvalds {
3251da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	if (!s) {
328bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3298e70c458SSam Ravnborg 	} else {
3308e70c458SSam Ravnborg 		if (!s->preloaded) {
3317b75b13cSSam Ravnborg 			warn("%s: '%s' exported twice. Previous export "
3328e70c458SSam Ravnborg 			     "was in %s%s\n", mod->name, name,
3338e70c458SSam Ravnborg 			     s->module->name,
3348e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ?"":".ko");
3354b21960fSTrent Piepho 		} else {
336baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3374b21960fSTrent Piepho 			s->module = mod;
3381da177e4SLinus Torvalds 		}
3391da177e4SLinus Torvalds 	}
3408e70c458SSam Ravnborg 	s->preloaded = 0;
341040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
342040fcc81SSam Ravnborg 	s->kernel    = 0;
343bd5cbcedSRam Pai 	s->export    = export;
344040fcc81SSam Ravnborg 	return s;
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
347040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
348bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
349040fcc81SSam Ravnborg {
350040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
351040fcc81SSam Ravnborg 
352b6568b1aSRusty Russell 	if (!s) {
353bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
354b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
355b6568b1aSRusty Russell 		s->preloaded = 1;
356b6568b1aSRusty Russell 	}
357040fcc81SSam Ravnborg 	s->crc = crc;
3581da177e4SLinus Torvalds 	s->crc_valid = 1;
3591da177e4SLinus Torvalds }
3601da177e4SLinus Torvalds 
3615c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
3621da177e4SLinus Torvalds {
3631da177e4SLinus Torvalds 	struct stat st;
364eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
3651da177e4SLinus Torvalds 	int fd;
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
368eb3d5cc6SJesper Juhl 	if (fd < 0)
3691da177e4SLinus Torvalds 		return NULL;
370eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
371eb3d5cc6SJesper Juhl 		goto failed;
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	*size = st.st_size;
3741da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
3751da177e4SLinus Torvalds 
376eb3d5cc6SJesper Juhl failed:
377eb3d5cc6SJesper Juhl 	close(fd);
3781da177e4SLinus Torvalds 	if (map == MAP_FAILED)
3791da177e4SLinus Torvalds 		return NULL;
3801da177e4SLinus Torvalds 	return map;
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds 
3835c3ead8cSSam Ravnborg /**
3845c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
3855c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
3865c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
3875c3ead8cSSam Ravnborg   **/
3885c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
3891da177e4SLinus Torvalds {
3901da177e4SLinus Torvalds 	static char line[4096];
3911da177e4SLinus Torvalds 	int skip = 1;
3921da177e4SLinus Torvalds 	size_t len = 0;
3931da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
3941da177e4SLinus Torvalds 	char *s = line;
3951da177e4SLinus Torvalds 
396df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
3971da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
3981da177e4SLinus Torvalds 			p++;
3991da177e4SLinus Torvalds 			continue;
4001da177e4SLinus Torvalds 		}
4011da177e4SLinus Torvalds 		skip = 0;
4021da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4031da177e4SLinus Torvalds 			len++;
4041da177e4SLinus Torvalds 			*s++ = *p++;
4051da177e4SLinus Torvalds 			if (len > 4095)
4061da177e4SLinus Torvalds 				break; /* Too long, stop */
4071da177e4SLinus Torvalds 		} else {
4081da177e4SLinus Torvalds 			/* End of string */
4091da177e4SLinus Torvalds 			*s = '\0';
4101da177e4SLinus Torvalds 			return line;
4111da177e4SLinus Torvalds 		}
4121da177e4SLinus Torvalds 	}
4131da177e4SLinus Torvalds 	/* End of buffer */
4141da177e4SLinus Torvalds 	return NULL;
4151da177e4SLinus Torvalds }
4161da177e4SLinus Torvalds 
4175c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4181da177e4SLinus Torvalds {
4191da177e4SLinus Torvalds 	munmap(file, size);
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
42285bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4231da177e4SLinus Torvalds {
4241da177e4SLinus Torvalds 	unsigned int i;
42585bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4261da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4271da177e4SLinus Torvalds 	Elf_Sym  *sym;
4281ce53adfSDenys Vlasenko 	const char *secstrings;
4291ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4321da177e4SLinus Torvalds 	if (!hdr) {
433eed380f3SGuenter Roeck 		if (ignore_missing_files) {
434eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
435eed380f3SGuenter Roeck 				strerror(errno));
436eed380f3SGuenter Roeck 			return 0;
437eed380f3SGuenter Roeck 		}
4381da177e4SLinus Torvalds 		perror(filename);
4396803dc0eSSam Ravnborg 		exit(1);
4401da177e4SLinus Torvalds 	}
4411da177e4SLinus Torvalds 	info->hdr = hdr;
44285bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
44385bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
44485bd2fddSSam Ravnborg 		return 0;
44585bd2fddSSam Ravnborg 	}
44685bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
44785bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
44885bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
44985bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
45085bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
45185bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
45285bd2fddSSam Ravnborg 		return 0;
45385bd2fddSSam Ravnborg 	}
4541da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
455ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
4567d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
4577d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
4587d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
4597d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
4607d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
4617d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
4627d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
4637d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
4647d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
4657d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
4667d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
4677d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
4681da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
4691da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
4701da177e4SLinus Torvalds 
471a83710e5SPetr Stetiar 	/* Check if file offset is correct */
472a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
473df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
474df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
475df578e7dSSam Ravnborg 		      filename, info->size);
476a83710e5SPetr Stetiar 		return 0;
477a83710e5SPetr Stetiar 	}
478a83710e5SPetr Stetiar 
4796845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
4801ce53adfSDenys Vlasenko 		/*
4811ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
4821ce53adfSDenys Vlasenko 		 * read count from .sh_size.
4831ce53adfSDenys Vlasenko 		 */
4841ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
4851ce53adfSDenys Vlasenko 	}
4861ce53adfSDenys Vlasenko 	else {
4871ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
4881ce53adfSDenys Vlasenko 	}
4891ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
4906845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
4911ce53adfSDenys Vlasenko 	}
4921ce53adfSDenys Vlasenko 	else {
4931ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
4941ce53adfSDenys Vlasenko 	}
4951ce53adfSDenys Vlasenko 
4961da177e4SLinus Torvalds 	/* Fix endianness in section headers */
4971ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
4987d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
4991da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
5007d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
5017d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5021da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5031da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5041da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
505ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5067d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5077d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5081da177e4SLinus Torvalds 	}
5091da177e4SLinus Torvalds 	/* Find symbol table. */
5101ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5111ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
512bd5cbcedSRam Pai 		const char *secname;
51356fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5141da177e4SLinus Torvalds 
51556fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
516df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
517df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
518df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
519df578e7dSSam Ravnborg 			      sizeof(*hdr));
52085bd2fddSSam Ravnborg 			return 0;
52185bd2fddSSam Ravnborg 		}
522bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
523bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
52456fc82c5STejun Heo 			if (nobits)
52556fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5261da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5271da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
528bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
529bd5cbcedSRam Pai 			info->export_sec = i;
530c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
531c96fca21SSam Ravnborg 			info->export_unused_sec = i;
532bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
533bd5cbcedSRam Pai 			info->export_gpl_sec = i;
534c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
535c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
536bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
537bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
538bd5cbcedSRam Pai 
5391ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5401ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
5411ce53adfSDenys Vlasenko 			symtab_idx = i;
5421ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
5431ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5441ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
5451ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5466845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
5471da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
5481ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
5491ce53adfSDenys Vlasenko 		}
5501ce53adfSDenys Vlasenko 
5511ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
5521ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
5531ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
5541ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
5551ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5561ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
5571ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5581ce53adfSDenys Vlasenko 		}
5591da177e4SLinus Torvalds 	}
560df578e7dSSam Ravnborg 	if (!info->symtab_start)
561cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
562df578e7dSSam Ravnborg 
5631da177e4SLinus Torvalds 	/* Fix endianness in symbols */
5641da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
5651da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
5661da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
5671da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
5681da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
5691da177e4SLinus Torvalds 	}
5701ce53adfSDenys Vlasenko 
5711ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
5721ce53adfSDenys Vlasenko 		Elf32_Word *p;
5736845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
5741ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
5756845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
5761ce53adfSDenys Vlasenko 			      symtab_idx);
5771ce53adfSDenys Vlasenko 		/* Fix endianness */
5781ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
5791ce53adfSDenys Vlasenko 		     p++)
5801ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
5811ce53adfSDenys Vlasenko 	}
5821ce53adfSDenys Vlasenko 
58385bd2fddSSam Ravnborg 	return 1;
5841da177e4SLinus Torvalds }
5851da177e4SLinus Torvalds 
5865c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
5871da177e4SLinus Torvalds {
5881da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
5891da177e4SLinus Torvalds }
5901da177e4SLinus Torvalds 
5914d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
5924d7365d6SSam Ravnborg {
5934d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
594b92021b0SRusty Russell 	if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0)
5954d7365d6SSam Ravnborg 		return 1;
5964d7365d6SSam Ravnborg 	/* ignore global offset table */
5974d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
5984d7365d6SSam Ravnborg 		return 1;
5994d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
6004d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
6014d7365d6SSam Ravnborg 		if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 ||
6024d7365d6SSam Ravnborg 		    strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 ||
6034d7365d6SSam Ravnborg 		    strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 ||
6048fe9c93eSAndreas Schwab 		    strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 ||
6058fe9c93eSAndreas Schwab 		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
6068fe9c93eSAndreas Schwab 		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
6074d7365d6SSam Ravnborg 			return 1;
6087fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6097fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
6107fca5dc8SStephen Rothwell 		if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
6118fe9c93eSAndreas Schwab 		    strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
6128fe9c93eSAndreas Schwab 		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
613c153693dSAlan Modra 		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 ||
614c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6157fca5dc8SStephen Rothwell 			return 1;
6164d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6174d7365d6SSam Ravnborg 	return 0;
6184d7365d6SSam Ravnborg }
6194d7365d6SSam Ravnborg 
620b92021b0SRusty Russell #define CRC_PFX     VMLINUX_SYMBOL_STR(__crc_)
621b92021b0SRusty Russell #define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_)
6221da177e4SLinus Torvalds 
6235c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6241da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6251da177e4SLinus Torvalds {
6261da177e4SLinus Torvalds 	unsigned int crc;
62762a26356SAlessio Igor Bogani 	enum export export;
628d8c1eb86SNicholas Piggin 	bool is_crc = false;
62962a26356SAlessio Igor Bogani 
630258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
631258f7426SFrank Rowand 	    strncmp(symname, "__ksymtab", 9) == 0)
63262a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
63362a26356SAlessio Igor Bogani 	else
63462a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 	/* CRC'd symbol */
6378d99513cSMichal Marek 	if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
638d8c1eb86SNicholas Piggin 		is_crc = true;
6391da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
64056067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
64156067812SArd Biesheuvel 			unsigned int *crcp;
64256067812SArd Biesheuvel 
64356067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
64456067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
64556067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
64656067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
64756067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
64856067812SArd Biesheuvel 			crc = *crcp;
64956067812SArd Biesheuvel 		}
650bd5cbcedSRam Pai 		sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
651bd5cbcedSRam Pai 				export);
6521da177e4SLinus Torvalds 	}
653b5064654SAndi Kleen 
654b5064654SAndi Kleen 	switch (sym->st_shndx) {
655b5064654SAndi Kleen 	case SHN_COMMON:
656ef178f92SAndi Kleen 		if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) {
657ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
658ef178f92SAndi Kleen 		} else
659b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
6601da177e4SLinus Torvalds 		break;
6611da177e4SLinus Torvalds 	case SHN_UNDEF:
6621da177e4SLinus Torvalds 		/* undefined symbol */
6631da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
6641da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
6651da177e4SLinus Torvalds 			break;
6664d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
6671da177e4SLinus Torvalds 			break;
6688d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
6698d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
6708d529014SBen Colline /* add compatibility with older glibc */
6718d529014SBen Colline #ifndef STT_SPARC_REGISTER
6728d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
6738d529014SBen Colline #endif
6741da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
6751da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
6761da177e4SLinus Torvalds 			/* Ignore register directives. */
6778d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
6781da177e4SLinus Torvalds 				break;
6797caaeabbSAl Viro 			if (symname[0] == '.') {
6807caaeabbSAl Viro 				char *munged = strdup(symname);
6817caaeabbSAl Viro 				munged[0] = '_';
6827caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
6837caaeabbSAl Viro 				symname = munged;
6847caaeabbSAl Viro 			}
6851da177e4SLinus Torvalds 		}
6861da177e4SLinus Torvalds #endif
6871da177e4SLinus Torvalds 
688b92021b0SRusty Russell #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
689b92021b0SRusty Russell 		if (symname[0] != '_')
690b92021b0SRusty Russell 			break;
691b92021b0SRusty Russell 		else
692b92021b0SRusty Russell 			symname++;
693b92021b0SRusty Russell #endif
694d8c1eb86SNicholas Piggin 		if (is_crc) {
695d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
696d8c1eb86SNicholas Piggin 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", symname + strlen(CRC_PFX), mod->name, e);
697d8c1eb86SNicholas Piggin 		}
698b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
6991da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
7001da177e4SLinus Torvalds 					  mod->unres);
7011da177e4SLinus Torvalds 		break;
7021da177e4SLinus Torvalds 	default:
7031da177e4SLinus Torvalds 		/* All exported symbols */
7048d99513cSMichal Marek 		if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
705bd5cbcedSRam Pai 			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
706bd5cbcedSRam Pai 					export);
7071da177e4SLinus Torvalds 		}
708b92021b0SRusty Russell 		if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0)
7091da177e4SLinus Torvalds 			mod->has_init = 1;
710b92021b0SRusty Russell 		if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0)
7111da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7121da177e4SLinus Torvalds 		break;
7131da177e4SLinus Torvalds 	}
7141da177e4SLinus Torvalds }
7151da177e4SLinus Torvalds 
7165c3ead8cSSam Ravnborg /**
7175c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7185c3ead8cSSam Ravnborg  **/
7191da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7201da177e4SLinus Torvalds {
7211da177e4SLinus Torvalds 	/* Skip non-zero chars */
7221da177e4SLinus Torvalds 	while (string[0]) {
7231da177e4SLinus Torvalds 		string++;
7241da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7251da177e4SLinus Torvalds 			return NULL;
7261da177e4SLinus Torvalds 	}
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds 	/* Skip any zero padding. */
7291da177e4SLinus Torvalds 	while (!string[0]) {
7301da177e4SLinus Torvalds 		string++;
7311da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7321da177e4SLinus Torvalds 			return NULL;
7331da177e4SLinus Torvalds 	}
7341da177e4SLinus Torvalds 	return string;
7351da177e4SLinus Torvalds }
7361da177e4SLinus Torvalds 
737b817f6feSSam Ravnborg static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
738b817f6feSSam Ravnborg 			      const char *tag, char *info)
7391da177e4SLinus Torvalds {
7401da177e4SLinus Torvalds 	char *p;
7411da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
7421da177e4SLinus Torvalds 	unsigned long size = modinfo_len;
7431da177e4SLinus Torvalds 
744b817f6feSSam Ravnborg 	if (info) {
745b817f6feSSam Ravnborg 		size -= info - (char *)modinfo;
746b817f6feSSam Ravnborg 		modinfo = next_string(info, &size);
747b817f6feSSam Ravnborg 	}
748b817f6feSSam Ravnborg 
7491da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
7501da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7511da177e4SLinus Torvalds 			return p + taglen + 1;
7521da177e4SLinus Torvalds 	}
7531da177e4SLinus Torvalds 	return NULL;
7541da177e4SLinus Torvalds }
7551da177e4SLinus Torvalds 
756b817f6feSSam Ravnborg static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
757b817f6feSSam Ravnborg 			 const char *tag)
758b817f6feSSam Ravnborg 
759b817f6feSSam Ravnborg {
760b817f6feSSam Ravnborg 	return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
761b817f6feSSam Ravnborg }
762b817f6feSSam Ravnborg 
76393684d3bSSam Ravnborg /**
7644c8fbca5SSam Ravnborg  * Test if string s ends in string sub
7654c8fbca5SSam Ravnborg  * return 0 if match
7664c8fbca5SSam Ravnborg  **/
7674c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
7684c8fbca5SSam Ravnborg {
7694c8fbca5SSam Ravnborg 	int slen, sublen;
7704c8fbca5SSam Ravnborg 
7714c8fbca5SSam Ravnborg 	if (!s || !sub)
7724c8fbca5SSam Ravnborg 		return 1;
7734c8fbca5SSam Ravnborg 
7744c8fbca5SSam Ravnborg 	slen = strlen(s);
7754c8fbca5SSam Ravnborg 	sublen = strlen(sub);
7764c8fbca5SSam Ravnborg 
7774c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
7784c8fbca5SSam Ravnborg 		return 1;
7794c8fbca5SSam Ravnborg 
7804c8fbca5SSam Ravnborg 	if (sublen > slen)
7814c8fbca5SSam Ravnborg 		return 1;
7824c8fbca5SSam Ravnborg 
7834c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
7844c8fbca5SSam Ravnborg }
7854c8fbca5SSam Ravnborg 
786ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
787ff13f926SSam Ravnborg {
78858fb0d4fSSam Ravnborg 	if (sym)
789ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
79058fb0d4fSSam Ravnborg 	else
791f666751aSSam Ravnborg 		return "(unknown)";
792ff13f926SSam Ravnborg }
793ff13f926SSam Ravnborg 
79410668220SSam Ravnborg /* The pattern is an array of simple patterns.
79510668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
7966c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
79710668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
79809c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
79910668220SSam Ravnborg  */
8005c725138STrevor Keith static int match(const char *sym, const char * const pat[])
80110668220SSam Ravnborg {
80210668220SSam Ravnborg 	const char *p;
80310668220SSam Ravnborg 	while (*pat) {
80410668220SSam Ravnborg 		p = *pat++;
80510668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
80610668220SSam Ravnborg 
80709c20c03SPaul Gortmaker 		/* "*foo*" */
80809c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
80909c20c03SPaul Gortmaker 			char *here, *bare = strndup(p + 1, strlen(p) - 2);
81009c20c03SPaul Gortmaker 
81109c20c03SPaul Gortmaker 			here = strstr(sym, bare);
81209c20c03SPaul Gortmaker 			free(bare);
81309c20c03SPaul Gortmaker 			if (here != NULL)
81409c20c03SPaul Gortmaker 				return 1;
81509c20c03SPaul Gortmaker 		}
8166c5bd235SSam Ravnborg 		/* "*foo" */
81709c20c03SPaul Gortmaker 		else if (*p == '*') {
8186c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8196c5bd235SSam Ravnborg 				return 1;
8206c5bd235SSam Ravnborg 		}
82110668220SSam Ravnborg 		/* "foo*" */
8226c5bd235SSam Ravnborg 		else if (*endp == '*') {
82310668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
82410668220SSam Ravnborg 				return 1;
82510668220SSam Ravnborg 		}
82610668220SSam Ravnborg 		/* no wildcards */
82710668220SSam Ravnborg 		else {
82810668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
82910668220SSam Ravnborg 				return 1;
83010668220SSam Ravnborg 		}
83110668220SSam Ravnborg 	}
83210668220SSam Ravnborg 	/* no match */
83310668220SSam Ravnborg 	return 0;
83410668220SSam Ravnborg }
83510668220SSam Ravnborg 
83610668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8377a3ee753SMathias Krause static const char *const section_white_list[] =
8384391ed6aSSam Ravnborg {
8394391ed6aSSam Ravnborg 	".comment*",
8404391ed6aSSam Ravnborg 	".debug*",
8414d10c223SChen Gang 	".cranges",		/* sh64 */
8421121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
843019fca84SDavid Howells 	".GCC-command-line",	/* mn10300 */
84476b27645SJonathan Kliegman 	".GCC.command.line",	/* record-gcc-switches, non mn10300 */
8454391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8464391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8474391ed6aSSam Ravnborg 	".stab*",
8484391ed6aSSam Ravnborg 	".note*",
8494391ed6aSSam Ravnborg 	".got*",
8504391ed6aSSam Ravnborg 	".toc*",
851af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
852af42e970SMax Filippov 	".xt.lit",         /* xtensa */
853f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
854f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
855d1189c63SNoam Camus 	".cmem*",			/* EZchip */
856d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
857ef178f92SAndi Kleen 	".gnu.lto*",
858e390f9a9SJosh Poimboeuf 	".discard.*",
8594391ed6aSSam Ravnborg 	NULL
8604391ed6aSSam Ravnborg };
86110668220SSam Ravnborg 
862e241a630SSam Ravnborg /*
863b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
864e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
865b614a697SAnders Kaseorg  * without "ax" / "aw".
866e241a630SSam Ravnborg  */
867b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
868b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
869e241a630SSam Ravnborg {
870b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
871e241a630SSam Ravnborg 
872b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
873b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
874b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
875b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
876b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
877e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
878e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
879e241a630SSam Ravnborg 		     modname, sec);
880e241a630SSam Ravnborg 	}
881e241a630SSam Ravnborg }
882e241a630SSam Ravnborg 
883e241a630SSam Ravnborg 
884e241a630SSam Ravnborg 
885eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
886a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
887a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
888eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
889a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
89010668220SSam Ravnborg 
891eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
892a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
893eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
894a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
89510668220SSam Ravnborg 
896bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
897a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
898a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
899a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
900bb15d8dbSSebastian Andrzej Siewior 
901e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
902e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
9034a31a229SUwe Kleine-König 
9044a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
9054a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
90610668220SSam Ravnborg 
907a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
908157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
9096727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
91052dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
911673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
912673c2c34SChris Metcalf 		".coldtext"
91310668220SSam Ravnborg 
914fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
915fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
916eb8f6890SSam Ravnborg 
917fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
918fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
919eb8f6890SSam Ravnborg 
92052dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
92152dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
92252dc0595SQuentin Casasnovas 
9236c5bd235SSam Ravnborg /* init data sections */
9247a3ee753SMathias Krause static const char *const init_data_sections[] =
9257a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9266c5bd235SSam Ravnborg 
9276c5bd235SSam Ravnborg /* all init sections */
9287a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9296c5bd235SSam Ravnborg 
9306c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9317a3ee753SMathias Krause static const char *const init_exit_sections[] =
932eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9336c5bd235SSam Ravnborg 
9344a3893d0SPaul Gortmaker /* all text sections */
9354a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9364a3893d0SPaul Gortmaker 
9376c5bd235SSam Ravnborg /* data section */
9387a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9396c5bd235SSam Ravnborg 
9406c5bd235SSam Ravnborg 
9416c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
942af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
943af92a82dSUwe Kleine-König 	"*driver",							\
944af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
945af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
946af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
947af92a82dSUwe Kleine-König 	"*_ops",							\
948af92a82dSUwe Kleine-König 	"*_probe",							\
949af92a82dSUwe Kleine-König 	"*_probe_one",							\
950af92a82dSUwe Kleine-König 	"*_console"
9516c5bd235SSam Ravnborg 
9527a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
9537a3ee753SMathias Krause static const char *const linker_symbols[] =
9546c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
9554a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
9566c5bd235SSam Ravnborg 
957588ccd73SSam Ravnborg enum mismatch {
958bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
959bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
960bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
961bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
962bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
963bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
964bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
965bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
966588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
96752dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
968588ccd73SSam Ravnborg };
969588ccd73SSam Ravnborg 
970e5d8f59aSQuentin Casasnovas /**
971e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
972e5d8f59aSQuentin Casasnovas  *
973e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
974e5d8f59aSQuentin Casasnovas  *
975e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
976e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
977e5d8f59aSQuentin Casasnovas  *
978e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
979e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
980e5d8f59aSQuentin Casasnovas  *
981e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
982e5d8f59aSQuentin Casasnovas  *
983e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
984e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
985e5d8f59aSQuentin Casasnovas  *
986e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
987e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
988e5d8f59aSQuentin Casasnovas  *
989e5d8f59aSQuentin Casasnovas  */
99010668220SSam Ravnborg struct sectioncheck {
99110668220SSam Ravnborg 	const char *fromsec[20];
992050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
993050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
994588ccd73SSam Ravnborg 	enum mismatch mismatch;
995af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
996644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
997644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
998644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
999644e8f14SQuentin Casasnovas 
100010668220SSam Ravnborg };
100110668220SSam Ravnborg 
100252dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
100352dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
100452dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
100552dc0595SQuentin Casasnovas 				     const char *fromsec);
100652dc0595SQuentin Casasnovas 
10077a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
100810668220SSam Ravnborg /* Do not reference init/exit code/data from
100910668220SSam Ravnborg  * normal code and data
101010668220SSam Ravnborg  */
101110668220SSam Ravnborg {
1012588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1013050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1014bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1015af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1016588ccd73SSam Ravnborg },
1017588ccd73SSam Ravnborg {
1018588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1019050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1020bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1021af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1022588ccd73SSam Ravnborg },
1023588ccd73SSam Ravnborg {
10240db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1025050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10260db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10270db25245SUwe Kleine-König 	.symbol_white_list = {
10280db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10290db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10300db25245SUwe Kleine-König 	},
10310db25245SUwe Kleine-König },
10320db25245SUwe Kleine-König {
1033588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1034050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1035bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1036af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1037588ccd73SSam Ravnborg },
1038588ccd73SSam Ravnborg {
1039588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1040050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1041bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1042af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1043eb8f6890SSam Ravnborg },
1044e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1045eb8f6890SSam Ravnborg {
10464a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1047050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1048bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1049af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1050eb8f6890SSam Ravnborg },
1051e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1052eb8f6890SSam Ravnborg {
10534a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1054050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1055bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1056af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
105710668220SSam Ravnborg },
105810668220SSam Ravnborg /* Do not use exit code/data from init code */
105910668220SSam Ravnborg {
1060eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1061050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1062bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1063af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
106410668220SSam Ravnborg },
106510668220SSam Ravnborg /* Do not use init code/data from exit code */
106610668220SSam Ravnborg {
1067eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1068050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1069bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1070af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
107110668220SSam Ravnborg },
1072bb15d8dbSSebastian Andrzej Siewior {
1073bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1074050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1075bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1076bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1077bb15d8dbSSebastian Andrzej Siewior },
107810668220SSam Ravnborg /* Do not export init/exit functions or data */
107910668220SSam Ravnborg {
108010668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1081050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1082af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1083af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
108452dc0595SQuentin Casasnovas },
108552dc0595SQuentin Casasnovas {
108652dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
108752dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
108852dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
108952dc0595SQuentin Casasnovas 	 */
109052dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
109152dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
109252dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
109352dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
109410668220SSam Ravnborg }
109510668220SSam Ravnborg };
109610668220SSam Ravnborg 
10970d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
10980d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
109910668220SSam Ravnborg {
110010668220SSam Ravnborg 	int i;
110110668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
110210668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
110310668220SSam Ravnborg 
1104c5c3439aSQuentin Casasnovas 	/*
1105c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1106c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1107c5c3439aSQuentin Casasnovas 	 * doesn't make much sense and causes build failures on parisc and
1108c5c3439aSQuentin Casasnovas 	 * mn10300 architectures.
1109c5c3439aSQuentin Casasnovas 	 */
1110c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1111c5c3439aSQuentin Casasnovas 		return NULL;
1112c5c3439aSQuentin Casasnovas 
111310668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1114050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1115050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11160d2a636eSUwe Kleine-König 				return check;
1117050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1118050e57fdSQuentin Casasnovas 				return check;
1119050e57fdSQuentin Casasnovas 		}
112010668220SSam Ravnborg 		check++;
112110668220SSam Ravnborg 	}
11220d2a636eSUwe Kleine-König 	return NULL;
112310668220SSam Ravnborg }
112410668220SSam Ravnborg 
11254c8fbca5SSam Ravnborg /**
11264c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11270e0d314eSSam Ravnborg  *
11284c8fbca5SSam Ravnborg  * Pattern 1:
11294c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11304c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11314c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11324c8fbca5SSam Ravnborg  *   this pattern.
11334c8fbca5SSam Ravnborg  *   The pattern is identified by:
11344c8fbca5SSam Ravnborg  *   tosec   = .init.data
11359209aed0SSam Ravnborg  *   fromsec = .data*
11364c8fbca5SSam Ravnborg  *   atsym   =__param*
11374c8fbca5SSam Ravnborg  *
11386a841528SRusty Russell  * Pattern 1a:
11396a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11406a841528SRusty Russell  *   The pattern is identified by:
11416a841528SRusty Russell  *   tosec   = .init.text
11426a841528SRusty Russell  *   fromsec = .data*
11436a841528SRusty Russell  *   atsym   = __param_ops_*
11446a841528SRusty Russell  *
11454c8fbca5SSam Ravnborg  * Pattern 2:
114672ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11474c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
11484c8fbca5SSam Ravnborg  *   the pattern is identified by:
114983cda2bbSSam Ravnborg  *   tosec   = init or exit section
115083cda2bbSSam Ravnborg  *   fromsec = data section
1151df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1152df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1153ee6a8545SVivek Goyal  *
1154ee6a8545SVivek Goyal  * Pattern 3:
1155c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
11569bf8cb9bSSam Ravnborg  *
11571d8af559SSam Ravnborg  * Pattern 4:
1158ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1159ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1160ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1161ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1162ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1163ee6a8545SVivek Goyal  *   This pattern is identified by
1164ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
11659bf8cb9bSSam Ravnborg  *
11664a3893d0SPaul Gortmaker  * Pattern 5:
11674a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
11684a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
11694a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
11704a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
11714a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
11724a3893d0SPaul Gortmaker  *   This pattern is identified by
11734a3893d0SPaul Gortmaker  *   tosec   = init section
11744a3893d0SPaul Gortmaker  *   fromsec = text section
11754a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
11764a3893d0SPaul Gortmaker  *
11774c8fbca5SSam Ravnborg  **/
1178af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1179af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
118058fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
11814c8fbca5SSam Ravnborg {
11824c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
11836c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
11846c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
118558fb0d4fSSam Ravnborg 	    (strncmp(fromsym, "__param", strlen("__param")) == 0))
118658fb0d4fSSam Ravnborg 		return 0;
11874c8fbca5SSam Ravnborg 
11886a841528SRusty Russell 	/* Check for pattern 1a */
11896a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
11906a841528SRusty Russell 	    match(fromsec, data_sections) &&
11916a841528SRusty Russell 	    (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0))
11926a841528SRusty Russell 		return 0;
11936a841528SRusty Russell 
11944c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
11956c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
11966c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1197af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
119858fb0d4fSSam Ravnborg 		return 0;
11994c8fbca5SSam Ravnborg 
12009bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
12016c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
12026c5bd235SSam Ravnborg 	    match(tosec, init_sections))
120358fb0d4fSSam Ravnborg 		return 0;
1204f8657e1bSVivek Goyal 
12051d8af559SSam Ravnborg 	/* Check for pattern 4 */
120658fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
120793659af1SSam Ravnborg 		return 0;
120858fb0d4fSSam Ravnborg 
12094a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12104a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12114a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12124a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12134a3893d0SPaul Gortmaker 		return 0;
12144a3893d0SPaul Gortmaker 
121558fb0d4fSSam Ravnborg 	return 1;
12164c8fbca5SSam Ravnborg }
12174c8fbca5SSam Ravnborg 
12184c8fbca5SSam Ravnborg /**
121993684d3bSSam Ravnborg  * Find symbol based on relocation record info.
122093684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
122193684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
122293684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
122393684d3bSSam Ravnborg  * based on section and address.
122493684d3bSSam Ravnborg  *  **/
12259ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
122693684d3bSSam Ravnborg 				Elf_Sym *relsym)
122793684d3bSSam Ravnborg {
122893684d3bSSam Ravnborg 	Elf_Sym *sym;
12299ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
12309ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
12319ad21c3fSSam Ravnborg 	Elf64_Sword d;
12321ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
123393684d3bSSam Ravnborg 
123493684d3bSSam Ravnborg 	if (relsym->st_name != 0)
123593684d3bSSam Ravnborg 		return relsym;
12361ce53adfSDenys Vlasenko 
12371ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
123893684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
12391ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
124093684d3bSSam Ravnborg 			continue;
1241ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1242ae4ac123SAtsushi Nemoto 			continue;
124393684d3bSSam Ravnborg 		if (sym->st_value == addr)
124493684d3bSSam Ravnborg 			return sym;
12459ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
12469ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
12479ad21c3fSSam Ravnborg 		if (d < 0)
12489ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
12499ad21c3fSSam Ravnborg 		if (d < distance) {
12509ad21c3fSSam Ravnborg 			distance = d;
12519ad21c3fSSam Ravnborg 			near = sym;
125293684d3bSSam Ravnborg 		}
12539ad21c3fSSam Ravnborg 	}
12549ad21c3fSSam Ravnborg 	/* We need a close match */
12559ad21c3fSSam Ravnborg 	if (distance < 20)
12569ad21c3fSSam Ravnborg 		return near;
12579ad21c3fSSam Ravnborg 	else
125893684d3bSSam Ravnborg 		return NULL;
125993684d3bSSam Ravnborg }
126093684d3bSSam Ravnborg 
1261da68d61fSDavid Brownell static inline int is_arm_mapping_symbol(const char *str)
1262da68d61fSDavid Brownell {
12636c34f1f5SKyle McMartin 	return str[0] == '$' && strchr("axtd", str[1])
1264da68d61fSDavid Brownell 	       && (str[2] == '\0' || str[2] == '.');
1265da68d61fSDavid Brownell }
1266da68d61fSDavid Brownell 
1267da68d61fSDavid Brownell /*
1268da68d61fSDavid Brownell  * If there's no name there, ignore it; likewise, ignore it if it's
1269da68d61fSDavid Brownell  * one of the magic symbols emitted used by current ARM tools.
1270da68d61fSDavid Brownell  *
1271da68d61fSDavid Brownell  * Otherwise if find_symbols_between() returns those symbols, they'll
1272da68d61fSDavid Brownell  * fail the whitelist tests and cause lots of false alarms ... fixable
1273da68d61fSDavid Brownell  * only by merging __exit and __init sections into __text, bloating
1274da68d61fSDavid Brownell  * the kernel (which is especially evil on embedded platforms).
1275da68d61fSDavid Brownell  */
1276da68d61fSDavid Brownell static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
1277da68d61fSDavid Brownell {
1278da68d61fSDavid Brownell 	const char *name = elf->strtab + sym->st_name;
1279da68d61fSDavid Brownell 
1280da68d61fSDavid Brownell 	if (!name || !strlen(name))
1281da68d61fSDavid Brownell 		return 0;
1282da68d61fSDavid Brownell 	return !is_arm_mapping_symbol(name);
1283da68d61fSDavid Brownell }
1284da68d61fSDavid Brownell 
1285b39927cfSSam Ravnborg /*
128643c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
128743c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
128843c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
128943c74d17SSam Ravnborg  * it is, but this works for now.
1290b39927cfSSam Ravnborg  **/
1291157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1292157c23c8SSam Ravnborg 				 const char *sec)
1293b39927cfSSam Ravnborg {
1294b39927cfSSam Ravnborg 	Elf_Sym *sym;
1295157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1296157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1297b39927cfSSam Ravnborg 
1298b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1299b39927cfSSam Ravnborg 		const char *symsec;
1300b39927cfSSam Ravnborg 
13011ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1302b39927cfSSam Ravnborg 			continue;
13031ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1304b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1305b39927cfSSam Ravnborg 			continue;
1306da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1307da68d61fSDavid Brownell 			continue;
1308b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1309157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1310157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1311157c23c8SSam Ravnborg 				near = sym;
1312157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1313157c23c8SSam Ravnborg 				near = sym;
131443c74d17SSam Ravnborg 			}
1315b39927cfSSam Ravnborg 		}
1316b39927cfSSam Ravnborg 	}
1317157c23c8SSam Ravnborg 	return near;
1318157c23c8SSam Ravnborg }
1319b39927cfSSam Ravnborg 
132058fb0d4fSSam Ravnborg /*
1321588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1322588ccd73SSam Ravnborg  * .init.text => __init
1323588ccd73SSam Ravnborg  * .memexitconst => __memconst
1324588ccd73SSam Ravnborg  * etc.
1325cbcf14a9SAndy Shevchenko  *
1326cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1327cbcf14a9SAndy Shevchenko  * method should free it after usage.
1328588ccd73SSam Ravnborg */
1329588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1330588ccd73SSam Ravnborg {
1331588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
1332588ccd73SSam Ravnborg 		char *p = malloc(20);
1333588ccd73SSam Ravnborg 		char *r = p;
1334588ccd73SSam Ravnborg 
1335588ccd73SSam Ravnborg 		*p++ = '_';
1336588ccd73SSam Ravnborg 		*p++ = '_';
1337588ccd73SSam Ravnborg 		if (*s == '.')
1338588ccd73SSam Ravnborg 			s++;
1339588ccd73SSam Ravnborg 		while (*s && *s != '.')
1340588ccd73SSam Ravnborg 			*p++ = *s++;
1341588ccd73SSam Ravnborg 		*p = '\0';
1342588ccd73SSam Ravnborg 		if (*s == '.')
1343588ccd73SSam Ravnborg 			s++;
1344588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1345588ccd73SSam Ravnborg 			strcat(p, "const ");
1346588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1347588ccd73SSam Ravnborg 			strcat(p, "data ");
1348588ccd73SSam Ravnborg 		else
1349588ccd73SSam Ravnborg 			strcat(p, " ");
1350cbcf14a9SAndy Shevchenko 		return r;
1351588ccd73SSam Ravnborg 	} else {
13525003bab8SAndrew Morton 		return strdup("");
1353588ccd73SSam Ravnborg 	}
1354588ccd73SSam Ravnborg }
1355588ccd73SSam Ravnborg 
1356588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1357588ccd73SSam Ravnborg {
1358588ccd73SSam Ravnborg 	if (sym)
1359588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1360588ccd73SSam Ravnborg 	else
1361f666751aSSam Ravnborg 		return -1;
1362588ccd73SSam Ravnborg }
1363588ccd73SSam Ravnborg 
136400759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
136500759c0eSRandy Dunlap {
136600759c0eSRandy Dunlap 	const char *const *s = list;
136700759c0eSRandy Dunlap 
136800759c0eSRandy Dunlap 	while (*s) {
136900759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
137000759c0eSRandy Dunlap 		s++;
137100759c0eSRandy Dunlap 		if (*s)
137200759c0eSRandy Dunlap 			fprintf(stderr, ", ");
137300759c0eSRandy Dunlap 	}
137400759c0eSRandy Dunlap 	fprintf(stderr, "\n");
137500759c0eSRandy Dunlap }
137600759c0eSRandy Dunlap 
1377356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1378356ad538SQuentin Casasnovas {
1379356ad538SQuentin Casasnovas 	switch (is_func) {
1380356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1381356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1382356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1383356ad538SQuentin Casasnovas 	}
1384356ad538SQuentin Casasnovas }
1385356ad538SQuentin Casasnovas 
1386588ccd73SSam Ravnborg /*
1387b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1388b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
13894c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
139058fb0d4fSSam Ravnborg  */
13910d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
13920d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
139358fb0d4fSSam Ravnborg 				const char *fromsec,
139458fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
139558fb0d4fSSam Ravnborg 				const char *fromsym,
1396588ccd73SSam Ravnborg 				int from_is_func,
1397588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1398588ccd73SSam Ravnborg 				int to_is_func)
1399b39927cfSSam Ravnborg {
1400588ccd73SSam Ravnborg 	const char *from, *from_p;
1401588ccd73SSam Ravnborg 	const char *to, *to_p;
140237ed19d5SAlexey Fomenko 	char *prl_from;
140337ed19d5SAlexey Fomenko 	char *prl_to;
1404f666751aSSam Ravnborg 
1405e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1406e5f95c8bSSam Ravnborg 	if (!sec_mismatch_verbose)
1407e5f95c8bSSam Ravnborg 		return;
1408e5f95c8bSSam Ravnborg 
1409356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1410356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1411356ad538SQuentin Casasnovas 
14127c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14137c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14147c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14157c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1416588ccd73SSam Ravnborg 
14170d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1418bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
141937ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
142037ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1421588ccd73SSam Ravnborg 		fprintf(stderr,
1422588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1423588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1424588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1425588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
142637ed19d5SAlexey Fomenko 		prl_from, fromsym,
142737ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
142837ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
142937ed19d5SAlexey Fomenko 		free(prl_from);
143037ed19d5SAlexey Fomenko 		free(prl_to);
1431588ccd73SSam Ravnborg 		break;
1432bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
143337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1434588ccd73SSam Ravnborg 		fprintf(stderr,
1435588ccd73SSam Ravnborg 		"The variable %s references\n"
1436588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1437588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
14388b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1439588ccd73SSam Ravnborg 		"or name the variable:\n",
144037ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
144100759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
144237ed19d5SAlexey Fomenko 		free(prl_to);
1443588ccd73SSam Ravnborg 		break;
144458fb0d4fSSam Ravnborg 	}
1445bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
144637ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1447588ccd73SSam Ravnborg 		fprintf(stderr,
1448588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1449588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1450588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
145137ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
145237ed19d5SAlexey Fomenko 		free(prl_to);
1453588ccd73SSam Ravnborg 		break;
1454bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
145537ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1456588ccd73SSam Ravnborg 		fprintf(stderr,
1457588ccd73SSam Ravnborg 		"The variable %s references\n"
1458588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1459588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1460588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1461588ccd73SSam Ravnborg 		"name the variable:\n",
146237ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
146300759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
146437ed19d5SAlexey Fomenko 		free(prl_to);
1465588ccd73SSam Ravnborg 		break;
1466588ccd73SSam Ravnborg 	}
1467bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1468bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
146937ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
147037ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1471588ccd73SSam Ravnborg 		fprintf(stderr,
1472588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1473588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1474588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1475588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
147637ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
147737ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1478b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
147937ed19d5SAlexey Fomenko 		free(prl_from);
148037ed19d5SAlexey Fomenko 		free(prl_to);
1481588ccd73SSam Ravnborg 		break;
1482bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
148337ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
148437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1485588ccd73SSam Ravnborg 		fprintf(stderr,
1486588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1487588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1488588ccd73SSam Ravnborg 		"This is often seen when error handling "
1489588ccd73SSam Ravnborg 		"in the init function\n"
1490588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1491588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1492588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
149337ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
149437ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
14955003bab8SAndrew Morton 		prl_to, tosym, to_p);
149637ed19d5SAlexey Fomenko 		free(prl_from);
149737ed19d5SAlexey Fomenko 		free(prl_to);
1498588ccd73SSam Ravnborg 		break;
1499bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
150037ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
150137ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1502588ccd73SSam Ravnborg 		fprintf(stderr,
1503588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1504588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1505588ccd73SSam Ravnborg 		"This is often seen when error handling "
1506588ccd73SSam Ravnborg 		"in the exit function\n"
1507588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1508588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1509588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
151037ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
151137ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
151237ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
151337ed19d5SAlexey Fomenko 		free(prl_from);
151437ed19d5SAlexey Fomenko 		free(prl_to);
1515588ccd73SSam Ravnborg 		break;
1516588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
151737ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1518588ccd73SSam Ravnborg 		fprintf(stderr,
1519588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1520588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1521588ccd73SSam Ravnborg 		"or drop the export.\n",
152237ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
152337ed19d5SAlexey Fomenko 		free(prl_to);
1524588ccd73SSam Ravnborg 		break;
152552dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
152652dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
152752dc0595SQuentin Casasnovas 		      "we should never get here.");
152852dc0595SQuentin Casasnovas 		break;
1529588ccd73SSam Ravnborg 	}
1530588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
153158fb0d4fSSam Ravnborg }
153258fb0d4fSSam Ravnborg 
1533644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1534644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
153558fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
153658fb0d4fSSam Ravnborg {
153758fb0d4fSSam Ravnborg 	const char *tosec;
1538588ccd73SSam Ravnborg 	Elf_Sym *to;
1539588ccd73SSam Ravnborg 	Elf_Sym *from;
154058fb0d4fSSam Ravnborg 	const char *tosym;
1541588ccd73SSam Ravnborg 	const char *fromsym;
154258fb0d4fSSam Ravnborg 
1543588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1544588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
154558fb0d4fSSam Ravnborg 
154677ab21adSAndi Kleen 	if (!strncmp(fromsym, "reference___initcall",
154777ab21adSAndi Kleen 		     sizeof("reference___initcall")-1))
154877ab21adSAndi Kleen 		return;
154977ab21adSAndi Kleen 
1550c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1551c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1552c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1553c7a65e06SQuentin Casasnovas 
155458fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1555af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1556af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1557588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1558588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1559588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1560588ccd73SSam Ravnborg 				    is_function(to));
156158fb0d4fSSam Ravnborg 	}
1562b39927cfSSam Ravnborg }
1563644e8f14SQuentin Casasnovas 
156452dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
156552dc0595SQuentin Casasnovas {
156652dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
156752dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
156852dc0595SQuentin Casasnovas 
156952dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
157052dc0595SQuentin Casasnovas }
157152dc0595SQuentin Casasnovas 
157252dc0595SQuentin Casasnovas /*
157352dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
157452dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
157552dc0595SQuentin Casasnovas  */
157652dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1577e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
157852dc0595SQuentin Casasnovas {
157952dc0595SQuentin Casasnovas 	/*
158052dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
158152dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
158252dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
158352dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
158452dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
158552dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
158652dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
158752dc0595SQuentin Casasnovas 	 */
1588e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
158952dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
159052dc0595SQuentin Casasnovas }
1591e84048aaSQuentin Casasnovas 
159252dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
159352dc0595SQuentin Casasnovas {
1594d3df4de7SQuentin Casasnovas 	/*
1595d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1596d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1597d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1598d3df4de7SQuentin Casasnovas 	 */
1599d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
160052dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
160152dc0595SQuentin Casasnovas 
160252dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
160352dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
160452dc0595SQuentin Casasnovas }
160552dc0595SQuentin Casasnovas 
1606e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1607e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1608e84048aaSQuentin Casasnovas 
160952dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
161052dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
161152dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
161252dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
161352dc0595SQuentin Casasnovas {
161452dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
161552dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
161652dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
161752dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
161852dc0595SQuentin Casasnovas 	const char* from_pretty_name;
161952dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
162052dc0595SQuentin Casasnovas 	const char* to_pretty_name;
162152dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
162252dc0595SQuentin Casasnovas 
162352dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
162452dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
162552dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
162652dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
162752dc0595SQuentin Casasnovas 
162852dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
162952dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
163052dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
163152dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
163252dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
163352dc0595SQuentin Casasnovas 
163452dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
163552dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
163652dc0595SQuentin Casasnovas 		fprintf(stderr,
163752dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
163852dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
163952dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
164052dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
164152dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
164252dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
164352dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
164452dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
164552dc0595SQuentin Casasnovas }
164652dc0595SQuentin Casasnovas 
164752dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
164852dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
164952dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
165052dc0595SQuentin Casasnovas 				     const char *fromsec)
165152dc0595SQuentin Casasnovas {
165252dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
165352dc0595SQuentin Casasnovas 
165452dc0595SQuentin Casasnovas 	sec_mismatch_count++;
165552dc0595SQuentin Casasnovas 
165652dc0595SQuentin Casasnovas 	if (sec_mismatch_verbose)
165752dc0595SQuentin Casasnovas 		report_extable_warnings(modname, elf, mismatch, r, sym,
165852dc0595SQuentin Casasnovas 					fromsec, tosec);
165952dc0595SQuentin Casasnovas 
166052dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
166152dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
166252dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
166352dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
166452dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
166552dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
166652dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
166752dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
166852dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
166952dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
167052dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
167152dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
167252dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
167352dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
167452dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
167552dc0595SQuentin Casasnovas 		else
167652dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
167752dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
167852dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
167952dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
168052dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
168152dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
168252dc0595SQuentin Casasnovas 	}
168352dc0595SQuentin Casasnovas }
168452dc0595SQuentin Casasnovas 
1685644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1686644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1687644e8f14SQuentin Casasnovas {
1688644e8f14SQuentin Casasnovas 	const char *tosec = sec_name(elf, get_secindex(elf, sym));;
1689644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1690644e8f14SQuentin Casasnovas 
1691644e8f14SQuentin Casasnovas 	if (mismatch) {
1692644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1693644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1694644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1695644e8f14SQuentin Casasnovas 		else
1696644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1697644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1698644e8f14SQuentin Casasnovas 	}
1699b39927cfSSam Ravnborg }
1700b39927cfSSam Ravnborg 
1701ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
17025b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1703ae4ac123SAtsushi Nemoto {
1704ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17056845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1706ae4ac123SAtsushi Nemoto 
1707ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1708731ece41SOlof Johansson 		r->r_offset;
1709ae4ac123SAtsushi Nemoto }
1710ae4ac123SAtsushi Nemoto 
17115b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1712ae4ac123SAtsushi Nemoto {
1713ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17145b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1715ae4ac123SAtsushi Nemoto 
1716ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1717ae4ac123SAtsushi Nemoto 	case R_386_32:
1718ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1719ae4ac123SAtsushi Nemoto 		break;
1720ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1721ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1722ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1723ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1724ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1725ae4ac123SAtsushi Nemoto 		break;
1726ae4ac123SAtsushi Nemoto 	}
1727ae4ac123SAtsushi Nemoto 	return 0;
1728ae4ac123SAtsushi Nemoto }
1729ae4ac123SAtsushi Nemoto 
17306e2e340bSTony Lindgren #ifndef R_ARM_CALL
17316e2e340bSTony Lindgren #define R_ARM_CALL	28
17326e2e340bSTony Lindgren #endif
17336e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17346e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17356e2e340bSTony Lindgren #endif
17366e2e340bSTony Lindgren 
1737c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1738c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1739c9698e5cSDavid A. Long #endif
1740c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1741c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1742c9698e5cSDavid A. Long #endif
1743c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1744c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1745c9698e5cSDavid A. Long #endif
1746c9698e5cSDavid A. Long 
17475b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
174856a974faSSam Ravnborg {
174956a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
175056a974faSSam Ravnborg 
175156a974faSSam Ravnborg 	switch (r_typ) {
175256a974faSSam Ravnborg 	case R_ARM_ABS32:
175356a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1754df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1755df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
175656a974faSSam Ravnborg 		break;
175756a974faSSam Ravnborg 	case R_ARM_PC24:
17586e2e340bSTony Lindgren 	case R_ARM_CALL:
17596e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1760c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1761c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1762c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
176356a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1764df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
17655b24c071SSam Ravnborg 			      sechdr->sh_offset +
17665b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
176756a974faSSam Ravnborg 		break;
176856a974faSSam Ravnborg 	default:
176956a974faSSam Ravnborg 		return 1;
177056a974faSSam Ravnborg 	}
177156a974faSSam Ravnborg 	return 0;
177256a974faSSam Ravnborg }
177356a974faSSam Ravnborg 
17745b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1775ae4ac123SAtsushi Nemoto {
1776ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17775b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1778ae4ac123SAtsushi Nemoto 	unsigned int inst;
1779ae4ac123SAtsushi Nemoto 
1780ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1781ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1782ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1783ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1784ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1785ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1786ae4ac123SAtsushi Nemoto 		break;
1787ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1788ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1789ae4ac123SAtsushi Nemoto 		break;
1790ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1791ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1792ae4ac123SAtsushi Nemoto 		break;
1793ae4ac123SAtsushi Nemoto 	}
1794ae4ac123SAtsushi Nemoto 	return 0;
1795ae4ac123SAtsushi Nemoto }
1796ae4ac123SAtsushi Nemoto 
17975b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
179810668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1799b39927cfSSam Ravnborg {
1800b39927cfSSam Ravnborg 	Elf_Sym  *sym;
18015b24c071SSam Ravnborg 	Elf_Rela *rela;
18022c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1803eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18045b24c071SSam Ravnborg 	const char *fromsec;
18055b24c071SSam Ravnborg 
1806ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18075b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18085b24c071SSam Ravnborg 
1809ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18105b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18115b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1812b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18135b24c071SSam Ravnborg 		return;
1814e241a630SSam Ravnborg 
1815b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1816b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1817eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1818ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1819ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1820eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1821eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1822ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1823ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1824eae07ac6SAtsushi Nemoto 		} else {
1825601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1826eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1827eae07ac6SAtsushi Nemoto 		}
1828eae07ac6SAtsushi Nemoto #else
1829eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1830eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1831eae07ac6SAtsushi Nemoto #endif
183293684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1833eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1834b39927cfSSam Ravnborg 		/* Skip special sections */
18351ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1836b39927cfSSam Ravnborg 			continue;
1837e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1838e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
183958fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18402c1a51f3SAtsushi Nemoto 	}
18415b24c071SSam Ravnborg }
18425b24c071SSam Ravnborg 
18435b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
184410668220SSam Ravnborg 			Elf_Shdr *sechdr)
18455b24c071SSam Ravnborg {
18465b24c071SSam Ravnborg 	Elf_Sym *sym;
18472c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
18485b24c071SSam Ravnborg 	Elf_Rela r;
18495b24c071SSam Ravnborg 	unsigned int r_sym;
18505b24c071SSam Ravnborg 	const char *fromsec;
18515b24c071SSam Ravnborg 
1852ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
18535b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
18545b24c071SSam Ravnborg 
1855ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18565b24c071SSam Ravnborg 	fromsec += strlen(".rel");
18575b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1858b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18595b24c071SSam Ravnborg 		return;
18602c1a51f3SAtsushi Nemoto 
18612c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
18622c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1863eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1864ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1865ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1866eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1867eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1868ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1869ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1870eae07ac6SAtsushi Nemoto 		} else {
18712c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1872eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1873eae07ac6SAtsushi Nemoto 		}
1874eae07ac6SAtsushi Nemoto #else
1875eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1876eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1877eae07ac6SAtsushi Nemoto #endif
18782c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1879ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1880ae4ac123SAtsushi Nemoto 		case EM_386:
18815b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1882ae4ac123SAtsushi Nemoto 				continue;
1883ae4ac123SAtsushi Nemoto 			break;
188456a974faSSam Ravnborg 		case EM_ARM:
18855b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
188656a974faSSam Ravnborg 				continue;
188756a974faSSam Ravnborg 			break;
1888ae4ac123SAtsushi Nemoto 		case EM_MIPS:
18895b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1890ae4ac123SAtsushi Nemoto 				continue;
1891ae4ac123SAtsushi Nemoto 			break;
1892ae4ac123SAtsushi Nemoto 		}
1893eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
18942c1a51f3SAtsushi Nemoto 		/* Skip special sections */
18951ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
18962c1a51f3SAtsushi Nemoto 			continue;
1897e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1898e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
189958fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19002c1a51f3SAtsushi Nemoto 	}
1901b39927cfSSam Ravnborg }
19025b24c071SSam Ravnborg 
19035b24c071SSam Ravnborg /**
19045b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19055b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19065b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1907b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19085b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19095b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
191032be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19115b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19125b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19135b24c071SSam Ravnborg  * be discarded and warns about it.
19145b24c071SSam Ravnborg  **/
19155b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
191610668220SSam Ravnborg 			  struct elf_info *elf)
19175b24c071SSam Ravnborg {
19185b24c071SSam Ravnborg 	int i;
19195b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19205b24c071SSam Ravnborg 
19215b24c071SSam Ravnborg 	/* Walk through all sections */
19221ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1923b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19245b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19255b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
192610668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19275b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
192810668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1929b39927cfSSam Ravnborg 	}
1930b39927cfSSam Ravnborg }
1931b39927cfSSam Ravnborg 
19327d02b490SAndi Kleen static char *remove_dot(char *s)
19337d02b490SAndi Kleen {
1934fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19357d02b490SAndi Kleen 
1936fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1937fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1938fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
19397d02b490SAndi Kleen 			s[n] = 0;
19407d02b490SAndi Kleen 	}
19417d02b490SAndi Kleen 	return s;
19427d02b490SAndi Kleen }
19437d02b490SAndi Kleen 
19445c3ead8cSSam Ravnborg static void read_symbols(char *modname)
19451da177e4SLinus Torvalds {
19461da177e4SLinus Torvalds 	const char *symname;
19471da177e4SLinus Torvalds 	char *version;
1948b817f6feSSam Ravnborg 	char *license;
19491da177e4SLinus Torvalds 	struct module *mod;
19501da177e4SLinus Torvalds 	struct elf_info info = { };
19511da177e4SLinus Torvalds 	Elf_Sym *sym;
19521da177e4SLinus Torvalds 
195385bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
195485bd2fddSSam Ravnborg 		return;
19551da177e4SLinus Torvalds 
19561da177e4SLinus Torvalds 	mod = new_module(modname);
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
19591da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
19601da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
19611da177e4SLinus Torvalds 		have_vmlinux = 1;
19621da177e4SLinus Torvalds 		mod->skip = 1;
19631da177e4SLinus Torvalds 	}
19641da177e4SLinus Torvalds 
1965b817f6feSSam Ravnborg 	license = get_modinfo(info.modinfo, info.modinfo_len, "license");
19662fa36568SSam Ravnborg 	if (info.modinfo && !license && !is_vmlinux(modname))
19672fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
1968eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
1969eed7d279SSam Ravnborg 		     "more information\n", modname);
1970b817f6feSSam Ravnborg 	while (license) {
1971b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
1972b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
1973b817f6feSSam Ravnborg 		else {
1974b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
1975b817f6feSSam Ravnborg 			break;
1976b817f6feSSam Ravnborg 		}
1977b817f6feSSam Ravnborg 		license = get_next_modinfo(info.modinfo, info.modinfo_len,
1978b817f6feSSam Ravnborg 					   "license", license);
1979b817f6feSSam Ravnborg 	}
1980b817f6feSSam Ravnborg 
19811da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
19827d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
19831da177e4SLinus Torvalds 
19841da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
19851da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
19861da177e4SLinus Torvalds 	}
1987d1f25e66SSam Ravnborg 	if (!is_vmlinux(modname) ||
198810668220SSam Ravnborg 	     (is_vmlinux(modname) && vmlinux_section_warnings))
198910668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 	version = get_modinfo(info.modinfo, info.modinfo_len, "version");
19921da177e4SLinus Torvalds 	if (version)
19931da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
19941da177e4SLinus Torvalds 				       version - (char *)info.hdr);
19951da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
19961da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
19971da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
19981da177e4SLinus Torvalds 
19991da177e4SLinus Torvalds 	parse_elf_finish(&info);
20001da177e4SLinus Torvalds 
20018c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
20021da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
20031da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
20041da177e4SLinus Torvalds 	 * important anyhow */
20051da177e4SLinus Torvalds 	if (modversions)
20068c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
20071da177e4SLinus Torvalds }
20081da177e4SLinus Torvalds 
2009712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2010712f9b46SRusty Russell {
2011712f9b46SRusty Russell 	FILE *in = stdin;
2012712f9b46SRusty Russell 	char fname[PATH_MAX];
2013712f9b46SRusty Russell 
2014712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2015712f9b46SRusty Russell 		in = fopen(filename, "r");
2016712f9b46SRusty Russell 		if (!in)
2017712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2018712f9b46SRusty Russell 	}
2019712f9b46SRusty Russell 
2020712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2021712f9b46SRusty Russell 		if (strends(fname, "\n"))
2022712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2023712f9b46SRusty Russell 		read_symbols(fname);
2024712f9b46SRusty Russell 	}
2025712f9b46SRusty Russell 
2026712f9b46SRusty Russell 	if (in != stdin)
2027712f9b46SRusty Russell 		fclose(in);
2028712f9b46SRusty Russell }
2029712f9b46SRusty Russell 
20301da177e4SLinus Torvalds #define SZ 500
20311da177e4SLinus Torvalds 
20321da177e4SLinus Torvalds /* We first write the generated file into memory using the
20331da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
20341da177e4SLinus Torvalds  * only update the later if anything changed */
20351da177e4SLinus Torvalds 
20365c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
20375c3ead8cSSam Ravnborg 						      const char *fmt, ...)
20381da177e4SLinus Torvalds {
20391da177e4SLinus Torvalds 	char tmp[SZ];
20401da177e4SLinus Torvalds 	int len;
20411da177e4SLinus Torvalds 	va_list ap;
20421da177e4SLinus Torvalds 
20431da177e4SLinus Torvalds 	va_start(ap, fmt);
20441da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
20457670f023SSam Ravnborg 	buf_write(buf, tmp, len);
20461da177e4SLinus Torvalds 	va_end(ap);
20471da177e4SLinus Torvalds }
20481da177e4SLinus Torvalds 
20495c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
20501da177e4SLinus Torvalds {
20511da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
20527670f023SSam Ravnborg 		buf->size += len + SZ;
20531da177e4SLinus Torvalds 		buf->p = realloc(buf->p, buf->size);
20541da177e4SLinus Torvalds 	}
20551da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
20561da177e4SLinus Torvalds 	buf->pos += len;
20571da177e4SLinus Torvalds }
20581da177e4SLinus Torvalds 
2059c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2060c96fca21SSam Ravnborg {
2061c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2062c96fca21SSam Ravnborg 
2063c96fca21SSam Ravnborg 	switch (exp) {
2064c96fca21SSam Ravnborg 	case export_gpl:
2065c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2066c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2067c96fca21SSam Ravnborg 		break;
2068c96fca21SSam Ravnborg 	case export_unused_gpl:
2069c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2070c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2071c96fca21SSam Ravnborg 		break;
2072c96fca21SSam Ravnborg 	case export_gpl_future:
2073c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2074c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2075c96fca21SSam Ravnborg 		break;
2076c96fca21SSam Ravnborg 	case export_plain:
2077c96fca21SSam Ravnborg 	case export_unused:
2078c96fca21SSam Ravnborg 	case export_unknown:
2079c96fca21SSam Ravnborg 		/* ignore */
2080c96fca21SSam Ravnborg 		break;
2081c96fca21SSam Ravnborg 	}
2082c96fca21SSam Ravnborg }
2083c96fca21SSam Ravnborg 
2084c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2085c96fca21SSam Ravnborg {
2086c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2087c96fca21SSam Ravnborg 
2088c96fca21SSam Ravnborg 	switch (exp) {
2089c96fca21SSam Ravnborg 	case export_unused:
2090c96fca21SSam Ravnborg 	case export_unused_gpl:
2091c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2092c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2093c96fca21SSam Ravnborg 		break;
2094c96fca21SSam Ravnborg 	default:
2095c96fca21SSam Ravnborg 		/* ignore */
2096c96fca21SSam Ravnborg 		break;
2097c96fca21SSam Ravnborg 	}
2098c96fca21SSam Ravnborg }
2099c96fca21SSam Ravnborg 
2100c96fca21SSam Ravnborg static void check_exports(struct module *mod)
2101b817f6feSSam Ravnborg {
2102b817f6feSSam Ravnborg 	struct symbol *s, *exp;
2103b817f6feSSam Ravnborg 
2104b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21056449bd62SAndrew Morton 		const char *basename;
2106b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
2107b817f6feSSam Ravnborg 		if (!exp || exp->module == mod)
2108b817f6feSSam Ravnborg 			continue;
21096449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2110b817f6feSSam Ravnborg 		if (basename)
2111b817f6feSSam Ravnborg 			basename++;
2112c96fca21SSam Ravnborg 		else
2113c96fca21SSam Ravnborg 			basename = mod->name;
2114c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2115c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2116c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2117b817f6feSSam Ravnborg 	}
2118b817f6feSSam Ravnborg }
2119b817f6feSSam Ravnborg 
21204fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
21214fd3e4efSWanlong Gao {
21224fd3e4efSWanlong Gao 	const char *mod_name;
21234fd3e4efSWanlong Gao 
21244fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
21254fd3e4efSWanlong Gao 	if (mod_name == NULL)
21264fd3e4efSWanlong Gao 		mod_name = mod->name;
21274fd3e4efSWanlong Gao 	else
21284fd3e4efSWanlong Gao 		mod_name++;
21294fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
21304fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
21314fd3e4efSWanlong Gao 		return 1;
21324fd3e4efSWanlong Gao 	}
21334fd3e4efSWanlong Gao 
21344fd3e4efSWanlong Gao 	return 0;
21354fd3e4efSWanlong Gao }
21364fd3e4efSWanlong Gao 
21375c3ead8cSSam Ravnborg /**
21385c3ead8cSSam Ravnborg  * Header for the generated file
21395c3ead8cSSam Ravnborg  **/
21405c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
21411da177e4SLinus Torvalds {
21421da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
21431da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
21441da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
21451da177e4SLinus Torvalds 	buf_printf(b, "\n");
21461da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
21473e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
21481da177e4SLinus Torvalds 	buf_printf(b, "\n");
2149e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
21501da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
21513c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
21521da177e4SLinus Torvalds 	if (mod->has_init)
21533c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
21541da177e4SLinus Torvalds 	if (mod->has_cleanup)
21551da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
21563c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
21571da177e4SLinus Torvalds 			      "#endif\n");
21583c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
21591da177e4SLinus Torvalds 	buf_printf(b, "};\n");
21601da177e4SLinus Torvalds }
21611da177e4SLinus Torvalds 
21622449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
21632449b8baSBen Hutchings {
21642449b8baSBen Hutchings 	if (is_intree)
21652449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
21662449b8baSBen Hutchings }
21672449b8baSBen Hutchings 
2168*caf7501aSAndi Kleen /* Cannot check for assembler */
2169*caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2170*caf7501aSAndi Kleen {
2171*caf7501aSAndi Kleen 	buf_printf(b, "\n#ifdef RETPOLINE\n");
2172*caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2173*caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2174*caf7501aSAndi Kleen }
2175*caf7501aSAndi Kleen 
21765c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2177a9860bf0SGreg Kroah-Hartman {
2178a9860bf0SGreg Kroah-Hartman 	static const char *staging_dir = "drivers/staging";
2179a9860bf0SGreg Kroah-Hartman 
2180a9860bf0SGreg Kroah-Hartman 	if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
2181a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2182a9860bf0SGreg Kroah-Hartman }
2183a9860bf0SGreg Kroah-Hartman 
21845c3ead8cSSam Ravnborg /**
21855c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
21865c3ead8cSSam Ravnborg  **/
2187c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
21881da177e4SLinus Torvalds {
21891da177e4SLinus Torvalds 	struct symbol *s, *exp;
2190c53ddacdSKirill Korotaev 	int err = 0;
21911da177e4SLinus Torvalds 
21921da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
21931da177e4SLinus Torvalds 		exp = find_symbol(s->name);
21941da177e4SLinus Torvalds 		if (!exp || exp->module == mod) {
2195c53ddacdSKirill Korotaev 			if (have_vmlinux && !s->weak) {
21962a116659SMatthew Wilcox 				if (warn_unresolved) {
2197cb80514dSSam Ravnborg 					warn("\"%s\" [%s.ko] undefined!\n",
2198cb80514dSSam Ravnborg 					     s->name, mod->name);
21992a116659SMatthew Wilcox 				} else {
22002a116659SMatthew Wilcox 					merror("\"%s\" [%s.ko] undefined!\n",
22012a116659SMatthew Wilcox 					       s->name, mod->name);
22022a116659SMatthew Wilcox 					err = 1;
22032a116659SMatthew Wilcox 				}
2204c53ddacdSKirill Korotaev 			}
22051da177e4SLinus Torvalds 			continue;
22061da177e4SLinus Torvalds 		}
22071da177e4SLinus Torvalds 		s->module = exp->module;
22081da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
22091da177e4SLinus Torvalds 		s->crc = exp->crc;
22101da177e4SLinus Torvalds 	}
22111da177e4SLinus Torvalds 
22121da177e4SLinus Torvalds 	if (!modversions)
2213c53ddacdSKirill Korotaev 		return err;
22141da177e4SLinus Torvalds 
22151da177e4SLinus Torvalds 	buf_printf(b, "\n");
22161da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
22173ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22181da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
22191da177e4SLinus Torvalds 
22201da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2221df578e7dSSam Ravnborg 		if (!s->module)
22221da177e4SLinus Torvalds 			continue;
22231da177e4SLinus Torvalds 		if (!s->crc_valid) {
2224cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
22251da177e4SLinus Torvalds 				s->name, mod->name);
22261da177e4SLinus Torvalds 			continue;
22271da177e4SLinus Torvalds 		}
22285cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
22295cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
22305cfb203aSTakashi Iwai 			       s->name, mod->name);
22315cfb203aSTakashi Iwai 			err = 1;
22325cfb203aSTakashi Iwai 			break;
22335cfb203aSTakashi Iwai 		}
2234a53a11f3SJames Hogan 		buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n",
2235a4b6a77bSJames Hogan 			   s->crc, s->name);
22361da177e4SLinus Torvalds 	}
22371da177e4SLinus Torvalds 
22381da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2239c53ddacdSKirill Korotaev 
2240c53ddacdSKirill Korotaev 	return err;
22411da177e4SLinus Torvalds }
22421da177e4SLinus Torvalds 
22435c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod,
22445c3ead8cSSam Ravnborg 			struct module *modules)
22451da177e4SLinus Torvalds {
22461da177e4SLinus Torvalds 	struct symbol *s;
22471da177e4SLinus Torvalds 	struct module *m;
22481da177e4SLinus Torvalds 	int first = 1;
22491da177e4SLinus Torvalds 
2250df578e7dSSam Ravnborg 	for (m = modules; m; m = m->next)
22511da177e4SLinus Torvalds 		m->seen = is_vmlinux(m->name);
22521da177e4SLinus Torvalds 
22531da177e4SLinus Torvalds 	buf_printf(b, "\n");
22541da177e4SLinus Torvalds 	buf_printf(b, "static const char __module_depends[]\n");
22553ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22561da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
22571da177e4SLinus Torvalds 	buf_printf(b, "\"depends=");
22581da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2259a61b2dfdSSam Ravnborg 		const char *p;
22601da177e4SLinus Torvalds 		if (!s->module)
22611da177e4SLinus Torvalds 			continue;
22621da177e4SLinus Torvalds 
22631da177e4SLinus Torvalds 		if (s->module->seen)
22641da177e4SLinus Torvalds 			continue;
22651da177e4SLinus Torvalds 
22661da177e4SLinus Torvalds 		s->module->seen = 1;
2267df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2268df578e7dSSam Ravnborg 		if (p)
2269a61b2dfdSSam Ravnborg 			p++;
2270a61b2dfdSSam Ravnborg 		else
2271a61b2dfdSSam Ravnborg 			p = s->module->name;
2272a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
22731da177e4SLinus Torvalds 		first = 0;
22741da177e4SLinus Torvalds 	}
22751da177e4SLinus Torvalds 	buf_printf(b, "\";\n");
22761da177e4SLinus Torvalds }
22771da177e4SLinus Torvalds 
22785c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
22791da177e4SLinus Torvalds {
22801da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
22811da177e4SLinus Torvalds 		buf_printf(b, "\n");
22821da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
22831da177e4SLinus Torvalds 			   mod->srcversion);
22841da177e4SLinus Torvalds 	}
22851da177e4SLinus Torvalds }
22861da177e4SLinus Torvalds 
22875c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
22881da177e4SLinus Torvalds {
22891da177e4SLinus Torvalds 	char *tmp;
22901da177e4SLinus Torvalds 	FILE *file;
22911da177e4SLinus Torvalds 	struct stat st;
22921da177e4SLinus Torvalds 
22931da177e4SLinus Torvalds 	file = fopen(fname, "r");
22941da177e4SLinus Torvalds 	if (!file)
22951da177e4SLinus Torvalds 		goto write;
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
22981da177e4SLinus Torvalds 		goto close_write;
22991da177e4SLinus Torvalds 
23001da177e4SLinus Torvalds 	if (st.st_size != b->pos)
23011da177e4SLinus Torvalds 		goto close_write;
23021da177e4SLinus Torvalds 
23031da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
23041da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
23051da177e4SLinus Torvalds 		goto free_write;
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
23081da177e4SLinus Torvalds 		goto free_write;
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds 	free(tmp);
23111da177e4SLinus Torvalds 	fclose(file);
23121da177e4SLinus Torvalds 	return;
23131da177e4SLinus Torvalds 
23141da177e4SLinus Torvalds  free_write:
23151da177e4SLinus Torvalds 	free(tmp);
23161da177e4SLinus Torvalds  close_write:
23171da177e4SLinus Torvalds 	fclose(file);
23181da177e4SLinus Torvalds  write:
23191da177e4SLinus Torvalds 	file = fopen(fname, "w");
23201da177e4SLinus Torvalds 	if (!file) {
23211da177e4SLinus Torvalds 		perror(fname);
23221da177e4SLinus Torvalds 		exit(1);
23231da177e4SLinus Torvalds 	}
23241da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
23251da177e4SLinus Torvalds 		perror(fname);
23261da177e4SLinus Torvalds 		exit(1);
23271da177e4SLinus Torvalds 	}
23281da177e4SLinus Torvalds 	fclose(file);
23291da177e4SLinus Torvalds }
23301da177e4SLinus Torvalds 
2331bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2332534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2333bd5cbcedSRam Pai  **/
2334040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
23351da177e4SLinus Torvalds {
23361da177e4SLinus Torvalds 	unsigned long size, pos = 0;
23371da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
23381da177e4SLinus Torvalds 	char *line;
23391da177e4SLinus Torvalds 
23401da177e4SLinus Torvalds 	if (!file)
23411da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
23421da177e4SLinus Torvalds 		return;
23431da177e4SLinus Torvalds 
23441da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2345534b89a9SSam Ravnborg 		char *symname, *modname, *d, *export, *end;
23461da177e4SLinus Torvalds 		unsigned int crc;
23471da177e4SLinus Torvalds 		struct module *mod;
2348040fcc81SSam Ravnborg 		struct symbol *s;
23491da177e4SLinus Torvalds 
23501da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
23511da177e4SLinus Torvalds 			goto fail;
23521da177e4SLinus Torvalds 		*symname++ = '\0';
23531da177e4SLinus Torvalds 		if (!(modname = strchr(symname, '\t')))
23541da177e4SLinus Torvalds 			goto fail;
23551da177e4SLinus Torvalds 		*modname++ = '\0';
23569ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2357bd5cbcedSRam Pai 			*export++ = '\0';
2358534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2359534b89a9SSam Ravnborg 			*end = '\0';
23601da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
23611da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
23621da177e4SLinus Torvalds 			goto fail;
2363df578e7dSSam Ravnborg 		mod = find_module(modname);
2364df578e7dSSam Ravnborg 		if (!mod) {
2365df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
23661da177e4SLinus Torvalds 				have_vmlinux = 1;
23670fa3a88cSJan Beulich 			mod = new_module(modname);
23681da177e4SLinus Torvalds 			mod->skip = 1;
23691da177e4SLinus Torvalds 		}
2370bd5cbcedSRam Pai 		s = sym_add_exported(symname, mod, export_no(export));
2371040fcc81SSam Ravnborg 		s->kernel    = kernel;
23728e70c458SSam Ravnborg 		s->preloaded = 1;
2373bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
23741da177e4SLinus Torvalds 	}
23752ee41e62SChristian Engelmayer 	release_file(file, size);
23761da177e4SLinus Torvalds 	return;
23771da177e4SLinus Torvalds fail:
23782ee41e62SChristian Engelmayer 	release_file(file, size);
23791da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
23801da177e4SLinus Torvalds }
23811da177e4SLinus Torvalds 
2382040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2383040fcc81SSam Ravnborg  * For external modules only dump symbols
2384040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2385040fcc81SSam Ravnborg  **/
2386040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2387040fcc81SSam Ravnborg {
2388040fcc81SSam Ravnborg 	if (!external_module)
2389040fcc81SSam Ravnborg 		return 1;
2390040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2391040fcc81SSam Ravnborg 		return 0;
2392040fcc81SSam Ravnborg 	return 1;
2393040fcc81SSam Ravnborg }
2394040fcc81SSam Ravnborg 
23955c3ead8cSSam Ravnborg static void write_dump(const char *fname)
23961da177e4SLinus Torvalds {
23971da177e4SLinus Torvalds 	struct buffer buf = { };
23981da177e4SLinus Torvalds 	struct symbol *symbol;
23991da177e4SLinus Torvalds 	int n;
24001da177e4SLinus Torvalds 
24011da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
24021da177e4SLinus Torvalds 		symbol = symbolhash[n];
24031da177e4SLinus Torvalds 		while (symbol) {
2404040fcc81SSam Ravnborg 			if (dump_sym(symbol))
2405bd5cbcedSRam Pai 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
2406040fcc81SSam Ravnborg 					symbol->crc, symbol->name,
2407bd5cbcedSRam Pai 					symbol->module->name,
2408bd5cbcedSRam Pai 					export_str(symbol->export));
24091da177e4SLinus Torvalds 			symbol = symbol->next;
24101da177e4SLinus Torvalds 		}
24111da177e4SLinus Torvalds 	}
24121da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2413c7d47f26SHeinrich Schuchardt 	free(buf.p);
24141da177e4SLinus Torvalds }
24151da177e4SLinus Torvalds 
24162d04b5aeSRichard Hacker struct ext_sym_list {
24172d04b5aeSRichard Hacker 	struct ext_sym_list *next;
24182d04b5aeSRichard Hacker 	const char *file;
24192d04b5aeSRichard Hacker };
24202d04b5aeSRichard Hacker 
24215c3ead8cSSam Ravnborg int main(int argc, char **argv)
24221da177e4SLinus Torvalds {
24231da177e4SLinus Torvalds 	struct module *mod;
24241da177e4SLinus Torvalds 	struct buffer buf = { };
2425040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2426712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
24271da177e4SLinus Torvalds 	int opt;
2428c53ddacdSKirill Korotaev 	int err;
24292d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
24302d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
24311da177e4SLinus Torvalds 
243247490ec1SNicolas Boichat 	while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:E")) != -1) {
24331da177e4SLinus Torvalds 		switch (opt) {
24341da177e4SLinus Torvalds 		case 'i':
2435040fcc81SSam Ravnborg 			kernel_read = optarg;
2436040fcc81SSam Ravnborg 			break;
2437040fcc81SSam Ravnborg 		case 'I':
2438040fcc81SSam Ravnborg 			module_read = optarg;
2439040fcc81SSam Ravnborg 			external_module = 1;
24401da177e4SLinus Torvalds 			break;
24412d04b5aeSRichard Hacker 		case 'e':
24422d04b5aeSRichard Hacker 			external_module = 1;
24432d04b5aeSRichard Hacker 			extsym_iter =
24442d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
24452d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
24462d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
24472d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
24482d04b5aeSRichard Hacker 			break;
24491da177e4SLinus Torvalds 		case 'm':
24501da177e4SLinus Torvalds 			modversions = 1;
24511da177e4SLinus Torvalds 			break;
2452eed380f3SGuenter Roeck 		case 'n':
2453eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2454eed380f3SGuenter Roeck 			break;
24551da177e4SLinus Torvalds 		case 'o':
24561da177e4SLinus Torvalds 			dump_write = optarg;
24571da177e4SLinus Torvalds 			break;
24581da177e4SLinus Torvalds 		case 'a':
24591da177e4SLinus Torvalds 			all_versions = 1;
24601da177e4SLinus Torvalds 			break;
24618d8d8289SSam Ravnborg 		case 's':
24628d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
24638d8d8289SSam Ravnborg 			break;
2464588ccd73SSam Ravnborg 		case 'S':
2465588ccd73SSam Ravnborg 			sec_mismatch_verbose = 0;
2466588ccd73SSam Ravnborg 			break;
2467712f9b46SRusty Russell 		case 'T':
2468712f9b46SRusty Russell 			files_source = optarg;
2469712f9b46SRusty Russell 			break;
2470c53ddacdSKirill Korotaev 		case 'w':
2471c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2472c53ddacdSKirill Korotaev 			break;
247347490ec1SNicolas Boichat 		case 'E':
247447490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
247547490ec1SNicolas Boichat 			break;
24761da177e4SLinus Torvalds 		default:
24771da177e4SLinus Torvalds 			exit(1);
24781da177e4SLinus Torvalds 		}
24791da177e4SLinus Torvalds 	}
24801da177e4SLinus Torvalds 
2481040fcc81SSam Ravnborg 	if (kernel_read)
2482040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2483040fcc81SSam Ravnborg 	if (module_read)
2484040fcc81SSam Ravnborg 		read_dump(module_read, 0);
24852d04b5aeSRichard Hacker 	while (extsym_start) {
24862d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
24872d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
24882d04b5aeSRichard Hacker 		free(extsym_start);
24892d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
24902d04b5aeSRichard Hacker 	}
24911da177e4SLinus Torvalds 
2492df578e7dSSam Ravnborg 	while (optind < argc)
24931da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
24941da177e4SLinus Torvalds 
2495712f9b46SRusty Russell 	if (files_source)
2496712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2497712f9b46SRusty Russell 
24981da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next) {
24991da177e4SLinus Torvalds 		if (mod->skip)
25001da177e4SLinus Torvalds 			continue;
2501c96fca21SSam Ravnborg 		check_exports(mod);
2502b817f6feSSam Ravnborg 	}
2503b817f6feSSam Ravnborg 
2504c53ddacdSKirill Korotaev 	err = 0;
2505c53ddacdSKirill Korotaev 
2506b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2507d93e1719SMathias Krause 		char fname[PATH_MAX];
2508666ab414SAndi Kleen 
2509b817f6feSSam Ravnborg 		if (mod->skip)
2510b817f6feSSam Ravnborg 			continue;
25111da177e4SLinus Torvalds 
25121da177e4SLinus Torvalds 		buf.pos = 0;
25131da177e4SLinus Torvalds 
25144fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
25151da177e4SLinus Torvalds 		add_header(&buf, mod);
25162449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2517*caf7501aSAndi Kleen 		add_retpoline(&buf);
2518a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2519c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
25201da177e4SLinus Torvalds 		add_depends(&buf, mod, modules);
25211da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
25221da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
25231da177e4SLinus Torvalds 
25241da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
25251da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
25261da177e4SLinus Torvalds 	}
25271da177e4SLinus Torvalds 	if (dump_write)
25281da177e4SLinus Torvalds 		write_dump(dump_write);
252947490ec1SNicolas Boichat 	if (sec_mismatch_count) {
253047490ec1SNicolas Boichat 		if (!sec_mismatch_verbose) {
25317c0ac495SGeert Uytterhoeven 			warn("modpost: Found %d section mismatch(es).\n"
2532e5f95c8bSSam Ravnborg 			     "To see full details build your kernel with:\n"
2533e5f95c8bSSam Ravnborg 			     "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n",
2534e5f95c8bSSam Ravnborg 			     sec_mismatch_count);
253547490ec1SNicolas Boichat 		}
253647490ec1SNicolas Boichat 		if (sec_mismatch_fatal) {
253747490ec1SNicolas Boichat 			fatal("modpost: Section mismatches detected.\n"
253847490ec1SNicolas Boichat 			      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
253947490ec1SNicolas Boichat 		}
254047490ec1SNicolas Boichat 	}
2541c7d47f26SHeinrich Schuchardt 	free(buf.p);
25421da177e4SLinus Torvalds 
2543c53ddacdSKirill Korotaev 	return err;
25441da177e4SLinus Torvalds }
2545