xref: /linux-6.15/scripts/mod/modpost.c (revision e4f35891)
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;
38588ccd73SSam Ravnborg static int sec_mismatch_verbose = 1;
3947490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
40eed380f3SGuenter Roeck /* ignore missing files */
41eed380f3SGuenter Roeck static int ignore_missing_files;
42588ccd73SSam Ravnborg 
43c96fca21SSam Ravnborg enum export {
44c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
45c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
46c96fca21SSam Ravnborg };
471da177e4SLinus Torvalds 
484fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h;
494fd3e4efSWanlong Gao  * here we use Elf_Addr instead of long for covering cross-compile
504fd3e4efSWanlong Gao  */
514fd3e4efSWanlong Gao 
524fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
534fd3e4efSWanlong Gao 
546d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
556d9a89eaSAndi Kleen 
566d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	va_list arglist;
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	va_start(arglist, fmt);
631da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
641da177e4SLinus Torvalds 	va_end(arglist);
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	exit(1);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
696d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	va_list arglist;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	va_start(arglist, fmt);
761da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
771da177e4SLinus Torvalds 	va_end(arglist);
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
806d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
812a116659SMatthew Wilcox {
822a116659SMatthew Wilcox 	va_list arglist;
832a116659SMatthew Wilcox 
842a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
852a116659SMatthew Wilcox 
862a116659SMatthew Wilcox 	va_start(arglist, fmt);
872a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
882a116659SMatthew Wilcox 	va_end(arglist);
892a116659SMatthew Wilcox }
902a116659SMatthew Wilcox 
91d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
92d4ef1c30SRusty Russell {
93d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
94d4ef1c30SRusty Russell 		return false;
95d4ef1c30SRusty Russell 
96d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
97d4ef1c30SRusty Russell }
98d4ef1c30SRusty Russell 
99040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
100040fcc81SSam Ravnborg {
101040fcc81SSam Ravnborg 	const char *myname;
102040fcc81SSam Ravnborg 
103df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
104df578e7dSSam Ravnborg 	if (myname)
105040fcc81SSam Ravnborg 		myname++;
106040fcc81SSam Ravnborg 	else
107040fcc81SSam Ravnborg 		myname = modname;
108040fcc81SSam Ravnborg 
109741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
110741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
111040fcc81SSam Ravnborg }
112040fcc81SSam Ravnborg 
1131da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1141da177e4SLinus Torvalds {
115df578e7dSSam Ravnborg 	if (!ptr)
1161da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
117df578e7dSSam Ravnborg 
1181da177e4SLinus Torvalds 	return ptr;
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds /* A list of all modules we processed */
1221da177e4SLinus Torvalds static struct module *modules;
1231da177e4SLinus Torvalds 
1248b185743SMasahiro Yamada static struct module *find_module(const char *modname)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	struct module *mod;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1291da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1301da177e4SLinus Torvalds 			break;
1311da177e4SLinus Torvalds 	return mod;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds 
134d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds 	struct module *mod;
137d4ef1c30SRusty Russell 	char *p;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1401da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1411da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	/* strip trailing .o */
144d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
145d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
146258f7426SFrank Rowand 		mod->is_dot_o = 1;
147258f7426SFrank Rowand 	}
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 	/* add to list */
1501da177e4SLinus Torvalds 	mod->name = p;
151b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1521da177e4SLinus Torvalds 	mod->next = modules;
1531da177e4SLinus Torvalds 	modules = mod;
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 	return mod;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds /* A hash of all exported symbols,
1591da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds struct symbol {
1641da177e4SLinus Torvalds 	struct symbol *next;
1651da177e4SLinus Torvalds 	struct module *module;
1661da177e4SLinus Torvalds 	unsigned int crc;
1671da177e4SLinus Torvalds 	int crc_valid;
1681da177e4SLinus Torvalds 	unsigned int weak:1;
169040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
170040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
171040fcc81SSam Ravnborg 				    *  (only for external modules) **/
172b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
173bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1741da177e4SLinus Torvalds 	char name[0];
1751da177e4SLinus Torvalds };
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1801da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1831da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1861da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1871da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1901da177e4SLinus Torvalds }
1911da177e4SLinus Torvalds 
1925c3ead8cSSam Ravnborg /**
1935c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1945c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1955c3ead8cSSam Ravnborg  **/
1965c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1975c3ead8cSSam Ravnborg 				   struct symbol *next)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
2021da177e4SLinus Torvalds 	strcpy(s->name, name);
2031da177e4SLinus Torvalds 	s->weak = weak;
2041da177e4SLinus Torvalds 	s->next = next;
2051da177e4SLinus Torvalds 	return s;
2061da177e4SLinus Torvalds }
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds /* For the hash of exported symbols */
209bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
210bd5cbcedSRam Pai 				 enum export export)
2111da177e4SLinus Torvalds {
2121da177e4SLinus Torvalds 	unsigned int hash;
2131da177e4SLinus Torvalds 	struct symbol *new;
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2161da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2171da177e4SLinus Torvalds 	new->module = module;
218bd5cbcedSRam Pai 	new->export = export;
219040fcc81SSam Ravnborg 	return new;
2201da177e4SLinus Torvalds }
2211da177e4SLinus Torvalds 
2225c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2231da177e4SLinus Torvalds {
2241da177e4SLinus Torvalds 	struct symbol *s;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2271da177e4SLinus Torvalds 	if (name[0] == '.')
2281da177e4SLinus Torvalds 		name++;
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2311da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2321da177e4SLinus Torvalds 			return s;
2331da177e4SLinus Torvalds 	}
2341da177e4SLinus Torvalds 	return NULL;
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds 
2377a3ee753SMathias Krause static const struct {
238bd5cbcedSRam Pai 	const char *str;
239bd5cbcedSRam Pai 	enum export export;
240bd5cbcedSRam Pai } export_list[] = {
241bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
242c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
243bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
244c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
245bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
246bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
247bd5cbcedSRam Pai };
248bd5cbcedSRam Pai 
249bd5cbcedSRam Pai 
250bd5cbcedSRam Pai static const char *export_str(enum export ex)
251bd5cbcedSRam Pai {
252bd5cbcedSRam Pai 	return export_list[ex].str;
253bd5cbcedSRam Pai }
254bd5cbcedSRam Pai 
255bd5cbcedSRam Pai static enum export export_no(const char *s)
256bd5cbcedSRam Pai {
257bd5cbcedSRam Pai 	int i;
258df578e7dSSam Ravnborg 
259534b89a9SSam Ravnborg 	if (!s)
260534b89a9SSam Ravnborg 		return export_unknown;
261bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
262bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
263bd5cbcedSRam Pai 			return export_list[i].export;
264bd5cbcedSRam Pai 	}
265bd5cbcedSRam Pai 	return export_unknown;
266bd5cbcedSRam Pai }
267bd5cbcedSRam Pai 
2686124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
2696124c04cSMasahiro Yamada {
2706124c04cSMasahiro Yamada 	return (void *)elf->hdr +
2716124c04cSMasahiro Yamada 		elf->sechdrs[elf->secindex_strings].sh_offset +
2726124c04cSMasahiro Yamada 		sechdr->sh_name;
2736124c04cSMasahiro Yamada }
2746124c04cSMasahiro Yamada 
2756124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex)
2766124c04cSMasahiro Yamada {
2776124c04cSMasahiro Yamada 	return sech_name(elf, &elf->sechdrs[secindex]);
2786124c04cSMasahiro Yamada }
27962a26356SAlessio Igor Bogani 
28062a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
28162a26356SAlessio Igor Bogani 
28262a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
28362a26356SAlessio Igor Bogani {
28462a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
28562a26356SAlessio Igor Bogani 
28662a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
28762a26356SAlessio Igor Bogani 		return export_plain;
28862a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
28962a26356SAlessio Igor Bogani 		return export_unused;
29062a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
29162a26356SAlessio Igor Bogani 		return export_gpl;
29262a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
29362a26356SAlessio Igor Bogani 		return export_unused_gpl;
29462a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
29562a26356SAlessio Igor Bogani 		return export_gpl_future;
29662a26356SAlessio Igor Bogani 	else
29762a26356SAlessio Igor Bogani 		return export_unknown;
29862a26356SAlessio Igor Bogani }
29962a26356SAlessio Igor Bogani 
3001ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
301bd5cbcedSRam Pai {
302bd5cbcedSRam Pai 	if (sec == elf->export_sec)
303bd5cbcedSRam Pai 		return export_plain;
304c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
305c96fca21SSam Ravnborg 		return export_unused;
306bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
307bd5cbcedSRam Pai 		return export_gpl;
308c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
309c96fca21SSam Ravnborg 		return export_unused_gpl;
310bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
311bd5cbcedSRam Pai 		return export_gpl_future;
312bd5cbcedSRam Pai 	else
313bd5cbcedSRam Pai 		return export_unknown;
314bd5cbcedSRam Pai }
315bd5cbcedSRam Pai 
3165c3ead8cSSam Ravnborg /**
3175c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3185c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3195c3ead8cSSam Ravnborg  **/
320bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod,
321bd5cbcedSRam Pai 				       enum export export)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	if (!s) {
326bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3278e70c458SSam Ravnborg 	} else {
3288e70c458SSam Ravnborg 		if (!s->preloaded) {
3297b75b13cSSam Ravnborg 			warn("%s: '%s' exported twice. Previous export "
3308e70c458SSam Ravnborg 			     "was in %s%s\n", mod->name, name,
3318e70c458SSam Ravnborg 			     s->module->name,
3328e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ?"":".ko");
3334b21960fSTrent Piepho 		} else {
334baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3354b21960fSTrent Piepho 			s->module = mod;
3361da177e4SLinus Torvalds 		}
3371da177e4SLinus Torvalds 	}
3388e70c458SSam Ravnborg 	s->preloaded = 0;
339040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
340040fcc81SSam Ravnborg 	s->kernel    = 0;
341bd5cbcedSRam Pai 	s->export    = export;
342040fcc81SSam Ravnborg 	return s;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
345040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
346bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
347040fcc81SSam Ravnborg {
348040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
349040fcc81SSam Ravnborg 
350b6568b1aSRusty Russell 	if (!s) {
351bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
352b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
353b6568b1aSRusty Russell 		s->preloaded = 1;
354b6568b1aSRusty Russell 	}
355040fcc81SSam Ravnborg 	s->crc = crc;
3561da177e4SLinus Torvalds 	s->crc_valid = 1;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds 
3595c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
3601da177e4SLinus Torvalds {
3611da177e4SLinus Torvalds 	struct stat st;
362eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
3631da177e4SLinus Torvalds 	int fd;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
366eb3d5cc6SJesper Juhl 	if (fd < 0)
3671da177e4SLinus Torvalds 		return NULL;
368eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
369eb3d5cc6SJesper Juhl 		goto failed;
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	*size = st.st_size;
3721da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
3731da177e4SLinus Torvalds 
374eb3d5cc6SJesper Juhl failed:
375eb3d5cc6SJesper Juhl 	close(fd);
3761da177e4SLinus Torvalds 	if (map == MAP_FAILED)
3771da177e4SLinus Torvalds 		return NULL;
3781da177e4SLinus Torvalds 	return map;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds 
3815c3ead8cSSam Ravnborg /**
3825c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
3835c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
3845c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
3855c3ead8cSSam Ravnborg   **/
3865c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
3871da177e4SLinus Torvalds {
3881da177e4SLinus Torvalds 	static char line[4096];
3891da177e4SLinus Torvalds 	int skip = 1;
3901da177e4SLinus Torvalds 	size_t len = 0;
3911da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
3921da177e4SLinus Torvalds 	char *s = line;
3931da177e4SLinus Torvalds 
394df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
3951da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
3961da177e4SLinus Torvalds 			p++;
3971da177e4SLinus Torvalds 			continue;
3981da177e4SLinus Torvalds 		}
3991da177e4SLinus Torvalds 		skip = 0;
4001da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4011da177e4SLinus Torvalds 			len++;
4021da177e4SLinus Torvalds 			*s++ = *p++;
4031da177e4SLinus Torvalds 			if (len > 4095)
4041da177e4SLinus Torvalds 				break; /* Too long, stop */
4051da177e4SLinus Torvalds 		} else {
4061da177e4SLinus Torvalds 			/* End of string */
4071da177e4SLinus Torvalds 			*s = '\0';
4081da177e4SLinus Torvalds 			return line;
4091da177e4SLinus Torvalds 		}
4101da177e4SLinus Torvalds 	}
4111da177e4SLinus Torvalds 	/* End of buffer */
4121da177e4SLinus Torvalds 	return NULL;
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds 
4155c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4161da177e4SLinus Torvalds {
4171da177e4SLinus Torvalds 	munmap(file, size);
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds 
42085bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4211da177e4SLinus Torvalds {
4221da177e4SLinus Torvalds 	unsigned int i;
42385bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4241da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4251da177e4SLinus Torvalds 	Elf_Sym  *sym;
4261ce53adfSDenys Vlasenko 	const char *secstrings;
4271ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4301da177e4SLinus Torvalds 	if (!hdr) {
431eed380f3SGuenter Roeck 		if (ignore_missing_files) {
432eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
433eed380f3SGuenter Roeck 				strerror(errno));
434eed380f3SGuenter Roeck 			return 0;
435eed380f3SGuenter Roeck 		}
4361da177e4SLinus Torvalds 		perror(filename);
4376803dc0eSSam Ravnborg 		exit(1);
4381da177e4SLinus Torvalds 	}
4391da177e4SLinus Torvalds 	info->hdr = hdr;
44085bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
44185bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
44285bd2fddSSam Ravnborg 		return 0;
44385bd2fddSSam Ravnborg 	}
44485bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
44585bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
44685bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
44785bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
44885bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
44985bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
45085bd2fddSSam Ravnborg 		return 0;
45185bd2fddSSam Ravnborg 	}
4521da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
453ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
4547d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
4557d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
4567d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
4577d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
4587d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
4597d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
4607d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
4617d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
4627d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
4637d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
4647d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
4657d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
4661da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
4671da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
4681da177e4SLinus Torvalds 
469a83710e5SPetr Stetiar 	/* Check if file offset is correct */
470a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
471df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
472df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
473df578e7dSSam Ravnborg 		      filename, info->size);
474a83710e5SPetr Stetiar 		return 0;
475a83710e5SPetr Stetiar 	}
476a83710e5SPetr Stetiar 
4776845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
4781ce53adfSDenys Vlasenko 		/*
4791ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
4801ce53adfSDenys Vlasenko 		 * read count from .sh_size.
4811ce53adfSDenys Vlasenko 		 */
4821ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
4831ce53adfSDenys Vlasenko 	}
4841ce53adfSDenys Vlasenko 	else {
4851ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
4861ce53adfSDenys Vlasenko 	}
4871ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
4886845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
4891ce53adfSDenys Vlasenko 	}
4901ce53adfSDenys Vlasenko 	else {
4911ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
4921ce53adfSDenys Vlasenko 	}
4931ce53adfSDenys Vlasenko 
4941da177e4SLinus Torvalds 	/* Fix endianness in section headers */
4951ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
4967d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
4971da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
4987d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
4997d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5001da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5011da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5021da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
503ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5047d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5057d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5061da177e4SLinus Torvalds 	}
5071da177e4SLinus Torvalds 	/* Find symbol table. */
5081ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5091ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
510bd5cbcedSRam Pai 		const char *secname;
51156fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5121da177e4SLinus Torvalds 
51356fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
514df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
515df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
516df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
517df578e7dSSam Ravnborg 			      sizeof(*hdr));
51885bd2fddSSam Ravnborg 			return 0;
51985bd2fddSSam Ravnborg 		}
520bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
521bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
52256fc82c5STejun Heo 			if (nobits)
52356fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5241da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5251da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
526bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
527bd5cbcedSRam Pai 			info->export_sec = i;
528c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
529c96fca21SSam Ravnborg 			info->export_unused_sec = i;
530bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
531bd5cbcedSRam Pai 			info->export_gpl_sec = i;
532c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
533c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
534bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
535bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
536bd5cbcedSRam Pai 
5371ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5381ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
5391ce53adfSDenys Vlasenko 			symtab_idx = i;
5401ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
5411ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5421ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
5431ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5446845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
5451da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
5461ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
5471ce53adfSDenys Vlasenko 		}
5481ce53adfSDenys Vlasenko 
5491ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
5501ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
5511ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
5521ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
5531ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5541ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
5551ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5561ce53adfSDenys Vlasenko 		}
5571da177e4SLinus Torvalds 	}
558df578e7dSSam Ravnborg 	if (!info->symtab_start)
559cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
560df578e7dSSam Ravnborg 
5611da177e4SLinus Torvalds 	/* Fix endianness in symbols */
5621da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
5631da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
5641da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
5651da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
5661da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
5671da177e4SLinus Torvalds 	}
5681ce53adfSDenys Vlasenko 
5691ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
5701ce53adfSDenys Vlasenko 		Elf32_Word *p;
5716845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
5721ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
5736845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
5741ce53adfSDenys Vlasenko 			      symtab_idx);
5751ce53adfSDenys Vlasenko 		/* Fix endianness */
5761ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
5771ce53adfSDenys Vlasenko 		     p++)
5781ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
5791ce53adfSDenys Vlasenko 	}
5801ce53adfSDenys Vlasenko 
58185bd2fddSSam Ravnborg 	return 1;
5821da177e4SLinus Torvalds }
5831da177e4SLinus Torvalds 
5845c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
5851da177e4SLinus Torvalds {
5861da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
5871da177e4SLinus Torvalds }
5881da177e4SLinus Torvalds 
5894d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
5904d7365d6SSam Ravnborg {
5914d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
592b2c5cdcfSMasahiro Yamada 	if (strcmp(symname, "__this_module") == 0)
5934d7365d6SSam Ravnborg 		return 1;
5944d7365d6SSam Ravnborg 	/* ignore global offset table */
5954d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
5964d7365d6SSam Ravnborg 		return 1;
5974d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
5984d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
599d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr_") ||
600d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr_") ||
601d62c4765SMasahiro Yamada 		    strstarts(symname, "_rest32gpr_") ||
602d62c4765SMasahiro Yamada 		    strstarts(symname, "_save32gpr_") ||
603d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
604d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_"))
6054d7365d6SSam Ravnborg 			return 1;
6067fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6077fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
608d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr0_") ||
609d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr0_") ||
610d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
611d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_") ||
612c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6137fca5dc8SStephen Rothwell 			return 1;
6144d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6154d7365d6SSam Ravnborg 	return 0;
6164d7365d6SSam Ravnborg }
6174d7365d6SSam Ravnborg 
6185c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6191da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6201da177e4SLinus Torvalds {
6211da177e4SLinus Torvalds 	unsigned int crc;
62262a26356SAlessio Igor Bogani 	enum export export;
623d8c1eb86SNicholas Piggin 	bool is_crc = false;
62462a26356SAlessio Igor Bogani 
625258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
626d62c4765SMasahiro Yamada 	    strstarts(symname, "__ksymtab"))
62762a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
62862a26356SAlessio Igor Bogani 	else
62962a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	/* CRC'd symbol */
632d62c4765SMasahiro Yamada 	if (strstarts(symname, "__crc_")) {
633d8c1eb86SNicholas Piggin 		is_crc = true;
6341da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
63556067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
63656067812SArd Biesheuvel 			unsigned int *crcp;
63756067812SArd Biesheuvel 
63856067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
63956067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
64056067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
64156067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
64256067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
64356067812SArd Biesheuvel 			crc = *crcp;
64456067812SArd Biesheuvel 		}
645b2c5cdcfSMasahiro Yamada 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
646bd5cbcedSRam Pai 				export);
6471da177e4SLinus Torvalds 	}
648b5064654SAndi Kleen 
649b5064654SAndi Kleen 	switch (sym->st_shndx) {
650b5064654SAndi Kleen 	case SHN_COMMON:
651d62c4765SMasahiro Yamada 		if (strstarts(symname, "__gnu_lto_")) {
652ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
653ef178f92SAndi Kleen 		} else
654b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
6551da177e4SLinus Torvalds 		break;
6561da177e4SLinus Torvalds 	case SHN_UNDEF:
6571da177e4SLinus Torvalds 		/* undefined symbol */
6581da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
6591da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
6601da177e4SLinus Torvalds 			break;
6614d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
6621da177e4SLinus Torvalds 			break;
6638d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
6648d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
6658d529014SBen Colline /* add compatibility with older glibc */
6668d529014SBen Colline #ifndef STT_SPARC_REGISTER
6678d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
6688d529014SBen Colline #endif
6691da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
6701da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
6711da177e4SLinus Torvalds 			/* Ignore register directives. */
6728d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
6731da177e4SLinus Torvalds 				break;
6747caaeabbSAl Viro 			if (symname[0] == '.') {
6751f3aa900SRandy Dunlap 				char *munged = NOFAIL(strdup(symname));
6767caaeabbSAl Viro 				munged[0] = '_';
6777caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
6787caaeabbSAl Viro 				symname = munged;
6797caaeabbSAl Viro 			}
6801da177e4SLinus Torvalds 		}
6811da177e4SLinus Torvalds #endif
6821da177e4SLinus Torvalds 
683d8c1eb86SNicholas Piggin 		if (is_crc) {
684d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
685b2c5cdcfSMasahiro Yamada 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
686b2c5cdcfSMasahiro Yamada 			     symname + strlen("__crc_"), mod->name, e);
687d8c1eb86SNicholas Piggin 		}
688b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
6891da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
6901da177e4SLinus Torvalds 					  mod->unres);
6911da177e4SLinus Torvalds 		break;
6921da177e4SLinus Torvalds 	default:
6931da177e4SLinus Torvalds 		/* All exported symbols */
694d62c4765SMasahiro Yamada 		if (strstarts(symname, "__ksymtab_")) {
695b2c5cdcfSMasahiro Yamada 			sym_add_exported(symname + strlen("__ksymtab_"), mod,
696bd5cbcedSRam Pai 					export);
6971da177e4SLinus Torvalds 		}
698b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "init_module") == 0)
6991da177e4SLinus Torvalds 			mod->has_init = 1;
700b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "cleanup_module") == 0)
7011da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7021da177e4SLinus Torvalds 		break;
7031da177e4SLinus Torvalds 	}
7041da177e4SLinus Torvalds }
7051da177e4SLinus Torvalds 
7065c3ead8cSSam Ravnborg /**
7075c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7085c3ead8cSSam Ravnborg  **/
7091da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7101da177e4SLinus Torvalds {
7111da177e4SLinus Torvalds 	/* Skip non-zero chars */
7121da177e4SLinus Torvalds 	while (string[0]) {
7131da177e4SLinus Torvalds 		string++;
7141da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7151da177e4SLinus Torvalds 			return NULL;
7161da177e4SLinus Torvalds 	}
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	/* Skip any zero padding. */
7191da177e4SLinus Torvalds 	while (!string[0]) {
7201da177e4SLinus Torvalds 		string++;
7211da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7221da177e4SLinus Torvalds 			return NULL;
7231da177e4SLinus Torvalds 	}
7241da177e4SLinus Torvalds 	return string;
7251da177e4SLinus Torvalds }
7261da177e4SLinus Torvalds 
727bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag,
728bca2cceeSMasahiro Yamada 			      char *prev)
7291da177e4SLinus Torvalds {
7301da177e4SLinus Torvalds 	char *p;
7311da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
732bca2cceeSMasahiro Yamada 	char *modinfo = info->modinfo;
733bca2cceeSMasahiro Yamada 	unsigned long size = info->modinfo_len;
7341da177e4SLinus Torvalds 
735bca2cceeSMasahiro Yamada 	if (prev) {
736bca2cceeSMasahiro Yamada 		size -= prev - modinfo;
737bca2cceeSMasahiro Yamada 		modinfo = next_string(prev, &size);
738b817f6feSSam Ravnborg 	}
739b817f6feSSam Ravnborg 
7401da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
7411da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7421da177e4SLinus Torvalds 			return p + taglen + 1;
7431da177e4SLinus Torvalds 	}
7441da177e4SLinus Torvalds 	return NULL;
7451da177e4SLinus Torvalds }
7461da177e4SLinus Torvalds 
747bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag)
748b817f6feSSam Ravnborg 
749b817f6feSSam Ravnborg {
750bca2cceeSMasahiro Yamada 	return get_next_modinfo(info, tag, NULL);
751b817f6feSSam Ravnborg }
752b817f6feSSam Ravnborg 
75393684d3bSSam Ravnborg /**
7544c8fbca5SSam Ravnborg  * Test if string s ends in string sub
7554c8fbca5SSam Ravnborg  * return 0 if match
7564c8fbca5SSam Ravnborg  **/
7574c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
7584c8fbca5SSam Ravnborg {
7594c8fbca5SSam Ravnborg 	int slen, sublen;
7604c8fbca5SSam Ravnborg 
7614c8fbca5SSam Ravnborg 	if (!s || !sub)
7624c8fbca5SSam Ravnborg 		return 1;
7634c8fbca5SSam Ravnborg 
7644c8fbca5SSam Ravnborg 	slen = strlen(s);
7654c8fbca5SSam Ravnborg 	sublen = strlen(sub);
7664c8fbca5SSam Ravnborg 
7674c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
7684c8fbca5SSam Ravnborg 		return 1;
7694c8fbca5SSam Ravnborg 
7704c8fbca5SSam Ravnborg 	if (sublen > slen)
7714c8fbca5SSam Ravnborg 		return 1;
7724c8fbca5SSam Ravnborg 
7734c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
7744c8fbca5SSam Ravnborg }
7754c8fbca5SSam Ravnborg 
776ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
777ff13f926SSam Ravnborg {
77858fb0d4fSSam Ravnborg 	if (sym)
779ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
78058fb0d4fSSam Ravnborg 	else
781f666751aSSam Ravnborg 		return "(unknown)";
782ff13f926SSam Ravnborg }
783ff13f926SSam Ravnborg 
78410668220SSam Ravnborg /* The pattern is an array of simple patterns.
78510668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
7866c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
78710668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
78809c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
78910668220SSam Ravnborg  */
7905c725138STrevor Keith static int match(const char *sym, const char * const pat[])
79110668220SSam Ravnborg {
79210668220SSam Ravnborg 	const char *p;
79310668220SSam Ravnborg 	while (*pat) {
79410668220SSam Ravnborg 		p = *pat++;
79510668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
79610668220SSam Ravnborg 
79709c20c03SPaul Gortmaker 		/* "*foo*" */
79809c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
79909c20c03SPaul Gortmaker 			char *here, *bare = strndup(p + 1, strlen(p) - 2);
80009c20c03SPaul Gortmaker 
80109c20c03SPaul Gortmaker 			here = strstr(sym, bare);
80209c20c03SPaul Gortmaker 			free(bare);
80309c20c03SPaul Gortmaker 			if (here != NULL)
80409c20c03SPaul Gortmaker 				return 1;
80509c20c03SPaul Gortmaker 		}
8066c5bd235SSam Ravnborg 		/* "*foo" */
80709c20c03SPaul Gortmaker 		else if (*p == '*') {
8086c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8096c5bd235SSam Ravnborg 				return 1;
8106c5bd235SSam Ravnborg 		}
81110668220SSam Ravnborg 		/* "foo*" */
8126c5bd235SSam Ravnborg 		else if (*endp == '*') {
81310668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
81410668220SSam Ravnborg 				return 1;
81510668220SSam Ravnborg 		}
81610668220SSam Ravnborg 		/* no wildcards */
81710668220SSam Ravnborg 		else {
81810668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
81910668220SSam Ravnborg 				return 1;
82010668220SSam Ravnborg 		}
82110668220SSam Ravnborg 	}
82210668220SSam Ravnborg 	/* no match */
82310668220SSam Ravnborg 	return 0;
82410668220SSam Ravnborg }
82510668220SSam Ravnborg 
82610668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8277a3ee753SMathias Krause static const char *const section_white_list[] =
8284391ed6aSSam Ravnborg {
8294391ed6aSSam Ravnborg 	".comment*",
8304391ed6aSSam Ravnborg 	".debug*",
8314d10c223SChen Gang 	".cranges",		/* sh64 */
8321121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
833739d875dSDavid Howells 	".GCC.command.line",	/* record-gcc-switches */
8344391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8354391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8364391ed6aSSam Ravnborg 	".stab*",
8374391ed6aSSam Ravnborg 	".note*",
8384391ed6aSSam Ravnborg 	".got*",
8394391ed6aSSam Ravnborg 	".toc*",
840af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
841af42e970SMax Filippov 	".xt.lit",         /* xtensa */
842f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
843f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
844d1189c63SNoam Camus 	".cmem*",			/* EZchip */
845d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
846ef178f92SAndi Kleen 	".gnu.lto*",
847e390f9a9SJosh Poimboeuf 	".discard.*",
8484391ed6aSSam Ravnborg 	NULL
8494391ed6aSSam Ravnborg };
85010668220SSam Ravnborg 
851e241a630SSam Ravnborg /*
852b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
853e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
854b614a697SAnders Kaseorg  * without "ax" / "aw".
855e241a630SSam Ravnborg  */
856b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
857b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
858e241a630SSam Ravnborg {
859b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
860e241a630SSam Ravnborg 
861b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
862b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
863b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
864b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
865b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
866e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
867e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
868e241a630SSam Ravnborg 		     modname, sec);
869e241a630SSam Ravnborg 	}
870e241a630SSam Ravnborg }
871e241a630SSam Ravnborg 
872e241a630SSam Ravnborg 
873e241a630SSam Ravnborg 
874eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
875a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
876a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
877eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
878a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
87910668220SSam Ravnborg 
880eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
881a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
882eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
883a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
88410668220SSam Ravnborg 
885bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
886a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
887a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
888a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
889bb15d8dbSSebastian Andrzej Siewior 
890e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
891e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
8924a31a229SUwe Kleine-König 
8934a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
8944a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
89510668220SSam Ravnborg 
896a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
897157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
8986727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
89952dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
900673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
901673c2c34SChris Metcalf 		".coldtext"
90210668220SSam Ravnborg 
903fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
904fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
905eb8f6890SSam Ravnborg 
906fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
907fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
908eb8f6890SSam Ravnborg 
90952dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
91052dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
91152dc0595SQuentin Casasnovas 
9126c5bd235SSam Ravnborg /* init data sections */
9137a3ee753SMathias Krause static const char *const init_data_sections[] =
9147a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9156c5bd235SSam Ravnborg 
9166c5bd235SSam Ravnborg /* all init sections */
9177a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9186c5bd235SSam Ravnborg 
9196c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9207a3ee753SMathias Krause static const char *const init_exit_sections[] =
921eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9226c5bd235SSam Ravnborg 
9234a3893d0SPaul Gortmaker /* all text sections */
9244a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9254a3893d0SPaul Gortmaker 
9266c5bd235SSam Ravnborg /* data section */
9277a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9286c5bd235SSam Ravnborg 
9296c5bd235SSam Ravnborg 
9306c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
931af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
932af92a82dSUwe Kleine-König 	"*driver",							\
933af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
934af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
935af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
936af92a82dSUwe Kleine-König 	"*_ops",							\
937af92a82dSUwe Kleine-König 	"*_probe",							\
938af92a82dSUwe Kleine-König 	"*_probe_one",							\
939af92a82dSUwe Kleine-König 	"*_console"
9406c5bd235SSam Ravnborg 
9417a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
9427a3ee753SMathias Krause static const char *const linker_symbols[] =
9436c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
9444a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
9456c5bd235SSam Ravnborg 
946588ccd73SSam Ravnborg enum mismatch {
947bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
948bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
949bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
950bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
951bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
952bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
953bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
954bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
955588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
95652dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
957588ccd73SSam Ravnborg };
958588ccd73SSam Ravnborg 
959e5d8f59aSQuentin Casasnovas /**
960e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
961e5d8f59aSQuentin Casasnovas  *
962e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
963e5d8f59aSQuentin Casasnovas  *
964e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
965e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
966e5d8f59aSQuentin Casasnovas  *
967e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
968e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
969e5d8f59aSQuentin Casasnovas  *
970e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
971e5d8f59aSQuentin Casasnovas  *
972e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
973e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
974e5d8f59aSQuentin Casasnovas  *
975e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
976e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
977e5d8f59aSQuentin Casasnovas  *
978e5d8f59aSQuentin Casasnovas  */
97910668220SSam Ravnborg struct sectioncheck {
98010668220SSam Ravnborg 	const char *fromsec[20];
981050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
982050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
983588ccd73SSam Ravnborg 	enum mismatch mismatch;
984af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
985644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
986644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
987644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
988644e8f14SQuentin Casasnovas 
98910668220SSam Ravnborg };
99010668220SSam Ravnborg 
99152dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
99252dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
99352dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
99452dc0595SQuentin Casasnovas 				     const char *fromsec);
99552dc0595SQuentin Casasnovas 
9967a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
99710668220SSam Ravnborg /* Do not reference init/exit code/data from
99810668220SSam Ravnborg  * normal code and data
99910668220SSam Ravnborg  */
100010668220SSam Ravnborg {
1001588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1002050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1003bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1004af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1005588ccd73SSam Ravnborg },
1006588ccd73SSam Ravnborg {
1007588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1008050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1009bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1010af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1011588ccd73SSam Ravnborg },
1012588ccd73SSam Ravnborg {
10130db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1014050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10150db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10160db25245SUwe Kleine-König 	.symbol_white_list = {
10170db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10180db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10190db25245SUwe Kleine-König 	},
10200db25245SUwe Kleine-König },
10210db25245SUwe Kleine-König {
1022588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1023050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1024bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1025af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1026588ccd73SSam Ravnborg },
1027588ccd73SSam Ravnborg {
1028588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1029050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1030bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1031af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1032eb8f6890SSam Ravnborg },
1033e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1034eb8f6890SSam Ravnborg {
10354a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1036050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1037bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1038af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1039eb8f6890SSam Ravnborg },
1040e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1041eb8f6890SSam Ravnborg {
10424a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1043050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1044bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1045af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
104610668220SSam Ravnborg },
104710668220SSam Ravnborg /* Do not use exit code/data from init code */
104810668220SSam Ravnborg {
1049eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1050050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1051bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1052af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
105310668220SSam Ravnborg },
105410668220SSam Ravnborg /* Do not use init code/data from exit code */
105510668220SSam Ravnborg {
1056eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1057050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1058bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1059af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
106010668220SSam Ravnborg },
1061bb15d8dbSSebastian Andrzej Siewior {
1062bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1063050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1064bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1065bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1066bb15d8dbSSebastian Andrzej Siewior },
106710668220SSam Ravnborg /* Do not export init/exit functions or data */
106810668220SSam Ravnborg {
106910668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1070050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1071af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1072af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
107352dc0595SQuentin Casasnovas },
107452dc0595SQuentin Casasnovas {
107552dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
107652dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
107752dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
107852dc0595SQuentin Casasnovas 	 */
107952dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
108052dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
108152dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
108252dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
108310668220SSam Ravnborg }
108410668220SSam Ravnborg };
108510668220SSam Ravnborg 
10860d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
10870d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
108810668220SSam Ravnborg {
108910668220SSam Ravnborg 	int i;
109010668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
109110668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
109210668220SSam Ravnborg 
1093c5c3439aSQuentin Casasnovas 	/*
1094c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1095c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1096739d875dSDavid Howells 	 * doesn't make much sense and causes build failures on parisc
1097739d875dSDavid Howells 	 * architectures.
1098c5c3439aSQuentin Casasnovas 	 */
1099c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1100c5c3439aSQuentin Casasnovas 		return NULL;
1101c5c3439aSQuentin Casasnovas 
110210668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1103050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1104050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11050d2a636eSUwe Kleine-König 				return check;
1106050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1107050e57fdSQuentin Casasnovas 				return check;
1108050e57fdSQuentin Casasnovas 		}
110910668220SSam Ravnborg 		check++;
111010668220SSam Ravnborg 	}
11110d2a636eSUwe Kleine-König 	return NULL;
111210668220SSam Ravnborg }
111310668220SSam Ravnborg 
11144c8fbca5SSam Ravnborg /**
11154c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11160e0d314eSSam Ravnborg  *
11174c8fbca5SSam Ravnborg  * Pattern 1:
11184c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11194c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11204c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11214c8fbca5SSam Ravnborg  *   this pattern.
11224c8fbca5SSam Ravnborg  *   The pattern is identified by:
11234c8fbca5SSam Ravnborg  *   tosec   = .init.data
11249209aed0SSam Ravnborg  *   fromsec = .data*
11254c8fbca5SSam Ravnborg  *   atsym   =__param*
11264c8fbca5SSam Ravnborg  *
11276a841528SRusty Russell  * Pattern 1a:
11286a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11296a841528SRusty Russell  *   The pattern is identified by:
11306a841528SRusty Russell  *   tosec   = .init.text
11316a841528SRusty Russell  *   fromsec = .data*
11326a841528SRusty Russell  *   atsym   = __param_ops_*
11336a841528SRusty Russell  *
11344c8fbca5SSam Ravnborg  * Pattern 2:
113572ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11364c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
11374c8fbca5SSam Ravnborg  *   the pattern is identified by:
113883cda2bbSSam Ravnborg  *   tosec   = init or exit section
113983cda2bbSSam Ravnborg  *   fromsec = data section
1140df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1141df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1142ee6a8545SVivek Goyal  *
1143ee6a8545SVivek Goyal  * Pattern 3:
1144c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
11459bf8cb9bSSam Ravnborg  *
11461d8af559SSam Ravnborg  * Pattern 4:
1147ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1148ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1149ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1150ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1151ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1152ee6a8545SVivek Goyal  *   This pattern is identified by
1153ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
11549bf8cb9bSSam Ravnborg  *
11554a3893d0SPaul Gortmaker  * Pattern 5:
11564a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
11574a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
11584a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
11594a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
11604a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
11614a3893d0SPaul Gortmaker  *   This pattern is identified by
11624a3893d0SPaul Gortmaker  *   tosec   = init section
11634a3893d0SPaul Gortmaker  *   fromsec = text section
11644a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
11654a3893d0SPaul Gortmaker  *
1166a4d26f1aSPaul Walmsley  * Pattern 6:
1167a4d26f1aSPaul Walmsley  *   Hide section mismatch warnings for ELF local symbols.  The goal
1168a4d26f1aSPaul Walmsley  *   is to eliminate false positive modpost warnings caused by
1169a4d26f1aSPaul Walmsley  *   compiler-generated ELF local symbol names such as ".LANCHOR1".
1170a4d26f1aSPaul Walmsley  *   Autogenerated symbol names bypass modpost's "Pattern 2"
1171a4d26f1aSPaul Walmsley  *   whitelisting, which relies on pattern-matching against symbol
1172a4d26f1aSPaul Walmsley  *   names to work.  (One situation where gcc can autogenerate ELF
1173a4d26f1aSPaul Walmsley  *   local symbols is when "-fsection-anchors" is used.)
11744c8fbca5SSam Ravnborg  **/
1175af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1176af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
117758fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
11784c8fbca5SSam Ravnborg {
11794c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
11806c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
11816c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1182d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param"))
118358fb0d4fSSam Ravnborg 		return 0;
11844c8fbca5SSam Ravnborg 
11856a841528SRusty Russell 	/* Check for pattern 1a */
11866a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
11876a841528SRusty Russell 	    match(fromsec, data_sections) &&
1188d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param_ops_"))
11896a841528SRusty Russell 		return 0;
11906a841528SRusty Russell 
11914c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
11926c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
11936c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1194af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
119558fb0d4fSSam Ravnborg 		return 0;
11964c8fbca5SSam Ravnborg 
11979bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
11986c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
11996c5bd235SSam Ravnborg 	    match(tosec, init_sections))
120058fb0d4fSSam Ravnborg 		return 0;
1201f8657e1bSVivek Goyal 
12021d8af559SSam Ravnborg 	/* Check for pattern 4 */
120358fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
120493659af1SSam Ravnborg 		return 0;
120558fb0d4fSSam Ravnborg 
12064a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12074a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12084a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12094a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12104a3893d0SPaul Gortmaker 		return 0;
12114a3893d0SPaul Gortmaker 
1212a4d26f1aSPaul Walmsley 	/* Check for pattern 6 */
1213a4d26f1aSPaul Walmsley 	if (strstarts(fromsym, ".L"))
1214a4d26f1aSPaul Walmsley 		return 0;
1215a4d26f1aSPaul Walmsley 
121658fb0d4fSSam Ravnborg 	return 1;
12174c8fbca5SSam Ravnborg }
12184c8fbca5SSam Ravnborg 
12195818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str)
12205818c683SSami Tolvanen {
12215818c683SSami Tolvanen 	return str[0] == '$' && strchr("axtd", str[1])
12225818c683SSami Tolvanen 	       && (str[2] == '\0' || str[2] == '.');
12235818c683SSami Tolvanen }
12245818c683SSami Tolvanen 
12255818c683SSami Tolvanen /*
12265818c683SSami Tolvanen  * If there's no name there, ignore it; likewise, ignore it if it's
12275818c683SSami Tolvanen  * one of the magic symbols emitted used by current ARM tools.
12285818c683SSami Tolvanen  *
12295818c683SSami Tolvanen  * Otherwise if find_symbols_between() returns those symbols, they'll
12305818c683SSami Tolvanen  * fail the whitelist tests and cause lots of false alarms ... fixable
12315818c683SSami Tolvanen  * only by merging __exit and __init sections into __text, bloating
12325818c683SSami Tolvanen  * the kernel (which is especially evil on embedded platforms).
12335818c683SSami Tolvanen  */
12345818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
12355818c683SSami Tolvanen {
12365818c683SSami Tolvanen 	const char *name = elf->strtab + sym->st_name;
12375818c683SSami Tolvanen 
12385818c683SSami Tolvanen 	if (!name || !strlen(name))
12395818c683SSami Tolvanen 		return 0;
12405818c683SSami Tolvanen 	return !is_arm_mapping_symbol(name);
12415818c683SSami Tolvanen }
12425818c683SSami Tolvanen 
12434c8fbca5SSam Ravnborg /**
124493684d3bSSam Ravnborg  * Find symbol based on relocation record info.
124593684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
124693684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
124793684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
124893684d3bSSam Ravnborg  * based on section and address.
124993684d3bSSam Ravnborg  *  **/
12509ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
125193684d3bSSam Ravnborg 				Elf_Sym *relsym)
125293684d3bSSam Ravnborg {
125393684d3bSSam Ravnborg 	Elf_Sym *sym;
12549ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
12559ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
12569ad21c3fSSam Ravnborg 	Elf64_Sword d;
12571ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
125893684d3bSSam Ravnborg 
125993684d3bSSam Ravnborg 	if (relsym->st_name != 0)
126093684d3bSSam Ravnborg 		return relsym;
12611ce53adfSDenys Vlasenko 
12621ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
126393684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
12641ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
126593684d3bSSam Ravnborg 			continue;
1266ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1267ae4ac123SAtsushi Nemoto 			continue;
12685818c683SSami Tolvanen 		if (!is_valid_name(elf, sym))
12695818c683SSami Tolvanen 			continue;
127093684d3bSSam Ravnborg 		if (sym->st_value == addr)
127193684d3bSSam Ravnborg 			return sym;
12729ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
12739ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
12749ad21c3fSSam Ravnborg 		if (d < 0)
12759ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
12769ad21c3fSSam Ravnborg 		if (d < distance) {
12779ad21c3fSSam Ravnborg 			distance = d;
12789ad21c3fSSam Ravnborg 			near = sym;
127993684d3bSSam Ravnborg 		}
12809ad21c3fSSam Ravnborg 	}
12819ad21c3fSSam Ravnborg 	/* We need a close match */
12829ad21c3fSSam Ravnborg 	if (distance < 20)
12839ad21c3fSSam Ravnborg 		return near;
12849ad21c3fSSam Ravnborg 	else
128593684d3bSSam Ravnborg 		return NULL;
128693684d3bSSam Ravnborg }
128793684d3bSSam Ravnborg 
1288b39927cfSSam Ravnborg /*
128943c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
129043c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
129143c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
129243c74d17SSam Ravnborg  * it is, but this works for now.
1293b39927cfSSam Ravnborg  **/
1294157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1295157c23c8SSam Ravnborg 				 const char *sec)
1296b39927cfSSam Ravnborg {
1297b39927cfSSam Ravnborg 	Elf_Sym *sym;
1298157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1299157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1300b39927cfSSam Ravnborg 
1301b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1302b39927cfSSam Ravnborg 		const char *symsec;
1303b39927cfSSam Ravnborg 
13041ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1305b39927cfSSam Ravnborg 			continue;
13061ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1307b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1308b39927cfSSam Ravnborg 			continue;
1309da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1310da68d61fSDavid Brownell 			continue;
1311b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1312157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1313157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1314157c23c8SSam Ravnborg 				near = sym;
1315157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1316157c23c8SSam Ravnborg 				near = sym;
131743c74d17SSam Ravnborg 			}
1318b39927cfSSam Ravnborg 		}
1319b39927cfSSam Ravnborg 	}
1320157c23c8SSam Ravnborg 	return near;
1321157c23c8SSam Ravnborg }
1322b39927cfSSam Ravnborg 
132358fb0d4fSSam Ravnborg /*
1324588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1325588ccd73SSam Ravnborg  * .init.text => __init
1326588ccd73SSam Ravnborg  * .memexitconst => __memconst
1327588ccd73SSam Ravnborg  * etc.
1328cbcf14a9SAndy Shevchenko  *
1329cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1330cbcf14a9SAndy Shevchenko  * method should free it after usage.
1331588ccd73SSam Ravnborg */
1332588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1333588ccd73SSam Ravnborg {
1334588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
13351f3aa900SRandy Dunlap 		char *p = NOFAIL(malloc(20));
1336588ccd73SSam Ravnborg 		char *r = p;
1337588ccd73SSam Ravnborg 
1338588ccd73SSam Ravnborg 		*p++ = '_';
1339588ccd73SSam Ravnborg 		*p++ = '_';
1340588ccd73SSam Ravnborg 		if (*s == '.')
1341588ccd73SSam Ravnborg 			s++;
1342588ccd73SSam Ravnborg 		while (*s && *s != '.')
1343588ccd73SSam Ravnborg 			*p++ = *s++;
1344588ccd73SSam Ravnborg 		*p = '\0';
1345588ccd73SSam Ravnborg 		if (*s == '.')
1346588ccd73SSam Ravnborg 			s++;
1347588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1348588ccd73SSam Ravnborg 			strcat(p, "const ");
1349588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1350588ccd73SSam Ravnborg 			strcat(p, "data ");
1351588ccd73SSam Ravnborg 		else
1352588ccd73SSam Ravnborg 			strcat(p, " ");
1353cbcf14a9SAndy Shevchenko 		return r;
1354588ccd73SSam Ravnborg 	} else {
13551f3aa900SRandy Dunlap 		return NOFAIL(strdup(""));
1356588ccd73SSam Ravnborg 	}
1357588ccd73SSam Ravnborg }
1358588ccd73SSam Ravnborg 
1359588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1360588ccd73SSam Ravnborg {
1361588ccd73SSam Ravnborg 	if (sym)
1362588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1363588ccd73SSam Ravnborg 	else
1364f666751aSSam Ravnborg 		return -1;
1365588ccd73SSam Ravnborg }
1366588ccd73SSam Ravnborg 
136700759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
136800759c0eSRandy Dunlap {
136900759c0eSRandy Dunlap 	const char *const *s = list;
137000759c0eSRandy Dunlap 
137100759c0eSRandy Dunlap 	while (*s) {
137200759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
137300759c0eSRandy Dunlap 		s++;
137400759c0eSRandy Dunlap 		if (*s)
137500759c0eSRandy Dunlap 			fprintf(stderr, ", ");
137600759c0eSRandy Dunlap 	}
137700759c0eSRandy Dunlap 	fprintf(stderr, "\n");
137800759c0eSRandy Dunlap }
137900759c0eSRandy Dunlap 
1380356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1381356ad538SQuentin Casasnovas {
1382356ad538SQuentin Casasnovas 	switch (is_func) {
1383356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1384356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1385356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1386356ad538SQuentin Casasnovas 	}
1387356ad538SQuentin Casasnovas }
1388356ad538SQuentin Casasnovas 
1389588ccd73SSam Ravnborg /*
1390b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1391b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
13924c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
139358fb0d4fSSam Ravnborg  */
13940d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
13950d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
139658fb0d4fSSam Ravnborg 				const char *fromsec,
139758fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
139858fb0d4fSSam Ravnborg 				const char *fromsym,
1399588ccd73SSam Ravnborg 				int from_is_func,
1400588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1401588ccd73SSam Ravnborg 				int to_is_func)
1402b39927cfSSam Ravnborg {
1403588ccd73SSam Ravnborg 	const char *from, *from_p;
1404588ccd73SSam Ravnborg 	const char *to, *to_p;
140537ed19d5SAlexey Fomenko 	char *prl_from;
140637ed19d5SAlexey Fomenko 	char *prl_to;
1407f666751aSSam Ravnborg 
1408e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1409e5f95c8bSSam Ravnborg 	if (!sec_mismatch_verbose)
1410e5f95c8bSSam Ravnborg 		return;
1411e5f95c8bSSam Ravnborg 
1412356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1413356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1414356ad538SQuentin Casasnovas 
14157c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14167c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14177c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14187c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1419588ccd73SSam Ravnborg 
14200d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1421bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
142237ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
142337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1424588ccd73SSam Ravnborg 		fprintf(stderr,
1425588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1426588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1427588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1428588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
142937ed19d5SAlexey Fomenko 		prl_from, fromsym,
143037ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
143137ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
143237ed19d5SAlexey Fomenko 		free(prl_from);
143337ed19d5SAlexey Fomenko 		free(prl_to);
1434588ccd73SSam Ravnborg 		break;
1435bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
143637ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1437588ccd73SSam Ravnborg 		fprintf(stderr,
1438588ccd73SSam Ravnborg 		"The variable %s references\n"
1439588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1440588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
14418b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1442588ccd73SSam Ravnborg 		"or name the variable:\n",
144337ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
144400759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
144537ed19d5SAlexey Fomenko 		free(prl_to);
1446588ccd73SSam Ravnborg 		break;
144758fb0d4fSSam Ravnborg 	}
1448bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
144937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1450588ccd73SSam Ravnborg 		fprintf(stderr,
1451588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1452588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1453588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
145437ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
145537ed19d5SAlexey Fomenko 		free(prl_to);
1456588ccd73SSam Ravnborg 		break;
1457bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
145837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1459588ccd73SSam Ravnborg 		fprintf(stderr,
1460588ccd73SSam Ravnborg 		"The variable %s references\n"
1461588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1462588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1463588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1464588ccd73SSam Ravnborg 		"name the variable:\n",
146537ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
146600759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
146737ed19d5SAlexey Fomenko 		free(prl_to);
1468588ccd73SSam Ravnborg 		break;
1469588ccd73SSam Ravnborg 	}
1470bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1471bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
147237ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
147337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1474588ccd73SSam Ravnborg 		fprintf(stderr,
1475588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1476588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1477588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1478588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
147937ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
148037ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1481b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
148237ed19d5SAlexey Fomenko 		free(prl_from);
148337ed19d5SAlexey Fomenko 		free(prl_to);
1484588ccd73SSam Ravnborg 		break;
1485bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
148637ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
148737ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1488588ccd73SSam Ravnborg 		fprintf(stderr,
1489588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1490588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1491588ccd73SSam Ravnborg 		"This is often seen when error handling "
1492588ccd73SSam Ravnborg 		"in the init function\n"
1493588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1494588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1495588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
149637ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
149737ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
14985003bab8SAndrew Morton 		prl_to, tosym, to_p);
149937ed19d5SAlexey Fomenko 		free(prl_from);
150037ed19d5SAlexey Fomenko 		free(prl_to);
1501588ccd73SSam Ravnborg 		break;
1502bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
150337ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
150437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1505588ccd73SSam Ravnborg 		fprintf(stderr,
1506588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1507588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1508588ccd73SSam Ravnborg 		"This is often seen when error handling "
1509588ccd73SSam Ravnborg 		"in the exit function\n"
1510588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1511588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1512588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
151337ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
151437ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
151537ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
151637ed19d5SAlexey Fomenko 		free(prl_from);
151737ed19d5SAlexey Fomenko 		free(prl_to);
1518588ccd73SSam Ravnborg 		break;
1519588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
152037ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1521588ccd73SSam Ravnborg 		fprintf(stderr,
1522588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1523588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1524588ccd73SSam Ravnborg 		"or drop the export.\n",
152537ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
152637ed19d5SAlexey Fomenko 		free(prl_to);
1527588ccd73SSam Ravnborg 		break;
152852dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
152952dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
153052dc0595SQuentin Casasnovas 		      "we should never get here.");
153152dc0595SQuentin Casasnovas 		break;
1532588ccd73SSam Ravnborg 	}
1533588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
153458fb0d4fSSam Ravnborg }
153558fb0d4fSSam Ravnborg 
1536644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1537644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
153858fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
153958fb0d4fSSam Ravnborg {
154058fb0d4fSSam Ravnborg 	const char *tosec;
1541588ccd73SSam Ravnborg 	Elf_Sym *to;
1542588ccd73SSam Ravnborg 	Elf_Sym *from;
154358fb0d4fSSam Ravnborg 	const char *tosym;
1544588ccd73SSam Ravnborg 	const char *fromsym;
154558fb0d4fSSam Ravnborg 
1546588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1547588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
154858fb0d4fSSam Ravnborg 
1549d62c4765SMasahiro Yamada 	if (strstarts(fromsym, "reference___initcall"))
155077ab21adSAndi Kleen 		return;
155177ab21adSAndi Kleen 
1552c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1553c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1554c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1555c7a65e06SQuentin Casasnovas 
155658fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1557af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1558af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1559588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1560588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1561588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1562588ccd73SSam Ravnborg 				    is_function(to));
156358fb0d4fSSam Ravnborg 	}
1564b39927cfSSam Ravnborg }
1565644e8f14SQuentin Casasnovas 
156652dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
156752dc0595SQuentin Casasnovas {
156852dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
156952dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
157052dc0595SQuentin Casasnovas 
157152dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
157252dc0595SQuentin Casasnovas }
157352dc0595SQuentin Casasnovas 
157452dc0595SQuentin Casasnovas /*
157552dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
157652dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
157752dc0595SQuentin Casasnovas  */
157852dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1579e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
158052dc0595SQuentin Casasnovas {
158152dc0595SQuentin Casasnovas 	/*
158252dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
158352dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
158452dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
158552dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
158652dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
158752dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
158852dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
158952dc0595SQuentin Casasnovas 	 */
1590e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
159152dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
159252dc0595SQuentin Casasnovas }
1593e84048aaSQuentin Casasnovas 
159452dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
159552dc0595SQuentin Casasnovas {
1596d3df4de7SQuentin Casasnovas 	/*
1597d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1598d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1599d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1600d3df4de7SQuentin Casasnovas 	 */
1601d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
160252dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
160352dc0595SQuentin Casasnovas 
160452dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
160552dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
160652dc0595SQuentin Casasnovas }
160752dc0595SQuentin Casasnovas 
1608e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1609e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1610e84048aaSQuentin Casasnovas 
161152dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
161252dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
161352dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
161452dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
161552dc0595SQuentin Casasnovas {
161652dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
161752dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
161852dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
161952dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
162052dc0595SQuentin Casasnovas 	const char* from_pretty_name;
162152dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
162252dc0595SQuentin Casasnovas 	const char* to_pretty_name;
162352dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
162452dc0595SQuentin Casasnovas 
162552dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
162652dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
162752dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
162852dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
162952dc0595SQuentin Casasnovas 
163052dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
163152dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
163252dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
163352dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
163452dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
163552dc0595SQuentin Casasnovas 
163652dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
163752dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
163852dc0595SQuentin Casasnovas 		fprintf(stderr,
163952dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
164052dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
164152dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
164252dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
164352dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
164452dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
164552dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
164652dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
164752dc0595SQuentin Casasnovas }
164852dc0595SQuentin Casasnovas 
164952dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
165052dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
165152dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
165252dc0595SQuentin Casasnovas 				     const char *fromsec)
165352dc0595SQuentin Casasnovas {
165452dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
165552dc0595SQuentin Casasnovas 
165652dc0595SQuentin Casasnovas 	sec_mismatch_count++;
165752dc0595SQuentin Casasnovas 
165852dc0595SQuentin Casasnovas 	if (sec_mismatch_verbose)
165952dc0595SQuentin Casasnovas 		report_extable_warnings(modname, elf, mismatch, r, sym,
166052dc0595SQuentin Casasnovas 					fromsec, tosec);
166152dc0595SQuentin Casasnovas 
166252dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
166352dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
166452dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
166552dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
166652dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
166752dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
166852dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
166952dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
167052dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
167152dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
167252dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
167352dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
167452dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
167552dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
167652dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
167752dc0595SQuentin Casasnovas 		else
167852dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
167952dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
168052dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
168152dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
168252dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
168352dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
168452dc0595SQuentin Casasnovas 	}
168552dc0595SQuentin Casasnovas }
168652dc0595SQuentin Casasnovas 
1687644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1688644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1689644e8f14SQuentin Casasnovas {
16900cad61d7SLuis de Bethencourt 	const char *tosec = sec_name(elf, get_secindex(elf, sym));
1691644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1692644e8f14SQuentin Casasnovas 
1693644e8f14SQuentin Casasnovas 	if (mismatch) {
1694644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1695644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1696644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1697644e8f14SQuentin Casasnovas 		else
1698644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1699644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1700644e8f14SQuentin Casasnovas 	}
1701b39927cfSSam Ravnborg }
1702b39927cfSSam Ravnborg 
1703ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
17045b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1705ae4ac123SAtsushi Nemoto {
1706ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17076845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1708ae4ac123SAtsushi Nemoto 
1709ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1710731ece41SOlof Johansson 		r->r_offset;
1711ae4ac123SAtsushi Nemoto }
1712ae4ac123SAtsushi Nemoto 
17135b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1714ae4ac123SAtsushi Nemoto {
1715ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17165b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1717ae4ac123SAtsushi Nemoto 
1718ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1719ae4ac123SAtsushi Nemoto 	case R_386_32:
1720ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1721ae4ac123SAtsushi Nemoto 		break;
1722ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1723ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1724ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1725ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1726ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1727ae4ac123SAtsushi Nemoto 		break;
1728ae4ac123SAtsushi Nemoto 	}
1729ae4ac123SAtsushi Nemoto 	return 0;
1730ae4ac123SAtsushi Nemoto }
1731ae4ac123SAtsushi Nemoto 
17326e2e340bSTony Lindgren #ifndef R_ARM_CALL
17336e2e340bSTony Lindgren #define R_ARM_CALL	28
17346e2e340bSTony Lindgren #endif
17356e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17366e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17376e2e340bSTony Lindgren #endif
17386e2e340bSTony Lindgren 
1739c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1740c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1741c9698e5cSDavid A. Long #endif
1742c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1743c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1744c9698e5cSDavid A. Long #endif
1745c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1746c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1747c9698e5cSDavid A. Long #endif
1748c9698e5cSDavid A. Long 
17495b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
175056a974faSSam Ravnborg {
175156a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
175256a974faSSam Ravnborg 
175356a974faSSam Ravnborg 	switch (r_typ) {
175456a974faSSam Ravnborg 	case R_ARM_ABS32:
175556a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1756df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1757df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
175856a974faSSam Ravnborg 		break;
175956a974faSSam Ravnborg 	case R_ARM_PC24:
17606e2e340bSTony Lindgren 	case R_ARM_CALL:
17616e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1762c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1763c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1764c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
176556a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1766df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
17675b24c071SSam Ravnborg 			      sechdr->sh_offset +
17685b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
176956a974faSSam Ravnborg 		break;
177056a974faSSam Ravnborg 	default:
177156a974faSSam Ravnborg 		return 1;
177256a974faSSam Ravnborg 	}
177356a974faSSam Ravnborg 	return 0;
177456a974faSSam Ravnborg }
177556a974faSSam Ravnborg 
17765b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1777ae4ac123SAtsushi Nemoto {
1778ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17795b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1780ae4ac123SAtsushi Nemoto 	unsigned int inst;
1781ae4ac123SAtsushi Nemoto 
1782ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1783ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1784ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1785ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1786ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1787ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1788ae4ac123SAtsushi Nemoto 		break;
1789ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1790ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1791ae4ac123SAtsushi Nemoto 		break;
1792ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1793ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1794ae4ac123SAtsushi Nemoto 		break;
1795ae4ac123SAtsushi Nemoto 	}
1796ae4ac123SAtsushi Nemoto 	return 0;
1797ae4ac123SAtsushi Nemoto }
1798ae4ac123SAtsushi Nemoto 
17995b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
180010668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1801b39927cfSSam Ravnborg {
1802b39927cfSSam Ravnborg 	Elf_Sym  *sym;
18035b24c071SSam Ravnborg 	Elf_Rela *rela;
18042c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1805eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18065b24c071SSam Ravnborg 	const char *fromsec;
18075b24c071SSam Ravnborg 
1808ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18095b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18105b24c071SSam Ravnborg 
1811ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18125b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18135b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1814b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18155b24c071SSam Ravnborg 		return;
1816e241a630SSam Ravnborg 
1817b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1818b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1819eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1820ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1821ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1822eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1823eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1824ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1825ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1826eae07ac6SAtsushi Nemoto 		} else {
1827601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1828eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1829eae07ac6SAtsushi Nemoto 		}
1830eae07ac6SAtsushi Nemoto #else
1831eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1832eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1833eae07ac6SAtsushi Nemoto #endif
183493684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1835eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1836b39927cfSSam Ravnborg 		/* Skip special sections */
18371ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1838b39927cfSSam Ravnborg 			continue;
1839e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1840e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
184158fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18422c1a51f3SAtsushi Nemoto 	}
18435b24c071SSam Ravnborg }
18445b24c071SSam Ravnborg 
18455b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
184610668220SSam Ravnborg 			Elf_Shdr *sechdr)
18475b24c071SSam Ravnborg {
18485b24c071SSam Ravnborg 	Elf_Sym *sym;
18492c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
18505b24c071SSam Ravnborg 	Elf_Rela r;
18515b24c071SSam Ravnborg 	unsigned int r_sym;
18525b24c071SSam Ravnborg 	const char *fromsec;
18535b24c071SSam Ravnborg 
1854ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
18555b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
18565b24c071SSam Ravnborg 
1857ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18585b24c071SSam Ravnborg 	fromsec += strlen(".rel");
18595b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1860b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18615b24c071SSam Ravnborg 		return;
18622c1a51f3SAtsushi Nemoto 
18632c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
18642c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1865eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1866ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1867ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1868eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1869eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1870ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1871ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1872eae07ac6SAtsushi Nemoto 		} else {
18732c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1874eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1875eae07ac6SAtsushi Nemoto 		}
1876eae07ac6SAtsushi Nemoto #else
1877eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1878eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1879eae07ac6SAtsushi Nemoto #endif
18802c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1881ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1882ae4ac123SAtsushi Nemoto 		case EM_386:
18835b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1884ae4ac123SAtsushi Nemoto 				continue;
1885ae4ac123SAtsushi Nemoto 			break;
188656a974faSSam Ravnborg 		case EM_ARM:
18875b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
188856a974faSSam Ravnborg 				continue;
188956a974faSSam Ravnborg 			break;
1890ae4ac123SAtsushi Nemoto 		case EM_MIPS:
18915b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1892ae4ac123SAtsushi Nemoto 				continue;
1893ae4ac123SAtsushi Nemoto 			break;
1894ae4ac123SAtsushi Nemoto 		}
1895eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
18962c1a51f3SAtsushi Nemoto 		/* Skip special sections */
18971ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
18982c1a51f3SAtsushi Nemoto 			continue;
1899e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1900e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
190158fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19022c1a51f3SAtsushi Nemoto 	}
1903b39927cfSSam Ravnborg }
19045b24c071SSam Ravnborg 
19055b24c071SSam Ravnborg /**
19065b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19075b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19085b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1909b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19105b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19115b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
191232be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19135b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19145b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19155b24c071SSam Ravnborg  * be discarded and warns about it.
19165b24c071SSam Ravnborg  **/
19175b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
191810668220SSam Ravnborg 			  struct elf_info *elf)
19195b24c071SSam Ravnborg {
19205b24c071SSam Ravnborg 	int i;
19215b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19225b24c071SSam Ravnborg 
19235b24c071SSam Ravnborg 	/* Walk through all sections */
19241ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1925b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19265b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19275b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
192810668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19295b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
193010668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1931b39927cfSSam Ravnborg 	}
1932b39927cfSSam Ravnborg }
1933b39927cfSSam Ravnborg 
19347d02b490SAndi Kleen static char *remove_dot(char *s)
19357d02b490SAndi Kleen {
1936fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19377d02b490SAndi Kleen 
1938fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1939fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1940fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
19417d02b490SAndi Kleen 			s[n] = 0;
19427d02b490SAndi Kleen 	}
19437d02b490SAndi Kleen 	return s;
19447d02b490SAndi Kleen }
19457d02b490SAndi Kleen 
19468b185743SMasahiro Yamada static void read_symbols(const char *modname)
19471da177e4SLinus Torvalds {
19481da177e4SLinus Torvalds 	const char *symname;
19491da177e4SLinus Torvalds 	char *version;
1950b817f6feSSam Ravnborg 	char *license;
19511da177e4SLinus Torvalds 	struct module *mod;
19521da177e4SLinus Torvalds 	struct elf_info info = { };
19531da177e4SLinus Torvalds 	Elf_Sym *sym;
19541da177e4SLinus Torvalds 
195585bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
195685bd2fddSSam Ravnborg 		return;
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds 	mod = new_module(modname);
19591da177e4SLinus Torvalds 
19601da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
19611da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
19621da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
19631da177e4SLinus Torvalds 		have_vmlinux = 1;
19641da177e4SLinus Torvalds 		mod->skip = 1;
19651da177e4SLinus Torvalds 	}
19661da177e4SLinus Torvalds 
1967bca2cceeSMasahiro Yamada 	license = get_modinfo(&info, "license");
1968ba1029c9SRandy Dunlap 	if (!license && !is_vmlinux(modname))
19692fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
1970eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
1971eed7d279SSam Ravnborg 		     "more information\n", modname);
1972b817f6feSSam Ravnborg 	while (license) {
1973b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
1974b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
1975b817f6feSSam Ravnborg 		else {
1976b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
1977b817f6feSSam Ravnborg 			break;
1978b817f6feSSam Ravnborg 		}
1979bca2cceeSMasahiro Yamada 		license = get_next_modinfo(&info, "license", license);
1980b817f6feSSam Ravnborg 	}
1981b817f6feSSam Ravnborg 
19821da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
19837d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
19841da177e4SLinus Torvalds 
19851da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
19861da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
19871da177e4SLinus Torvalds 	}
1988074a04f5SMasahiro Yamada 	if (!is_vmlinux(modname) || vmlinux_section_warnings)
198910668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
19901da177e4SLinus Torvalds 
1991bca2cceeSMasahiro Yamada 	version = get_modinfo(&info, "version");
19921da177e4SLinus Torvalds 	if (version)
19931da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
19941da177e4SLinus Torvalds 				       version - (char *)info.hdr);
19951da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
19961da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
19971da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
19981da177e4SLinus Torvalds 
19991da177e4SLinus Torvalds 	parse_elf_finish(&info);
20001da177e4SLinus Torvalds 
20018c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
20021da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
20031da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
20041da177e4SLinus Torvalds 	 * important anyhow */
20051da177e4SLinus Torvalds 	if (modversions)
20068c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
20071da177e4SLinus Torvalds }
20081da177e4SLinus Torvalds 
2009712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2010712f9b46SRusty Russell {
2011712f9b46SRusty Russell 	FILE *in = stdin;
2012712f9b46SRusty Russell 	char fname[PATH_MAX];
2013712f9b46SRusty Russell 
2014712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2015712f9b46SRusty Russell 		in = fopen(filename, "r");
2016712f9b46SRusty Russell 		if (!in)
2017712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2018712f9b46SRusty Russell 	}
2019712f9b46SRusty Russell 
2020712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2021712f9b46SRusty Russell 		if (strends(fname, "\n"))
2022712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2023712f9b46SRusty Russell 		read_symbols(fname);
2024712f9b46SRusty Russell 	}
2025712f9b46SRusty Russell 
2026712f9b46SRusty Russell 	if (in != stdin)
2027712f9b46SRusty Russell 		fclose(in);
2028712f9b46SRusty Russell }
2029712f9b46SRusty Russell 
20301da177e4SLinus Torvalds #define SZ 500
20311da177e4SLinus Torvalds 
20321da177e4SLinus Torvalds /* We first write the generated file into memory using the
20331da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
20341da177e4SLinus Torvalds  * only update the later if anything changed */
20351da177e4SLinus Torvalds 
20365c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
20375c3ead8cSSam Ravnborg 						      const char *fmt, ...)
20381da177e4SLinus Torvalds {
20391da177e4SLinus Torvalds 	char tmp[SZ];
20401da177e4SLinus Torvalds 	int len;
20411da177e4SLinus Torvalds 	va_list ap;
20421da177e4SLinus Torvalds 
20431da177e4SLinus Torvalds 	va_start(ap, fmt);
20441da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
20457670f023SSam Ravnborg 	buf_write(buf, tmp, len);
20461da177e4SLinus Torvalds 	va_end(ap);
20471da177e4SLinus Torvalds }
20481da177e4SLinus Torvalds 
20495c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
20501da177e4SLinus Torvalds {
20511da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
20527670f023SSam Ravnborg 		buf->size += len + SZ;
20531f3aa900SRandy Dunlap 		buf->p = NOFAIL(realloc(buf->p, buf->size));
20541da177e4SLinus Torvalds 	}
20551da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
20561da177e4SLinus Torvalds 	buf->pos += len;
20571da177e4SLinus Torvalds }
20581da177e4SLinus Torvalds 
2059c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2060c96fca21SSam Ravnborg {
2061c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2062c96fca21SSam Ravnborg 
2063c96fca21SSam Ravnborg 	switch (exp) {
2064c96fca21SSam Ravnborg 	case export_gpl:
2065c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2066c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2067c96fca21SSam Ravnborg 		break;
2068c96fca21SSam Ravnborg 	case export_unused_gpl:
2069c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2070c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2071c96fca21SSam Ravnborg 		break;
2072c96fca21SSam Ravnborg 	case export_gpl_future:
2073c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2074c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2075c96fca21SSam Ravnborg 		break;
2076c96fca21SSam Ravnborg 	case export_plain:
2077c96fca21SSam Ravnborg 	case export_unused:
2078c96fca21SSam Ravnborg 	case export_unknown:
2079c96fca21SSam Ravnborg 		/* ignore */
2080c96fca21SSam Ravnborg 		break;
2081c96fca21SSam Ravnborg 	}
2082c96fca21SSam Ravnborg }
2083c96fca21SSam Ravnborg 
2084c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2085c96fca21SSam Ravnborg {
2086c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2087c96fca21SSam Ravnborg 
2088c96fca21SSam Ravnborg 	switch (exp) {
2089c96fca21SSam Ravnborg 	case export_unused:
2090c96fca21SSam Ravnborg 	case export_unused_gpl:
2091c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2092c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2093c96fca21SSam Ravnborg 		break;
2094c96fca21SSam Ravnborg 	default:
2095c96fca21SSam Ravnborg 		/* ignore */
2096c96fca21SSam Ravnborg 		break;
2097c96fca21SSam Ravnborg 	}
2098c96fca21SSam Ravnborg }
2099c96fca21SSam Ravnborg 
21003b415288SMasahiro Yamada static int check_exports(struct module *mod)
2101b817f6feSSam Ravnborg {
2102b817f6feSSam Ravnborg 	struct symbol *s, *exp;
21033b415288SMasahiro Yamada 	int err = 0;
2104b817f6feSSam Ravnborg 
2105b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21066449bd62SAndrew Morton 		const char *basename;
2107b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
21083b415288SMasahiro Yamada 		if (!exp || exp->module == mod) {
21093b415288SMasahiro Yamada 			if (have_vmlinux && !s->weak) {
21103b415288SMasahiro Yamada 				if (warn_unresolved) {
21113b415288SMasahiro Yamada 					warn("\"%s\" [%s.ko] undefined!\n",
21123b415288SMasahiro Yamada 					     s->name, mod->name);
21133b415288SMasahiro Yamada 				} else {
21143b415288SMasahiro Yamada 					merror("\"%s\" [%s.ko] undefined!\n",
21153b415288SMasahiro Yamada 					       s->name, mod->name);
21163b415288SMasahiro Yamada 					err = 1;
21173b415288SMasahiro Yamada 				}
21183b415288SMasahiro Yamada 			}
2119b817f6feSSam Ravnborg 			continue;
21203b415288SMasahiro Yamada 		}
21216449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2122b817f6feSSam Ravnborg 		if (basename)
2123b817f6feSSam Ravnborg 			basename++;
2124c96fca21SSam Ravnborg 		else
2125c96fca21SSam Ravnborg 			basename = mod->name;
2126c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2127c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2128c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2129b817f6feSSam Ravnborg 	}
21303b415288SMasahiro Yamada 
21313b415288SMasahiro Yamada 	return err;
2132b817f6feSSam Ravnborg }
2133b817f6feSSam Ravnborg 
21344fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
21354fd3e4efSWanlong Gao {
21364fd3e4efSWanlong Gao 	const char *mod_name;
21374fd3e4efSWanlong Gao 
21384fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
21394fd3e4efSWanlong Gao 	if (mod_name == NULL)
21404fd3e4efSWanlong Gao 		mod_name = mod->name;
21414fd3e4efSWanlong Gao 	else
21424fd3e4efSWanlong Gao 		mod_name++;
21434fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
21444fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
21454fd3e4efSWanlong Gao 		return 1;
21464fd3e4efSWanlong Gao 	}
21474fd3e4efSWanlong Gao 
21484fd3e4efSWanlong Gao 	return 0;
21494fd3e4efSWanlong Gao }
21504fd3e4efSWanlong Gao 
21515c3ead8cSSam Ravnborg /**
21525c3ead8cSSam Ravnborg  * Header for the generated file
21535c3ead8cSSam Ravnborg  **/
21545c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
21551da177e4SLinus Torvalds {
21569afb719eSLaura Abbott 	buf_printf(b, "#include <linux/build-salt.h>\n");
21571da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
21581da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
21591da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
21601da177e4SLinus Torvalds 	buf_printf(b, "\n");
21619afb719eSLaura Abbott 	buf_printf(b, "BUILD_SALT;\n");
21629afb719eSLaura Abbott 	buf_printf(b, "\n");
21631da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
21643e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
21651da177e4SLinus Torvalds 	buf_printf(b, "\n");
2166e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
21671da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
21683c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
21691da177e4SLinus Torvalds 	if (mod->has_init)
21703c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
21711da177e4SLinus Torvalds 	if (mod->has_cleanup)
21721da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
21733c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
21741da177e4SLinus Torvalds 			      "#endif\n");
21753c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
21761da177e4SLinus Torvalds 	buf_printf(b, "};\n");
21771da177e4SLinus Torvalds }
21781da177e4SLinus Torvalds 
21792449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
21802449b8baSBen Hutchings {
21812449b8baSBen Hutchings 	if (is_intree)
21822449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
21832449b8baSBen Hutchings }
21842449b8baSBen Hutchings 
2185caf7501aSAndi Kleen /* Cannot check for assembler */
2186caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2187caf7501aSAndi Kleen {
2188*e4f35891SWANG Chao 	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
2189caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2190caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2191caf7501aSAndi Kleen }
2192caf7501aSAndi Kleen 
21935c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2194a9860bf0SGreg Kroah-Hartman {
2195d62c4765SMasahiro Yamada 	if (strstarts(name, "drivers/staging"))
2196a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2197a9860bf0SGreg Kroah-Hartman }
2198a9860bf0SGreg Kroah-Hartman 
21995c3ead8cSSam Ravnborg /**
22005c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
22015c3ead8cSSam Ravnborg  **/
2202c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
22031da177e4SLinus Torvalds {
22041da177e4SLinus Torvalds 	struct symbol *s, *exp;
2205c53ddacdSKirill Korotaev 	int err = 0;
22061da177e4SLinus Torvalds 
22071da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
22081da177e4SLinus Torvalds 		exp = find_symbol(s->name);
22093b415288SMasahiro Yamada 		if (!exp || exp->module == mod)
22101da177e4SLinus Torvalds 			continue;
22111da177e4SLinus Torvalds 		s->module = exp->module;
22121da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
22131da177e4SLinus Torvalds 		s->crc = exp->crc;
22141da177e4SLinus Torvalds 	}
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds 	if (!modversions)
2217c53ddacdSKirill Korotaev 		return err;
22181da177e4SLinus Torvalds 
22191da177e4SLinus Torvalds 	buf_printf(b, "\n");
22201da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
22213ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22221da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
22231da177e4SLinus Torvalds 
22241da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2225df578e7dSSam Ravnborg 		if (!s->module)
22261da177e4SLinus Torvalds 			continue;
22271da177e4SLinus Torvalds 		if (!s->crc_valid) {
2228cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
22291da177e4SLinus Torvalds 				s->name, mod->name);
22301da177e4SLinus Torvalds 			continue;
22311da177e4SLinus Torvalds 		}
22325cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
22335cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
22345cfb203aSTakashi Iwai 			       s->name, mod->name);
22355cfb203aSTakashi Iwai 			err = 1;
22365cfb203aSTakashi Iwai 			break;
22375cfb203aSTakashi Iwai 		}
2238b2c5cdcfSMasahiro Yamada 		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
2239a4b6a77bSJames Hogan 			   s->crc, s->name);
22401da177e4SLinus Torvalds 	}
22411da177e4SLinus Torvalds 
22421da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2243c53ddacdSKirill Korotaev 
2244c53ddacdSKirill Korotaev 	return err;
22451da177e4SLinus Torvalds }
22461da177e4SLinus Torvalds 
2247d2665ca8SMasahiro Yamada static void add_depends(struct buffer *b, struct module *mod)
22481da177e4SLinus Torvalds {
22491da177e4SLinus Torvalds 	struct symbol *s;
22501da177e4SLinus Torvalds 	int first = 1;
22511da177e4SLinus Torvalds 
2252d2665ca8SMasahiro Yamada 	/* Clear ->seen flag of modules that own symbols needed by this. */
2253d2665ca8SMasahiro Yamada 	for (s = mod->unres; s; s = s->next)
2254d2665ca8SMasahiro Yamada 		if (s->module)
2255d2665ca8SMasahiro Yamada 			s->module->seen = is_vmlinux(s->module->name);
22561da177e4SLinus Torvalds 
22571da177e4SLinus Torvalds 	buf_printf(b, "\n");
22581da177e4SLinus Torvalds 	buf_printf(b, "static const char __module_depends[]\n");
22593ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22601da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
22611da177e4SLinus Torvalds 	buf_printf(b, "\"depends=");
22621da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2263a61b2dfdSSam Ravnborg 		const char *p;
22641da177e4SLinus Torvalds 		if (!s->module)
22651da177e4SLinus Torvalds 			continue;
22661da177e4SLinus Torvalds 
22671da177e4SLinus Torvalds 		if (s->module->seen)
22681da177e4SLinus Torvalds 			continue;
22691da177e4SLinus Torvalds 
22701da177e4SLinus Torvalds 		s->module->seen = 1;
2271df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2272df578e7dSSam Ravnborg 		if (p)
2273a61b2dfdSSam Ravnborg 			p++;
2274a61b2dfdSSam Ravnborg 		else
2275a61b2dfdSSam Ravnborg 			p = s->module->name;
2276a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
22771da177e4SLinus Torvalds 		first = 0;
22781da177e4SLinus Torvalds 	}
22791da177e4SLinus Torvalds 	buf_printf(b, "\";\n");
22801da177e4SLinus Torvalds }
22811da177e4SLinus Torvalds 
22825c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
22831da177e4SLinus Torvalds {
22841da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
22851da177e4SLinus Torvalds 		buf_printf(b, "\n");
22861da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
22871da177e4SLinus Torvalds 			   mod->srcversion);
22881da177e4SLinus Torvalds 	}
22891da177e4SLinus Torvalds }
22901da177e4SLinus Torvalds 
22915c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
22921da177e4SLinus Torvalds {
22931da177e4SLinus Torvalds 	char *tmp;
22941da177e4SLinus Torvalds 	FILE *file;
22951da177e4SLinus Torvalds 	struct stat st;
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds 	file = fopen(fname, "r");
22981da177e4SLinus Torvalds 	if (!file)
22991da177e4SLinus Torvalds 		goto write;
23001da177e4SLinus Torvalds 
23011da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
23021da177e4SLinus Torvalds 		goto close_write;
23031da177e4SLinus Torvalds 
23041da177e4SLinus Torvalds 	if (st.st_size != b->pos)
23051da177e4SLinus Torvalds 		goto close_write;
23061da177e4SLinus Torvalds 
23071da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
23081da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
23091da177e4SLinus Torvalds 		goto free_write;
23101da177e4SLinus Torvalds 
23111da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
23121da177e4SLinus Torvalds 		goto free_write;
23131da177e4SLinus Torvalds 
23141da177e4SLinus Torvalds 	free(tmp);
23151da177e4SLinus Torvalds 	fclose(file);
23161da177e4SLinus Torvalds 	return;
23171da177e4SLinus Torvalds 
23181da177e4SLinus Torvalds  free_write:
23191da177e4SLinus Torvalds 	free(tmp);
23201da177e4SLinus Torvalds  close_write:
23211da177e4SLinus Torvalds 	fclose(file);
23221da177e4SLinus Torvalds  write:
23231da177e4SLinus Torvalds 	file = fopen(fname, "w");
23241da177e4SLinus Torvalds 	if (!file) {
23251da177e4SLinus Torvalds 		perror(fname);
23261da177e4SLinus Torvalds 		exit(1);
23271da177e4SLinus Torvalds 	}
23281da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
23291da177e4SLinus Torvalds 		perror(fname);
23301da177e4SLinus Torvalds 		exit(1);
23311da177e4SLinus Torvalds 	}
23321da177e4SLinus Torvalds 	fclose(file);
23331da177e4SLinus Torvalds }
23341da177e4SLinus Torvalds 
2335bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2336534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2337bd5cbcedSRam Pai  **/
2338040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
23391da177e4SLinus Torvalds {
23401da177e4SLinus Torvalds 	unsigned long size, pos = 0;
23411da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
23421da177e4SLinus Torvalds 	char *line;
23431da177e4SLinus Torvalds 
23441da177e4SLinus Torvalds 	if (!file)
23451da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
23461da177e4SLinus Torvalds 		return;
23471da177e4SLinus Torvalds 
23481da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2349534b89a9SSam Ravnborg 		char *symname, *modname, *d, *export, *end;
23501da177e4SLinus Torvalds 		unsigned int crc;
23511da177e4SLinus Torvalds 		struct module *mod;
2352040fcc81SSam Ravnborg 		struct symbol *s;
23531da177e4SLinus Torvalds 
23541da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
23551da177e4SLinus Torvalds 			goto fail;
23561da177e4SLinus Torvalds 		*symname++ = '\0';
23571da177e4SLinus Torvalds 		if (!(modname = strchr(symname, '\t')))
23581da177e4SLinus Torvalds 			goto fail;
23591da177e4SLinus Torvalds 		*modname++ = '\0';
23609ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2361bd5cbcedSRam Pai 			*export++ = '\0';
2362534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2363534b89a9SSam Ravnborg 			*end = '\0';
23641da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
23651da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
23661da177e4SLinus Torvalds 			goto fail;
2367df578e7dSSam Ravnborg 		mod = find_module(modname);
2368df578e7dSSam Ravnborg 		if (!mod) {
2369df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
23701da177e4SLinus Torvalds 				have_vmlinux = 1;
23710fa3a88cSJan Beulich 			mod = new_module(modname);
23721da177e4SLinus Torvalds 			mod->skip = 1;
23731da177e4SLinus Torvalds 		}
2374bd5cbcedSRam Pai 		s = sym_add_exported(symname, mod, export_no(export));
2375040fcc81SSam Ravnborg 		s->kernel    = kernel;
23768e70c458SSam Ravnborg 		s->preloaded = 1;
2377bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
23781da177e4SLinus Torvalds 	}
23792ee41e62SChristian Engelmayer 	release_file(file, size);
23801da177e4SLinus Torvalds 	return;
23811da177e4SLinus Torvalds fail:
23822ee41e62SChristian Engelmayer 	release_file(file, size);
23831da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
23841da177e4SLinus Torvalds }
23851da177e4SLinus Torvalds 
2386040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2387040fcc81SSam Ravnborg  * For external modules only dump symbols
2388040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2389040fcc81SSam Ravnborg  **/
2390040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2391040fcc81SSam Ravnborg {
2392040fcc81SSam Ravnborg 	if (!external_module)
2393040fcc81SSam Ravnborg 		return 1;
2394040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2395040fcc81SSam Ravnborg 		return 0;
2396040fcc81SSam Ravnborg 	return 1;
2397040fcc81SSam Ravnborg }
2398040fcc81SSam Ravnborg 
23995c3ead8cSSam Ravnborg static void write_dump(const char *fname)
24001da177e4SLinus Torvalds {
24011da177e4SLinus Torvalds 	struct buffer buf = { };
24021da177e4SLinus Torvalds 	struct symbol *symbol;
24031da177e4SLinus Torvalds 	int n;
24041da177e4SLinus Torvalds 
24051da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
24061da177e4SLinus Torvalds 		symbol = symbolhash[n];
24071da177e4SLinus Torvalds 		while (symbol) {
2408040fcc81SSam Ravnborg 			if (dump_sym(symbol))
2409bd5cbcedSRam Pai 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
2410040fcc81SSam Ravnborg 					symbol->crc, symbol->name,
2411bd5cbcedSRam Pai 					symbol->module->name,
2412bd5cbcedSRam Pai 					export_str(symbol->export));
24131da177e4SLinus Torvalds 			symbol = symbol->next;
24141da177e4SLinus Torvalds 		}
24151da177e4SLinus Torvalds 	}
24161da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2417c7d47f26SHeinrich Schuchardt 	free(buf.p);
24181da177e4SLinus Torvalds }
24191da177e4SLinus Torvalds 
24202d04b5aeSRichard Hacker struct ext_sym_list {
24212d04b5aeSRichard Hacker 	struct ext_sym_list *next;
24222d04b5aeSRichard Hacker 	const char *file;
24232d04b5aeSRichard Hacker };
24242d04b5aeSRichard Hacker 
24255c3ead8cSSam Ravnborg int main(int argc, char **argv)
24261da177e4SLinus Torvalds {
24271da177e4SLinus Torvalds 	struct module *mod;
24281da177e4SLinus Torvalds 	struct buffer buf = { };
2429040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2430712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
24311da177e4SLinus Torvalds 	int opt;
2432c53ddacdSKirill Korotaev 	int err;
24332d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
24342d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
24351da177e4SLinus Torvalds 
24360987abcbSPaul Walmsley 	while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awE")) != -1) {
24371da177e4SLinus Torvalds 		switch (opt) {
24381da177e4SLinus Torvalds 		case 'i':
2439040fcc81SSam Ravnborg 			kernel_read = optarg;
2440040fcc81SSam Ravnborg 			break;
2441040fcc81SSam Ravnborg 		case 'I':
2442040fcc81SSam Ravnborg 			module_read = optarg;
2443040fcc81SSam Ravnborg 			external_module = 1;
24441da177e4SLinus Torvalds 			break;
24452d04b5aeSRichard Hacker 		case 'e':
24462d04b5aeSRichard Hacker 			external_module = 1;
24472d04b5aeSRichard Hacker 			extsym_iter =
24482d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
24492d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
24502d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
24512d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
24522d04b5aeSRichard Hacker 			break;
24531da177e4SLinus Torvalds 		case 'm':
24541da177e4SLinus Torvalds 			modversions = 1;
24551da177e4SLinus Torvalds 			break;
2456eed380f3SGuenter Roeck 		case 'n':
2457eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2458eed380f3SGuenter Roeck 			break;
24591da177e4SLinus Torvalds 		case 'o':
24601da177e4SLinus Torvalds 			dump_write = optarg;
24611da177e4SLinus Torvalds 			break;
24621da177e4SLinus Torvalds 		case 'a':
24631da177e4SLinus Torvalds 			all_versions = 1;
24641da177e4SLinus Torvalds 			break;
24658d8d8289SSam Ravnborg 		case 's':
24668d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
24678d8d8289SSam Ravnborg 			break;
2468588ccd73SSam Ravnborg 		case 'S':
2469588ccd73SSam Ravnborg 			sec_mismatch_verbose = 0;
2470588ccd73SSam Ravnborg 			break;
2471712f9b46SRusty Russell 		case 'T':
2472712f9b46SRusty Russell 			files_source = optarg;
2473712f9b46SRusty Russell 			break;
2474c53ddacdSKirill Korotaev 		case 'w':
2475c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2476c53ddacdSKirill Korotaev 			break;
247747490ec1SNicolas Boichat 		case 'E':
247847490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
247947490ec1SNicolas Boichat 			break;
24801da177e4SLinus Torvalds 		default:
24811da177e4SLinus Torvalds 			exit(1);
24821da177e4SLinus Torvalds 		}
24831da177e4SLinus Torvalds 	}
24841da177e4SLinus Torvalds 
2485040fcc81SSam Ravnborg 	if (kernel_read)
2486040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2487040fcc81SSam Ravnborg 	if (module_read)
2488040fcc81SSam Ravnborg 		read_dump(module_read, 0);
24892d04b5aeSRichard Hacker 	while (extsym_start) {
24902d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
24912d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
24922d04b5aeSRichard Hacker 		free(extsym_start);
24932d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
24942d04b5aeSRichard Hacker 	}
24951da177e4SLinus Torvalds 
2496df578e7dSSam Ravnborg 	while (optind < argc)
24971da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
24981da177e4SLinus Torvalds 
2499712f9b46SRusty Russell 	if (files_source)
2500712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2501712f9b46SRusty Russell 
2502c53ddacdSKirill Korotaev 	err = 0;
2503c53ddacdSKirill Korotaev 
2504b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2505d93e1719SMathias Krause 		char fname[PATH_MAX];
2506666ab414SAndi Kleen 
2507b817f6feSSam Ravnborg 		if (mod->skip)
2508b817f6feSSam Ravnborg 			continue;
25091da177e4SLinus Torvalds 
25101da177e4SLinus Torvalds 		buf.pos = 0;
25111da177e4SLinus Torvalds 
25124fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
25133b415288SMasahiro Yamada 		err |= check_exports(mod);
25141da177e4SLinus Torvalds 		add_header(&buf, mod);
25152449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2516caf7501aSAndi Kleen 		add_retpoline(&buf);
2517a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2518c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
2519d2665ca8SMasahiro Yamada 		add_depends(&buf, mod);
25201da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
25211da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
25221da177e4SLinus Torvalds 
25231da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
25241da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
25251da177e4SLinus Torvalds 	}
25261da177e4SLinus Torvalds 	if (dump_write)
25271da177e4SLinus Torvalds 		write_dump(dump_write);
252847490ec1SNicolas Boichat 	if (sec_mismatch_count) {
252947490ec1SNicolas Boichat 		if (!sec_mismatch_verbose) {
25307c0ac495SGeert Uytterhoeven 			warn("modpost: Found %d section mismatch(es).\n"
2531e5f95c8bSSam Ravnborg 			     "To see full details build your kernel with:\n"
2532e5f95c8bSSam Ravnborg 			     "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n",
2533e5f95c8bSSam Ravnborg 			     sec_mismatch_count);
253447490ec1SNicolas Boichat 		}
253547490ec1SNicolas Boichat 		if (sec_mismatch_fatal) {
253647490ec1SNicolas Boichat 			fatal("modpost: Section mismatches detected.\n"
253747490ec1SNicolas Boichat 			      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
253847490ec1SNicolas Boichat 		}
253947490ec1SNicolas Boichat 	}
2540c7d47f26SHeinrich Schuchardt 	free(buf.p);
25411da177e4SLinus Torvalds 
2542c53ddacdSKirill Korotaev 	return err;
25431da177e4SLinus Torvalds }
2544