xref: /linux-6.15/scripts/mod/modpost.c (revision 46c7dd56)
11da177e4SLinus Torvalds /* Postprocess module symbol versions
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright 2003       Kai Germaschewski
41da177e4SLinus Torvalds  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5df578e7dSSam Ravnborg  * Copyright 2006-2008  Sam Ravnborg
61da177e4SLinus Torvalds  * Based in part on module-init-tools/depmod.c,file2alias
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds  * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Usage: modpost vmlinux module1.o module2.o ...
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
14b2e3e658SMathieu Desnoyers #define _GNU_SOURCE
15b2e3e658SMathieu Desnoyers #include <stdio.h>
161da177e4SLinus Torvalds #include <ctype.h>
175003bab8SAndrew Morton #include <string.h>
18712f9b46SRusty Russell #include <limits.h>
19d4ef1c30SRusty Russell #include <stdbool.h>
20eed380f3SGuenter Roeck #include <errno.h>
211da177e4SLinus Torvalds #include "modpost.h"
22b817f6feSSam Ravnborg #include "../../include/linux/license.h"
239e1b9b80SAlan Jenkins 
241da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
257a3ee753SMathias Krause static int modversions = 0;
261da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
277a3ee753SMathias Krause static int have_vmlinux = 0;
281da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
291da177e4SLinus Torvalds static int all_versions = 0;
30040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
31040fcc81SSam Ravnborg static int external_module = 0;
328d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
338d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
34c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
35c53ddacdSKirill Korotaev static int warn_unresolved = 0;
36bd5cbcedSRam Pai /* How a symbol is exported */
37588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
3847490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
39eed380f3SGuenter Roeck /* ignore missing files */
40eed380f3SGuenter Roeck static int ignore_missing_files;
41588ccd73SSam Ravnborg 
42c96fca21SSam Ravnborg enum export {
43c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
44c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
45c96fca21SSam Ravnborg };
461da177e4SLinus Torvalds 
474fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h;
484fd3e4efSWanlong Gao  * here we use Elf_Addr instead of long for covering cross-compile
494fd3e4efSWanlong Gao  */
504fd3e4efSWanlong Gao 
514fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
524fd3e4efSWanlong Gao 
536d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
546d9a89eaSAndi Kleen 
556d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds 	va_list arglist;
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	va_start(arglist, fmt);
621da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
631da177e4SLinus Torvalds 	va_end(arglist);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	exit(1);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
686d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	va_list arglist;
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	va_start(arglist, fmt);
751da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
761da177e4SLinus Torvalds 	va_end(arglist);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
796d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
802a116659SMatthew Wilcox {
812a116659SMatthew Wilcox 	va_list arglist;
822a116659SMatthew Wilcox 
832a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
842a116659SMatthew Wilcox 
852a116659SMatthew Wilcox 	va_start(arglist, fmt);
862a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
872a116659SMatthew Wilcox 	va_end(arglist);
882a116659SMatthew Wilcox }
892a116659SMatthew Wilcox 
90d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
91d4ef1c30SRusty Russell {
92d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
93d4ef1c30SRusty Russell 		return false;
94d4ef1c30SRusty Russell 
95d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
96d4ef1c30SRusty Russell }
97d4ef1c30SRusty Russell 
98040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
99040fcc81SSam Ravnborg {
100040fcc81SSam Ravnborg 	const char *myname;
101040fcc81SSam Ravnborg 
102df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
103df578e7dSSam Ravnborg 	if (myname)
104040fcc81SSam Ravnborg 		myname++;
105040fcc81SSam Ravnborg 	else
106040fcc81SSam Ravnborg 		myname = modname;
107040fcc81SSam Ravnborg 
108741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
109741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
110040fcc81SSam Ravnborg }
111040fcc81SSam Ravnborg 
1121da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1131da177e4SLinus Torvalds {
114df578e7dSSam Ravnborg 	if (!ptr)
1151da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
116df578e7dSSam Ravnborg 
1171da177e4SLinus Torvalds 	return ptr;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds /* A list of all modules we processed */
1211da177e4SLinus Torvalds static struct module *modules;
1221da177e4SLinus Torvalds 
1238b185743SMasahiro Yamada static struct module *find_module(const char *modname)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	struct module *mod;
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1281da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1291da177e4SLinus Torvalds 			break;
1301da177e4SLinus Torvalds 	return mod;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
133d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	struct module *mod;
136d4ef1c30SRusty Russell 	char *p;
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1391da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1401da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 	/* strip trailing .o */
143d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
144d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
145258f7426SFrank Rowand 		mod->is_dot_o = 1;
146258f7426SFrank Rowand 	}
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	/* add to list */
1491da177e4SLinus Torvalds 	mod->name = p;
150b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1511da177e4SLinus Torvalds 	mod->next = modules;
1521da177e4SLinus Torvalds 	modules = mod;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	return mod;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /* A hash of all exported symbols,
1581da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds struct symbol {
1631da177e4SLinus Torvalds 	struct symbol *next;
1641da177e4SLinus Torvalds 	struct module *module;
1651da177e4SLinus Torvalds 	unsigned int crc;
1661da177e4SLinus Torvalds 	int crc_valid;
1671da177e4SLinus Torvalds 	unsigned int weak:1;
168040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
169040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
170040fcc81SSam Ravnborg 				    *  (only for external modules) **/
171b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
172bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1731da177e4SLinus Torvalds 	char name[0];
1741da177e4SLinus Torvalds };
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1791da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1821da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1851da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1861da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds 
1915c3ead8cSSam Ravnborg /**
1925c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1935c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1945c3ead8cSSam Ravnborg  **/
1955c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1965c3ead8cSSam Ravnborg 				   struct symbol *next)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
2011da177e4SLinus Torvalds 	strcpy(s->name, name);
2021da177e4SLinus Torvalds 	s->weak = weak;
2031da177e4SLinus Torvalds 	s->next = next;
2041da177e4SLinus Torvalds 	return s;
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds /* For the hash of exported symbols */
208bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
209bd5cbcedSRam Pai 				 enum export export)
2101da177e4SLinus Torvalds {
2111da177e4SLinus Torvalds 	unsigned int hash;
2121da177e4SLinus Torvalds 	struct symbol *new;
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2151da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2161da177e4SLinus Torvalds 	new->module = module;
217bd5cbcedSRam Pai 	new->export = export;
218040fcc81SSam Ravnborg 	return new;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds 
2215c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds 	struct symbol *s;
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2261da177e4SLinus Torvalds 	if (name[0] == '.')
2271da177e4SLinus Torvalds 		name++;
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2301da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2311da177e4SLinus Torvalds 			return s;
2321da177e4SLinus Torvalds 	}
2331da177e4SLinus Torvalds 	return NULL;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
2367a3ee753SMathias Krause static const struct {
237bd5cbcedSRam Pai 	const char *str;
238bd5cbcedSRam Pai 	enum export export;
239bd5cbcedSRam Pai } export_list[] = {
240bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
241c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
242bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
243c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
244bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
245bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
246bd5cbcedSRam Pai };
247bd5cbcedSRam Pai 
248bd5cbcedSRam Pai 
249bd5cbcedSRam Pai static const char *export_str(enum export ex)
250bd5cbcedSRam Pai {
251bd5cbcedSRam Pai 	return export_list[ex].str;
252bd5cbcedSRam Pai }
253bd5cbcedSRam Pai 
254bd5cbcedSRam Pai static enum export export_no(const char *s)
255bd5cbcedSRam Pai {
256bd5cbcedSRam Pai 	int i;
257df578e7dSSam Ravnborg 
258534b89a9SSam Ravnborg 	if (!s)
259534b89a9SSam Ravnborg 		return export_unknown;
260bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
261bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
262bd5cbcedSRam Pai 			return export_list[i].export;
263bd5cbcedSRam Pai 	}
264bd5cbcedSRam Pai 	return export_unknown;
265bd5cbcedSRam Pai }
266bd5cbcedSRam Pai 
2676124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
2686124c04cSMasahiro Yamada {
2696124c04cSMasahiro Yamada 	return (void *)elf->hdr +
2706124c04cSMasahiro Yamada 		elf->sechdrs[elf->secindex_strings].sh_offset +
2716124c04cSMasahiro Yamada 		sechdr->sh_name;
2726124c04cSMasahiro Yamada }
2736124c04cSMasahiro Yamada 
2746124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex)
2756124c04cSMasahiro Yamada {
2766124c04cSMasahiro Yamada 	return sech_name(elf, &elf->sechdrs[secindex]);
2776124c04cSMasahiro Yamada }
27862a26356SAlessio Igor Bogani 
27962a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
28062a26356SAlessio Igor Bogani 
28162a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
28262a26356SAlessio Igor Bogani {
28362a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
28462a26356SAlessio Igor Bogani 
28562a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
28662a26356SAlessio Igor Bogani 		return export_plain;
28762a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
28862a26356SAlessio Igor Bogani 		return export_unused;
28962a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
29062a26356SAlessio Igor Bogani 		return export_gpl;
29162a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
29262a26356SAlessio Igor Bogani 		return export_unused_gpl;
29362a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
29462a26356SAlessio Igor Bogani 		return export_gpl_future;
29562a26356SAlessio Igor Bogani 	else
29662a26356SAlessio Igor Bogani 		return export_unknown;
29762a26356SAlessio Igor Bogani }
29862a26356SAlessio Igor Bogani 
2991ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
300bd5cbcedSRam Pai {
301bd5cbcedSRam Pai 	if (sec == elf->export_sec)
302bd5cbcedSRam Pai 		return export_plain;
303c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
304c96fca21SSam Ravnborg 		return export_unused;
305bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
306bd5cbcedSRam Pai 		return export_gpl;
307c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
308c96fca21SSam Ravnborg 		return export_unused_gpl;
309bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
310bd5cbcedSRam Pai 		return export_gpl_future;
311bd5cbcedSRam Pai 	else
312bd5cbcedSRam Pai 		return export_unknown;
313bd5cbcedSRam Pai }
314bd5cbcedSRam Pai 
3155c3ead8cSSam Ravnborg /**
3165c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3175c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3185c3ead8cSSam Ravnborg  **/
319bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod,
320bd5cbcedSRam Pai 				       enum export export)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	if (!s) {
325bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3268e70c458SSam Ravnborg 	} else {
3278e70c458SSam Ravnborg 		if (!s->preloaded) {
3287b75b13cSSam Ravnborg 			warn("%s: '%s' exported twice. Previous export "
3298e70c458SSam Ravnborg 			     "was in %s%s\n", mod->name, name,
3308e70c458SSam Ravnborg 			     s->module->name,
3318e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ?"":".ko");
3324b21960fSTrent Piepho 		} else {
333baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3344b21960fSTrent Piepho 			s->module = mod;
3351da177e4SLinus Torvalds 		}
3361da177e4SLinus Torvalds 	}
3378e70c458SSam Ravnborg 	s->preloaded = 0;
338040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
339040fcc81SSam Ravnborg 	s->kernel    = 0;
340bd5cbcedSRam Pai 	s->export    = export;
341040fcc81SSam Ravnborg 	return s;
3421da177e4SLinus Torvalds }
3431da177e4SLinus Torvalds 
344040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
345bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
346040fcc81SSam Ravnborg {
347040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
348040fcc81SSam Ravnborg 
349b6568b1aSRusty Russell 	if (!s) {
350bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
351b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
352b6568b1aSRusty Russell 		s->preloaded = 1;
353b6568b1aSRusty Russell 	}
354040fcc81SSam Ravnborg 	s->crc = crc;
3551da177e4SLinus Torvalds 	s->crc_valid = 1;
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds 
3585c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
3591da177e4SLinus Torvalds {
3601da177e4SLinus Torvalds 	struct stat st;
361eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
3621da177e4SLinus Torvalds 	int fd;
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
365eb3d5cc6SJesper Juhl 	if (fd < 0)
3661da177e4SLinus Torvalds 		return NULL;
367eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
368eb3d5cc6SJesper Juhl 		goto failed;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	*size = st.st_size;
3711da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
3721da177e4SLinus Torvalds 
373eb3d5cc6SJesper Juhl failed:
374eb3d5cc6SJesper Juhl 	close(fd);
3751da177e4SLinus Torvalds 	if (map == MAP_FAILED)
3761da177e4SLinus Torvalds 		return NULL;
3771da177e4SLinus Torvalds 	return map;
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds 
3805c3ead8cSSam Ravnborg /**
3815c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
3825c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
3835c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
3845c3ead8cSSam Ravnborg   **/
3855c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
3861da177e4SLinus Torvalds {
3871da177e4SLinus Torvalds 	static char line[4096];
3881da177e4SLinus Torvalds 	int skip = 1;
3891da177e4SLinus Torvalds 	size_t len = 0;
3901da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
3911da177e4SLinus Torvalds 	char *s = line;
3921da177e4SLinus Torvalds 
393df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
3941da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
3951da177e4SLinus Torvalds 			p++;
3961da177e4SLinus Torvalds 			continue;
3971da177e4SLinus Torvalds 		}
3981da177e4SLinus Torvalds 		skip = 0;
3991da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4001da177e4SLinus Torvalds 			len++;
4011da177e4SLinus Torvalds 			*s++ = *p++;
4021da177e4SLinus Torvalds 			if (len > 4095)
4031da177e4SLinus Torvalds 				break; /* Too long, stop */
4041da177e4SLinus Torvalds 		} else {
4051da177e4SLinus Torvalds 			/* End of string */
4061da177e4SLinus Torvalds 			*s = '\0';
4071da177e4SLinus Torvalds 			return line;
4081da177e4SLinus Torvalds 		}
4091da177e4SLinus Torvalds 	}
4101da177e4SLinus Torvalds 	/* End of buffer */
4111da177e4SLinus Torvalds 	return NULL;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
4145c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4151da177e4SLinus Torvalds {
4161da177e4SLinus Torvalds 	munmap(file, size);
4171da177e4SLinus Torvalds }
4181da177e4SLinus Torvalds 
41985bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4201da177e4SLinus Torvalds {
4211da177e4SLinus Torvalds 	unsigned int i;
42285bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4231da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4241da177e4SLinus Torvalds 	Elf_Sym  *sym;
4251ce53adfSDenys Vlasenko 	const char *secstrings;
4261ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4291da177e4SLinus Torvalds 	if (!hdr) {
430eed380f3SGuenter Roeck 		if (ignore_missing_files) {
431eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
432eed380f3SGuenter Roeck 				strerror(errno));
433eed380f3SGuenter Roeck 			return 0;
434eed380f3SGuenter Roeck 		}
4351da177e4SLinus Torvalds 		perror(filename);
4366803dc0eSSam Ravnborg 		exit(1);
4371da177e4SLinus Torvalds 	}
4381da177e4SLinus Torvalds 	info->hdr = hdr;
43985bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
44085bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
44185bd2fddSSam Ravnborg 		return 0;
44285bd2fddSSam Ravnborg 	}
44385bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
44485bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
44585bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
44685bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
44785bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
44885bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
44985bd2fddSSam Ravnborg 		return 0;
45085bd2fddSSam Ravnborg 	}
4511da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
452ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
4537d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
4547d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
4557d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
4567d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
4577d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
4587d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
4597d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
4607d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
4617d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
4627d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
4637d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
4647d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
4651da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
4661da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
4671da177e4SLinus Torvalds 
468a83710e5SPetr Stetiar 	/* Check if file offset is correct */
469a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
470df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
471df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
472df578e7dSSam Ravnborg 		      filename, info->size);
473a83710e5SPetr Stetiar 		return 0;
474a83710e5SPetr Stetiar 	}
475a83710e5SPetr Stetiar 
4766845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
4771ce53adfSDenys Vlasenko 		/*
4781ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
4791ce53adfSDenys Vlasenko 		 * read count from .sh_size.
4801ce53adfSDenys Vlasenko 		 */
4811ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
4821ce53adfSDenys Vlasenko 	}
4831ce53adfSDenys Vlasenko 	else {
4841ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
4851ce53adfSDenys Vlasenko 	}
4861ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
4876845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
4881ce53adfSDenys Vlasenko 	}
4891ce53adfSDenys Vlasenko 	else {
4901ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
4911ce53adfSDenys Vlasenko 	}
4921ce53adfSDenys Vlasenko 
4931da177e4SLinus Torvalds 	/* Fix endianness in section headers */
4941ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
4957d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
4961da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
4977d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
4987d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
4991da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5001da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5011da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
502ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5037d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5047d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5051da177e4SLinus Torvalds 	}
5061da177e4SLinus Torvalds 	/* Find symbol table. */
5071ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5081ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
509bd5cbcedSRam Pai 		const char *secname;
51056fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5111da177e4SLinus Torvalds 
51256fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
513df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
514df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
515df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
516df578e7dSSam Ravnborg 			      sizeof(*hdr));
51785bd2fddSSam Ravnborg 			return 0;
51885bd2fddSSam Ravnborg 		}
519bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
520bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
52156fc82c5STejun Heo 			if (nobits)
52256fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5231da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5241da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
525bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
526bd5cbcedSRam Pai 			info->export_sec = i;
527c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
528c96fca21SSam Ravnborg 			info->export_unused_sec = i;
529bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
530bd5cbcedSRam Pai 			info->export_gpl_sec = i;
531c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
532c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
533bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
534bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
535bd5cbcedSRam Pai 
5361ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5371ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
5381ce53adfSDenys Vlasenko 			symtab_idx = i;
5391ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
5401ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5411ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
5421ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5436845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
5441da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
5451ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
5461ce53adfSDenys Vlasenko 		}
5471ce53adfSDenys Vlasenko 
5481ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
5491ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
5501ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
5511ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
5521ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5531ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
5541ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5551ce53adfSDenys Vlasenko 		}
5561da177e4SLinus Torvalds 	}
557df578e7dSSam Ravnborg 	if (!info->symtab_start)
558cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
559df578e7dSSam Ravnborg 
5601da177e4SLinus Torvalds 	/* Fix endianness in symbols */
5611da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
5621da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
5631da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
5641da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
5651da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
5661da177e4SLinus Torvalds 	}
5671ce53adfSDenys Vlasenko 
5681ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
5691ce53adfSDenys Vlasenko 		Elf32_Word *p;
5706845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
5711ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
5726845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
5731ce53adfSDenys Vlasenko 			      symtab_idx);
5741ce53adfSDenys Vlasenko 		/* Fix endianness */
5751ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
5761ce53adfSDenys Vlasenko 		     p++)
5771ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
5781ce53adfSDenys Vlasenko 	}
5791ce53adfSDenys Vlasenko 
58085bd2fddSSam Ravnborg 	return 1;
5811da177e4SLinus Torvalds }
5821da177e4SLinus Torvalds 
5835c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
5841da177e4SLinus Torvalds {
5851da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
5861da177e4SLinus Torvalds }
5871da177e4SLinus Torvalds 
5884d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
5894d7365d6SSam Ravnborg {
5904d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
591b2c5cdcfSMasahiro Yamada 	if (strcmp(symname, "__this_module") == 0)
5924d7365d6SSam Ravnborg 		return 1;
5934d7365d6SSam Ravnborg 	/* ignore global offset table */
5944d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
5954d7365d6SSam Ravnborg 		return 1;
5964d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
5974d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
598d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr_") ||
599d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr_") ||
600d62c4765SMasahiro Yamada 		    strstarts(symname, "_rest32gpr_") ||
601d62c4765SMasahiro Yamada 		    strstarts(symname, "_save32gpr_") ||
602d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
603d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_"))
6044d7365d6SSam Ravnborg 			return 1;
6057fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6067fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
607d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr0_") ||
608d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr0_") ||
609d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
610d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_") ||
611c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6127fca5dc8SStephen Rothwell 			return 1;
6134d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6144d7365d6SSam Ravnborg 	return 0;
6154d7365d6SSam Ravnborg }
6164d7365d6SSam Ravnborg 
6175c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6181da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6191da177e4SLinus Torvalds {
6201da177e4SLinus Torvalds 	unsigned int crc;
62162a26356SAlessio Igor Bogani 	enum export export;
622d8c1eb86SNicholas Piggin 	bool is_crc = false;
62362a26356SAlessio Igor Bogani 
624258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
625d62c4765SMasahiro Yamada 	    strstarts(symname, "__ksymtab"))
62662a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
62762a26356SAlessio Igor Bogani 	else
62862a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 	/* CRC'd symbol */
631d62c4765SMasahiro Yamada 	if (strstarts(symname, "__crc_")) {
632d8c1eb86SNicholas Piggin 		is_crc = true;
6331da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
63456067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
63556067812SArd Biesheuvel 			unsigned int *crcp;
63656067812SArd Biesheuvel 
63756067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
63856067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
63956067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
64056067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
64156067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
64256067812SArd Biesheuvel 			crc = *crcp;
64356067812SArd Biesheuvel 		}
644b2c5cdcfSMasahiro Yamada 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
645bd5cbcedSRam Pai 				export);
6461da177e4SLinus Torvalds 	}
647b5064654SAndi Kleen 
648b5064654SAndi Kleen 	switch (sym->st_shndx) {
649b5064654SAndi Kleen 	case SHN_COMMON:
650d62c4765SMasahiro Yamada 		if (strstarts(symname, "__gnu_lto_")) {
651ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
652ef178f92SAndi Kleen 		} else
653b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
6541da177e4SLinus Torvalds 		break;
6551da177e4SLinus Torvalds 	case SHN_UNDEF:
6561da177e4SLinus Torvalds 		/* undefined symbol */
6571da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
6581da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
6591da177e4SLinus Torvalds 			break;
6604d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
6611da177e4SLinus Torvalds 			break;
6628d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
6638d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
6648d529014SBen Colline /* add compatibility with older glibc */
6658d529014SBen Colline #ifndef STT_SPARC_REGISTER
6668d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
6678d529014SBen Colline #endif
6681da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
6691da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
6701da177e4SLinus Torvalds 			/* Ignore register directives. */
6718d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
6721da177e4SLinus Torvalds 				break;
6737caaeabbSAl Viro 			if (symname[0] == '.') {
6741f3aa900SRandy Dunlap 				char *munged = NOFAIL(strdup(symname));
6757caaeabbSAl Viro 				munged[0] = '_';
6767caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
6777caaeabbSAl Viro 				symname = munged;
6787caaeabbSAl Viro 			}
6791da177e4SLinus Torvalds 		}
6801da177e4SLinus Torvalds #endif
6811da177e4SLinus Torvalds 
682d8c1eb86SNicholas Piggin 		if (is_crc) {
683d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
684b2c5cdcfSMasahiro Yamada 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
685b2c5cdcfSMasahiro Yamada 			     symname + strlen("__crc_"), mod->name, e);
686d8c1eb86SNicholas Piggin 		}
687b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
6881da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
6891da177e4SLinus Torvalds 					  mod->unres);
6901da177e4SLinus Torvalds 		break;
6911da177e4SLinus Torvalds 	default:
6921da177e4SLinus Torvalds 		/* All exported symbols */
693d62c4765SMasahiro Yamada 		if (strstarts(symname, "__ksymtab_")) {
694b2c5cdcfSMasahiro Yamada 			sym_add_exported(symname + strlen("__ksymtab_"), mod,
695bd5cbcedSRam Pai 					export);
6961da177e4SLinus Torvalds 		}
697b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "init_module") == 0)
6981da177e4SLinus Torvalds 			mod->has_init = 1;
699b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "cleanup_module") == 0)
7001da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7011da177e4SLinus Torvalds 		break;
7021da177e4SLinus Torvalds 	}
7031da177e4SLinus Torvalds }
7041da177e4SLinus Torvalds 
7055c3ead8cSSam Ravnborg /**
7065c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7075c3ead8cSSam Ravnborg  **/
7081da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7091da177e4SLinus Torvalds {
7101da177e4SLinus Torvalds 	/* Skip non-zero chars */
7111da177e4SLinus Torvalds 	while (string[0]) {
7121da177e4SLinus Torvalds 		string++;
7131da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7141da177e4SLinus Torvalds 			return NULL;
7151da177e4SLinus Torvalds 	}
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 	/* Skip any zero padding. */
7181da177e4SLinus Torvalds 	while (!string[0]) {
7191da177e4SLinus Torvalds 		string++;
7201da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7211da177e4SLinus Torvalds 			return NULL;
7221da177e4SLinus Torvalds 	}
7231da177e4SLinus Torvalds 	return string;
7241da177e4SLinus Torvalds }
7251da177e4SLinus Torvalds 
726bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag,
727bca2cceeSMasahiro Yamada 			      char *prev)
7281da177e4SLinus Torvalds {
7291da177e4SLinus Torvalds 	char *p;
7301da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
731bca2cceeSMasahiro Yamada 	char *modinfo = info->modinfo;
732bca2cceeSMasahiro Yamada 	unsigned long size = info->modinfo_len;
7331da177e4SLinus Torvalds 
734bca2cceeSMasahiro Yamada 	if (prev) {
735bca2cceeSMasahiro Yamada 		size -= prev - modinfo;
736bca2cceeSMasahiro Yamada 		modinfo = next_string(prev, &size);
737b817f6feSSam Ravnborg 	}
738b817f6feSSam Ravnborg 
7391da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
7401da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7411da177e4SLinus Torvalds 			return p + taglen + 1;
7421da177e4SLinus Torvalds 	}
7431da177e4SLinus Torvalds 	return NULL;
7441da177e4SLinus Torvalds }
7451da177e4SLinus Torvalds 
746bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag)
747b817f6feSSam Ravnborg 
748b817f6feSSam Ravnborg {
749bca2cceeSMasahiro Yamada 	return get_next_modinfo(info, tag, NULL);
750b817f6feSSam Ravnborg }
751b817f6feSSam Ravnborg 
75293684d3bSSam Ravnborg /**
7534c8fbca5SSam Ravnborg  * Test if string s ends in string sub
7544c8fbca5SSam Ravnborg  * return 0 if match
7554c8fbca5SSam Ravnborg  **/
7564c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
7574c8fbca5SSam Ravnborg {
7584c8fbca5SSam Ravnborg 	int slen, sublen;
7594c8fbca5SSam Ravnborg 
7604c8fbca5SSam Ravnborg 	if (!s || !sub)
7614c8fbca5SSam Ravnborg 		return 1;
7624c8fbca5SSam Ravnborg 
7634c8fbca5SSam Ravnborg 	slen = strlen(s);
7644c8fbca5SSam Ravnborg 	sublen = strlen(sub);
7654c8fbca5SSam Ravnborg 
7664c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
7674c8fbca5SSam Ravnborg 		return 1;
7684c8fbca5SSam Ravnborg 
7694c8fbca5SSam Ravnborg 	if (sublen > slen)
7704c8fbca5SSam Ravnborg 		return 1;
7714c8fbca5SSam Ravnborg 
7724c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
7734c8fbca5SSam Ravnborg }
7744c8fbca5SSam Ravnborg 
775ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
776ff13f926SSam Ravnborg {
77758fb0d4fSSam Ravnborg 	if (sym)
778ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
77958fb0d4fSSam Ravnborg 	else
780f666751aSSam Ravnborg 		return "(unknown)";
781ff13f926SSam Ravnborg }
782ff13f926SSam Ravnborg 
78310668220SSam Ravnborg /* The pattern is an array of simple patterns.
78410668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
7856c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
78610668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
78709c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
78810668220SSam Ravnborg  */
7895c725138STrevor Keith static int match(const char *sym, const char * const pat[])
79010668220SSam Ravnborg {
79110668220SSam Ravnborg 	const char *p;
79210668220SSam Ravnborg 	while (*pat) {
79310668220SSam Ravnborg 		p = *pat++;
79410668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
79510668220SSam Ravnborg 
79609c20c03SPaul Gortmaker 		/* "*foo*" */
79709c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
79809c20c03SPaul Gortmaker 			char *here, *bare = strndup(p + 1, strlen(p) - 2);
79909c20c03SPaul Gortmaker 
80009c20c03SPaul Gortmaker 			here = strstr(sym, bare);
80109c20c03SPaul Gortmaker 			free(bare);
80209c20c03SPaul Gortmaker 			if (here != NULL)
80309c20c03SPaul Gortmaker 				return 1;
80409c20c03SPaul Gortmaker 		}
8056c5bd235SSam Ravnborg 		/* "*foo" */
80609c20c03SPaul Gortmaker 		else if (*p == '*') {
8076c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8086c5bd235SSam Ravnborg 				return 1;
8096c5bd235SSam Ravnborg 		}
81010668220SSam Ravnborg 		/* "foo*" */
8116c5bd235SSam Ravnborg 		else if (*endp == '*') {
81210668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
81310668220SSam Ravnborg 				return 1;
81410668220SSam Ravnborg 		}
81510668220SSam Ravnborg 		/* no wildcards */
81610668220SSam Ravnborg 		else {
81710668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
81810668220SSam Ravnborg 				return 1;
81910668220SSam Ravnborg 		}
82010668220SSam Ravnborg 	}
82110668220SSam Ravnborg 	/* no match */
82210668220SSam Ravnborg 	return 0;
82310668220SSam Ravnborg }
82410668220SSam Ravnborg 
82510668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8267a3ee753SMathias Krause static const char *const section_white_list[] =
8274391ed6aSSam Ravnborg {
8284391ed6aSSam Ravnborg 	".comment*",
8294391ed6aSSam Ravnborg 	".debug*",
8304d10c223SChen Gang 	".cranges",		/* sh64 */
8311121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
832739d875dSDavid Howells 	".GCC.command.line",	/* record-gcc-switches */
8334391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8344391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8354391ed6aSSam Ravnborg 	".stab*",
8364391ed6aSSam Ravnborg 	".note*",
8374391ed6aSSam Ravnborg 	".got*",
8384391ed6aSSam Ravnborg 	".toc*",
839af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
840af42e970SMax Filippov 	".xt.lit",         /* xtensa */
841f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
842f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
843d1189c63SNoam Camus 	".cmem*",			/* EZchip */
844d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
845ef178f92SAndi Kleen 	".gnu.lto*",
846e390f9a9SJosh Poimboeuf 	".discard.*",
8474391ed6aSSam Ravnborg 	NULL
8484391ed6aSSam Ravnborg };
84910668220SSam Ravnborg 
850e241a630SSam Ravnborg /*
851b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
852e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
853b614a697SAnders Kaseorg  * without "ax" / "aw".
854e241a630SSam Ravnborg  */
855b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
856b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
857e241a630SSam Ravnborg {
858b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
859e241a630SSam Ravnborg 
860b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
861b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
862b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
863b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
864b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
865e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
866e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
867e241a630SSam Ravnborg 		     modname, sec);
868e241a630SSam Ravnborg 	}
869e241a630SSam Ravnborg }
870e241a630SSam Ravnborg 
871e241a630SSam Ravnborg 
872e241a630SSam Ravnborg 
873eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
874a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
875a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
876eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
877a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
87810668220SSam Ravnborg 
879eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
880a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
881eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
882a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
88310668220SSam Ravnborg 
884bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
885a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
886a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
887a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
888bb15d8dbSSebastian Andrzej Siewior 
889e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
890e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
8914a31a229SUwe Kleine-König 
8924a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
8934a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
89410668220SSam Ravnborg 
895a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
896157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
8976727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
89852dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
899673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
900673c2c34SChris Metcalf 		".coldtext"
90110668220SSam Ravnborg 
902fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
903fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
904eb8f6890SSam Ravnborg 
905fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
906fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
907eb8f6890SSam Ravnborg 
90852dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
90952dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
91052dc0595SQuentin Casasnovas 
9116c5bd235SSam Ravnborg /* init data sections */
9127a3ee753SMathias Krause static const char *const init_data_sections[] =
9137a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9146c5bd235SSam Ravnborg 
9156c5bd235SSam Ravnborg /* all init sections */
9167a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9176c5bd235SSam Ravnborg 
9186c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9197a3ee753SMathias Krause static const char *const init_exit_sections[] =
920eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9216c5bd235SSam Ravnborg 
9224a3893d0SPaul Gortmaker /* all text sections */
9234a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9244a3893d0SPaul Gortmaker 
9256c5bd235SSam Ravnborg /* data section */
9267a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9276c5bd235SSam Ravnborg 
9286c5bd235SSam Ravnborg 
9296c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
930af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
931af92a82dSUwe Kleine-König 	"*driver",							\
932af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
933af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
934af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
935af92a82dSUwe Kleine-König 	"*_ops",							\
936af92a82dSUwe Kleine-König 	"*_probe",							\
937af92a82dSUwe Kleine-König 	"*_probe_one",							\
938af92a82dSUwe Kleine-König 	"*_console"
9396c5bd235SSam Ravnborg 
9407a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
9417a3ee753SMathias Krause static const char *const linker_symbols[] =
9426c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
9434a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
9446c5bd235SSam Ravnborg 
945588ccd73SSam Ravnborg enum mismatch {
946bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
947bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
948bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
949bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
950bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
951bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
952bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
953bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
954588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
95552dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
956588ccd73SSam Ravnborg };
957588ccd73SSam Ravnborg 
958e5d8f59aSQuentin Casasnovas /**
959e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
960e5d8f59aSQuentin Casasnovas  *
961e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
962e5d8f59aSQuentin Casasnovas  *
963e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
964e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
965e5d8f59aSQuentin Casasnovas  *
966e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
967e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
968e5d8f59aSQuentin Casasnovas  *
969e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
970e5d8f59aSQuentin Casasnovas  *
971e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
972e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
973e5d8f59aSQuentin Casasnovas  *
974e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
975e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
976e5d8f59aSQuentin Casasnovas  *
977e5d8f59aSQuentin Casasnovas  */
97810668220SSam Ravnborg struct sectioncheck {
97910668220SSam Ravnborg 	const char *fromsec[20];
980050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
981050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
982588ccd73SSam Ravnborg 	enum mismatch mismatch;
983af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
984644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
985644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
986644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
987644e8f14SQuentin Casasnovas 
98810668220SSam Ravnborg };
98910668220SSam Ravnborg 
99052dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
99152dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
99252dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
99352dc0595SQuentin Casasnovas 				     const char *fromsec);
99452dc0595SQuentin Casasnovas 
9957a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
99610668220SSam Ravnborg /* Do not reference init/exit code/data from
99710668220SSam Ravnborg  * normal code and data
99810668220SSam Ravnborg  */
99910668220SSam Ravnborg {
1000588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1001050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1002bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1003af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1004588ccd73SSam Ravnborg },
1005588ccd73SSam Ravnborg {
1006588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1007050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1008bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1009af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1010588ccd73SSam Ravnborg },
1011588ccd73SSam Ravnborg {
10120db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1013050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10140db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10150db25245SUwe Kleine-König 	.symbol_white_list = {
10160db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10170db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10180db25245SUwe Kleine-König 	},
10190db25245SUwe Kleine-König },
10200db25245SUwe Kleine-König {
1021588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1022050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1023bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1024af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1025588ccd73SSam Ravnborg },
1026588ccd73SSam Ravnborg {
1027588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1028050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1029bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1030af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1031eb8f6890SSam Ravnborg },
1032e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1033eb8f6890SSam Ravnborg {
10344a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1035050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1036bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1037af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1038eb8f6890SSam Ravnborg },
1039e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1040eb8f6890SSam Ravnborg {
10414a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1042050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1043bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1044af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
104510668220SSam Ravnborg },
104610668220SSam Ravnborg /* Do not use exit code/data from init code */
104710668220SSam Ravnborg {
1048eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1049050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1050bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1051af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
105210668220SSam Ravnborg },
105310668220SSam Ravnborg /* Do not use init code/data from exit code */
105410668220SSam Ravnborg {
1055eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1056050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1057bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1058af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
105910668220SSam Ravnborg },
1060bb15d8dbSSebastian Andrzej Siewior {
1061bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1062050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1063bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1064bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1065bb15d8dbSSebastian Andrzej Siewior },
106610668220SSam Ravnborg /* Do not export init/exit functions or data */
106710668220SSam Ravnborg {
106810668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1069050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1070af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1071af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
107252dc0595SQuentin Casasnovas },
107352dc0595SQuentin Casasnovas {
107452dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
107552dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
107652dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
107752dc0595SQuentin Casasnovas 	 */
107852dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
107952dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
108052dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
108152dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
108210668220SSam Ravnborg }
108310668220SSam Ravnborg };
108410668220SSam Ravnborg 
10850d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
10860d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
108710668220SSam Ravnborg {
108810668220SSam Ravnborg 	int i;
108910668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
109010668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
109110668220SSam Ravnborg 
1092c5c3439aSQuentin Casasnovas 	/*
1093c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1094c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1095739d875dSDavid Howells 	 * doesn't make much sense and causes build failures on parisc
1096739d875dSDavid Howells 	 * architectures.
1097c5c3439aSQuentin Casasnovas 	 */
1098c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1099c5c3439aSQuentin Casasnovas 		return NULL;
1100c5c3439aSQuentin Casasnovas 
110110668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1102050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1103050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11040d2a636eSUwe Kleine-König 				return check;
1105050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1106050e57fdSQuentin Casasnovas 				return check;
1107050e57fdSQuentin Casasnovas 		}
110810668220SSam Ravnborg 		check++;
110910668220SSam Ravnborg 	}
11100d2a636eSUwe Kleine-König 	return NULL;
111110668220SSam Ravnborg }
111210668220SSam Ravnborg 
11134c8fbca5SSam Ravnborg /**
11144c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11150e0d314eSSam Ravnborg  *
11164c8fbca5SSam Ravnborg  * Pattern 1:
11174c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11184c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11194c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11204c8fbca5SSam Ravnborg  *   this pattern.
11214c8fbca5SSam Ravnborg  *   The pattern is identified by:
11224c8fbca5SSam Ravnborg  *   tosec   = .init.data
11239209aed0SSam Ravnborg  *   fromsec = .data*
11244c8fbca5SSam Ravnborg  *   atsym   =__param*
11254c8fbca5SSam Ravnborg  *
11266a841528SRusty Russell  * Pattern 1a:
11276a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11286a841528SRusty Russell  *   The pattern is identified by:
11296a841528SRusty Russell  *   tosec   = .init.text
11306a841528SRusty Russell  *   fromsec = .data*
11316a841528SRusty Russell  *   atsym   = __param_ops_*
11326a841528SRusty Russell  *
11334c8fbca5SSam Ravnborg  * Pattern 2:
113472ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11354c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
11364c8fbca5SSam Ravnborg  *   the pattern is identified by:
113783cda2bbSSam Ravnborg  *   tosec   = init or exit section
113883cda2bbSSam Ravnborg  *   fromsec = data section
1139df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1140df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1141ee6a8545SVivek Goyal  *
1142ee6a8545SVivek Goyal  * Pattern 3:
1143c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
11449bf8cb9bSSam Ravnborg  *
11451d8af559SSam Ravnborg  * Pattern 4:
1146ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1147ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1148ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1149ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1150ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1151ee6a8545SVivek Goyal  *   This pattern is identified by
1152ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
11539bf8cb9bSSam Ravnborg  *
11544a3893d0SPaul Gortmaker  * Pattern 5:
11554a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
11564a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
11574a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
11584a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
11594a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
11604a3893d0SPaul Gortmaker  *   This pattern is identified by
11614a3893d0SPaul Gortmaker  *   tosec   = init section
11624a3893d0SPaul Gortmaker  *   fromsec = text section
11634a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
11644a3893d0SPaul Gortmaker  *
1165a4d26f1aSPaul Walmsley  * Pattern 6:
1166a4d26f1aSPaul Walmsley  *   Hide section mismatch warnings for ELF local symbols.  The goal
1167a4d26f1aSPaul Walmsley  *   is to eliminate false positive modpost warnings caused by
1168a4d26f1aSPaul Walmsley  *   compiler-generated ELF local symbol names such as ".LANCHOR1".
1169a4d26f1aSPaul Walmsley  *   Autogenerated symbol names bypass modpost's "Pattern 2"
1170a4d26f1aSPaul Walmsley  *   whitelisting, which relies on pattern-matching against symbol
1171a4d26f1aSPaul Walmsley  *   names to work.  (One situation where gcc can autogenerate ELF
1172a4d26f1aSPaul Walmsley  *   local symbols is when "-fsection-anchors" is used.)
11734c8fbca5SSam Ravnborg  **/
1174af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1175af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
117658fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
11774c8fbca5SSam Ravnborg {
11784c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
11796c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
11806c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1181d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param"))
118258fb0d4fSSam Ravnborg 		return 0;
11834c8fbca5SSam Ravnborg 
11846a841528SRusty Russell 	/* Check for pattern 1a */
11856a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
11866a841528SRusty Russell 	    match(fromsec, data_sections) &&
1187d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param_ops_"))
11886a841528SRusty Russell 		return 0;
11896a841528SRusty Russell 
11904c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
11916c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
11926c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1193af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
119458fb0d4fSSam Ravnborg 		return 0;
11954c8fbca5SSam Ravnborg 
11969bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
11976c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
11986c5bd235SSam Ravnborg 	    match(tosec, init_sections))
119958fb0d4fSSam Ravnborg 		return 0;
1200f8657e1bSVivek Goyal 
12011d8af559SSam Ravnborg 	/* Check for pattern 4 */
120258fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
120393659af1SSam Ravnborg 		return 0;
120458fb0d4fSSam Ravnborg 
12054a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12064a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12074a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12084a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12094a3893d0SPaul Gortmaker 		return 0;
12104a3893d0SPaul Gortmaker 
1211a4d26f1aSPaul Walmsley 	/* Check for pattern 6 */
1212a4d26f1aSPaul Walmsley 	if (strstarts(fromsym, ".L"))
1213a4d26f1aSPaul Walmsley 		return 0;
1214a4d26f1aSPaul Walmsley 
121558fb0d4fSSam Ravnborg 	return 1;
12164c8fbca5SSam Ravnborg }
12174c8fbca5SSam Ravnborg 
12185818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str)
12195818c683SSami Tolvanen {
12205818c683SSami Tolvanen 	return str[0] == '$' && strchr("axtd", str[1])
12215818c683SSami Tolvanen 	       && (str[2] == '\0' || str[2] == '.');
12225818c683SSami Tolvanen }
12235818c683SSami Tolvanen 
12245818c683SSami Tolvanen /*
12255818c683SSami Tolvanen  * If there's no name there, ignore it; likewise, ignore it if it's
12265818c683SSami Tolvanen  * one of the magic symbols emitted used by current ARM tools.
12275818c683SSami Tolvanen  *
12285818c683SSami Tolvanen  * Otherwise if find_symbols_between() returns those symbols, they'll
12295818c683SSami Tolvanen  * fail the whitelist tests and cause lots of false alarms ... fixable
12305818c683SSami Tolvanen  * only by merging __exit and __init sections into __text, bloating
12315818c683SSami Tolvanen  * the kernel (which is especially evil on embedded platforms).
12325818c683SSami Tolvanen  */
12335818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
12345818c683SSami Tolvanen {
12355818c683SSami Tolvanen 	const char *name = elf->strtab + sym->st_name;
12365818c683SSami Tolvanen 
12375818c683SSami Tolvanen 	if (!name || !strlen(name))
12385818c683SSami Tolvanen 		return 0;
12395818c683SSami Tolvanen 	return !is_arm_mapping_symbol(name);
12405818c683SSami Tolvanen }
12415818c683SSami Tolvanen 
12424c8fbca5SSam Ravnborg /**
124393684d3bSSam Ravnborg  * Find symbol based on relocation record info.
124493684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
124593684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
124693684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
124793684d3bSSam Ravnborg  * based on section and address.
124893684d3bSSam Ravnborg  *  **/
12499ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
125093684d3bSSam Ravnborg 				Elf_Sym *relsym)
125193684d3bSSam Ravnborg {
125293684d3bSSam Ravnborg 	Elf_Sym *sym;
12539ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
12549ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
12559ad21c3fSSam Ravnborg 	Elf64_Sword d;
12561ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
125793684d3bSSam Ravnborg 
125893684d3bSSam Ravnborg 	if (relsym->st_name != 0)
125993684d3bSSam Ravnborg 		return relsym;
12601ce53adfSDenys Vlasenko 
12611ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
126293684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
12631ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
126493684d3bSSam Ravnborg 			continue;
1265ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1266ae4ac123SAtsushi Nemoto 			continue;
12675818c683SSami Tolvanen 		if (!is_valid_name(elf, sym))
12685818c683SSami Tolvanen 			continue;
126993684d3bSSam Ravnborg 		if (sym->st_value == addr)
127093684d3bSSam Ravnborg 			return sym;
12719ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
12729ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
12739ad21c3fSSam Ravnborg 		if (d < 0)
12749ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
12759ad21c3fSSam Ravnborg 		if (d < distance) {
12769ad21c3fSSam Ravnborg 			distance = d;
12779ad21c3fSSam Ravnborg 			near = sym;
127893684d3bSSam Ravnborg 		}
12799ad21c3fSSam Ravnborg 	}
12809ad21c3fSSam Ravnborg 	/* We need a close match */
12819ad21c3fSSam Ravnborg 	if (distance < 20)
12829ad21c3fSSam Ravnborg 		return near;
12839ad21c3fSSam Ravnborg 	else
128493684d3bSSam Ravnborg 		return NULL;
128593684d3bSSam Ravnborg }
128693684d3bSSam Ravnborg 
1287b39927cfSSam Ravnborg /*
128843c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
128943c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
129043c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
129143c74d17SSam Ravnborg  * it is, but this works for now.
1292b39927cfSSam Ravnborg  **/
1293157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1294157c23c8SSam Ravnborg 				 const char *sec)
1295b39927cfSSam Ravnborg {
1296b39927cfSSam Ravnborg 	Elf_Sym *sym;
1297157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1298157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1299b39927cfSSam Ravnborg 
1300b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1301b39927cfSSam Ravnborg 		const char *symsec;
1302b39927cfSSam Ravnborg 
13031ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1304b39927cfSSam Ravnborg 			continue;
13051ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1306b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1307b39927cfSSam Ravnborg 			continue;
1308da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1309da68d61fSDavid Brownell 			continue;
1310b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1311157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1312157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1313157c23c8SSam Ravnborg 				near = sym;
1314157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1315157c23c8SSam Ravnborg 				near = sym;
131643c74d17SSam Ravnborg 			}
1317b39927cfSSam Ravnborg 		}
1318b39927cfSSam Ravnborg 	}
1319157c23c8SSam Ravnborg 	return near;
1320157c23c8SSam Ravnborg }
1321b39927cfSSam Ravnborg 
132258fb0d4fSSam Ravnborg /*
1323588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1324588ccd73SSam Ravnborg  * .init.text => __init
1325588ccd73SSam Ravnborg  * .memexitconst => __memconst
1326588ccd73SSam Ravnborg  * etc.
1327cbcf14a9SAndy Shevchenko  *
1328cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1329cbcf14a9SAndy Shevchenko  * method should free it after usage.
1330588ccd73SSam Ravnborg */
1331588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1332588ccd73SSam Ravnborg {
1333588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
13341f3aa900SRandy Dunlap 		char *p = NOFAIL(malloc(20));
1335588ccd73SSam Ravnborg 		char *r = p;
1336588ccd73SSam Ravnborg 
1337588ccd73SSam Ravnborg 		*p++ = '_';
1338588ccd73SSam Ravnborg 		*p++ = '_';
1339588ccd73SSam Ravnborg 		if (*s == '.')
1340588ccd73SSam Ravnborg 			s++;
1341588ccd73SSam Ravnborg 		while (*s && *s != '.')
1342588ccd73SSam Ravnborg 			*p++ = *s++;
1343588ccd73SSam Ravnborg 		*p = '\0';
1344588ccd73SSam Ravnborg 		if (*s == '.')
1345588ccd73SSam Ravnborg 			s++;
1346588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1347588ccd73SSam Ravnborg 			strcat(p, "const ");
1348588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1349588ccd73SSam Ravnborg 			strcat(p, "data ");
1350588ccd73SSam Ravnborg 		else
1351588ccd73SSam Ravnborg 			strcat(p, " ");
1352cbcf14a9SAndy Shevchenko 		return r;
1353588ccd73SSam Ravnborg 	} else {
13541f3aa900SRandy Dunlap 		return NOFAIL(strdup(""));
1355588ccd73SSam Ravnborg 	}
1356588ccd73SSam Ravnborg }
1357588ccd73SSam Ravnborg 
1358588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1359588ccd73SSam Ravnborg {
1360588ccd73SSam Ravnborg 	if (sym)
1361588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1362588ccd73SSam Ravnborg 	else
1363f666751aSSam Ravnborg 		return -1;
1364588ccd73SSam Ravnborg }
1365588ccd73SSam Ravnborg 
136600759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
136700759c0eSRandy Dunlap {
136800759c0eSRandy Dunlap 	const char *const *s = list;
136900759c0eSRandy Dunlap 
137000759c0eSRandy Dunlap 	while (*s) {
137100759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
137200759c0eSRandy Dunlap 		s++;
137300759c0eSRandy Dunlap 		if (*s)
137400759c0eSRandy Dunlap 			fprintf(stderr, ", ");
137500759c0eSRandy Dunlap 	}
137600759c0eSRandy Dunlap 	fprintf(stderr, "\n");
137700759c0eSRandy Dunlap }
137800759c0eSRandy Dunlap 
1379356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1380356ad538SQuentin Casasnovas {
1381356ad538SQuentin Casasnovas 	switch (is_func) {
1382356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1383356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1384356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1385356ad538SQuentin Casasnovas 	}
1386356ad538SQuentin Casasnovas }
1387356ad538SQuentin Casasnovas 
1388588ccd73SSam Ravnborg /*
1389b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1390b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
13914c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
139258fb0d4fSSam Ravnborg  */
13930d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
13940d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
139558fb0d4fSSam Ravnborg 				const char *fromsec,
139658fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
139758fb0d4fSSam Ravnborg 				const char *fromsym,
1398588ccd73SSam Ravnborg 				int from_is_func,
1399588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1400588ccd73SSam Ravnborg 				int to_is_func)
1401b39927cfSSam Ravnborg {
1402588ccd73SSam Ravnborg 	const char *from, *from_p;
1403588ccd73SSam Ravnborg 	const char *to, *to_p;
140437ed19d5SAlexey Fomenko 	char *prl_from;
140537ed19d5SAlexey Fomenko 	char *prl_to;
1406f666751aSSam Ravnborg 
1407e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
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 
1546d62c4765SMasahiro Yamada 	if (strstarts(fromsym, "reference___initcall"))
154777ab21adSAndi Kleen 		return;
154877ab21adSAndi Kleen 
1549c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1550c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1551c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1552c7a65e06SQuentin Casasnovas 
155358fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1554af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1555af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1556588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1557588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1558588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1559588ccd73SSam Ravnborg 				    is_function(to));
156058fb0d4fSSam Ravnborg 	}
1561b39927cfSSam Ravnborg }
1562644e8f14SQuentin Casasnovas 
156352dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
156452dc0595SQuentin Casasnovas {
156552dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
156652dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
156752dc0595SQuentin Casasnovas 
156852dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
156952dc0595SQuentin Casasnovas }
157052dc0595SQuentin Casasnovas 
157152dc0595SQuentin Casasnovas /*
157252dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
157352dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
157452dc0595SQuentin Casasnovas  */
157552dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1576e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
157752dc0595SQuentin Casasnovas {
157852dc0595SQuentin Casasnovas 	/*
157952dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
158052dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
158152dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
158252dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
158352dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
158452dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
158552dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
158652dc0595SQuentin Casasnovas 	 */
1587e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
158852dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
158952dc0595SQuentin Casasnovas }
1590e84048aaSQuentin Casasnovas 
159152dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
159252dc0595SQuentin Casasnovas {
1593d3df4de7SQuentin Casasnovas 	/*
1594d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1595d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1596d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1597d3df4de7SQuentin Casasnovas 	 */
1598d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
159952dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
160052dc0595SQuentin Casasnovas 
160152dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
160252dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
160352dc0595SQuentin Casasnovas }
160452dc0595SQuentin Casasnovas 
1605e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1606e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1607e84048aaSQuentin Casasnovas 
160852dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
160952dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
161052dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
161152dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
161252dc0595SQuentin Casasnovas {
161352dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
161452dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
161552dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
161652dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
161752dc0595SQuentin Casasnovas 	const char* from_pretty_name;
161852dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
161952dc0595SQuentin Casasnovas 	const char* to_pretty_name;
162052dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
162152dc0595SQuentin Casasnovas 
162252dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
162352dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
162452dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
162552dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
162652dc0595SQuentin Casasnovas 
162752dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
162852dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
162952dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
163052dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
163152dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
163252dc0595SQuentin Casasnovas 
163352dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
163452dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
163552dc0595SQuentin Casasnovas 		fprintf(stderr,
163652dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
163752dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
163852dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
163952dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
164052dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
164152dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
164252dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
164352dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
164452dc0595SQuentin Casasnovas }
164552dc0595SQuentin Casasnovas 
164652dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
164752dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
164852dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
164952dc0595SQuentin Casasnovas 				     const char *fromsec)
165052dc0595SQuentin Casasnovas {
165152dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
165252dc0595SQuentin Casasnovas 
165352dc0595SQuentin Casasnovas 	sec_mismatch_count++;
165452dc0595SQuentin Casasnovas 
1655*46c7dd56SMasahiro Yamada 	report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
165652dc0595SQuentin Casasnovas 
165752dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
165852dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
165952dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
166052dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
166152dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
166252dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
166352dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
166452dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
166552dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
166652dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
166752dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
166852dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
166952dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
167052dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
167152dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
167252dc0595SQuentin Casasnovas 		else
167352dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
167452dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
167552dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
167652dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
167752dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
167852dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
167952dc0595SQuentin Casasnovas 	}
168052dc0595SQuentin Casasnovas }
168152dc0595SQuentin Casasnovas 
1682644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1683644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1684644e8f14SQuentin Casasnovas {
16850cad61d7SLuis de Bethencourt 	const char *tosec = sec_name(elf, get_secindex(elf, sym));
1686644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1687644e8f14SQuentin Casasnovas 
1688644e8f14SQuentin Casasnovas 	if (mismatch) {
1689644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1690644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1691644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1692644e8f14SQuentin Casasnovas 		else
1693644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1694644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1695644e8f14SQuentin Casasnovas 	}
1696b39927cfSSam Ravnborg }
1697b39927cfSSam Ravnborg 
1698ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
16995b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1700ae4ac123SAtsushi Nemoto {
1701ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17026845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1703ae4ac123SAtsushi Nemoto 
1704ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1705731ece41SOlof Johansson 		r->r_offset;
1706ae4ac123SAtsushi Nemoto }
1707ae4ac123SAtsushi Nemoto 
17085b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1709ae4ac123SAtsushi Nemoto {
1710ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17115b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1712ae4ac123SAtsushi Nemoto 
1713ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1714ae4ac123SAtsushi Nemoto 	case R_386_32:
1715ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1716ae4ac123SAtsushi Nemoto 		break;
1717ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1718ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1719ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1720ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1721ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1722ae4ac123SAtsushi Nemoto 		break;
1723ae4ac123SAtsushi Nemoto 	}
1724ae4ac123SAtsushi Nemoto 	return 0;
1725ae4ac123SAtsushi Nemoto }
1726ae4ac123SAtsushi Nemoto 
17276e2e340bSTony Lindgren #ifndef R_ARM_CALL
17286e2e340bSTony Lindgren #define R_ARM_CALL	28
17296e2e340bSTony Lindgren #endif
17306e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17316e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17326e2e340bSTony Lindgren #endif
17336e2e340bSTony Lindgren 
1734c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1735c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1736c9698e5cSDavid A. Long #endif
1737c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1738c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1739c9698e5cSDavid A. Long #endif
1740c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1741c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1742c9698e5cSDavid A. Long #endif
1743c9698e5cSDavid A. Long 
17445b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
174556a974faSSam Ravnborg {
174656a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
174756a974faSSam Ravnborg 
174856a974faSSam Ravnborg 	switch (r_typ) {
174956a974faSSam Ravnborg 	case R_ARM_ABS32:
175056a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1751df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1752df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
175356a974faSSam Ravnborg 		break;
175456a974faSSam Ravnborg 	case R_ARM_PC24:
17556e2e340bSTony Lindgren 	case R_ARM_CALL:
17566e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1757c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1758c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1759c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
176056a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1761df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
17625b24c071SSam Ravnborg 			      sechdr->sh_offset +
17635b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
176456a974faSSam Ravnborg 		break;
176556a974faSSam Ravnborg 	default:
176656a974faSSam Ravnborg 		return 1;
176756a974faSSam Ravnborg 	}
176856a974faSSam Ravnborg 	return 0;
176956a974faSSam Ravnborg }
177056a974faSSam Ravnborg 
17715b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1772ae4ac123SAtsushi Nemoto {
1773ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17745b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1775ae4ac123SAtsushi Nemoto 	unsigned int inst;
1776ae4ac123SAtsushi Nemoto 
1777ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1778ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1779ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1780ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1781ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1782ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1783ae4ac123SAtsushi Nemoto 		break;
1784ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1785ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1786ae4ac123SAtsushi Nemoto 		break;
1787ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1788ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1789ae4ac123SAtsushi Nemoto 		break;
1790ae4ac123SAtsushi Nemoto 	}
1791ae4ac123SAtsushi Nemoto 	return 0;
1792ae4ac123SAtsushi Nemoto }
1793ae4ac123SAtsushi Nemoto 
17945b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
179510668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1796b39927cfSSam Ravnborg {
1797b39927cfSSam Ravnborg 	Elf_Sym  *sym;
17985b24c071SSam Ravnborg 	Elf_Rela *rela;
17992c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1800eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18015b24c071SSam Ravnborg 	const char *fromsec;
18025b24c071SSam Ravnborg 
1803ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18045b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18055b24c071SSam Ravnborg 
1806ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18075b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18085b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1809b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18105b24c071SSam Ravnborg 		return;
1811e241a630SSam Ravnborg 
1812b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1813b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1814eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1815ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1816ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1817eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1818eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1819ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1820ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1821eae07ac6SAtsushi Nemoto 		} else {
1822601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1823eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1824eae07ac6SAtsushi Nemoto 		}
1825eae07ac6SAtsushi Nemoto #else
1826eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1827eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1828eae07ac6SAtsushi Nemoto #endif
182993684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1830eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1831b39927cfSSam Ravnborg 		/* Skip special sections */
18321ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1833b39927cfSSam Ravnborg 			continue;
1834e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1835e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
183658fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18372c1a51f3SAtsushi Nemoto 	}
18385b24c071SSam Ravnborg }
18395b24c071SSam Ravnborg 
18405b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
184110668220SSam Ravnborg 			Elf_Shdr *sechdr)
18425b24c071SSam Ravnborg {
18435b24c071SSam Ravnborg 	Elf_Sym *sym;
18442c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
18455b24c071SSam Ravnborg 	Elf_Rela r;
18465b24c071SSam Ravnborg 	unsigned int r_sym;
18475b24c071SSam Ravnborg 	const char *fromsec;
18485b24c071SSam Ravnborg 
1849ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
18505b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
18515b24c071SSam Ravnborg 
1852ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18535b24c071SSam Ravnborg 	fromsec += strlen(".rel");
18545b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1855b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18565b24c071SSam Ravnborg 		return;
18572c1a51f3SAtsushi Nemoto 
18582c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
18592c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1860eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1861ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1862ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1863eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1864eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1865ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1866ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1867eae07ac6SAtsushi Nemoto 		} else {
18682c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1869eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1870eae07ac6SAtsushi Nemoto 		}
1871eae07ac6SAtsushi Nemoto #else
1872eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1873eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1874eae07ac6SAtsushi Nemoto #endif
18752c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1876ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1877ae4ac123SAtsushi Nemoto 		case EM_386:
18785b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1879ae4ac123SAtsushi Nemoto 				continue;
1880ae4ac123SAtsushi Nemoto 			break;
188156a974faSSam Ravnborg 		case EM_ARM:
18825b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
188356a974faSSam Ravnborg 				continue;
188456a974faSSam Ravnborg 			break;
1885ae4ac123SAtsushi Nemoto 		case EM_MIPS:
18865b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1887ae4ac123SAtsushi Nemoto 				continue;
1888ae4ac123SAtsushi Nemoto 			break;
1889ae4ac123SAtsushi Nemoto 		}
1890eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
18912c1a51f3SAtsushi Nemoto 		/* Skip special sections */
18921ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
18932c1a51f3SAtsushi Nemoto 			continue;
1894e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1895e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
189658fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18972c1a51f3SAtsushi Nemoto 	}
1898b39927cfSSam Ravnborg }
18995b24c071SSam Ravnborg 
19005b24c071SSam Ravnborg /**
19015b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19025b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19035b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1904b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19055b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19065b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
190732be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19085b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19095b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19105b24c071SSam Ravnborg  * be discarded and warns about it.
19115b24c071SSam Ravnborg  **/
19125b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
191310668220SSam Ravnborg 			  struct elf_info *elf)
19145b24c071SSam Ravnborg {
19155b24c071SSam Ravnborg 	int i;
19165b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19175b24c071SSam Ravnborg 
19185b24c071SSam Ravnborg 	/* Walk through all sections */
19191ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1920b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19215b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19225b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
192310668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19245b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
192510668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1926b39927cfSSam Ravnborg 	}
1927b39927cfSSam Ravnborg }
1928b39927cfSSam Ravnborg 
19297d02b490SAndi Kleen static char *remove_dot(char *s)
19307d02b490SAndi Kleen {
1931fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19327d02b490SAndi Kleen 
1933fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1934fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1935fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
19367d02b490SAndi Kleen 			s[n] = 0;
19377d02b490SAndi Kleen 	}
19387d02b490SAndi Kleen 	return s;
19397d02b490SAndi Kleen }
19407d02b490SAndi Kleen 
19418b185743SMasahiro Yamada static void read_symbols(const char *modname)
19421da177e4SLinus Torvalds {
19431da177e4SLinus Torvalds 	const char *symname;
19441da177e4SLinus Torvalds 	char *version;
1945b817f6feSSam Ravnborg 	char *license;
19461da177e4SLinus Torvalds 	struct module *mod;
19471da177e4SLinus Torvalds 	struct elf_info info = { };
19481da177e4SLinus Torvalds 	Elf_Sym *sym;
19491da177e4SLinus Torvalds 
195085bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
195185bd2fddSSam Ravnborg 		return;
19521da177e4SLinus Torvalds 
19531da177e4SLinus Torvalds 	mod = new_module(modname);
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
19561da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
19571da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
19581da177e4SLinus Torvalds 		have_vmlinux = 1;
19591da177e4SLinus Torvalds 		mod->skip = 1;
19601da177e4SLinus Torvalds 	}
19611da177e4SLinus Torvalds 
1962bca2cceeSMasahiro Yamada 	license = get_modinfo(&info, "license");
1963ba1029c9SRandy Dunlap 	if (!license && !is_vmlinux(modname))
19642fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
1965eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
1966eed7d279SSam Ravnborg 		     "more information\n", modname);
1967b817f6feSSam Ravnborg 	while (license) {
1968b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
1969b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
1970b817f6feSSam Ravnborg 		else {
1971b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
1972b817f6feSSam Ravnborg 			break;
1973b817f6feSSam Ravnborg 		}
1974bca2cceeSMasahiro Yamada 		license = get_next_modinfo(&info, "license", license);
1975b817f6feSSam Ravnborg 	}
1976b817f6feSSam Ravnborg 
19771da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
19787d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
19791da177e4SLinus Torvalds 
19801da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
19811da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
19821da177e4SLinus Torvalds 	}
1983074a04f5SMasahiro Yamada 	if (!is_vmlinux(modname) || vmlinux_section_warnings)
198410668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
19851da177e4SLinus Torvalds 
1986bca2cceeSMasahiro Yamada 	version = get_modinfo(&info, "version");
19871da177e4SLinus Torvalds 	if (version)
19881da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
19891da177e4SLinus Torvalds 				       version - (char *)info.hdr);
19901da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
19911da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
19921da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 	parse_elf_finish(&info);
19951da177e4SLinus Torvalds 
19968c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
19971da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
19981da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
19991da177e4SLinus Torvalds 	 * important anyhow */
20001da177e4SLinus Torvalds 	if (modversions)
20018c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
20021da177e4SLinus Torvalds }
20031da177e4SLinus Torvalds 
2004712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2005712f9b46SRusty Russell {
2006712f9b46SRusty Russell 	FILE *in = stdin;
2007712f9b46SRusty Russell 	char fname[PATH_MAX];
2008712f9b46SRusty Russell 
2009712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2010712f9b46SRusty Russell 		in = fopen(filename, "r");
2011712f9b46SRusty Russell 		if (!in)
2012712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2013712f9b46SRusty Russell 	}
2014712f9b46SRusty Russell 
2015712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2016712f9b46SRusty Russell 		if (strends(fname, "\n"))
2017712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2018712f9b46SRusty Russell 		read_symbols(fname);
2019712f9b46SRusty Russell 	}
2020712f9b46SRusty Russell 
2021712f9b46SRusty Russell 	if (in != stdin)
2022712f9b46SRusty Russell 		fclose(in);
2023712f9b46SRusty Russell }
2024712f9b46SRusty Russell 
20251da177e4SLinus Torvalds #define SZ 500
20261da177e4SLinus Torvalds 
20271da177e4SLinus Torvalds /* We first write the generated file into memory using the
20281da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
20291da177e4SLinus Torvalds  * only update the later if anything changed */
20301da177e4SLinus Torvalds 
20315c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
20325c3ead8cSSam Ravnborg 						      const char *fmt, ...)
20331da177e4SLinus Torvalds {
20341da177e4SLinus Torvalds 	char tmp[SZ];
20351da177e4SLinus Torvalds 	int len;
20361da177e4SLinus Torvalds 	va_list ap;
20371da177e4SLinus Torvalds 
20381da177e4SLinus Torvalds 	va_start(ap, fmt);
20391da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
20407670f023SSam Ravnborg 	buf_write(buf, tmp, len);
20411da177e4SLinus Torvalds 	va_end(ap);
20421da177e4SLinus Torvalds }
20431da177e4SLinus Torvalds 
20445c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
20451da177e4SLinus Torvalds {
20461da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
20477670f023SSam Ravnborg 		buf->size += len + SZ;
20481f3aa900SRandy Dunlap 		buf->p = NOFAIL(realloc(buf->p, buf->size));
20491da177e4SLinus Torvalds 	}
20501da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
20511da177e4SLinus Torvalds 	buf->pos += len;
20521da177e4SLinus Torvalds }
20531da177e4SLinus Torvalds 
2054c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2055c96fca21SSam Ravnborg {
2056c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2057c96fca21SSam Ravnborg 
2058c96fca21SSam Ravnborg 	switch (exp) {
2059c96fca21SSam Ravnborg 	case export_gpl:
2060c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2061c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2062c96fca21SSam Ravnborg 		break;
2063c96fca21SSam Ravnborg 	case export_unused_gpl:
2064c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2065c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2066c96fca21SSam Ravnborg 		break;
2067c96fca21SSam Ravnborg 	case export_gpl_future:
2068c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2069c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2070c96fca21SSam Ravnborg 		break;
2071c96fca21SSam Ravnborg 	case export_plain:
2072c96fca21SSam Ravnborg 	case export_unused:
2073c96fca21SSam Ravnborg 	case export_unknown:
2074c96fca21SSam Ravnborg 		/* ignore */
2075c96fca21SSam Ravnborg 		break;
2076c96fca21SSam Ravnborg 	}
2077c96fca21SSam Ravnborg }
2078c96fca21SSam Ravnborg 
2079c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2080c96fca21SSam Ravnborg {
2081c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2082c96fca21SSam Ravnborg 
2083c96fca21SSam Ravnborg 	switch (exp) {
2084c96fca21SSam Ravnborg 	case export_unused:
2085c96fca21SSam Ravnborg 	case export_unused_gpl:
2086c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2087c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2088c96fca21SSam Ravnborg 		break;
2089c96fca21SSam Ravnborg 	default:
2090c96fca21SSam Ravnborg 		/* ignore */
2091c96fca21SSam Ravnborg 		break;
2092c96fca21SSam Ravnborg 	}
2093c96fca21SSam Ravnborg }
2094c96fca21SSam Ravnborg 
20953b415288SMasahiro Yamada static int check_exports(struct module *mod)
2096b817f6feSSam Ravnborg {
2097b817f6feSSam Ravnborg 	struct symbol *s, *exp;
20983b415288SMasahiro Yamada 	int err = 0;
2099b817f6feSSam Ravnborg 
2100b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21016449bd62SAndrew Morton 		const char *basename;
2102b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
21033b415288SMasahiro Yamada 		if (!exp || exp->module == mod) {
21043b415288SMasahiro Yamada 			if (have_vmlinux && !s->weak) {
21053b415288SMasahiro Yamada 				if (warn_unresolved) {
21063b415288SMasahiro Yamada 					warn("\"%s\" [%s.ko] undefined!\n",
21073b415288SMasahiro Yamada 					     s->name, mod->name);
21083b415288SMasahiro Yamada 				} else {
21093b415288SMasahiro Yamada 					merror("\"%s\" [%s.ko] undefined!\n",
21103b415288SMasahiro Yamada 					       s->name, mod->name);
21113b415288SMasahiro Yamada 					err = 1;
21123b415288SMasahiro Yamada 				}
21133b415288SMasahiro Yamada 			}
2114b817f6feSSam Ravnborg 			continue;
21153b415288SMasahiro Yamada 		}
21166449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2117b817f6feSSam Ravnborg 		if (basename)
2118b817f6feSSam Ravnborg 			basename++;
2119c96fca21SSam Ravnborg 		else
2120c96fca21SSam Ravnborg 			basename = mod->name;
2121c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2122c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2123c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2124b817f6feSSam Ravnborg 	}
21253b415288SMasahiro Yamada 
21263b415288SMasahiro Yamada 	return err;
2127b817f6feSSam Ravnborg }
2128b817f6feSSam Ravnborg 
21294fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
21304fd3e4efSWanlong Gao {
21314fd3e4efSWanlong Gao 	const char *mod_name;
21324fd3e4efSWanlong Gao 
21334fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
21344fd3e4efSWanlong Gao 	if (mod_name == NULL)
21354fd3e4efSWanlong Gao 		mod_name = mod->name;
21364fd3e4efSWanlong Gao 	else
21374fd3e4efSWanlong Gao 		mod_name++;
21384fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
21394fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
21404fd3e4efSWanlong Gao 		return 1;
21414fd3e4efSWanlong Gao 	}
21424fd3e4efSWanlong Gao 
21434fd3e4efSWanlong Gao 	return 0;
21444fd3e4efSWanlong Gao }
21454fd3e4efSWanlong Gao 
21465c3ead8cSSam Ravnborg /**
21475c3ead8cSSam Ravnborg  * Header for the generated file
21485c3ead8cSSam Ravnborg  **/
21495c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
21501da177e4SLinus Torvalds {
21519afb719eSLaura Abbott 	buf_printf(b, "#include <linux/build-salt.h>\n");
21521da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
21531da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
21541da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
21551da177e4SLinus Torvalds 	buf_printf(b, "\n");
21569afb719eSLaura Abbott 	buf_printf(b, "BUILD_SALT;\n");
21579afb719eSLaura Abbott 	buf_printf(b, "\n");
21581da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
21593e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
21601da177e4SLinus Torvalds 	buf_printf(b, "\n");
2161e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
21621da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
21633c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
21641da177e4SLinus Torvalds 	if (mod->has_init)
21653c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
21661da177e4SLinus Torvalds 	if (mod->has_cleanup)
21671da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
21683c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
21691da177e4SLinus Torvalds 			      "#endif\n");
21703c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
21711da177e4SLinus Torvalds 	buf_printf(b, "};\n");
21721da177e4SLinus Torvalds }
21731da177e4SLinus Torvalds 
21742449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
21752449b8baSBen Hutchings {
21762449b8baSBen Hutchings 	if (is_intree)
21772449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
21782449b8baSBen Hutchings }
21792449b8baSBen Hutchings 
2180caf7501aSAndi Kleen /* Cannot check for assembler */
2181caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2182caf7501aSAndi Kleen {
2183e4f35891SWANG Chao 	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
2184caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2185caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2186caf7501aSAndi Kleen }
2187caf7501aSAndi Kleen 
21885c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2189a9860bf0SGreg Kroah-Hartman {
2190d62c4765SMasahiro Yamada 	if (strstarts(name, "drivers/staging"))
2191a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2192a9860bf0SGreg Kroah-Hartman }
2193a9860bf0SGreg Kroah-Hartman 
21945c3ead8cSSam Ravnborg /**
21955c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
21965c3ead8cSSam Ravnborg  **/
2197c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
21981da177e4SLinus Torvalds {
21991da177e4SLinus Torvalds 	struct symbol *s, *exp;
2200c53ddacdSKirill Korotaev 	int err = 0;
22011da177e4SLinus Torvalds 
22021da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
22031da177e4SLinus Torvalds 		exp = find_symbol(s->name);
22043b415288SMasahiro Yamada 		if (!exp || exp->module == mod)
22051da177e4SLinus Torvalds 			continue;
22061da177e4SLinus Torvalds 		s->module = exp->module;
22071da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
22081da177e4SLinus Torvalds 		s->crc = exp->crc;
22091da177e4SLinus Torvalds 	}
22101da177e4SLinus Torvalds 
22111da177e4SLinus Torvalds 	if (!modversions)
2212c53ddacdSKirill Korotaev 		return err;
22131da177e4SLinus Torvalds 
22141da177e4SLinus Torvalds 	buf_printf(b, "\n");
22151da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
22163ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22171da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
22181da177e4SLinus Torvalds 
22191da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2220df578e7dSSam Ravnborg 		if (!s->module)
22211da177e4SLinus Torvalds 			continue;
22221da177e4SLinus Torvalds 		if (!s->crc_valid) {
2223cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
22241da177e4SLinus Torvalds 				s->name, mod->name);
22251da177e4SLinus Torvalds 			continue;
22261da177e4SLinus Torvalds 		}
22275cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
22285cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
22295cfb203aSTakashi Iwai 			       s->name, mod->name);
22305cfb203aSTakashi Iwai 			err = 1;
22315cfb203aSTakashi Iwai 			break;
22325cfb203aSTakashi Iwai 		}
2233b2c5cdcfSMasahiro Yamada 		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
2234a4b6a77bSJames Hogan 			   s->crc, s->name);
22351da177e4SLinus Torvalds 	}
22361da177e4SLinus Torvalds 
22371da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2238c53ddacdSKirill Korotaev 
2239c53ddacdSKirill Korotaev 	return err;
22401da177e4SLinus Torvalds }
22411da177e4SLinus Torvalds 
2242d2665ca8SMasahiro Yamada static void add_depends(struct buffer *b, struct module *mod)
22431da177e4SLinus Torvalds {
22441da177e4SLinus Torvalds 	struct symbol *s;
22451da177e4SLinus Torvalds 	int first = 1;
22461da177e4SLinus Torvalds 
2247d2665ca8SMasahiro Yamada 	/* Clear ->seen flag of modules that own symbols needed by this. */
2248d2665ca8SMasahiro Yamada 	for (s = mod->unres; s; s = s->next)
2249d2665ca8SMasahiro Yamada 		if (s->module)
2250d2665ca8SMasahiro Yamada 			s->module->seen = is_vmlinux(s->module->name);
22511da177e4SLinus Torvalds 
22521da177e4SLinus Torvalds 	buf_printf(b, "\n");
22531da177e4SLinus Torvalds 	buf_printf(b, "static const char __module_depends[]\n");
22543ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22551da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
22561da177e4SLinus Torvalds 	buf_printf(b, "\"depends=");
22571da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2258a61b2dfdSSam Ravnborg 		const char *p;
22591da177e4SLinus Torvalds 		if (!s->module)
22601da177e4SLinus Torvalds 			continue;
22611da177e4SLinus Torvalds 
22621da177e4SLinus Torvalds 		if (s->module->seen)
22631da177e4SLinus Torvalds 			continue;
22641da177e4SLinus Torvalds 
22651da177e4SLinus Torvalds 		s->module->seen = 1;
2266df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2267df578e7dSSam Ravnborg 		if (p)
2268a61b2dfdSSam Ravnborg 			p++;
2269a61b2dfdSSam Ravnborg 		else
2270a61b2dfdSSam Ravnborg 			p = s->module->name;
2271a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
22721da177e4SLinus Torvalds 		first = 0;
22731da177e4SLinus Torvalds 	}
22741da177e4SLinus Torvalds 	buf_printf(b, "\";\n");
22751da177e4SLinus Torvalds }
22761da177e4SLinus Torvalds 
22775c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
22781da177e4SLinus Torvalds {
22791da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
22801da177e4SLinus Torvalds 		buf_printf(b, "\n");
22811da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
22821da177e4SLinus Torvalds 			   mod->srcversion);
22831da177e4SLinus Torvalds 	}
22841da177e4SLinus Torvalds }
22851da177e4SLinus Torvalds 
22865c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
22871da177e4SLinus Torvalds {
22881da177e4SLinus Torvalds 	char *tmp;
22891da177e4SLinus Torvalds 	FILE *file;
22901da177e4SLinus Torvalds 	struct stat st;
22911da177e4SLinus Torvalds 
22921da177e4SLinus Torvalds 	file = fopen(fname, "r");
22931da177e4SLinus Torvalds 	if (!file)
22941da177e4SLinus Torvalds 		goto write;
22951da177e4SLinus Torvalds 
22961da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
22971da177e4SLinus Torvalds 		goto close_write;
22981da177e4SLinus Torvalds 
22991da177e4SLinus Torvalds 	if (st.st_size != b->pos)
23001da177e4SLinus Torvalds 		goto close_write;
23011da177e4SLinus Torvalds 
23021da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
23031da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
23041da177e4SLinus Torvalds 		goto free_write;
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
23071da177e4SLinus Torvalds 		goto free_write;
23081da177e4SLinus Torvalds 
23091da177e4SLinus Torvalds 	free(tmp);
23101da177e4SLinus Torvalds 	fclose(file);
23111da177e4SLinus Torvalds 	return;
23121da177e4SLinus Torvalds 
23131da177e4SLinus Torvalds  free_write:
23141da177e4SLinus Torvalds 	free(tmp);
23151da177e4SLinus Torvalds  close_write:
23161da177e4SLinus Torvalds 	fclose(file);
23171da177e4SLinus Torvalds  write:
23181da177e4SLinus Torvalds 	file = fopen(fname, "w");
23191da177e4SLinus Torvalds 	if (!file) {
23201da177e4SLinus Torvalds 		perror(fname);
23211da177e4SLinus Torvalds 		exit(1);
23221da177e4SLinus Torvalds 	}
23231da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
23241da177e4SLinus Torvalds 		perror(fname);
23251da177e4SLinus Torvalds 		exit(1);
23261da177e4SLinus Torvalds 	}
23271da177e4SLinus Torvalds 	fclose(file);
23281da177e4SLinus Torvalds }
23291da177e4SLinus Torvalds 
2330bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2331534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2332bd5cbcedSRam Pai  **/
2333040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
23341da177e4SLinus Torvalds {
23351da177e4SLinus Torvalds 	unsigned long size, pos = 0;
23361da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
23371da177e4SLinus Torvalds 	char *line;
23381da177e4SLinus Torvalds 
23391da177e4SLinus Torvalds 	if (!file)
23401da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
23411da177e4SLinus Torvalds 		return;
23421da177e4SLinus Torvalds 
23431da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2344534b89a9SSam Ravnborg 		char *symname, *modname, *d, *export, *end;
23451da177e4SLinus Torvalds 		unsigned int crc;
23461da177e4SLinus Torvalds 		struct module *mod;
2347040fcc81SSam Ravnborg 		struct symbol *s;
23481da177e4SLinus Torvalds 
23491da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
23501da177e4SLinus Torvalds 			goto fail;
23511da177e4SLinus Torvalds 		*symname++ = '\0';
23521da177e4SLinus Torvalds 		if (!(modname = strchr(symname, '\t')))
23531da177e4SLinus Torvalds 			goto fail;
23541da177e4SLinus Torvalds 		*modname++ = '\0';
23559ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2356bd5cbcedSRam Pai 			*export++ = '\0';
2357534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2358534b89a9SSam Ravnborg 			*end = '\0';
23591da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
23601da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
23611da177e4SLinus Torvalds 			goto fail;
2362df578e7dSSam Ravnborg 		mod = find_module(modname);
2363df578e7dSSam Ravnborg 		if (!mod) {
2364df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
23651da177e4SLinus Torvalds 				have_vmlinux = 1;
23660fa3a88cSJan Beulich 			mod = new_module(modname);
23671da177e4SLinus Torvalds 			mod->skip = 1;
23681da177e4SLinus Torvalds 		}
2369bd5cbcedSRam Pai 		s = sym_add_exported(symname, mod, export_no(export));
2370040fcc81SSam Ravnborg 		s->kernel    = kernel;
23718e70c458SSam Ravnborg 		s->preloaded = 1;
2372bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
23731da177e4SLinus Torvalds 	}
23742ee41e62SChristian Engelmayer 	release_file(file, size);
23751da177e4SLinus Torvalds 	return;
23761da177e4SLinus Torvalds fail:
23772ee41e62SChristian Engelmayer 	release_file(file, size);
23781da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
23791da177e4SLinus Torvalds }
23801da177e4SLinus Torvalds 
2381040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2382040fcc81SSam Ravnborg  * For external modules only dump symbols
2383040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2384040fcc81SSam Ravnborg  **/
2385040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2386040fcc81SSam Ravnborg {
2387040fcc81SSam Ravnborg 	if (!external_module)
2388040fcc81SSam Ravnborg 		return 1;
2389040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2390040fcc81SSam Ravnborg 		return 0;
2391040fcc81SSam Ravnborg 	return 1;
2392040fcc81SSam Ravnborg }
2393040fcc81SSam Ravnborg 
23945c3ead8cSSam Ravnborg static void write_dump(const char *fname)
23951da177e4SLinus Torvalds {
23961da177e4SLinus Torvalds 	struct buffer buf = { };
23971da177e4SLinus Torvalds 	struct symbol *symbol;
23981da177e4SLinus Torvalds 	int n;
23991da177e4SLinus Torvalds 
24001da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
24011da177e4SLinus Torvalds 		symbol = symbolhash[n];
24021da177e4SLinus Torvalds 		while (symbol) {
2403040fcc81SSam Ravnborg 			if (dump_sym(symbol))
2404bd5cbcedSRam Pai 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
2405040fcc81SSam Ravnborg 					symbol->crc, symbol->name,
2406bd5cbcedSRam Pai 					symbol->module->name,
2407bd5cbcedSRam Pai 					export_str(symbol->export));
24081da177e4SLinus Torvalds 			symbol = symbol->next;
24091da177e4SLinus Torvalds 		}
24101da177e4SLinus Torvalds 	}
24111da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2412c7d47f26SHeinrich Schuchardt 	free(buf.p);
24131da177e4SLinus Torvalds }
24141da177e4SLinus Torvalds 
24152d04b5aeSRichard Hacker struct ext_sym_list {
24162d04b5aeSRichard Hacker 	struct ext_sym_list *next;
24172d04b5aeSRichard Hacker 	const char *file;
24182d04b5aeSRichard Hacker };
24192d04b5aeSRichard Hacker 
24205c3ead8cSSam Ravnborg int main(int argc, char **argv)
24211da177e4SLinus Torvalds {
24221da177e4SLinus Torvalds 	struct module *mod;
24231da177e4SLinus Torvalds 	struct buffer buf = { };
2424040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2425712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
24261da177e4SLinus Torvalds 	int opt;
2427c53ddacdSKirill Korotaev 	int err;
24282d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
24292d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
24301da177e4SLinus Torvalds 
2431*46c7dd56SMasahiro Yamada 	while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awE")) != -1) {
24321da177e4SLinus Torvalds 		switch (opt) {
24331da177e4SLinus Torvalds 		case 'i':
2434040fcc81SSam Ravnborg 			kernel_read = optarg;
2435040fcc81SSam Ravnborg 			break;
2436040fcc81SSam Ravnborg 		case 'I':
2437040fcc81SSam Ravnborg 			module_read = optarg;
2438040fcc81SSam Ravnborg 			external_module = 1;
24391da177e4SLinus Torvalds 			break;
24402d04b5aeSRichard Hacker 		case 'e':
24412d04b5aeSRichard Hacker 			external_module = 1;
24422d04b5aeSRichard Hacker 			extsym_iter =
24432d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
24442d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
24452d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
24462d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
24472d04b5aeSRichard Hacker 			break;
24481da177e4SLinus Torvalds 		case 'm':
24491da177e4SLinus Torvalds 			modversions = 1;
24501da177e4SLinus Torvalds 			break;
2451eed380f3SGuenter Roeck 		case 'n':
2452eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2453eed380f3SGuenter Roeck 			break;
24541da177e4SLinus Torvalds 		case 'o':
24551da177e4SLinus Torvalds 			dump_write = optarg;
24561da177e4SLinus Torvalds 			break;
24571da177e4SLinus Torvalds 		case 'a':
24581da177e4SLinus Torvalds 			all_versions = 1;
24591da177e4SLinus Torvalds 			break;
24608d8d8289SSam Ravnborg 		case 's':
24618d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
24628d8d8289SSam Ravnborg 			break;
2463712f9b46SRusty Russell 		case 'T':
2464712f9b46SRusty Russell 			files_source = optarg;
2465712f9b46SRusty Russell 			break;
2466c53ddacdSKirill Korotaev 		case 'w':
2467c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2468c53ddacdSKirill Korotaev 			break;
246947490ec1SNicolas Boichat 		case 'E':
247047490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
247147490ec1SNicolas Boichat 			break;
24721da177e4SLinus Torvalds 		default:
24731da177e4SLinus Torvalds 			exit(1);
24741da177e4SLinus Torvalds 		}
24751da177e4SLinus Torvalds 	}
24761da177e4SLinus Torvalds 
2477040fcc81SSam Ravnborg 	if (kernel_read)
2478040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2479040fcc81SSam Ravnborg 	if (module_read)
2480040fcc81SSam Ravnborg 		read_dump(module_read, 0);
24812d04b5aeSRichard Hacker 	while (extsym_start) {
24822d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
24832d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
24842d04b5aeSRichard Hacker 		free(extsym_start);
24852d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
24862d04b5aeSRichard Hacker 	}
24871da177e4SLinus Torvalds 
2488df578e7dSSam Ravnborg 	while (optind < argc)
24891da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
24901da177e4SLinus Torvalds 
2491712f9b46SRusty Russell 	if (files_source)
2492712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2493712f9b46SRusty Russell 
2494c53ddacdSKirill Korotaev 	err = 0;
2495c53ddacdSKirill Korotaev 
2496b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2497d93e1719SMathias Krause 		char fname[PATH_MAX];
2498666ab414SAndi Kleen 
2499b817f6feSSam Ravnborg 		if (mod->skip)
2500b817f6feSSam Ravnborg 			continue;
25011da177e4SLinus Torvalds 
25021da177e4SLinus Torvalds 		buf.pos = 0;
25031da177e4SLinus Torvalds 
25044fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
25053b415288SMasahiro Yamada 		err |= check_exports(mod);
25061da177e4SLinus Torvalds 		add_header(&buf, mod);
25072449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2508caf7501aSAndi Kleen 		add_retpoline(&buf);
2509a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2510c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
2511d2665ca8SMasahiro Yamada 		add_depends(&buf, mod);
25121da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
25131da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
25141da177e4SLinus Torvalds 
25151da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
25161da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
25171da177e4SLinus Torvalds 	}
25181da177e4SLinus Torvalds 	if (dump_write)
25191da177e4SLinus Torvalds 		write_dump(dump_write);
2520*46c7dd56SMasahiro Yamada 	if (sec_mismatch_count && sec_mismatch_fatal)
252147490ec1SNicolas Boichat 		fatal("modpost: Section mismatches detected.\n"
252247490ec1SNicolas Boichat 		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
2523c7d47f26SHeinrich Schuchardt 	free(buf.p);
25241da177e4SLinus Torvalds 
2525c53ddacdSKirill Korotaev 	return err;
25261da177e4SLinus Torvalds }
2527