xref: /linux-6.15/scripts/mod/modpost.c (revision 673c2c34)
11da177e4SLinus Torvalds /* Postprocess module symbol versions
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright 2003       Kai Germaschewski
41da177e4SLinus Torvalds  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5df578e7dSSam Ravnborg  * Copyright 2006-2008  Sam Ravnborg
61da177e4SLinus Torvalds  * Based in part on module-init-tools/depmod.c,file2alias
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds  * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Usage: modpost vmlinux module1.o module2.o ...
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
14b2e3e658SMathieu Desnoyers #define _GNU_SOURCE
15b2e3e658SMathieu Desnoyers #include <stdio.h>
161da177e4SLinus Torvalds #include <ctype.h>
175003bab8SAndrew Morton #include <string.h>
18712f9b46SRusty Russell #include <limits.h>
19d4ef1c30SRusty Russell #include <stdbool.h>
20eed380f3SGuenter Roeck #include <errno.h>
211da177e4SLinus Torvalds #include "modpost.h"
225a865c06SLinus Torvalds #include "../../include/generated/autoconf.h"
23b817f6feSSam Ravnborg #include "../../include/linux/license.h"
24b92021b0SRusty Russell #include "../../include/linux/export.h"
259e1b9b80SAlan Jenkins 
261da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
277a3ee753SMathias Krause static int modversions = 0;
281da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
297a3ee753SMathias Krause static int have_vmlinux = 0;
301da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
311da177e4SLinus Torvalds static int all_versions = 0;
32040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
33040fcc81SSam Ravnborg static int external_module = 0;
348d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
358d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
36c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
37c53ddacdSKirill Korotaev static int warn_unresolved = 0;
38bd5cbcedSRam Pai /* How a symbol is exported */
39588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
40588ccd73SSam Ravnborg static int sec_mismatch_verbose = 1;
41eed380f3SGuenter Roeck /* ignore missing files */
42eed380f3SGuenter Roeck static int ignore_missing_files;
43588ccd73SSam Ravnborg 
44c96fca21SSam Ravnborg enum export {
45c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
46c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
47c96fca21SSam Ravnborg };
481da177e4SLinus Torvalds 
496d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
506d9a89eaSAndi Kleen 
516d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
521da177e4SLinus Torvalds {
531da177e4SLinus Torvalds 	va_list arglist;
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 	va_start(arglist, fmt);
581da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
591da177e4SLinus Torvalds 	va_end(arglist);
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	exit(1);
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
646d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds 	va_list arglist;
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	va_start(arglist, fmt);
711da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
721da177e4SLinus Torvalds 	va_end(arglist);
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
756d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
762a116659SMatthew Wilcox {
772a116659SMatthew Wilcox 	va_list arglist;
782a116659SMatthew Wilcox 
792a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
802a116659SMatthew Wilcox 
812a116659SMatthew Wilcox 	va_start(arglist, fmt);
822a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
832a116659SMatthew Wilcox 	va_end(arglist);
842a116659SMatthew Wilcox }
852a116659SMatthew Wilcox 
86d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
87d4ef1c30SRusty Russell {
88d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
89d4ef1c30SRusty Russell 		return false;
90d4ef1c30SRusty Russell 
91d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
92d4ef1c30SRusty Russell }
93d4ef1c30SRusty Russell 
94040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
95040fcc81SSam Ravnborg {
96040fcc81SSam Ravnborg 	const char *myname;
97040fcc81SSam Ravnborg 
98df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
99df578e7dSSam Ravnborg 	if (myname)
100040fcc81SSam Ravnborg 		myname++;
101040fcc81SSam Ravnborg 	else
102040fcc81SSam Ravnborg 		myname = modname;
103040fcc81SSam Ravnborg 
104741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
105741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
106040fcc81SSam Ravnborg }
107040fcc81SSam Ravnborg 
1081da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1091da177e4SLinus Torvalds {
110df578e7dSSam Ravnborg 	if (!ptr)
1111da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
112df578e7dSSam Ravnborg 
1131da177e4SLinus Torvalds 	return ptr;
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds /* A list of all modules we processed */
1171da177e4SLinus Torvalds static struct module *modules;
1181da177e4SLinus Torvalds 
1195c3ead8cSSam Ravnborg static struct module *find_module(char *modname)
1201da177e4SLinus Torvalds {
1211da177e4SLinus Torvalds 	struct module *mod;
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1241da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1251da177e4SLinus Torvalds 			break;
1261da177e4SLinus Torvalds 	return mod;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds 
129d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1301da177e4SLinus Torvalds {
1311da177e4SLinus Torvalds 	struct module *mod;
132d4ef1c30SRusty Russell 	char *p;
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1351da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1361da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 	/* strip trailing .o */
139d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
140d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
141258f7426SFrank Rowand 		mod->is_dot_o = 1;
142258f7426SFrank Rowand 	}
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	/* add to list */
1451da177e4SLinus Torvalds 	mod->name = p;
146b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1471da177e4SLinus Torvalds 	mod->next = modules;
1481da177e4SLinus Torvalds 	modules = mod;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	return mod;
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds /* A hash of all exported symbols,
1541da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds struct symbol {
1591da177e4SLinus Torvalds 	struct symbol *next;
1601da177e4SLinus Torvalds 	struct module *module;
1611da177e4SLinus Torvalds 	unsigned int crc;
1621da177e4SLinus Torvalds 	int crc_valid;
1631da177e4SLinus Torvalds 	unsigned int weak:1;
164040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
165040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
166040fcc81SSam Ravnborg 				    *  (only for external modules) **/
167b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
168bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1691da177e4SLinus Torvalds 	char name[0];
1701da177e4SLinus Torvalds };
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1751da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1781da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1811da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1821da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds 
1875c3ead8cSSam Ravnborg /**
1885c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1895c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1905c3ead8cSSam Ravnborg  **/
1915c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1925c3ead8cSSam Ravnborg 				   struct symbol *next)
1931da177e4SLinus Torvalds {
1941da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
1971da177e4SLinus Torvalds 	strcpy(s->name, name);
1981da177e4SLinus Torvalds 	s->weak = weak;
1991da177e4SLinus Torvalds 	s->next = next;
2001da177e4SLinus Torvalds 	return s;
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds /* For the hash of exported symbols */
204bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
205bd5cbcedSRam Pai 				 enum export export)
2061da177e4SLinus Torvalds {
2071da177e4SLinus Torvalds 	unsigned int hash;
2081da177e4SLinus Torvalds 	struct symbol *new;
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2111da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2121da177e4SLinus Torvalds 	new->module = module;
213bd5cbcedSRam Pai 	new->export = export;
214040fcc81SSam Ravnborg 	return new;
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds 
2175c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2181da177e4SLinus Torvalds {
2191da177e4SLinus Torvalds 	struct symbol *s;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2221da177e4SLinus Torvalds 	if (name[0] == '.')
2231da177e4SLinus Torvalds 		name++;
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2261da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2271da177e4SLinus Torvalds 			return s;
2281da177e4SLinus Torvalds 	}
2291da177e4SLinus Torvalds 	return NULL;
2301da177e4SLinus Torvalds }
2311da177e4SLinus Torvalds 
2327a3ee753SMathias Krause static const struct {
233bd5cbcedSRam Pai 	const char *str;
234bd5cbcedSRam Pai 	enum export export;
235bd5cbcedSRam Pai } export_list[] = {
236bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
237c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
238bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
239c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
240bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
241bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
242bd5cbcedSRam Pai };
243bd5cbcedSRam Pai 
244bd5cbcedSRam Pai 
245bd5cbcedSRam Pai static const char *export_str(enum export ex)
246bd5cbcedSRam Pai {
247bd5cbcedSRam Pai 	return export_list[ex].str;
248bd5cbcedSRam Pai }
249bd5cbcedSRam Pai 
250bd5cbcedSRam Pai static enum export export_no(const char *s)
251bd5cbcedSRam Pai {
252bd5cbcedSRam Pai 	int i;
253df578e7dSSam Ravnborg 
254534b89a9SSam Ravnborg 	if (!s)
255534b89a9SSam Ravnborg 		return export_unknown;
256bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
257bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
258bd5cbcedSRam Pai 			return export_list[i].export;
259bd5cbcedSRam Pai 	}
260bd5cbcedSRam Pai 	return export_unknown;
261bd5cbcedSRam Pai }
262bd5cbcedSRam Pai 
26362a26356SAlessio Igor Bogani static const char *sec_name(struct elf_info *elf, int secindex);
26462a26356SAlessio Igor Bogani 
26562a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
26662a26356SAlessio Igor Bogani 
26762a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
26862a26356SAlessio Igor Bogani {
26962a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
27062a26356SAlessio Igor Bogani 
27162a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
27262a26356SAlessio Igor Bogani 		return export_plain;
27362a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
27462a26356SAlessio Igor Bogani 		return export_unused;
27562a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
27662a26356SAlessio Igor Bogani 		return export_gpl;
27762a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
27862a26356SAlessio Igor Bogani 		return export_unused_gpl;
27962a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
28062a26356SAlessio Igor Bogani 		return export_gpl_future;
28162a26356SAlessio Igor Bogani 	else
28262a26356SAlessio Igor Bogani 		return export_unknown;
28362a26356SAlessio Igor Bogani }
28462a26356SAlessio Igor Bogani 
2851ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
286bd5cbcedSRam Pai {
287bd5cbcedSRam Pai 	if (sec == elf->export_sec)
288bd5cbcedSRam Pai 		return export_plain;
289c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
290c96fca21SSam Ravnborg 		return export_unused;
291bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
292bd5cbcedSRam Pai 		return export_gpl;
293c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
294c96fca21SSam Ravnborg 		return export_unused_gpl;
295bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
296bd5cbcedSRam Pai 		return export_gpl_future;
297bd5cbcedSRam Pai 	else
298bd5cbcedSRam Pai 		return export_unknown;
299bd5cbcedSRam Pai }
300bd5cbcedSRam Pai 
3015c3ead8cSSam Ravnborg /**
3025c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3035c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3045c3ead8cSSam Ravnborg  **/
305bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod,
306bd5cbcedSRam Pai 				       enum export export)
3071da177e4SLinus Torvalds {
3081da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	if (!s) {
311bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3128e70c458SSam Ravnborg 	} else {
3138e70c458SSam Ravnborg 		if (!s->preloaded) {
3147b75b13cSSam Ravnborg 			warn("%s: '%s' exported twice. Previous export "
3158e70c458SSam Ravnborg 			     "was in %s%s\n", mod->name, name,
3168e70c458SSam Ravnborg 			     s->module->name,
3178e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ?"":".ko");
3184b21960fSTrent Piepho 		} else {
319baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3204b21960fSTrent Piepho 			s->module = mod;
3211da177e4SLinus Torvalds 		}
3221da177e4SLinus Torvalds 	}
3238e70c458SSam Ravnborg 	s->preloaded = 0;
324040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
325040fcc81SSam Ravnborg 	s->kernel    = 0;
326bd5cbcedSRam Pai 	s->export    = export;
327040fcc81SSam Ravnborg 	return s;
3281da177e4SLinus Torvalds }
3291da177e4SLinus Torvalds 
330040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
331bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
332040fcc81SSam Ravnborg {
333040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
334040fcc81SSam Ravnborg 
335b6568b1aSRusty Russell 	if (!s) {
336bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
337b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
338b6568b1aSRusty Russell 		s->preloaded = 1;
339b6568b1aSRusty Russell 	}
340040fcc81SSam Ravnborg 	s->crc = crc;
3411da177e4SLinus Torvalds 	s->crc_valid = 1;
3421da177e4SLinus Torvalds }
3431da177e4SLinus Torvalds 
3445c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
3451da177e4SLinus Torvalds {
3461da177e4SLinus Torvalds 	struct stat st;
347eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
3481da177e4SLinus Torvalds 	int fd;
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
351eb3d5cc6SJesper Juhl 	if (fd < 0)
3521da177e4SLinus Torvalds 		return NULL;
353eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
354eb3d5cc6SJesper Juhl 		goto failed;
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 	*size = st.st_size;
3571da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
3581da177e4SLinus Torvalds 
359eb3d5cc6SJesper Juhl failed:
360eb3d5cc6SJesper Juhl 	close(fd);
3611da177e4SLinus Torvalds 	if (map == MAP_FAILED)
3621da177e4SLinus Torvalds 		return NULL;
3631da177e4SLinus Torvalds 	return map;
3641da177e4SLinus Torvalds }
3651da177e4SLinus Torvalds 
3665c3ead8cSSam Ravnborg /**
3675c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
3685c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
3695c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
3705c3ead8cSSam Ravnborg   **/
3715c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
3721da177e4SLinus Torvalds {
3731da177e4SLinus Torvalds 	static char line[4096];
3741da177e4SLinus Torvalds 	int skip = 1;
3751da177e4SLinus Torvalds 	size_t len = 0;
3761da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
3771da177e4SLinus Torvalds 	char *s = line;
3781da177e4SLinus Torvalds 
379df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
3801da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
3811da177e4SLinus Torvalds 			p++;
3821da177e4SLinus Torvalds 			continue;
3831da177e4SLinus Torvalds 		}
3841da177e4SLinus Torvalds 		skip = 0;
3851da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
3861da177e4SLinus Torvalds 			len++;
3871da177e4SLinus Torvalds 			*s++ = *p++;
3881da177e4SLinus Torvalds 			if (len > 4095)
3891da177e4SLinus Torvalds 				break; /* Too long, stop */
3901da177e4SLinus Torvalds 		} else {
3911da177e4SLinus Torvalds 			/* End of string */
3921da177e4SLinus Torvalds 			*s = '\0';
3931da177e4SLinus Torvalds 			return line;
3941da177e4SLinus Torvalds 		}
3951da177e4SLinus Torvalds 	}
3961da177e4SLinus Torvalds 	/* End of buffer */
3971da177e4SLinus Torvalds 	return NULL;
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
4005c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4011da177e4SLinus Torvalds {
4021da177e4SLinus Torvalds 	munmap(file, size);
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds 
40585bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4061da177e4SLinus Torvalds {
4071da177e4SLinus Torvalds 	unsigned int i;
40885bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4091da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4101da177e4SLinus Torvalds 	Elf_Sym  *sym;
4111ce53adfSDenys Vlasenko 	const char *secstrings;
4121ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4151da177e4SLinus Torvalds 	if (!hdr) {
416eed380f3SGuenter Roeck 		if (ignore_missing_files) {
417eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
418eed380f3SGuenter Roeck 				strerror(errno));
419eed380f3SGuenter Roeck 			return 0;
420eed380f3SGuenter Roeck 		}
4211da177e4SLinus Torvalds 		perror(filename);
4226803dc0eSSam Ravnborg 		exit(1);
4231da177e4SLinus Torvalds 	}
4241da177e4SLinus Torvalds 	info->hdr = hdr;
42585bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
42685bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
42785bd2fddSSam Ravnborg 		return 0;
42885bd2fddSSam Ravnborg 	}
42985bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
43085bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
43185bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
43285bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
43385bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
43485bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
43585bd2fddSSam Ravnborg 		return 0;
43685bd2fddSSam Ravnborg 	}
4371da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
438ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
4397d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
4407d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
4417d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
4427d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
4437d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
4447d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
4457d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
4467d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
4477d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
4487d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
4497d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
4507d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
4511da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
4521da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
4531da177e4SLinus Torvalds 
454a83710e5SPetr Stetiar 	/* Check if file offset is correct */
455a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
456df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
457df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
458df578e7dSSam Ravnborg 		      filename, info->size);
459a83710e5SPetr Stetiar 		return 0;
460a83710e5SPetr Stetiar 	}
461a83710e5SPetr Stetiar 
4626845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
4631ce53adfSDenys Vlasenko 		/*
4641ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
4651ce53adfSDenys Vlasenko 		 * read count from .sh_size.
4661ce53adfSDenys Vlasenko 		 */
4671ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
4681ce53adfSDenys Vlasenko 	}
4691ce53adfSDenys Vlasenko 	else {
4701ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
4711ce53adfSDenys Vlasenko 	}
4721ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
4736845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
4741ce53adfSDenys Vlasenko 	}
4751ce53adfSDenys Vlasenko 	else {
4761ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
4771ce53adfSDenys Vlasenko 	}
4781ce53adfSDenys Vlasenko 
4791da177e4SLinus Torvalds 	/* Fix endianness in section headers */
4801ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
4817d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
4821da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
4837d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
4847d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
4851da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
4861da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
4871da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
488ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
4897d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
4907d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
4911da177e4SLinus Torvalds 	}
4921da177e4SLinus Torvalds 	/* Find symbol table. */
4931ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
4941ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
495bd5cbcedSRam Pai 		const char *secname;
49656fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
4971da177e4SLinus Torvalds 
49856fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
499df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
500df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
501df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
502df578e7dSSam Ravnborg 			      sizeof(*hdr));
50385bd2fddSSam Ravnborg 			return 0;
50485bd2fddSSam Ravnborg 		}
505bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
506bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
50756fc82c5STejun Heo 			if (nobits)
50856fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5091da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5101da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
511bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
512bd5cbcedSRam Pai 			info->export_sec = i;
513c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
514c96fca21SSam Ravnborg 			info->export_unused_sec = i;
515bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
516bd5cbcedSRam Pai 			info->export_gpl_sec = i;
517c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
518c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
519bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
520bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
521bd5cbcedSRam Pai 
5221ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5231ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
5241ce53adfSDenys Vlasenko 			symtab_idx = i;
5251ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
5261ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5271ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
5281ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5296845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
5301da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
5311ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
5321ce53adfSDenys Vlasenko 		}
5331ce53adfSDenys Vlasenko 
5341ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
5351ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
5361ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
5371ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
5381ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5391ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
5401ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5411ce53adfSDenys Vlasenko 		}
5421da177e4SLinus Torvalds 	}
543df578e7dSSam Ravnborg 	if (!info->symtab_start)
544cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
545df578e7dSSam Ravnborg 
5461da177e4SLinus Torvalds 	/* Fix endianness in symbols */
5471da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
5481da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
5491da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
5501da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
5511da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
5521da177e4SLinus Torvalds 	}
5531ce53adfSDenys Vlasenko 
5541ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
5551ce53adfSDenys Vlasenko 		Elf32_Word *p;
5566845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
5571ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
5586845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
5591ce53adfSDenys Vlasenko 			      symtab_idx);
5601ce53adfSDenys Vlasenko 		/* Fix endianness */
5611ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
5621ce53adfSDenys Vlasenko 		     p++)
5631ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
5641ce53adfSDenys Vlasenko 	}
5651ce53adfSDenys Vlasenko 
56685bd2fddSSam Ravnborg 	return 1;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds 
5695c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
5701da177e4SLinus Torvalds {
5711da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
5721da177e4SLinus Torvalds }
5731da177e4SLinus Torvalds 
5744d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
5754d7365d6SSam Ravnborg {
5764d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
577b92021b0SRusty Russell 	if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0)
5784d7365d6SSam Ravnborg 		return 1;
5794d7365d6SSam Ravnborg 	/* ignore global offset table */
5804d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
5814d7365d6SSam Ravnborg 		return 1;
5824d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
5834d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
5844d7365d6SSam Ravnborg 		if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 ||
5854d7365d6SSam Ravnborg 		    strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 ||
5864d7365d6SSam Ravnborg 		    strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 ||
5878fe9c93eSAndreas Schwab 		    strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 ||
5888fe9c93eSAndreas Schwab 		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
5898fe9c93eSAndreas Schwab 		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
5904d7365d6SSam Ravnborg 			return 1;
5917fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
5927fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
5937fca5dc8SStephen Rothwell 		if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
5948fe9c93eSAndreas Schwab 		    strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
5958fe9c93eSAndreas Schwab 		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
5968fe9c93eSAndreas Schwab 		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
5977fca5dc8SStephen Rothwell 			return 1;
5984d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
5994d7365d6SSam Ravnborg 	return 0;
6004d7365d6SSam Ravnborg }
6014d7365d6SSam Ravnborg 
602b92021b0SRusty Russell #define CRC_PFX     VMLINUX_SYMBOL_STR(__crc_)
603b92021b0SRusty Russell #define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_)
6041da177e4SLinus Torvalds 
6055c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6061da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6071da177e4SLinus Torvalds {
6081da177e4SLinus Torvalds 	unsigned int crc;
60962a26356SAlessio Igor Bogani 	enum export export;
61062a26356SAlessio Igor Bogani 
611258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
612258f7426SFrank Rowand 	    strncmp(symname, "__ksymtab", 9) == 0)
61362a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
61462a26356SAlessio Igor Bogani 	else
61562a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 	/* CRC'd symbol */
6188d99513cSMichal Marek 	if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
6191da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
620bd5cbcedSRam Pai 		sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
621bd5cbcedSRam Pai 				export);
6221da177e4SLinus Torvalds 	}
623b5064654SAndi Kleen 
624b5064654SAndi Kleen 	switch (sym->st_shndx) {
625b5064654SAndi Kleen 	case SHN_COMMON:
626ef178f92SAndi Kleen 		if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) {
627ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
628ef178f92SAndi Kleen 		} else
629b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
6301da177e4SLinus Torvalds 		break;
6311da177e4SLinus Torvalds 	case SHN_UNDEF:
6321da177e4SLinus Torvalds 		/* undefined symbol */
6331da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
6341da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
6351da177e4SLinus Torvalds 			break;
6364d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
6371da177e4SLinus Torvalds 			break;
6388d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
6398d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
6408d529014SBen Colline /* add compatibility with older glibc */
6418d529014SBen Colline #ifndef STT_SPARC_REGISTER
6428d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
6438d529014SBen Colline #endif
6441da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
6451da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
6461da177e4SLinus Torvalds 			/* Ignore register directives. */
6478d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
6481da177e4SLinus Torvalds 				break;
6497caaeabbSAl Viro 			if (symname[0] == '.') {
6507caaeabbSAl Viro 				char *munged = strdup(symname);
6517caaeabbSAl Viro 				munged[0] = '_';
6527caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
6537caaeabbSAl Viro 				symname = munged;
6547caaeabbSAl Viro 			}
6551da177e4SLinus Torvalds 		}
6561da177e4SLinus Torvalds #endif
6571da177e4SLinus Torvalds 
658b92021b0SRusty Russell #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
659b92021b0SRusty Russell 		if (symname[0] != '_')
660b92021b0SRusty Russell 			break;
661b92021b0SRusty Russell 		else
662b92021b0SRusty Russell 			symname++;
663b92021b0SRusty Russell #endif
664b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
6651da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
6661da177e4SLinus Torvalds 					  mod->unres);
6671da177e4SLinus Torvalds 		break;
6681da177e4SLinus Torvalds 	default:
6691da177e4SLinus Torvalds 		/* All exported symbols */
6708d99513cSMichal Marek 		if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
671bd5cbcedSRam Pai 			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
672bd5cbcedSRam Pai 					export);
6731da177e4SLinus Torvalds 		}
674b92021b0SRusty Russell 		if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0)
6751da177e4SLinus Torvalds 			mod->has_init = 1;
676b92021b0SRusty Russell 		if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0)
6771da177e4SLinus Torvalds 			mod->has_cleanup = 1;
6781da177e4SLinus Torvalds 		break;
6791da177e4SLinus Torvalds 	}
6801da177e4SLinus Torvalds }
6811da177e4SLinus Torvalds 
6825c3ead8cSSam Ravnborg /**
6835c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
6845c3ead8cSSam Ravnborg  **/
6851da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
6861da177e4SLinus Torvalds {
6871da177e4SLinus Torvalds 	/* Skip non-zero chars */
6881da177e4SLinus Torvalds 	while (string[0]) {
6891da177e4SLinus Torvalds 		string++;
6901da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
6911da177e4SLinus Torvalds 			return NULL;
6921da177e4SLinus Torvalds 	}
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	/* Skip any zero padding. */
6951da177e4SLinus Torvalds 	while (!string[0]) {
6961da177e4SLinus Torvalds 		string++;
6971da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
6981da177e4SLinus Torvalds 			return NULL;
6991da177e4SLinus Torvalds 	}
7001da177e4SLinus Torvalds 	return string;
7011da177e4SLinus Torvalds }
7021da177e4SLinus Torvalds 
703b817f6feSSam Ravnborg static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
704b817f6feSSam Ravnborg 			      const char *tag, char *info)
7051da177e4SLinus Torvalds {
7061da177e4SLinus Torvalds 	char *p;
7071da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
7081da177e4SLinus Torvalds 	unsigned long size = modinfo_len;
7091da177e4SLinus Torvalds 
710b817f6feSSam Ravnborg 	if (info) {
711b817f6feSSam Ravnborg 		size -= info - (char *)modinfo;
712b817f6feSSam Ravnborg 		modinfo = next_string(info, &size);
713b817f6feSSam Ravnborg 	}
714b817f6feSSam Ravnborg 
7151da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
7161da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7171da177e4SLinus Torvalds 			return p + taglen + 1;
7181da177e4SLinus Torvalds 	}
7191da177e4SLinus Torvalds 	return NULL;
7201da177e4SLinus Torvalds }
7211da177e4SLinus Torvalds 
722b817f6feSSam Ravnborg static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
723b817f6feSSam Ravnborg 			 const char *tag)
724b817f6feSSam Ravnborg 
725b817f6feSSam Ravnborg {
726b817f6feSSam Ravnborg 	return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
727b817f6feSSam Ravnborg }
728b817f6feSSam Ravnborg 
72993684d3bSSam Ravnborg /**
7304c8fbca5SSam Ravnborg  * Test if string s ends in string sub
7314c8fbca5SSam Ravnborg  * return 0 if match
7324c8fbca5SSam Ravnborg  **/
7334c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
7344c8fbca5SSam Ravnborg {
7354c8fbca5SSam Ravnborg 	int slen, sublen;
7364c8fbca5SSam Ravnborg 
7374c8fbca5SSam Ravnborg 	if (!s || !sub)
7384c8fbca5SSam Ravnborg 		return 1;
7394c8fbca5SSam Ravnborg 
7404c8fbca5SSam Ravnborg 	slen = strlen(s);
7414c8fbca5SSam Ravnborg 	sublen = strlen(sub);
7424c8fbca5SSam Ravnborg 
7434c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
7444c8fbca5SSam Ravnborg 		return 1;
7454c8fbca5SSam Ravnborg 
7464c8fbca5SSam Ravnborg 	if (sublen > slen)
7474c8fbca5SSam Ravnborg 		return 1;
7484c8fbca5SSam Ravnborg 
7494c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
7504c8fbca5SSam Ravnborg }
7514c8fbca5SSam Ravnborg 
752ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
753ff13f926SSam Ravnborg {
75458fb0d4fSSam Ravnborg 	if (sym)
755ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
75658fb0d4fSSam Ravnborg 	else
757f666751aSSam Ravnborg 		return "(unknown)";
758ff13f926SSam Ravnborg }
759ff13f926SSam Ravnborg 
7601ce53adfSDenys Vlasenko static const char *sec_name(struct elf_info *elf, int secindex)
761ff13f926SSam Ravnborg {
762ff13f926SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
763ff13f926SSam Ravnborg 	return (void *)elf->hdr +
7641ce53adfSDenys Vlasenko 		elf->sechdrs[elf->secindex_strings].sh_offset +
7651ce53adfSDenys Vlasenko 		sechdrs[secindex].sh_name;
766ff13f926SSam Ravnborg }
767ff13f926SSam Ravnborg 
768ff13f926SSam Ravnborg static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
769ff13f926SSam Ravnborg {
770ff13f926SSam Ravnborg 	return (void *)elf->hdr +
7711ce53adfSDenys Vlasenko 		elf->sechdrs[elf->secindex_strings].sh_offset +
772ff13f926SSam Ravnborg 		sechdr->sh_name;
773ff13f926SSam Ravnborg }
774ff13f926SSam Ravnborg 
77510668220SSam Ravnborg /* The pattern is an array of simple patterns.
77610668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
7776c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
77810668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
77909c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
78010668220SSam Ravnborg  */
7815c725138STrevor Keith static int match(const char *sym, const char * const pat[])
78210668220SSam Ravnborg {
78310668220SSam Ravnborg 	const char *p;
78410668220SSam Ravnborg 	while (*pat) {
78510668220SSam Ravnborg 		p = *pat++;
78610668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
78710668220SSam Ravnborg 
78809c20c03SPaul Gortmaker 		/* "*foo*" */
78909c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
79009c20c03SPaul Gortmaker 			char *here, *bare = strndup(p + 1, strlen(p) - 2);
79109c20c03SPaul Gortmaker 
79209c20c03SPaul Gortmaker 			here = strstr(sym, bare);
79309c20c03SPaul Gortmaker 			free(bare);
79409c20c03SPaul Gortmaker 			if (here != NULL)
79509c20c03SPaul Gortmaker 				return 1;
79609c20c03SPaul Gortmaker 		}
7976c5bd235SSam Ravnborg 		/* "*foo" */
79809c20c03SPaul Gortmaker 		else if (*p == '*') {
7996c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8006c5bd235SSam Ravnborg 				return 1;
8016c5bd235SSam Ravnborg 		}
80210668220SSam Ravnborg 		/* "foo*" */
8036c5bd235SSam Ravnborg 		else if (*endp == '*') {
80410668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
80510668220SSam Ravnborg 				return 1;
80610668220SSam Ravnborg 		}
80710668220SSam Ravnborg 		/* no wildcards */
80810668220SSam Ravnborg 		else {
80910668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
81010668220SSam Ravnborg 				return 1;
81110668220SSam Ravnborg 		}
81210668220SSam Ravnborg 	}
81310668220SSam Ravnborg 	/* no match */
81410668220SSam Ravnborg 	return 0;
81510668220SSam Ravnborg }
81610668220SSam Ravnborg 
81710668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8187a3ee753SMathias Krause static const char *const section_white_list[] =
8194391ed6aSSam Ravnborg {
8204391ed6aSSam Ravnborg 	".comment*",
8214391ed6aSSam Ravnborg 	".debug*",
8224d10c223SChen Gang 	".cranges",		/* sh64 */
8231121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
824019fca84SDavid Howells 	".GCC-command-line",	/* mn10300 */
82576b27645SJonathan Kliegman 	".GCC.command.line",	/* record-gcc-switches, non mn10300 */
8264391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8274391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8284391ed6aSSam Ravnborg 	".stab*",
8294391ed6aSSam Ravnborg 	".note*",
8304391ed6aSSam Ravnborg 	".got*",
8314391ed6aSSam Ravnborg 	".toc*",
832af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
833af42e970SMax Filippov 	".xt.lit",         /* xtensa */
834f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
835f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
836ef178f92SAndi Kleen 	".gnu.lto*",
8374391ed6aSSam Ravnborg 	NULL
8384391ed6aSSam Ravnborg };
83910668220SSam Ravnborg 
840e241a630SSam Ravnborg /*
841b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
842e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
843b614a697SAnders Kaseorg  * without "ax" / "aw".
844e241a630SSam Ravnborg  */
845b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
846b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
847e241a630SSam Ravnborg {
848b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
849e241a630SSam Ravnborg 
850b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
851b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
852b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
853b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
854b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
855e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
856e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
857e241a630SSam Ravnborg 		     modname, sec);
858e241a630SSam Ravnborg 	}
859e241a630SSam Ravnborg }
860e241a630SSam Ravnborg 
861e241a630SSam Ravnborg 
862e241a630SSam Ravnborg 
863eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
864a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
865a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
866eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
867a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
86810668220SSam Ravnborg 
869eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
870a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
871eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
872a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
87310668220SSam Ravnborg 
874bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
875a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
876a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
877a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
878bb15d8dbSSebastian Andrzej Siewior 
879e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
880e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
8814a31a229SUwe Kleine-König 
8824a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
8834a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
88410668220SSam Ravnborg 
885a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
886157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
887157d1972SQuentin Casasnovas 		".kprobes.text"
88852dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
889*673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
890*673c2c34SChris Metcalf 		".coldtext"
89110668220SSam Ravnborg 
892fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
893fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
894eb8f6890SSam Ravnborg 
895fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
896fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
897eb8f6890SSam Ravnborg 
89852dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
89952dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
90052dc0595SQuentin Casasnovas 
9016c5bd235SSam Ravnborg /* init data sections */
9027a3ee753SMathias Krause static const char *const init_data_sections[] =
9037a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9046c5bd235SSam Ravnborg 
9056c5bd235SSam Ravnborg /* all init sections */
9067a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9076c5bd235SSam Ravnborg 
9086c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9097a3ee753SMathias Krause static const char *const init_exit_sections[] =
910eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9116c5bd235SSam Ravnborg 
9124a3893d0SPaul Gortmaker /* all text sections */
9134a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9144a3893d0SPaul Gortmaker 
9156c5bd235SSam Ravnborg /* data section */
9167a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9176c5bd235SSam Ravnborg 
9186c5bd235SSam Ravnborg 
9196c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
920af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
921af92a82dSUwe Kleine-König 	"*driver",							\
922af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
923af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
924af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
925af92a82dSUwe Kleine-König 	"*_ops",							\
926af92a82dSUwe Kleine-König 	"*_probe",							\
927af92a82dSUwe Kleine-König 	"*_probe_one",							\
928af92a82dSUwe Kleine-König 	"*_console"
9296c5bd235SSam Ravnborg 
9307a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
9317a3ee753SMathias Krause static const char *const linker_symbols[] =
9326c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
9334a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
9346c5bd235SSam Ravnborg 
935588ccd73SSam Ravnborg enum mismatch {
936bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
937bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
938bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
939bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
940bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
941bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
942bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
943bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
944588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
94552dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
946588ccd73SSam Ravnborg };
947588ccd73SSam Ravnborg 
948e5d8f59aSQuentin Casasnovas /**
949e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
950e5d8f59aSQuentin Casasnovas  *
951e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
952e5d8f59aSQuentin Casasnovas  *
953e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
954e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
955e5d8f59aSQuentin Casasnovas  *
956e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
957e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
958e5d8f59aSQuentin Casasnovas  *
959e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
960e5d8f59aSQuentin Casasnovas  *
961e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
962e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
963e5d8f59aSQuentin Casasnovas  *
964e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
965e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
966e5d8f59aSQuentin Casasnovas  *
967e5d8f59aSQuentin Casasnovas  */
96810668220SSam Ravnborg struct sectioncheck {
96910668220SSam Ravnborg 	const char *fromsec[20];
970050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
971050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
972588ccd73SSam Ravnborg 	enum mismatch mismatch;
973af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
974644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
975644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
976644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
977644e8f14SQuentin Casasnovas 
97810668220SSam Ravnborg };
97910668220SSam Ravnborg 
98052dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
98152dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
98252dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
98352dc0595SQuentin Casasnovas 				     const char *fromsec);
98452dc0595SQuentin Casasnovas 
9857a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
98610668220SSam Ravnborg /* Do not reference init/exit code/data from
98710668220SSam Ravnborg  * normal code and data
98810668220SSam Ravnborg  */
98910668220SSam Ravnborg {
990588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
991050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
992bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
993af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
994588ccd73SSam Ravnborg },
995588ccd73SSam Ravnborg {
996588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
997050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
998bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
999af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1000588ccd73SSam Ravnborg },
1001588ccd73SSam Ravnborg {
10020db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1003050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10040db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10050db25245SUwe Kleine-König 	.symbol_white_list = {
10060db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10070db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10080db25245SUwe Kleine-König 	},
10090db25245SUwe Kleine-König },
10100db25245SUwe Kleine-König {
1011588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1012050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1013bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1014af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1015588ccd73SSam Ravnborg },
1016588ccd73SSam Ravnborg {
1017588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1018050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1019bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1020af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1021eb8f6890SSam Ravnborg },
1022e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1023eb8f6890SSam Ravnborg {
10244a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1025050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1026bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1027af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1028eb8f6890SSam Ravnborg },
1029e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1030eb8f6890SSam Ravnborg {
10314a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1032050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1033bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1034af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
103510668220SSam Ravnborg },
103610668220SSam Ravnborg /* Do not use exit code/data from init code */
103710668220SSam Ravnborg {
1038eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1039050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1040bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1041af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
104210668220SSam Ravnborg },
104310668220SSam Ravnborg /* Do not use init code/data from exit code */
104410668220SSam Ravnborg {
1045eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1046050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1047bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1048af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
104910668220SSam Ravnborg },
1050bb15d8dbSSebastian Andrzej Siewior {
1051bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1052050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1053bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1054bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1055bb15d8dbSSebastian Andrzej Siewior },
105610668220SSam Ravnborg /* Do not export init/exit functions or data */
105710668220SSam Ravnborg {
105810668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1059050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1060af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1061af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
106252dc0595SQuentin Casasnovas },
106352dc0595SQuentin Casasnovas {
106452dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
106552dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
106652dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
106752dc0595SQuentin Casasnovas 	 */
106852dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
106952dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
107052dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
107152dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
107210668220SSam Ravnborg }
107310668220SSam Ravnborg };
107410668220SSam Ravnborg 
10750d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
10760d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
107710668220SSam Ravnborg {
107810668220SSam Ravnborg 	int i;
107910668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
108010668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
108110668220SSam Ravnborg 
1082c5c3439aSQuentin Casasnovas 	/*
1083c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1084c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1085c5c3439aSQuentin Casasnovas 	 * doesn't make much sense and causes build failures on parisc and
1086c5c3439aSQuentin Casasnovas 	 * mn10300 architectures.
1087c5c3439aSQuentin Casasnovas 	 */
1088c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1089c5c3439aSQuentin Casasnovas 		return NULL;
1090c5c3439aSQuentin Casasnovas 
109110668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1092050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1093050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
10940d2a636eSUwe Kleine-König 				return check;
1095050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1096050e57fdSQuentin Casasnovas 				return check;
1097050e57fdSQuentin Casasnovas 		}
109810668220SSam Ravnborg 		check++;
109910668220SSam Ravnborg 	}
11000d2a636eSUwe Kleine-König 	return NULL;
110110668220SSam Ravnborg }
110210668220SSam Ravnborg 
11034c8fbca5SSam Ravnborg /**
11044c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11050e0d314eSSam Ravnborg  *
11064c8fbca5SSam Ravnborg  * Pattern 1:
11074c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11084c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11094c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11104c8fbca5SSam Ravnborg  *   this pattern.
11114c8fbca5SSam Ravnborg  *   The pattern is identified by:
11124c8fbca5SSam Ravnborg  *   tosec   = .init.data
11139209aed0SSam Ravnborg  *   fromsec = .data*
11144c8fbca5SSam Ravnborg  *   atsym   =__param*
11154c8fbca5SSam Ravnborg  *
11166a841528SRusty Russell  * Pattern 1a:
11176a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11186a841528SRusty Russell  *   The pattern is identified by:
11196a841528SRusty Russell  *   tosec   = .init.text
11206a841528SRusty Russell  *   fromsec = .data*
11216a841528SRusty Russell  *   atsym   = __param_ops_*
11226a841528SRusty Russell  *
11234c8fbca5SSam Ravnborg  * Pattern 2:
112472ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11254c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
11264c8fbca5SSam Ravnborg  *   the pattern is identified by:
112783cda2bbSSam Ravnborg  *   tosec   = init or exit section
112883cda2bbSSam Ravnborg  *   fromsec = data section
1129df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1130df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1131ee6a8545SVivek Goyal  *
1132ee6a8545SVivek Goyal  * Pattern 3:
1133c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
11349bf8cb9bSSam Ravnborg  *
11351d8af559SSam Ravnborg  * Pattern 4:
1136ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1137ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1138ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1139ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1140ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1141ee6a8545SVivek Goyal  *   This pattern is identified by
1142ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
11439bf8cb9bSSam Ravnborg  *
11444a3893d0SPaul Gortmaker  * Pattern 5:
11454a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
11464a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
11474a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
11484a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
11494a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
11504a3893d0SPaul Gortmaker  *   This pattern is identified by
11514a3893d0SPaul Gortmaker  *   tosec   = init section
11524a3893d0SPaul Gortmaker  *   fromsec = text section
11534a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
11544a3893d0SPaul Gortmaker  *
11554c8fbca5SSam Ravnborg  **/
1156af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1157af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
115858fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
11594c8fbca5SSam Ravnborg {
11604c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
11616c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
11626c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
116358fb0d4fSSam Ravnborg 	    (strncmp(fromsym, "__param", strlen("__param")) == 0))
116458fb0d4fSSam Ravnborg 		return 0;
11654c8fbca5SSam Ravnborg 
11666a841528SRusty Russell 	/* Check for pattern 1a */
11676a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
11686a841528SRusty Russell 	    match(fromsec, data_sections) &&
11696a841528SRusty Russell 	    (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0))
11706a841528SRusty Russell 		return 0;
11716a841528SRusty Russell 
11724c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
11736c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
11746c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1175af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
117658fb0d4fSSam Ravnborg 		return 0;
11774c8fbca5SSam Ravnborg 
11789bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
11796c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
11806c5bd235SSam Ravnborg 	    match(tosec, init_sections))
118158fb0d4fSSam Ravnborg 		return 0;
1182f8657e1bSVivek Goyal 
11831d8af559SSam Ravnborg 	/* Check for pattern 4 */
118458fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
118593659af1SSam Ravnborg 		return 0;
118658fb0d4fSSam Ravnborg 
11874a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
11884a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
11894a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
11904a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
11914a3893d0SPaul Gortmaker 		return 0;
11924a3893d0SPaul Gortmaker 
119358fb0d4fSSam Ravnborg 	return 1;
11944c8fbca5SSam Ravnborg }
11954c8fbca5SSam Ravnborg 
11964c8fbca5SSam Ravnborg /**
119793684d3bSSam Ravnborg  * Find symbol based on relocation record info.
119893684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
119993684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
120093684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
120193684d3bSSam Ravnborg  * based on section and address.
120293684d3bSSam Ravnborg  *  **/
12039ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
120493684d3bSSam Ravnborg 				Elf_Sym *relsym)
120593684d3bSSam Ravnborg {
120693684d3bSSam Ravnborg 	Elf_Sym *sym;
12079ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
12089ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
12099ad21c3fSSam Ravnborg 	Elf64_Sword d;
12101ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
121193684d3bSSam Ravnborg 
121293684d3bSSam Ravnborg 	if (relsym->st_name != 0)
121393684d3bSSam Ravnborg 		return relsym;
12141ce53adfSDenys Vlasenko 
12151ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
121693684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
12171ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
121893684d3bSSam Ravnborg 			continue;
1219ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1220ae4ac123SAtsushi Nemoto 			continue;
122193684d3bSSam Ravnborg 		if (sym->st_value == addr)
122293684d3bSSam Ravnborg 			return sym;
12239ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
12249ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
12259ad21c3fSSam Ravnborg 		if (d < 0)
12269ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
12279ad21c3fSSam Ravnborg 		if (d < distance) {
12289ad21c3fSSam Ravnborg 			distance = d;
12299ad21c3fSSam Ravnborg 			near = sym;
123093684d3bSSam Ravnborg 		}
12319ad21c3fSSam Ravnborg 	}
12329ad21c3fSSam Ravnborg 	/* We need a close match */
12339ad21c3fSSam Ravnborg 	if (distance < 20)
12349ad21c3fSSam Ravnborg 		return near;
12359ad21c3fSSam Ravnborg 	else
123693684d3bSSam Ravnborg 		return NULL;
123793684d3bSSam Ravnborg }
123893684d3bSSam Ravnborg 
1239da68d61fSDavid Brownell static inline int is_arm_mapping_symbol(const char *str)
1240da68d61fSDavid Brownell {
12416c34f1f5SKyle McMartin 	return str[0] == '$' && strchr("axtd", str[1])
1242da68d61fSDavid Brownell 	       && (str[2] == '\0' || str[2] == '.');
1243da68d61fSDavid Brownell }
1244da68d61fSDavid Brownell 
1245da68d61fSDavid Brownell /*
1246da68d61fSDavid Brownell  * If there's no name there, ignore it; likewise, ignore it if it's
1247da68d61fSDavid Brownell  * one of the magic symbols emitted used by current ARM tools.
1248da68d61fSDavid Brownell  *
1249da68d61fSDavid Brownell  * Otherwise if find_symbols_between() returns those symbols, they'll
1250da68d61fSDavid Brownell  * fail the whitelist tests and cause lots of false alarms ... fixable
1251da68d61fSDavid Brownell  * only by merging __exit and __init sections into __text, bloating
1252da68d61fSDavid Brownell  * the kernel (which is especially evil on embedded platforms).
1253da68d61fSDavid Brownell  */
1254da68d61fSDavid Brownell static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
1255da68d61fSDavid Brownell {
1256da68d61fSDavid Brownell 	const char *name = elf->strtab + sym->st_name;
1257da68d61fSDavid Brownell 
1258da68d61fSDavid Brownell 	if (!name || !strlen(name))
1259da68d61fSDavid Brownell 		return 0;
1260da68d61fSDavid Brownell 	return !is_arm_mapping_symbol(name);
1261da68d61fSDavid Brownell }
1262da68d61fSDavid Brownell 
1263b39927cfSSam Ravnborg /*
126443c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
126543c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
126643c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
126743c74d17SSam Ravnborg  * it is, but this works for now.
1268b39927cfSSam Ravnborg  **/
1269157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1270157c23c8SSam Ravnborg 				 const char *sec)
1271b39927cfSSam Ravnborg {
1272b39927cfSSam Ravnborg 	Elf_Sym *sym;
1273157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1274157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1275b39927cfSSam Ravnborg 
1276b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1277b39927cfSSam Ravnborg 		const char *symsec;
1278b39927cfSSam Ravnborg 
12791ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1280b39927cfSSam Ravnborg 			continue;
12811ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1282b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1283b39927cfSSam Ravnborg 			continue;
1284da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1285da68d61fSDavid Brownell 			continue;
1286b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1287157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1288157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1289157c23c8SSam Ravnborg 				near = sym;
1290157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1291157c23c8SSam Ravnborg 				near = sym;
129243c74d17SSam Ravnborg 			}
1293b39927cfSSam Ravnborg 		}
1294b39927cfSSam Ravnborg 	}
1295157c23c8SSam Ravnborg 	return near;
1296157c23c8SSam Ravnborg }
1297b39927cfSSam Ravnborg 
129858fb0d4fSSam Ravnborg /*
1299588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1300588ccd73SSam Ravnborg  * .init.text => __init
1301588ccd73SSam Ravnborg  * .memexitconst => __memconst
1302588ccd73SSam Ravnborg  * etc.
1303cbcf14a9SAndy Shevchenko  *
1304cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1305cbcf14a9SAndy Shevchenko  * method should free it after usage.
1306588ccd73SSam Ravnborg */
1307588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1308588ccd73SSam Ravnborg {
1309588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
1310588ccd73SSam Ravnborg 		char *p = malloc(20);
1311588ccd73SSam Ravnborg 		char *r = p;
1312588ccd73SSam Ravnborg 
1313588ccd73SSam Ravnborg 		*p++ = '_';
1314588ccd73SSam Ravnborg 		*p++ = '_';
1315588ccd73SSam Ravnborg 		if (*s == '.')
1316588ccd73SSam Ravnborg 			s++;
1317588ccd73SSam Ravnborg 		while (*s && *s != '.')
1318588ccd73SSam Ravnborg 			*p++ = *s++;
1319588ccd73SSam Ravnborg 		*p = '\0';
1320588ccd73SSam Ravnborg 		if (*s == '.')
1321588ccd73SSam Ravnborg 			s++;
1322588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1323588ccd73SSam Ravnborg 			strcat(p, "const ");
1324588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1325588ccd73SSam Ravnborg 			strcat(p, "data ");
1326588ccd73SSam Ravnborg 		else
1327588ccd73SSam Ravnborg 			strcat(p, " ");
1328cbcf14a9SAndy Shevchenko 		return r;
1329588ccd73SSam Ravnborg 	} else {
13305003bab8SAndrew Morton 		return strdup("");
1331588ccd73SSam Ravnborg 	}
1332588ccd73SSam Ravnborg }
1333588ccd73SSam Ravnborg 
1334588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1335588ccd73SSam Ravnborg {
1336588ccd73SSam Ravnborg 	if (sym)
1337588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1338588ccd73SSam Ravnborg 	else
1339f666751aSSam Ravnborg 		return -1;
1340588ccd73SSam Ravnborg }
1341588ccd73SSam Ravnborg 
134200759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
134300759c0eSRandy Dunlap {
134400759c0eSRandy Dunlap 	const char *const *s = list;
134500759c0eSRandy Dunlap 
134600759c0eSRandy Dunlap 	while (*s) {
134700759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
134800759c0eSRandy Dunlap 		s++;
134900759c0eSRandy Dunlap 		if (*s)
135000759c0eSRandy Dunlap 			fprintf(stderr, ", ");
135100759c0eSRandy Dunlap 	}
135200759c0eSRandy Dunlap 	fprintf(stderr, "\n");
135300759c0eSRandy Dunlap }
135400759c0eSRandy Dunlap 
1355356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1356356ad538SQuentin Casasnovas {
1357356ad538SQuentin Casasnovas 	switch (is_func) {
1358356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1359356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1360356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1361356ad538SQuentin Casasnovas 	}
1362356ad538SQuentin Casasnovas }
1363356ad538SQuentin Casasnovas 
1364588ccd73SSam Ravnborg /*
1365b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1366b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
13674c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
136858fb0d4fSSam Ravnborg  */
13690d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
13700d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
137158fb0d4fSSam Ravnborg 				const char *fromsec,
137258fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
137358fb0d4fSSam Ravnborg 				const char *fromsym,
1374588ccd73SSam Ravnborg 				int from_is_func,
1375588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1376588ccd73SSam Ravnborg 				int to_is_func)
1377b39927cfSSam Ravnborg {
1378588ccd73SSam Ravnborg 	const char *from, *from_p;
1379588ccd73SSam Ravnborg 	const char *to, *to_p;
138037ed19d5SAlexey Fomenko 	char *prl_from;
138137ed19d5SAlexey Fomenko 	char *prl_to;
1382f666751aSSam Ravnborg 
1383e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1384e5f95c8bSSam Ravnborg 	if (!sec_mismatch_verbose)
1385e5f95c8bSSam Ravnborg 		return;
1386e5f95c8bSSam Ravnborg 
1387356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1388356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1389356ad538SQuentin Casasnovas 
13907c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
13917c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
13927c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
13937c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1394588ccd73SSam Ravnborg 
13950d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1396bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
139737ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
139837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1399588ccd73SSam Ravnborg 		fprintf(stderr,
1400588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1401588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1402588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1403588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
140437ed19d5SAlexey Fomenko 		prl_from, fromsym,
140537ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
140637ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
140737ed19d5SAlexey Fomenko 		free(prl_from);
140837ed19d5SAlexey Fomenko 		free(prl_to);
1409588ccd73SSam Ravnborg 		break;
1410bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
141137ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1412588ccd73SSam Ravnborg 		fprintf(stderr,
1413588ccd73SSam Ravnborg 		"The variable %s references\n"
1414588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1415588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
14168b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1417588ccd73SSam Ravnborg 		"or name the variable:\n",
141837ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
141900759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
142037ed19d5SAlexey Fomenko 		free(prl_to);
1421588ccd73SSam Ravnborg 		break;
142258fb0d4fSSam Ravnborg 	}
1423bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
142437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1425588ccd73SSam Ravnborg 		fprintf(stderr,
1426588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1427588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1428588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
142937ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
143037ed19d5SAlexey Fomenko 		free(prl_to);
1431588ccd73SSam Ravnborg 		break;
1432bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
143337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1434588ccd73SSam Ravnborg 		fprintf(stderr,
1435588ccd73SSam Ravnborg 		"The variable %s references\n"
1436588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1437588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1438588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1439588ccd73SSam Ravnborg 		"name the variable:\n",
144037ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
144100759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
144237ed19d5SAlexey Fomenko 		free(prl_to);
1443588ccd73SSam Ravnborg 		break;
1444588ccd73SSam Ravnborg 	}
1445bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1446bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
144737ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
144837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1449588ccd73SSam Ravnborg 		fprintf(stderr,
1450588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1451588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1452588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1453588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
145437ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
145537ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1456b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
145737ed19d5SAlexey Fomenko 		free(prl_from);
145837ed19d5SAlexey Fomenko 		free(prl_to);
1459588ccd73SSam Ravnborg 		break;
1460bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
146137ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
146237ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1463588ccd73SSam Ravnborg 		fprintf(stderr,
1464588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1465588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1466588ccd73SSam Ravnborg 		"This is often seen when error handling "
1467588ccd73SSam Ravnborg 		"in the init function\n"
1468588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1469588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1470588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
147137ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
147237ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
14735003bab8SAndrew Morton 		prl_to, tosym, to_p);
147437ed19d5SAlexey Fomenko 		free(prl_from);
147537ed19d5SAlexey Fomenko 		free(prl_to);
1476588ccd73SSam Ravnborg 		break;
1477bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
147837ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
147937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1480588ccd73SSam Ravnborg 		fprintf(stderr,
1481588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1482588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1483588ccd73SSam Ravnborg 		"This is often seen when error handling "
1484588ccd73SSam Ravnborg 		"in the exit function\n"
1485588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1486588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1487588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
148837ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
148937ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
149037ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
149137ed19d5SAlexey Fomenko 		free(prl_from);
149237ed19d5SAlexey Fomenko 		free(prl_to);
1493588ccd73SSam Ravnborg 		break;
1494588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
149537ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1496588ccd73SSam Ravnborg 		fprintf(stderr,
1497588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1498588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1499588ccd73SSam Ravnborg 		"or drop the export.\n",
150037ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
150137ed19d5SAlexey Fomenko 		free(prl_to);
1502588ccd73SSam Ravnborg 		break;
150352dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
150452dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
150552dc0595SQuentin Casasnovas 		      "we should never get here.");
150652dc0595SQuentin Casasnovas 		break;
1507588ccd73SSam Ravnborg 	}
1508588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
150958fb0d4fSSam Ravnborg }
151058fb0d4fSSam Ravnborg 
1511644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1512644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
151358fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
151458fb0d4fSSam Ravnborg {
151558fb0d4fSSam Ravnborg 	const char *tosec;
1516588ccd73SSam Ravnborg 	Elf_Sym *to;
1517588ccd73SSam Ravnborg 	Elf_Sym *from;
151858fb0d4fSSam Ravnborg 	const char *tosym;
1519588ccd73SSam Ravnborg 	const char *fromsym;
152058fb0d4fSSam Ravnborg 
1521588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1522588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
152358fb0d4fSSam Ravnborg 
152477ab21adSAndi Kleen 	if (!strncmp(fromsym, "reference___initcall",
152577ab21adSAndi Kleen 		     sizeof("reference___initcall")-1))
152677ab21adSAndi Kleen 		return;
152777ab21adSAndi Kleen 
1528c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1529c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1530c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1531c7a65e06SQuentin Casasnovas 
153258fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1533af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1534af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1535588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1536588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1537588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1538588ccd73SSam Ravnborg 				    is_function(to));
153958fb0d4fSSam Ravnborg 	}
1540b39927cfSSam Ravnborg }
1541644e8f14SQuentin Casasnovas 
154252dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
154352dc0595SQuentin Casasnovas {
154452dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
154552dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
154652dc0595SQuentin Casasnovas 
154752dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
154852dc0595SQuentin Casasnovas }
154952dc0595SQuentin Casasnovas 
155052dc0595SQuentin Casasnovas /*
155152dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
155252dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
155352dc0595SQuentin Casasnovas  */
155452dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1555e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
155652dc0595SQuentin Casasnovas {
155752dc0595SQuentin Casasnovas 	/*
155852dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
155952dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
156052dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
156152dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
156252dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
156352dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
156452dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
156552dc0595SQuentin Casasnovas 	 */
1566e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
156752dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
156852dc0595SQuentin Casasnovas }
1569e84048aaSQuentin Casasnovas 
157052dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
157152dc0595SQuentin Casasnovas {
1572d3df4de7SQuentin Casasnovas 	/*
1573d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1574d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1575d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1576d3df4de7SQuentin Casasnovas 	 */
1577d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
157852dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
157952dc0595SQuentin Casasnovas 
158052dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
158152dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
158252dc0595SQuentin Casasnovas }
158352dc0595SQuentin Casasnovas 
1584e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1585e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1586e84048aaSQuentin Casasnovas 
158752dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
158852dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
158952dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
159052dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
159152dc0595SQuentin Casasnovas {
159252dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
159352dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
159452dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
159552dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
159652dc0595SQuentin Casasnovas 	const char* from_pretty_name;
159752dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
159852dc0595SQuentin Casasnovas 	const char* to_pretty_name;
159952dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
160052dc0595SQuentin Casasnovas 
160152dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
160252dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
160352dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
160452dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
160552dc0595SQuentin Casasnovas 
160652dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
160752dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
160852dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
160952dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
161052dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
161152dc0595SQuentin Casasnovas 
161252dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
161352dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
161452dc0595SQuentin Casasnovas 		fprintf(stderr,
161552dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
161652dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
161752dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
161852dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
161952dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
162052dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
162152dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
162252dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
162352dc0595SQuentin Casasnovas }
162452dc0595SQuentin Casasnovas 
162552dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
162652dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
162752dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
162852dc0595SQuentin Casasnovas 				     const char *fromsec)
162952dc0595SQuentin Casasnovas {
163052dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
163152dc0595SQuentin Casasnovas 
163252dc0595SQuentin Casasnovas 	sec_mismatch_count++;
163352dc0595SQuentin Casasnovas 
163452dc0595SQuentin Casasnovas 	if (sec_mismatch_verbose)
163552dc0595SQuentin Casasnovas 		report_extable_warnings(modname, elf, mismatch, r, sym,
163652dc0595SQuentin Casasnovas 					fromsec, tosec);
163752dc0595SQuentin Casasnovas 
163852dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
163952dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
164052dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
164152dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
164252dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
164352dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
164452dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
164552dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
164652dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
164752dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
164852dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
164952dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
165052dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
165152dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
165252dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
165352dc0595SQuentin Casasnovas 		else
165452dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
165552dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
165652dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
165752dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
165852dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
165952dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
166052dc0595SQuentin Casasnovas 	}
166152dc0595SQuentin Casasnovas }
166252dc0595SQuentin Casasnovas 
1663644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1664644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1665644e8f14SQuentin Casasnovas {
1666644e8f14SQuentin Casasnovas 	const char *tosec = sec_name(elf, get_secindex(elf, sym));;
1667644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1668644e8f14SQuentin Casasnovas 
1669644e8f14SQuentin Casasnovas 	if (mismatch) {
1670644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1671644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1672644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1673644e8f14SQuentin Casasnovas 		else
1674644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1675644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1676644e8f14SQuentin Casasnovas 	}
1677b39927cfSSam Ravnborg }
1678b39927cfSSam Ravnborg 
1679ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
16805b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1681ae4ac123SAtsushi Nemoto {
1682ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
16836845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1684ae4ac123SAtsushi Nemoto 
1685ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1686731ece41SOlof Johansson 		r->r_offset;
1687ae4ac123SAtsushi Nemoto }
1688ae4ac123SAtsushi Nemoto 
16895b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1690ae4ac123SAtsushi Nemoto {
1691ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
16925b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1693ae4ac123SAtsushi Nemoto 
1694ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1695ae4ac123SAtsushi Nemoto 	case R_386_32:
1696ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1697ae4ac123SAtsushi Nemoto 		break;
1698ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1699ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1700ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1701ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1702ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1703ae4ac123SAtsushi Nemoto 		break;
1704ae4ac123SAtsushi Nemoto 	}
1705ae4ac123SAtsushi Nemoto 	return 0;
1706ae4ac123SAtsushi Nemoto }
1707ae4ac123SAtsushi Nemoto 
17086e2e340bSTony Lindgren #ifndef R_ARM_CALL
17096e2e340bSTony Lindgren #define R_ARM_CALL	28
17106e2e340bSTony Lindgren #endif
17116e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17126e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17136e2e340bSTony Lindgren #endif
17146e2e340bSTony Lindgren 
1715c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1716c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1717c9698e5cSDavid A. Long #endif
1718c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1719c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1720c9698e5cSDavid A. Long #endif
1721c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1722c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1723c9698e5cSDavid A. Long #endif
1724c9698e5cSDavid A. Long 
17255b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
172656a974faSSam Ravnborg {
172756a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
172856a974faSSam Ravnborg 
172956a974faSSam Ravnborg 	switch (r_typ) {
173056a974faSSam Ravnborg 	case R_ARM_ABS32:
173156a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1732df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1733df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
173456a974faSSam Ravnborg 		break;
173556a974faSSam Ravnborg 	case R_ARM_PC24:
17366e2e340bSTony Lindgren 	case R_ARM_CALL:
17376e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1738c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1739c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1740c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
174156a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1742df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
17435b24c071SSam Ravnborg 			      sechdr->sh_offset +
17445b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
174556a974faSSam Ravnborg 		break;
174656a974faSSam Ravnborg 	default:
174756a974faSSam Ravnborg 		return 1;
174856a974faSSam Ravnborg 	}
174956a974faSSam Ravnborg 	return 0;
175056a974faSSam Ravnborg }
175156a974faSSam Ravnborg 
17525b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1753ae4ac123SAtsushi Nemoto {
1754ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17555b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1756ae4ac123SAtsushi Nemoto 	unsigned int inst;
1757ae4ac123SAtsushi Nemoto 
1758ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1759ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1760ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1761ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1762ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1763ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1764ae4ac123SAtsushi Nemoto 		break;
1765ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1766ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1767ae4ac123SAtsushi Nemoto 		break;
1768ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1769ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1770ae4ac123SAtsushi Nemoto 		break;
1771ae4ac123SAtsushi Nemoto 	}
1772ae4ac123SAtsushi Nemoto 	return 0;
1773ae4ac123SAtsushi Nemoto }
1774ae4ac123SAtsushi Nemoto 
17755b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
177610668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1777b39927cfSSam Ravnborg {
1778b39927cfSSam Ravnborg 	Elf_Sym  *sym;
17795b24c071SSam Ravnborg 	Elf_Rela *rela;
17802c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1781eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
17825b24c071SSam Ravnborg 	const char *fromsec;
17835b24c071SSam Ravnborg 
1784ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
17855b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
17865b24c071SSam Ravnborg 
1787ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
17885b24c071SSam Ravnborg 	fromsec += strlen(".rela");
17895b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1790b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
17915b24c071SSam Ravnborg 		return;
1792e241a630SSam Ravnborg 
1793b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1794b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1795eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1796ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1797ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1798eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1799eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1800ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1801ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1802eae07ac6SAtsushi Nemoto 		} else {
1803601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1804eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1805eae07ac6SAtsushi Nemoto 		}
1806eae07ac6SAtsushi Nemoto #else
1807eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1808eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1809eae07ac6SAtsushi Nemoto #endif
181093684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1811eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1812b39927cfSSam Ravnborg 		/* Skip special sections */
18131ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1814b39927cfSSam Ravnborg 			continue;
1815e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1816e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
181758fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18182c1a51f3SAtsushi Nemoto 	}
18195b24c071SSam Ravnborg }
18205b24c071SSam Ravnborg 
18215b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
182210668220SSam Ravnborg 			Elf_Shdr *sechdr)
18235b24c071SSam Ravnborg {
18245b24c071SSam Ravnborg 	Elf_Sym *sym;
18252c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
18265b24c071SSam Ravnborg 	Elf_Rela r;
18275b24c071SSam Ravnborg 	unsigned int r_sym;
18285b24c071SSam Ravnborg 	const char *fromsec;
18295b24c071SSam Ravnborg 
1830ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
18315b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
18325b24c071SSam Ravnborg 
1833ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18345b24c071SSam Ravnborg 	fromsec += strlen(".rel");
18355b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1836b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18375b24c071SSam Ravnborg 		return;
18382c1a51f3SAtsushi Nemoto 
18392c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
18402c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1841eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1842ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1843ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1844eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1845eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1846ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1847ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1848eae07ac6SAtsushi Nemoto 		} else {
18492c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1850eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1851eae07ac6SAtsushi Nemoto 		}
1852eae07ac6SAtsushi Nemoto #else
1853eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1854eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1855eae07ac6SAtsushi Nemoto #endif
18562c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1857ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1858ae4ac123SAtsushi Nemoto 		case EM_386:
18595b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1860ae4ac123SAtsushi Nemoto 				continue;
1861ae4ac123SAtsushi Nemoto 			break;
186256a974faSSam Ravnborg 		case EM_ARM:
18635b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
186456a974faSSam Ravnborg 				continue;
186556a974faSSam Ravnborg 			break;
1866ae4ac123SAtsushi Nemoto 		case EM_MIPS:
18675b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1868ae4ac123SAtsushi Nemoto 				continue;
1869ae4ac123SAtsushi Nemoto 			break;
1870ae4ac123SAtsushi Nemoto 		}
1871eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
18722c1a51f3SAtsushi Nemoto 		/* Skip special sections */
18731ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
18742c1a51f3SAtsushi Nemoto 			continue;
1875e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1876e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
187758fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18782c1a51f3SAtsushi Nemoto 	}
1879b39927cfSSam Ravnborg }
18805b24c071SSam Ravnborg 
18815b24c071SSam Ravnborg /**
18825b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
18835b24c071SSam Ravnborg  * either when loaded or when used as built-in.
18845b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1885b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
18865b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
18875b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
188832be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
18895b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
18905b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
18915b24c071SSam Ravnborg  * be discarded and warns about it.
18925b24c071SSam Ravnborg  **/
18935b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
189410668220SSam Ravnborg 			  struct elf_info *elf)
18955b24c071SSam Ravnborg {
18965b24c071SSam Ravnborg 	int i;
18975b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
18985b24c071SSam Ravnborg 
18995b24c071SSam Ravnborg 	/* Walk through all sections */
19001ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1901b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19025b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19035b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
190410668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19055b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
190610668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1907b39927cfSSam Ravnborg 	}
1908b39927cfSSam Ravnborg }
1909b39927cfSSam Ravnborg 
19107d02b490SAndi Kleen static char *remove_dot(char *s)
19117d02b490SAndi Kleen {
1912fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19137d02b490SAndi Kleen 
1914fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1915fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1916fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
19177d02b490SAndi Kleen 			s[n] = 0;
19187d02b490SAndi Kleen 	}
19197d02b490SAndi Kleen 	return s;
19207d02b490SAndi Kleen }
19217d02b490SAndi Kleen 
19225c3ead8cSSam Ravnborg static void read_symbols(char *modname)
19231da177e4SLinus Torvalds {
19241da177e4SLinus Torvalds 	const char *symname;
19251da177e4SLinus Torvalds 	char *version;
1926b817f6feSSam Ravnborg 	char *license;
19271da177e4SLinus Torvalds 	struct module *mod;
19281da177e4SLinus Torvalds 	struct elf_info info = { };
19291da177e4SLinus Torvalds 	Elf_Sym *sym;
19301da177e4SLinus Torvalds 
193185bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
193285bd2fddSSam Ravnborg 		return;
19331da177e4SLinus Torvalds 
19341da177e4SLinus Torvalds 	mod = new_module(modname);
19351da177e4SLinus Torvalds 
19361da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
19371da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
19381da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
19391da177e4SLinus Torvalds 		have_vmlinux = 1;
19401da177e4SLinus Torvalds 		mod->skip = 1;
19411da177e4SLinus Torvalds 	}
19421da177e4SLinus Torvalds 
1943b817f6feSSam Ravnborg 	license = get_modinfo(info.modinfo, info.modinfo_len, "license");
19442fa36568SSam Ravnborg 	if (info.modinfo && !license && !is_vmlinux(modname))
19452fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
1946eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
1947eed7d279SSam Ravnborg 		     "more information\n", modname);
1948b817f6feSSam Ravnborg 	while (license) {
1949b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
1950b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
1951b817f6feSSam Ravnborg 		else {
1952b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
1953b817f6feSSam Ravnborg 			break;
1954b817f6feSSam Ravnborg 		}
1955b817f6feSSam Ravnborg 		license = get_next_modinfo(info.modinfo, info.modinfo_len,
1956b817f6feSSam Ravnborg 					   "license", license);
1957b817f6feSSam Ravnborg 	}
1958b817f6feSSam Ravnborg 
19591da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
19607d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
19631da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
19641da177e4SLinus Torvalds 	}
1965d1f25e66SSam Ravnborg 	if (!is_vmlinux(modname) ||
196610668220SSam Ravnborg 	     (is_vmlinux(modname) && vmlinux_section_warnings))
196710668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
19681da177e4SLinus Torvalds 
19691da177e4SLinus Torvalds 	version = get_modinfo(info.modinfo, info.modinfo_len, "version");
19701da177e4SLinus Torvalds 	if (version)
19711da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
19721da177e4SLinus Torvalds 				       version - (char *)info.hdr);
19731da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
19741da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
19751da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
19761da177e4SLinus Torvalds 
19771da177e4SLinus Torvalds 	parse_elf_finish(&info);
19781da177e4SLinus Torvalds 
19798c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
19801da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
19811da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
19821da177e4SLinus Torvalds 	 * important anyhow */
19831da177e4SLinus Torvalds 	if (modversions)
19848c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
19851da177e4SLinus Torvalds }
19861da177e4SLinus Torvalds 
1987712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
1988712f9b46SRusty Russell {
1989712f9b46SRusty Russell 	FILE *in = stdin;
1990712f9b46SRusty Russell 	char fname[PATH_MAX];
1991712f9b46SRusty Russell 
1992712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
1993712f9b46SRusty Russell 		in = fopen(filename, "r");
1994712f9b46SRusty Russell 		if (!in)
1995712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
1996712f9b46SRusty Russell 	}
1997712f9b46SRusty Russell 
1998712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
1999712f9b46SRusty Russell 		if (strends(fname, "\n"))
2000712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2001712f9b46SRusty Russell 		read_symbols(fname);
2002712f9b46SRusty Russell 	}
2003712f9b46SRusty Russell 
2004712f9b46SRusty Russell 	if (in != stdin)
2005712f9b46SRusty Russell 		fclose(in);
2006712f9b46SRusty Russell }
2007712f9b46SRusty Russell 
20081da177e4SLinus Torvalds #define SZ 500
20091da177e4SLinus Torvalds 
20101da177e4SLinus Torvalds /* We first write the generated file into memory using the
20111da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
20121da177e4SLinus Torvalds  * only update the later if anything changed */
20131da177e4SLinus Torvalds 
20145c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
20155c3ead8cSSam Ravnborg 						      const char *fmt, ...)
20161da177e4SLinus Torvalds {
20171da177e4SLinus Torvalds 	char tmp[SZ];
20181da177e4SLinus Torvalds 	int len;
20191da177e4SLinus Torvalds 	va_list ap;
20201da177e4SLinus Torvalds 
20211da177e4SLinus Torvalds 	va_start(ap, fmt);
20221da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
20237670f023SSam Ravnborg 	buf_write(buf, tmp, len);
20241da177e4SLinus Torvalds 	va_end(ap);
20251da177e4SLinus Torvalds }
20261da177e4SLinus Torvalds 
20275c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
20281da177e4SLinus Torvalds {
20291da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
20307670f023SSam Ravnborg 		buf->size += len + SZ;
20311da177e4SLinus Torvalds 		buf->p = realloc(buf->p, buf->size);
20321da177e4SLinus Torvalds 	}
20331da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
20341da177e4SLinus Torvalds 	buf->pos += len;
20351da177e4SLinus Torvalds }
20361da177e4SLinus Torvalds 
2037c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2038c96fca21SSam Ravnborg {
2039c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2040c96fca21SSam Ravnborg 
2041c96fca21SSam Ravnborg 	switch (exp) {
2042c96fca21SSam Ravnborg 	case export_gpl:
2043c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2044c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2045c96fca21SSam Ravnborg 		break;
2046c96fca21SSam Ravnborg 	case export_unused_gpl:
2047c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2048c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2049c96fca21SSam Ravnborg 		break;
2050c96fca21SSam Ravnborg 	case export_gpl_future:
2051c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2052c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2053c96fca21SSam Ravnborg 		break;
2054c96fca21SSam Ravnborg 	case export_plain:
2055c96fca21SSam Ravnborg 	case export_unused:
2056c96fca21SSam Ravnborg 	case export_unknown:
2057c96fca21SSam Ravnborg 		/* ignore */
2058c96fca21SSam Ravnborg 		break;
2059c96fca21SSam Ravnborg 	}
2060c96fca21SSam Ravnborg }
2061c96fca21SSam Ravnborg 
2062c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2063c96fca21SSam Ravnborg {
2064c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2065c96fca21SSam Ravnborg 
2066c96fca21SSam Ravnborg 	switch (exp) {
2067c96fca21SSam Ravnborg 	case export_unused:
2068c96fca21SSam Ravnborg 	case export_unused_gpl:
2069c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2070c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2071c96fca21SSam Ravnborg 		break;
2072c96fca21SSam Ravnborg 	default:
2073c96fca21SSam Ravnborg 		/* ignore */
2074c96fca21SSam Ravnborg 		break;
2075c96fca21SSam Ravnborg 	}
2076c96fca21SSam Ravnborg }
2077c96fca21SSam Ravnborg 
2078c96fca21SSam Ravnborg static void check_exports(struct module *mod)
2079b817f6feSSam Ravnborg {
2080b817f6feSSam Ravnborg 	struct symbol *s, *exp;
2081b817f6feSSam Ravnborg 
2082b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
20836449bd62SAndrew Morton 		const char *basename;
2084b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
2085b817f6feSSam Ravnborg 		if (!exp || exp->module == mod)
2086b817f6feSSam Ravnborg 			continue;
20876449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2088b817f6feSSam Ravnborg 		if (basename)
2089b817f6feSSam Ravnborg 			basename++;
2090c96fca21SSam Ravnborg 		else
2091c96fca21SSam Ravnborg 			basename = mod->name;
2092c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2093c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2094c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2095b817f6feSSam Ravnborg 	}
2096b817f6feSSam Ravnborg }
2097b817f6feSSam Ravnborg 
20985c3ead8cSSam Ravnborg /**
20995c3ead8cSSam Ravnborg  * Header for the generated file
21005c3ead8cSSam Ravnborg  **/
21015c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
21021da177e4SLinus Torvalds {
21031da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
21041da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
21051da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
21061da177e4SLinus Torvalds 	buf_printf(b, "\n");
21071da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
21081da177e4SLinus Torvalds 	buf_printf(b, "\n");
2109e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
21101da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
21113c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
21121da177e4SLinus Torvalds 	if (mod->has_init)
21133c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
21141da177e4SLinus Torvalds 	if (mod->has_cleanup)
21151da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
21163c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
21171da177e4SLinus Torvalds 			      "#endif\n");
21183c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
21191da177e4SLinus Torvalds 	buf_printf(b, "};\n");
21201da177e4SLinus Torvalds }
21211da177e4SLinus Torvalds 
21222449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
21232449b8baSBen Hutchings {
21242449b8baSBen Hutchings 	if (is_intree)
21252449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
21262449b8baSBen Hutchings }
21272449b8baSBen Hutchings 
21285c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2129a9860bf0SGreg Kroah-Hartman {
2130a9860bf0SGreg Kroah-Hartman 	static const char *staging_dir = "drivers/staging";
2131a9860bf0SGreg Kroah-Hartman 
2132a9860bf0SGreg Kroah-Hartman 	if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
2133a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2134a9860bf0SGreg Kroah-Hartman }
2135a9860bf0SGreg Kroah-Hartman 
21365c3ead8cSSam Ravnborg /**
21375c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
21385c3ead8cSSam Ravnborg  **/
2139c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
21401da177e4SLinus Torvalds {
21411da177e4SLinus Torvalds 	struct symbol *s, *exp;
2142c53ddacdSKirill Korotaev 	int err = 0;
21431da177e4SLinus Torvalds 
21441da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
21451da177e4SLinus Torvalds 		exp = find_symbol(s->name);
21461da177e4SLinus Torvalds 		if (!exp || exp->module == mod) {
2147c53ddacdSKirill Korotaev 			if (have_vmlinux && !s->weak) {
21482a116659SMatthew Wilcox 				if (warn_unresolved) {
2149cb80514dSSam Ravnborg 					warn("\"%s\" [%s.ko] undefined!\n",
2150cb80514dSSam Ravnborg 					     s->name, mod->name);
21512a116659SMatthew Wilcox 				} else {
21522a116659SMatthew Wilcox 					merror("\"%s\" [%s.ko] undefined!\n",
21532a116659SMatthew Wilcox 					       s->name, mod->name);
21542a116659SMatthew Wilcox 					err = 1;
21552a116659SMatthew Wilcox 				}
2156c53ddacdSKirill Korotaev 			}
21571da177e4SLinus Torvalds 			continue;
21581da177e4SLinus Torvalds 		}
21591da177e4SLinus Torvalds 		s->module = exp->module;
21601da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
21611da177e4SLinus Torvalds 		s->crc = exp->crc;
21621da177e4SLinus Torvalds 	}
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds 	if (!modversions)
2165c53ddacdSKirill Korotaev 		return err;
21661da177e4SLinus Torvalds 
21671da177e4SLinus Torvalds 	buf_printf(b, "\n");
21681da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
21693ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
21701da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
21711da177e4SLinus Torvalds 
21721da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2173df578e7dSSam Ravnborg 		if (!s->module)
21741da177e4SLinus Torvalds 			continue;
21751da177e4SLinus Torvalds 		if (!s->crc_valid) {
2176cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
21771da177e4SLinus Torvalds 				s->name, mod->name);
21781da177e4SLinus Torvalds 			continue;
21791da177e4SLinus Torvalds 		}
2180a53a11f3SJames Hogan 		buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n",
2181a4b6a77bSJames Hogan 			   s->crc, s->name);
21821da177e4SLinus Torvalds 	}
21831da177e4SLinus Torvalds 
21841da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2185c53ddacdSKirill Korotaev 
2186c53ddacdSKirill Korotaev 	return err;
21871da177e4SLinus Torvalds }
21881da177e4SLinus Torvalds 
21895c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod,
21905c3ead8cSSam Ravnborg 			struct module *modules)
21911da177e4SLinus Torvalds {
21921da177e4SLinus Torvalds 	struct symbol *s;
21931da177e4SLinus Torvalds 	struct module *m;
21941da177e4SLinus Torvalds 	int first = 1;
21951da177e4SLinus Torvalds 
2196df578e7dSSam Ravnborg 	for (m = modules; m; m = m->next)
21971da177e4SLinus Torvalds 		m->seen = is_vmlinux(m->name);
21981da177e4SLinus Torvalds 
21991da177e4SLinus Torvalds 	buf_printf(b, "\n");
22001da177e4SLinus Torvalds 	buf_printf(b, "static const char __module_depends[]\n");
22013ff6eeccSAdrian Bunk 	buf_printf(b, "__used\n");
22021da177e4SLinus Torvalds 	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
22031da177e4SLinus Torvalds 	buf_printf(b, "\"depends=");
22041da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2205a61b2dfdSSam Ravnborg 		const char *p;
22061da177e4SLinus Torvalds 		if (!s->module)
22071da177e4SLinus Torvalds 			continue;
22081da177e4SLinus Torvalds 
22091da177e4SLinus Torvalds 		if (s->module->seen)
22101da177e4SLinus Torvalds 			continue;
22111da177e4SLinus Torvalds 
22121da177e4SLinus Torvalds 		s->module->seen = 1;
2213df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2214df578e7dSSam Ravnborg 		if (p)
2215a61b2dfdSSam Ravnborg 			p++;
2216a61b2dfdSSam Ravnborg 		else
2217a61b2dfdSSam Ravnborg 			p = s->module->name;
2218a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
22191da177e4SLinus Torvalds 		first = 0;
22201da177e4SLinus Torvalds 	}
22211da177e4SLinus Torvalds 	buf_printf(b, "\";\n");
22221da177e4SLinus Torvalds }
22231da177e4SLinus Torvalds 
22245c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
22251da177e4SLinus Torvalds {
22261da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
22271da177e4SLinus Torvalds 		buf_printf(b, "\n");
22281da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
22291da177e4SLinus Torvalds 			   mod->srcversion);
22301da177e4SLinus Torvalds 	}
22311da177e4SLinus Torvalds }
22321da177e4SLinus Torvalds 
22335c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
22341da177e4SLinus Torvalds {
22351da177e4SLinus Torvalds 	char *tmp;
22361da177e4SLinus Torvalds 	FILE *file;
22371da177e4SLinus Torvalds 	struct stat st;
22381da177e4SLinus Torvalds 
22391da177e4SLinus Torvalds 	file = fopen(fname, "r");
22401da177e4SLinus Torvalds 	if (!file)
22411da177e4SLinus Torvalds 		goto write;
22421da177e4SLinus Torvalds 
22431da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
22441da177e4SLinus Torvalds 		goto close_write;
22451da177e4SLinus Torvalds 
22461da177e4SLinus Torvalds 	if (st.st_size != b->pos)
22471da177e4SLinus Torvalds 		goto close_write;
22481da177e4SLinus Torvalds 
22491da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
22501da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
22511da177e4SLinus Torvalds 		goto free_write;
22521da177e4SLinus Torvalds 
22531da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
22541da177e4SLinus Torvalds 		goto free_write;
22551da177e4SLinus Torvalds 
22561da177e4SLinus Torvalds 	free(tmp);
22571da177e4SLinus Torvalds 	fclose(file);
22581da177e4SLinus Torvalds 	return;
22591da177e4SLinus Torvalds 
22601da177e4SLinus Torvalds  free_write:
22611da177e4SLinus Torvalds 	free(tmp);
22621da177e4SLinus Torvalds  close_write:
22631da177e4SLinus Torvalds 	fclose(file);
22641da177e4SLinus Torvalds  write:
22651da177e4SLinus Torvalds 	file = fopen(fname, "w");
22661da177e4SLinus Torvalds 	if (!file) {
22671da177e4SLinus Torvalds 		perror(fname);
22681da177e4SLinus Torvalds 		exit(1);
22691da177e4SLinus Torvalds 	}
22701da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
22711da177e4SLinus Torvalds 		perror(fname);
22721da177e4SLinus Torvalds 		exit(1);
22731da177e4SLinus Torvalds 	}
22741da177e4SLinus Torvalds 	fclose(file);
22751da177e4SLinus Torvalds }
22761da177e4SLinus Torvalds 
2277bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2278534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2279bd5cbcedSRam Pai  **/
2280040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
22811da177e4SLinus Torvalds {
22821da177e4SLinus Torvalds 	unsigned long size, pos = 0;
22831da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
22841da177e4SLinus Torvalds 	char *line;
22851da177e4SLinus Torvalds 
22861da177e4SLinus Torvalds 	if (!file)
22871da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
22881da177e4SLinus Torvalds 		return;
22891da177e4SLinus Torvalds 
22901da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2291534b89a9SSam Ravnborg 		char *symname, *modname, *d, *export, *end;
22921da177e4SLinus Torvalds 		unsigned int crc;
22931da177e4SLinus Torvalds 		struct module *mod;
2294040fcc81SSam Ravnborg 		struct symbol *s;
22951da177e4SLinus Torvalds 
22961da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
22971da177e4SLinus Torvalds 			goto fail;
22981da177e4SLinus Torvalds 		*symname++ = '\0';
22991da177e4SLinus Torvalds 		if (!(modname = strchr(symname, '\t')))
23001da177e4SLinus Torvalds 			goto fail;
23011da177e4SLinus Torvalds 		*modname++ = '\0';
23029ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2303bd5cbcedSRam Pai 			*export++ = '\0';
2304534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2305534b89a9SSam Ravnborg 			*end = '\0';
23061da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
23071da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
23081da177e4SLinus Torvalds 			goto fail;
2309df578e7dSSam Ravnborg 		mod = find_module(modname);
2310df578e7dSSam Ravnborg 		if (!mod) {
2311df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
23121da177e4SLinus Torvalds 				have_vmlinux = 1;
23130fa3a88cSJan Beulich 			mod = new_module(modname);
23141da177e4SLinus Torvalds 			mod->skip = 1;
23151da177e4SLinus Torvalds 		}
2316bd5cbcedSRam Pai 		s = sym_add_exported(symname, mod, export_no(export));
2317040fcc81SSam Ravnborg 		s->kernel    = kernel;
23188e70c458SSam Ravnborg 		s->preloaded = 1;
2319bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
23201da177e4SLinus Torvalds 	}
23212ee41e62SChristian Engelmayer 	release_file(file, size);
23221da177e4SLinus Torvalds 	return;
23231da177e4SLinus Torvalds fail:
23242ee41e62SChristian Engelmayer 	release_file(file, size);
23251da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
23261da177e4SLinus Torvalds }
23271da177e4SLinus Torvalds 
2328040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2329040fcc81SSam Ravnborg  * For external modules only dump symbols
2330040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2331040fcc81SSam Ravnborg  **/
2332040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2333040fcc81SSam Ravnborg {
2334040fcc81SSam Ravnborg 	if (!external_module)
2335040fcc81SSam Ravnborg 		return 1;
2336040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2337040fcc81SSam Ravnborg 		return 0;
2338040fcc81SSam Ravnborg 	return 1;
2339040fcc81SSam Ravnborg }
2340040fcc81SSam Ravnborg 
23415c3ead8cSSam Ravnborg static void write_dump(const char *fname)
23421da177e4SLinus Torvalds {
23431da177e4SLinus Torvalds 	struct buffer buf = { };
23441da177e4SLinus Torvalds 	struct symbol *symbol;
23451da177e4SLinus Torvalds 	int n;
23461da177e4SLinus Torvalds 
23471da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
23481da177e4SLinus Torvalds 		symbol = symbolhash[n];
23491da177e4SLinus Torvalds 		while (symbol) {
2350040fcc81SSam Ravnborg 			if (dump_sym(symbol))
2351bd5cbcedSRam Pai 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
2352040fcc81SSam Ravnborg 					symbol->crc, symbol->name,
2353bd5cbcedSRam Pai 					symbol->module->name,
2354bd5cbcedSRam Pai 					export_str(symbol->export));
23551da177e4SLinus Torvalds 			symbol = symbol->next;
23561da177e4SLinus Torvalds 		}
23571da177e4SLinus Torvalds 	}
23581da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
23591da177e4SLinus Torvalds }
23601da177e4SLinus Torvalds 
23612d04b5aeSRichard Hacker struct ext_sym_list {
23622d04b5aeSRichard Hacker 	struct ext_sym_list *next;
23632d04b5aeSRichard Hacker 	const char *file;
23642d04b5aeSRichard Hacker };
23652d04b5aeSRichard Hacker 
23665c3ead8cSSam Ravnborg int main(int argc, char **argv)
23671da177e4SLinus Torvalds {
23681da177e4SLinus Torvalds 	struct module *mod;
23691da177e4SLinus Torvalds 	struct buffer buf = { };
2370040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2371712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
23721da177e4SLinus Torvalds 	int opt;
2373c53ddacdSKirill Korotaev 	int err;
23742d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
23752d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
23761da177e4SLinus Torvalds 
2377eed380f3SGuenter Roeck 	while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:")) != -1) {
23781da177e4SLinus Torvalds 		switch (opt) {
23791da177e4SLinus Torvalds 		case 'i':
2380040fcc81SSam Ravnborg 			kernel_read = optarg;
2381040fcc81SSam Ravnborg 			break;
2382040fcc81SSam Ravnborg 		case 'I':
2383040fcc81SSam Ravnborg 			module_read = optarg;
2384040fcc81SSam Ravnborg 			external_module = 1;
23851da177e4SLinus Torvalds 			break;
23862d04b5aeSRichard Hacker 		case 'e':
23872d04b5aeSRichard Hacker 			external_module = 1;
23882d04b5aeSRichard Hacker 			extsym_iter =
23892d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
23902d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
23912d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
23922d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
23932d04b5aeSRichard Hacker 			break;
23941da177e4SLinus Torvalds 		case 'm':
23951da177e4SLinus Torvalds 			modversions = 1;
23961da177e4SLinus Torvalds 			break;
2397eed380f3SGuenter Roeck 		case 'n':
2398eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2399eed380f3SGuenter Roeck 			break;
24001da177e4SLinus Torvalds 		case 'o':
24011da177e4SLinus Torvalds 			dump_write = optarg;
24021da177e4SLinus Torvalds 			break;
24031da177e4SLinus Torvalds 		case 'a':
24041da177e4SLinus Torvalds 			all_versions = 1;
24051da177e4SLinus Torvalds 			break;
24068d8d8289SSam Ravnborg 		case 's':
24078d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
24088d8d8289SSam Ravnborg 			break;
2409588ccd73SSam Ravnborg 		case 'S':
2410588ccd73SSam Ravnborg 			sec_mismatch_verbose = 0;
2411588ccd73SSam Ravnborg 			break;
2412712f9b46SRusty Russell 		case 'T':
2413712f9b46SRusty Russell 			files_source = optarg;
2414712f9b46SRusty Russell 			break;
2415c53ddacdSKirill Korotaev 		case 'w':
2416c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2417c53ddacdSKirill Korotaev 			break;
24181da177e4SLinus Torvalds 		default:
24191da177e4SLinus Torvalds 			exit(1);
24201da177e4SLinus Torvalds 		}
24211da177e4SLinus Torvalds 	}
24221da177e4SLinus Torvalds 
2423040fcc81SSam Ravnborg 	if (kernel_read)
2424040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2425040fcc81SSam Ravnborg 	if (module_read)
2426040fcc81SSam Ravnborg 		read_dump(module_read, 0);
24272d04b5aeSRichard Hacker 	while (extsym_start) {
24282d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
24292d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
24302d04b5aeSRichard Hacker 		free(extsym_start);
24312d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
24322d04b5aeSRichard Hacker 	}
24331da177e4SLinus Torvalds 
2434df578e7dSSam Ravnborg 	while (optind < argc)
24351da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
24361da177e4SLinus Torvalds 
2437712f9b46SRusty Russell 	if (files_source)
2438712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2439712f9b46SRusty Russell 
24401da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next) {
24411da177e4SLinus Torvalds 		if (mod->skip)
24421da177e4SLinus Torvalds 			continue;
2443c96fca21SSam Ravnborg 		check_exports(mod);
2444b817f6feSSam Ravnborg 	}
2445b817f6feSSam Ravnborg 
2446c53ddacdSKirill Korotaev 	err = 0;
2447c53ddacdSKirill Korotaev 
2448b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2449d93e1719SMathias Krause 		char fname[PATH_MAX];
2450666ab414SAndi Kleen 
2451b817f6feSSam Ravnborg 		if (mod->skip)
2452b817f6feSSam Ravnborg 			continue;
24531da177e4SLinus Torvalds 
24541da177e4SLinus Torvalds 		buf.pos = 0;
24551da177e4SLinus Torvalds 
24561da177e4SLinus Torvalds 		add_header(&buf, mod);
24572449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2458a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2459c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
24601da177e4SLinus Torvalds 		add_depends(&buf, mod, modules);
24611da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
24621da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
24631da177e4SLinus Torvalds 
24641da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
24651da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
24661da177e4SLinus Torvalds 	}
24671da177e4SLinus Torvalds 
24681da177e4SLinus Torvalds 	if (dump_write)
24691da177e4SLinus Torvalds 		write_dump(dump_write);
2470588ccd73SSam Ravnborg 	if (sec_mismatch_count && !sec_mismatch_verbose)
24717c0ac495SGeert Uytterhoeven 		warn("modpost: Found %d section mismatch(es).\n"
2472e5f95c8bSSam Ravnborg 		     "To see full details build your kernel with:\n"
2473e5f95c8bSSam Ravnborg 		     "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n",
2474e5f95c8bSSam Ravnborg 		     sec_mismatch_count);
24751da177e4SLinus Torvalds 
2476c53ddacdSKirill Korotaev 	return err;
24771da177e4SLinus Torvalds }
2478