xref: /linux-6.15/scripts/mod/modpost.c (revision a2b11184)
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;
169389eb3f5SMasahiro Yamada 	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 
351389eb3f5SMasahiro Yamada static char *sym_extract_namespace(const char **symname)
352cb9b55d2SMatthias Maennich {
353bf70b050SMasahiro Yamada 	char *namespace = NULL;
354bf70b050SMasahiro Yamada 	char *ns_separator;
355cb9b55d2SMatthias Maennich 
356bf70b050SMasahiro Yamada 	ns_separator = strchr(*symname, '.');
357bf70b050SMasahiro Yamada 	if (ns_separator) {
358bf70b050SMasahiro Yamada 		namespace = NOFAIL(strndup(*symname, ns_separator - *symname));
359bf70b050SMasahiro Yamada 		*symname = ns_separator + 1;
360cb9b55d2SMatthias Maennich 	}
361cb9b55d2SMatthias Maennich 
362bf70b050SMasahiro Yamada 	return namespace;
363cb9b55d2SMatthias Maennich }
364cb9b55d2SMatthias Maennich 
365*a2b11184SMatthias Maennich static void sym_update_namespace(const char *symname, const char *namespace)
366*a2b11184SMatthias Maennich {
367*a2b11184SMatthias Maennich 	struct symbol *s = find_symbol(symname);
368*a2b11184SMatthias Maennich 
369*a2b11184SMatthias Maennich 	/*
370*a2b11184SMatthias Maennich 	 * That symbol should have been created earlier and thus this is
371*a2b11184SMatthias Maennich 	 * actually an assertion.
372*a2b11184SMatthias Maennich 	 */
373*a2b11184SMatthias Maennich 	if (!s) {
374*a2b11184SMatthias Maennich 		merror("Could not update namespace(%s) for symbol %s\n",
375*a2b11184SMatthias Maennich 		       namespace, symname);
376*a2b11184SMatthias Maennich 		return;
377*a2b11184SMatthias Maennich 	}
378*a2b11184SMatthias Maennich 
379*a2b11184SMatthias Maennich 	free(s->namespace);
380*a2b11184SMatthias Maennich 	s->namespace =
381*a2b11184SMatthias Maennich 		namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
382*a2b11184SMatthias Maennich }
383*a2b11184SMatthias Maennich 
3845c3ead8cSSam Ravnborg /**
3855c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3865c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3875c3ead8cSSam Ravnborg  **/
388cb9b55d2SMatthias Maennich static struct symbol *sym_add_exported(const char *name, const char *namespace,
389cb9b55d2SMatthias Maennich 				       struct module *mod, enum export export)
3901da177e4SLinus Torvalds {
3911da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	if (!s) {
394bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3958e70c458SSam Ravnborg 	} else {
3968e70c458SSam Ravnborg 		if (!s->preloaded) {
397cb9b55d2SMatthias Maennich 			warn("%s: '%s' exported twice. Previous export was in %s%s\n",
398cb9b55d2SMatthias Maennich 			     mod->name, name, s->module->name,
3998e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ? "" : ".ko");
4004b21960fSTrent Piepho 		} else {
401baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
4024b21960fSTrent Piepho 			s->module = mod;
4031da177e4SLinus Torvalds 		}
4041da177e4SLinus Torvalds 	}
405*a2b11184SMatthias Maennich 	sym_update_namespace(name, namespace);
4068e70c458SSam Ravnborg 	s->preloaded = 0;
407040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
408040fcc81SSam Ravnborg 	s->kernel    = 0;
409bd5cbcedSRam Pai 	s->export    = export;
410040fcc81SSam Ravnborg 	return s;
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
413040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
414bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
415040fcc81SSam Ravnborg {
416040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
417040fcc81SSam Ravnborg 
418b6568b1aSRusty Russell 	if (!s) {
419bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
420b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
421b6568b1aSRusty Russell 		s->preloaded = 1;
422b6568b1aSRusty Russell 	}
423040fcc81SSam Ravnborg 	s->crc = crc;
4241da177e4SLinus Torvalds 	s->crc_valid = 1;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds 
4275c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
4281da177e4SLinus Torvalds {
4291da177e4SLinus Torvalds 	struct stat st;
430eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
4311da177e4SLinus Torvalds 	int fd;
4321da177e4SLinus Torvalds 
4331da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
434eb3d5cc6SJesper Juhl 	if (fd < 0)
4351da177e4SLinus Torvalds 		return NULL;
436eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
437eb3d5cc6SJesper Juhl 		goto failed;
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 	*size = st.st_size;
4401da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
4411da177e4SLinus Torvalds 
442eb3d5cc6SJesper Juhl failed:
443eb3d5cc6SJesper Juhl 	close(fd);
4441da177e4SLinus Torvalds 	if (map == MAP_FAILED)
4451da177e4SLinus Torvalds 		return NULL;
4461da177e4SLinus Torvalds 	return map;
4471da177e4SLinus Torvalds }
4481da177e4SLinus Torvalds 
4495c3ead8cSSam Ravnborg /**
4505c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
4515c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
4525c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
4535c3ead8cSSam Ravnborg   **/
4545c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
4551da177e4SLinus Torvalds {
4561da177e4SLinus Torvalds 	static char line[4096];
4571da177e4SLinus Torvalds 	int skip = 1;
4581da177e4SLinus Torvalds 	size_t len = 0;
4591da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
4601da177e4SLinus Torvalds 	char *s = line;
4611da177e4SLinus Torvalds 
462df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
4631da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
4641da177e4SLinus Torvalds 			p++;
4651da177e4SLinus Torvalds 			continue;
4661da177e4SLinus Torvalds 		}
4671da177e4SLinus Torvalds 		skip = 0;
4681da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4691da177e4SLinus Torvalds 			len++;
4701da177e4SLinus Torvalds 			*s++ = *p++;
4711da177e4SLinus Torvalds 			if (len > 4095)
4721da177e4SLinus Torvalds 				break; /* Too long, stop */
4731da177e4SLinus Torvalds 		} else {
4741da177e4SLinus Torvalds 			/* End of string */
4751da177e4SLinus Torvalds 			*s = '\0';
4761da177e4SLinus Torvalds 			return line;
4771da177e4SLinus Torvalds 		}
4781da177e4SLinus Torvalds 	}
4791da177e4SLinus Torvalds 	/* End of buffer */
4801da177e4SLinus Torvalds 	return NULL;
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
4835c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4841da177e4SLinus Torvalds {
4851da177e4SLinus Torvalds 	munmap(file, size);
4861da177e4SLinus Torvalds }
4871da177e4SLinus Torvalds 
48885bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4891da177e4SLinus Torvalds {
4901da177e4SLinus Torvalds 	unsigned int i;
49185bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4921da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4931da177e4SLinus Torvalds 	Elf_Sym  *sym;
4941ce53adfSDenys Vlasenko 	const char *secstrings;
4951ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4981da177e4SLinus Torvalds 	if (!hdr) {
499eed380f3SGuenter Roeck 		if (ignore_missing_files) {
500eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
501eed380f3SGuenter Roeck 				strerror(errno));
502eed380f3SGuenter Roeck 			return 0;
503eed380f3SGuenter Roeck 		}
5041da177e4SLinus Torvalds 		perror(filename);
5056803dc0eSSam Ravnborg 		exit(1);
5061da177e4SLinus Torvalds 	}
5071da177e4SLinus Torvalds 	info->hdr = hdr;
50885bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
50985bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
51085bd2fddSSam Ravnborg 		return 0;
51185bd2fddSSam Ravnborg 	}
51285bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
51385bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
51485bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
51585bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
51685bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
51785bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
51885bd2fddSSam Ravnborg 		return 0;
51985bd2fddSSam Ravnborg 	}
5201da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
521ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
5227d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
5237d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
5247d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
5257d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
5267d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
5277d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
5287d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
5297d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
5307d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
5317d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
5327d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
5337d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
5341da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
5351da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
5361da177e4SLinus Torvalds 
537a83710e5SPetr Stetiar 	/* Check if file offset is correct */
538a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
539df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
540df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
541df578e7dSSam Ravnborg 		      filename, info->size);
542a83710e5SPetr Stetiar 		return 0;
543a83710e5SPetr Stetiar 	}
544a83710e5SPetr Stetiar 
5456845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
5461ce53adfSDenys Vlasenko 		/*
5471ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
5481ce53adfSDenys Vlasenko 		 * read count from .sh_size.
5491ce53adfSDenys Vlasenko 		 */
5501ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
5511ce53adfSDenys Vlasenko 	}
5521ce53adfSDenys Vlasenko 	else {
5531ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
5541ce53adfSDenys Vlasenko 	}
5551ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
5566845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
5571ce53adfSDenys Vlasenko 	}
5581ce53adfSDenys Vlasenko 	else {
5591ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
5601ce53adfSDenys Vlasenko 	}
5611ce53adfSDenys Vlasenko 
5621da177e4SLinus Torvalds 	/* Fix endianness in section headers */
5631ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
5647d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
5651da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
5667d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
5677d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5681da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5691da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5701da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
571ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5727d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5737d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5741da177e4SLinus Torvalds 	}
5751da177e4SLinus Torvalds 	/* Find symbol table. */
5761ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5771ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
578bd5cbcedSRam Pai 		const char *secname;
57956fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5801da177e4SLinus Torvalds 
58156fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
582df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
583df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
584df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
585df578e7dSSam Ravnborg 			      sizeof(*hdr));
58685bd2fddSSam Ravnborg 			return 0;
58785bd2fddSSam Ravnborg 		}
588bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
589bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
59056fc82c5STejun Heo 			if (nobits)
59156fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5921da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5931da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
594bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
595bd5cbcedSRam Pai 			info->export_sec = i;
596c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
597c96fca21SSam Ravnborg 			info->export_unused_sec = i;
598bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
599bd5cbcedSRam Pai 			info->export_gpl_sec = i;
600c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
601c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
602bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
603bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
604bd5cbcedSRam Pai 
6051ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
6061ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
6071ce53adfSDenys Vlasenko 			symtab_idx = i;
6081ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
6091ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
6101ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
6111ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6126845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
6131da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
6141ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
6151ce53adfSDenys Vlasenko 		}
6161ce53adfSDenys Vlasenko 
6171ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
6181ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
6191ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
6201ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
6211ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
6221ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
6231ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6241ce53adfSDenys Vlasenko 		}
6251da177e4SLinus Torvalds 	}
626df578e7dSSam Ravnborg 	if (!info->symtab_start)
627cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
628df578e7dSSam Ravnborg 
6291da177e4SLinus Torvalds 	/* Fix endianness in symbols */
6301da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
6311da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
6321da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
6331da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
6341da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
6351da177e4SLinus Torvalds 	}
6361ce53adfSDenys Vlasenko 
6371ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
6381ce53adfSDenys Vlasenko 		Elf32_Word *p;
6396845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
6401ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
6416845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
6421ce53adfSDenys Vlasenko 			      symtab_idx);
6431ce53adfSDenys Vlasenko 		/* Fix endianness */
6441ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
6451ce53adfSDenys Vlasenko 		     p++)
6461ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
6471ce53adfSDenys Vlasenko 	}
6481ce53adfSDenys Vlasenko 
64985bd2fddSSam Ravnborg 	return 1;
6501da177e4SLinus Torvalds }
6511da177e4SLinus Torvalds 
6525c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
6531da177e4SLinus Torvalds {
6541da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
6551da177e4SLinus Torvalds }
6561da177e4SLinus Torvalds 
6574d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
6584d7365d6SSam Ravnborg {
6594d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
660b2c5cdcfSMasahiro Yamada 	if (strcmp(symname, "__this_module") == 0)
6614d7365d6SSam Ravnborg 		return 1;
6624d7365d6SSam Ravnborg 	/* ignore global offset table */
6634d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
6644d7365d6SSam Ravnborg 		return 1;
6654d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
6664d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
667d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr_") ||
668d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr_") ||
669d62c4765SMasahiro Yamada 		    strstarts(symname, "_rest32gpr_") ||
670d62c4765SMasahiro Yamada 		    strstarts(symname, "_save32gpr_") ||
671d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
672d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_"))
6734d7365d6SSam Ravnborg 			return 1;
6747fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6757fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
676d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr0_") ||
677d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr0_") ||
678d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
679d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_") ||
680c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6817fca5dc8SStephen Rothwell 			return 1;
6824d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6834d7365d6SSam Ravnborg 	return 0;
6844d7365d6SSam Ravnborg }
6854d7365d6SSam Ravnborg 
6865c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6871da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6881da177e4SLinus Torvalds {
6891da177e4SLinus Torvalds 	unsigned int crc;
69062a26356SAlessio Igor Bogani 	enum export export;
691d8c1eb86SNicholas Piggin 	bool is_crc = false;
692389eb3f5SMasahiro Yamada 	const char *name;
693389eb3f5SMasahiro Yamada 	char *namespace;
69462a26356SAlessio Igor Bogani 
695258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
696d62c4765SMasahiro Yamada 	    strstarts(symname, "__ksymtab"))
69762a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
69862a26356SAlessio Igor Bogani 	else
69962a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	/* CRC'd symbol */
702d62c4765SMasahiro Yamada 	if (strstarts(symname, "__crc_")) {
703d8c1eb86SNicholas Piggin 		is_crc = true;
7041da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
70556067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
70656067812SArd Biesheuvel 			unsigned int *crcp;
70756067812SArd Biesheuvel 
70856067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
70956067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
71056067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
71156067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
71256067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
71354a7151bSFredrik Noring 			crc = TO_NATIVE(*crcp);
71456067812SArd Biesheuvel 		}
715b2c5cdcfSMasahiro Yamada 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
716bd5cbcedSRam Pai 				export);
7171da177e4SLinus Torvalds 	}
718b5064654SAndi Kleen 
719b5064654SAndi Kleen 	switch (sym->st_shndx) {
720b5064654SAndi Kleen 	case SHN_COMMON:
721d62c4765SMasahiro Yamada 		if (strstarts(symname, "__gnu_lto_")) {
722ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
723ef178f92SAndi Kleen 		} else
724b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
7251da177e4SLinus Torvalds 		break;
7261da177e4SLinus Torvalds 	case SHN_UNDEF:
7271da177e4SLinus Torvalds 		/* undefined symbol */
7281da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
7291da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
7301da177e4SLinus Torvalds 			break;
7314d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
7321da177e4SLinus Torvalds 			break;
7338d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
7348d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
7358d529014SBen Colline /* add compatibility with older glibc */
7368d529014SBen Colline #ifndef STT_SPARC_REGISTER
7378d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
7388d529014SBen Colline #endif
7391da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
7401da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
7411da177e4SLinus Torvalds 			/* Ignore register directives. */
7428d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
7431da177e4SLinus Torvalds 				break;
7447caaeabbSAl Viro 			if (symname[0] == '.') {
7451f3aa900SRandy Dunlap 				char *munged = NOFAIL(strdup(symname));
7467caaeabbSAl Viro 				munged[0] = '_';
7477caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
7487caaeabbSAl Viro 				symname = munged;
7497caaeabbSAl Viro 			}
7501da177e4SLinus Torvalds 		}
7511da177e4SLinus Torvalds #endif
7521da177e4SLinus Torvalds 
753d8c1eb86SNicholas Piggin 		if (is_crc) {
754d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
755b2c5cdcfSMasahiro Yamada 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
756b2c5cdcfSMasahiro Yamada 			     symname + strlen("__crc_"), mod->name, e);
757d8c1eb86SNicholas Piggin 		}
758b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
7591da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
7601da177e4SLinus Torvalds 					  mod->unres);
7611da177e4SLinus Torvalds 		break;
7621da177e4SLinus Torvalds 	default:
7631da177e4SLinus Torvalds 		/* All exported symbols */
764d62c4765SMasahiro Yamada 		if (strstarts(symname, "__ksymtab_")) {
765cb9b55d2SMatthias Maennich 			name = symname + strlen("__ksymtab_");
766cb9b55d2SMatthias Maennich 			namespace = sym_extract_namespace(&name);
767cb9b55d2SMatthias Maennich 			sym_add_exported(name, namespace, mod, export);
768389eb3f5SMasahiro Yamada 			free(namespace);
7691da177e4SLinus Torvalds 		}
770b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "init_module") == 0)
7711da177e4SLinus Torvalds 			mod->has_init = 1;
772b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "cleanup_module") == 0)
7731da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7741da177e4SLinus Torvalds 		break;
7751da177e4SLinus Torvalds 	}
7761da177e4SLinus Torvalds }
7771da177e4SLinus Torvalds 
7785c3ead8cSSam Ravnborg /**
7795c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7805c3ead8cSSam Ravnborg  **/
7811da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7821da177e4SLinus Torvalds {
7831da177e4SLinus Torvalds 	/* Skip non-zero chars */
7841da177e4SLinus Torvalds 	while (string[0]) {
7851da177e4SLinus Torvalds 		string++;
7861da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7871da177e4SLinus Torvalds 			return NULL;
7881da177e4SLinus Torvalds 	}
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 	/* Skip any zero padding. */
7911da177e4SLinus Torvalds 	while (!string[0]) {
7921da177e4SLinus Torvalds 		string++;
7931da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7941da177e4SLinus Torvalds 			return NULL;
7951da177e4SLinus Torvalds 	}
7961da177e4SLinus Torvalds 	return string;
7971da177e4SLinus Torvalds }
7981da177e4SLinus Torvalds 
799bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag,
800bca2cceeSMasahiro Yamada 			      char *prev)
8011da177e4SLinus Torvalds {
8021da177e4SLinus Torvalds 	char *p;
8031da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
804bca2cceeSMasahiro Yamada 	char *modinfo = info->modinfo;
805bca2cceeSMasahiro Yamada 	unsigned long size = info->modinfo_len;
8061da177e4SLinus Torvalds 
807bca2cceeSMasahiro Yamada 	if (prev) {
808bca2cceeSMasahiro Yamada 		size -= prev - modinfo;
809bca2cceeSMasahiro Yamada 		modinfo = next_string(prev, &size);
810b817f6feSSam Ravnborg 	}
811b817f6feSSam Ravnborg 
8121da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
8131da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
8141da177e4SLinus Torvalds 			return p + taglen + 1;
8151da177e4SLinus Torvalds 	}
8161da177e4SLinus Torvalds 	return NULL;
8171da177e4SLinus Torvalds }
8181da177e4SLinus Torvalds 
819bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag)
820b817f6feSSam Ravnborg 
821b817f6feSSam Ravnborg {
822bca2cceeSMasahiro Yamada 	return get_next_modinfo(info, tag, NULL);
823b817f6feSSam Ravnborg }
824b817f6feSSam Ravnborg 
82593684d3bSSam Ravnborg /**
8264c8fbca5SSam Ravnborg  * Test if string s ends in string sub
8274c8fbca5SSam Ravnborg  * return 0 if match
8284c8fbca5SSam Ravnborg  **/
8294c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
8304c8fbca5SSam Ravnborg {
8314c8fbca5SSam Ravnborg 	int slen, sublen;
8324c8fbca5SSam Ravnborg 
8334c8fbca5SSam Ravnborg 	if (!s || !sub)
8344c8fbca5SSam Ravnborg 		return 1;
8354c8fbca5SSam Ravnborg 
8364c8fbca5SSam Ravnborg 	slen = strlen(s);
8374c8fbca5SSam Ravnborg 	sublen = strlen(sub);
8384c8fbca5SSam Ravnborg 
8394c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
8404c8fbca5SSam Ravnborg 		return 1;
8414c8fbca5SSam Ravnborg 
8424c8fbca5SSam Ravnborg 	if (sublen > slen)
8434c8fbca5SSam Ravnborg 		return 1;
8444c8fbca5SSam Ravnborg 
8454c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
8464c8fbca5SSam Ravnborg }
8474c8fbca5SSam Ravnborg 
848ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
849ff13f926SSam Ravnborg {
85058fb0d4fSSam Ravnborg 	if (sym)
851ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
85258fb0d4fSSam Ravnborg 	else
853f666751aSSam Ravnborg 		return "(unknown)";
854ff13f926SSam Ravnborg }
855ff13f926SSam Ravnborg 
85610668220SSam Ravnborg /* The pattern is an array of simple patterns.
85710668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
8586c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
85910668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
86009c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
86110668220SSam Ravnborg  */
8625c725138STrevor Keith static int match(const char *sym, const char * const pat[])
86310668220SSam Ravnborg {
86410668220SSam Ravnborg 	const char *p;
86510668220SSam Ravnborg 	while (*pat) {
86610668220SSam Ravnborg 		p = *pat++;
86710668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
86810668220SSam Ravnborg 
86909c20c03SPaul Gortmaker 		/* "*foo*" */
87009c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
8716f02bdfcSDenis Efremov 			char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
8726f02bdfcSDenis Efremov 			char *here = strstr(sym, bare);
87309c20c03SPaul Gortmaker 
87409c20c03SPaul Gortmaker 			free(bare);
87509c20c03SPaul Gortmaker 			if (here != NULL)
87609c20c03SPaul Gortmaker 				return 1;
87709c20c03SPaul Gortmaker 		}
8786c5bd235SSam Ravnborg 		/* "*foo" */
87909c20c03SPaul Gortmaker 		else if (*p == '*') {
8806c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8816c5bd235SSam Ravnborg 				return 1;
8826c5bd235SSam Ravnborg 		}
88310668220SSam Ravnborg 		/* "foo*" */
8846c5bd235SSam Ravnborg 		else if (*endp == '*') {
88510668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
88610668220SSam Ravnborg 				return 1;
88710668220SSam Ravnborg 		}
88810668220SSam Ravnborg 		/* no wildcards */
88910668220SSam Ravnborg 		else {
89010668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
89110668220SSam Ravnborg 				return 1;
89210668220SSam Ravnborg 		}
89310668220SSam Ravnborg 	}
89410668220SSam Ravnborg 	/* no match */
89510668220SSam Ravnborg 	return 0;
89610668220SSam Ravnborg }
89710668220SSam Ravnborg 
89810668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8997a3ee753SMathias Krause static const char *const section_white_list[] =
9004391ed6aSSam Ravnborg {
9014391ed6aSSam Ravnborg 	".comment*",
9024391ed6aSSam Ravnborg 	".debug*",
9034d10c223SChen Gang 	".cranges",		/* sh64 */
9041121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
905739d875dSDavid Howells 	".GCC.command.line",	/* record-gcc-switches */
9064391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
9074391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
9084391ed6aSSam Ravnborg 	".stab*",
9094391ed6aSSam Ravnborg 	".note*",
9104391ed6aSSam Ravnborg 	".got*",
9114391ed6aSSam Ravnborg 	".toc*",
912af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
913af42e970SMax Filippov 	".xt.lit",         /* xtensa */
914f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
915f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
916d1189c63SNoam Camus 	".cmem*",			/* EZchip */
917d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
918ef178f92SAndi Kleen 	".gnu.lto*",
919e390f9a9SJosh Poimboeuf 	".discard.*",
9204391ed6aSSam Ravnborg 	NULL
9214391ed6aSSam Ravnborg };
92210668220SSam Ravnborg 
923e241a630SSam Ravnborg /*
924b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
925e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
926b614a697SAnders Kaseorg  * without "ax" / "aw".
927e241a630SSam Ravnborg  */
928b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
929b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
930e241a630SSam Ravnborg {
931b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
932e241a630SSam Ravnborg 
933b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
934b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
935b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
936b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
937b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
938e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
939e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
940e241a630SSam Ravnborg 		     modname, sec);
941e241a630SSam Ravnborg 	}
942e241a630SSam Ravnborg }
943e241a630SSam Ravnborg 
944e241a630SSam Ravnborg 
945e241a630SSam Ravnborg 
946eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
947a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
948a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
949eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
950a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
95110668220SSam Ravnborg 
952eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
953a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
954eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
955a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
95610668220SSam Ravnborg 
957bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
958a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
959a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
960a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
961bb15d8dbSSebastian Andrzej Siewior 
962e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
963e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
9644a31a229SUwe Kleine-König 
9654a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
9664a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
96710668220SSam Ravnborg 
968a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
969157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
9706727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
97152dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
972673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
973673c2c34SChris Metcalf 		".coldtext"
97410668220SSam Ravnborg 
975fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
976fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
977eb8f6890SSam Ravnborg 
978fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
979fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
980eb8f6890SSam Ravnborg 
98152dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
98252dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
98352dc0595SQuentin Casasnovas 
9846c5bd235SSam Ravnborg /* init data sections */
9857a3ee753SMathias Krause static const char *const init_data_sections[] =
9867a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9876c5bd235SSam Ravnborg 
9886c5bd235SSam Ravnborg /* all init sections */
9897a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9906c5bd235SSam Ravnborg 
9916c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9927a3ee753SMathias Krause static const char *const init_exit_sections[] =
993eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9946c5bd235SSam Ravnborg 
9954a3893d0SPaul Gortmaker /* all text sections */
9964a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9974a3893d0SPaul Gortmaker 
9986c5bd235SSam Ravnborg /* data section */
9997a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
10006c5bd235SSam Ravnborg 
10016c5bd235SSam Ravnborg 
10026c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
1003af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
1004af92a82dSUwe Kleine-König 	"*driver",							\
1005af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
1006af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
1007af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
1008af92a82dSUwe Kleine-König 	"*_ops",							\
1009af92a82dSUwe Kleine-König 	"*_probe",							\
1010af92a82dSUwe Kleine-König 	"*_probe_one",							\
1011af92a82dSUwe Kleine-König 	"*_console"
10126c5bd235SSam Ravnborg 
10137a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
10147a3ee753SMathias Krause static const char *const linker_symbols[] =
10156c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
10164a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
10176c5bd235SSam Ravnborg 
1018588ccd73SSam Ravnborg enum mismatch {
1019bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
1020bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
1021bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
1022bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
1023bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
1024bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
1025bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
1026bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
1027588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
102852dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
1029588ccd73SSam Ravnborg };
1030588ccd73SSam Ravnborg 
1031e5d8f59aSQuentin Casasnovas /**
1032e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
1033e5d8f59aSQuentin Casasnovas  *
1034e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
1035e5d8f59aSQuentin Casasnovas  *
1036e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
1037e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
1038e5d8f59aSQuentin Casasnovas  *
1039e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
1040e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
1041e5d8f59aSQuentin Casasnovas  *
1042e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
1043e5d8f59aSQuentin Casasnovas  *
1044e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
1045e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
1046e5d8f59aSQuentin Casasnovas  *
1047e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
1048e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
1049e5d8f59aSQuentin Casasnovas  *
1050e5d8f59aSQuentin Casasnovas  */
105110668220SSam Ravnborg struct sectioncheck {
105210668220SSam Ravnborg 	const char *fromsec[20];
1053050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
1054050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
1055588ccd73SSam Ravnborg 	enum mismatch mismatch;
1056af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
1057644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
1058644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
1059644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
1060644e8f14SQuentin Casasnovas 
106110668220SSam Ravnborg };
106210668220SSam Ravnborg 
106352dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
106452dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
106552dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
106652dc0595SQuentin Casasnovas 				     const char *fromsec);
106752dc0595SQuentin Casasnovas 
10687a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
106910668220SSam Ravnborg /* Do not reference init/exit code/data from
107010668220SSam Ravnborg  * normal code and data
107110668220SSam Ravnborg  */
107210668220SSam Ravnborg {
1073588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1074050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1075bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1076af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1077588ccd73SSam Ravnborg },
1078588ccd73SSam Ravnborg {
1079588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1080050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1081bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1082af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1083588ccd73SSam Ravnborg },
1084588ccd73SSam Ravnborg {
10850db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1086050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10870db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10880db25245SUwe Kleine-König 	.symbol_white_list = {
10890db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10900db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10910db25245SUwe Kleine-König 	},
10920db25245SUwe Kleine-König },
10930db25245SUwe Kleine-König {
1094588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1095050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1096bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1097af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1098588ccd73SSam Ravnborg },
1099588ccd73SSam Ravnborg {
1100588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1101050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1102bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1103af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1104eb8f6890SSam Ravnborg },
1105e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1106eb8f6890SSam Ravnborg {
11074a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1108050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1109bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1110af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1111eb8f6890SSam Ravnborg },
1112e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1113eb8f6890SSam Ravnborg {
11144a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1115050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1116bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1117af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
111810668220SSam Ravnborg },
111910668220SSam Ravnborg /* Do not use exit code/data from init code */
112010668220SSam Ravnborg {
1121eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1122050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1123bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1124af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
112510668220SSam Ravnborg },
112610668220SSam Ravnborg /* Do not use init code/data from exit code */
112710668220SSam Ravnborg {
1128eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1129050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1130bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1131af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
113210668220SSam Ravnborg },
1133bb15d8dbSSebastian Andrzej Siewior {
1134bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1135050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1136bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1137bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1138bb15d8dbSSebastian Andrzej Siewior },
113910668220SSam Ravnborg /* Do not export init/exit functions or data */
114010668220SSam Ravnborg {
114110668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1142050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1143af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1144af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
114552dc0595SQuentin Casasnovas },
114652dc0595SQuentin Casasnovas {
114752dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
114852dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
114952dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
115052dc0595SQuentin Casasnovas 	 */
115152dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
115252dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
115352dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
115452dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
115510668220SSam Ravnborg }
115610668220SSam Ravnborg };
115710668220SSam Ravnborg 
11580d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
11590d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
116010668220SSam Ravnborg {
116110668220SSam Ravnborg 	int i;
116210668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
116310668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
116410668220SSam Ravnborg 
1165c5c3439aSQuentin Casasnovas 	/*
1166c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1167c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1168739d875dSDavid Howells 	 * doesn't make much sense and causes build failures on parisc
1169739d875dSDavid Howells 	 * architectures.
1170c5c3439aSQuentin Casasnovas 	 */
1171c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1172c5c3439aSQuentin Casasnovas 		return NULL;
1173c5c3439aSQuentin Casasnovas 
117410668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1175050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1176050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11770d2a636eSUwe Kleine-König 				return check;
1178050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1179050e57fdSQuentin Casasnovas 				return check;
1180050e57fdSQuentin Casasnovas 		}
118110668220SSam Ravnborg 		check++;
118210668220SSam Ravnborg 	}
11830d2a636eSUwe Kleine-König 	return NULL;
118410668220SSam Ravnborg }
118510668220SSam Ravnborg 
11864c8fbca5SSam Ravnborg /**
11874c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11880e0d314eSSam Ravnborg  *
11894c8fbca5SSam Ravnborg  * Pattern 1:
11904c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11914c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11924c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11934c8fbca5SSam Ravnborg  *   this pattern.
11944c8fbca5SSam Ravnborg  *   The pattern is identified by:
11954c8fbca5SSam Ravnborg  *   tosec   = .init.data
11969209aed0SSam Ravnborg  *   fromsec = .data*
11974c8fbca5SSam Ravnborg  *   atsym   =__param*
11984c8fbca5SSam Ravnborg  *
11996a841528SRusty Russell  * Pattern 1a:
12006a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
12016a841528SRusty Russell  *   The pattern is identified by:
12026a841528SRusty Russell  *   tosec   = .init.text
12036a841528SRusty Russell  *   fromsec = .data*
12046a841528SRusty Russell  *   atsym   = __param_ops_*
12056a841528SRusty Russell  *
12064c8fbca5SSam Ravnborg  * Pattern 2:
120772ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
12084c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
12094c8fbca5SSam Ravnborg  *   the pattern is identified by:
121083cda2bbSSam Ravnborg  *   tosec   = init or exit section
121183cda2bbSSam Ravnborg  *   fromsec = data section
1212df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1213df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1214ee6a8545SVivek Goyal  *
1215ee6a8545SVivek Goyal  * Pattern 3:
1216c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
12179bf8cb9bSSam Ravnborg  *
12181d8af559SSam Ravnborg  * Pattern 4:
1219ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1220ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1221ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1222ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1223ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1224ee6a8545SVivek Goyal  *   This pattern is identified by
1225ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
12269bf8cb9bSSam Ravnborg  *
12274a3893d0SPaul Gortmaker  * Pattern 5:
12284a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
12294a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
12304a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
12314a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
12324a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
12334a3893d0SPaul Gortmaker  *   This pattern is identified by
12344a3893d0SPaul Gortmaker  *   tosec   = init section
12354a3893d0SPaul Gortmaker  *   fromsec = text section
12364a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
12374a3893d0SPaul Gortmaker  *
1238a4d26f1aSPaul Walmsley  * Pattern 6:
1239a4d26f1aSPaul Walmsley  *   Hide section mismatch warnings for ELF local symbols.  The goal
1240a4d26f1aSPaul Walmsley  *   is to eliminate false positive modpost warnings caused by
1241a4d26f1aSPaul Walmsley  *   compiler-generated ELF local symbol names such as ".LANCHOR1".
1242a4d26f1aSPaul Walmsley  *   Autogenerated symbol names bypass modpost's "Pattern 2"
1243a4d26f1aSPaul Walmsley  *   whitelisting, which relies on pattern-matching against symbol
1244a4d26f1aSPaul Walmsley  *   names to work.  (One situation where gcc can autogenerate ELF
1245a4d26f1aSPaul Walmsley  *   local symbols is when "-fsection-anchors" is used.)
12464c8fbca5SSam Ravnborg  **/
1247af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1248af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
124958fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
12504c8fbca5SSam Ravnborg {
12514c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
12526c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
12536c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1254d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param"))
125558fb0d4fSSam Ravnborg 		return 0;
12564c8fbca5SSam Ravnborg 
12576a841528SRusty Russell 	/* Check for pattern 1a */
12586a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
12596a841528SRusty Russell 	    match(fromsec, data_sections) &&
1260d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param_ops_"))
12616a841528SRusty Russell 		return 0;
12626a841528SRusty Russell 
12634c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
12646c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
12656c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1266af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
126758fb0d4fSSam Ravnborg 		return 0;
12684c8fbca5SSam Ravnborg 
12699bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
12706c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
12716c5bd235SSam Ravnborg 	    match(tosec, init_sections))
127258fb0d4fSSam Ravnborg 		return 0;
1273f8657e1bSVivek Goyal 
12741d8af559SSam Ravnborg 	/* Check for pattern 4 */
127558fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
127693659af1SSam Ravnborg 		return 0;
127758fb0d4fSSam Ravnborg 
12784a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12794a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12804a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12814a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12824a3893d0SPaul Gortmaker 		return 0;
12834a3893d0SPaul Gortmaker 
1284a4d26f1aSPaul Walmsley 	/* Check for pattern 6 */
1285a4d26f1aSPaul Walmsley 	if (strstarts(fromsym, ".L"))
1286a4d26f1aSPaul Walmsley 		return 0;
1287a4d26f1aSPaul Walmsley 
128858fb0d4fSSam Ravnborg 	return 1;
12894c8fbca5SSam Ravnborg }
12904c8fbca5SSam Ravnborg 
12915818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str)
12925818c683SSami Tolvanen {
12935818c683SSami Tolvanen 	return str[0] == '$' && strchr("axtd", str[1])
12945818c683SSami Tolvanen 	       && (str[2] == '\0' || str[2] == '.');
12955818c683SSami Tolvanen }
12965818c683SSami Tolvanen 
12975818c683SSami Tolvanen /*
12985818c683SSami Tolvanen  * If there's no name there, ignore it; likewise, ignore it if it's
12995818c683SSami Tolvanen  * one of the magic symbols emitted used by current ARM tools.
13005818c683SSami Tolvanen  *
13015818c683SSami Tolvanen  * Otherwise if find_symbols_between() returns those symbols, they'll
13025818c683SSami Tolvanen  * fail the whitelist tests and cause lots of false alarms ... fixable
13035818c683SSami Tolvanen  * only by merging __exit and __init sections into __text, bloating
13045818c683SSami Tolvanen  * the kernel (which is especially evil on embedded platforms).
13055818c683SSami Tolvanen  */
13065818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
13075818c683SSami Tolvanen {
13085818c683SSami Tolvanen 	const char *name = elf->strtab + sym->st_name;
13095818c683SSami Tolvanen 
13105818c683SSami Tolvanen 	if (!name || !strlen(name))
13115818c683SSami Tolvanen 		return 0;
13125818c683SSami Tolvanen 	return !is_arm_mapping_symbol(name);
13135818c683SSami Tolvanen }
13145818c683SSami Tolvanen 
13154c8fbca5SSam Ravnborg /**
131693684d3bSSam Ravnborg  * Find symbol based on relocation record info.
131793684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
131893684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
131993684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
132093684d3bSSam Ravnborg  * based on section and address.
132193684d3bSSam Ravnborg  *  **/
13229ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
132393684d3bSSam Ravnborg 				Elf_Sym *relsym)
132493684d3bSSam Ravnborg {
132593684d3bSSam Ravnborg 	Elf_Sym *sym;
13269ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
13279ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
13289ad21c3fSSam Ravnborg 	Elf64_Sword d;
13291ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
133093684d3bSSam Ravnborg 
133193684d3bSSam Ravnborg 	if (relsym->st_name != 0)
133293684d3bSSam Ravnborg 		return relsym;
13331ce53adfSDenys Vlasenko 
13341ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
133593684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
13361ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
133793684d3bSSam Ravnborg 			continue;
1338ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1339ae4ac123SAtsushi Nemoto 			continue;
13405818c683SSami Tolvanen 		if (!is_valid_name(elf, sym))
13415818c683SSami Tolvanen 			continue;
134293684d3bSSam Ravnborg 		if (sym->st_value == addr)
134393684d3bSSam Ravnborg 			return sym;
13449ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
13459ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
13469ad21c3fSSam Ravnborg 		if (d < 0)
13479ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
13489ad21c3fSSam Ravnborg 		if (d < distance) {
13499ad21c3fSSam Ravnborg 			distance = d;
13509ad21c3fSSam Ravnborg 			near = sym;
135193684d3bSSam Ravnborg 		}
13529ad21c3fSSam Ravnborg 	}
13539ad21c3fSSam Ravnborg 	/* We need a close match */
13549ad21c3fSSam Ravnborg 	if (distance < 20)
13559ad21c3fSSam Ravnborg 		return near;
13569ad21c3fSSam Ravnborg 	else
135793684d3bSSam Ravnborg 		return NULL;
135893684d3bSSam Ravnborg }
135993684d3bSSam Ravnborg 
1360b39927cfSSam Ravnborg /*
136143c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
136243c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
136343c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
136443c74d17SSam Ravnborg  * it is, but this works for now.
1365b39927cfSSam Ravnborg  **/
1366157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1367157c23c8SSam Ravnborg 				 const char *sec)
1368b39927cfSSam Ravnborg {
1369b39927cfSSam Ravnborg 	Elf_Sym *sym;
1370157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1371157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1372b39927cfSSam Ravnborg 
1373b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1374b39927cfSSam Ravnborg 		const char *symsec;
1375b39927cfSSam Ravnborg 
13761ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1377b39927cfSSam Ravnborg 			continue;
13781ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1379b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1380b39927cfSSam Ravnborg 			continue;
1381da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1382da68d61fSDavid Brownell 			continue;
1383b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1384157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1385157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1386157c23c8SSam Ravnborg 				near = sym;
1387157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1388157c23c8SSam Ravnborg 				near = sym;
138943c74d17SSam Ravnborg 			}
1390b39927cfSSam Ravnborg 		}
1391b39927cfSSam Ravnborg 	}
1392157c23c8SSam Ravnborg 	return near;
1393157c23c8SSam Ravnborg }
1394b39927cfSSam Ravnborg 
139558fb0d4fSSam Ravnborg /*
1396588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1397588ccd73SSam Ravnborg  * .init.text => __init
1398588ccd73SSam Ravnborg  * .memexitconst => __memconst
1399588ccd73SSam Ravnborg  * etc.
1400cbcf14a9SAndy Shevchenko  *
1401cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1402cbcf14a9SAndy Shevchenko  * method should free it after usage.
1403588ccd73SSam Ravnborg */
1404588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1405588ccd73SSam Ravnborg {
1406588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
14071f3aa900SRandy Dunlap 		char *p = NOFAIL(malloc(20));
1408588ccd73SSam Ravnborg 		char *r = p;
1409588ccd73SSam Ravnborg 
1410588ccd73SSam Ravnborg 		*p++ = '_';
1411588ccd73SSam Ravnborg 		*p++ = '_';
1412588ccd73SSam Ravnborg 		if (*s == '.')
1413588ccd73SSam Ravnborg 			s++;
1414588ccd73SSam Ravnborg 		while (*s && *s != '.')
1415588ccd73SSam Ravnborg 			*p++ = *s++;
1416588ccd73SSam Ravnborg 		*p = '\0';
1417588ccd73SSam Ravnborg 		if (*s == '.')
1418588ccd73SSam Ravnborg 			s++;
1419588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1420588ccd73SSam Ravnborg 			strcat(p, "const ");
1421588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1422588ccd73SSam Ravnborg 			strcat(p, "data ");
1423588ccd73SSam Ravnborg 		else
1424588ccd73SSam Ravnborg 			strcat(p, " ");
1425cbcf14a9SAndy Shevchenko 		return r;
1426588ccd73SSam Ravnborg 	} else {
14271f3aa900SRandy Dunlap 		return NOFAIL(strdup(""));
1428588ccd73SSam Ravnborg 	}
1429588ccd73SSam Ravnborg }
1430588ccd73SSam Ravnborg 
1431588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1432588ccd73SSam Ravnborg {
1433588ccd73SSam Ravnborg 	if (sym)
1434588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1435588ccd73SSam Ravnborg 	else
1436f666751aSSam Ravnborg 		return -1;
1437588ccd73SSam Ravnborg }
1438588ccd73SSam Ravnborg 
143900759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
144000759c0eSRandy Dunlap {
144100759c0eSRandy Dunlap 	const char *const *s = list;
144200759c0eSRandy Dunlap 
144300759c0eSRandy Dunlap 	while (*s) {
144400759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
144500759c0eSRandy Dunlap 		s++;
144600759c0eSRandy Dunlap 		if (*s)
144700759c0eSRandy Dunlap 			fprintf(stderr, ", ");
144800759c0eSRandy Dunlap 	}
144900759c0eSRandy Dunlap 	fprintf(stderr, "\n");
145000759c0eSRandy Dunlap }
145100759c0eSRandy Dunlap 
1452356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1453356ad538SQuentin Casasnovas {
1454356ad538SQuentin Casasnovas 	switch (is_func) {
1455356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1456356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1457356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1458356ad538SQuentin Casasnovas 	}
1459356ad538SQuentin Casasnovas }
1460356ad538SQuentin Casasnovas 
1461588ccd73SSam Ravnborg /*
1462b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1463b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
14644c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
146558fb0d4fSSam Ravnborg  */
14660d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
14670d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
146858fb0d4fSSam Ravnborg 				const char *fromsec,
146958fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
147058fb0d4fSSam Ravnborg 				const char *fromsym,
1471588ccd73SSam Ravnborg 				int from_is_func,
1472588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1473588ccd73SSam Ravnborg 				int to_is_func)
1474b39927cfSSam Ravnborg {
1475588ccd73SSam Ravnborg 	const char *from, *from_p;
1476588ccd73SSam Ravnborg 	const char *to, *to_p;
147737ed19d5SAlexey Fomenko 	char *prl_from;
147837ed19d5SAlexey Fomenko 	char *prl_to;
1479f666751aSSam Ravnborg 
1480e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1481e5f95c8bSSam Ravnborg 
1482356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1483356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1484356ad538SQuentin Casasnovas 
14857c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14867c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14877c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14887c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1489588ccd73SSam Ravnborg 
14900d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1491bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
149237ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
149337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1494588ccd73SSam Ravnborg 		fprintf(stderr,
1495588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1496588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1497588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1498588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
149937ed19d5SAlexey Fomenko 		prl_from, fromsym,
150037ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
150137ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
150237ed19d5SAlexey Fomenko 		free(prl_from);
150337ed19d5SAlexey Fomenko 		free(prl_to);
1504588ccd73SSam Ravnborg 		break;
1505bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
150637ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1507588ccd73SSam Ravnborg 		fprintf(stderr,
1508588ccd73SSam Ravnborg 		"The variable %s references\n"
1509588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1510588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
15118b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1512588ccd73SSam Ravnborg 		"or name the variable:\n",
151337ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
151400759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
151537ed19d5SAlexey Fomenko 		free(prl_to);
1516588ccd73SSam Ravnborg 		break;
151758fb0d4fSSam Ravnborg 	}
1518bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
151937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1520588ccd73SSam Ravnborg 		fprintf(stderr,
1521588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1522588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1523588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
152437ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
152537ed19d5SAlexey Fomenko 		free(prl_to);
1526588ccd73SSam Ravnborg 		break;
1527bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
152837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1529588ccd73SSam Ravnborg 		fprintf(stderr,
1530588ccd73SSam Ravnborg 		"The variable %s references\n"
1531588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1532588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1533588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1534588ccd73SSam Ravnborg 		"name the variable:\n",
153537ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
153600759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
153737ed19d5SAlexey Fomenko 		free(prl_to);
1538588ccd73SSam Ravnborg 		break;
1539588ccd73SSam Ravnborg 	}
1540bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1541bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
154237ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
154337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1544588ccd73SSam Ravnborg 		fprintf(stderr,
1545588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1546588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1547588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1548588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
154937ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
155037ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1551b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
155237ed19d5SAlexey Fomenko 		free(prl_from);
155337ed19d5SAlexey Fomenko 		free(prl_to);
1554588ccd73SSam Ravnborg 		break;
1555bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
155637ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
155737ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1558588ccd73SSam Ravnborg 		fprintf(stderr,
1559588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1560588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1561588ccd73SSam Ravnborg 		"This is often seen when error handling "
1562588ccd73SSam Ravnborg 		"in the init function\n"
1563588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1564588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1565588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
156637ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
156737ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
15685003bab8SAndrew Morton 		prl_to, tosym, to_p);
156937ed19d5SAlexey Fomenko 		free(prl_from);
157037ed19d5SAlexey Fomenko 		free(prl_to);
1571588ccd73SSam Ravnborg 		break;
1572bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
157337ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
157437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1575588ccd73SSam Ravnborg 		fprintf(stderr,
1576588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1577588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1578588ccd73SSam Ravnborg 		"This is often seen when error handling "
1579588ccd73SSam Ravnborg 		"in the exit function\n"
1580588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1581588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1582588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
158337ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
158437ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
158537ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
158637ed19d5SAlexey Fomenko 		free(prl_from);
158737ed19d5SAlexey Fomenko 		free(prl_to);
1588588ccd73SSam Ravnborg 		break;
1589588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
159037ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1591588ccd73SSam Ravnborg 		fprintf(stderr,
1592588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1593588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1594588ccd73SSam Ravnborg 		"or drop the export.\n",
159537ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
159637ed19d5SAlexey Fomenko 		free(prl_to);
1597588ccd73SSam Ravnborg 		break;
159852dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
159952dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
160052dc0595SQuentin Casasnovas 		      "we should never get here.");
160152dc0595SQuentin Casasnovas 		break;
1602588ccd73SSam Ravnborg 	}
1603588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
160458fb0d4fSSam Ravnborg }
160558fb0d4fSSam Ravnborg 
1606644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1607644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
160858fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
160958fb0d4fSSam Ravnborg {
161058fb0d4fSSam Ravnborg 	const char *tosec;
1611588ccd73SSam Ravnborg 	Elf_Sym *to;
1612588ccd73SSam Ravnborg 	Elf_Sym *from;
161358fb0d4fSSam Ravnborg 	const char *tosym;
1614588ccd73SSam Ravnborg 	const char *fromsym;
161558fb0d4fSSam Ravnborg 
1616588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1617588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
161858fb0d4fSSam Ravnborg 
1619d62c4765SMasahiro Yamada 	if (strstarts(fromsym, "reference___initcall"))
162077ab21adSAndi Kleen 		return;
162177ab21adSAndi Kleen 
1622c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1623c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1624c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1625c7a65e06SQuentin Casasnovas 
162658fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1627af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1628af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1629588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1630588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1631588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1632588ccd73SSam Ravnborg 				    is_function(to));
163358fb0d4fSSam Ravnborg 	}
1634b39927cfSSam Ravnborg }
1635644e8f14SQuentin Casasnovas 
163652dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
163752dc0595SQuentin Casasnovas {
163852dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
163952dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
164052dc0595SQuentin Casasnovas 
164152dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
164252dc0595SQuentin Casasnovas }
164352dc0595SQuentin Casasnovas 
164452dc0595SQuentin Casasnovas /*
164552dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
164652dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
164752dc0595SQuentin Casasnovas  */
164852dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1649e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
165052dc0595SQuentin Casasnovas {
165152dc0595SQuentin Casasnovas 	/*
165252dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
165352dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
165452dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
165552dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
165652dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
165752dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
165852dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
165952dc0595SQuentin Casasnovas 	 */
1660e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
166152dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
166252dc0595SQuentin Casasnovas }
1663e84048aaSQuentin Casasnovas 
166452dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
166552dc0595SQuentin Casasnovas {
1666d3df4de7SQuentin Casasnovas 	/*
1667d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1668d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1669d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1670d3df4de7SQuentin Casasnovas 	 */
1671d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
167252dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
167352dc0595SQuentin Casasnovas 
167452dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
167552dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
167652dc0595SQuentin Casasnovas }
167752dc0595SQuentin Casasnovas 
1678e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1679e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1680e84048aaSQuentin Casasnovas 
168152dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
168252dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
168352dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
168452dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
168552dc0595SQuentin Casasnovas {
168652dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
168752dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
168852dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
168952dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
169052dc0595SQuentin Casasnovas 	const char* from_pretty_name;
169152dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
169252dc0595SQuentin Casasnovas 	const char* to_pretty_name;
169352dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
169452dc0595SQuentin Casasnovas 
169552dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
169652dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
169752dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
169852dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
169952dc0595SQuentin Casasnovas 
170052dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
170152dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
170252dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
170352dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
170452dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
170552dc0595SQuentin Casasnovas 
170652dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
170752dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
170852dc0595SQuentin Casasnovas 		fprintf(stderr,
170952dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
171052dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
171152dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
171252dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
171352dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
171452dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
171552dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
171652dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
171752dc0595SQuentin Casasnovas }
171852dc0595SQuentin Casasnovas 
171952dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
172052dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
172152dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
172252dc0595SQuentin Casasnovas 				     const char *fromsec)
172352dc0595SQuentin Casasnovas {
172452dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
172552dc0595SQuentin Casasnovas 
172652dc0595SQuentin Casasnovas 	sec_mismatch_count++;
172752dc0595SQuentin Casasnovas 
172846c7dd56SMasahiro Yamada 	report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
172952dc0595SQuentin Casasnovas 
173052dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
173152dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
173252dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
173352dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
173452dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
173552dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
173652dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
173752dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
173852dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
173952dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
174052dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
174152dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
174252dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
174352dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
174452dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
174552dc0595SQuentin Casasnovas 		else
174652dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
174752dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
174852dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
174952dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
175052dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
175152dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
175252dc0595SQuentin Casasnovas 	}
175352dc0595SQuentin Casasnovas }
175452dc0595SQuentin Casasnovas 
1755644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1756644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1757644e8f14SQuentin Casasnovas {
17580cad61d7SLuis de Bethencourt 	const char *tosec = sec_name(elf, get_secindex(elf, sym));
1759644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1760644e8f14SQuentin Casasnovas 
1761644e8f14SQuentin Casasnovas 	if (mismatch) {
1762644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1763644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1764644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1765644e8f14SQuentin Casasnovas 		else
1766644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1767644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1768644e8f14SQuentin Casasnovas 	}
1769b39927cfSSam Ravnborg }
1770b39927cfSSam Ravnborg 
1771ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
17725b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1773ae4ac123SAtsushi Nemoto {
1774ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17756845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1776ae4ac123SAtsushi Nemoto 
1777ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1778731ece41SOlof Johansson 		r->r_offset;
1779ae4ac123SAtsushi Nemoto }
1780ae4ac123SAtsushi Nemoto 
17815b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1782ae4ac123SAtsushi Nemoto {
1783ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17845b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1785ae4ac123SAtsushi Nemoto 
1786ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1787ae4ac123SAtsushi Nemoto 	case R_386_32:
1788ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1789ae4ac123SAtsushi Nemoto 		break;
1790ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1791ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1792ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1793ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1794ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1795ae4ac123SAtsushi Nemoto 		break;
1796ae4ac123SAtsushi Nemoto 	}
1797ae4ac123SAtsushi Nemoto 	return 0;
1798ae4ac123SAtsushi Nemoto }
1799ae4ac123SAtsushi Nemoto 
18006e2e340bSTony Lindgren #ifndef R_ARM_CALL
18016e2e340bSTony Lindgren #define R_ARM_CALL	28
18026e2e340bSTony Lindgren #endif
18036e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
18046e2e340bSTony Lindgren #define R_ARM_JUMP24	29
18056e2e340bSTony Lindgren #endif
18066e2e340bSTony Lindgren 
1807c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1808c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1809c9698e5cSDavid A. Long #endif
1810c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1811c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1812c9698e5cSDavid A. Long #endif
1813c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1814c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1815c9698e5cSDavid A. Long #endif
1816c9698e5cSDavid A. Long 
18175b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
181856a974faSSam Ravnborg {
181956a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
182056a974faSSam Ravnborg 
182156a974faSSam Ravnborg 	switch (r_typ) {
182256a974faSSam Ravnborg 	case R_ARM_ABS32:
182356a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1824df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1825df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
182656a974faSSam Ravnborg 		break;
182756a974faSSam Ravnborg 	case R_ARM_PC24:
18286e2e340bSTony Lindgren 	case R_ARM_CALL:
18296e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1830c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1831c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1832c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
183356a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1834df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
18355b24c071SSam Ravnborg 			      sechdr->sh_offset +
18365b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
183756a974faSSam Ravnborg 		break;
183856a974faSSam Ravnborg 	default:
183956a974faSSam Ravnborg 		return 1;
184056a974faSSam Ravnborg 	}
184156a974faSSam Ravnborg 	return 0;
184256a974faSSam Ravnborg }
184356a974faSSam Ravnborg 
18445b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1845ae4ac123SAtsushi Nemoto {
1846ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
18475b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1848ae4ac123SAtsushi Nemoto 	unsigned int inst;
1849ae4ac123SAtsushi Nemoto 
1850ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1851ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1852ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1853ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1854ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1855ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1856ae4ac123SAtsushi Nemoto 		break;
1857ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1858ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1859ae4ac123SAtsushi Nemoto 		break;
1860ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1861ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1862ae4ac123SAtsushi Nemoto 		break;
1863ae4ac123SAtsushi Nemoto 	}
1864ae4ac123SAtsushi Nemoto 	return 0;
1865ae4ac123SAtsushi Nemoto }
1866ae4ac123SAtsushi Nemoto 
18675b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
186810668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1869b39927cfSSam Ravnborg {
1870b39927cfSSam Ravnborg 	Elf_Sym  *sym;
18715b24c071SSam Ravnborg 	Elf_Rela *rela;
18722c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1873eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18745b24c071SSam Ravnborg 	const char *fromsec;
18755b24c071SSam Ravnborg 
1876ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18775b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18785b24c071SSam Ravnborg 
1879ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18805b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18815b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1882b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18835b24c071SSam Ravnborg 		return;
1884e241a630SSam Ravnborg 
1885b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1886b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1887eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1888ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1889ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1890eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1891eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1892ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1893ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1894eae07ac6SAtsushi Nemoto 		} else {
1895601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1896eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1897eae07ac6SAtsushi Nemoto 		}
1898eae07ac6SAtsushi Nemoto #else
1899eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1900eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1901eae07ac6SAtsushi Nemoto #endif
190293684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1903eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1904b39927cfSSam Ravnborg 		/* Skip special sections */
19051ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1906b39927cfSSam Ravnborg 			continue;
1907e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1908e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
190958fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19102c1a51f3SAtsushi Nemoto 	}
19115b24c071SSam Ravnborg }
19125b24c071SSam Ravnborg 
19135b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
191410668220SSam Ravnborg 			Elf_Shdr *sechdr)
19155b24c071SSam Ravnborg {
19165b24c071SSam Ravnborg 	Elf_Sym *sym;
19172c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
19185b24c071SSam Ravnborg 	Elf_Rela r;
19195b24c071SSam Ravnborg 	unsigned int r_sym;
19205b24c071SSam Ravnborg 	const char *fromsec;
19215b24c071SSam Ravnborg 
1922ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
19235b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
19245b24c071SSam Ravnborg 
1925ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
19265b24c071SSam Ravnborg 	fromsec += strlen(".rel");
19275b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1928b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
19295b24c071SSam Ravnborg 		return;
19302c1a51f3SAtsushi Nemoto 
19312c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
19322c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1933eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1934ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1935ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1936eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1937eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1938ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1939ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1940eae07ac6SAtsushi Nemoto 		} else {
19412c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1942eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1943eae07ac6SAtsushi Nemoto 		}
1944eae07ac6SAtsushi Nemoto #else
1945eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1946eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1947eae07ac6SAtsushi Nemoto #endif
19482c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1949ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1950ae4ac123SAtsushi Nemoto 		case EM_386:
19515b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1952ae4ac123SAtsushi Nemoto 				continue;
1953ae4ac123SAtsushi Nemoto 			break;
195456a974faSSam Ravnborg 		case EM_ARM:
19555b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
195656a974faSSam Ravnborg 				continue;
195756a974faSSam Ravnborg 			break;
1958ae4ac123SAtsushi Nemoto 		case EM_MIPS:
19595b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1960ae4ac123SAtsushi Nemoto 				continue;
1961ae4ac123SAtsushi Nemoto 			break;
1962ae4ac123SAtsushi Nemoto 		}
1963eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
19642c1a51f3SAtsushi Nemoto 		/* Skip special sections */
19651ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
19662c1a51f3SAtsushi Nemoto 			continue;
1967e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1968e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
196958fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19702c1a51f3SAtsushi Nemoto 	}
1971b39927cfSSam Ravnborg }
19725b24c071SSam Ravnborg 
19735b24c071SSam Ravnborg /**
19745b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19755b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19765b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1977b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19785b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19795b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
198032be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19815b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19825b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19835b24c071SSam Ravnborg  * be discarded and warns about it.
19845b24c071SSam Ravnborg  **/
19855b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
198610668220SSam Ravnborg 			  struct elf_info *elf)
19875b24c071SSam Ravnborg {
19885b24c071SSam Ravnborg 	int i;
19895b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19905b24c071SSam Ravnborg 
19915b24c071SSam Ravnborg 	/* Walk through all sections */
19921ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1993b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19945b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19955b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
199610668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19975b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
199810668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1999b39927cfSSam Ravnborg 	}
2000b39927cfSSam Ravnborg }
2001b39927cfSSam Ravnborg 
20027d02b490SAndi Kleen static char *remove_dot(char *s)
20037d02b490SAndi Kleen {
2004fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
20057d02b490SAndi Kleen 
2006fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
2007fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
2008fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
20097d02b490SAndi Kleen 			s[n] = 0;
20107d02b490SAndi Kleen 	}
20117d02b490SAndi Kleen 	return s;
20127d02b490SAndi Kleen }
20137d02b490SAndi Kleen 
20148b185743SMasahiro Yamada static void read_symbols(const char *modname)
20151da177e4SLinus Torvalds {
20161da177e4SLinus Torvalds 	const char *symname;
20171da177e4SLinus Torvalds 	char *version;
2018b817f6feSSam Ravnborg 	char *license;
2019cb9b55d2SMatthias Maennich 	char *namespace;
20201da177e4SLinus Torvalds 	struct module *mod;
20211da177e4SLinus Torvalds 	struct elf_info info = { };
20221da177e4SLinus Torvalds 	Elf_Sym *sym;
20231da177e4SLinus Torvalds 
202485bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
202585bd2fddSSam Ravnborg 		return;
20261da177e4SLinus Torvalds 
20271da177e4SLinus Torvalds 	mod = new_module(modname);
20281da177e4SLinus Torvalds 
20291da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
20301da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
20311da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
20321da177e4SLinus Torvalds 		have_vmlinux = 1;
20331da177e4SLinus Torvalds 		mod->skip = 1;
20341da177e4SLinus Torvalds 	}
20351da177e4SLinus Torvalds 
2036bca2cceeSMasahiro Yamada 	license = get_modinfo(&info, "license");
2037ba1029c9SRandy Dunlap 	if (!license && !is_vmlinux(modname))
20382fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
2039eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
2040eed7d279SSam Ravnborg 		     "more information\n", modname);
2041b817f6feSSam Ravnborg 	while (license) {
2042b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
2043b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
2044b817f6feSSam Ravnborg 		else {
2045b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
2046b817f6feSSam Ravnborg 			break;
2047b817f6feSSam Ravnborg 		}
2048bca2cceeSMasahiro Yamada 		license = get_next_modinfo(&info, "license", license);
2049b817f6feSSam Ravnborg 	}
2050b817f6feSSam Ravnborg 
2051cb9b55d2SMatthias Maennich 	namespace = get_modinfo(&info, "import_ns");
2052cb9b55d2SMatthias Maennich 	while (namespace) {
2053cb9b55d2SMatthias Maennich 		add_namespace(&mod->imported_namespaces, namespace);
2054cb9b55d2SMatthias Maennich 		namespace = get_next_modinfo(&info, "import_ns", namespace);
2055cb9b55d2SMatthias Maennich 	}
2056cb9b55d2SMatthias Maennich 
20571da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
20587d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
20591da177e4SLinus Torvalds 
20601da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
20611da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
20621da177e4SLinus Torvalds 	}
206315bfc234SDenis Efremov 
206415bfc234SDenis Efremov 	// check for static EXPORT_SYMBOL_* functions && global vars
206515bfc234SDenis Efremov 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
206615bfc234SDenis Efremov 		unsigned char bind = ELF_ST_BIND(sym->st_info);
206715bfc234SDenis Efremov 
206815bfc234SDenis Efremov 		if (bind == STB_GLOBAL || bind == STB_WEAK) {
206915bfc234SDenis Efremov 			struct symbol *s =
207015bfc234SDenis Efremov 				find_symbol(remove_dot(info.strtab +
207115bfc234SDenis Efremov 						       sym->st_name));
207215bfc234SDenis Efremov 
207315bfc234SDenis Efremov 			if (s)
207415bfc234SDenis Efremov 				s->is_static = 0;
207515bfc234SDenis Efremov 		}
207615bfc234SDenis Efremov 	}
207715bfc234SDenis Efremov 
2078074a04f5SMasahiro Yamada 	if (!is_vmlinux(modname) || vmlinux_section_warnings)
207910668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
20801da177e4SLinus Torvalds 
2081bca2cceeSMasahiro Yamada 	version = get_modinfo(&info, "version");
20821da177e4SLinus Torvalds 	if (version)
20831da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
20841da177e4SLinus Torvalds 				       version - (char *)info.hdr);
20851da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
20861da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
20871da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
20881da177e4SLinus Torvalds 
20891da177e4SLinus Torvalds 	parse_elf_finish(&info);
20901da177e4SLinus Torvalds 
20918c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
20921da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
20931da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
20941da177e4SLinus Torvalds 	 * important anyhow */
20951da177e4SLinus Torvalds 	if (modversions)
20968c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
20971da177e4SLinus Torvalds }
20981da177e4SLinus Torvalds 
2099712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2100712f9b46SRusty Russell {
2101712f9b46SRusty Russell 	FILE *in = stdin;
2102712f9b46SRusty Russell 	char fname[PATH_MAX];
2103712f9b46SRusty Russell 
2104712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2105712f9b46SRusty Russell 		in = fopen(filename, "r");
2106712f9b46SRusty Russell 		if (!in)
2107712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2108712f9b46SRusty Russell 	}
2109712f9b46SRusty Russell 
2110712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2111712f9b46SRusty Russell 		if (strends(fname, "\n"))
2112712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2113712f9b46SRusty Russell 		read_symbols(fname);
2114712f9b46SRusty Russell 	}
2115712f9b46SRusty Russell 
2116712f9b46SRusty Russell 	if (in != stdin)
2117712f9b46SRusty Russell 		fclose(in);
2118712f9b46SRusty Russell }
2119712f9b46SRusty Russell 
21201da177e4SLinus Torvalds #define SZ 500
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds /* We first write the generated file into memory using the
21231da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
21241da177e4SLinus Torvalds  * only update the later if anything changed */
21251da177e4SLinus Torvalds 
21265c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
21275c3ead8cSSam Ravnborg 						      const char *fmt, ...)
21281da177e4SLinus Torvalds {
21291da177e4SLinus Torvalds 	char tmp[SZ];
21301da177e4SLinus Torvalds 	int len;
21311da177e4SLinus Torvalds 	va_list ap;
21321da177e4SLinus Torvalds 
21331da177e4SLinus Torvalds 	va_start(ap, fmt);
21341da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
21357670f023SSam Ravnborg 	buf_write(buf, tmp, len);
21361da177e4SLinus Torvalds 	va_end(ap);
21371da177e4SLinus Torvalds }
21381da177e4SLinus Torvalds 
21395c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
21401da177e4SLinus Torvalds {
21411da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
21427670f023SSam Ravnborg 		buf->size += len + SZ;
21431f3aa900SRandy Dunlap 		buf->p = NOFAIL(realloc(buf->p, buf->size));
21441da177e4SLinus Torvalds 	}
21451da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
21461da177e4SLinus Torvalds 	buf->pos += len;
21471da177e4SLinus Torvalds }
21481da177e4SLinus Torvalds 
2149c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2150c96fca21SSam Ravnborg {
2151c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2152c96fca21SSam Ravnborg 
2153c96fca21SSam Ravnborg 	switch (exp) {
2154c96fca21SSam Ravnborg 	case export_gpl:
2155c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2156c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2157c96fca21SSam Ravnborg 		break;
2158c96fca21SSam Ravnborg 	case export_unused_gpl:
2159c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2160c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2161c96fca21SSam Ravnborg 		break;
2162c96fca21SSam Ravnborg 	case export_gpl_future:
2163c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2164c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2165c96fca21SSam Ravnborg 		break;
2166c96fca21SSam Ravnborg 	case export_plain:
2167c96fca21SSam Ravnborg 	case export_unused:
2168c96fca21SSam Ravnborg 	case export_unknown:
2169c96fca21SSam Ravnborg 		/* ignore */
2170c96fca21SSam Ravnborg 		break;
2171c96fca21SSam Ravnborg 	}
2172c96fca21SSam Ravnborg }
2173c96fca21SSam Ravnborg 
2174c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2175c96fca21SSam Ravnborg {
2176c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2177c96fca21SSam Ravnborg 
2178c96fca21SSam Ravnborg 	switch (exp) {
2179c96fca21SSam Ravnborg 	case export_unused:
2180c96fca21SSam Ravnborg 	case export_unused_gpl:
2181c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2182c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2183c96fca21SSam Ravnborg 		break;
2184c96fca21SSam Ravnborg 	default:
2185c96fca21SSam Ravnborg 		/* ignore */
2186c96fca21SSam Ravnborg 		break;
2187c96fca21SSam Ravnborg 	}
2188c96fca21SSam Ravnborg }
2189c96fca21SSam Ravnborg 
21903b415288SMasahiro Yamada static int check_exports(struct module *mod)
2191b817f6feSSam Ravnborg {
2192b817f6feSSam Ravnborg 	struct symbol *s, *exp;
21933b415288SMasahiro Yamada 	int err = 0;
2194b817f6feSSam Ravnborg 
2195b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21966449bd62SAndrew Morton 		const char *basename;
2197b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
21983b415288SMasahiro Yamada 		if (!exp || exp->module == mod) {
21993b415288SMasahiro Yamada 			if (have_vmlinux && !s->weak) {
22003b415288SMasahiro Yamada 				if (warn_unresolved) {
22013b415288SMasahiro Yamada 					warn("\"%s\" [%s.ko] undefined!\n",
22023b415288SMasahiro Yamada 					     s->name, mod->name);
22033b415288SMasahiro Yamada 				} else {
22043b415288SMasahiro Yamada 					merror("\"%s\" [%s.ko] undefined!\n",
22053b415288SMasahiro Yamada 					       s->name, mod->name);
22063b415288SMasahiro Yamada 					err = 1;
22073b415288SMasahiro Yamada 				}
22083b415288SMasahiro Yamada 			}
2209b817f6feSSam Ravnborg 			continue;
22103b415288SMasahiro Yamada 		}
22116449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2212b817f6feSSam Ravnborg 		if (basename)
2213b817f6feSSam Ravnborg 			basename++;
2214c96fca21SSam Ravnborg 		else
2215c96fca21SSam Ravnborg 			basename = mod->name;
2216cb9b55d2SMatthias Maennich 
2217*a2b11184SMatthias Maennich 		if (exp->namespace) {
22181d082773SMatthias Maennich 			add_namespace(&mod->required_namespaces,
22191d082773SMatthias Maennich 				      exp->namespace);
22201d082773SMatthias Maennich 
22211d082773SMatthias Maennich 			if (!write_namespace_deps &&
2222cb9b55d2SMatthias Maennich 			    !module_imports_namespace(mod, exp->namespace)) {
2223cb9b55d2SMatthias Maennich 				warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
2224cb9b55d2SMatthias Maennich 				     basename, exp->name, exp->namespace);
2225cb9b55d2SMatthias Maennich 			}
22261d082773SMatthias Maennich 		}
2227cb9b55d2SMatthias Maennich 
2228c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2229c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2230c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2231b817f6feSSam Ravnborg 	}
22323b415288SMasahiro Yamada 
22333b415288SMasahiro Yamada 	return err;
2234b817f6feSSam Ravnborg }
2235b817f6feSSam Ravnborg 
22364fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
22374fd3e4efSWanlong Gao {
22384fd3e4efSWanlong Gao 	const char *mod_name;
22394fd3e4efSWanlong Gao 
22404fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
22414fd3e4efSWanlong Gao 	if (mod_name == NULL)
22424fd3e4efSWanlong Gao 		mod_name = mod->name;
22434fd3e4efSWanlong Gao 	else
22444fd3e4efSWanlong Gao 		mod_name++;
22454fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
22464fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
22474fd3e4efSWanlong Gao 		return 1;
22484fd3e4efSWanlong Gao 	}
22494fd3e4efSWanlong Gao 
22504fd3e4efSWanlong Gao 	return 0;
22514fd3e4efSWanlong Gao }
22524fd3e4efSWanlong Gao 
22535c3ead8cSSam Ravnborg /**
22545c3ead8cSSam Ravnborg  * Header for the generated file
22555c3ead8cSSam Ravnborg  **/
22565c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
22571da177e4SLinus Torvalds {
22589afb719eSLaura Abbott 	buf_printf(b, "#include <linux/build-salt.h>\n");
22591da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
22601da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
22611da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
22621da177e4SLinus Torvalds 	buf_printf(b, "\n");
22639afb719eSLaura Abbott 	buf_printf(b, "BUILD_SALT;\n");
22649afb719eSLaura Abbott 	buf_printf(b, "\n");
22651da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
22663e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
22671da177e4SLinus Torvalds 	buf_printf(b, "\n");
2268e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
2269a3d0cb04SMasahiro Yamada 	buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
22703c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
22711da177e4SLinus Torvalds 	if (mod->has_init)
22723c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
22731da177e4SLinus Torvalds 	if (mod->has_cleanup)
22741da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
22753c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
22761da177e4SLinus Torvalds 			      "#endif\n");
22773c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
22781da177e4SLinus Torvalds 	buf_printf(b, "};\n");
22791da177e4SLinus Torvalds }
22801da177e4SLinus Torvalds 
22812449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
22822449b8baSBen Hutchings {
22832449b8baSBen Hutchings 	if (is_intree)
22842449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
22852449b8baSBen Hutchings }
22862449b8baSBen Hutchings 
2287caf7501aSAndi Kleen /* Cannot check for assembler */
2288caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2289caf7501aSAndi Kleen {
2290e4f35891SWANG Chao 	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
2291caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2292caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2293caf7501aSAndi Kleen }
2294caf7501aSAndi Kleen 
22955c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2296a9860bf0SGreg Kroah-Hartman {
2297d62c4765SMasahiro Yamada 	if (strstarts(name, "drivers/staging"))
2298a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2299a9860bf0SGreg Kroah-Hartman }
2300a9860bf0SGreg Kroah-Hartman 
23015c3ead8cSSam Ravnborg /**
23025c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
23035c3ead8cSSam Ravnborg  **/
2304c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
23051da177e4SLinus Torvalds {
23061da177e4SLinus Torvalds 	struct symbol *s, *exp;
2307c53ddacdSKirill Korotaev 	int err = 0;
23081da177e4SLinus Torvalds 
23091da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
23101da177e4SLinus Torvalds 		exp = find_symbol(s->name);
23113b415288SMasahiro Yamada 		if (!exp || exp->module == mod)
23121da177e4SLinus Torvalds 			continue;
23131da177e4SLinus Torvalds 		s->module = exp->module;
23141da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
23151da177e4SLinus Torvalds 		s->crc = exp->crc;
23161da177e4SLinus Torvalds 	}
23171da177e4SLinus Torvalds 
23181da177e4SLinus Torvalds 	if (!modversions)
2319c53ddacdSKirill Korotaev 		return err;
23201da177e4SLinus Torvalds 
23211da177e4SLinus Torvalds 	buf_printf(b, "\n");
23221da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
2323a3d0cb04SMasahiro Yamada 	buf_printf(b, "__used __section(__versions) = {\n");
23241da177e4SLinus Torvalds 
23251da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2326df578e7dSSam Ravnborg 		if (!s->module)
23271da177e4SLinus Torvalds 			continue;
23281da177e4SLinus Torvalds 		if (!s->crc_valid) {
2329cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
23301da177e4SLinus Torvalds 				s->name, mod->name);
23311da177e4SLinus Torvalds 			continue;
23321da177e4SLinus Torvalds 		}
23335cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
23345cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
23355cfb203aSTakashi Iwai 			       s->name, mod->name);
23365cfb203aSTakashi Iwai 			err = 1;
23375cfb203aSTakashi Iwai 			break;
23385cfb203aSTakashi Iwai 		}
2339b2c5cdcfSMasahiro Yamada 		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
2340a4b6a77bSJames Hogan 			   s->crc, s->name);
23411da177e4SLinus Torvalds 	}
23421da177e4SLinus Torvalds 
23431da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2344c53ddacdSKirill Korotaev 
2345c53ddacdSKirill Korotaev 	return err;
23461da177e4SLinus Torvalds }
23471da177e4SLinus Torvalds 
2348d2665ca8SMasahiro Yamada static void add_depends(struct buffer *b, struct module *mod)
23491da177e4SLinus Torvalds {
23501da177e4SLinus Torvalds 	struct symbol *s;
23511da177e4SLinus Torvalds 	int first = 1;
23521da177e4SLinus Torvalds 
2353d2665ca8SMasahiro Yamada 	/* Clear ->seen flag of modules that own symbols needed by this. */
2354d2665ca8SMasahiro Yamada 	for (s = mod->unres; s; s = s->next)
2355d2665ca8SMasahiro Yamada 		if (s->module)
2356d2665ca8SMasahiro Yamada 			s->module->seen = is_vmlinux(s->module->name);
23571da177e4SLinus Torvalds 
23581da177e4SLinus Torvalds 	buf_printf(b, "\n");
23596df7e1ecSMasahiro Yamada 	buf_printf(b, "MODULE_INFO(depends, \"");
23601da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2361a61b2dfdSSam Ravnborg 		const char *p;
23621da177e4SLinus Torvalds 		if (!s->module)
23631da177e4SLinus Torvalds 			continue;
23641da177e4SLinus Torvalds 
23651da177e4SLinus Torvalds 		if (s->module->seen)
23661da177e4SLinus Torvalds 			continue;
23671da177e4SLinus Torvalds 
23681da177e4SLinus Torvalds 		s->module->seen = 1;
2369df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2370df578e7dSSam Ravnborg 		if (p)
2371a61b2dfdSSam Ravnborg 			p++;
2372a61b2dfdSSam Ravnborg 		else
2373a61b2dfdSSam Ravnborg 			p = s->module->name;
2374a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
23751da177e4SLinus Torvalds 		first = 0;
23761da177e4SLinus Torvalds 	}
23776df7e1ecSMasahiro Yamada 	buf_printf(b, "\");\n");
23781da177e4SLinus Torvalds }
23791da177e4SLinus Torvalds 
23805c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
23811da177e4SLinus Torvalds {
23821da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
23831da177e4SLinus Torvalds 		buf_printf(b, "\n");
23841da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
23851da177e4SLinus Torvalds 			   mod->srcversion);
23861da177e4SLinus Torvalds 	}
23871da177e4SLinus Torvalds }
23881da177e4SLinus Torvalds 
23895c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
23901da177e4SLinus Torvalds {
23911da177e4SLinus Torvalds 	char *tmp;
23921da177e4SLinus Torvalds 	FILE *file;
23931da177e4SLinus Torvalds 	struct stat st;
23941da177e4SLinus Torvalds 
23951da177e4SLinus Torvalds 	file = fopen(fname, "r");
23961da177e4SLinus Torvalds 	if (!file)
23971da177e4SLinus Torvalds 		goto write;
23981da177e4SLinus Torvalds 
23991da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
24001da177e4SLinus Torvalds 		goto close_write;
24011da177e4SLinus Torvalds 
24021da177e4SLinus Torvalds 	if (st.st_size != b->pos)
24031da177e4SLinus Torvalds 		goto close_write;
24041da177e4SLinus Torvalds 
24051da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
24061da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
24071da177e4SLinus Torvalds 		goto free_write;
24081da177e4SLinus Torvalds 
24091da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
24101da177e4SLinus Torvalds 		goto free_write;
24111da177e4SLinus Torvalds 
24121da177e4SLinus Torvalds 	free(tmp);
24131da177e4SLinus Torvalds 	fclose(file);
24141da177e4SLinus Torvalds 	return;
24151da177e4SLinus Torvalds 
24161da177e4SLinus Torvalds  free_write:
24171da177e4SLinus Torvalds 	free(tmp);
24181da177e4SLinus Torvalds  close_write:
24191da177e4SLinus Torvalds 	fclose(file);
24201da177e4SLinus Torvalds  write:
24211da177e4SLinus Torvalds 	file = fopen(fname, "w");
24221da177e4SLinus Torvalds 	if (!file) {
24231da177e4SLinus Torvalds 		perror(fname);
24241da177e4SLinus Torvalds 		exit(1);
24251da177e4SLinus Torvalds 	}
24261da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
24271da177e4SLinus Torvalds 		perror(fname);
24281da177e4SLinus Torvalds 		exit(1);
24291da177e4SLinus Torvalds 	}
24301da177e4SLinus Torvalds 	fclose(file);
24311da177e4SLinus Torvalds }
24321da177e4SLinus Torvalds 
2433bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2434534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2435bd5cbcedSRam Pai  **/
2436040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
24371da177e4SLinus Torvalds {
24381da177e4SLinus Torvalds 	unsigned long size, pos = 0;
24391da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
24401da177e4SLinus Torvalds 	char *line;
24411da177e4SLinus Torvalds 
24421da177e4SLinus Torvalds 	if (!file)
24431da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
24441da177e4SLinus Torvalds 		return;
24451da177e4SLinus Torvalds 
24461da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2447cb9b55d2SMatthias Maennich 		char *symname, *namespace, *modname, *d, *export, *end;
24481da177e4SLinus Torvalds 		unsigned int crc;
24491da177e4SLinus Torvalds 		struct module *mod;
2450040fcc81SSam Ravnborg 		struct symbol *s;
24511da177e4SLinus Torvalds 
24521da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
24531da177e4SLinus Torvalds 			goto fail;
24541da177e4SLinus Torvalds 		*symname++ = '\0';
2455cb9b55d2SMatthias Maennich 		if (!(namespace = strchr(symname, '\t')))
2456cb9b55d2SMatthias Maennich 			goto fail;
2457cb9b55d2SMatthias Maennich 		*namespace++ = '\0';
2458cb9b55d2SMatthias Maennich 		if (!(modname = strchr(namespace, '\t')))
24591da177e4SLinus Torvalds 			goto fail;
24601da177e4SLinus Torvalds 		*modname++ = '\0';
24619ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2462bd5cbcedSRam Pai 			*export++ = '\0';
2463534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2464534b89a9SSam Ravnborg 			*end = '\0';
24651da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
24661da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
24671da177e4SLinus Torvalds 			goto fail;
2468df578e7dSSam Ravnborg 		mod = find_module(modname);
2469df578e7dSSam Ravnborg 		if (!mod) {
2470df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
24711da177e4SLinus Torvalds 				have_vmlinux = 1;
24720fa3a88cSJan Beulich 			mod = new_module(modname);
24731da177e4SLinus Torvalds 			mod->skip = 1;
24741da177e4SLinus Torvalds 		}
2475cb9b55d2SMatthias Maennich 		s = sym_add_exported(symname, namespace, mod,
2476cb9b55d2SMatthias Maennich 				     export_no(export));
2477040fcc81SSam Ravnborg 		s->kernel    = kernel;
24788e70c458SSam Ravnborg 		s->preloaded = 1;
247915bfc234SDenis Efremov 		s->is_static = 0;
2480bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
24811da177e4SLinus Torvalds 	}
24822ee41e62SChristian Engelmayer 	release_file(file, size);
24831da177e4SLinus Torvalds 	return;
24841da177e4SLinus Torvalds fail:
24852ee41e62SChristian Engelmayer 	release_file(file, size);
24861da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
24871da177e4SLinus Torvalds }
24881da177e4SLinus Torvalds 
2489040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2490040fcc81SSam Ravnborg  * For external modules only dump symbols
2491040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2492040fcc81SSam Ravnborg  **/
2493040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2494040fcc81SSam Ravnborg {
2495040fcc81SSam Ravnborg 	if (!external_module)
2496040fcc81SSam Ravnborg 		return 1;
2497040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2498040fcc81SSam Ravnborg 		return 0;
2499040fcc81SSam Ravnborg 	return 1;
2500040fcc81SSam Ravnborg }
2501040fcc81SSam Ravnborg 
25025c3ead8cSSam Ravnborg static void write_dump(const char *fname)
25031da177e4SLinus Torvalds {
25041da177e4SLinus Torvalds 	struct buffer buf = { };
25051da177e4SLinus Torvalds 	struct symbol *symbol;
2506cb9b55d2SMatthias Maennich 	const char *namespace;
25071da177e4SLinus Torvalds 	int n;
25081da177e4SLinus Torvalds 
25091da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
25101da177e4SLinus Torvalds 		symbol = symbolhash[n];
25111da177e4SLinus Torvalds 		while (symbol) {
2512cb9b55d2SMatthias Maennich 			if (dump_sym(symbol)) {
2513cb9b55d2SMatthias Maennich 				namespace = symbol->namespace;
2514cb9b55d2SMatthias Maennich 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
2515040fcc81SSam Ravnborg 					   symbol->crc, symbol->name,
2516cb9b55d2SMatthias Maennich 					   namespace ? namespace : "",
2517bd5cbcedSRam Pai 					   symbol->module->name,
2518bd5cbcedSRam Pai 					   export_str(symbol->export));
2519cb9b55d2SMatthias Maennich 			}
25201da177e4SLinus Torvalds 			symbol = symbol->next;
25211da177e4SLinus Torvalds 		}
25221da177e4SLinus Torvalds 	}
25231da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2524c7d47f26SHeinrich Schuchardt 	free(buf.p);
25251da177e4SLinus Torvalds }
25261da177e4SLinus Torvalds 
25271d082773SMatthias Maennich static void write_namespace_deps_files(void)
25281d082773SMatthias Maennich {
25291d082773SMatthias Maennich 	struct module *mod;
25301d082773SMatthias Maennich 	struct namespace_list *ns;
25311d082773SMatthias Maennich 	struct buffer ns_deps_buf = {};
25321d082773SMatthias Maennich 
25331d082773SMatthias Maennich 	for (mod = modules; mod; mod = mod->next) {
25341d082773SMatthias Maennich 		char fname[PATH_MAX];
25351d082773SMatthias Maennich 
25361d082773SMatthias Maennich 		if (mod->skip)
25371d082773SMatthias Maennich 			continue;
25381d082773SMatthias Maennich 
25391d082773SMatthias Maennich 		ns_deps_buf.pos = 0;
25401d082773SMatthias Maennich 
25411d082773SMatthias Maennich 		for (ns = mod->required_namespaces; ns; ns = ns->next)
25421d082773SMatthias Maennich 			buf_printf(&ns_deps_buf, "%s\n", ns->namespace);
25431d082773SMatthias Maennich 
25441d082773SMatthias Maennich 		if (ns_deps_buf.pos == 0)
25451d082773SMatthias Maennich 			continue;
25461d082773SMatthias Maennich 
25471d082773SMatthias Maennich 		sprintf(fname, "%s.ns_deps", mod->name);
25481d082773SMatthias Maennich 		write_if_changed(&ns_deps_buf, fname);
25491d082773SMatthias Maennich 	}
25501d082773SMatthias Maennich }
25511d082773SMatthias Maennich 
25522d04b5aeSRichard Hacker struct ext_sym_list {
25532d04b5aeSRichard Hacker 	struct ext_sym_list *next;
25542d04b5aeSRichard Hacker 	const char *file;
25552d04b5aeSRichard Hacker };
25562d04b5aeSRichard Hacker 
25575c3ead8cSSam Ravnborg int main(int argc, char **argv)
25581da177e4SLinus Torvalds {
25591da177e4SLinus Torvalds 	struct module *mod;
25601da177e4SLinus Torvalds 	struct buffer buf = { };
2561040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2562712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
25631da177e4SLinus Torvalds 	int opt;
2564c53ddacdSKirill Korotaev 	int err;
256515bfc234SDenis Efremov 	int n;
25662d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
25672d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
25681da177e4SLinus Torvalds 
25691d082773SMatthias Maennich 	while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {
25701da177e4SLinus Torvalds 		switch (opt) {
25711da177e4SLinus Torvalds 		case 'i':
2572040fcc81SSam Ravnborg 			kernel_read = optarg;
2573040fcc81SSam Ravnborg 			break;
2574040fcc81SSam Ravnborg 		case 'I':
2575040fcc81SSam Ravnborg 			module_read = optarg;
2576040fcc81SSam Ravnborg 			external_module = 1;
25771da177e4SLinus Torvalds 			break;
25782d04b5aeSRichard Hacker 		case 'e':
25792d04b5aeSRichard Hacker 			external_module = 1;
25802d04b5aeSRichard Hacker 			extsym_iter =
25812d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
25822d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
25832d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
25842d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
25852d04b5aeSRichard Hacker 			break;
25861da177e4SLinus Torvalds 		case 'm':
25871da177e4SLinus Torvalds 			modversions = 1;
25881da177e4SLinus Torvalds 			break;
2589eed380f3SGuenter Roeck 		case 'n':
2590eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2591eed380f3SGuenter Roeck 			break;
25921da177e4SLinus Torvalds 		case 'o':
25931da177e4SLinus Torvalds 			dump_write = optarg;
25941da177e4SLinus Torvalds 			break;
25951da177e4SLinus Torvalds 		case 'a':
25961da177e4SLinus Torvalds 			all_versions = 1;
25971da177e4SLinus Torvalds 			break;
25988d8d8289SSam Ravnborg 		case 's':
25998d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
26008d8d8289SSam Ravnborg 			break;
2601712f9b46SRusty Russell 		case 'T':
2602712f9b46SRusty Russell 			files_source = optarg;
2603712f9b46SRusty Russell 			break;
2604c53ddacdSKirill Korotaev 		case 'w':
2605c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2606c53ddacdSKirill Korotaev 			break;
260747490ec1SNicolas Boichat 		case 'E':
260847490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
260947490ec1SNicolas Boichat 			break;
26101d082773SMatthias Maennich 		case 'd':
26111d082773SMatthias Maennich 			write_namespace_deps = 1;
26121d082773SMatthias Maennich 			break;
26131da177e4SLinus Torvalds 		default:
26141da177e4SLinus Torvalds 			exit(1);
26151da177e4SLinus Torvalds 		}
26161da177e4SLinus Torvalds 	}
26171da177e4SLinus Torvalds 
2618040fcc81SSam Ravnborg 	if (kernel_read)
2619040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2620040fcc81SSam Ravnborg 	if (module_read)
2621040fcc81SSam Ravnborg 		read_dump(module_read, 0);
26222d04b5aeSRichard Hacker 	while (extsym_start) {
26232d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
26242d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
26252d04b5aeSRichard Hacker 		free(extsym_start);
26262d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
26272d04b5aeSRichard Hacker 	}
26281da177e4SLinus Torvalds 
2629df578e7dSSam Ravnborg 	while (optind < argc)
26301da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
26311da177e4SLinus Torvalds 
2632712f9b46SRusty Russell 	if (files_source)
2633712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2634712f9b46SRusty Russell 
2635c53ddacdSKirill Korotaev 	err = 0;
2636c53ddacdSKirill Korotaev 
2637b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2638d93e1719SMathias Krause 		char fname[PATH_MAX];
2639666ab414SAndi Kleen 
2640b817f6feSSam Ravnborg 		if (mod->skip)
2641b817f6feSSam Ravnborg 			continue;
26421da177e4SLinus Torvalds 
26431da177e4SLinus Torvalds 		buf.pos = 0;
26441da177e4SLinus Torvalds 
26454fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
26463b415288SMasahiro Yamada 		err |= check_exports(mod);
26471d082773SMatthias Maennich 		if (write_namespace_deps)
26481d082773SMatthias Maennich 			continue;
26491d082773SMatthias Maennich 
26501da177e4SLinus Torvalds 		add_header(&buf, mod);
26512449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2652caf7501aSAndi Kleen 		add_retpoline(&buf);
2653a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2654c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
2655d2665ca8SMasahiro Yamada 		add_depends(&buf, mod);
26561da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
26571da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
26581da177e4SLinus Torvalds 
26591da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
26601da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
26611da177e4SLinus Torvalds 	}
26621d082773SMatthias Maennich 
26631d082773SMatthias Maennich 	if (write_namespace_deps) {
26641d082773SMatthias Maennich 		write_namespace_deps_files();
26651d082773SMatthias Maennich 		return 0;
26661d082773SMatthias Maennich 	}
26671d082773SMatthias Maennich 
26681da177e4SLinus Torvalds 	if (dump_write)
26691da177e4SLinus Torvalds 		write_dump(dump_write);
267046c7dd56SMasahiro Yamada 	if (sec_mismatch_count && sec_mismatch_fatal)
267147490ec1SNicolas Boichat 		fatal("modpost: Section mismatches detected.\n"
267247490ec1SNicolas Boichat 		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
267315bfc234SDenis Efremov 	for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
267447346e96SMasahiro Yamada 		struct symbol *s;
267515bfc234SDenis Efremov 
267647346e96SMasahiro Yamada 		for (s = symbolhash[n]; s; s = s->next) {
267747346e96SMasahiro Yamada 			/*
267847346e96SMasahiro Yamada 			 * Do not check "vmlinux". This avoids the same warnings
267947346e96SMasahiro Yamada 			 * shown twice, and false-positives for ARCH=um.
268047346e96SMasahiro Yamada 			 */
268147346e96SMasahiro Yamada 			if (is_vmlinux(s->module->name) && !s->module->is_dot_o)
268247346e96SMasahiro Yamada 				continue;
268347346e96SMasahiro Yamada 
268415bfc234SDenis Efremov 			if (s->is_static)
268515bfc234SDenis Efremov 				warn("\"%s\" [%s] is a static %s\n",
268615bfc234SDenis Efremov 				     s->name, s->module->name,
268715bfc234SDenis Efremov 				     export_str(s->export));
268815bfc234SDenis Efremov 		}
268915bfc234SDenis Efremov 	}
269015bfc234SDenis Efremov 
2691c7d47f26SHeinrich Schuchardt 	free(buf.p);
26921da177e4SLinus Torvalds 
2693c53ddacdSKirill Korotaev 	return err;
26941da177e4SLinus Torvalds }
2695