xref: /linux-6.15/scripts/mod/modpost.c (revision bbc55bde)
11da177e4SLinus Torvalds /* Postprocess module symbol versions
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright 2003       Kai Germaschewski
41da177e4SLinus Torvalds  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5df578e7dSSam Ravnborg  * Copyright 2006-2008  Sam Ravnborg
61da177e4SLinus Torvalds  * Based in part on module-init-tools/depmod.c,file2alias
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds  * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Usage: modpost vmlinux module1.o module2.o ...
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
14b2e3e658SMathieu Desnoyers #define _GNU_SOURCE
15b2e3e658SMathieu Desnoyers #include <stdio.h>
161da177e4SLinus Torvalds #include <ctype.h>
175003bab8SAndrew Morton #include <string.h>
18712f9b46SRusty Russell #include <limits.h>
19d4ef1c30SRusty Russell #include <stdbool.h>
20eed380f3SGuenter Roeck #include <errno.h>
211da177e4SLinus Torvalds #include "modpost.h"
22b817f6feSSam Ravnborg #include "../../include/linux/license.h"
239e1b9b80SAlan Jenkins 
241da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
257a3ee753SMathias Krause static int modversions = 0;
261da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
277a3ee753SMathias Krause static int have_vmlinux = 0;
281da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
291da177e4SLinus Torvalds static int all_versions = 0;
30040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
31040fcc81SSam Ravnborg static int external_module = 0;
328d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
338d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
34c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
35c53ddacdSKirill Korotaev static int warn_unresolved = 0;
36bd5cbcedSRam Pai /* How a symbol is exported */
37588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
3847490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
39eed380f3SGuenter Roeck /* ignore missing files */
40eed380f3SGuenter Roeck static int ignore_missing_files;
41588ccd73SSam Ravnborg 
42c96fca21SSam Ravnborg enum export {
43c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
44c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
45c96fca21SSam Ravnborg };
461da177e4SLinus Torvalds 
474fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h;
484fd3e4efSWanlong Gao  * here we use Elf_Addr instead of long for covering cross-compile
494fd3e4efSWanlong Gao  */
504fd3e4efSWanlong Gao 
514fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
524fd3e4efSWanlong Gao 
536d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
546d9a89eaSAndi Kleen 
556d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds 	va_list arglist;
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	va_start(arglist, fmt);
621da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
631da177e4SLinus Torvalds 	va_end(arglist);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	exit(1);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
686d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	va_list arglist;
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	va_start(arglist, fmt);
751da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
761da177e4SLinus Torvalds 	va_end(arglist);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
796d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
802a116659SMatthew Wilcox {
812a116659SMatthew Wilcox 	va_list arglist;
822a116659SMatthew Wilcox 
832a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
842a116659SMatthew Wilcox 
852a116659SMatthew Wilcox 	va_start(arglist, fmt);
862a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
872a116659SMatthew Wilcox 	va_end(arglist);
882a116659SMatthew Wilcox }
892a116659SMatthew Wilcox 
90d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
91d4ef1c30SRusty Russell {
92d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
93d4ef1c30SRusty Russell 		return false;
94d4ef1c30SRusty Russell 
95d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
96d4ef1c30SRusty Russell }
97d4ef1c30SRusty Russell 
98040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
99040fcc81SSam Ravnborg {
100040fcc81SSam Ravnborg 	const char *myname;
101040fcc81SSam Ravnborg 
102df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
103df578e7dSSam Ravnborg 	if (myname)
104040fcc81SSam Ravnborg 		myname++;
105040fcc81SSam Ravnborg 	else
106040fcc81SSam Ravnborg 		myname = modname;
107040fcc81SSam Ravnborg 
108741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
109741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
110040fcc81SSam Ravnborg }
111040fcc81SSam Ravnborg 
1121da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1131da177e4SLinus Torvalds {
114df578e7dSSam Ravnborg 	if (!ptr)
1151da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
116df578e7dSSam Ravnborg 
1171da177e4SLinus Torvalds 	return ptr;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds /* A list of all modules we processed */
1211da177e4SLinus Torvalds static struct module *modules;
1221da177e4SLinus Torvalds 
1238b185743SMasahiro Yamada static struct module *find_module(const char *modname)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	struct module *mod;
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1281da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1291da177e4SLinus Torvalds 			break;
1301da177e4SLinus Torvalds 	return mod;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
133d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	struct module *mod;
136d4ef1c30SRusty Russell 	char *p;
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1391da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1401da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 	/* strip trailing .o */
143d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
144d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
145258f7426SFrank Rowand 		mod->is_dot_o = 1;
146258f7426SFrank Rowand 	}
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	/* add to list */
1491da177e4SLinus Torvalds 	mod->name = p;
150b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1511da177e4SLinus Torvalds 	mod->next = modules;
1521da177e4SLinus Torvalds 	modules = mod;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	return mod;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /* A hash of all exported symbols,
1581da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds struct symbol {
1631da177e4SLinus Torvalds 	struct symbol *next;
1641da177e4SLinus Torvalds 	struct module *module;
1651da177e4SLinus Torvalds 	unsigned int crc;
1661da177e4SLinus Torvalds 	int crc_valid;
167389eb3f5SMasahiro Yamada 	char *namespace;
1681da177e4SLinus Torvalds 	unsigned int weak:1;
169040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
170040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
171040fcc81SSam Ravnborg 				    *  (only for external modules) **/
172b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
17315bfc234SDenis Efremov 	unsigned int is_static:1;  /* 1 if symbol is not global */
174bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1751da177e4SLinus Torvalds 	char name[0];
1761da177e4SLinus Torvalds };
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1811da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1821da177e4SLinus Torvalds {
1831da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1841da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1871da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1881da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds 
1935c3ead8cSSam Ravnborg /**
1945c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1955c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1965c3ead8cSSam Ravnborg  **/
1975c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
1985c3ead8cSSam Ravnborg 				   struct symbol *next)
1991da177e4SLinus Torvalds {
2001da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
2031da177e4SLinus Torvalds 	strcpy(s->name, name);
2041da177e4SLinus Torvalds 	s->weak = weak;
2051da177e4SLinus Torvalds 	s->next = next;
20615bfc234SDenis Efremov 	s->is_static = 1;
2071da177e4SLinus Torvalds 	return s;
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /* For the hash of exported symbols */
211bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
212bd5cbcedSRam Pai 				 enum export export)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	unsigned int hash;
2151da177e4SLinus Torvalds 	struct symbol *new;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2181da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2191da177e4SLinus Torvalds 	new->module = module;
220bd5cbcedSRam Pai 	new->export = export;
221040fcc81SSam Ravnborg 	return new;
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds 
2245c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	struct symbol *s;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2291da177e4SLinus Torvalds 	if (name[0] == '.')
2301da177e4SLinus Torvalds 		name++;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2331da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2341da177e4SLinus Torvalds 			return s;
2351da177e4SLinus Torvalds 	}
2361da177e4SLinus Torvalds 	return NULL;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds 
239cb9b55d2SMatthias Maennich static bool contains_namespace(struct namespace_list *list,
240cb9b55d2SMatthias Maennich 			       const char *namespace)
241cb9b55d2SMatthias Maennich {
242cb9b55d2SMatthias Maennich 	struct namespace_list *ns_entry;
243cb9b55d2SMatthias Maennich 
244cb9b55d2SMatthias Maennich 	for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next)
245cb9b55d2SMatthias Maennich 		if (strcmp(ns_entry->namespace, namespace) == 0)
246cb9b55d2SMatthias Maennich 			return true;
247cb9b55d2SMatthias Maennich 
248cb9b55d2SMatthias Maennich 	return false;
249cb9b55d2SMatthias Maennich }
250cb9b55d2SMatthias Maennich 
251cb9b55d2SMatthias Maennich static void add_namespace(struct namespace_list **list, const char *namespace)
252cb9b55d2SMatthias Maennich {
253cb9b55d2SMatthias Maennich 	struct namespace_list *ns_entry;
254cb9b55d2SMatthias Maennich 
255cb9b55d2SMatthias Maennich 	if (!contains_namespace(*list, namespace)) {
256cb9b55d2SMatthias Maennich 		ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
257cb9b55d2SMatthias Maennich 					 strlen(namespace) + 1));
258cb9b55d2SMatthias Maennich 		strcpy(ns_entry->namespace, namespace);
259cb9b55d2SMatthias Maennich 		ns_entry->next = *list;
260cb9b55d2SMatthias Maennich 		*list = ns_entry;
261cb9b55d2SMatthias Maennich 	}
262cb9b55d2SMatthias Maennich }
263cb9b55d2SMatthias Maennich 
264cb9b55d2SMatthias Maennich static bool module_imports_namespace(struct module *module,
265cb9b55d2SMatthias Maennich 				     const char *namespace)
266cb9b55d2SMatthias Maennich {
267cb9b55d2SMatthias Maennich 	return contains_namespace(module->imported_namespaces, namespace);
268cb9b55d2SMatthias Maennich }
269cb9b55d2SMatthias Maennich 
2707a3ee753SMathias Krause static const struct {
271bd5cbcedSRam Pai 	const char *str;
272bd5cbcedSRam Pai 	enum export export;
273bd5cbcedSRam Pai } export_list[] = {
274bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
275c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
276bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
277c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
278bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
279bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
280bd5cbcedSRam Pai };
281bd5cbcedSRam Pai 
282bd5cbcedSRam Pai 
283bd5cbcedSRam Pai static const char *export_str(enum export ex)
284bd5cbcedSRam Pai {
285bd5cbcedSRam Pai 	return export_list[ex].str;
286bd5cbcedSRam Pai }
287bd5cbcedSRam Pai 
288bd5cbcedSRam Pai static enum export export_no(const char *s)
289bd5cbcedSRam Pai {
290bd5cbcedSRam Pai 	int i;
291df578e7dSSam Ravnborg 
292534b89a9SSam Ravnborg 	if (!s)
293534b89a9SSam Ravnborg 		return export_unknown;
294bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
295bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
296bd5cbcedSRam Pai 			return export_list[i].export;
297bd5cbcedSRam Pai 	}
298bd5cbcedSRam Pai 	return export_unknown;
299bd5cbcedSRam Pai }
300bd5cbcedSRam Pai 
3016124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
3026124c04cSMasahiro Yamada {
3036124c04cSMasahiro Yamada 	return (void *)elf->hdr +
3046124c04cSMasahiro Yamada 		elf->sechdrs[elf->secindex_strings].sh_offset +
3056124c04cSMasahiro Yamada 		sechdr->sh_name;
3066124c04cSMasahiro Yamada }
3076124c04cSMasahiro Yamada 
3086124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex)
3096124c04cSMasahiro Yamada {
3106124c04cSMasahiro Yamada 	return sech_name(elf, &elf->sechdrs[secindex]);
3116124c04cSMasahiro Yamada }
31262a26356SAlessio Igor Bogani 
31362a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
31462a26356SAlessio Igor Bogani 
31562a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
31662a26356SAlessio Igor Bogani {
31762a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
31862a26356SAlessio Igor Bogani 
31962a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
32062a26356SAlessio Igor Bogani 		return export_plain;
32162a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
32262a26356SAlessio Igor Bogani 		return export_unused;
32362a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
32462a26356SAlessio Igor Bogani 		return export_gpl;
32562a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
32662a26356SAlessio Igor Bogani 		return export_unused_gpl;
32762a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
32862a26356SAlessio Igor Bogani 		return export_gpl_future;
32962a26356SAlessio Igor Bogani 	else
33062a26356SAlessio Igor Bogani 		return export_unknown;
33162a26356SAlessio Igor Bogani }
33262a26356SAlessio Igor Bogani 
3331ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
334bd5cbcedSRam Pai {
335bd5cbcedSRam Pai 	if (sec == elf->export_sec)
336bd5cbcedSRam Pai 		return export_plain;
337c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
338c96fca21SSam Ravnborg 		return export_unused;
339bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
340bd5cbcedSRam Pai 		return export_gpl;
341c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
342c96fca21SSam Ravnborg 		return export_unused_gpl;
343bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
344bd5cbcedSRam Pai 		return export_gpl_future;
345bd5cbcedSRam Pai 	else
346bd5cbcedSRam Pai 		return export_unknown;
347bd5cbcedSRam Pai }
348bd5cbcedSRam Pai 
34969923208SMatthias Maennich static const char *namespace_from_kstrtabns(struct elf_info *info,
35069923208SMatthias Maennich 					    Elf_Sym *kstrtabns)
351cb9b55d2SMatthias Maennich {
35269923208SMatthias Maennich 	char *value = info->ksymtab_strings + kstrtabns->st_value;
35369923208SMatthias Maennich 	return value[0] ? value : NULL;
354cb9b55d2SMatthias Maennich }
355cb9b55d2SMatthias Maennich 
356a2b11184SMatthias Maennich static void sym_update_namespace(const char *symname, const char *namespace)
357a2b11184SMatthias Maennich {
358a2b11184SMatthias Maennich 	struct symbol *s = find_symbol(symname);
359a2b11184SMatthias Maennich 
360a2b11184SMatthias Maennich 	/*
361a2b11184SMatthias Maennich 	 * That symbol should have been created earlier and thus this is
362a2b11184SMatthias Maennich 	 * actually an assertion.
363a2b11184SMatthias Maennich 	 */
364a2b11184SMatthias Maennich 	if (!s) {
365a2b11184SMatthias Maennich 		merror("Could not update namespace(%s) for symbol %s\n",
366a2b11184SMatthias Maennich 		       namespace, symname);
367a2b11184SMatthias Maennich 		return;
368a2b11184SMatthias Maennich 	}
369a2b11184SMatthias Maennich 
370a2b11184SMatthias Maennich 	free(s->namespace);
371a2b11184SMatthias Maennich 	s->namespace =
372a2b11184SMatthias Maennich 		namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
373a2b11184SMatthias Maennich }
374a2b11184SMatthias Maennich 
3755c3ead8cSSam Ravnborg /**
3765c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3775c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3785c3ead8cSSam Ravnborg  **/
3799ae5bd18SMatthias Maennich static struct symbol *sym_add_exported(const char *name, struct module *mod,
3809ae5bd18SMatthias Maennich 				       enum export export)
3811da177e4SLinus Torvalds {
3821da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	if (!s) {
385bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3868e70c458SSam Ravnborg 	} else {
3878e70c458SSam Ravnborg 		if (!s->preloaded) {
388cb9b55d2SMatthias Maennich 			warn("%s: '%s' exported twice. Previous export was in %s%s\n",
389cb9b55d2SMatthias Maennich 			     mod->name, name, s->module->name,
3908e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ? "" : ".ko");
3914b21960fSTrent Piepho 		} else {
392baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3934b21960fSTrent Piepho 			s->module = mod;
3941da177e4SLinus Torvalds 		}
3951da177e4SLinus Torvalds 	}
3968e70c458SSam Ravnborg 	s->preloaded = 0;
397040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
398040fcc81SSam Ravnborg 	s->kernel    = 0;
399bd5cbcedSRam Pai 	s->export    = export;
400040fcc81SSam Ravnborg 	return s;
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
403040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
404bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
405040fcc81SSam Ravnborg {
406040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
407040fcc81SSam Ravnborg 
408b6568b1aSRusty Russell 	if (!s) {
409bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
410b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
411b6568b1aSRusty Russell 		s->preloaded = 1;
412b6568b1aSRusty Russell 	}
413040fcc81SSam Ravnborg 	s->crc = crc;
4141da177e4SLinus Torvalds 	s->crc_valid = 1;
4151da177e4SLinus Torvalds }
4161da177e4SLinus Torvalds 
4175c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
4181da177e4SLinus Torvalds {
4191da177e4SLinus Torvalds 	struct stat st;
420eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
4211da177e4SLinus Torvalds 	int fd;
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
424eb3d5cc6SJesper Juhl 	if (fd < 0)
4251da177e4SLinus Torvalds 		return NULL;
426eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
427eb3d5cc6SJesper Juhl 		goto failed;
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	*size = st.st_size;
4301da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
4311da177e4SLinus Torvalds 
432eb3d5cc6SJesper Juhl failed:
433eb3d5cc6SJesper Juhl 	close(fd);
4341da177e4SLinus Torvalds 	if (map == MAP_FAILED)
4351da177e4SLinus Torvalds 		return NULL;
4361da177e4SLinus Torvalds 	return map;
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds 
4395c3ead8cSSam Ravnborg /**
4405c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
4415c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
4425c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
4435c3ead8cSSam Ravnborg   **/
4445c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
4451da177e4SLinus Torvalds {
4461da177e4SLinus Torvalds 	static char line[4096];
4471da177e4SLinus Torvalds 	int skip = 1;
4481da177e4SLinus Torvalds 	size_t len = 0;
4491da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
4501da177e4SLinus Torvalds 	char *s = line;
4511da177e4SLinus Torvalds 
452df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
4531da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
4541da177e4SLinus Torvalds 			p++;
4551da177e4SLinus Torvalds 			continue;
4561da177e4SLinus Torvalds 		}
4571da177e4SLinus Torvalds 		skip = 0;
4581da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4591da177e4SLinus Torvalds 			len++;
4601da177e4SLinus Torvalds 			*s++ = *p++;
4611da177e4SLinus Torvalds 			if (len > 4095)
4621da177e4SLinus Torvalds 				break; /* Too long, stop */
4631da177e4SLinus Torvalds 		} else {
4641da177e4SLinus Torvalds 			/* End of string */
4651da177e4SLinus Torvalds 			*s = '\0';
4661da177e4SLinus Torvalds 			return line;
4671da177e4SLinus Torvalds 		}
4681da177e4SLinus Torvalds 	}
4691da177e4SLinus Torvalds 	/* End of buffer */
4701da177e4SLinus Torvalds 	return NULL;
4711da177e4SLinus Torvalds }
4721da177e4SLinus Torvalds 
4735c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4741da177e4SLinus Torvalds {
4751da177e4SLinus Torvalds 	munmap(file, size);
4761da177e4SLinus Torvalds }
4771da177e4SLinus Torvalds 
47885bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4791da177e4SLinus Torvalds {
4801da177e4SLinus Torvalds 	unsigned int i;
48185bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4821da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4831da177e4SLinus Torvalds 	Elf_Sym  *sym;
4841ce53adfSDenys Vlasenko 	const char *secstrings;
4851ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4881da177e4SLinus Torvalds 	if (!hdr) {
489eed380f3SGuenter Roeck 		if (ignore_missing_files) {
490eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
491eed380f3SGuenter Roeck 				strerror(errno));
492eed380f3SGuenter Roeck 			return 0;
493eed380f3SGuenter Roeck 		}
4941da177e4SLinus Torvalds 		perror(filename);
4956803dc0eSSam Ravnborg 		exit(1);
4961da177e4SLinus Torvalds 	}
4971da177e4SLinus Torvalds 	info->hdr = hdr;
49885bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
49985bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
50085bd2fddSSam Ravnborg 		return 0;
50185bd2fddSSam Ravnborg 	}
50285bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
50385bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
50485bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
50585bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
50685bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
50785bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
50885bd2fddSSam Ravnborg 		return 0;
50985bd2fddSSam Ravnborg 	}
5101da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
511ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
5127d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
5137d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
5147d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
5157d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
5167d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
5177d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
5187d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
5197d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
5207d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
5217d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
5227d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
5237d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
5241da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
5251da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
5261da177e4SLinus Torvalds 
527a83710e5SPetr Stetiar 	/* Check if file offset is correct */
528a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
529df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
530df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
531df578e7dSSam Ravnborg 		      filename, info->size);
532a83710e5SPetr Stetiar 		return 0;
533a83710e5SPetr Stetiar 	}
534a83710e5SPetr Stetiar 
5356845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
5361ce53adfSDenys Vlasenko 		/*
5371ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
5381ce53adfSDenys Vlasenko 		 * read count from .sh_size.
5391ce53adfSDenys Vlasenko 		 */
5401ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
5411ce53adfSDenys Vlasenko 	}
5421ce53adfSDenys Vlasenko 	else {
5431ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
5441ce53adfSDenys Vlasenko 	}
5451ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
5466845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
5471ce53adfSDenys Vlasenko 	}
5481ce53adfSDenys Vlasenko 	else {
5491ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
5501ce53adfSDenys Vlasenko 	}
5511ce53adfSDenys Vlasenko 
5521da177e4SLinus Torvalds 	/* Fix endianness in section headers */
5531ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
5547d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
5551da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
5567d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
5577d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5581da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5591da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5601da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
561ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5627d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5637d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5641da177e4SLinus Torvalds 	}
5651da177e4SLinus Torvalds 	/* Find symbol table. */
5661ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5671ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
568bd5cbcedSRam Pai 		const char *secname;
56956fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5701da177e4SLinus Torvalds 
57156fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
572df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
573df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
574df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
575df578e7dSSam Ravnborg 			      sizeof(*hdr));
57685bd2fddSSam Ravnborg 			return 0;
57785bd2fddSSam Ravnborg 		}
578bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
579bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
58056fc82c5STejun Heo 			if (nobits)
58156fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5821da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5831da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
584bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
585bd5cbcedSRam Pai 			info->export_sec = i;
586c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
587c96fca21SSam Ravnborg 			info->export_unused_sec = i;
588bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
589bd5cbcedSRam Pai 			info->export_gpl_sec = i;
590c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
591c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
592bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
593bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
59469923208SMatthias Maennich 		else if (strcmp(secname, "__ksymtab_strings") == 0)
59569923208SMatthias Maennich 			info->ksymtab_strings = (void *)hdr +
59669923208SMatthias Maennich 						sechdrs[i].sh_offset -
59769923208SMatthias Maennich 						sechdrs[i].sh_addr;
598bd5cbcedSRam Pai 
5991ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
6001ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
6011ce53adfSDenys Vlasenko 			symtab_idx = i;
6021ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
6031ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
6041ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
6051ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6066845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
6071da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
6081ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
6091ce53adfSDenys Vlasenko 		}
6101ce53adfSDenys Vlasenko 
6111ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
6121ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
6131ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
6141ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
6151ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
6161ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
6171ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6181ce53adfSDenys Vlasenko 		}
6191da177e4SLinus Torvalds 	}
620df578e7dSSam Ravnborg 	if (!info->symtab_start)
621cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
622df578e7dSSam Ravnborg 
6231da177e4SLinus Torvalds 	/* Fix endianness in symbols */
6241da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
6251da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
6261da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
6271da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
6281da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
6291da177e4SLinus Torvalds 	}
6301ce53adfSDenys Vlasenko 
6311ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
6321ce53adfSDenys Vlasenko 		Elf32_Word *p;
6336845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
6341ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
6356845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
6361ce53adfSDenys Vlasenko 			      symtab_idx);
6371ce53adfSDenys Vlasenko 		/* Fix endianness */
6381ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
6391ce53adfSDenys Vlasenko 		     p++)
6401ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
6411ce53adfSDenys Vlasenko 	}
6421ce53adfSDenys Vlasenko 
64385bd2fddSSam Ravnborg 	return 1;
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds 
6465c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
6471da177e4SLinus Torvalds {
6481da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
6491da177e4SLinus Torvalds }
6501da177e4SLinus Torvalds 
6514d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
6524d7365d6SSam Ravnborg {
6534d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
654b2c5cdcfSMasahiro Yamada 	if (strcmp(symname, "__this_module") == 0)
6554d7365d6SSam Ravnborg 		return 1;
6564d7365d6SSam Ravnborg 	/* ignore global offset table */
6574d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
6584d7365d6SSam Ravnborg 		return 1;
6594d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
6604d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
661d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr_") ||
662d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr_") ||
663d62c4765SMasahiro Yamada 		    strstarts(symname, "_rest32gpr_") ||
664d62c4765SMasahiro Yamada 		    strstarts(symname, "_save32gpr_") ||
665d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
666d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_"))
6674d7365d6SSam Ravnborg 			return 1;
6687fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6697fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
670d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr0_") ||
671d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr0_") ||
672d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
673d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_") ||
674c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6757fca5dc8SStephen Rothwell 			return 1;
6764d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6774d7365d6SSam Ravnborg 	return 0;
6784d7365d6SSam Ravnborg }
6794d7365d6SSam Ravnborg 
6805c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6811da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6821da177e4SLinus Torvalds {
6831da177e4SLinus Torvalds 	unsigned int crc;
68462a26356SAlessio Igor Bogani 	enum export export;
685d8c1eb86SNicholas Piggin 	bool is_crc = false;
686389eb3f5SMasahiro Yamada 	const char *name;
68762a26356SAlessio Igor Bogani 
688258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
689d62c4765SMasahiro Yamada 	    strstarts(symname, "__ksymtab"))
69062a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
69162a26356SAlessio Igor Bogani 	else
69262a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	/* CRC'd symbol */
695d62c4765SMasahiro Yamada 	if (strstarts(symname, "__crc_")) {
696d8c1eb86SNicholas Piggin 		is_crc = true;
6971da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
69856067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
69956067812SArd Biesheuvel 			unsigned int *crcp;
70056067812SArd Biesheuvel 
70156067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
70256067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
70356067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
70456067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
70556067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
70654a7151bSFredrik Noring 			crc = TO_NATIVE(*crcp);
70756067812SArd Biesheuvel 		}
708b2c5cdcfSMasahiro Yamada 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
709bd5cbcedSRam Pai 				export);
7101da177e4SLinus Torvalds 	}
711b5064654SAndi Kleen 
712b5064654SAndi Kleen 	switch (sym->st_shndx) {
713b5064654SAndi Kleen 	case SHN_COMMON:
714d62c4765SMasahiro Yamada 		if (strstarts(symname, "__gnu_lto_")) {
715ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
716ef178f92SAndi Kleen 		} else
717b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
7181da177e4SLinus Torvalds 		break;
7191da177e4SLinus Torvalds 	case SHN_UNDEF:
7201da177e4SLinus Torvalds 		/* undefined symbol */
7211da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
7221da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
7231da177e4SLinus Torvalds 			break;
7244d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
7251da177e4SLinus Torvalds 			break;
7268d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
7278d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
7288d529014SBen Colline /* add compatibility with older glibc */
7298d529014SBen Colline #ifndef STT_SPARC_REGISTER
7308d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
7318d529014SBen Colline #endif
7321da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
7331da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
7341da177e4SLinus Torvalds 			/* Ignore register directives. */
7358d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
7361da177e4SLinus Torvalds 				break;
7377caaeabbSAl Viro 			if (symname[0] == '.') {
7381f3aa900SRandy Dunlap 				char *munged = NOFAIL(strdup(symname));
7397caaeabbSAl Viro 				munged[0] = '_';
7407caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
7417caaeabbSAl Viro 				symname = munged;
7427caaeabbSAl Viro 			}
7431da177e4SLinus Torvalds 		}
7441da177e4SLinus Torvalds #endif
7451da177e4SLinus Torvalds 
746d8c1eb86SNicholas Piggin 		if (is_crc) {
747d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
748b2c5cdcfSMasahiro Yamada 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
749b2c5cdcfSMasahiro Yamada 			     symname + strlen("__crc_"), mod->name, e);
750d8c1eb86SNicholas Piggin 		}
751b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
7521da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
7531da177e4SLinus Torvalds 					  mod->unres);
7541da177e4SLinus Torvalds 		break;
7551da177e4SLinus Torvalds 	default:
7561da177e4SLinus Torvalds 		/* All exported symbols */
757d62c4765SMasahiro Yamada 		if (strstarts(symname, "__ksymtab_")) {
758cb9b55d2SMatthias Maennich 			name = symname + strlen("__ksymtab_");
7599ae5bd18SMatthias Maennich 			sym_add_exported(name, mod, export);
7601da177e4SLinus Torvalds 		}
761b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "init_module") == 0)
7621da177e4SLinus Torvalds 			mod->has_init = 1;
763b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "cleanup_module") == 0)
7641da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7651da177e4SLinus Torvalds 		break;
7661da177e4SLinus Torvalds 	}
7671da177e4SLinus Torvalds }
7681da177e4SLinus Torvalds 
7695c3ead8cSSam Ravnborg /**
7705c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7715c3ead8cSSam Ravnborg  **/
7721da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7731da177e4SLinus Torvalds {
7741da177e4SLinus Torvalds 	/* Skip non-zero chars */
7751da177e4SLinus Torvalds 	while (string[0]) {
7761da177e4SLinus Torvalds 		string++;
7771da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7781da177e4SLinus Torvalds 			return NULL;
7791da177e4SLinus Torvalds 	}
7801da177e4SLinus Torvalds 
7811da177e4SLinus Torvalds 	/* Skip any zero padding. */
7821da177e4SLinus Torvalds 	while (!string[0]) {
7831da177e4SLinus Torvalds 		string++;
7841da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7851da177e4SLinus Torvalds 			return NULL;
7861da177e4SLinus Torvalds 	}
7871da177e4SLinus Torvalds 	return string;
7881da177e4SLinus Torvalds }
7891da177e4SLinus Torvalds 
790bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag,
791bca2cceeSMasahiro Yamada 			      char *prev)
7921da177e4SLinus Torvalds {
7931da177e4SLinus Torvalds 	char *p;
7941da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
795bca2cceeSMasahiro Yamada 	char *modinfo = info->modinfo;
796bca2cceeSMasahiro Yamada 	unsigned long size = info->modinfo_len;
7971da177e4SLinus Torvalds 
798bca2cceeSMasahiro Yamada 	if (prev) {
799bca2cceeSMasahiro Yamada 		size -= prev - modinfo;
800bca2cceeSMasahiro Yamada 		modinfo = next_string(prev, &size);
801b817f6feSSam Ravnborg 	}
802b817f6feSSam Ravnborg 
8031da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
8041da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
8051da177e4SLinus Torvalds 			return p + taglen + 1;
8061da177e4SLinus Torvalds 	}
8071da177e4SLinus Torvalds 	return NULL;
8081da177e4SLinus Torvalds }
8091da177e4SLinus Torvalds 
810bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag)
811b817f6feSSam Ravnborg 
812b817f6feSSam Ravnborg {
813bca2cceeSMasahiro Yamada 	return get_next_modinfo(info, tag, NULL);
814b817f6feSSam Ravnborg }
815b817f6feSSam Ravnborg 
81693684d3bSSam Ravnborg /**
8174c8fbca5SSam Ravnborg  * Test if string s ends in string sub
8184c8fbca5SSam Ravnborg  * return 0 if match
8194c8fbca5SSam Ravnborg  **/
8204c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
8214c8fbca5SSam Ravnborg {
8224c8fbca5SSam Ravnborg 	int slen, sublen;
8234c8fbca5SSam Ravnborg 
8244c8fbca5SSam Ravnborg 	if (!s || !sub)
8254c8fbca5SSam Ravnborg 		return 1;
8264c8fbca5SSam Ravnborg 
8274c8fbca5SSam Ravnborg 	slen = strlen(s);
8284c8fbca5SSam Ravnborg 	sublen = strlen(sub);
8294c8fbca5SSam Ravnborg 
8304c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
8314c8fbca5SSam Ravnborg 		return 1;
8324c8fbca5SSam Ravnborg 
8334c8fbca5SSam Ravnborg 	if (sublen > slen)
8344c8fbca5SSam Ravnborg 		return 1;
8354c8fbca5SSam Ravnborg 
8364c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
8374c8fbca5SSam Ravnborg }
8384c8fbca5SSam Ravnborg 
839ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
840ff13f926SSam Ravnborg {
84158fb0d4fSSam Ravnborg 	if (sym)
842ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
84358fb0d4fSSam Ravnborg 	else
844f666751aSSam Ravnborg 		return "(unknown)";
845ff13f926SSam Ravnborg }
846ff13f926SSam Ravnborg 
84710668220SSam Ravnborg /* The pattern is an array of simple patterns.
84810668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
8496c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
85010668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
85109c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
85210668220SSam Ravnborg  */
8535c725138STrevor Keith static int match(const char *sym, const char * const pat[])
85410668220SSam Ravnborg {
85510668220SSam Ravnborg 	const char *p;
85610668220SSam Ravnborg 	while (*pat) {
85710668220SSam Ravnborg 		p = *pat++;
85810668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
85910668220SSam Ravnborg 
86009c20c03SPaul Gortmaker 		/* "*foo*" */
86109c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
8626f02bdfcSDenis Efremov 			char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
8636f02bdfcSDenis Efremov 			char *here = strstr(sym, bare);
86409c20c03SPaul Gortmaker 
86509c20c03SPaul Gortmaker 			free(bare);
86609c20c03SPaul Gortmaker 			if (here != NULL)
86709c20c03SPaul Gortmaker 				return 1;
86809c20c03SPaul Gortmaker 		}
8696c5bd235SSam Ravnborg 		/* "*foo" */
87009c20c03SPaul Gortmaker 		else if (*p == '*') {
8716c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8726c5bd235SSam Ravnborg 				return 1;
8736c5bd235SSam Ravnborg 		}
87410668220SSam Ravnborg 		/* "foo*" */
8756c5bd235SSam Ravnborg 		else if (*endp == '*') {
87610668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
87710668220SSam Ravnborg 				return 1;
87810668220SSam Ravnborg 		}
87910668220SSam Ravnborg 		/* no wildcards */
88010668220SSam Ravnborg 		else {
88110668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
88210668220SSam Ravnborg 				return 1;
88310668220SSam Ravnborg 		}
88410668220SSam Ravnborg 	}
88510668220SSam Ravnborg 	/* no match */
88610668220SSam Ravnborg 	return 0;
88710668220SSam Ravnborg }
88810668220SSam Ravnborg 
88910668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8907a3ee753SMathias Krause static const char *const section_white_list[] =
8914391ed6aSSam Ravnborg {
8924391ed6aSSam Ravnborg 	".comment*",
8934391ed6aSSam Ravnborg 	".debug*",
8944d10c223SChen Gang 	".cranges",		/* sh64 */
8951121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
896739d875dSDavid Howells 	".GCC.command.line",	/* record-gcc-switches */
8974391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
8984391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
8994391ed6aSSam Ravnborg 	".stab*",
9004391ed6aSSam Ravnborg 	".note*",
9014391ed6aSSam Ravnborg 	".got*",
9024391ed6aSSam Ravnborg 	".toc*",
903af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
904af42e970SMax Filippov 	".xt.lit",         /* xtensa */
905f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
906f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
907d1189c63SNoam Camus 	".cmem*",			/* EZchip */
908d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
909ef178f92SAndi Kleen 	".gnu.lto*",
910e390f9a9SJosh Poimboeuf 	".discard.*",
9114391ed6aSSam Ravnborg 	NULL
9124391ed6aSSam Ravnborg };
91310668220SSam Ravnborg 
914e241a630SSam Ravnborg /*
915b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
916e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
917b614a697SAnders Kaseorg  * without "ax" / "aw".
918e241a630SSam Ravnborg  */
919b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
920b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
921e241a630SSam Ravnborg {
922b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
923e241a630SSam Ravnborg 
924b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
925b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
926b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
927b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
928b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
929e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
930e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
931e241a630SSam Ravnborg 		     modname, sec);
932e241a630SSam Ravnborg 	}
933e241a630SSam Ravnborg }
934e241a630SSam Ravnborg 
935e241a630SSam Ravnborg 
936e241a630SSam Ravnborg 
937eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
938a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
939a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
940eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
941a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
94210668220SSam Ravnborg 
943eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
944a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
945eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
946a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
94710668220SSam Ravnborg 
948bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
949a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
950a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
951a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
952bb15d8dbSSebastian Andrzej Siewior 
953e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
954e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
9554a31a229SUwe Kleine-König 
9564a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
9574a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
95810668220SSam Ravnborg 
959a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
960157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
9616727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
96252dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
963673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
964673c2c34SChris Metcalf 		".coldtext"
96510668220SSam Ravnborg 
966fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
967fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
968eb8f6890SSam Ravnborg 
969fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
970fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
971eb8f6890SSam Ravnborg 
97252dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
97352dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
97452dc0595SQuentin Casasnovas 
9756c5bd235SSam Ravnborg /* init data sections */
9767a3ee753SMathias Krause static const char *const init_data_sections[] =
9777a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9786c5bd235SSam Ravnborg 
9796c5bd235SSam Ravnborg /* all init sections */
9807a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9816c5bd235SSam Ravnborg 
9826c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9837a3ee753SMathias Krause static const char *const init_exit_sections[] =
984eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9856c5bd235SSam Ravnborg 
9864a3893d0SPaul Gortmaker /* all text sections */
9874a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9884a3893d0SPaul Gortmaker 
9896c5bd235SSam Ravnborg /* data section */
9907a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9916c5bd235SSam Ravnborg 
9926c5bd235SSam Ravnborg 
9936c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
994af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
995af92a82dSUwe Kleine-König 	"*driver",							\
996af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
997af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
998af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
999af92a82dSUwe Kleine-König 	"*_ops",							\
1000af92a82dSUwe Kleine-König 	"*_probe",							\
1001af92a82dSUwe Kleine-König 	"*_probe_one",							\
1002af92a82dSUwe Kleine-König 	"*_console"
10036c5bd235SSam Ravnborg 
10047a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
10057a3ee753SMathias Krause static const char *const linker_symbols[] =
10066c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
10074a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
10086c5bd235SSam Ravnborg 
1009588ccd73SSam Ravnborg enum mismatch {
1010bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
1011bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
1012bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
1013bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
1014bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
1015bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
1016bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
1017bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
1018588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
101952dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
1020588ccd73SSam Ravnborg };
1021588ccd73SSam Ravnborg 
1022e5d8f59aSQuentin Casasnovas /**
1023e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
1024e5d8f59aSQuentin Casasnovas  *
1025e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
1026e5d8f59aSQuentin Casasnovas  *
1027e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
1028e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
1029e5d8f59aSQuentin Casasnovas  *
1030e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
1031e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
1032e5d8f59aSQuentin Casasnovas  *
1033e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
1034e5d8f59aSQuentin Casasnovas  *
1035e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
1036e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
1037e5d8f59aSQuentin Casasnovas  *
1038e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
1039e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
1040e5d8f59aSQuentin Casasnovas  *
1041e5d8f59aSQuentin Casasnovas  */
104210668220SSam Ravnborg struct sectioncheck {
104310668220SSam Ravnborg 	const char *fromsec[20];
1044050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
1045050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
1046588ccd73SSam Ravnborg 	enum mismatch mismatch;
1047af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
1048644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
1049644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
1050644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
1051644e8f14SQuentin Casasnovas 
105210668220SSam Ravnborg };
105310668220SSam Ravnborg 
105452dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
105552dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
105652dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
105752dc0595SQuentin Casasnovas 				     const char *fromsec);
105852dc0595SQuentin Casasnovas 
10597a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
106010668220SSam Ravnborg /* Do not reference init/exit code/data from
106110668220SSam Ravnborg  * normal code and data
106210668220SSam Ravnborg  */
106310668220SSam Ravnborg {
1064588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1065050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1066bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1067af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1068588ccd73SSam Ravnborg },
1069588ccd73SSam Ravnborg {
1070588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1071050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1072bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1073af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1074588ccd73SSam Ravnborg },
1075588ccd73SSam Ravnborg {
10760db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1077050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10780db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10790db25245SUwe Kleine-König 	.symbol_white_list = {
10800db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10810db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10820db25245SUwe Kleine-König 	},
10830db25245SUwe Kleine-König },
10840db25245SUwe Kleine-König {
1085588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1086050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1087bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1088af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1089588ccd73SSam Ravnborg },
1090588ccd73SSam Ravnborg {
1091588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1092050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1093bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1094af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1095eb8f6890SSam Ravnborg },
1096e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1097eb8f6890SSam Ravnborg {
10984a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1099050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1100bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1101af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1102eb8f6890SSam Ravnborg },
1103e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1104eb8f6890SSam Ravnborg {
11054a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1106050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1107bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1108af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
110910668220SSam Ravnborg },
111010668220SSam Ravnborg /* Do not use exit code/data from init code */
111110668220SSam Ravnborg {
1112eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1113050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1114bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1115af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
111610668220SSam Ravnborg },
111710668220SSam Ravnborg /* Do not use init code/data from exit code */
111810668220SSam Ravnborg {
1119eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1120050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1121bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1122af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
112310668220SSam Ravnborg },
1124bb15d8dbSSebastian Andrzej Siewior {
1125bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1126050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1127bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1128bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1129bb15d8dbSSebastian Andrzej Siewior },
113010668220SSam Ravnborg /* Do not export init/exit functions or data */
113110668220SSam Ravnborg {
113210668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1133050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1134af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1135af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
113652dc0595SQuentin Casasnovas },
113752dc0595SQuentin Casasnovas {
113852dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
113952dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
114052dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
114152dc0595SQuentin Casasnovas 	 */
114252dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
114352dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
114452dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
114552dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
114610668220SSam Ravnborg }
114710668220SSam Ravnborg };
114810668220SSam Ravnborg 
11490d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
11500d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
115110668220SSam Ravnborg {
115210668220SSam Ravnborg 	int i;
115310668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
115410668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
115510668220SSam Ravnborg 
1156c5c3439aSQuentin Casasnovas 	/*
1157c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1158c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1159739d875dSDavid Howells 	 * doesn't make much sense and causes build failures on parisc
1160739d875dSDavid Howells 	 * architectures.
1161c5c3439aSQuentin Casasnovas 	 */
1162c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1163c5c3439aSQuentin Casasnovas 		return NULL;
1164c5c3439aSQuentin Casasnovas 
116510668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1166050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1167050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11680d2a636eSUwe Kleine-König 				return check;
1169050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1170050e57fdSQuentin Casasnovas 				return check;
1171050e57fdSQuentin Casasnovas 		}
117210668220SSam Ravnborg 		check++;
117310668220SSam Ravnborg 	}
11740d2a636eSUwe Kleine-König 	return NULL;
117510668220SSam Ravnborg }
117610668220SSam Ravnborg 
11774c8fbca5SSam Ravnborg /**
11784c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11790e0d314eSSam Ravnborg  *
11804c8fbca5SSam Ravnborg  * Pattern 1:
11814c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11824c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11834c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11844c8fbca5SSam Ravnborg  *   this pattern.
11854c8fbca5SSam Ravnborg  *   The pattern is identified by:
11864c8fbca5SSam Ravnborg  *   tosec   = .init.data
11879209aed0SSam Ravnborg  *   fromsec = .data*
11884c8fbca5SSam Ravnborg  *   atsym   =__param*
11894c8fbca5SSam Ravnborg  *
11906a841528SRusty Russell  * Pattern 1a:
11916a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11926a841528SRusty Russell  *   The pattern is identified by:
11936a841528SRusty Russell  *   tosec   = .init.text
11946a841528SRusty Russell  *   fromsec = .data*
11956a841528SRusty Russell  *   atsym   = __param_ops_*
11966a841528SRusty Russell  *
11974c8fbca5SSam Ravnborg  * Pattern 2:
119872ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
11994c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
12004c8fbca5SSam Ravnborg  *   the pattern is identified by:
120183cda2bbSSam Ravnborg  *   tosec   = init or exit section
120283cda2bbSSam Ravnborg  *   fromsec = data section
1203df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1204df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1205ee6a8545SVivek Goyal  *
1206ee6a8545SVivek Goyal  * Pattern 3:
1207c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
12089bf8cb9bSSam Ravnborg  *
12091d8af559SSam Ravnborg  * Pattern 4:
1210ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1211ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1212ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1213ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1214ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1215ee6a8545SVivek Goyal  *   This pattern is identified by
1216ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
12179bf8cb9bSSam Ravnborg  *
12184a3893d0SPaul Gortmaker  * Pattern 5:
12194a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
12204a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
12214a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
12224a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
12234a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
12244a3893d0SPaul Gortmaker  *   This pattern is identified by
12254a3893d0SPaul Gortmaker  *   tosec   = init section
12264a3893d0SPaul Gortmaker  *   fromsec = text section
12274a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
12284a3893d0SPaul Gortmaker  *
1229a4d26f1aSPaul Walmsley  * Pattern 6:
1230a4d26f1aSPaul Walmsley  *   Hide section mismatch warnings for ELF local symbols.  The goal
1231a4d26f1aSPaul Walmsley  *   is to eliminate false positive modpost warnings caused by
1232a4d26f1aSPaul Walmsley  *   compiler-generated ELF local symbol names such as ".LANCHOR1".
1233a4d26f1aSPaul Walmsley  *   Autogenerated symbol names bypass modpost's "Pattern 2"
1234a4d26f1aSPaul Walmsley  *   whitelisting, which relies on pattern-matching against symbol
1235a4d26f1aSPaul Walmsley  *   names to work.  (One situation where gcc can autogenerate ELF
1236a4d26f1aSPaul Walmsley  *   local symbols is when "-fsection-anchors" is used.)
12374c8fbca5SSam Ravnborg  **/
1238af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1239af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
124058fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
12414c8fbca5SSam Ravnborg {
12424c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
12436c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
12446c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1245d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param"))
124658fb0d4fSSam Ravnborg 		return 0;
12474c8fbca5SSam Ravnborg 
12486a841528SRusty Russell 	/* Check for pattern 1a */
12496a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
12506a841528SRusty Russell 	    match(fromsec, data_sections) &&
1251d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param_ops_"))
12526a841528SRusty Russell 		return 0;
12536a841528SRusty Russell 
12544c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
12556c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
12566c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1257af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
125858fb0d4fSSam Ravnborg 		return 0;
12594c8fbca5SSam Ravnborg 
12609bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
12616c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
12626c5bd235SSam Ravnborg 	    match(tosec, init_sections))
126358fb0d4fSSam Ravnborg 		return 0;
1264f8657e1bSVivek Goyal 
12651d8af559SSam Ravnborg 	/* Check for pattern 4 */
126658fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
126793659af1SSam Ravnborg 		return 0;
126858fb0d4fSSam Ravnborg 
12694a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12704a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12714a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12724a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12734a3893d0SPaul Gortmaker 		return 0;
12744a3893d0SPaul Gortmaker 
1275a4d26f1aSPaul Walmsley 	/* Check for pattern 6 */
1276a4d26f1aSPaul Walmsley 	if (strstarts(fromsym, ".L"))
1277a4d26f1aSPaul Walmsley 		return 0;
1278a4d26f1aSPaul Walmsley 
127958fb0d4fSSam Ravnborg 	return 1;
12804c8fbca5SSam Ravnborg }
12814c8fbca5SSam Ravnborg 
12825818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str)
12835818c683SSami Tolvanen {
12845818c683SSami Tolvanen 	return str[0] == '$' && strchr("axtd", str[1])
12855818c683SSami Tolvanen 	       && (str[2] == '\0' || str[2] == '.');
12865818c683SSami Tolvanen }
12875818c683SSami Tolvanen 
12885818c683SSami Tolvanen /*
12895818c683SSami Tolvanen  * If there's no name there, ignore it; likewise, ignore it if it's
12905818c683SSami Tolvanen  * one of the magic symbols emitted used by current ARM tools.
12915818c683SSami Tolvanen  *
12925818c683SSami Tolvanen  * Otherwise if find_symbols_between() returns those symbols, they'll
12935818c683SSami Tolvanen  * fail the whitelist tests and cause lots of false alarms ... fixable
12945818c683SSami Tolvanen  * only by merging __exit and __init sections into __text, bloating
12955818c683SSami Tolvanen  * the kernel (which is especially evil on embedded platforms).
12965818c683SSami Tolvanen  */
12975818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
12985818c683SSami Tolvanen {
12995818c683SSami Tolvanen 	const char *name = elf->strtab + sym->st_name;
13005818c683SSami Tolvanen 
13015818c683SSami Tolvanen 	if (!name || !strlen(name))
13025818c683SSami Tolvanen 		return 0;
13035818c683SSami Tolvanen 	return !is_arm_mapping_symbol(name);
13045818c683SSami Tolvanen }
13055818c683SSami Tolvanen 
13064c8fbca5SSam Ravnborg /**
130793684d3bSSam Ravnborg  * Find symbol based on relocation record info.
130893684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
130993684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
131093684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
131193684d3bSSam Ravnborg  * based on section and address.
131293684d3bSSam Ravnborg  *  **/
13139ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
131493684d3bSSam Ravnborg 				Elf_Sym *relsym)
131593684d3bSSam Ravnborg {
131693684d3bSSam Ravnborg 	Elf_Sym *sym;
13179ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
13189ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
13199ad21c3fSSam Ravnborg 	Elf64_Sword d;
13201ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
132193684d3bSSam Ravnborg 
132293684d3bSSam Ravnborg 	if (relsym->st_name != 0)
132393684d3bSSam Ravnborg 		return relsym;
13241ce53adfSDenys Vlasenko 
13251ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
132693684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
13271ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
132893684d3bSSam Ravnborg 			continue;
1329ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1330ae4ac123SAtsushi Nemoto 			continue;
13315818c683SSami Tolvanen 		if (!is_valid_name(elf, sym))
13325818c683SSami Tolvanen 			continue;
133393684d3bSSam Ravnborg 		if (sym->st_value == addr)
133493684d3bSSam Ravnborg 			return sym;
13359ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
13369ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
13379ad21c3fSSam Ravnborg 		if (d < 0)
13389ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
13399ad21c3fSSam Ravnborg 		if (d < distance) {
13409ad21c3fSSam Ravnborg 			distance = d;
13419ad21c3fSSam Ravnborg 			near = sym;
134293684d3bSSam Ravnborg 		}
13439ad21c3fSSam Ravnborg 	}
13449ad21c3fSSam Ravnborg 	/* We need a close match */
13459ad21c3fSSam Ravnborg 	if (distance < 20)
13469ad21c3fSSam Ravnborg 		return near;
13479ad21c3fSSam Ravnborg 	else
134893684d3bSSam Ravnborg 		return NULL;
134993684d3bSSam Ravnborg }
135093684d3bSSam Ravnborg 
1351b39927cfSSam Ravnborg /*
135243c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
135343c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
135443c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
135543c74d17SSam Ravnborg  * it is, but this works for now.
1356b39927cfSSam Ravnborg  **/
1357157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1358157c23c8SSam Ravnborg 				 const char *sec)
1359b39927cfSSam Ravnborg {
1360b39927cfSSam Ravnborg 	Elf_Sym *sym;
1361157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1362157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1363b39927cfSSam Ravnborg 
1364b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1365b39927cfSSam Ravnborg 		const char *symsec;
1366b39927cfSSam Ravnborg 
13671ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1368b39927cfSSam Ravnborg 			continue;
13691ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1370b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1371b39927cfSSam Ravnborg 			continue;
1372da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1373da68d61fSDavid Brownell 			continue;
1374b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1375157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1376157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1377157c23c8SSam Ravnborg 				near = sym;
1378157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1379157c23c8SSam Ravnborg 				near = sym;
138043c74d17SSam Ravnborg 			}
1381b39927cfSSam Ravnborg 		}
1382b39927cfSSam Ravnborg 	}
1383157c23c8SSam Ravnborg 	return near;
1384157c23c8SSam Ravnborg }
1385b39927cfSSam Ravnborg 
138658fb0d4fSSam Ravnborg /*
1387588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1388588ccd73SSam Ravnborg  * .init.text => __init
1389588ccd73SSam Ravnborg  * .memexitconst => __memconst
1390588ccd73SSam Ravnborg  * etc.
1391cbcf14a9SAndy Shevchenko  *
1392cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1393cbcf14a9SAndy Shevchenko  * method should free it after usage.
1394588ccd73SSam Ravnborg */
1395588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1396588ccd73SSam Ravnborg {
1397588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
13981f3aa900SRandy Dunlap 		char *p = NOFAIL(malloc(20));
1399588ccd73SSam Ravnborg 		char *r = p;
1400588ccd73SSam Ravnborg 
1401588ccd73SSam Ravnborg 		*p++ = '_';
1402588ccd73SSam Ravnborg 		*p++ = '_';
1403588ccd73SSam Ravnborg 		if (*s == '.')
1404588ccd73SSam Ravnborg 			s++;
1405588ccd73SSam Ravnborg 		while (*s && *s != '.')
1406588ccd73SSam Ravnborg 			*p++ = *s++;
1407588ccd73SSam Ravnborg 		*p = '\0';
1408588ccd73SSam Ravnborg 		if (*s == '.')
1409588ccd73SSam Ravnborg 			s++;
1410588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1411588ccd73SSam Ravnborg 			strcat(p, "const ");
1412588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1413588ccd73SSam Ravnborg 			strcat(p, "data ");
1414588ccd73SSam Ravnborg 		else
1415588ccd73SSam Ravnborg 			strcat(p, " ");
1416cbcf14a9SAndy Shevchenko 		return r;
1417588ccd73SSam Ravnborg 	} else {
14181f3aa900SRandy Dunlap 		return NOFAIL(strdup(""));
1419588ccd73SSam Ravnborg 	}
1420588ccd73SSam Ravnborg }
1421588ccd73SSam Ravnborg 
1422588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1423588ccd73SSam Ravnborg {
1424588ccd73SSam Ravnborg 	if (sym)
1425588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1426588ccd73SSam Ravnborg 	else
1427f666751aSSam Ravnborg 		return -1;
1428588ccd73SSam Ravnborg }
1429588ccd73SSam Ravnborg 
143000759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
143100759c0eSRandy Dunlap {
143200759c0eSRandy Dunlap 	const char *const *s = list;
143300759c0eSRandy Dunlap 
143400759c0eSRandy Dunlap 	while (*s) {
143500759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
143600759c0eSRandy Dunlap 		s++;
143700759c0eSRandy Dunlap 		if (*s)
143800759c0eSRandy Dunlap 			fprintf(stderr, ", ");
143900759c0eSRandy Dunlap 	}
144000759c0eSRandy Dunlap 	fprintf(stderr, "\n");
144100759c0eSRandy Dunlap }
144200759c0eSRandy Dunlap 
1443356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1444356ad538SQuentin Casasnovas {
1445356ad538SQuentin Casasnovas 	switch (is_func) {
1446356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1447356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1448356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1449356ad538SQuentin Casasnovas 	}
1450356ad538SQuentin Casasnovas }
1451356ad538SQuentin Casasnovas 
1452588ccd73SSam Ravnborg /*
1453b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1454b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
14554c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
145658fb0d4fSSam Ravnborg  */
14570d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
14580d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
145958fb0d4fSSam Ravnborg 				const char *fromsec,
146058fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
146158fb0d4fSSam Ravnborg 				const char *fromsym,
1462588ccd73SSam Ravnborg 				int from_is_func,
1463588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1464588ccd73SSam Ravnborg 				int to_is_func)
1465b39927cfSSam Ravnborg {
1466588ccd73SSam Ravnborg 	const char *from, *from_p;
1467588ccd73SSam Ravnborg 	const char *to, *to_p;
146837ed19d5SAlexey Fomenko 	char *prl_from;
146937ed19d5SAlexey Fomenko 	char *prl_to;
1470f666751aSSam Ravnborg 
1471e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1472e5f95c8bSSam Ravnborg 
1473356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1474356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1475356ad538SQuentin Casasnovas 
14767c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14777c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14787c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14797c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1480588ccd73SSam Ravnborg 
14810d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1482bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
148337ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
148437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1485588ccd73SSam Ravnborg 		fprintf(stderr,
1486588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1487588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1488588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1489588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
149037ed19d5SAlexey Fomenko 		prl_from, fromsym,
149137ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
149237ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
149337ed19d5SAlexey Fomenko 		free(prl_from);
149437ed19d5SAlexey Fomenko 		free(prl_to);
1495588ccd73SSam Ravnborg 		break;
1496bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
149737ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1498588ccd73SSam Ravnborg 		fprintf(stderr,
1499588ccd73SSam Ravnborg 		"The variable %s references\n"
1500588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1501588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
15028b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1503588ccd73SSam Ravnborg 		"or name the variable:\n",
150437ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
150500759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
150637ed19d5SAlexey Fomenko 		free(prl_to);
1507588ccd73SSam Ravnborg 		break;
150858fb0d4fSSam Ravnborg 	}
1509bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
151037ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1511588ccd73SSam Ravnborg 		fprintf(stderr,
1512588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1513588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1514588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
151537ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
151637ed19d5SAlexey Fomenko 		free(prl_to);
1517588ccd73SSam Ravnborg 		break;
1518bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
151937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1520588ccd73SSam Ravnborg 		fprintf(stderr,
1521588ccd73SSam Ravnborg 		"The variable %s references\n"
1522588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1523588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1524588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1525588ccd73SSam Ravnborg 		"name the variable:\n",
152637ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
152700759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
152837ed19d5SAlexey Fomenko 		free(prl_to);
1529588ccd73SSam Ravnborg 		break;
1530588ccd73SSam Ravnborg 	}
1531bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1532bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
153337ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
153437ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1535588ccd73SSam Ravnborg 		fprintf(stderr,
1536588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1537588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1538588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1539588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
154037ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
154137ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1542b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
154337ed19d5SAlexey Fomenko 		free(prl_from);
154437ed19d5SAlexey Fomenko 		free(prl_to);
1545588ccd73SSam Ravnborg 		break;
1546bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
154737ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
154837ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1549588ccd73SSam Ravnborg 		fprintf(stderr,
1550588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1551588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1552588ccd73SSam Ravnborg 		"This is often seen when error handling "
1553588ccd73SSam Ravnborg 		"in the init function\n"
1554588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1555588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1556588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
155737ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
155837ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
15595003bab8SAndrew Morton 		prl_to, tosym, to_p);
156037ed19d5SAlexey Fomenko 		free(prl_from);
156137ed19d5SAlexey Fomenko 		free(prl_to);
1562588ccd73SSam Ravnborg 		break;
1563bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
156437ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
156537ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1566588ccd73SSam Ravnborg 		fprintf(stderr,
1567588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1568588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1569588ccd73SSam Ravnborg 		"This is often seen when error handling "
1570588ccd73SSam Ravnborg 		"in the exit function\n"
1571588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1572588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1573588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
157437ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
157537ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
157637ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
157737ed19d5SAlexey Fomenko 		free(prl_from);
157837ed19d5SAlexey Fomenko 		free(prl_to);
1579588ccd73SSam Ravnborg 		break;
1580588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
158137ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1582588ccd73SSam Ravnborg 		fprintf(stderr,
1583588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1584588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1585588ccd73SSam Ravnborg 		"or drop the export.\n",
158637ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
158737ed19d5SAlexey Fomenko 		free(prl_to);
1588588ccd73SSam Ravnborg 		break;
158952dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
159052dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
159152dc0595SQuentin Casasnovas 		      "we should never get here.");
159252dc0595SQuentin Casasnovas 		break;
1593588ccd73SSam Ravnborg 	}
1594588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
159558fb0d4fSSam Ravnborg }
159658fb0d4fSSam Ravnborg 
1597644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1598644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
159958fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
160058fb0d4fSSam Ravnborg {
160158fb0d4fSSam Ravnborg 	const char *tosec;
1602588ccd73SSam Ravnborg 	Elf_Sym *to;
1603588ccd73SSam Ravnborg 	Elf_Sym *from;
160458fb0d4fSSam Ravnborg 	const char *tosym;
1605588ccd73SSam Ravnborg 	const char *fromsym;
160658fb0d4fSSam Ravnborg 
1607588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1608588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
160958fb0d4fSSam Ravnborg 
1610d62c4765SMasahiro Yamada 	if (strstarts(fromsym, "reference___initcall"))
161177ab21adSAndi Kleen 		return;
161277ab21adSAndi Kleen 
1613c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1614c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1615c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1616c7a65e06SQuentin Casasnovas 
161758fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1618af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1619af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1620588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1621588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1622588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1623588ccd73SSam Ravnborg 				    is_function(to));
162458fb0d4fSSam Ravnborg 	}
1625b39927cfSSam Ravnborg }
1626644e8f14SQuentin Casasnovas 
162752dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
162852dc0595SQuentin Casasnovas {
162952dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
163052dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
163152dc0595SQuentin Casasnovas 
163252dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
163352dc0595SQuentin Casasnovas }
163452dc0595SQuentin Casasnovas 
163552dc0595SQuentin Casasnovas /*
163652dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
163752dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
163852dc0595SQuentin Casasnovas  */
163952dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1640e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
164152dc0595SQuentin Casasnovas {
164252dc0595SQuentin Casasnovas 	/*
164352dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
164452dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
164552dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
164652dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
164752dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
164852dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
164952dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
165052dc0595SQuentin Casasnovas 	 */
1651e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
165252dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
165352dc0595SQuentin Casasnovas }
1654e84048aaSQuentin Casasnovas 
165552dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
165652dc0595SQuentin Casasnovas {
1657d3df4de7SQuentin Casasnovas 	/*
1658d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1659d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1660d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1661d3df4de7SQuentin Casasnovas 	 */
1662d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
166352dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
166452dc0595SQuentin Casasnovas 
166552dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
166652dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
166752dc0595SQuentin Casasnovas }
166852dc0595SQuentin Casasnovas 
1669e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1670e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1671e84048aaSQuentin Casasnovas 
167252dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
167352dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
167452dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
167552dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
167652dc0595SQuentin Casasnovas {
167752dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
167852dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
167952dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
168052dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
168152dc0595SQuentin Casasnovas 	const char* from_pretty_name;
168252dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
168352dc0595SQuentin Casasnovas 	const char* to_pretty_name;
168452dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
168552dc0595SQuentin Casasnovas 
168652dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
168752dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
168852dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
168952dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
169052dc0595SQuentin Casasnovas 
169152dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
169252dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
169352dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
169452dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
169552dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
169652dc0595SQuentin Casasnovas 
169752dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
169852dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
169952dc0595SQuentin Casasnovas 		fprintf(stderr,
170052dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
170152dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
170252dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
170352dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
170452dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
170552dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
170652dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
170752dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
170852dc0595SQuentin Casasnovas }
170952dc0595SQuentin Casasnovas 
171052dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
171152dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
171252dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
171352dc0595SQuentin Casasnovas 				     const char *fromsec)
171452dc0595SQuentin Casasnovas {
171552dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
171652dc0595SQuentin Casasnovas 
171752dc0595SQuentin Casasnovas 	sec_mismatch_count++;
171852dc0595SQuentin Casasnovas 
171946c7dd56SMasahiro Yamada 	report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
172052dc0595SQuentin Casasnovas 
172152dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
172252dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
172352dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
172452dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
172552dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
172652dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
172752dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
172852dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
172952dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
173052dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
173152dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
173252dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
173352dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
173452dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
173552dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
173652dc0595SQuentin Casasnovas 		else
173752dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
173852dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
173952dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
174052dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
174152dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
174252dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
174352dc0595SQuentin Casasnovas 	}
174452dc0595SQuentin Casasnovas }
174552dc0595SQuentin Casasnovas 
1746644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1747644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1748644e8f14SQuentin Casasnovas {
17490cad61d7SLuis de Bethencourt 	const char *tosec = sec_name(elf, get_secindex(elf, sym));
1750644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1751644e8f14SQuentin Casasnovas 
1752644e8f14SQuentin Casasnovas 	if (mismatch) {
1753644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1754644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1755644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1756644e8f14SQuentin Casasnovas 		else
1757644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1758644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1759644e8f14SQuentin Casasnovas 	}
1760b39927cfSSam Ravnborg }
1761b39927cfSSam Ravnborg 
1762ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
17635b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1764ae4ac123SAtsushi Nemoto {
1765ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17666845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1767ae4ac123SAtsushi Nemoto 
1768ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1769731ece41SOlof Johansson 		r->r_offset;
1770ae4ac123SAtsushi Nemoto }
1771ae4ac123SAtsushi Nemoto 
17725b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1773ae4ac123SAtsushi Nemoto {
1774ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17755b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1776ae4ac123SAtsushi Nemoto 
1777ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1778ae4ac123SAtsushi Nemoto 	case R_386_32:
1779ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1780ae4ac123SAtsushi Nemoto 		break;
1781ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1782ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1783ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1784ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1785ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1786ae4ac123SAtsushi Nemoto 		break;
1787ae4ac123SAtsushi Nemoto 	}
1788ae4ac123SAtsushi Nemoto 	return 0;
1789ae4ac123SAtsushi Nemoto }
1790ae4ac123SAtsushi Nemoto 
17916e2e340bSTony Lindgren #ifndef R_ARM_CALL
17926e2e340bSTony Lindgren #define R_ARM_CALL	28
17936e2e340bSTony Lindgren #endif
17946e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17956e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17966e2e340bSTony Lindgren #endif
17976e2e340bSTony Lindgren 
1798c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1799c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1800c9698e5cSDavid A. Long #endif
1801c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1802c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1803c9698e5cSDavid A. Long #endif
1804c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1805c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1806c9698e5cSDavid A. Long #endif
1807c9698e5cSDavid A. Long 
18085b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
180956a974faSSam Ravnborg {
181056a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
181156a974faSSam Ravnborg 
181256a974faSSam Ravnborg 	switch (r_typ) {
181356a974faSSam Ravnborg 	case R_ARM_ABS32:
181456a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1815df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1816df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
181756a974faSSam Ravnborg 		break;
181856a974faSSam Ravnborg 	case R_ARM_PC24:
18196e2e340bSTony Lindgren 	case R_ARM_CALL:
18206e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1821c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1822c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1823c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
182456a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1825df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
18265b24c071SSam Ravnborg 			      sechdr->sh_offset +
18275b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
182856a974faSSam Ravnborg 		break;
182956a974faSSam Ravnborg 	default:
183056a974faSSam Ravnborg 		return 1;
183156a974faSSam Ravnborg 	}
183256a974faSSam Ravnborg 	return 0;
183356a974faSSam Ravnborg }
183456a974faSSam Ravnborg 
18355b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1836ae4ac123SAtsushi Nemoto {
1837ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
18385b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1839ae4ac123SAtsushi Nemoto 	unsigned int inst;
1840ae4ac123SAtsushi Nemoto 
1841ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1842ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1843ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1844ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1845ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1846ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1847ae4ac123SAtsushi Nemoto 		break;
1848ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1849ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1850ae4ac123SAtsushi Nemoto 		break;
1851ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1852ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1853ae4ac123SAtsushi Nemoto 		break;
1854ae4ac123SAtsushi Nemoto 	}
1855ae4ac123SAtsushi Nemoto 	return 0;
1856ae4ac123SAtsushi Nemoto }
1857ae4ac123SAtsushi Nemoto 
18585b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
185910668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1860b39927cfSSam Ravnborg {
1861b39927cfSSam Ravnborg 	Elf_Sym  *sym;
18625b24c071SSam Ravnborg 	Elf_Rela *rela;
18632c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1864eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18655b24c071SSam Ravnborg 	const char *fromsec;
18665b24c071SSam Ravnborg 
1867ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18685b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18695b24c071SSam Ravnborg 
1870ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18715b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18725b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1873b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18745b24c071SSam Ravnborg 		return;
1875e241a630SSam Ravnborg 
1876b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1877b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1878eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1879ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1880ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1881eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1882eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1883ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1884ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1885eae07ac6SAtsushi Nemoto 		} else {
1886601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1887eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1888eae07ac6SAtsushi Nemoto 		}
1889eae07ac6SAtsushi Nemoto #else
1890eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1891eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1892eae07ac6SAtsushi Nemoto #endif
189393684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1894eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1895b39927cfSSam Ravnborg 		/* Skip special sections */
18961ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1897b39927cfSSam Ravnborg 			continue;
1898e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1899e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
190058fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19012c1a51f3SAtsushi Nemoto 	}
19025b24c071SSam Ravnborg }
19035b24c071SSam Ravnborg 
19045b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
190510668220SSam Ravnborg 			Elf_Shdr *sechdr)
19065b24c071SSam Ravnborg {
19075b24c071SSam Ravnborg 	Elf_Sym *sym;
19082c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
19095b24c071SSam Ravnborg 	Elf_Rela r;
19105b24c071SSam Ravnborg 	unsigned int r_sym;
19115b24c071SSam Ravnborg 	const char *fromsec;
19125b24c071SSam Ravnborg 
1913ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
19145b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
19155b24c071SSam Ravnborg 
1916ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
19175b24c071SSam Ravnborg 	fromsec += strlen(".rel");
19185b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1919b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
19205b24c071SSam Ravnborg 		return;
19212c1a51f3SAtsushi Nemoto 
19222c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
19232c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1924eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1925ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1926ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1927eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1928eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1929ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1930ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1931eae07ac6SAtsushi Nemoto 		} else {
19322c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1933eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1934eae07ac6SAtsushi Nemoto 		}
1935eae07ac6SAtsushi Nemoto #else
1936eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1937eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1938eae07ac6SAtsushi Nemoto #endif
19392c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1940ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1941ae4ac123SAtsushi Nemoto 		case EM_386:
19425b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1943ae4ac123SAtsushi Nemoto 				continue;
1944ae4ac123SAtsushi Nemoto 			break;
194556a974faSSam Ravnborg 		case EM_ARM:
19465b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
194756a974faSSam Ravnborg 				continue;
194856a974faSSam Ravnborg 			break;
1949ae4ac123SAtsushi Nemoto 		case EM_MIPS:
19505b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1951ae4ac123SAtsushi Nemoto 				continue;
1952ae4ac123SAtsushi Nemoto 			break;
1953ae4ac123SAtsushi Nemoto 		}
1954eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
19552c1a51f3SAtsushi Nemoto 		/* Skip special sections */
19561ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
19572c1a51f3SAtsushi Nemoto 			continue;
1958e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1959e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
196058fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19612c1a51f3SAtsushi Nemoto 	}
1962b39927cfSSam Ravnborg }
19635b24c071SSam Ravnborg 
19645b24c071SSam Ravnborg /**
19655b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19665b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19675b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1968b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19695b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19705b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
197132be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19725b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19735b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19745b24c071SSam Ravnborg  * be discarded and warns about it.
19755b24c071SSam Ravnborg  **/
19765b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
197710668220SSam Ravnborg 			  struct elf_info *elf)
19785b24c071SSam Ravnborg {
19795b24c071SSam Ravnborg 	int i;
19805b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19815b24c071SSam Ravnborg 
19825b24c071SSam Ravnborg 	/* Walk through all sections */
19831ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1984b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19855b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19865b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
198710668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19885b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
198910668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1990b39927cfSSam Ravnborg 	}
1991b39927cfSSam Ravnborg }
1992b39927cfSSam Ravnborg 
19937d02b490SAndi Kleen static char *remove_dot(char *s)
19947d02b490SAndi Kleen {
1995fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19967d02b490SAndi Kleen 
1997fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
1998fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
1999fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
20007d02b490SAndi Kleen 			s[n] = 0;
20017d02b490SAndi Kleen 	}
20027d02b490SAndi Kleen 	return s;
20037d02b490SAndi Kleen }
20047d02b490SAndi Kleen 
20058b185743SMasahiro Yamada static void read_symbols(const char *modname)
20061da177e4SLinus Torvalds {
20071da177e4SLinus Torvalds 	const char *symname;
20081da177e4SLinus Torvalds 	char *version;
2009b817f6feSSam Ravnborg 	char *license;
2010cb9b55d2SMatthias Maennich 	char *namespace;
20111da177e4SLinus Torvalds 	struct module *mod;
20121da177e4SLinus Torvalds 	struct elf_info info = { };
20131da177e4SLinus Torvalds 	Elf_Sym *sym;
20141da177e4SLinus Torvalds 
201585bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
201685bd2fddSSam Ravnborg 		return;
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds 	mod = new_module(modname);
20191da177e4SLinus Torvalds 
20201da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
20211da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
20221da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
20231da177e4SLinus Torvalds 		have_vmlinux = 1;
20241da177e4SLinus Torvalds 		mod->skip = 1;
20251da177e4SLinus Torvalds 	}
20261da177e4SLinus Torvalds 
2027bca2cceeSMasahiro Yamada 	license = get_modinfo(&info, "license");
2028ba1029c9SRandy Dunlap 	if (!license && !is_vmlinux(modname))
20292fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
2030eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
2031eed7d279SSam Ravnborg 		     "more information\n", modname);
2032b817f6feSSam Ravnborg 	while (license) {
2033b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
2034b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
2035b817f6feSSam Ravnborg 		else {
2036b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
2037b817f6feSSam Ravnborg 			break;
2038b817f6feSSam Ravnborg 		}
2039bca2cceeSMasahiro Yamada 		license = get_next_modinfo(&info, "license", license);
2040b817f6feSSam Ravnborg 	}
2041b817f6feSSam Ravnborg 
2042cb9b55d2SMatthias Maennich 	namespace = get_modinfo(&info, "import_ns");
2043cb9b55d2SMatthias Maennich 	while (namespace) {
2044cb9b55d2SMatthias Maennich 		add_namespace(&mod->imported_namespaces, namespace);
2045cb9b55d2SMatthias Maennich 		namespace = get_next_modinfo(&info, "import_ns", namespace);
2046cb9b55d2SMatthias Maennich 	}
2047cb9b55d2SMatthias Maennich 
20481da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
20497d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
20501da177e4SLinus Torvalds 
20511da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
20521da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
20531da177e4SLinus Torvalds 	}
205415bfc234SDenis Efremov 
205569923208SMatthias Maennich 	/* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
205669923208SMatthias Maennich 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
205769923208SMatthias Maennich 		symname = remove_dot(info.strtab + sym->st_name);
205869923208SMatthias Maennich 
205969923208SMatthias Maennich 		if (strstarts(symname, "__kstrtabns_"))
206069923208SMatthias Maennich 			sym_update_namespace(symname + strlen("__kstrtabns_"),
206169923208SMatthias Maennich 					     namespace_from_kstrtabns(&info,
206269923208SMatthias Maennich 								      sym));
206369923208SMatthias Maennich 	}
206469923208SMatthias Maennich 
206515bfc234SDenis Efremov 	// check for static EXPORT_SYMBOL_* functions && global vars
206615bfc234SDenis Efremov 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
206715bfc234SDenis Efremov 		unsigned char bind = ELF_ST_BIND(sym->st_info);
206815bfc234SDenis Efremov 
206915bfc234SDenis Efremov 		if (bind == STB_GLOBAL || bind == STB_WEAK) {
207015bfc234SDenis Efremov 			struct symbol *s =
207115bfc234SDenis Efremov 				find_symbol(remove_dot(info.strtab +
207215bfc234SDenis Efremov 						       sym->st_name));
207315bfc234SDenis Efremov 
207415bfc234SDenis Efremov 			if (s)
207515bfc234SDenis Efremov 				s->is_static = 0;
207615bfc234SDenis Efremov 		}
207715bfc234SDenis Efremov 	}
207815bfc234SDenis Efremov 
2079074a04f5SMasahiro Yamada 	if (!is_vmlinux(modname) || vmlinux_section_warnings)
208010668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
20811da177e4SLinus Torvalds 
2082bca2cceeSMasahiro Yamada 	version = get_modinfo(&info, "version");
20831da177e4SLinus Torvalds 	if (version)
20841da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
20851da177e4SLinus Torvalds 				       version - (char *)info.hdr);
20861da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
20871da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
20881da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
20891da177e4SLinus Torvalds 
20901da177e4SLinus Torvalds 	parse_elf_finish(&info);
20911da177e4SLinus Torvalds 
20928c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
20931da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
20941da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
20951da177e4SLinus Torvalds 	 * important anyhow */
20961da177e4SLinus Torvalds 	if (modversions)
20978c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
20981da177e4SLinus Torvalds }
20991da177e4SLinus Torvalds 
2100712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2101712f9b46SRusty Russell {
2102712f9b46SRusty Russell 	FILE *in = stdin;
2103712f9b46SRusty Russell 	char fname[PATH_MAX];
2104712f9b46SRusty Russell 
2105712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2106712f9b46SRusty Russell 		in = fopen(filename, "r");
2107712f9b46SRusty Russell 		if (!in)
2108712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2109712f9b46SRusty Russell 	}
2110712f9b46SRusty Russell 
2111712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2112712f9b46SRusty Russell 		if (strends(fname, "\n"))
2113712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2114712f9b46SRusty Russell 		read_symbols(fname);
2115712f9b46SRusty Russell 	}
2116712f9b46SRusty Russell 
2117712f9b46SRusty Russell 	if (in != stdin)
2118712f9b46SRusty Russell 		fclose(in);
2119712f9b46SRusty Russell }
2120712f9b46SRusty Russell 
21211da177e4SLinus Torvalds #define SZ 500
21221da177e4SLinus Torvalds 
21231da177e4SLinus Torvalds /* We first write the generated file into memory using the
21241da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
21251da177e4SLinus Torvalds  * only update the later if anything changed */
21261da177e4SLinus Torvalds 
21275c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
21285c3ead8cSSam Ravnborg 						      const char *fmt, ...)
21291da177e4SLinus Torvalds {
21301da177e4SLinus Torvalds 	char tmp[SZ];
21311da177e4SLinus Torvalds 	int len;
21321da177e4SLinus Torvalds 	va_list ap;
21331da177e4SLinus Torvalds 
21341da177e4SLinus Torvalds 	va_start(ap, fmt);
21351da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
21367670f023SSam Ravnborg 	buf_write(buf, tmp, len);
21371da177e4SLinus Torvalds 	va_end(ap);
21381da177e4SLinus Torvalds }
21391da177e4SLinus Torvalds 
21405c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
21411da177e4SLinus Torvalds {
21421da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
21437670f023SSam Ravnborg 		buf->size += len + SZ;
21441f3aa900SRandy Dunlap 		buf->p = NOFAIL(realloc(buf->p, buf->size));
21451da177e4SLinus Torvalds 	}
21461da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
21471da177e4SLinus Torvalds 	buf->pos += len;
21481da177e4SLinus Torvalds }
21491da177e4SLinus Torvalds 
2150c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2151c96fca21SSam Ravnborg {
2152c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2153c96fca21SSam Ravnborg 
2154c96fca21SSam Ravnborg 	switch (exp) {
2155c96fca21SSam Ravnborg 	case export_gpl:
2156c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2157c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2158c96fca21SSam Ravnborg 		break;
2159c96fca21SSam Ravnborg 	case export_unused_gpl:
2160c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2161c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2162c96fca21SSam Ravnborg 		break;
2163c96fca21SSam Ravnborg 	case export_gpl_future:
2164c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2165c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2166c96fca21SSam Ravnborg 		break;
2167c96fca21SSam Ravnborg 	case export_plain:
2168c96fca21SSam Ravnborg 	case export_unused:
2169c96fca21SSam Ravnborg 	case export_unknown:
2170c96fca21SSam Ravnborg 		/* ignore */
2171c96fca21SSam Ravnborg 		break;
2172c96fca21SSam Ravnborg 	}
2173c96fca21SSam Ravnborg }
2174c96fca21SSam Ravnborg 
2175c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2176c96fca21SSam Ravnborg {
2177c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2178c96fca21SSam Ravnborg 
2179c96fca21SSam Ravnborg 	switch (exp) {
2180c96fca21SSam Ravnborg 	case export_unused:
2181c96fca21SSam Ravnborg 	case export_unused_gpl:
2182c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2183c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2184c96fca21SSam Ravnborg 		break;
2185c96fca21SSam Ravnborg 	default:
2186c96fca21SSam Ravnborg 		/* ignore */
2187c96fca21SSam Ravnborg 		break;
2188c96fca21SSam Ravnborg 	}
2189c96fca21SSam Ravnborg }
2190c96fca21SSam Ravnborg 
21913b415288SMasahiro Yamada static int check_exports(struct module *mod)
2192b817f6feSSam Ravnborg {
2193b817f6feSSam Ravnborg 	struct symbol *s, *exp;
21943b415288SMasahiro Yamada 	int err = 0;
2195b817f6feSSam Ravnborg 
2196b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21976449bd62SAndrew Morton 		const char *basename;
2198b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
21993b415288SMasahiro Yamada 		if (!exp || exp->module == mod) {
22003b415288SMasahiro Yamada 			if (have_vmlinux && !s->weak) {
22013b415288SMasahiro Yamada 				if (warn_unresolved) {
22023b415288SMasahiro Yamada 					warn("\"%s\" [%s.ko] undefined!\n",
22033b415288SMasahiro Yamada 					     s->name, mod->name);
22043b415288SMasahiro Yamada 				} else {
22053b415288SMasahiro Yamada 					merror("\"%s\" [%s.ko] undefined!\n",
22063b415288SMasahiro Yamada 					       s->name, mod->name);
22073b415288SMasahiro Yamada 					err = 1;
22083b415288SMasahiro Yamada 				}
22093b415288SMasahiro Yamada 			}
2210b817f6feSSam Ravnborg 			continue;
22113b415288SMasahiro Yamada 		}
22126449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2213b817f6feSSam Ravnborg 		if (basename)
2214b817f6feSSam Ravnborg 			basename++;
2215c96fca21SSam Ravnborg 		else
2216c96fca21SSam Ravnborg 			basename = mod->name;
2217cb9b55d2SMatthias Maennich 
2218*bbc55bdeSMasahiro Yamada 		if (exp->namespace &&
2219*bbc55bdeSMasahiro Yamada 		    !module_imports_namespace(mod, exp->namespace)) {
2220cb9b55d2SMatthias Maennich 			warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
2221cb9b55d2SMatthias Maennich 			     basename, exp->name, exp->namespace);
2222*bbc55bdeSMasahiro Yamada 			add_namespace(&mod->missing_namespaces, exp->namespace);
22231d082773SMatthias Maennich 		}
2224cb9b55d2SMatthias Maennich 
2225c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2226c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2227c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2228b817f6feSSam Ravnborg 	}
22293b415288SMasahiro Yamada 
22303b415288SMasahiro Yamada 	return err;
2231b817f6feSSam Ravnborg }
2232b817f6feSSam Ravnborg 
22334fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
22344fd3e4efSWanlong Gao {
22354fd3e4efSWanlong Gao 	const char *mod_name;
22364fd3e4efSWanlong Gao 
22374fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
22384fd3e4efSWanlong Gao 	if (mod_name == NULL)
22394fd3e4efSWanlong Gao 		mod_name = mod->name;
22404fd3e4efSWanlong Gao 	else
22414fd3e4efSWanlong Gao 		mod_name++;
22424fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
22434fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
22444fd3e4efSWanlong Gao 		return 1;
22454fd3e4efSWanlong Gao 	}
22464fd3e4efSWanlong Gao 
22474fd3e4efSWanlong Gao 	return 0;
22484fd3e4efSWanlong Gao }
22494fd3e4efSWanlong Gao 
22505c3ead8cSSam Ravnborg /**
22515c3ead8cSSam Ravnborg  * Header for the generated file
22525c3ead8cSSam Ravnborg  **/
22535c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
22541da177e4SLinus Torvalds {
22559afb719eSLaura Abbott 	buf_printf(b, "#include <linux/build-salt.h>\n");
22561da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
22571da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
22581da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
22591da177e4SLinus Torvalds 	buf_printf(b, "\n");
22609afb719eSLaura Abbott 	buf_printf(b, "BUILD_SALT;\n");
22619afb719eSLaura Abbott 	buf_printf(b, "\n");
22621da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
22633e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
22641da177e4SLinus Torvalds 	buf_printf(b, "\n");
2265e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
2266a3d0cb04SMasahiro Yamada 	buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
22673c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
22681da177e4SLinus Torvalds 	if (mod->has_init)
22693c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
22701da177e4SLinus Torvalds 	if (mod->has_cleanup)
22711da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
22723c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
22731da177e4SLinus Torvalds 			      "#endif\n");
22743c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
22751da177e4SLinus Torvalds 	buf_printf(b, "};\n");
22761da177e4SLinus Torvalds }
22771da177e4SLinus Torvalds 
22782449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
22792449b8baSBen Hutchings {
22802449b8baSBen Hutchings 	if (is_intree)
22812449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
22822449b8baSBen Hutchings }
22832449b8baSBen Hutchings 
2284caf7501aSAndi Kleen /* Cannot check for assembler */
2285caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2286caf7501aSAndi Kleen {
2287e4f35891SWANG Chao 	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
2288caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2289caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2290caf7501aSAndi Kleen }
2291caf7501aSAndi Kleen 
22925c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2293a9860bf0SGreg Kroah-Hartman {
2294d62c4765SMasahiro Yamada 	if (strstarts(name, "drivers/staging"))
2295a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2296a9860bf0SGreg Kroah-Hartman }
2297a9860bf0SGreg Kroah-Hartman 
22985c3ead8cSSam Ravnborg /**
22995c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
23005c3ead8cSSam Ravnborg  **/
2301c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
23021da177e4SLinus Torvalds {
23031da177e4SLinus Torvalds 	struct symbol *s, *exp;
2304c53ddacdSKirill Korotaev 	int err = 0;
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
23071da177e4SLinus Torvalds 		exp = find_symbol(s->name);
23083b415288SMasahiro Yamada 		if (!exp || exp->module == mod)
23091da177e4SLinus Torvalds 			continue;
23101da177e4SLinus Torvalds 		s->module = exp->module;
23111da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
23121da177e4SLinus Torvalds 		s->crc = exp->crc;
23131da177e4SLinus Torvalds 	}
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds 	if (!modversions)
2316c53ddacdSKirill Korotaev 		return err;
23171da177e4SLinus Torvalds 
23181da177e4SLinus Torvalds 	buf_printf(b, "\n");
23191da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
2320a3d0cb04SMasahiro Yamada 	buf_printf(b, "__used __section(__versions) = {\n");
23211da177e4SLinus Torvalds 
23221da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2323df578e7dSSam Ravnborg 		if (!s->module)
23241da177e4SLinus Torvalds 			continue;
23251da177e4SLinus Torvalds 		if (!s->crc_valid) {
2326cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
23271da177e4SLinus Torvalds 				s->name, mod->name);
23281da177e4SLinus Torvalds 			continue;
23291da177e4SLinus Torvalds 		}
23305cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
23315cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
23325cfb203aSTakashi Iwai 			       s->name, mod->name);
23335cfb203aSTakashi Iwai 			err = 1;
23345cfb203aSTakashi Iwai 			break;
23355cfb203aSTakashi Iwai 		}
2336b2c5cdcfSMasahiro Yamada 		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
2337a4b6a77bSJames Hogan 			   s->crc, s->name);
23381da177e4SLinus Torvalds 	}
23391da177e4SLinus Torvalds 
23401da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2341c53ddacdSKirill Korotaev 
2342c53ddacdSKirill Korotaev 	return err;
23431da177e4SLinus Torvalds }
23441da177e4SLinus Torvalds 
2345d2665ca8SMasahiro Yamada static void add_depends(struct buffer *b, struct module *mod)
23461da177e4SLinus Torvalds {
23471da177e4SLinus Torvalds 	struct symbol *s;
23481da177e4SLinus Torvalds 	int first = 1;
23491da177e4SLinus Torvalds 
2350d2665ca8SMasahiro Yamada 	/* Clear ->seen flag of modules that own symbols needed by this. */
2351d2665ca8SMasahiro Yamada 	for (s = mod->unres; s; s = s->next)
2352d2665ca8SMasahiro Yamada 		if (s->module)
2353d2665ca8SMasahiro Yamada 			s->module->seen = is_vmlinux(s->module->name);
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds 	buf_printf(b, "\n");
23566df7e1ecSMasahiro Yamada 	buf_printf(b, "MODULE_INFO(depends, \"");
23571da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2358a61b2dfdSSam Ravnborg 		const char *p;
23591da177e4SLinus Torvalds 		if (!s->module)
23601da177e4SLinus Torvalds 			continue;
23611da177e4SLinus Torvalds 
23621da177e4SLinus Torvalds 		if (s->module->seen)
23631da177e4SLinus Torvalds 			continue;
23641da177e4SLinus Torvalds 
23651da177e4SLinus Torvalds 		s->module->seen = 1;
2366df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2367df578e7dSSam Ravnborg 		if (p)
2368a61b2dfdSSam Ravnborg 			p++;
2369a61b2dfdSSam Ravnborg 		else
2370a61b2dfdSSam Ravnborg 			p = s->module->name;
2371a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
23721da177e4SLinus Torvalds 		first = 0;
23731da177e4SLinus Torvalds 	}
23746df7e1ecSMasahiro Yamada 	buf_printf(b, "\");\n");
23751da177e4SLinus Torvalds }
23761da177e4SLinus Torvalds 
23775c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
23781da177e4SLinus Torvalds {
23791da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
23801da177e4SLinus Torvalds 		buf_printf(b, "\n");
23811da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
23821da177e4SLinus Torvalds 			   mod->srcversion);
23831da177e4SLinus Torvalds 	}
23841da177e4SLinus Torvalds }
23851da177e4SLinus Torvalds 
23865c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
23871da177e4SLinus Torvalds {
23881da177e4SLinus Torvalds 	char *tmp;
23891da177e4SLinus Torvalds 	FILE *file;
23901da177e4SLinus Torvalds 	struct stat st;
23911da177e4SLinus Torvalds 
23921da177e4SLinus Torvalds 	file = fopen(fname, "r");
23931da177e4SLinus Torvalds 	if (!file)
23941da177e4SLinus Torvalds 		goto write;
23951da177e4SLinus Torvalds 
23961da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
23971da177e4SLinus Torvalds 		goto close_write;
23981da177e4SLinus Torvalds 
23991da177e4SLinus Torvalds 	if (st.st_size != b->pos)
24001da177e4SLinus Torvalds 		goto close_write;
24011da177e4SLinus Torvalds 
24021da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
24031da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
24041da177e4SLinus Torvalds 		goto free_write;
24051da177e4SLinus Torvalds 
24061da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
24071da177e4SLinus Torvalds 		goto free_write;
24081da177e4SLinus Torvalds 
24091da177e4SLinus Torvalds 	free(tmp);
24101da177e4SLinus Torvalds 	fclose(file);
24111da177e4SLinus Torvalds 	return;
24121da177e4SLinus Torvalds 
24131da177e4SLinus Torvalds  free_write:
24141da177e4SLinus Torvalds 	free(tmp);
24151da177e4SLinus Torvalds  close_write:
24161da177e4SLinus Torvalds 	fclose(file);
24171da177e4SLinus Torvalds  write:
24181da177e4SLinus Torvalds 	file = fopen(fname, "w");
24191da177e4SLinus Torvalds 	if (!file) {
24201da177e4SLinus Torvalds 		perror(fname);
24211da177e4SLinus Torvalds 		exit(1);
24221da177e4SLinus Torvalds 	}
24231da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
24241da177e4SLinus Torvalds 		perror(fname);
24251da177e4SLinus Torvalds 		exit(1);
24261da177e4SLinus Torvalds 	}
24271da177e4SLinus Torvalds 	fclose(file);
24281da177e4SLinus Torvalds }
24291da177e4SLinus Torvalds 
2430bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2431534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2432bd5cbcedSRam Pai  **/
2433040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
24341da177e4SLinus Torvalds {
24351da177e4SLinus Torvalds 	unsigned long size, pos = 0;
24361da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
24371da177e4SLinus Torvalds 	char *line;
24381da177e4SLinus Torvalds 
24391da177e4SLinus Torvalds 	if (!file)
24401da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
24411da177e4SLinus Torvalds 		return;
24421da177e4SLinus Torvalds 
24431da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2444cb9b55d2SMatthias Maennich 		char *symname, *namespace, *modname, *d, *export, *end;
24451da177e4SLinus Torvalds 		unsigned int crc;
24461da177e4SLinus Torvalds 		struct module *mod;
2447040fcc81SSam Ravnborg 		struct symbol *s;
24481da177e4SLinus Torvalds 
24491da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
24501da177e4SLinus Torvalds 			goto fail;
24511da177e4SLinus Torvalds 		*symname++ = '\0';
2452cb9b55d2SMatthias Maennich 		if (!(namespace = strchr(symname, '\t')))
2453cb9b55d2SMatthias Maennich 			goto fail;
2454cb9b55d2SMatthias Maennich 		*namespace++ = '\0';
2455cb9b55d2SMatthias Maennich 		if (!(modname = strchr(namespace, '\t')))
24561da177e4SLinus Torvalds 			goto fail;
24571da177e4SLinus Torvalds 		*modname++ = '\0';
24589ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2459bd5cbcedSRam Pai 			*export++ = '\0';
2460534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2461534b89a9SSam Ravnborg 			*end = '\0';
24621da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
24631da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
24641da177e4SLinus Torvalds 			goto fail;
2465df578e7dSSam Ravnborg 		mod = find_module(modname);
2466df578e7dSSam Ravnborg 		if (!mod) {
2467df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
24681da177e4SLinus Torvalds 				have_vmlinux = 1;
24690fa3a88cSJan Beulich 			mod = new_module(modname);
24701da177e4SLinus Torvalds 			mod->skip = 1;
24711da177e4SLinus Torvalds 		}
24729ae5bd18SMatthias Maennich 		s = sym_add_exported(symname, mod, export_no(export));
2473040fcc81SSam Ravnborg 		s->kernel    = kernel;
24748e70c458SSam Ravnborg 		s->preloaded = 1;
247515bfc234SDenis Efremov 		s->is_static = 0;
2476bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
24779ae5bd18SMatthias Maennich 		sym_update_namespace(symname, namespace);
24781da177e4SLinus Torvalds 	}
24792ee41e62SChristian Engelmayer 	release_file(file, size);
24801da177e4SLinus Torvalds 	return;
24811da177e4SLinus Torvalds fail:
24822ee41e62SChristian Engelmayer 	release_file(file, size);
24831da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
24841da177e4SLinus Torvalds }
24851da177e4SLinus Torvalds 
2486040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2487040fcc81SSam Ravnborg  * For external modules only dump symbols
2488040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2489040fcc81SSam Ravnborg  **/
2490040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2491040fcc81SSam Ravnborg {
2492040fcc81SSam Ravnborg 	if (!external_module)
2493040fcc81SSam Ravnborg 		return 1;
2494040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2495040fcc81SSam Ravnborg 		return 0;
2496040fcc81SSam Ravnborg 	return 1;
2497040fcc81SSam Ravnborg }
2498040fcc81SSam Ravnborg 
24995c3ead8cSSam Ravnborg static void write_dump(const char *fname)
25001da177e4SLinus Torvalds {
25011da177e4SLinus Torvalds 	struct buffer buf = { };
25021da177e4SLinus Torvalds 	struct symbol *symbol;
2503cb9b55d2SMatthias Maennich 	const char *namespace;
25041da177e4SLinus Torvalds 	int n;
25051da177e4SLinus Torvalds 
25061da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
25071da177e4SLinus Torvalds 		symbol = symbolhash[n];
25081da177e4SLinus Torvalds 		while (symbol) {
2509cb9b55d2SMatthias Maennich 			if (dump_sym(symbol)) {
2510cb9b55d2SMatthias Maennich 				namespace = symbol->namespace;
2511cb9b55d2SMatthias Maennich 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
2512040fcc81SSam Ravnborg 					   symbol->crc, symbol->name,
2513cb9b55d2SMatthias Maennich 					   namespace ? namespace : "",
2514bd5cbcedSRam Pai 					   symbol->module->name,
2515bd5cbcedSRam Pai 					   export_str(symbol->export));
2516cb9b55d2SMatthias Maennich 			}
25171da177e4SLinus Torvalds 			symbol = symbol->next;
25181da177e4SLinus Torvalds 		}
25191da177e4SLinus Torvalds 	}
25201da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2521c7d47f26SHeinrich Schuchardt 	free(buf.p);
25221da177e4SLinus Torvalds }
25231da177e4SLinus Torvalds 
2524*bbc55bdeSMasahiro Yamada static void write_namespace_deps_files(const char *fname)
25251d082773SMatthias Maennich {
25261d082773SMatthias Maennich 	struct module *mod;
25271d082773SMatthias Maennich 	struct namespace_list *ns;
25281d082773SMatthias Maennich 	struct buffer ns_deps_buf = {};
25291d082773SMatthias Maennich 
25301d082773SMatthias Maennich 	for (mod = modules; mod; mod = mod->next) {
25311d082773SMatthias Maennich 
2532*bbc55bdeSMasahiro Yamada 		if (mod->skip || !mod->missing_namespaces)
25331d082773SMatthias Maennich 			continue;
25341d082773SMatthias Maennich 
2535*bbc55bdeSMasahiro Yamada 		buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
25361d082773SMatthias Maennich 
2537*bbc55bdeSMasahiro Yamada 		for (ns = mod->missing_namespaces; ns; ns = ns->next)
2538*bbc55bdeSMasahiro Yamada 			buf_printf(&ns_deps_buf, " %s", ns->namespace);
25391d082773SMatthias Maennich 
2540*bbc55bdeSMasahiro Yamada 		buf_printf(&ns_deps_buf, "\n");
25411d082773SMatthias Maennich 	}
25420241ea8cSMasahiro Yamada 
2543*bbc55bdeSMasahiro Yamada 	write_if_changed(&ns_deps_buf, fname);
25440241ea8cSMasahiro Yamada 	free(ns_deps_buf.p);
25451d082773SMatthias Maennich }
25461d082773SMatthias Maennich 
25472d04b5aeSRichard Hacker struct ext_sym_list {
25482d04b5aeSRichard Hacker 	struct ext_sym_list *next;
25492d04b5aeSRichard Hacker 	const char *file;
25502d04b5aeSRichard Hacker };
25512d04b5aeSRichard Hacker 
25525c3ead8cSSam Ravnborg int main(int argc, char **argv)
25531da177e4SLinus Torvalds {
25541da177e4SLinus Torvalds 	struct module *mod;
25551da177e4SLinus Torvalds 	struct buffer buf = { };
255639808e45SMasahiro Yamada 	char *kernel_read = NULL;
2557*bbc55bdeSMasahiro Yamada 	char *missing_namespace_deps = NULL;
2558712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
25591da177e4SLinus Torvalds 	int opt;
2560c53ddacdSKirill Korotaev 	int err;
256115bfc234SDenis Efremov 	int n;
25622d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
25632d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
25641da177e4SLinus Torvalds 
2565*bbc55bdeSMasahiro Yamada 	while ((opt = getopt(argc, argv, "i:e:mnsT:o:awEd:")) != -1) {
25661da177e4SLinus Torvalds 		switch (opt) {
25671da177e4SLinus Torvalds 		case 'i':
2568040fcc81SSam Ravnborg 			kernel_read = optarg;
2569040fcc81SSam Ravnborg 			external_module = 1;
25701da177e4SLinus Torvalds 			break;
25712d04b5aeSRichard Hacker 		case 'e':
25722d04b5aeSRichard Hacker 			external_module = 1;
25732d04b5aeSRichard Hacker 			extsym_iter =
25742d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
25752d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
25762d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
25772d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
25782d04b5aeSRichard Hacker 			break;
25791da177e4SLinus Torvalds 		case 'm':
25801da177e4SLinus Torvalds 			modversions = 1;
25811da177e4SLinus Torvalds 			break;
2582eed380f3SGuenter Roeck 		case 'n':
2583eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2584eed380f3SGuenter Roeck 			break;
25851da177e4SLinus Torvalds 		case 'o':
25861da177e4SLinus Torvalds 			dump_write = optarg;
25871da177e4SLinus Torvalds 			break;
25881da177e4SLinus Torvalds 		case 'a':
25891da177e4SLinus Torvalds 			all_versions = 1;
25901da177e4SLinus Torvalds 			break;
25918d8d8289SSam Ravnborg 		case 's':
25928d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
25938d8d8289SSam Ravnborg 			break;
2594712f9b46SRusty Russell 		case 'T':
2595712f9b46SRusty Russell 			files_source = optarg;
2596712f9b46SRusty Russell 			break;
2597c53ddacdSKirill Korotaev 		case 'w':
2598c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2599c53ddacdSKirill Korotaev 			break;
260047490ec1SNicolas Boichat 		case 'E':
260147490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
260247490ec1SNicolas Boichat 			break;
26031d082773SMatthias Maennich 		case 'd':
2604*bbc55bdeSMasahiro Yamada 			missing_namespace_deps = optarg;
26051d082773SMatthias Maennich 			break;
26061da177e4SLinus Torvalds 		default:
26071da177e4SLinus Torvalds 			exit(1);
26081da177e4SLinus Torvalds 		}
26091da177e4SLinus Torvalds 	}
26101da177e4SLinus Torvalds 
2611040fcc81SSam Ravnborg 	if (kernel_read)
2612040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
26132d04b5aeSRichard Hacker 	while (extsym_start) {
26142d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
26152d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
26162d04b5aeSRichard Hacker 		free(extsym_start);
26172d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
26182d04b5aeSRichard Hacker 	}
26191da177e4SLinus Torvalds 
2620df578e7dSSam Ravnborg 	while (optind < argc)
26211da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
26221da177e4SLinus Torvalds 
2623712f9b46SRusty Russell 	if (files_source)
2624712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2625712f9b46SRusty Russell 
2626c53ddacdSKirill Korotaev 	err = 0;
2627c53ddacdSKirill Korotaev 
2628b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2629d93e1719SMathias Krause 		char fname[PATH_MAX];
2630666ab414SAndi Kleen 
2631b817f6feSSam Ravnborg 		if (mod->skip)
2632b817f6feSSam Ravnborg 			continue;
26331da177e4SLinus Torvalds 
26341da177e4SLinus Torvalds 		buf.pos = 0;
26351da177e4SLinus Torvalds 
26364fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
26373b415288SMasahiro Yamada 		err |= check_exports(mod);
26381d082773SMatthias Maennich 
26391da177e4SLinus Torvalds 		add_header(&buf, mod);
26402449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2641caf7501aSAndi Kleen 		add_retpoline(&buf);
2642a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2643c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
2644d2665ca8SMasahiro Yamada 		add_depends(&buf, mod);
26451da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
26461da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
26471da177e4SLinus Torvalds 
26481da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
26491da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
26501da177e4SLinus Torvalds 	}
26511d082773SMatthias Maennich 
2652*bbc55bdeSMasahiro Yamada 	if (missing_namespace_deps)
2653*bbc55bdeSMasahiro Yamada 		write_namespace_deps_files(missing_namespace_deps);
26541d082773SMatthias Maennich 
26551da177e4SLinus Torvalds 	if (dump_write)
26561da177e4SLinus Torvalds 		write_dump(dump_write);
265746c7dd56SMasahiro Yamada 	if (sec_mismatch_count && sec_mismatch_fatal)
265847490ec1SNicolas Boichat 		fatal("modpost: Section mismatches detected.\n"
265947490ec1SNicolas Boichat 		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
266015bfc234SDenis Efremov 	for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
266147346e96SMasahiro Yamada 		struct symbol *s;
266215bfc234SDenis Efremov 
266347346e96SMasahiro Yamada 		for (s = symbolhash[n]; s; s = s->next) {
266447346e96SMasahiro Yamada 			/*
266547346e96SMasahiro Yamada 			 * Do not check "vmlinux". This avoids the same warnings
266647346e96SMasahiro Yamada 			 * shown twice, and false-positives for ARCH=um.
266747346e96SMasahiro Yamada 			 */
266847346e96SMasahiro Yamada 			if (is_vmlinux(s->module->name) && !s->module->is_dot_o)
266947346e96SMasahiro Yamada 				continue;
267047346e96SMasahiro Yamada 
267115bfc234SDenis Efremov 			if (s->is_static)
267215bfc234SDenis Efremov 				warn("\"%s\" [%s] is a static %s\n",
267315bfc234SDenis Efremov 				     s->name, s->module->name,
267415bfc234SDenis Efremov 				     export_str(s->export));
267515bfc234SDenis Efremov 		}
267615bfc234SDenis Efremov 	}
267715bfc234SDenis Efremov 
2678c7d47f26SHeinrich Schuchardt 	free(buf.p);
26791da177e4SLinus Torvalds 
2680c53ddacdSKirill Korotaev 	return err;
26811da177e4SLinus Torvalds }
2682