xref: /linux-6.15/scripts/mod/modpost.c (revision 47346e96)
11da177e4SLinus Torvalds /* Postprocess module symbol versions
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright 2003       Kai Germaschewski
41da177e4SLinus Torvalds  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5df578e7dSSam Ravnborg  * Copyright 2006-2008  Sam Ravnborg
61da177e4SLinus Torvalds  * Based in part on module-init-tools/depmod.c,file2alias
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds  * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Usage: modpost vmlinux module1.o module2.o ...
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
14b2e3e658SMathieu Desnoyers #define _GNU_SOURCE
15b2e3e658SMathieu Desnoyers #include <stdio.h>
161da177e4SLinus Torvalds #include <ctype.h>
175003bab8SAndrew Morton #include <string.h>
18712f9b46SRusty Russell #include <limits.h>
19d4ef1c30SRusty Russell #include <stdbool.h>
20eed380f3SGuenter Roeck #include <errno.h>
211da177e4SLinus Torvalds #include "modpost.h"
22b817f6feSSam Ravnborg #include "../../include/linux/license.h"
239e1b9b80SAlan Jenkins 
241da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
257a3ee753SMathias Krause static int modversions = 0;
261da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
277a3ee753SMathias Krause static int have_vmlinux = 0;
281da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
291da177e4SLinus Torvalds static int all_versions = 0;
30040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
31040fcc81SSam Ravnborg static int external_module = 0;
328d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
338d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
34c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
35c53ddacdSKirill Korotaev static int warn_unresolved = 0;
36bd5cbcedSRam Pai /* How a symbol is exported */
37588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
3847490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
39eed380f3SGuenter Roeck /* ignore missing files */
40eed380f3SGuenter Roeck static int ignore_missing_files;
411d082773SMatthias Maennich /* write namespace dependencies */
421d082773SMatthias Maennich static int write_namespace_deps;
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 
494fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h;
504fd3e4efSWanlong Gao  * here we use Elf_Addr instead of long for covering cross-compile
514fd3e4efSWanlong Gao  */
524fd3e4efSWanlong Gao 
534fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
544fd3e4efSWanlong Gao 
556d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
566d9a89eaSAndi Kleen 
576d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	va_list arglist;
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	va_start(arglist, fmt);
641da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
651da177e4SLinus Torvalds 	va_end(arglist);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	exit(1);
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
706d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	va_list arglist;
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 	va_start(arglist, fmt);
771da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
781da177e4SLinus Torvalds 	va_end(arglist);
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds 
816d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
822a116659SMatthew Wilcox {
832a116659SMatthew Wilcox 	va_list arglist;
842a116659SMatthew Wilcox 
852a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
862a116659SMatthew Wilcox 
872a116659SMatthew Wilcox 	va_start(arglist, fmt);
882a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
892a116659SMatthew Wilcox 	va_end(arglist);
902a116659SMatthew Wilcox }
912a116659SMatthew Wilcox 
92d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
93d4ef1c30SRusty Russell {
94d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
95d4ef1c30SRusty Russell 		return false;
96d4ef1c30SRusty Russell 
97d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
98d4ef1c30SRusty Russell }
99d4ef1c30SRusty Russell 
100040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
101040fcc81SSam Ravnborg {
102040fcc81SSam Ravnborg 	const char *myname;
103040fcc81SSam Ravnborg 
104df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
105df578e7dSSam Ravnborg 	if (myname)
106040fcc81SSam Ravnborg 		myname++;
107040fcc81SSam Ravnborg 	else
108040fcc81SSam Ravnborg 		myname = modname;
109040fcc81SSam Ravnborg 
110741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
111741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
112040fcc81SSam Ravnborg }
113040fcc81SSam Ravnborg 
1141da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1151da177e4SLinus Torvalds {
116df578e7dSSam Ravnborg 	if (!ptr)
1171da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
118df578e7dSSam Ravnborg 
1191da177e4SLinus Torvalds 	return ptr;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds /* A list of all modules we processed */
1231da177e4SLinus Torvalds static struct module *modules;
1241da177e4SLinus Torvalds 
1258b185743SMasahiro Yamada static struct module *find_module(const char *modname)
1261da177e4SLinus Torvalds {
1271da177e4SLinus Torvalds 	struct module *mod;
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1301da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1311da177e4SLinus Torvalds 			break;
1321da177e4SLinus Torvalds 	return mod;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds 
135d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1361da177e4SLinus Torvalds {
1371da177e4SLinus Torvalds 	struct module *mod;
138d4ef1c30SRusty Russell 	char *p;
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1411da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1421da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	/* strip trailing .o */
145d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
146d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
147258f7426SFrank Rowand 		mod->is_dot_o = 1;
148258f7426SFrank Rowand 	}
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	/* add to list */
1511da177e4SLinus Torvalds 	mod->name = p;
152b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1531da177e4SLinus Torvalds 	mod->next = modules;
1541da177e4SLinus Torvalds 	modules = mod;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	return mod;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds /* A hash of all exported symbols,
1601da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds struct symbol {
1651da177e4SLinus Torvalds 	struct symbol *next;
1661da177e4SLinus Torvalds 	struct module *module;
1671da177e4SLinus Torvalds 	unsigned int crc;
1681da177e4SLinus Torvalds 	int crc_valid;
169cb9b55d2SMatthias Maennich 	const char *namespace;
1701da177e4SLinus Torvalds 	unsigned int weak:1;
171040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
172040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
173040fcc81SSam Ravnborg 				    *  (only for external modules) **/
174b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
17515bfc234SDenis Efremov 	unsigned int is_static:1;  /* 1 if symbol is not global */
176bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1771da177e4SLinus Torvalds 	char name[0];
1781da177e4SLinus Torvalds };
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1831da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1841da177e4SLinus Torvalds {
1851da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1861da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1891da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1901da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds 
1955c3ead8cSSam Ravnborg /**
1965c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1975c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1985c3ead8cSSam Ravnborg  **/
1995c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
2005c3ead8cSSam Ravnborg 				   struct symbol *next)
2011da177e4SLinus Torvalds {
2021da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
2051da177e4SLinus Torvalds 	strcpy(s->name, name);
2061da177e4SLinus Torvalds 	s->weak = weak;
2071da177e4SLinus Torvalds 	s->next = next;
20815bfc234SDenis Efremov 	s->is_static = 1;
2091da177e4SLinus Torvalds 	return s;
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds /* For the hash of exported symbols */
213bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
214bd5cbcedSRam Pai 				 enum export export)
2151da177e4SLinus Torvalds {
2161da177e4SLinus Torvalds 	unsigned int hash;
2171da177e4SLinus Torvalds 	struct symbol *new;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2201da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2211da177e4SLinus Torvalds 	new->module = module;
222bd5cbcedSRam Pai 	new->export = export;
223040fcc81SSam Ravnborg 	return new;
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds 
2265c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds 	struct symbol *s;
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2311da177e4SLinus Torvalds 	if (name[0] == '.')
2321da177e4SLinus Torvalds 		name++;
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2351da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2361da177e4SLinus Torvalds 			return s;
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 	return NULL;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
241cb9b55d2SMatthias Maennich static bool contains_namespace(struct namespace_list *list,
242cb9b55d2SMatthias Maennich 			       const char *namespace)
243cb9b55d2SMatthias Maennich {
244cb9b55d2SMatthias Maennich 	struct namespace_list *ns_entry;
245cb9b55d2SMatthias Maennich 
246cb9b55d2SMatthias Maennich 	for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next)
247cb9b55d2SMatthias Maennich 		if (strcmp(ns_entry->namespace, namespace) == 0)
248cb9b55d2SMatthias Maennich 			return true;
249cb9b55d2SMatthias Maennich 
250cb9b55d2SMatthias Maennich 	return false;
251cb9b55d2SMatthias Maennich }
252cb9b55d2SMatthias Maennich 
253cb9b55d2SMatthias Maennich static void add_namespace(struct namespace_list **list, const char *namespace)
254cb9b55d2SMatthias Maennich {
255cb9b55d2SMatthias Maennich 	struct namespace_list *ns_entry;
256cb9b55d2SMatthias Maennich 
257cb9b55d2SMatthias Maennich 	if (!contains_namespace(*list, namespace)) {
258cb9b55d2SMatthias Maennich 		ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
259cb9b55d2SMatthias Maennich 					 strlen(namespace) + 1));
260cb9b55d2SMatthias Maennich 		strcpy(ns_entry->namespace, namespace);
261cb9b55d2SMatthias Maennich 		ns_entry->next = *list;
262cb9b55d2SMatthias Maennich 		*list = ns_entry;
263cb9b55d2SMatthias Maennich 	}
264cb9b55d2SMatthias Maennich }
265cb9b55d2SMatthias Maennich 
266cb9b55d2SMatthias Maennich static bool module_imports_namespace(struct module *module,
267cb9b55d2SMatthias Maennich 				     const char *namespace)
268cb9b55d2SMatthias Maennich {
269cb9b55d2SMatthias Maennich 	return contains_namespace(module->imported_namespaces, namespace);
270cb9b55d2SMatthias Maennich }
271cb9b55d2SMatthias Maennich 
2727a3ee753SMathias Krause static const struct {
273bd5cbcedSRam Pai 	const char *str;
274bd5cbcedSRam Pai 	enum export export;
275bd5cbcedSRam Pai } export_list[] = {
276bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
277c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
278bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
279c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
280bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
281bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
282bd5cbcedSRam Pai };
283bd5cbcedSRam Pai 
284bd5cbcedSRam Pai 
285bd5cbcedSRam Pai static const char *export_str(enum export ex)
286bd5cbcedSRam Pai {
287bd5cbcedSRam Pai 	return export_list[ex].str;
288bd5cbcedSRam Pai }
289bd5cbcedSRam Pai 
290bd5cbcedSRam Pai static enum export export_no(const char *s)
291bd5cbcedSRam Pai {
292bd5cbcedSRam Pai 	int i;
293df578e7dSSam Ravnborg 
294534b89a9SSam Ravnborg 	if (!s)
295534b89a9SSam Ravnborg 		return export_unknown;
296bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
297bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
298bd5cbcedSRam Pai 			return export_list[i].export;
299bd5cbcedSRam Pai 	}
300bd5cbcedSRam Pai 	return export_unknown;
301bd5cbcedSRam Pai }
302bd5cbcedSRam Pai 
3036124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
3046124c04cSMasahiro Yamada {
3056124c04cSMasahiro Yamada 	return (void *)elf->hdr +
3066124c04cSMasahiro Yamada 		elf->sechdrs[elf->secindex_strings].sh_offset +
3076124c04cSMasahiro Yamada 		sechdr->sh_name;
3086124c04cSMasahiro Yamada }
3096124c04cSMasahiro Yamada 
3106124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex)
3116124c04cSMasahiro Yamada {
3126124c04cSMasahiro Yamada 	return sech_name(elf, &elf->sechdrs[secindex]);
3136124c04cSMasahiro Yamada }
31462a26356SAlessio Igor Bogani 
31562a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
31662a26356SAlessio Igor Bogani 
31762a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
31862a26356SAlessio Igor Bogani {
31962a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
32062a26356SAlessio Igor Bogani 
32162a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
32262a26356SAlessio Igor Bogani 		return export_plain;
32362a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
32462a26356SAlessio Igor Bogani 		return export_unused;
32562a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
32662a26356SAlessio Igor Bogani 		return export_gpl;
32762a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
32862a26356SAlessio Igor Bogani 		return export_unused_gpl;
32962a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
33062a26356SAlessio Igor Bogani 		return export_gpl_future;
33162a26356SAlessio Igor Bogani 	else
33262a26356SAlessio Igor Bogani 		return export_unknown;
33362a26356SAlessio Igor Bogani }
33462a26356SAlessio Igor Bogani 
3351ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
336bd5cbcedSRam Pai {
337bd5cbcedSRam Pai 	if (sec == elf->export_sec)
338bd5cbcedSRam Pai 		return export_plain;
339c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
340c96fca21SSam Ravnborg 		return export_unused;
341bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
342bd5cbcedSRam Pai 		return export_gpl;
343c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
344c96fca21SSam Ravnborg 		return export_unused_gpl;
345bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
346bd5cbcedSRam Pai 		return export_gpl_future;
347bd5cbcedSRam Pai 	else
348bd5cbcedSRam Pai 		return export_unknown;
349bd5cbcedSRam Pai }
350bd5cbcedSRam Pai 
351cb9b55d2SMatthias Maennich static const char *sym_extract_namespace(const char **symname)
352cb9b55d2SMatthias Maennich {
353cb9b55d2SMatthias Maennich 	size_t n;
354cb9b55d2SMatthias Maennich 	char *dupsymname;
355cb9b55d2SMatthias Maennich 
356cb9b55d2SMatthias Maennich 	n = strcspn(*symname, ".");
357cb9b55d2SMatthias Maennich 	if (n < strlen(*symname) - 1) {
358cb9b55d2SMatthias Maennich 		dupsymname = NOFAIL(strdup(*symname));
359cb9b55d2SMatthias Maennich 		dupsymname[n] = '\0';
360cb9b55d2SMatthias Maennich 		*symname = dupsymname;
361cb9b55d2SMatthias Maennich 		return dupsymname + n + 1;
362cb9b55d2SMatthias Maennich 	}
363cb9b55d2SMatthias Maennich 
364cb9b55d2SMatthias Maennich 	return NULL;
365cb9b55d2SMatthias Maennich }
366cb9b55d2SMatthias Maennich 
3675c3ead8cSSam Ravnborg /**
3685c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3695c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3705c3ead8cSSam Ravnborg  **/
371cb9b55d2SMatthias Maennich static struct symbol *sym_add_exported(const char *name, const char *namespace,
372cb9b55d2SMatthias Maennich 				       struct module *mod, enum export export)
3731da177e4SLinus Torvalds {
3741da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	if (!s) {
377bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
378cb9b55d2SMatthias Maennich 		s->namespace = namespace;
3798e70c458SSam Ravnborg 	} else {
3808e70c458SSam Ravnborg 		if (!s->preloaded) {
381cb9b55d2SMatthias Maennich 			warn("%s: '%s' exported twice. Previous export was in %s%s\n",
382cb9b55d2SMatthias Maennich 			     mod->name, name, s->module->name,
3838e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ? "" : ".ko");
3844b21960fSTrent Piepho 		} else {
385baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3864b21960fSTrent Piepho 			s->module = mod;
3871da177e4SLinus Torvalds 		}
3881da177e4SLinus Torvalds 	}
3898e70c458SSam Ravnborg 	s->preloaded = 0;
390040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
391040fcc81SSam Ravnborg 	s->kernel    = 0;
392bd5cbcedSRam Pai 	s->export    = export;
393040fcc81SSam Ravnborg 	return s;
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds 
396040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
397bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
398040fcc81SSam Ravnborg {
399040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
400040fcc81SSam Ravnborg 
401b6568b1aSRusty Russell 	if (!s) {
402bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
403b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
404b6568b1aSRusty Russell 		s->preloaded = 1;
405b6568b1aSRusty Russell 	}
406040fcc81SSam Ravnborg 	s->crc = crc;
4071da177e4SLinus Torvalds 	s->crc_valid = 1;
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds 
4105c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
4111da177e4SLinus Torvalds {
4121da177e4SLinus Torvalds 	struct stat st;
413eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
4141da177e4SLinus Torvalds 	int fd;
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
417eb3d5cc6SJesper Juhl 	if (fd < 0)
4181da177e4SLinus Torvalds 		return NULL;
419eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
420eb3d5cc6SJesper Juhl 		goto failed;
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 	*size = st.st_size;
4231da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
4241da177e4SLinus Torvalds 
425eb3d5cc6SJesper Juhl failed:
426eb3d5cc6SJesper Juhl 	close(fd);
4271da177e4SLinus Torvalds 	if (map == MAP_FAILED)
4281da177e4SLinus Torvalds 		return NULL;
4291da177e4SLinus Torvalds 	return map;
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds 
4325c3ead8cSSam Ravnborg /**
4335c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
4345c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
4355c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
4365c3ead8cSSam Ravnborg   **/
4375c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
4381da177e4SLinus Torvalds {
4391da177e4SLinus Torvalds 	static char line[4096];
4401da177e4SLinus Torvalds 	int skip = 1;
4411da177e4SLinus Torvalds 	size_t len = 0;
4421da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
4431da177e4SLinus Torvalds 	char *s = line;
4441da177e4SLinus Torvalds 
445df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
4461da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
4471da177e4SLinus Torvalds 			p++;
4481da177e4SLinus Torvalds 			continue;
4491da177e4SLinus Torvalds 		}
4501da177e4SLinus Torvalds 		skip = 0;
4511da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4521da177e4SLinus Torvalds 			len++;
4531da177e4SLinus Torvalds 			*s++ = *p++;
4541da177e4SLinus Torvalds 			if (len > 4095)
4551da177e4SLinus Torvalds 				break; /* Too long, stop */
4561da177e4SLinus Torvalds 		} else {
4571da177e4SLinus Torvalds 			/* End of string */
4581da177e4SLinus Torvalds 			*s = '\0';
4591da177e4SLinus Torvalds 			return line;
4601da177e4SLinus Torvalds 		}
4611da177e4SLinus Torvalds 	}
4621da177e4SLinus Torvalds 	/* End of buffer */
4631da177e4SLinus Torvalds 	return NULL;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds 
4665c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4671da177e4SLinus Torvalds {
4681da177e4SLinus Torvalds 	munmap(file, size);
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds 
47185bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4721da177e4SLinus Torvalds {
4731da177e4SLinus Torvalds 	unsigned int i;
47485bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4751da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4761da177e4SLinus Torvalds 	Elf_Sym  *sym;
4771ce53adfSDenys Vlasenko 	const char *secstrings;
4781ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4811da177e4SLinus Torvalds 	if (!hdr) {
482eed380f3SGuenter Roeck 		if (ignore_missing_files) {
483eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
484eed380f3SGuenter Roeck 				strerror(errno));
485eed380f3SGuenter Roeck 			return 0;
486eed380f3SGuenter Roeck 		}
4871da177e4SLinus Torvalds 		perror(filename);
4886803dc0eSSam Ravnborg 		exit(1);
4891da177e4SLinus Torvalds 	}
4901da177e4SLinus Torvalds 	info->hdr = hdr;
49185bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
49285bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
49385bd2fddSSam Ravnborg 		return 0;
49485bd2fddSSam Ravnborg 	}
49585bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
49685bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
49785bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
49885bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
49985bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
50085bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
50185bd2fddSSam Ravnborg 		return 0;
50285bd2fddSSam Ravnborg 	}
5031da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
504ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
5057d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
5067d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
5077d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
5087d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
5097d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
5107d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
5117d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
5127d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
5137d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
5147d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
5157d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
5167d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
5171da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
5181da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
5191da177e4SLinus Torvalds 
520a83710e5SPetr Stetiar 	/* Check if file offset is correct */
521a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
522df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
523df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
524df578e7dSSam Ravnborg 		      filename, info->size);
525a83710e5SPetr Stetiar 		return 0;
526a83710e5SPetr Stetiar 	}
527a83710e5SPetr Stetiar 
5286845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
5291ce53adfSDenys Vlasenko 		/*
5301ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
5311ce53adfSDenys Vlasenko 		 * read count from .sh_size.
5321ce53adfSDenys Vlasenko 		 */
5331ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
5341ce53adfSDenys Vlasenko 	}
5351ce53adfSDenys Vlasenko 	else {
5361ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
5371ce53adfSDenys Vlasenko 	}
5381ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
5396845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
5401ce53adfSDenys Vlasenko 	}
5411ce53adfSDenys Vlasenko 	else {
5421ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
5431ce53adfSDenys Vlasenko 	}
5441ce53adfSDenys Vlasenko 
5451da177e4SLinus Torvalds 	/* Fix endianness in section headers */
5461ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
5477d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
5481da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
5497d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
5507d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5511da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5521da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5531da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
554ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5557d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5567d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5571da177e4SLinus Torvalds 	}
5581da177e4SLinus Torvalds 	/* Find symbol table. */
5591ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5601ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
561bd5cbcedSRam Pai 		const char *secname;
56256fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5631da177e4SLinus Torvalds 
56456fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
565df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
566df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
567df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
568df578e7dSSam Ravnborg 			      sizeof(*hdr));
56985bd2fddSSam Ravnborg 			return 0;
57085bd2fddSSam Ravnborg 		}
571bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
572bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
57356fc82c5STejun Heo 			if (nobits)
57456fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5751da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5761da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
577bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
578bd5cbcedSRam Pai 			info->export_sec = i;
579c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
580c96fca21SSam Ravnborg 			info->export_unused_sec = i;
581bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
582bd5cbcedSRam Pai 			info->export_gpl_sec = i;
583c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
584c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
585bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
586bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
587bd5cbcedSRam Pai 
5881ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5891ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
5901ce53adfSDenys Vlasenko 			symtab_idx = i;
5911ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
5921ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
5931ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
5941ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5956845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
5961da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
5971ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
5981ce53adfSDenys Vlasenko 		}
5991ce53adfSDenys Vlasenko 
6001ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
6011ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
6021ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
6031ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
6041ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
6051ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
6061ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6071ce53adfSDenys Vlasenko 		}
6081da177e4SLinus Torvalds 	}
609df578e7dSSam Ravnborg 	if (!info->symtab_start)
610cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
611df578e7dSSam Ravnborg 
6121da177e4SLinus Torvalds 	/* Fix endianness in symbols */
6131da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
6141da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
6151da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
6161da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
6171da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
6181da177e4SLinus Torvalds 	}
6191ce53adfSDenys Vlasenko 
6201ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
6211ce53adfSDenys Vlasenko 		Elf32_Word *p;
6226845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
6231ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
6246845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
6251ce53adfSDenys Vlasenko 			      symtab_idx);
6261ce53adfSDenys Vlasenko 		/* Fix endianness */
6271ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
6281ce53adfSDenys Vlasenko 		     p++)
6291ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
6301ce53adfSDenys Vlasenko 	}
6311ce53adfSDenys Vlasenko 
63285bd2fddSSam Ravnborg 	return 1;
6331da177e4SLinus Torvalds }
6341da177e4SLinus Torvalds 
6355c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
6361da177e4SLinus Torvalds {
6371da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
6381da177e4SLinus Torvalds }
6391da177e4SLinus Torvalds 
6404d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
6414d7365d6SSam Ravnborg {
6424d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
643b2c5cdcfSMasahiro Yamada 	if (strcmp(symname, "__this_module") == 0)
6444d7365d6SSam Ravnborg 		return 1;
6454d7365d6SSam Ravnborg 	/* ignore global offset table */
6464d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
6474d7365d6SSam Ravnborg 		return 1;
6484d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
6494d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
650d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr_") ||
651d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr_") ||
652d62c4765SMasahiro Yamada 		    strstarts(symname, "_rest32gpr_") ||
653d62c4765SMasahiro Yamada 		    strstarts(symname, "_save32gpr_") ||
654d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
655d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_"))
6564d7365d6SSam Ravnborg 			return 1;
6577fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6587fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
659d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr0_") ||
660d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr0_") ||
661d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
662d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_") ||
663c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6647fca5dc8SStephen Rothwell 			return 1;
6654d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6664d7365d6SSam Ravnborg 	return 0;
6674d7365d6SSam Ravnborg }
6684d7365d6SSam Ravnborg 
6695c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6701da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6711da177e4SLinus Torvalds {
6721da177e4SLinus Torvalds 	unsigned int crc;
67362a26356SAlessio Igor Bogani 	enum export export;
674d8c1eb86SNicholas Piggin 	bool is_crc = false;
675cb9b55d2SMatthias Maennich 	const char *name, *namespace;
67662a26356SAlessio Igor Bogani 
677258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
678d62c4765SMasahiro Yamada 	    strstarts(symname, "__ksymtab"))
67962a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
68062a26356SAlessio Igor Bogani 	else
68162a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	/* CRC'd symbol */
684d62c4765SMasahiro Yamada 	if (strstarts(symname, "__crc_")) {
685d8c1eb86SNicholas Piggin 		is_crc = true;
6861da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
68756067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
68856067812SArd Biesheuvel 			unsigned int *crcp;
68956067812SArd Biesheuvel 
69056067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
69156067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
69256067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
69356067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
69456067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
69554a7151bSFredrik Noring 			crc = TO_NATIVE(*crcp);
69656067812SArd Biesheuvel 		}
697b2c5cdcfSMasahiro Yamada 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
698bd5cbcedSRam Pai 				export);
6991da177e4SLinus Torvalds 	}
700b5064654SAndi Kleen 
701b5064654SAndi Kleen 	switch (sym->st_shndx) {
702b5064654SAndi Kleen 	case SHN_COMMON:
703d62c4765SMasahiro Yamada 		if (strstarts(symname, "__gnu_lto_")) {
704ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
705ef178f92SAndi Kleen 		} else
706b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
7071da177e4SLinus Torvalds 		break;
7081da177e4SLinus Torvalds 	case SHN_UNDEF:
7091da177e4SLinus Torvalds 		/* undefined symbol */
7101da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
7111da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
7121da177e4SLinus Torvalds 			break;
7134d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
7141da177e4SLinus Torvalds 			break;
7158d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
7168d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
7178d529014SBen Colline /* add compatibility with older glibc */
7188d529014SBen Colline #ifndef STT_SPARC_REGISTER
7198d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
7208d529014SBen Colline #endif
7211da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
7221da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
7231da177e4SLinus Torvalds 			/* Ignore register directives. */
7248d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
7251da177e4SLinus Torvalds 				break;
7267caaeabbSAl Viro 			if (symname[0] == '.') {
7271f3aa900SRandy Dunlap 				char *munged = NOFAIL(strdup(symname));
7287caaeabbSAl Viro 				munged[0] = '_';
7297caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
7307caaeabbSAl Viro 				symname = munged;
7317caaeabbSAl Viro 			}
7321da177e4SLinus Torvalds 		}
7331da177e4SLinus Torvalds #endif
7341da177e4SLinus Torvalds 
735d8c1eb86SNicholas Piggin 		if (is_crc) {
736d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
737b2c5cdcfSMasahiro Yamada 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
738b2c5cdcfSMasahiro Yamada 			     symname + strlen("__crc_"), mod->name, e);
739d8c1eb86SNicholas Piggin 		}
740b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
7411da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
7421da177e4SLinus Torvalds 					  mod->unres);
7431da177e4SLinus Torvalds 		break;
7441da177e4SLinus Torvalds 	default:
7451da177e4SLinus Torvalds 		/* All exported symbols */
746d62c4765SMasahiro Yamada 		if (strstarts(symname, "__ksymtab_")) {
747cb9b55d2SMatthias Maennich 			name = symname + strlen("__ksymtab_");
748cb9b55d2SMatthias Maennich 			namespace = sym_extract_namespace(&name);
749cb9b55d2SMatthias Maennich 			sym_add_exported(name, namespace, mod, export);
7501da177e4SLinus Torvalds 		}
751b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "init_module") == 0)
7521da177e4SLinus Torvalds 			mod->has_init = 1;
753b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "cleanup_module") == 0)
7541da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7551da177e4SLinus Torvalds 		break;
7561da177e4SLinus Torvalds 	}
7571da177e4SLinus Torvalds }
7581da177e4SLinus Torvalds 
7595c3ead8cSSam Ravnborg /**
7605c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7615c3ead8cSSam Ravnborg  **/
7621da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7631da177e4SLinus Torvalds {
7641da177e4SLinus Torvalds 	/* Skip non-zero chars */
7651da177e4SLinus Torvalds 	while (string[0]) {
7661da177e4SLinus Torvalds 		string++;
7671da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7681da177e4SLinus Torvalds 			return NULL;
7691da177e4SLinus Torvalds 	}
7701da177e4SLinus Torvalds 
7711da177e4SLinus Torvalds 	/* Skip any zero padding. */
7721da177e4SLinus Torvalds 	while (!string[0]) {
7731da177e4SLinus Torvalds 		string++;
7741da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7751da177e4SLinus Torvalds 			return NULL;
7761da177e4SLinus Torvalds 	}
7771da177e4SLinus Torvalds 	return string;
7781da177e4SLinus Torvalds }
7791da177e4SLinus Torvalds 
780bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag,
781bca2cceeSMasahiro Yamada 			      char *prev)
7821da177e4SLinus Torvalds {
7831da177e4SLinus Torvalds 	char *p;
7841da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
785bca2cceeSMasahiro Yamada 	char *modinfo = info->modinfo;
786bca2cceeSMasahiro Yamada 	unsigned long size = info->modinfo_len;
7871da177e4SLinus Torvalds 
788bca2cceeSMasahiro Yamada 	if (prev) {
789bca2cceeSMasahiro Yamada 		size -= prev - modinfo;
790bca2cceeSMasahiro Yamada 		modinfo = next_string(prev, &size);
791b817f6feSSam Ravnborg 	}
792b817f6feSSam Ravnborg 
7931da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
7941da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7951da177e4SLinus Torvalds 			return p + taglen + 1;
7961da177e4SLinus Torvalds 	}
7971da177e4SLinus Torvalds 	return NULL;
7981da177e4SLinus Torvalds }
7991da177e4SLinus Torvalds 
800bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag)
801b817f6feSSam Ravnborg 
802b817f6feSSam Ravnborg {
803bca2cceeSMasahiro Yamada 	return get_next_modinfo(info, tag, NULL);
804b817f6feSSam Ravnborg }
805b817f6feSSam Ravnborg 
80693684d3bSSam Ravnborg /**
8074c8fbca5SSam Ravnborg  * Test if string s ends in string sub
8084c8fbca5SSam Ravnborg  * return 0 if match
8094c8fbca5SSam Ravnborg  **/
8104c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
8114c8fbca5SSam Ravnborg {
8124c8fbca5SSam Ravnborg 	int slen, sublen;
8134c8fbca5SSam Ravnborg 
8144c8fbca5SSam Ravnborg 	if (!s || !sub)
8154c8fbca5SSam Ravnborg 		return 1;
8164c8fbca5SSam Ravnborg 
8174c8fbca5SSam Ravnborg 	slen = strlen(s);
8184c8fbca5SSam Ravnborg 	sublen = strlen(sub);
8194c8fbca5SSam Ravnborg 
8204c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
8214c8fbca5SSam Ravnborg 		return 1;
8224c8fbca5SSam Ravnborg 
8234c8fbca5SSam Ravnborg 	if (sublen > slen)
8244c8fbca5SSam Ravnborg 		return 1;
8254c8fbca5SSam Ravnborg 
8264c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
8274c8fbca5SSam Ravnborg }
8284c8fbca5SSam Ravnborg 
829ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
830ff13f926SSam Ravnborg {
83158fb0d4fSSam Ravnborg 	if (sym)
832ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
83358fb0d4fSSam Ravnborg 	else
834f666751aSSam Ravnborg 		return "(unknown)";
835ff13f926SSam Ravnborg }
836ff13f926SSam Ravnborg 
83710668220SSam Ravnborg /* The pattern is an array of simple patterns.
83810668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
8396c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
84010668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
84109c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
84210668220SSam Ravnborg  */
8435c725138STrevor Keith static int match(const char *sym, const char * const pat[])
84410668220SSam Ravnborg {
84510668220SSam Ravnborg 	const char *p;
84610668220SSam Ravnborg 	while (*pat) {
84710668220SSam Ravnborg 		p = *pat++;
84810668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
84910668220SSam Ravnborg 
85009c20c03SPaul Gortmaker 		/* "*foo*" */
85109c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
8526f02bdfcSDenis Efremov 			char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
8536f02bdfcSDenis Efremov 			char *here = strstr(sym, bare);
85409c20c03SPaul Gortmaker 
85509c20c03SPaul Gortmaker 			free(bare);
85609c20c03SPaul Gortmaker 			if (here != NULL)
85709c20c03SPaul Gortmaker 				return 1;
85809c20c03SPaul Gortmaker 		}
8596c5bd235SSam Ravnborg 		/* "*foo" */
86009c20c03SPaul Gortmaker 		else if (*p == '*') {
8616c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8626c5bd235SSam Ravnborg 				return 1;
8636c5bd235SSam Ravnborg 		}
86410668220SSam Ravnborg 		/* "foo*" */
8656c5bd235SSam Ravnborg 		else if (*endp == '*') {
86610668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
86710668220SSam Ravnborg 				return 1;
86810668220SSam Ravnborg 		}
86910668220SSam Ravnborg 		/* no wildcards */
87010668220SSam Ravnborg 		else {
87110668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
87210668220SSam Ravnborg 				return 1;
87310668220SSam Ravnborg 		}
87410668220SSam Ravnborg 	}
87510668220SSam Ravnborg 	/* no match */
87610668220SSam Ravnborg 	return 0;
87710668220SSam Ravnborg }
87810668220SSam Ravnborg 
87910668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8807a3ee753SMathias Krause static const char *const section_white_list[] =
8814391ed6aSSam Ravnborg {
8824391ed6aSSam Ravnborg 	".comment*",
8834391ed6aSSam Ravnborg 	".debug*",
8844d10c223SChen Gang 	".cranges",		/* sh64 */
8851121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
886739d875dSDavid Howells 	".GCC.command.line",	/* record-gcc-switches */
8874391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8884391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8894391ed6aSSam Ravnborg 	".stab*",
8904391ed6aSSam Ravnborg 	".note*",
8914391ed6aSSam Ravnborg 	".got*",
8924391ed6aSSam Ravnborg 	".toc*",
893af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
894af42e970SMax Filippov 	".xt.lit",         /* xtensa */
895f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
896f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
897d1189c63SNoam Camus 	".cmem*",			/* EZchip */
898d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
899ef178f92SAndi Kleen 	".gnu.lto*",
900e390f9a9SJosh Poimboeuf 	".discard.*",
9014391ed6aSSam Ravnborg 	NULL
9024391ed6aSSam Ravnborg };
90310668220SSam Ravnborg 
904e241a630SSam Ravnborg /*
905b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
906e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
907b614a697SAnders Kaseorg  * without "ax" / "aw".
908e241a630SSam Ravnborg  */
909b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
910b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
911e241a630SSam Ravnborg {
912b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
913e241a630SSam Ravnborg 
914b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
915b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
916b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
917b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
918b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
919e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
920e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
921e241a630SSam Ravnborg 		     modname, sec);
922e241a630SSam Ravnborg 	}
923e241a630SSam Ravnborg }
924e241a630SSam Ravnborg 
925e241a630SSam Ravnborg 
926e241a630SSam Ravnborg 
927eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
928a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
929a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
930eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
931a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
93210668220SSam Ravnborg 
933eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
934a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
935eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
936a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
93710668220SSam Ravnborg 
938bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
939a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
940a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
941a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
942bb15d8dbSSebastian Andrzej Siewior 
943e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
944e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
9454a31a229SUwe Kleine-König 
9464a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
9474a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
94810668220SSam Ravnborg 
949a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
950157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
9516727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
95252dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
953673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
954673c2c34SChris Metcalf 		".coldtext"
95510668220SSam Ravnborg 
956fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
957fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
958eb8f6890SSam Ravnborg 
959fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
960fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
961eb8f6890SSam Ravnborg 
96252dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
96352dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
96452dc0595SQuentin Casasnovas 
9656c5bd235SSam Ravnborg /* init data sections */
9667a3ee753SMathias Krause static const char *const init_data_sections[] =
9677a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9686c5bd235SSam Ravnborg 
9696c5bd235SSam Ravnborg /* all init sections */
9707a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9716c5bd235SSam Ravnborg 
9726c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9737a3ee753SMathias Krause static const char *const init_exit_sections[] =
974eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9756c5bd235SSam Ravnborg 
9764a3893d0SPaul Gortmaker /* all text sections */
9774a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9784a3893d0SPaul Gortmaker 
9796c5bd235SSam Ravnborg /* data section */
9807a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9816c5bd235SSam Ravnborg 
9826c5bd235SSam Ravnborg 
9836c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
984af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
985af92a82dSUwe Kleine-König 	"*driver",							\
986af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
987af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
988af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
989af92a82dSUwe Kleine-König 	"*_ops",							\
990af92a82dSUwe Kleine-König 	"*_probe",							\
991af92a82dSUwe Kleine-König 	"*_probe_one",							\
992af92a82dSUwe Kleine-König 	"*_console"
9936c5bd235SSam Ravnborg 
9947a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
9957a3ee753SMathias Krause static const char *const linker_symbols[] =
9966c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
9974a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
9986c5bd235SSam Ravnborg 
999588ccd73SSam Ravnborg enum mismatch {
1000bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
1001bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
1002bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
1003bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
1004bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
1005bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
1006bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
1007bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
1008588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
100952dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
1010588ccd73SSam Ravnborg };
1011588ccd73SSam Ravnborg 
1012e5d8f59aSQuentin Casasnovas /**
1013e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
1014e5d8f59aSQuentin Casasnovas  *
1015e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
1016e5d8f59aSQuentin Casasnovas  *
1017e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
1018e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
1019e5d8f59aSQuentin Casasnovas  *
1020e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
1021e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
1022e5d8f59aSQuentin Casasnovas  *
1023e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
1024e5d8f59aSQuentin Casasnovas  *
1025e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
1026e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
1027e5d8f59aSQuentin Casasnovas  *
1028e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
1029e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
1030e5d8f59aSQuentin Casasnovas  *
1031e5d8f59aSQuentin Casasnovas  */
103210668220SSam Ravnborg struct sectioncheck {
103310668220SSam Ravnborg 	const char *fromsec[20];
1034050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
1035050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
1036588ccd73SSam Ravnborg 	enum mismatch mismatch;
1037af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
1038644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
1039644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
1040644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
1041644e8f14SQuentin Casasnovas 
104210668220SSam Ravnborg };
104310668220SSam Ravnborg 
104452dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
104552dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
104652dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
104752dc0595SQuentin Casasnovas 				     const char *fromsec);
104852dc0595SQuentin Casasnovas 
10497a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
105010668220SSam Ravnborg /* Do not reference init/exit code/data from
105110668220SSam Ravnborg  * normal code and data
105210668220SSam Ravnborg  */
105310668220SSam Ravnborg {
1054588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1055050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1056bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1057af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1058588ccd73SSam Ravnborg },
1059588ccd73SSam Ravnborg {
1060588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1061050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1062bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1063af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1064588ccd73SSam Ravnborg },
1065588ccd73SSam Ravnborg {
10660db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1067050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10680db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10690db25245SUwe Kleine-König 	.symbol_white_list = {
10700db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10710db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10720db25245SUwe Kleine-König 	},
10730db25245SUwe Kleine-König },
10740db25245SUwe Kleine-König {
1075588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1076050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1077bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1078af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1079588ccd73SSam Ravnborg },
1080588ccd73SSam Ravnborg {
1081588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1082050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1083bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1084af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1085eb8f6890SSam Ravnborg },
1086e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1087eb8f6890SSam Ravnborg {
10884a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1089050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1090bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1091af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1092eb8f6890SSam Ravnborg },
1093e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1094eb8f6890SSam Ravnborg {
10954a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1096050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1097bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1098af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
109910668220SSam Ravnborg },
110010668220SSam Ravnborg /* Do not use exit code/data from init code */
110110668220SSam Ravnborg {
1102eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1103050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1104bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1105af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
110610668220SSam Ravnborg },
110710668220SSam Ravnborg /* Do not use init code/data from exit code */
110810668220SSam Ravnborg {
1109eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1110050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1111bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1112af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
111310668220SSam Ravnborg },
1114bb15d8dbSSebastian Andrzej Siewior {
1115bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1116050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1117bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1118bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1119bb15d8dbSSebastian Andrzej Siewior },
112010668220SSam Ravnborg /* Do not export init/exit functions or data */
112110668220SSam Ravnborg {
112210668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1123050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1124af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1125af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
112652dc0595SQuentin Casasnovas },
112752dc0595SQuentin Casasnovas {
112852dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
112952dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
113052dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
113152dc0595SQuentin Casasnovas 	 */
113252dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
113352dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
113452dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
113552dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
113610668220SSam Ravnborg }
113710668220SSam Ravnborg };
113810668220SSam Ravnborg 
11390d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
11400d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
114110668220SSam Ravnborg {
114210668220SSam Ravnborg 	int i;
114310668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
114410668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
114510668220SSam Ravnborg 
1146c5c3439aSQuentin Casasnovas 	/*
1147c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1148c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1149739d875dSDavid Howells 	 * doesn't make much sense and causes build failures on parisc
1150739d875dSDavid Howells 	 * architectures.
1151c5c3439aSQuentin Casasnovas 	 */
1152c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1153c5c3439aSQuentin Casasnovas 		return NULL;
1154c5c3439aSQuentin Casasnovas 
115510668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1156050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1157050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11580d2a636eSUwe Kleine-König 				return check;
1159050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1160050e57fdSQuentin Casasnovas 				return check;
1161050e57fdSQuentin Casasnovas 		}
116210668220SSam Ravnborg 		check++;
116310668220SSam Ravnborg 	}
11640d2a636eSUwe Kleine-König 	return NULL;
116510668220SSam Ravnborg }
116610668220SSam Ravnborg 
11674c8fbca5SSam Ravnborg /**
11684c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11690e0d314eSSam Ravnborg  *
11704c8fbca5SSam Ravnborg  * Pattern 1:
11714c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11724c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11734c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11744c8fbca5SSam Ravnborg  *   this pattern.
11754c8fbca5SSam Ravnborg  *   The pattern is identified by:
11764c8fbca5SSam Ravnborg  *   tosec   = .init.data
11779209aed0SSam Ravnborg  *   fromsec = .data*
11784c8fbca5SSam Ravnborg  *   atsym   =__param*
11794c8fbca5SSam Ravnborg  *
11806a841528SRusty Russell  * Pattern 1a:
11816a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11826a841528SRusty Russell  *   The pattern is identified by:
11836a841528SRusty Russell  *   tosec   = .init.text
11846a841528SRusty Russell  *   fromsec = .data*
11856a841528SRusty Russell  *   atsym   = __param_ops_*
11866a841528SRusty Russell  *
11874c8fbca5SSam Ravnborg  * Pattern 2:
118872ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11894c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
11904c8fbca5SSam Ravnborg  *   the pattern is identified by:
119183cda2bbSSam Ravnborg  *   tosec   = init or exit section
119283cda2bbSSam Ravnborg  *   fromsec = data section
1193df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1194df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1195ee6a8545SVivek Goyal  *
1196ee6a8545SVivek Goyal  * Pattern 3:
1197c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
11989bf8cb9bSSam Ravnborg  *
11991d8af559SSam Ravnborg  * Pattern 4:
1200ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1201ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1202ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1203ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1204ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1205ee6a8545SVivek Goyal  *   This pattern is identified by
1206ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
12079bf8cb9bSSam Ravnborg  *
12084a3893d0SPaul Gortmaker  * Pattern 5:
12094a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
12104a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
12114a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
12124a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
12134a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
12144a3893d0SPaul Gortmaker  *   This pattern is identified by
12154a3893d0SPaul Gortmaker  *   tosec   = init section
12164a3893d0SPaul Gortmaker  *   fromsec = text section
12174a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
12184a3893d0SPaul Gortmaker  *
1219a4d26f1aSPaul Walmsley  * Pattern 6:
1220a4d26f1aSPaul Walmsley  *   Hide section mismatch warnings for ELF local symbols.  The goal
1221a4d26f1aSPaul Walmsley  *   is to eliminate false positive modpost warnings caused by
1222a4d26f1aSPaul Walmsley  *   compiler-generated ELF local symbol names such as ".LANCHOR1".
1223a4d26f1aSPaul Walmsley  *   Autogenerated symbol names bypass modpost's "Pattern 2"
1224a4d26f1aSPaul Walmsley  *   whitelisting, which relies on pattern-matching against symbol
1225a4d26f1aSPaul Walmsley  *   names to work.  (One situation where gcc can autogenerate ELF
1226a4d26f1aSPaul Walmsley  *   local symbols is when "-fsection-anchors" is used.)
12274c8fbca5SSam Ravnborg  **/
1228af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1229af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
123058fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
12314c8fbca5SSam Ravnborg {
12324c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
12336c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
12346c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1235d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param"))
123658fb0d4fSSam Ravnborg 		return 0;
12374c8fbca5SSam Ravnborg 
12386a841528SRusty Russell 	/* Check for pattern 1a */
12396a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
12406a841528SRusty Russell 	    match(fromsec, data_sections) &&
1241d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param_ops_"))
12426a841528SRusty Russell 		return 0;
12436a841528SRusty Russell 
12444c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
12456c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
12466c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1247af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
124858fb0d4fSSam Ravnborg 		return 0;
12494c8fbca5SSam Ravnborg 
12509bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
12516c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
12526c5bd235SSam Ravnborg 	    match(tosec, init_sections))
125358fb0d4fSSam Ravnborg 		return 0;
1254f8657e1bSVivek Goyal 
12551d8af559SSam Ravnborg 	/* Check for pattern 4 */
125658fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
125793659af1SSam Ravnborg 		return 0;
125858fb0d4fSSam Ravnborg 
12594a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12604a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12614a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12624a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12634a3893d0SPaul Gortmaker 		return 0;
12644a3893d0SPaul Gortmaker 
1265a4d26f1aSPaul Walmsley 	/* Check for pattern 6 */
1266a4d26f1aSPaul Walmsley 	if (strstarts(fromsym, ".L"))
1267a4d26f1aSPaul Walmsley 		return 0;
1268a4d26f1aSPaul Walmsley 
126958fb0d4fSSam Ravnborg 	return 1;
12704c8fbca5SSam Ravnborg }
12714c8fbca5SSam Ravnborg 
12725818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str)
12735818c683SSami Tolvanen {
12745818c683SSami Tolvanen 	return str[0] == '$' && strchr("axtd", str[1])
12755818c683SSami Tolvanen 	       && (str[2] == '\0' || str[2] == '.');
12765818c683SSami Tolvanen }
12775818c683SSami Tolvanen 
12785818c683SSami Tolvanen /*
12795818c683SSami Tolvanen  * If there's no name there, ignore it; likewise, ignore it if it's
12805818c683SSami Tolvanen  * one of the magic symbols emitted used by current ARM tools.
12815818c683SSami Tolvanen  *
12825818c683SSami Tolvanen  * Otherwise if find_symbols_between() returns those symbols, they'll
12835818c683SSami Tolvanen  * fail the whitelist tests and cause lots of false alarms ... fixable
12845818c683SSami Tolvanen  * only by merging __exit and __init sections into __text, bloating
12855818c683SSami Tolvanen  * the kernel (which is especially evil on embedded platforms).
12865818c683SSami Tolvanen  */
12875818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
12885818c683SSami Tolvanen {
12895818c683SSami Tolvanen 	const char *name = elf->strtab + sym->st_name;
12905818c683SSami Tolvanen 
12915818c683SSami Tolvanen 	if (!name || !strlen(name))
12925818c683SSami Tolvanen 		return 0;
12935818c683SSami Tolvanen 	return !is_arm_mapping_symbol(name);
12945818c683SSami Tolvanen }
12955818c683SSami Tolvanen 
12964c8fbca5SSam Ravnborg /**
129793684d3bSSam Ravnborg  * Find symbol based on relocation record info.
129893684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
129993684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
130093684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
130193684d3bSSam Ravnborg  * based on section and address.
130293684d3bSSam Ravnborg  *  **/
13039ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
130493684d3bSSam Ravnborg 				Elf_Sym *relsym)
130593684d3bSSam Ravnborg {
130693684d3bSSam Ravnborg 	Elf_Sym *sym;
13079ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
13089ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
13099ad21c3fSSam Ravnborg 	Elf64_Sword d;
13101ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
131193684d3bSSam Ravnborg 
131293684d3bSSam Ravnborg 	if (relsym->st_name != 0)
131393684d3bSSam Ravnborg 		return relsym;
13141ce53adfSDenys Vlasenko 
13151ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
131693684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
13171ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
131893684d3bSSam Ravnborg 			continue;
1319ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1320ae4ac123SAtsushi Nemoto 			continue;
13215818c683SSami Tolvanen 		if (!is_valid_name(elf, sym))
13225818c683SSami Tolvanen 			continue;
132393684d3bSSam Ravnborg 		if (sym->st_value == addr)
132493684d3bSSam Ravnborg 			return sym;
13259ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
13269ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
13279ad21c3fSSam Ravnborg 		if (d < 0)
13289ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
13299ad21c3fSSam Ravnborg 		if (d < distance) {
13309ad21c3fSSam Ravnborg 			distance = d;
13319ad21c3fSSam Ravnborg 			near = sym;
133293684d3bSSam Ravnborg 		}
13339ad21c3fSSam Ravnborg 	}
13349ad21c3fSSam Ravnborg 	/* We need a close match */
13359ad21c3fSSam Ravnborg 	if (distance < 20)
13369ad21c3fSSam Ravnborg 		return near;
13379ad21c3fSSam Ravnborg 	else
133893684d3bSSam Ravnborg 		return NULL;
133993684d3bSSam Ravnborg }
134093684d3bSSam Ravnborg 
1341b39927cfSSam Ravnborg /*
134243c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
134343c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
134443c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
134543c74d17SSam Ravnborg  * it is, but this works for now.
1346b39927cfSSam Ravnborg  **/
1347157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1348157c23c8SSam Ravnborg 				 const char *sec)
1349b39927cfSSam Ravnborg {
1350b39927cfSSam Ravnborg 	Elf_Sym *sym;
1351157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1352157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1353b39927cfSSam Ravnborg 
1354b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1355b39927cfSSam Ravnborg 		const char *symsec;
1356b39927cfSSam Ravnborg 
13571ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1358b39927cfSSam Ravnborg 			continue;
13591ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1360b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1361b39927cfSSam Ravnborg 			continue;
1362da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1363da68d61fSDavid Brownell 			continue;
1364b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1365157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1366157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1367157c23c8SSam Ravnborg 				near = sym;
1368157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1369157c23c8SSam Ravnborg 				near = sym;
137043c74d17SSam Ravnborg 			}
1371b39927cfSSam Ravnborg 		}
1372b39927cfSSam Ravnborg 	}
1373157c23c8SSam Ravnborg 	return near;
1374157c23c8SSam Ravnborg }
1375b39927cfSSam Ravnborg 
137658fb0d4fSSam Ravnborg /*
1377588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1378588ccd73SSam Ravnborg  * .init.text => __init
1379588ccd73SSam Ravnborg  * .memexitconst => __memconst
1380588ccd73SSam Ravnborg  * etc.
1381cbcf14a9SAndy Shevchenko  *
1382cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1383cbcf14a9SAndy Shevchenko  * method should free it after usage.
1384588ccd73SSam Ravnborg */
1385588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1386588ccd73SSam Ravnborg {
1387588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
13881f3aa900SRandy Dunlap 		char *p = NOFAIL(malloc(20));
1389588ccd73SSam Ravnborg 		char *r = p;
1390588ccd73SSam Ravnborg 
1391588ccd73SSam Ravnborg 		*p++ = '_';
1392588ccd73SSam Ravnborg 		*p++ = '_';
1393588ccd73SSam Ravnborg 		if (*s == '.')
1394588ccd73SSam Ravnborg 			s++;
1395588ccd73SSam Ravnborg 		while (*s && *s != '.')
1396588ccd73SSam Ravnborg 			*p++ = *s++;
1397588ccd73SSam Ravnborg 		*p = '\0';
1398588ccd73SSam Ravnborg 		if (*s == '.')
1399588ccd73SSam Ravnborg 			s++;
1400588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1401588ccd73SSam Ravnborg 			strcat(p, "const ");
1402588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1403588ccd73SSam Ravnborg 			strcat(p, "data ");
1404588ccd73SSam Ravnborg 		else
1405588ccd73SSam Ravnborg 			strcat(p, " ");
1406cbcf14a9SAndy Shevchenko 		return r;
1407588ccd73SSam Ravnborg 	} else {
14081f3aa900SRandy Dunlap 		return NOFAIL(strdup(""));
1409588ccd73SSam Ravnborg 	}
1410588ccd73SSam Ravnborg }
1411588ccd73SSam Ravnborg 
1412588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1413588ccd73SSam Ravnborg {
1414588ccd73SSam Ravnborg 	if (sym)
1415588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1416588ccd73SSam Ravnborg 	else
1417f666751aSSam Ravnborg 		return -1;
1418588ccd73SSam Ravnborg }
1419588ccd73SSam Ravnborg 
142000759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
142100759c0eSRandy Dunlap {
142200759c0eSRandy Dunlap 	const char *const *s = list;
142300759c0eSRandy Dunlap 
142400759c0eSRandy Dunlap 	while (*s) {
142500759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
142600759c0eSRandy Dunlap 		s++;
142700759c0eSRandy Dunlap 		if (*s)
142800759c0eSRandy Dunlap 			fprintf(stderr, ", ");
142900759c0eSRandy Dunlap 	}
143000759c0eSRandy Dunlap 	fprintf(stderr, "\n");
143100759c0eSRandy Dunlap }
143200759c0eSRandy Dunlap 
1433356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1434356ad538SQuentin Casasnovas {
1435356ad538SQuentin Casasnovas 	switch (is_func) {
1436356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1437356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1438356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1439356ad538SQuentin Casasnovas 	}
1440356ad538SQuentin Casasnovas }
1441356ad538SQuentin Casasnovas 
1442588ccd73SSam Ravnborg /*
1443b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1444b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
14454c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
144658fb0d4fSSam Ravnborg  */
14470d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
14480d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
144958fb0d4fSSam Ravnborg 				const char *fromsec,
145058fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
145158fb0d4fSSam Ravnborg 				const char *fromsym,
1452588ccd73SSam Ravnborg 				int from_is_func,
1453588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1454588ccd73SSam Ravnborg 				int to_is_func)
1455b39927cfSSam Ravnborg {
1456588ccd73SSam Ravnborg 	const char *from, *from_p;
1457588ccd73SSam Ravnborg 	const char *to, *to_p;
145837ed19d5SAlexey Fomenko 	char *prl_from;
145937ed19d5SAlexey Fomenko 	char *prl_to;
1460f666751aSSam Ravnborg 
1461e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1462e5f95c8bSSam Ravnborg 
1463356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1464356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1465356ad538SQuentin Casasnovas 
14667c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14677c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14687c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14697c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1470588ccd73SSam Ravnborg 
14710d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1472bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
147337ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
147437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1475588ccd73SSam Ravnborg 		fprintf(stderr,
1476588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1477588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1478588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1479588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
148037ed19d5SAlexey Fomenko 		prl_from, fromsym,
148137ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
148237ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
148337ed19d5SAlexey Fomenko 		free(prl_from);
148437ed19d5SAlexey Fomenko 		free(prl_to);
1485588ccd73SSam Ravnborg 		break;
1486bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
148737ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1488588ccd73SSam Ravnborg 		fprintf(stderr,
1489588ccd73SSam Ravnborg 		"The variable %s references\n"
1490588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1491588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
14928b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1493588ccd73SSam Ravnborg 		"or name the variable:\n",
149437ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
149500759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
149637ed19d5SAlexey Fomenko 		free(prl_to);
1497588ccd73SSam Ravnborg 		break;
149858fb0d4fSSam Ravnborg 	}
1499bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
150037ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1501588ccd73SSam Ravnborg 		fprintf(stderr,
1502588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1503588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1504588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
150537ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
150637ed19d5SAlexey Fomenko 		free(prl_to);
1507588ccd73SSam Ravnborg 		break;
1508bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
150937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1510588ccd73SSam Ravnborg 		fprintf(stderr,
1511588ccd73SSam Ravnborg 		"The variable %s references\n"
1512588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1513588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1514588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1515588ccd73SSam Ravnborg 		"name the variable:\n",
151637ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
151700759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
151837ed19d5SAlexey Fomenko 		free(prl_to);
1519588ccd73SSam Ravnborg 		break;
1520588ccd73SSam Ravnborg 	}
1521bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1522bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
152337ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
152437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1525588ccd73SSam Ravnborg 		fprintf(stderr,
1526588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1527588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1528588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1529588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
153037ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
153137ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1532b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
153337ed19d5SAlexey Fomenko 		free(prl_from);
153437ed19d5SAlexey Fomenko 		free(prl_to);
1535588ccd73SSam Ravnborg 		break;
1536bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
153737ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
153837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1539588ccd73SSam Ravnborg 		fprintf(stderr,
1540588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1541588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1542588ccd73SSam Ravnborg 		"This is often seen when error handling "
1543588ccd73SSam Ravnborg 		"in the init function\n"
1544588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1545588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1546588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
154737ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
154837ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
15495003bab8SAndrew Morton 		prl_to, tosym, to_p);
155037ed19d5SAlexey Fomenko 		free(prl_from);
155137ed19d5SAlexey Fomenko 		free(prl_to);
1552588ccd73SSam Ravnborg 		break;
1553bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
155437ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
155537ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1556588ccd73SSam Ravnborg 		fprintf(stderr,
1557588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1558588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1559588ccd73SSam Ravnborg 		"This is often seen when error handling "
1560588ccd73SSam Ravnborg 		"in the exit function\n"
1561588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1562588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1563588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
156437ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
156537ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
156637ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
156737ed19d5SAlexey Fomenko 		free(prl_from);
156837ed19d5SAlexey Fomenko 		free(prl_to);
1569588ccd73SSam Ravnborg 		break;
1570588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
157137ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1572588ccd73SSam Ravnborg 		fprintf(stderr,
1573588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1574588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1575588ccd73SSam Ravnborg 		"or drop the export.\n",
157637ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
157737ed19d5SAlexey Fomenko 		free(prl_to);
1578588ccd73SSam Ravnborg 		break;
157952dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
158052dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
158152dc0595SQuentin Casasnovas 		      "we should never get here.");
158252dc0595SQuentin Casasnovas 		break;
1583588ccd73SSam Ravnborg 	}
1584588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
158558fb0d4fSSam Ravnborg }
158658fb0d4fSSam Ravnborg 
1587644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1588644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
158958fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
159058fb0d4fSSam Ravnborg {
159158fb0d4fSSam Ravnborg 	const char *tosec;
1592588ccd73SSam Ravnborg 	Elf_Sym *to;
1593588ccd73SSam Ravnborg 	Elf_Sym *from;
159458fb0d4fSSam Ravnborg 	const char *tosym;
1595588ccd73SSam Ravnborg 	const char *fromsym;
159658fb0d4fSSam Ravnborg 
1597588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1598588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
159958fb0d4fSSam Ravnborg 
1600d62c4765SMasahiro Yamada 	if (strstarts(fromsym, "reference___initcall"))
160177ab21adSAndi Kleen 		return;
160277ab21adSAndi Kleen 
1603c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1604c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1605c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1606c7a65e06SQuentin Casasnovas 
160758fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1608af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1609af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1610588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1611588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1612588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1613588ccd73SSam Ravnborg 				    is_function(to));
161458fb0d4fSSam Ravnborg 	}
1615b39927cfSSam Ravnborg }
1616644e8f14SQuentin Casasnovas 
161752dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
161852dc0595SQuentin Casasnovas {
161952dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
162052dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
162152dc0595SQuentin Casasnovas 
162252dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
162352dc0595SQuentin Casasnovas }
162452dc0595SQuentin Casasnovas 
162552dc0595SQuentin Casasnovas /*
162652dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
162752dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
162852dc0595SQuentin Casasnovas  */
162952dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1630e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
163152dc0595SQuentin Casasnovas {
163252dc0595SQuentin Casasnovas 	/*
163352dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
163452dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
163552dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
163652dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
163752dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
163852dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
163952dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
164052dc0595SQuentin Casasnovas 	 */
1641e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
164252dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
164352dc0595SQuentin Casasnovas }
1644e84048aaSQuentin Casasnovas 
164552dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
164652dc0595SQuentin Casasnovas {
1647d3df4de7SQuentin Casasnovas 	/*
1648d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1649d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1650d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1651d3df4de7SQuentin Casasnovas 	 */
1652d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
165352dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
165452dc0595SQuentin Casasnovas 
165552dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
165652dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
165752dc0595SQuentin Casasnovas }
165852dc0595SQuentin Casasnovas 
1659e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1660e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1661e84048aaSQuentin Casasnovas 
166252dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
166352dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
166452dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
166552dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
166652dc0595SQuentin Casasnovas {
166752dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
166852dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
166952dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
167052dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
167152dc0595SQuentin Casasnovas 	const char* from_pretty_name;
167252dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
167352dc0595SQuentin Casasnovas 	const char* to_pretty_name;
167452dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
167552dc0595SQuentin Casasnovas 
167652dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
167752dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
167852dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
167952dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
168052dc0595SQuentin Casasnovas 
168152dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
168252dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
168352dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
168452dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
168552dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
168652dc0595SQuentin Casasnovas 
168752dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
168852dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
168952dc0595SQuentin Casasnovas 		fprintf(stderr,
169052dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
169152dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
169252dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
169352dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
169452dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
169552dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
169652dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
169752dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
169852dc0595SQuentin Casasnovas }
169952dc0595SQuentin Casasnovas 
170052dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
170152dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
170252dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
170352dc0595SQuentin Casasnovas 				     const char *fromsec)
170452dc0595SQuentin Casasnovas {
170552dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
170652dc0595SQuentin Casasnovas 
170752dc0595SQuentin Casasnovas 	sec_mismatch_count++;
170852dc0595SQuentin Casasnovas 
170946c7dd56SMasahiro Yamada 	report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
171052dc0595SQuentin Casasnovas 
171152dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
171252dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
171352dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
171452dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
171552dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
171652dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
171752dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
171852dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
171952dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
172052dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
172152dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
172252dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
172352dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
172452dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
172552dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
172652dc0595SQuentin Casasnovas 		else
172752dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
172852dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
172952dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
173052dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
173152dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
173252dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
173352dc0595SQuentin Casasnovas 	}
173452dc0595SQuentin Casasnovas }
173552dc0595SQuentin Casasnovas 
1736644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1737644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1738644e8f14SQuentin Casasnovas {
17390cad61d7SLuis de Bethencourt 	const char *tosec = sec_name(elf, get_secindex(elf, sym));
1740644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1741644e8f14SQuentin Casasnovas 
1742644e8f14SQuentin Casasnovas 	if (mismatch) {
1743644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1744644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1745644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1746644e8f14SQuentin Casasnovas 		else
1747644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1748644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1749644e8f14SQuentin Casasnovas 	}
1750b39927cfSSam Ravnborg }
1751b39927cfSSam Ravnborg 
1752ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
17535b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1754ae4ac123SAtsushi Nemoto {
1755ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17566845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1757ae4ac123SAtsushi Nemoto 
1758ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1759731ece41SOlof Johansson 		r->r_offset;
1760ae4ac123SAtsushi Nemoto }
1761ae4ac123SAtsushi Nemoto 
17625b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1763ae4ac123SAtsushi Nemoto {
1764ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17655b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1766ae4ac123SAtsushi Nemoto 
1767ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1768ae4ac123SAtsushi Nemoto 	case R_386_32:
1769ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1770ae4ac123SAtsushi Nemoto 		break;
1771ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1772ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1773ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1774ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1775ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1776ae4ac123SAtsushi Nemoto 		break;
1777ae4ac123SAtsushi Nemoto 	}
1778ae4ac123SAtsushi Nemoto 	return 0;
1779ae4ac123SAtsushi Nemoto }
1780ae4ac123SAtsushi Nemoto 
17816e2e340bSTony Lindgren #ifndef R_ARM_CALL
17826e2e340bSTony Lindgren #define R_ARM_CALL	28
17836e2e340bSTony Lindgren #endif
17846e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17856e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17866e2e340bSTony Lindgren #endif
17876e2e340bSTony Lindgren 
1788c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1789c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1790c9698e5cSDavid A. Long #endif
1791c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1792c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1793c9698e5cSDavid A. Long #endif
1794c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1795c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1796c9698e5cSDavid A. Long #endif
1797c9698e5cSDavid A. Long 
17985b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
179956a974faSSam Ravnborg {
180056a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
180156a974faSSam Ravnborg 
180256a974faSSam Ravnborg 	switch (r_typ) {
180356a974faSSam Ravnborg 	case R_ARM_ABS32:
180456a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1805df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1806df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
180756a974faSSam Ravnborg 		break;
180856a974faSSam Ravnborg 	case R_ARM_PC24:
18096e2e340bSTony Lindgren 	case R_ARM_CALL:
18106e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1811c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1812c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1813c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
181456a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1815df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
18165b24c071SSam Ravnborg 			      sechdr->sh_offset +
18175b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
181856a974faSSam Ravnborg 		break;
181956a974faSSam Ravnborg 	default:
182056a974faSSam Ravnborg 		return 1;
182156a974faSSam Ravnborg 	}
182256a974faSSam Ravnborg 	return 0;
182356a974faSSam Ravnborg }
182456a974faSSam Ravnborg 
18255b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1826ae4ac123SAtsushi Nemoto {
1827ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
18285b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1829ae4ac123SAtsushi Nemoto 	unsigned int inst;
1830ae4ac123SAtsushi Nemoto 
1831ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1832ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1833ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1834ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1835ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1836ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1837ae4ac123SAtsushi Nemoto 		break;
1838ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1839ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1840ae4ac123SAtsushi Nemoto 		break;
1841ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1842ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1843ae4ac123SAtsushi Nemoto 		break;
1844ae4ac123SAtsushi Nemoto 	}
1845ae4ac123SAtsushi Nemoto 	return 0;
1846ae4ac123SAtsushi Nemoto }
1847ae4ac123SAtsushi Nemoto 
18485b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
184910668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1850b39927cfSSam Ravnborg {
1851b39927cfSSam Ravnborg 	Elf_Sym  *sym;
18525b24c071SSam Ravnborg 	Elf_Rela *rela;
18532c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1854eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18555b24c071SSam Ravnborg 	const char *fromsec;
18565b24c071SSam Ravnborg 
1857ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18585b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18595b24c071SSam Ravnborg 
1860ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18615b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18625b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1863b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18645b24c071SSam Ravnborg 		return;
1865e241a630SSam Ravnborg 
1866b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1867b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1868eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1869ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1870ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1871eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1872eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1873ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1874ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1875eae07ac6SAtsushi Nemoto 		} else {
1876601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1877eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1878eae07ac6SAtsushi Nemoto 		}
1879eae07ac6SAtsushi Nemoto #else
1880eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1881eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1882eae07ac6SAtsushi Nemoto #endif
188393684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1884eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1885b39927cfSSam Ravnborg 		/* Skip special sections */
18861ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1887b39927cfSSam Ravnborg 			continue;
1888e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1889e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
189058fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
18912c1a51f3SAtsushi Nemoto 	}
18925b24c071SSam Ravnborg }
18935b24c071SSam Ravnborg 
18945b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
189510668220SSam Ravnborg 			Elf_Shdr *sechdr)
18965b24c071SSam Ravnborg {
18975b24c071SSam Ravnborg 	Elf_Sym *sym;
18982c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
18995b24c071SSam Ravnborg 	Elf_Rela r;
19005b24c071SSam Ravnborg 	unsigned int r_sym;
19015b24c071SSam Ravnborg 	const char *fromsec;
19025b24c071SSam Ravnborg 
1903ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
19045b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
19055b24c071SSam Ravnborg 
1906ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
19075b24c071SSam Ravnborg 	fromsec += strlen(".rel");
19085b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1909b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
19105b24c071SSam Ravnborg 		return;
19112c1a51f3SAtsushi Nemoto 
19122c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
19132c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1914eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1915ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1916ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1917eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1918eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1919ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1920ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1921eae07ac6SAtsushi Nemoto 		} else {
19222c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1923eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1924eae07ac6SAtsushi Nemoto 		}
1925eae07ac6SAtsushi Nemoto #else
1926eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1927eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1928eae07ac6SAtsushi Nemoto #endif
19292c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1930ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1931ae4ac123SAtsushi Nemoto 		case EM_386:
19325b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1933ae4ac123SAtsushi Nemoto 				continue;
1934ae4ac123SAtsushi Nemoto 			break;
193556a974faSSam Ravnborg 		case EM_ARM:
19365b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
193756a974faSSam Ravnborg 				continue;
193856a974faSSam Ravnborg 			break;
1939ae4ac123SAtsushi Nemoto 		case EM_MIPS:
19405b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1941ae4ac123SAtsushi Nemoto 				continue;
1942ae4ac123SAtsushi Nemoto 			break;
1943ae4ac123SAtsushi Nemoto 		}
1944eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
19452c1a51f3SAtsushi Nemoto 		/* Skip special sections */
19461ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
19472c1a51f3SAtsushi Nemoto 			continue;
1948e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1949e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
195058fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19512c1a51f3SAtsushi Nemoto 	}
1952b39927cfSSam Ravnborg }
19535b24c071SSam Ravnborg 
19545b24c071SSam Ravnborg /**
19555b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19565b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19575b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1958b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19595b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19605b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
196132be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19625b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19635b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19645b24c071SSam Ravnborg  * be discarded and warns about it.
19655b24c071SSam Ravnborg  **/
19665b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
196710668220SSam Ravnborg 			  struct elf_info *elf)
19685b24c071SSam Ravnborg {
19695b24c071SSam Ravnborg 	int i;
19705b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19715b24c071SSam Ravnborg 
19725b24c071SSam Ravnborg 	/* Walk through all sections */
19731ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1974b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19755b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19765b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
197710668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19785b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
197910668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1980b39927cfSSam Ravnborg 	}
1981b39927cfSSam Ravnborg }
1982b39927cfSSam Ravnborg 
19837d02b490SAndi Kleen static char *remove_dot(char *s)
19847d02b490SAndi Kleen {
1985fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19867d02b490SAndi Kleen 
1987fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1988fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1989fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
19907d02b490SAndi Kleen 			s[n] = 0;
19917d02b490SAndi Kleen 	}
19927d02b490SAndi Kleen 	return s;
19937d02b490SAndi Kleen }
19947d02b490SAndi Kleen 
19958b185743SMasahiro Yamada static void read_symbols(const char *modname)
19961da177e4SLinus Torvalds {
19971da177e4SLinus Torvalds 	const char *symname;
19981da177e4SLinus Torvalds 	char *version;
1999b817f6feSSam Ravnborg 	char *license;
2000cb9b55d2SMatthias Maennich 	char *namespace;
20011da177e4SLinus Torvalds 	struct module *mod;
20021da177e4SLinus Torvalds 	struct elf_info info = { };
20031da177e4SLinus Torvalds 	Elf_Sym *sym;
20041da177e4SLinus Torvalds 
200585bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
200685bd2fddSSam Ravnborg 		return;
20071da177e4SLinus Torvalds 
20081da177e4SLinus Torvalds 	mod = new_module(modname);
20091da177e4SLinus Torvalds 
20101da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
20111da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
20121da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
20131da177e4SLinus Torvalds 		have_vmlinux = 1;
20141da177e4SLinus Torvalds 		mod->skip = 1;
20151da177e4SLinus Torvalds 	}
20161da177e4SLinus Torvalds 
2017bca2cceeSMasahiro Yamada 	license = get_modinfo(&info, "license");
2018ba1029c9SRandy Dunlap 	if (!license && !is_vmlinux(modname))
20192fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
2020eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
2021eed7d279SSam Ravnborg 		     "more information\n", modname);
2022b817f6feSSam Ravnborg 	while (license) {
2023b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
2024b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
2025b817f6feSSam Ravnborg 		else {
2026b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
2027b817f6feSSam Ravnborg 			break;
2028b817f6feSSam Ravnborg 		}
2029bca2cceeSMasahiro Yamada 		license = get_next_modinfo(&info, "license", license);
2030b817f6feSSam Ravnborg 	}
2031b817f6feSSam Ravnborg 
2032cb9b55d2SMatthias Maennich 	namespace = get_modinfo(&info, "import_ns");
2033cb9b55d2SMatthias Maennich 	while (namespace) {
2034cb9b55d2SMatthias Maennich 		add_namespace(&mod->imported_namespaces, namespace);
2035cb9b55d2SMatthias Maennich 		namespace = get_next_modinfo(&info, "import_ns", namespace);
2036cb9b55d2SMatthias Maennich 	}
2037cb9b55d2SMatthias Maennich 
20381da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
20397d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
20421da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
20431da177e4SLinus Torvalds 	}
204415bfc234SDenis Efremov 
204515bfc234SDenis Efremov 	// check for static EXPORT_SYMBOL_* functions && global vars
204615bfc234SDenis Efremov 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
204715bfc234SDenis Efremov 		unsigned char bind = ELF_ST_BIND(sym->st_info);
204815bfc234SDenis Efremov 
204915bfc234SDenis Efremov 		if (bind == STB_GLOBAL || bind == STB_WEAK) {
205015bfc234SDenis Efremov 			struct symbol *s =
205115bfc234SDenis Efremov 				find_symbol(remove_dot(info.strtab +
205215bfc234SDenis Efremov 						       sym->st_name));
205315bfc234SDenis Efremov 
205415bfc234SDenis Efremov 			if (s)
205515bfc234SDenis Efremov 				s->is_static = 0;
205615bfc234SDenis Efremov 		}
205715bfc234SDenis Efremov 	}
205815bfc234SDenis Efremov 
2059074a04f5SMasahiro Yamada 	if (!is_vmlinux(modname) || vmlinux_section_warnings)
206010668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
20611da177e4SLinus Torvalds 
2062bca2cceeSMasahiro Yamada 	version = get_modinfo(&info, "version");
20631da177e4SLinus Torvalds 	if (version)
20641da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
20651da177e4SLinus Torvalds 				       version - (char *)info.hdr);
20661da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
20671da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
20681da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
20691da177e4SLinus Torvalds 
20701da177e4SLinus Torvalds 	parse_elf_finish(&info);
20711da177e4SLinus Torvalds 
20728c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
20731da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
20741da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
20751da177e4SLinus Torvalds 	 * important anyhow */
20761da177e4SLinus Torvalds 	if (modversions)
20778c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
20781da177e4SLinus Torvalds }
20791da177e4SLinus Torvalds 
2080712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2081712f9b46SRusty Russell {
2082712f9b46SRusty Russell 	FILE *in = stdin;
2083712f9b46SRusty Russell 	char fname[PATH_MAX];
2084712f9b46SRusty Russell 
2085712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2086712f9b46SRusty Russell 		in = fopen(filename, "r");
2087712f9b46SRusty Russell 		if (!in)
2088712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2089712f9b46SRusty Russell 	}
2090712f9b46SRusty Russell 
2091712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2092712f9b46SRusty Russell 		if (strends(fname, "\n"))
2093712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2094712f9b46SRusty Russell 		read_symbols(fname);
2095712f9b46SRusty Russell 	}
2096712f9b46SRusty Russell 
2097712f9b46SRusty Russell 	if (in != stdin)
2098712f9b46SRusty Russell 		fclose(in);
2099712f9b46SRusty Russell }
2100712f9b46SRusty Russell 
21011da177e4SLinus Torvalds #define SZ 500
21021da177e4SLinus Torvalds 
21031da177e4SLinus Torvalds /* We first write the generated file into memory using the
21041da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
21051da177e4SLinus Torvalds  * only update the later if anything changed */
21061da177e4SLinus Torvalds 
21075c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
21085c3ead8cSSam Ravnborg 						      const char *fmt, ...)
21091da177e4SLinus Torvalds {
21101da177e4SLinus Torvalds 	char tmp[SZ];
21111da177e4SLinus Torvalds 	int len;
21121da177e4SLinus Torvalds 	va_list ap;
21131da177e4SLinus Torvalds 
21141da177e4SLinus Torvalds 	va_start(ap, fmt);
21151da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
21167670f023SSam Ravnborg 	buf_write(buf, tmp, len);
21171da177e4SLinus Torvalds 	va_end(ap);
21181da177e4SLinus Torvalds }
21191da177e4SLinus Torvalds 
21205c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
21211da177e4SLinus Torvalds {
21221da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
21237670f023SSam Ravnborg 		buf->size += len + SZ;
21241f3aa900SRandy Dunlap 		buf->p = NOFAIL(realloc(buf->p, buf->size));
21251da177e4SLinus Torvalds 	}
21261da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
21271da177e4SLinus Torvalds 	buf->pos += len;
21281da177e4SLinus Torvalds }
21291da177e4SLinus Torvalds 
2130c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2131c96fca21SSam Ravnborg {
2132c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2133c96fca21SSam Ravnborg 
2134c96fca21SSam Ravnborg 	switch (exp) {
2135c96fca21SSam Ravnborg 	case export_gpl:
2136c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2137c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2138c96fca21SSam Ravnborg 		break;
2139c96fca21SSam Ravnborg 	case export_unused_gpl:
2140c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2141c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2142c96fca21SSam Ravnborg 		break;
2143c96fca21SSam Ravnborg 	case export_gpl_future:
2144c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2145c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2146c96fca21SSam Ravnborg 		break;
2147c96fca21SSam Ravnborg 	case export_plain:
2148c96fca21SSam Ravnborg 	case export_unused:
2149c96fca21SSam Ravnborg 	case export_unknown:
2150c96fca21SSam Ravnborg 		/* ignore */
2151c96fca21SSam Ravnborg 		break;
2152c96fca21SSam Ravnborg 	}
2153c96fca21SSam Ravnborg }
2154c96fca21SSam Ravnborg 
2155c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2156c96fca21SSam Ravnborg {
2157c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2158c96fca21SSam Ravnborg 
2159c96fca21SSam Ravnborg 	switch (exp) {
2160c96fca21SSam Ravnborg 	case export_unused:
2161c96fca21SSam Ravnborg 	case export_unused_gpl:
2162c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2163c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2164c96fca21SSam Ravnborg 		break;
2165c96fca21SSam Ravnborg 	default:
2166c96fca21SSam Ravnborg 		/* ignore */
2167c96fca21SSam Ravnborg 		break;
2168c96fca21SSam Ravnborg 	}
2169c96fca21SSam Ravnborg }
2170c96fca21SSam Ravnborg 
21713b415288SMasahiro Yamada static int check_exports(struct module *mod)
2172b817f6feSSam Ravnborg {
2173b817f6feSSam Ravnborg 	struct symbol *s, *exp;
21743b415288SMasahiro Yamada 	int err = 0;
2175b817f6feSSam Ravnborg 
2176b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21776449bd62SAndrew Morton 		const char *basename;
2178b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
21793b415288SMasahiro Yamada 		if (!exp || exp->module == mod) {
21803b415288SMasahiro Yamada 			if (have_vmlinux && !s->weak) {
21813b415288SMasahiro Yamada 				if (warn_unresolved) {
21823b415288SMasahiro Yamada 					warn("\"%s\" [%s.ko] undefined!\n",
21833b415288SMasahiro Yamada 					     s->name, mod->name);
21843b415288SMasahiro Yamada 				} else {
21853b415288SMasahiro Yamada 					merror("\"%s\" [%s.ko] undefined!\n",
21863b415288SMasahiro Yamada 					       s->name, mod->name);
21873b415288SMasahiro Yamada 					err = 1;
21883b415288SMasahiro Yamada 				}
21893b415288SMasahiro Yamada 			}
2190b817f6feSSam Ravnborg 			continue;
21913b415288SMasahiro Yamada 		}
21926449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2193b817f6feSSam Ravnborg 		if (basename)
2194b817f6feSSam Ravnborg 			basename++;
2195c96fca21SSam Ravnborg 		else
2196c96fca21SSam Ravnborg 			basename = mod->name;
2197cb9b55d2SMatthias Maennich 
21981d082773SMatthias Maennich 		if (exp->namespace) {
21991d082773SMatthias Maennich 			add_namespace(&mod->required_namespaces,
22001d082773SMatthias Maennich 				      exp->namespace);
22011d082773SMatthias Maennich 
22021d082773SMatthias Maennich 			if (!write_namespace_deps &&
2203cb9b55d2SMatthias Maennich 			    !module_imports_namespace(mod, exp->namespace)) {
2204cb9b55d2SMatthias Maennich 				warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
2205cb9b55d2SMatthias Maennich 				     basename, exp->name, exp->namespace);
2206cb9b55d2SMatthias Maennich 			}
22071d082773SMatthias Maennich 		}
2208cb9b55d2SMatthias Maennich 
2209c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2210c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2211c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2212b817f6feSSam Ravnborg 	}
22133b415288SMasahiro Yamada 
22143b415288SMasahiro Yamada 	return err;
2215b817f6feSSam Ravnborg }
2216b817f6feSSam Ravnborg 
22174fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
22184fd3e4efSWanlong Gao {
22194fd3e4efSWanlong Gao 	const char *mod_name;
22204fd3e4efSWanlong Gao 
22214fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
22224fd3e4efSWanlong Gao 	if (mod_name == NULL)
22234fd3e4efSWanlong Gao 		mod_name = mod->name;
22244fd3e4efSWanlong Gao 	else
22254fd3e4efSWanlong Gao 		mod_name++;
22264fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
22274fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
22284fd3e4efSWanlong Gao 		return 1;
22294fd3e4efSWanlong Gao 	}
22304fd3e4efSWanlong Gao 
22314fd3e4efSWanlong Gao 	return 0;
22324fd3e4efSWanlong Gao }
22334fd3e4efSWanlong Gao 
22345c3ead8cSSam Ravnborg /**
22355c3ead8cSSam Ravnborg  * Header for the generated file
22365c3ead8cSSam Ravnborg  **/
22375c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
22381da177e4SLinus Torvalds {
22399afb719eSLaura Abbott 	buf_printf(b, "#include <linux/build-salt.h>\n");
22401da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
22411da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
22421da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
22431da177e4SLinus Torvalds 	buf_printf(b, "\n");
22449afb719eSLaura Abbott 	buf_printf(b, "BUILD_SALT;\n");
22459afb719eSLaura Abbott 	buf_printf(b, "\n");
22461da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
22473e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
22481da177e4SLinus Torvalds 	buf_printf(b, "\n");
2249e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
2250a3d0cb04SMasahiro Yamada 	buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
22513c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
22521da177e4SLinus Torvalds 	if (mod->has_init)
22533c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
22541da177e4SLinus Torvalds 	if (mod->has_cleanup)
22551da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
22563c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
22571da177e4SLinus Torvalds 			      "#endif\n");
22583c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
22591da177e4SLinus Torvalds 	buf_printf(b, "};\n");
22601da177e4SLinus Torvalds }
22611da177e4SLinus Torvalds 
22622449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
22632449b8baSBen Hutchings {
22642449b8baSBen Hutchings 	if (is_intree)
22652449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
22662449b8baSBen Hutchings }
22672449b8baSBen Hutchings 
2268caf7501aSAndi Kleen /* Cannot check for assembler */
2269caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2270caf7501aSAndi Kleen {
2271e4f35891SWANG Chao 	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
2272caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2273caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2274caf7501aSAndi Kleen }
2275caf7501aSAndi Kleen 
22765c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2277a9860bf0SGreg Kroah-Hartman {
2278d62c4765SMasahiro Yamada 	if (strstarts(name, "drivers/staging"))
2279a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2280a9860bf0SGreg Kroah-Hartman }
2281a9860bf0SGreg Kroah-Hartman 
22825c3ead8cSSam Ravnborg /**
22835c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
22845c3ead8cSSam Ravnborg  **/
2285c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
22861da177e4SLinus Torvalds {
22871da177e4SLinus Torvalds 	struct symbol *s, *exp;
2288c53ddacdSKirill Korotaev 	int err = 0;
22891da177e4SLinus Torvalds 
22901da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
22911da177e4SLinus Torvalds 		exp = find_symbol(s->name);
22923b415288SMasahiro Yamada 		if (!exp || exp->module == mod)
22931da177e4SLinus Torvalds 			continue;
22941da177e4SLinus Torvalds 		s->module = exp->module;
22951da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
22961da177e4SLinus Torvalds 		s->crc = exp->crc;
22971da177e4SLinus Torvalds 	}
22981da177e4SLinus Torvalds 
22991da177e4SLinus Torvalds 	if (!modversions)
2300c53ddacdSKirill Korotaev 		return err;
23011da177e4SLinus Torvalds 
23021da177e4SLinus Torvalds 	buf_printf(b, "\n");
23031da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
2304a3d0cb04SMasahiro Yamada 	buf_printf(b, "__used __section(__versions) = {\n");
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2307df578e7dSSam Ravnborg 		if (!s->module)
23081da177e4SLinus Torvalds 			continue;
23091da177e4SLinus Torvalds 		if (!s->crc_valid) {
2310cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
23111da177e4SLinus Torvalds 				s->name, mod->name);
23121da177e4SLinus Torvalds 			continue;
23131da177e4SLinus Torvalds 		}
23145cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
23155cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
23165cfb203aSTakashi Iwai 			       s->name, mod->name);
23175cfb203aSTakashi Iwai 			err = 1;
23185cfb203aSTakashi Iwai 			break;
23195cfb203aSTakashi Iwai 		}
2320b2c5cdcfSMasahiro Yamada 		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
2321a4b6a77bSJames Hogan 			   s->crc, s->name);
23221da177e4SLinus Torvalds 	}
23231da177e4SLinus Torvalds 
23241da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2325c53ddacdSKirill Korotaev 
2326c53ddacdSKirill Korotaev 	return err;
23271da177e4SLinus Torvalds }
23281da177e4SLinus Torvalds 
2329d2665ca8SMasahiro Yamada static void add_depends(struct buffer *b, struct module *mod)
23301da177e4SLinus Torvalds {
23311da177e4SLinus Torvalds 	struct symbol *s;
23321da177e4SLinus Torvalds 	int first = 1;
23331da177e4SLinus Torvalds 
2334d2665ca8SMasahiro Yamada 	/* Clear ->seen flag of modules that own symbols needed by this. */
2335d2665ca8SMasahiro Yamada 	for (s = mod->unres; s; s = s->next)
2336d2665ca8SMasahiro Yamada 		if (s->module)
2337d2665ca8SMasahiro Yamada 			s->module->seen = is_vmlinux(s->module->name);
23381da177e4SLinus Torvalds 
23391da177e4SLinus Torvalds 	buf_printf(b, "\n");
23406df7e1ecSMasahiro Yamada 	buf_printf(b, "MODULE_INFO(depends, \"");
23411da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2342a61b2dfdSSam Ravnborg 		const char *p;
23431da177e4SLinus Torvalds 		if (!s->module)
23441da177e4SLinus Torvalds 			continue;
23451da177e4SLinus Torvalds 
23461da177e4SLinus Torvalds 		if (s->module->seen)
23471da177e4SLinus Torvalds 			continue;
23481da177e4SLinus Torvalds 
23491da177e4SLinus Torvalds 		s->module->seen = 1;
2350df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2351df578e7dSSam Ravnborg 		if (p)
2352a61b2dfdSSam Ravnborg 			p++;
2353a61b2dfdSSam Ravnborg 		else
2354a61b2dfdSSam Ravnborg 			p = s->module->name;
2355a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
23561da177e4SLinus Torvalds 		first = 0;
23571da177e4SLinus Torvalds 	}
23586df7e1ecSMasahiro Yamada 	buf_printf(b, "\");\n");
23591da177e4SLinus Torvalds }
23601da177e4SLinus Torvalds 
23615c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
23621da177e4SLinus Torvalds {
23631da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
23641da177e4SLinus Torvalds 		buf_printf(b, "\n");
23651da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
23661da177e4SLinus Torvalds 			   mod->srcversion);
23671da177e4SLinus Torvalds 	}
23681da177e4SLinus Torvalds }
23691da177e4SLinus Torvalds 
23705c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
23711da177e4SLinus Torvalds {
23721da177e4SLinus Torvalds 	char *tmp;
23731da177e4SLinus Torvalds 	FILE *file;
23741da177e4SLinus Torvalds 	struct stat st;
23751da177e4SLinus Torvalds 
23761da177e4SLinus Torvalds 	file = fopen(fname, "r");
23771da177e4SLinus Torvalds 	if (!file)
23781da177e4SLinus Torvalds 		goto write;
23791da177e4SLinus Torvalds 
23801da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
23811da177e4SLinus Torvalds 		goto close_write;
23821da177e4SLinus Torvalds 
23831da177e4SLinus Torvalds 	if (st.st_size != b->pos)
23841da177e4SLinus Torvalds 		goto close_write;
23851da177e4SLinus Torvalds 
23861da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
23871da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
23881da177e4SLinus Torvalds 		goto free_write;
23891da177e4SLinus Torvalds 
23901da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
23911da177e4SLinus Torvalds 		goto free_write;
23921da177e4SLinus Torvalds 
23931da177e4SLinus Torvalds 	free(tmp);
23941da177e4SLinus Torvalds 	fclose(file);
23951da177e4SLinus Torvalds 	return;
23961da177e4SLinus Torvalds 
23971da177e4SLinus Torvalds  free_write:
23981da177e4SLinus Torvalds 	free(tmp);
23991da177e4SLinus Torvalds  close_write:
24001da177e4SLinus Torvalds 	fclose(file);
24011da177e4SLinus Torvalds  write:
24021da177e4SLinus Torvalds 	file = fopen(fname, "w");
24031da177e4SLinus Torvalds 	if (!file) {
24041da177e4SLinus Torvalds 		perror(fname);
24051da177e4SLinus Torvalds 		exit(1);
24061da177e4SLinus Torvalds 	}
24071da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
24081da177e4SLinus Torvalds 		perror(fname);
24091da177e4SLinus Torvalds 		exit(1);
24101da177e4SLinus Torvalds 	}
24111da177e4SLinus Torvalds 	fclose(file);
24121da177e4SLinus Torvalds }
24131da177e4SLinus Torvalds 
2414bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2415534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2416bd5cbcedSRam Pai  **/
2417040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
24181da177e4SLinus Torvalds {
24191da177e4SLinus Torvalds 	unsigned long size, pos = 0;
24201da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
24211da177e4SLinus Torvalds 	char *line;
24221da177e4SLinus Torvalds 
24231da177e4SLinus Torvalds 	if (!file)
24241da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
24251da177e4SLinus Torvalds 		return;
24261da177e4SLinus Torvalds 
24271da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2428cb9b55d2SMatthias Maennich 		char *symname, *namespace, *modname, *d, *export, *end;
24291da177e4SLinus Torvalds 		unsigned int crc;
24301da177e4SLinus Torvalds 		struct module *mod;
2431040fcc81SSam Ravnborg 		struct symbol *s;
24321da177e4SLinus Torvalds 
24331da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
24341da177e4SLinus Torvalds 			goto fail;
24351da177e4SLinus Torvalds 		*symname++ = '\0';
2436cb9b55d2SMatthias Maennich 		if (!(namespace = strchr(symname, '\t')))
2437cb9b55d2SMatthias Maennich 			goto fail;
2438cb9b55d2SMatthias Maennich 		*namespace++ = '\0';
2439cb9b55d2SMatthias Maennich 		if (!(modname = strchr(namespace, '\t')))
24401da177e4SLinus Torvalds 			goto fail;
24411da177e4SLinus Torvalds 		*modname++ = '\0';
24429ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2443bd5cbcedSRam Pai 			*export++ = '\0';
2444534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2445534b89a9SSam Ravnborg 			*end = '\0';
24461da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
24471da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
24481da177e4SLinus Torvalds 			goto fail;
2449df578e7dSSam Ravnborg 		mod = find_module(modname);
2450df578e7dSSam Ravnborg 		if (!mod) {
2451df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
24521da177e4SLinus Torvalds 				have_vmlinux = 1;
24530fa3a88cSJan Beulich 			mod = new_module(modname);
24541da177e4SLinus Torvalds 			mod->skip = 1;
24551da177e4SLinus Torvalds 		}
2456cb9b55d2SMatthias Maennich 		s = sym_add_exported(symname, namespace, mod,
2457cb9b55d2SMatthias Maennich 				     export_no(export));
2458040fcc81SSam Ravnborg 		s->kernel    = kernel;
24598e70c458SSam Ravnborg 		s->preloaded = 1;
246015bfc234SDenis Efremov 		s->is_static = 0;
2461bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
24621da177e4SLinus Torvalds 	}
24632ee41e62SChristian Engelmayer 	release_file(file, size);
24641da177e4SLinus Torvalds 	return;
24651da177e4SLinus Torvalds fail:
24662ee41e62SChristian Engelmayer 	release_file(file, size);
24671da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
24681da177e4SLinus Torvalds }
24691da177e4SLinus Torvalds 
2470040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2471040fcc81SSam Ravnborg  * For external modules only dump symbols
2472040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2473040fcc81SSam Ravnborg  **/
2474040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2475040fcc81SSam Ravnborg {
2476040fcc81SSam Ravnborg 	if (!external_module)
2477040fcc81SSam Ravnborg 		return 1;
2478040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2479040fcc81SSam Ravnborg 		return 0;
2480040fcc81SSam Ravnborg 	return 1;
2481040fcc81SSam Ravnborg }
2482040fcc81SSam Ravnborg 
24835c3ead8cSSam Ravnborg static void write_dump(const char *fname)
24841da177e4SLinus Torvalds {
24851da177e4SLinus Torvalds 	struct buffer buf = { };
24861da177e4SLinus Torvalds 	struct symbol *symbol;
2487cb9b55d2SMatthias Maennich 	const char *namespace;
24881da177e4SLinus Torvalds 	int n;
24891da177e4SLinus Torvalds 
24901da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
24911da177e4SLinus Torvalds 		symbol = symbolhash[n];
24921da177e4SLinus Torvalds 		while (symbol) {
2493cb9b55d2SMatthias Maennich 			if (dump_sym(symbol)) {
2494cb9b55d2SMatthias Maennich 				namespace = symbol->namespace;
2495cb9b55d2SMatthias Maennich 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
2496040fcc81SSam Ravnborg 					   symbol->crc, symbol->name,
2497cb9b55d2SMatthias Maennich 					   namespace ? namespace : "",
2498bd5cbcedSRam Pai 					   symbol->module->name,
2499bd5cbcedSRam Pai 					   export_str(symbol->export));
2500cb9b55d2SMatthias Maennich 			}
25011da177e4SLinus Torvalds 			symbol = symbol->next;
25021da177e4SLinus Torvalds 		}
25031da177e4SLinus Torvalds 	}
25041da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2505c7d47f26SHeinrich Schuchardt 	free(buf.p);
25061da177e4SLinus Torvalds }
25071da177e4SLinus Torvalds 
25081d082773SMatthias Maennich static void write_namespace_deps_files(void)
25091d082773SMatthias Maennich {
25101d082773SMatthias Maennich 	struct module *mod;
25111d082773SMatthias Maennich 	struct namespace_list *ns;
25121d082773SMatthias Maennich 	struct buffer ns_deps_buf = {};
25131d082773SMatthias Maennich 
25141d082773SMatthias Maennich 	for (mod = modules; mod; mod = mod->next) {
25151d082773SMatthias Maennich 		char fname[PATH_MAX];
25161d082773SMatthias Maennich 
25171d082773SMatthias Maennich 		if (mod->skip)
25181d082773SMatthias Maennich 			continue;
25191d082773SMatthias Maennich 
25201d082773SMatthias Maennich 		ns_deps_buf.pos = 0;
25211d082773SMatthias Maennich 
25221d082773SMatthias Maennich 		for (ns = mod->required_namespaces; ns; ns = ns->next)
25231d082773SMatthias Maennich 			buf_printf(&ns_deps_buf, "%s\n", ns->namespace);
25241d082773SMatthias Maennich 
25251d082773SMatthias Maennich 		if (ns_deps_buf.pos == 0)
25261d082773SMatthias Maennich 			continue;
25271d082773SMatthias Maennich 
25281d082773SMatthias Maennich 		sprintf(fname, "%s.ns_deps", mod->name);
25291d082773SMatthias Maennich 		write_if_changed(&ns_deps_buf, fname);
25301d082773SMatthias Maennich 	}
25311d082773SMatthias Maennich }
25321d082773SMatthias Maennich 
25332d04b5aeSRichard Hacker struct ext_sym_list {
25342d04b5aeSRichard Hacker 	struct ext_sym_list *next;
25352d04b5aeSRichard Hacker 	const char *file;
25362d04b5aeSRichard Hacker };
25372d04b5aeSRichard Hacker 
25385c3ead8cSSam Ravnborg int main(int argc, char **argv)
25391da177e4SLinus Torvalds {
25401da177e4SLinus Torvalds 	struct module *mod;
25411da177e4SLinus Torvalds 	struct buffer buf = { };
2542040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2543712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
25441da177e4SLinus Torvalds 	int opt;
2545c53ddacdSKirill Korotaev 	int err;
254615bfc234SDenis Efremov 	int n;
25472d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
25482d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
25491da177e4SLinus Torvalds 
25501d082773SMatthias Maennich 	while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {
25511da177e4SLinus Torvalds 		switch (opt) {
25521da177e4SLinus Torvalds 		case 'i':
2553040fcc81SSam Ravnborg 			kernel_read = optarg;
2554040fcc81SSam Ravnborg 			break;
2555040fcc81SSam Ravnborg 		case 'I':
2556040fcc81SSam Ravnborg 			module_read = optarg;
2557040fcc81SSam Ravnborg 			external_module = 1;
25581da177e4SLinus Torvalds 			break;
25592d04b5aeSRichard Hacker 		case 'e':
25602d04b5aeSRichard Hacker 			external_module = 1;
25612d04b5aeSRichard Hacker 			extsym_iter =
25622d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
25632d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
25642d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
25652d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
25662d04b5aeSRichard Hacker 			break;
25671da177e4SLinus Torvalds 		case 'm':
25681da177e4SLinus Torvalds 			modversions = 1;
25691da177e4SLinus Torvalds 			break;
2570eed380f3SGuenter Roeck 		case 'n':
2571eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2572eed380f3SGuenter Roeck 			break;
25731da177e4SLinus Torvalds 		case 'o':
25741da177e4SLinus Torvalds 			dump_write = optarg;
25751da177e4SLinus Torvalds 			break;
25761da177e4SLinus Torvalds 		case 'a':
25771da177e4SLinus Torvalds 			all_versions = 1;
25781da177e4SLinus Torvalds 			break;
25798d8d8289SSam Ravnborg 		case 's':
25808d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
25818d8d8289SSam Ravnborg 			break;
2582712f9b46SRusty Russell 		case 'T':
2583712f9b46SRusty Russell 			files_source = optarg;
2584712f9b46SRusty Russell 			break;
2585c53ddacdSKirill Korotaev 		case 'w':
2586c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2587c53ddacdSKirill Korotaev 			break;
258847490ec1SNicolas Boichat 		case 'E':
258947490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
259047490ec1SNicolas Boichat 			break;
25911d082773SMatthias Maennich 		case 'd':
25921d082773SMatthias Maennich 			write_namespace_deps = 1;
25931d082773SMatthias Maennich 			break;
25941da177e4SLinus Torvalds 		default:
25951da177e4SLinus Torvalds 			exit(1);
25961da177e4SLinus Torvalds 		}
25971da177e4SLinus Torvalds 	}
25981da177e4SLinus Torvalds 
2599040fcc81SSam Ravnborg 	if (kernel_read)
2600040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2601040fcc81SSam Ravnborg 	if (module_read)
2602040fcc81SSam Ravnborg 		read_dump(module_read, 0);
26032d04b5aeSRichard Hacker 	while (extsym_start) {
26042d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
26052d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
26062d04b5aeSRichard Hacker 		free(extsym_start);
26072d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
26082d04b5aeSRichard Hacker 	}
26091da177e4SLinus Torvalds 
2610df578e7dSSam Ravnborg 	while (optind < argc)
26111da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
26121da177e4SLinus Torvalds 
2613712f9b46SRusty Russell 	if (files_source)
2614712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2615712f9b46SRusty Russell 
2616c53ddacdSKirill Korotaev 	err = 0;
2617c53ddacdSKirill Korotaev 
2618b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2619d93e1719SMathias Krause 		char fname[PATH_MAX];
2620666ab414SAndi Kleen 
2621b817f6feSSam Ravnborg 		if (mod->skip)
2622b817f6feSSam Ravnborg 			continue;
26231da177e4SLinus Torvalds 
26241da177e4SLinus Torvalds 		buf.pos = 0;
26251da177e4SLinus Torvalds 
26264fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
26273b415288SMasahiro Yamada 		err |= check_exports(mod);
26281d082773SMatthias Maennich 		if (write_namespace_deps)
26291d082773SMatthias Maennich 			continue;
26301d082773SMatthias Maennich 
26311da177e4SLinus Torvalds 		add_header(&buf, mod);
26322449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2633caf7501aSAndi Kleen 		add_retpoline(&buf);
2634a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2635c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
2636d2665ca8SMasahiro Yamada 		add_depends(&buf, mod);
26371da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
26381da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
26391da177e4SLinus Torvalds 
26401da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
26411da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
26421da177e4SLinus Torvalds 	}
26431d082773SMatthias Maennich 
26441d082773SMatthias Maennich 	if (write_namespace_deps) {
26451d082773SMatthias Maennich 		write_namespace_deps_files();
26461d082773SMatthias Maennich 		return 0;
26471d082773SMatthias Maennich 	}
26481d082773SMatthias Maennich 
26491da177e4SLinus Torvalds 	if (dump_write)
26501da177e4SLinus Torvalds 		write_dump(dump_write);
265146c7dd56SMasahiro Yamada 	if (sec_mismatch_count && sec_mismatch_fatal)
265247490ec1SNicolas Boichat 		fatal("modpost: Section mismatches detected.\n"
265347490ec1SNicolas Boichat 		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
265415bfc234SDenis Efremov 	for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
2655*47346e96SMasahiro Yamada 		struct symbol *s;
265615bfc234SDenis Efremov 
2657*47346e96SMasahiro Yamada 		for (s = symbolhash[n]; s; s = s->next) {
2658*47346e96SMasahiro Yamada 			/*
2659*47346e96SMasahiro Yamada 			 * Do not check "vmlinux". This avoids the same warnings
2660*47346e96SMasahiro Yamada 			 * shown twice, and false-positives for ARCH=um.
2661*47346e96SMasahiro Yamada 			 */
2662*47346e96SMasahiro Yamada 			if (is_vmlinux(s->module->name) && !s->module->is_dot_o)
2663*47346e96SMasahiro Yamada 				continue;
2664*47346e96SMasahiro Yamada 
266515bfc234SDenis Efremov 			if (s->is_static)
266615bfc234SDenis Efremov 				warn("\"%s\" [%s] is a static %s\n",
266715bfc234SDenis Efremov 				     s->name, s->module->name,
266815bfc234SDenis Efremov 				     export_str(s->export));
266915bfc234SDenis Efremov 		}
267015bfc234SDenis Efremov 	}
267115bfc234SDenis Efremov 
2672c7d47f26SHeinrich Schuchardt 	free(buf.p);
26731da177e4SLinus Torvalds 
2674c53ddacdSKirill Korotaev 	return err;
26751da177e4SLinus Torvalds }
2676