xref: /linux-6.15/scripts/mod/modpost.c (revision 69923208)
11da177e4SLinus Torvalds /* Postprocess module symbol versions
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright 2003       Kai Germaschewski
41da177e4SLinus Torvalds  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5df578e7dSSam Ravnborg  * Copyright 2006-2008  Sam Ravnborg
61da177e4SLinus Torvalds  * Based in part on module-init-tools/depmod.c,file2alias
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds  * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Usage: modpost vmlinux module1.o module2.o ...
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
14b2e3e658SMathieu Desnoyers #define _GNU_SOURCE
15b2e3e658SMathieu Desnoyers #include <stdio.h>
161da177e4SLinus Torvalds #include <ctype.h>
175003bab8SAndrew Morton #include <string.h>
18712f9b46SRusty Russell #include <limits.h>
19d4ef1c30SRusty Russell #include <stdbool.h>
20eed380f3SGuenter Roeck #include <errno.h>
211da177e4SLinus Torvalds #include "modpost.h"
22b817f6feSSam Ravnborg #include "../../include/linux/license.h"
239e1b9b80SAlan Jenkins 
241da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */
257a3ee753SMathias Krause static int modversions = 0;
261da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */
277a3ee753SMathias Krause static int have_vmlinux = 0;
281da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
291da177e4SLinus Torvalds static int all_versions = 0;
30040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */
31040fcc81SSam Ravnborg static int external_module = 0;
328d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */
338d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1;
34c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */
35c53ddacdSKirill Korotaev static int warn_unresolved = 0;
36bd5cbcedSRam Pai /* How a symbol is exported */
37588ccd73SSam Ravnborg static int sec_mismatch_count = 0;
3847490ec1SNicolas Boichat static int sec_mismatch_fatal = 0;
39eed380f3SGuenter Roeck /* ignore missing files */
40eed380f3SGuenter Roeck static int ignore_missing_files;
411d082773SMatthias Maennich /* write namespace dependencies */
421d082773SMatthias Maennich static int write_namespace_deps;
43588ccd73SSam Ravnborg 
44c96fca21SSam Ravnborg enum export {
45c96fca21SSam Ravnborg 	export_plain,      export_unused,     export_gpl,
46c96fca21SSam Ravnborg 	export_unused_gpl, export_gpl_future, export_unknown
47c96fca21SSam Ravnborg };
481da177e4SLinus Torvalds 
494fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h;
504fd3e4efSWanlong Gao  * here we use Elf_Addr instead of long for covering cross-compile
514fd3e4efSWanlong Gao  */
524fd3e4efSWanlong Gao 
534fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
544fd3e4efSWanlong Gao 
556d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2)))
566d9a89eaSAndi Kleen 
576d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	va_list arglist;
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	fprintf(stderr, "FATAL: ");
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	va_start(arglist, fmt);
641da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
651da177e4SLinus Torvalds 	va_end(arglist);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	exit(1);
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
706d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	va_list arglist;
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	fprintf(stderr, "WARNING: ");
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 	va_start(arglist, fmt);
771da177e4SLinus Torvalds 	vfprintf(stderr, fmt, arglist);
781da177e4SLinus Torvalds 	va_end(arglist);
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds 
816d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...)
822a116659SMatthew Wilcox {
832a116659SMatthew Wilcox 	va_list arglist;
842a116659SMatthew Wilcox 
852a116659SMatthew Wilcox 	fprintf(stderr, "ERROR: ");
862a116659SMatthew Wilcox 
872a116659SMatthew Wilcox 	va_start(arglist, fmt);
882a116659SMatthew Wilcox 	vfprintf(stderr, fmt, arglist);
892a116659SMatthew Wilcox 	va_end(arglist);
902a116659SMatthew Wilcox }
912a116659SMatthew Wilcox 
92d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix)
93d4ef1c30SRusty Russell {
94d4ef1c30SRusty Russell 	if (strlen(str) < strlen(postfix))
95d4ef1c30SRusty Russell 		return false;
96d4ef1c30SRusty Russell 
97d4ef1c30SRusty Russell 	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
98d4ef1c30SRusty Russell }
99d4ef1c30SRusty Russell 
100040fcc81SSam Ravnborg static int is_vmlinux(const char *modname)
101040fcc81SSam Ravnborg {
102040fcc81SSam Ravnborg 	const char *myname;
103040fcc81SSam Ravnborg 
104df578e7dSSam Ravnborg 	myname = strrchr(modname, '/');
105df578e7dSSam Ravnborg 	if (myname)
106040fcc81SSam Ravnborg 		myname++;
107040fcc81SSam Ravnborg 	else
108040fcc81SSam Ravnborg 		myname = modname;
109040fcc81SSam Ravnborg 
110741f98feSSam Ravnborg 	return (strcmp(myname, "vmlinux") == 0) ||
111741f98feSSam Ravnborg 	       (strcmp(myname, "vmlinux.o") == 0);
112040fcc81SSam Ravnborg }
113040fcc81SSam Ravnborg 
1141da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr)
1151da177e4SLinus Torvalds {
116df578e7dSSam Ravnborg 	if (!ptr)
1171da177e4SLinus Torvalds 		fatal("modpost: Memory allocation failure: %s.\n", expr);
118df578e7dSSam Ravnborg 
1191da177e4SLinus Torvalds 	return ptr;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds /* A list of all modules we processed */
1231da177e4SLinus Torvalds static struct module *modules;
1241da177e4SLinus Torvalds 
1258b185743SMasahiro Yamada static struct module *find_module(const char *modname)
1261da177e4SLinus Torvalds {
1271da177e4SLinus Torvalds 	struct module *mod;
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds 	for (mod = modules; mod; mod = mod->next)
1301da177e4SLinus Torvalds 		if (strcmp(mod->name, modname) == 0)
1311da177e4SLinus Torvalds 			break;
1321da177e4SLinus Torvalds 	return mod;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds 
135d4ef1c30SRusty Russell static struct module *new_module(const char *modname)
1361da177e4SLinus Torvalds {
1371da177e4SLinus Torvalds 	struct module *mod;
138d4ef1c30SRusty Russell 	char *p;
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 	mod = NOFAIL(malloc(sizeof(*mod)));
1411da177e4SLinus Torvalds 	memset(mod, 0, sizeof(*mod));
1421da177e4SLinus Torvalds 	p = NOFAIL(strdup(modname));
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	/* strip trailing .o */
145d4ef1c30SRusty Russell 	if (strends(p, ".o")) {
146d4ef1c30SRusty Russell 		p[strlen(p) - 2] = '\0';
147258f7426SFrank Rowand 		mod->is_dot_o = 1;
148258f7426SFrank Rowand 	}
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	/* add to list */
1511da177e4SLinus Torvalds 	mod->name = p;
152b817f6feSSam Ravnborg 	mod->gpl_compatible = -1;
1531da177e4SLinus Torvalds 	mod->next = modules;
1541da177e4SLinus Torvalds 	modules = mod;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	return mod;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds /* A hash of all exported symbols,
1601da177e4SLinus Torvalds  * struct symbol is also used for lists of unresolved symbols */
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds struct symbol {
1651da177e4SLinus Torvalds 	struct symbol *next;
1661da177e4SLinus Torvalds 	struct module *module;
1671da177e4SLinus Torvalds 	unsigned int crc;
1681da177e4SLinus Torvalds 	int crc_valid;
169389eb3f5SMasahiro Yamada 	char *namespace;
1701da177e4SLinus Torvalds 	unsigned int weak:1;
171040fcc81SSam Ravnborg 	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
172040fcc81SSam Ravnborg 	unsigned int kernel:1;     /* 1 if symbol is from kernel
173040fcc81SSam Ravnborg 				    *  (only for external modules) **/
174b6568b1aSRusty Russell 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */
17515bfc234SDenis Efremov 	unsigned int is_static:1;  /* 1 if symbol is not global */
176bd5cbcedSRam Pai 	enum export  export;       /* Type of export */
1771da177e4SLinus Torvalds 	char name[0];
1781da177e4SLinus Torvalds };
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */
1831da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name)
1841da177e4SLinus Torvalds {
1851da177e4SLinus Torvalds 	unsigned value;	/* Used to compute the hash value.  */
1861da177e4SLinus Torvalds 	unsigned   i;	/* Used to cycle through random values. */
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	/* Set the initial value from the key size. */
1891da177e4SLinus Torvalds 	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
1901da177e4SLinus Torvalds 		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 	return (1103515243 * value + 12345);
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds 
1955c3ead8cSSam Ravnborg /**
1965c3ead8cSSam Ravnborg  * Allocate a new symbols for use in the hash of exported symbols or
1975c3ead8cSSam Ravnborg  * the list of unresolved symbols per module
1985c3ead8cSSam Ravnborg  **/
1995c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak,
2005c3ead8cSSam Ravnborg 				   struct symbol *next)
2011da177e4SLinus Torvalds {
2021da177e4SLinus Torvalds 	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
2051da177e4SLinus Torvalds 	strcpy(s->name, name);
2061da177e4SLinus Torvalds 	s->weak = weak;
2071da177e4SLinus Torvalds 	s->next = next;
20815bfc234SDenis Efremov 	s->is_static = 1;
2091da177e4SLinus Torvalds 	return s;
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds /* For the hash of exported symbols */
213bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module,
214bd5cbcedSRam Pai 				 enum export export)
2151da177e4SLinus Torvalds {
2161da177e4SLinus Torvalds 	unsigned int hash;
2171da177e4SLinus Torvalds 	struct symbol *new;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2201da177e4SLinus Torvalds 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2211da177e4SLinus Torvalds 	new->module = module;
222bd5cbcedSRam Pai 	new->export = export;
223040fcc81SSam Ravnborg 	return new;
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds 
2265c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds 	struct symbol *s;
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2311da177e4SLinus Torvalds 	if (name[0] == '.')
2321da177e4SLinus Torvalds 		name++;
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2351da177e4SLinus Torvalds 		if (strcmp(s->name, name) == 0)
2361da177e4SLinus Torvalds 			return s;
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 	return NULL;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
241cb9b55d2SMatthias Maennich static bool contains_namespace(struct namespace_list *list,
242cb9b55d2SMatthias Maennich 			       const char *namespace)
243cb9b55d2SMatthias Maennich {
244cb9b55d2SMatthias Maennich 	struct namespace_list *ns_entry;
245cb9b55d2SMatthias Maennich 
246cb9b55d2SMatthias Maennich 	for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next)
247cb9b55d2SMatthias Maennich 		if (strcmp(ns_entry->namespace, namespace) == 0)
248cb9b55d2SMatthias Maennich 			return true;
249cb9b55d2SMatthias Maennich 
250cb9b55d2SMatthias Maennich 	return false;
251cb9b55d2SMatthias Maennich }
252cb9b55d2SMatthias Maennich 
253cb9b55d2SMatthias Maennich static void add_namespace(struct namespace_list **list, const char *namespace)
254cb9b55d2SMatthias Maennich {
255cb9b55d2SMatthias Maennich 	struct namespace_list *ns_entry;
256cb9b55d2SMatthias Maennich 
257cb9b55d2SMatthias Maennich 	if (!contains_namespace(*list, namespace)) {
258cb9b55d2SMatthias Maennich 		ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
259cb9b55d2SMatthias Maennich 					 strlen(namespace) + 1));
260cb9b55d2SMatthias Maennich 		strcpy(ns_entry->namespace, namespace);
261cb9b55d2SMatthias Maennich 		ns_entry->next = *list;
262cb9b55d2SMatthias Maennich 		*list = ns_entry;
263cb9b55d2SMatthias Maennich 	}
264cb9b55d2SMatthias Maennich }
265cb9b55d2SMatthias Maennich 
266cb9b55d2SMatthias Maennich static bool module_imports_namespace(struct module *module,
267cb9b55d2SMatthias Maennich 				     const char *namespace)
268cb9b55d2SMatthias Maennich {
269cb9b55d2SMatthias Maennich 	return contains_namespace(module->imported_namespaces, namespace);
270cb9b55d2SMatthias Maennich }
271cb9b55d2SMatthias Maennich 
2727a3ee753SMathias Krause static const struct {
273bd5cbcedSRam Pai 	const char *str;
274bd5cbcedSRam Pai 	enum export export;
275bd5cbcedSRam Pai } export_list[] = {
276bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
277c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
278bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
279c96fca21SSam Ravnborg 	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
280bd5cbcedSRam Pai 	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
281bd5cbcedSRam Pai 	{ .str = "(unknown)",                .export = export_unknown },
282bd5cbcedSRam Pai };
283bd5cbcedSRam Pai 
284bd5cbcedSRam Pai 
285bd5cbcedSRam Pai static const char *export_str(enum export ex)
286bd5cbcedSRam Pai {
287bd5cbcedSRam Pai 	return export_list[ex].str;
288bd5cbcedSRam Pai }
289bd5cbcedSRam Pai 
290bd5cbcedSRam Pai static enum export export_no(const char *s)
291bd5cbcedSRam Pai {
292bd5cbcedSRam Pai 	int i;
293df578e7dSSam Ravnborg 
294534b89a9SSam Ravnborg 	if (!s)
295534b89a9SSam Ravnborg 		return export_unknown;
296bd5cbcedSRam Pai 	for (i = 0; export_list[i].export != export_unknown; i++) {
297bd5cbcedSRam Pai 		if (strcmp(export_list[i].str, s) == 0)
298bd5cbcedSRam Pai 			return export_list[i].export;
299bd5cbcedSRam Pai 	}
300bd5cbcedSRam Pai 	return export_unknown;
301bd5cbcedSRam Pai }
302bd5cbcedSRam Pai 
3036124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
3046124c04cSMasahiro Yamada {
3056124c04cSMasahiro Yamada 	return (void *)elf->hdr +
3066124c04cSMasahiro Yamada 		elf->sechdrs[elf->secindex_strings].sh_offset +
3076124c04cSMasahiro Yamada 		sechdr->sh_name;
3086124c04cSMasahiro Yamada }
3096124c04cSMasahiro Yamada 
3106124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex)
3116124c04cSMasahiro Yamada {
3126124c04cSMasahiro Yamada 	return sech_name(elf, &elf->sechdrs[secindex]);
3136124c04cSMasahiro Yamada }
31462a26356SAlessio Igor Bogani 
31562a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
31662a26356SAlessio Igor Bogani 
31762a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
31862a26356SAlessio Igor Bogani {
31962a26356SAlessio Igor Bogani 	const char *secname = sec_name(elf, sec);
32062a26356SAlessio Igor Bogani 
32162a26356SAlessio Igor Bogani 	if (strstarts(secname, "___ksymtab+"))
32262a26356SAlessio Igor Bogani 		return export_plain;
32362a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused+"))
32462a26356SAlessio Igor Bogani 		return export_unused;
32562a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl+"))
32662a26356SAlessio Igor Bogani 		return export_gpl;
32762a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
32862a26356SAlessio Igor Bogani 		return export_unused_gpl;
32962a26356SAlessio Igor Bogani 	else if (strstarts(secname, "___ksymtab_gpl_future+"))
33062a26356SAlessio Igor Bogani 		return export_gpl_future;
33162a26356SAlessio Igor Bogani 	else
33262a26356SAlessio Igor Bogani 		return export_unknown;
33362a26356SAlessio Igor Bogani }
33462a26356SAlessio Igor Bogani 
3351ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
336bd5cbcedSRam Pai {
337bd5cbcedSRam Pai 	if (sec == elf->export_sec)
338bd5cbcedSRam Pai 		return export_plain;
339c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_sec)
340c96fca21SSam Ravnborg 		return export_unused;
341bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_sec)
342bd5cbcedSRam Pai 		return export_gpl;
343c96fca21SSam Ravnborg 	else if (sec == elf->export_unused_gpl_sec)
344c96fca21SSam Ravnborg 		return export_unused_gpl;
345bd5cbcedSRam Pai 	else if (sec == elf->export_gpl_future_sec)
346bd5cbcedSRam Pai 		return export_gpl_future;
347bd5cbcedSRam Pai 	else
348bd5cbcedSRam Pai 		return export_unknown;
349bd5cbcedSRam Pai }
350bd5cbcedSRam Pai 
351*69923208SMatthias Maennich static const char *namespace_from_kstrtabns(struct elf_info *info,
352*69923208SMatthias Maennich 					    Elf_Sym *kstrtabns)
353cb9b55d2SMatthias Maennich {
354*69923208SMatthias Maennich 	char *value = info->ksymtab_strings + kstrtabns->st_value;
355*69923208SMatthias Maennich 	return value[0] ? value : NULL;
356cb9b55d2SMatthias Maennich }
357cb9b55d2SMatthias Maennich 
358a2b11184SMatthias Maennich static void sym_update_namespace(const char *symname, const char *namespace)
359a2b11184SMatthias Maennich {
360a2b11184SMatthias Maennich 	struct symbol *s = find_symbol(symname);
361a2b11184SMatthias Maennich 
362a2b11184SMatthias Maennich 	/*
363a2b11184SMatthias Maennich 	 * That symbol should have been created earlier and thus this is
364a2b11184SMatthias Maennich 	 * actually an assertion.
365a2b11184SMatthias Maennich 	 */
366a2b11184SMatthias Maennich 	if (!s) {
367a2b11184SMatthias Maennich 		merror("Could not update namespace(%s) for symbol %s\n",
368a2b11184SMatthias Maennich 		       namespace, symname);
369a2b11184SMatthias Maennich 		return;
370a2b11184SMatthias Maennich 	}
371a2b11184SMatthias Maennich 
372a2b11184SMatthias Maennich 	free(s->namespace);
373a2b11184SMatthias Maennich 	s->namespace =
374a2b11184SMatthias Maennich 		namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
375a2b11184SMatthias Maennich }
376a2b11184SMatthias Maennich 
3775c3ead8cSSam Ravnborg /**
3785c3ead8cSSam Ravnborg  * Add an exported symbol - it may have already been added without a
3795c3ead8cSSam Ravnborg  * CRC, in this case just update the CRC
3805c3ead8cSSam Ravnborg  **/
3819ae5bd18SMatthias Maennich static struct symbol *sym_add_exported(const char *name, struct module *mod,
3829ae5bd18SMatthias Maennich 				       enum export export)
3831da177e4SLinus Torvalds {
3841da177e4SLinus Torvalds 	struct symbol *s = find_symbol(name);
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	if (!s) {
387bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
3888e70c458SSam Ravnborg 	} else {
3898e70c458SSam Ravnborg 		if (!s->preloaded) {
390cb9b55d2SMatthias Maennich 			warn("%s: '%s' exported twice. Previous export was in %s%s\n",
391cb9b55d2SMatthias Maennich 			     mod->name, name, s->module->name,
3928e70c458SSam Ravnborg 			     is_vmlinux(s->module->name) ? "" : ".ko");
3934b21960fSTrent Piepho 		} else {
394baec30e4SPaul Bolle 			/* In case Module.symvers was out of date */
3954b21960fSTrent Piepho 			s->module = mod;
3961da177e4SLinus Torvalds 		}
3971da177e4SLinus Torvalds 	}
3988e70c458SSam Ravnborg 	s->preloaded = 0;
399040fcc81SSam Ravnborg 	s->vmlinux   = is_vmlinux(mod->name);
400040fcc81SSam Ravnborg 	s->kernel    = 0;
401bd5cbcedSRam Pai 	s->export    = export;
402040fcc81SSam Ravnborg 	return s;
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds 
405040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod,
406bd5cbcedSRam Pai 			   unsigned int crc, enum export export)
407040fcc81SSam Ravnborg {
408040fcc81SSam Ravnborg 	struct symbol *s = find_symbol(name);
409040fcc81SSam Ravnborg 
410b6568b1aSRusty Russell 	if (!s) {
411bd5cbcedSRam Pai 		s = new_symbol(name, mod, export);
412b6568b1aSRusty Russell 		/* Don't complain when we find it later. */
413b6568b1aSRusty Russell 		s->preloaded = 1;
414b6568b1aSRusty Russell 	}
415040fcc81SSam Ravnborg 	s->crc = crc;
4161da177e4SLinus Torvalds 	s->crc_valid = 1;
4171da177e4SLinus Torvalds }
4181da177e4SLinus Torvalds 
4195c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size)
4201da177e4SLinus Torvalds {
4211da177e4SLinus Torvalds 	struct stat st;
422eb3d5cc6SJesper Juhl 	void *map = MAP_FAILED;
4231da177e4SLinus Torvalds 	int fd;
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	fd = open(filename, O_RDONLY);
426eb3d5cc6SJesper Juhl 	if (fd < 0)
4271da177e4SLinus Torvalds 		return NULL;
428eb3d5cc6SJesper Juhl 	if (fstat(fd, &st))
429eb3d5cc6SJesper Juhl 		goto failed;
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 	*size = st.st_size;
4321da177e4SLinus Torvalds 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
4331da177e4SLinus Torvalds 
434eb3d5cc6SJesper Juhl failed:
435eb3d5cc6SJesper Juhl 	close(fd);
4361da177e4SLinus Torvalds 	if (map == MAP_FAILED)
4371da177e4SLinus Torvalds 		return NULL;
4381da177e4SLinus Torvalds 	return map;
4391da177e4SLinus Torvalds }
4401da177e4SLinus Torvalds 
4415c3ead8cSSam Ravnborg /**
4425c3ead8cSSam Ravnborg   * Return a copy of the next line in a mmap'ed file.
4435c3ead8cSSam Ravnborg   * spaces in the beginning of the line is trimmed away.
4445c3ead8cSSam Ravnborg   * Return a pointer to a static buffer.
4455c3ead8cSSam Ravnborg   **/
4465c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size)
4471da177e4SLinus Torvalds {
4481da177e4SLinus Torvalds 	static char line[4096];
4491da177e4SLinus Torvalds 	int skip = 1;
4501da177e4SLinus Torvalds 	size_t len = 0;
4511da177e4SLinus Torvalds 	signed char *p = (signed char *)file + *pos;
4521da177e4SLinus Torvalds 	char *s = line;
4531da177e4SLinus Torvalds 
454df578e7dSSam Ravnborg 	for (; *pos < size ; (*pos)++) {
4551da177e4SLinus Torvalds 		if (skip && isspace(*p)) {
4561da177e4SLinus Torvalds 			p++;
4571da177e4SLinus Torvalds 			continue;
4581da177e4SLinus Torvalds 		}
4591da177e4SLinus Torvalds 		skip = 0;
4601da177e4SLinus Torvalds 		if (*p != '\n' && (*pos < size)) {
4611da177e4SLinus Torvalds 			len++;
4621da177e4SLinus Torvalds 			*s++ = *p++;
4631da177e4SLinus Torvalds 			if (len > 4095)
4641da177e4SLinus Torvalds 				break; /* Too long, stop */
4651da177e4SLinus Torvalds 		} else {
4661da177e4SLinus Torvalds 			/* End of string */
4671da177e4SLinus Torvalds 			*s = '\0';
4681da177e4SLinus Torvalds 			return line;
4691da177e4SLinus Torvalds 		}
4701da177e4SLinus Torvalds 	}
4711da177e4SLinus Torvalds 	/* End of buffer */
4721da177e4SLinus Torvalds 	return NULL;
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds 
4755c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size)
4761da177e4SLinus Torvalds {
4771da177e4SLinus Torvalds 	munmap(file, size);
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds 
48085bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename)
4811da177e4SLinus Torvalds {
4821da177e4SLinus Torvalds 	unsigned int i;
48385bd2fddSSam Ravnborg 	Elf_Ehdr *hdr;
4841da177e4SLinus Torvalds 	Elf_Shdr *sechdrs;
4851da177e4SLinus Torvalds 	Elf_Sym  *sym;
4861ce53adfSDenys Vlasenko 	const char *secstrings;
4871ce53adfSDenys Vlasenko 	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 	hdr = grab_file(filename, &info->size);
4901da177e4SLinus Torvalds 	if (!hdr) {
491eed380f3SGuenter Roeck 		if (ignore_missing_files) {
492eed380f3SGuenter Roeck 			fprintf(stderr, "%s: %s (ignored)\n", filename,
493eed380f3SGuenter Roeck 				strerror(errno));
494eed380f3SGuenter Roeck 			return 0;
495eed380f3SGuenter Roeck 		}
4961da177e4SLinus Torvalds 		perror(filename);
4976803dc0eSSam Ravnborg 		exit(1);
4981da177e4SLinus Torvalds 	}
4991da177e4SLinus Torvalds 	info->hdr = hdr;
50085bd2fddSSam Ravnborg 	if (info->size < sizeof(*hdr)) {
50185bd2fddSSam Ravnborg 		/* file too small, assume this is an empty .o file */
50285bd2fddSSam Ravnborg 		return 0;
50385bd2fddSSam Ravnborg 	}
50485bd2fddSSam Ravnborg 	/* Is this a valid ELF file? */
50585bd2fddSSam Ravnborg 	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
50685bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
50785bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
50885bd2fddSSam Ravnborg 	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
50985bd2fddSSam Ravnborg 		/* Not an ELF file - silently ignore it */
51085bd2fddSSam Ravnborg 		return 0;
51185bd2fddSSam Ravnborg 	}
5121da177e4SLinus Torvalds 	/* Fix endianness in ELF header */
513ae4ac123SAtsushi Nemoto 	hdr->e_type      = TO_NATIVE(hdr->e_type);
5147d875a02SAnders Kaseorg 	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
5157d875a02SAnders Kaseorg 	hdr->e_version   = TO_NATIVE(hdr->e_version);
5167d875a02SAnders Kaseorg 	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
5177d875a02SAnders Kaseorg 	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
5187d875a02SAnders Kaseorg 	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
5197d875a02SAnders Kaseorg 	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
5207d875a02SAnders Kaseorg 	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
5217d875a02SAnders Kaseorg 	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
5227d875a02SAnders Kaseorg 	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
5237d875a02SAnders Kaseorg 	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
5247d875a02SAnders Kaseorg 	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
5257d875a02SAnders Kaseorg 	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
5261da177e4SLinus Torvalds 	sechdrs = (void *)hdr + hdr->e_shoff;
5271da177e4SLinus Torvalds 	info->sechdrs = sechdrs;
5281da177e4SLinus Torvalds 
529a83710e5SPetr Stetiar 	/* Check if file offset is correct */
530a83710e5SPetr Stetiar 	if (hdr->e_shoff > info->size) {
531df578e7dSSam Ravnborg 		fatal("section header offset=%lu in file '%s' is bigger than "
532df578e7dSSam Ravnborg 		      "filesize=%lu\n", (unsigned long)hdr->e_shoff,
533df578e7dSSam Ravnborg 		      filename, info->size);
534a83710e5SPetr Stetiar 		return 0;
535a83710e5SPetr Stetiar 	}
536a83710e5SPetr Stetiar 
5376845756bSAnders Kaseorg 	if (hdr->e_shnum == SHN_UNDEF) {
5381ce53adfSDenys Vlasenko 		/*
5391ce53adfSDenys Vlasenko 		 * There are more than 64k sections,
5401ce53adfSDenys Vlasenko 		 * read count from .sh_size.
5411ce53adfSDenys Vlasenko 		 */
5421ce53adfSDenys Vlasenko 		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
5431ce53adfSDenys Vlasenko 	}
5441ce53adfSDenys Vlasenko 	else {
5451ce53adfSDenys Vlasenko 		info->num_sections = hdr->e_shnum;
5461ce53adfSDenys Vlasenko 	}
5471ce53adfSDenys Vlasenko 	if (hdr->e_shstrndx == SHN_XINDEX) {
5486845756bSAnders Kaseorg 		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
5491ce53adfSDenys Vlasenko 	}
5501ce53adfSDenys Vlasenko 	else {
5511ce53adfSDenys Vlasenko 		info->secindex_strings = hdr->e_shstrndx;
5521ce53adfSDenys Vlasenko 	}
5531ce53adfSDenys Vlasenko 
5541da177e4SLinus Torvalds 	/* Fix endianness in section headers */
5551ce53adfSDenys Vlasenko 	for (i = 0; i < info->num_sections; i++) {
5567d875a02SAnders Kaseorg 		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
5571da177e4SLinus Torvalds 		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
5587d875a02SAnders Kaseorg 		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
5597d875a02SAnders Kaseorg 		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5601da177e4SLinus Torvalds 		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5611da177e4SLinus Torvalds 		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5621da177e4SLinus Torvalds 		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
563ae4ac123SAtsushi Nemoto 		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5647d875a02SAnders Kaseorg 		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5657d875a02SAnders Kaseorg 		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5661da177e4SLinus Torvalds 	}
5671da177e4SLinus Torvalds 	/* Find symbol table. */
5681ce53adfSDenys Vlasenko 	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5691ce53adfSDenys Vlasenko 	for (i = 1; i < info->num_sections; i++) {
570bd5cbcedSRam Pai 		const char *secname;
57156fc82c5STejun Heo 		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5721da177e4SLinus Torvalds 
57356fc82c5STejun Heo 		if (!nobits && sechdrs[i].sh_offset > info->size) {
574df578e7dSSam Ravnborg 			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
575df578e7dSSam Ravnborg 			      "sizeof(*hrd)=%zu\n", filename,
576df578e7dSSam Ravnborg 			      (unsigned long)sechdrs[i].sh_offset,
577df578e7dSSam Ravnborg 			      sizeof(*hdr));
57885bd2fddSSam Ravnborg 			return 0;
57985bd2fddSSam Ravnborg 		}
580bd5cbcedSRam Pai 		secname = secstrings + sechdrs[i].sh_name;
581bd5cbcedSRam Pai 		if (strcmp(secname, ".modinfo") == 0) {
58256fc82c5STejun Heo 			if (nobits)
58356fc82c5STejun Heo 				fatal("%s has NOBITS .modinfo\n", filename);
5841da177e4SLinus Torvalds 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5851da177e4SLinus Torvalds 			info->modinfo_len = sechdrs[i].sh_size;
586bd5cbcedSRam Pai 		} else if (strcmp(secname, "__ksymtab") == 0)
587bd5cbcedSRam Pai 			info->export_sec = i;
588c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused") == 0)
589c96fca21SSam Ravnborg 			info->export_unused_sec = i;
590bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl") == 0)
591bd5cbcedSRam Pai 			info->export_gpl_sec = i;
592c96fca21SSam Ravnborg 		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
593c96fca21SSam Ravnborg 			info->export_unused_gpl_sec = i;
594bd5cbcedSRam Pai 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
595bd5cbcedSRam Pai 			info->export_gpl_future_sec = i;
596*69923208SMatthias Maennich 		else if (strcmp(secname, "__ksymtab_strings") == 0)
597*69923208SMatthias Maennich 			info->ksymtab_strings = (void *)hdr +
598*69923208SMatthias Maennich 						sechdrs[i].sh_offset -
599*69923208SMatthias Maennich 						sechdrs[i].sh_addr;
600bd5cbcedSRam Pai 
6011ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
6021ce53adfSDenys Vlasenko 			unsigned int sh_link_idx;
6031ce53adfSDenys Vlasenko 			symtab_idx = i;
6041ce53adfSDenys Vlasenko 			info->symtab_start = (void *)hdr +
6051ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
6061ce53adfSDenys Vlasenko 			info->symtab_stop  = (void *)hdr +
6071ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6086845756bSAnders Kaseorg 			sh_link_idx = sechdrs[i].sh_link;
6091da177e4SLinus Torvalds 			info->strtab       = (void *)hdr +
6101ce53adfSDenys Vlasenko 			    sechdrs[sh_link_idx].sh_offset;
6111ce53adfSDenys Vlasenko 		}
6121ce53adfSDenys Vlasenko 
6131ce53adfSDenys Vlasenko 		/* 32bit section no. table? ("more than 64k sections") */
6141ce53adfSDenys Vlasenko 		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
6151ce53adfSDenys Vlasenko 			symtab_shndx_idx = i;
6161ce53adfSDenys Vlasenko 			info->symtab_shndx_start = (void *)hdr +
6171ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset;
6181ce53adfSDenys Vlasenko 			info->symtab_shndx_stop  = (void *)hdr +
6191ce53adfSDenys Vlasenko 			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6201ce53adfSDenys Vlasenko 		}
6211da177e4SLinus Torvalds 	}
622df578e7dSSam Ravnborg 	if (!info->symtab_start)
623cb80514dSSam Ravnborg 		fatal("%s has no symtab?\n", filename);
624df578e7dSSam Ravnborg 
6251da177e4SLinus Torvalds 	/* Fix endianness in symbols */
6261da177e4SLinus Torvalds 	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
6271da177e4SLinus Torvalds 		sym->st_shndx = TO_NATIVE(sym->st_shndx);
6281da177e4SLinus Torvalds 		sym->st_name  = TO_NATIVE(sym->st_name);
6291da177e4SLinus Torvalds 		sym->st_value = TO_NATIVE(sym->st_value);
6301da177e4SLinus Torvalds 		sym->st_size  = TO_NATIVE(sym->st_size);
6311da177e4SLinus Torvalds 	}
6321ce53adfSDenys Vlasenko 
6331ce53adfSDenys Vlasenko 	if (symtab_shndx_idx != ~0U) {
6341ce53adfSDenys Vlasenko 		Elf32_Word *p;
6356845756bSAnders Kaseorg 		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
6361ce53adfSDenys Vlasenko 			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
6376845756bSAnders Kaseorg 			      filename, sechdrs[symtab_shndx_idx].sh_link,
6381ce53adfSDenys Vlasenko 			      symtab_idx);
6391ce53adfSDenys Vlasenko 		/* Fix endianness */
6401ce53adfSDenys Vlasenko 		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
6411ce53adfSDenys Vlasenko 		     p++)
6421ce53adfSDenys Vlasenko 			*p = TO_NATIVE(*p);
6431ce53adfSDenys Vlasenko 	}
6441ce53adfSDenys Vlasenko 
64585bd2fddSSam Ravnborg 	return 1;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds 
6485c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info)
6491da177e4SLinus Torvalds {
6501da177e4SLinus Torvalds 	release_file(info->hdr, info->size);
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds 
6534d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname)
6544d7365d6SSam Ravnborg {
6554d7365d6SSam Ravnborg 	/* ignore __this_module, it will be resolved shortly */
656b2c5cdcfSMasahiro Yamada 	if (strcmp(symname, "__this_module") == 0)
6574d7365d6SSam Ravnborg 		return 1;
6584d7365d6SSam Ravnborg 	/* ignore global offset table */
6594d7365d6SSam Ravnborg 	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
6604d7365d6SSam Ravnborg 		return 1;
6614d7365d6SSam Ravnborg 	if (info->hdr->e_machine == EM_PPC)
6624d7365d6SSam Ravnborg 		/* Special register function linked on all modules during final link of .ko */
663d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr_") ||
664d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr_") ||
665d62c4765SMasahiro Yamada 		    strstarts(symname, "_rest32gpr_") ||
666d62c4765SMasahiro Yamada 		    strstarts(symname, "_save32gpr_") ||
667d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
668d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_"))
6694d7365d6SSam Ravnborg 			return 1;
6707fca5dc8SStephen Rothwell 	if (info->hdr->e_machine == EM_PPC64)
6717fca5dc8SStephen Rothwell 		/* Special register function linked on all modules during final link of .ko */
672d62c4765SMasahiro Yamada 		if (strstarts(symname, "_restgpr0_") ||
673d62c4765SMasahiro Yamada 		    strstarts(symname, "_savegpr0_") ||
674d62c4765SMasahiro Yamada 		    strstarts(symname, "_restvr_") ||
675d62c4765SMasahiro Yamada 		    strstarts(symname, "_savevr_") ||
676c153693dSAlan Modra 		    strcmp(symname, ".TOC.") == 0)
6777fca5dc8SStephen Rothwell 			return 1;
6784d7365d6SSam Ravnborg 	/* Do not ignore this symbol */
6794d7365d6SSam Ravnborg 	return 0;
6804d7365d6SSam Ravnborg }
6814d7365d6SSam Ravnborg 
6825c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info,
6831da177e4SLinus Torvalds 			       Elf_Sym *sym, const char *symname)
6841da177e4SLinus Torvalds {
6851da177e4SLinus Torvalds 	unsigned int crc;
68662a26356SAlessio Igor Bogani 	enum export export;
687d8c1eb86SNicholas Piggin 	bool is_crc = false;
688389eb3f5SMasahiro Yamada 	const char *name;
68962a26356SAlessio Igor Bogani 
690258f7426SFrank Rowand 	if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
691d62c4765SMasahiro Yamada 	    strstarts(symname, "__ksymtab"))
69262a26356SAlessio Igor Bogani 		export = export_from_secname(info, get_secindex(info, sym));
69362a26356SAlessio Igor Bogani 	else
69462a26356SAlessio Igor Bogani 		export = export_from_sec(info, get_secindex(info, sym));
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	/* CRC'd symbol */
697d62c4765SMasahiro Yamada 	if (strstarts(symname, "__crc_")) {
698d8c1eb86SNicholas Piggin 		is_crc = true;
6991da177e4SLinus Torvalds 		crc = (unsigned int) sym->st_value;
70056067812SArd Biesheuvel 		if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
70156067812SArd Biesheuvel 			unsigned int *crcp;
70256067812SArd Biesheuvel 
70356067812SArd Biesheuvel 			/* symbol points to the CRC in the ELF object */
70456067812SArd Biesheuvel 			crcp = (void *)info->hdr + sym->st_value +
70556067812SArd Biesheuvel 			       info->sechdrs[sym->st_shndx].sh_offset -
70656067812SArd Biesheuvel 			       (info->hdr->e_type != ET_REL ?
70756067812SArd Biesheuvel 				info->sechdrs[sym->st_shndx].sh_addr : 0);
70854a7151bSFredrik Noring 			crc = TO_NATIVE(*crcp);
70956067812SArd Biesheuvel 		}
710b2c5cdcfSMasahiro Yamada 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
711bd5cbcedSRam Pai 				export);
7121da177e4SLinus Torvalds 	}
713b5064654SAndi Kleen 
714b5064654SAndi Kleen 	switch (sym->st_shndx) {
715b5064654SAndi Kleen 	case SHN_COMMON:
716d62c4765SMasahiro Yamada 		if (strstarts(symname, "__gnu_lto_")) {
717ef178f92SAndi Kleen 			/* Should warn here, but modpost runs before the linker */
718ef178f92SAndi Kleen 		} else
719b5064654SAndi Kleen 			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
7201da177e4SLinus Torvalds 		break;
7211da177e4SLinus Torvalds 	case SHN_UNDEF:
7221da177e4SLinus Torvalds 		/* undefined symbol */
7231da177e4SLinus Torvalds 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
7241da177e4SLinus Torvalds 		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
7251da177e4SLinus Torvalds 			break;
7264d7365d6SSam Ravnborg 		if (ignore_undef_symbol(info, symname))
7271da177e4SLinus Torvalds 			break;
7288d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
7298d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
7308d529014SBen Colline /* add compatibility with older glibc */
7318d529014SBen Colline #ifndef STT_SPARC_REGISTER
7328d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER
7338d529014SBen Colline #endif
7341da177e4SLinus Torvalds 		if (info->hdr->e_machine == EM_SPARC ||
7351da177e4SLinus Torvalds 		    info->hdr->e_machine == EM_SPARCV9) {
7361da177e4SLinus Torvalds 			/* Ignore register directives. */
7378d529014SBen Colline 			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
7381da177e4SLinus Torvalds 				break;
7397caaeabbSAl Viro 			if (symname[0] == '.') {
7401f3aa900SRandy Dunlap 				char *munged = NOFAIL(strdup(symname));
7417caaeabbSAl Viro 				munged[0] = '_';
7427caaeabbSAl Viro 				munged[1] = toupper(munged[1]);
7437caaeabbSAl Viro 				symname = munged;
7447caaeabbSAl Viro 			}
7451da177e4SLinus Torvalds 		}
7461da177e4SLinus Torvalds #endif
7471da177e4SLinus Torvalds 
748d8c1eb86SNicholas Piggin 		if (is_crc) {
749d8c1eb86SNicholas Piggin 			const char *e = is_vmlinux(mod->name) ?"":".ko";
750b2c5cdcfSMasahiro Yamada 			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
751b2c5cdcfSMasahiro Yamada 			     symname + strlen("__crc_"), mod->name, e);
752d8c1eb86SNicholas Piggin 		}
753b92021b0SRusty Russell 		mod->unres = alloc_symbol(symname,
7541da177e4SLinus Torvalds 					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
7551da177e4SLinus Torvalds 					  mod->unres);
7561da177e4SLinus Torvalds 		break;
7571da177e4SLinus Torvalds 	default:
7581da177e4SLinus Torvalds 		/* All exported symbols */
759d62c4765SMasahiro Yamada 		if (strstarts(symname, "__ksymtab_")) {
760cb9b55d2SMatthias Maennich 			name = symname + strlen("__ksymtab_");
7619ae5bd18SMatthias Maennich 			sym_add_exported(name, mod, export);
7621da177e4SLinus Torvalds 		}
763b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "init_module") == 0)
7641da177e4SLinus Torvalds 			mod->has_init = 1;
765b2c5cdcfSMasahiro Yamada 		if (strcmp(symname, "cleanup_module") == 0)
7661da177e4SLinus Torvalds 			mod->has_cleanup = 1;
7671da177e4SLinus Torvalds 		break;
7681da177e4SLinus Torvalds 	}
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds 
7715c3ead8cSSam Ravnborg /**
7725c3ead8cSSam Ravnborg  * Parse tag=value strings from .modinfo section
7735c3ead8cSSam Ravnborg  **/
7741da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize)
7751da177e4SLinus Torvalds {
7761da177e4SLinus Torvalds 	/* Skip non-zero chars */
7771da177e4SLinus Torvalds 	while (string[0]) {
7781da177e4SLinus Torvalds 		string++;
7791da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7801da177e4SLinus Torvalds 			return NULL;
7811da177e4SLinus Torvalds 	}
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds 	/* Skip any zero padding. */
7841da177e4SLinus Torvalds 	while (!string[0]) {
7851da177e4SLinus Torvalds 		string++;
7861da177e4SLinus Torvalds 		if ((*secsize)-- <= 1)
7871da177e4SLinus Torvalds 			return NULL;
7881da177e4SLinus Torvalds 	}
7891da177e4SLinus Torvalds 	return string;
7901da177e4SLinus Torvalds }
7911da177e4SLinus Torvalds 
792bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag,
793bca2cceeSMasahiro Yamada 			      char *prev)
7941da177e4SLinus Torvalds {
7951da177e4SLinus Torvalds 	char *p;
7961da177e4SLinus Torvalds 	unsigned int taglen = strlen(tag);
797bca2cceeSMasahiro Yamada 	char *modinfo = info->modinfo;
798bca2cceeSMasahiro Yamada 	unsigned long size = info->modinfo_len;
7991da177e4SLinus Torvalds 
800bca2cceeSMasahiro Yamada 	if (prev) {
801bca2cceeSMasahiro Yamada 		size -= prev - modinfo;
802bca2cceeSMasahiro Yamada 		modinfo = next_string(prev, &size);
803b817f6feSSam Ravnborg 	}
804b817f6feSSam Ravnborg 
8051da177e4SLinus Torvalds 	for (p = modinfo; p; p = next_string(p, &size)) {
8061da177e4SLinus Torvalds 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
8071da177e4SLinus Torvalds 			return p + taglen + 1;
8081da177e4SLinus Torvalds 	}
8091da177e4SLinus Torvalds 	return NULL;
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
812bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag)
813b817f6feSSam Ravnborg 
814b817f6feSSam Ravnborg {
815bca2cceeSMasahiro Yamada 	return get_next_modinfo(info, tag, NULL);
816b817f6feSSam Ravnborg }
817b817f6feSSam Ravnborg 
81893684d3bSSam Ravnborg /**
8194c8fbca5SSam Ravnborg  * Test if string s ends in string sub
8204c8fbca5SSam Ravnborg  * return 0 if match
8214c8fbca5SSam Ravnborg  **/
8224c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub)
8234c8fbca5SSam Ravnborg {
8244c8fbca5SSam Ravnborg 	int slen, sublen;
8254c8fbca5SSam Ravnborg 
8264c8fbca5SSam Ravnborg 	if (!s || !sub)
8274c8fbca5SSam Ravnborg 		return 1;
8284c8fbca5SSam Ravnborg 
8294c8fbca5SSam Ravnborg 	slen = strlen(s);
8304c8fbca5SSam Ravnborg 	sublen = strlen(sub);
8314c8fbca5SSam Ravnborg 
8324c8fbca5SSam Ravnborg 	if ((slen == 0) || (sublen == 0))
8334c8fbca5SSam Ravnborg 		return 1;
8344c8fbca5SSam Ravnborg 
8354c8fbca5SSam Ravnborg 	if (sublen > slen)
8364c8fbca5SSam Ravnborg 		return 1;
8374c8fbca5SSam Ravnborg 
8384c8fbca5SSam Ravnborg 	return memcmp(s + slen - sublen, sub, sublen);
8394c8fbca5SSam Ravnborg }
8404c8fbca5SSam Ravnborg 
841ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
842ff13f926SSam Ravnborg {
84358fb0d4fSSam Ravnborg 	if (sym)
844ff13f926SSam Ravnborg 		return elf->strtab + sym->st_name;
84558fb0d4fSSam Ravnborg 	else
846f666751aSSam Ravnborg 		return "(unknown)";
847ff13f926SSam Ravnborg }
848ff13f926SSam Ravnborg 
84910668220SSam Ravnborg /* The pattern is an array of simple patterns.
85010668220SSam Ravnborg  * "foo" will match an exact string equal to "foo"
8516c5bd235SSam Ravnborg  * "*foo" will match a string that ends with "foo"
85210668220SSam Ravnborg  * "foo*" will match a string that begins with "foo"
85309c20c03SPaul Gortmaker  * "*foo*" will match a string that contains "foo"
85410668220SSam Ravnborg  */
8555c725138STrevor Keith static int match(const char *sym, const char * const pat[])
85610668220SSam Ravnborg {
85710668220SSam Ravnborg 	const char *p;
85810668220SSam Ravnborg 	while (*pat) {
85910668220SSam Ravnborg 		p = *pat++;
86010668220SSam Ravnborg 		const char *endp = p + strlen(p) - 1;
86110668220SSam Ravnborg 
86209c20c03SPaul Gortmaker 		/* "*foo*" */
86309c20c03SPaul Gortmaker 		if (*p == '*' && *endp == '*') {
8646f02bdfcSDenis Efremov 			char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
8656f02bdfcSDenis Efremov 			char *here = strstr(sym, bare);
86609c20c03SPaul Gortmaker 
86709c20c03SPaul Gortmaker 			free(bare);
86809c20c03SPaul Gortmaker 			if (here != NULL)
86909c20c03SPaul Gortmaker 				return 1;
87009c20c03SPaul Gortmaker 		}
8716c5bd235SSam Ravnborg 		/* "*foo" */
87209c20c03SPaul Gortmaker 		else if (*p == '*') {
8736c5bd235SSam Ravnborg 			if (strrcmp(sym, p + 1) == 0)
8746c5bd235SSam Ravnborg 				return 1;
8756c5bd235SSam Ravnborg 		}
87610668220SSam Ravnborg 		/* "foo*" */
8776c5bd235SSam Ravnborg 		else if (*endp == '*') {
87810668220SSam Ravnborg 			if (strncmp(sym, p, strlen(p) - 1) == 0)
87910668220SSam Ravnborg 				return 1;
88010668220SSam Ravnborg 		}
88110668220SSam Ravnborg 		/* no wildcards */
88210668220SSam Ravnborg 		else {
88310668220SSam Ravnborg 			if (strcmp(p, sym) == 0)
88410668220SSam Ravnborg 				return 1;
88510668220SSam Ravnborg 		}
88610668220SSam Ravnborg 	}
88710668220SSam Ravnborg 	/* no match */
88810668220SSam Ravnborg 	return 0;
88910668220SSam Ravnborg }
89010668220SSam Ravnborg 
89110668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */
8927a3ee753SMathias Krause static const char *const section_white_list[] =
8934391ed6aSSam Ravnborg {
8944391ed6aSSam Ravnborg 	".comment*",
8954391ed6aSSam Ravnborg 	".debug*",
8964d10c223SChen Gang 	".cranges",		/* sh64 */
8971121584fSH.J. Lu 	".zdebug*",		/* Compressed debug sections. */
898739d875dSDavid Howells 	".GCC.command.line",	/* record-gcc-switches */
8994391ed6aSSam Ravnborg 	".mdebug*",        /* alpha, score, mips etc. */
9004391ed6aSSam Ravnborg 	".pdr",            /* alpha, score, mips etc. */
9014391ed6aSSam Ravnborg 	".stab*",
9024391ed6aSSam Ravnborg 	".note*",
9034391ed6aSSam Ravnborg 	".got*",
9044391ed6aSSam Ravnborg 	".toc*",
905af42e970SMax Filippov 	".xt.prop",				 /* xtensa */
906af42e970SMax Filippov 	".xt.lit",         /* xtensa */
907f2e207f3SVineet Gupta 	".arcextmap*",			/* arc */
908f2e207f3SVineet Gupta 	".gnu.linkonce.arcext*",	/* arc : modules */
909d1189c63SNoam Camus 	".cmem*",			/* EZchip */
910d1189c63SNoam Camus 	".fmt_slot*",			/* EZchip */
911ef178f92SAndi Kleen 	".gnu.lto*",
912e390f9a9SJosh Poimboeuf 	".discard.*",
9134391ed6aSSam Ravnborg 	NULL
9144391ed6aSSam Ravnborg };
91510668220SSam Ravnborg 
916e241a630SSam Ravnborg /*
917b614a697SAnders Kaseorg  * This is used to find sections missing the SHF_ALLOC flag.
918e241a630SSam Ravnborg  * The cause of this is often a section specified in assembler
919b614a697SAnders Kaseorg  * without "ax" / "aw".
920e241a630SSam Ravnborg  */
921b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf,
922b614a697SAnders Kaseorg 			  Elf_Shdr *sechdr)
923e241a630SSam Ravnborg {
924b614a697SAnders Kaseorg 	const char *sec = sech_name(elf, sechdr);
925e241a630SSam Ravnborg 
926b614a697SAnders Kaseorg 	if (sechdr->sh_type == SHT_PROGBITS &&
927b614a697SAnders Kaseorg 	    !(sechdr->sh_flags & SHF_ALLOC) &&
928b614a697SAnders Kaseorg 	    !match(sec, section_white_list)) {
929b614a697SAnders Kaseorg 		warn("%s (%s): unexpected non-allocatable section.\n"
930b614a697SAnders Kaseorg 		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
931e241a630SSam Ravnborg 		     "Note that for example <linux/init.h> contains\n"
932e241a630SSam Ravnborg 		     "section definitions for use in .S files.\n\n",
933e241a630SSam Ravnborg 		     modname, sec);
934e241a630SSam Ravnborg 	}
935e241a630SSam Ravnborg }
936e241a630SSam Ravnborg 
937e241a630SSam Ravnborg 
938e241a630SSam Ravnborg 
939eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \
940a0d8f803SRasmus Villemoes 	".init.setup", ".init.rodata", ".meminit.rodata", \
941a0d8f803SRasmus Villemoes 	".init.data", ".meminit.data"
942eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \
943a0d8f803SRasmus Villemoes 	".exit.data", ".memexit.data"
94410668220SSam Ravnborg 
945eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \
946a0d8f803SRasmus Villemoes 	".init.text", ".meminit.text"
947eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \
948a0d8f803SRasmus Villemoes 	".exit.text", ".memexit.text"
94910668220SSam Ravnborg 
950bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS	\
951a0d8f803SRasmus Villemoes 	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
952a0d8f803SRasmus Villemoes 	".pci_fixup_enable", ".pci_fixup_resume", \
953a0d8f803SRasmus Villemoes 	".pci_fixup_resume_early", ".pci_fixup_suspend"
954bb15d8dbSSebastian Andrzej Siewior 
955e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
956e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
9574a31a229SUwe Kleine-König 
9584a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
9594a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
96010668220SSam Ravnborg 
961a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel"
962157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
9636727ad9eSChris Metcalf 		".kprobes.text", ".cpuidle.text"
96452dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
965673c2c34SChris Metcalf 		".fixup", ".entry.text", ".exception.text", ".text.*", \
966673c2c34SChris Metcalf 		".coldtext"
96710668220SSam Ravnborg 
968fd6c3a8dSJan Beulich #define INIT_SECTIONS      ".init.*"
969fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS  ".meminit.*"
970eb8f6890SSam Ravnborg 
971fd6c3a8dSJan Beulich #define EXIT_SECTIONS      ".exit.*"
972fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS  ".memexit.*"
973eb8f6890SSam Ravnborg 
97452dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
97552dc0595SQuentin Casasnovas 		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
97652dc0595SQuentin Casasnovas 
9776c5bd235SSam Ravnborg /* init data sections */
9787a3ee753SMathias Krause static const char *const init_data_sections[] =
9797a3ee753SMathias Krause 	{ ALL_INIT_DATA_SECTIONS, NULL };
9806c5bd235SSam Ravnborg 
9816c5bd235SSam Ravnborg /* all init sections */
9827a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9836c5bd235SSam Ravnborg 
9846c5bd235SSam Ravnborg /* All init and exit sections (code + data) */
9857a3ee753SMathias Krause static const char *const init_exit_sections[] =
986eb8f6890SSam Ravnborg 	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9876c5bd235SSam Ravnborg 
9884a3893d0SPaul Gortmaker /* all text sections */
9894a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9904a3893d0SPaul Gortmaker 
9916c5bd235SSam Ravnborg /* data section */
9927a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL };
9936c5bd235SSam Ravnborg 
9946c5bd235SSam Ravnborg 
9956c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */
996af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST					\
997af92a82dSUwe Kleine-König 	"*driver",							\
998af92a82dSUwe Kleine-König 	"*_template", /* scsi uses *_template a lot */			\
999af92a82dSUwe Kleine-König 	"*_timer",    /* arm uses ops structures named _timer a lot */	\
1000af92a82dSUwe Kleine-König 	"*_sht",      /* scsi also used *_sht to some extent */		\
1001af92a82dSUwe Kleine-König 	"*_ops",							\
1002af92a82dSUwe Kleine-König 	"*_probe",							\
1003af92a82dSUwe Kleine-König 	"*_probe_one",							\
1004af92a82dSUwe Kleine-König 	"*_console"
10056c5bd235SSam Ravnborg 
10067a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL };
10077a3ee753SMathias Krause static const char *const linker_symbols[] =
10086c5bd235SSam Ravnborg 	{ "__init_begin", "_sinittext", "_einittext", NULL };
10094a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL };
10106c5bd235SSam Ravnborg 
1011588ccd73SSam Ravnborg enum mismatch {
1012bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_INIT,
1013bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_INIT,
1014bbd3f4fbSUwe Kleine-König 	TEXT_TO_ANY_EXIT,
1015bbd3f4fbSUwe Kleine-König 	DATA_TO_ANY_EXIT,
1016bbd3f4fbSUwe Kleine-König 	XXXINIT_TO_SOME_INIT,
1017bbd3f4fbSUwe Kleine-König 	XXXEXIT_TO_SOME_EXIT,
1018bbd3f4fbSUwe Kleine-König 	ANY_INIT_TO_ANY_EXIT,
1019bbd3f4fbSUwe Kleine-König 	ANY_EXIT_TO_ANY_INIT,
1020588ccd73SSam Ravnborg 	EXPORT_TO_INIT_EXIT,
102152dc0595SQuentin Casasnovas 	EXTABLE_TO_NON_TEXT,
1022588ccd73SSam Ravnborg };
1023588ccd73SSam Ravnborg 
1024e5d8f59aSQuentin Casasnovas /**
1025e5d8f59aSQuentin Casasnovas  * Describe how to match sections on different criterias:
1026e5d8f59aSQuentin Casasnovas  *
1027e5d8f59aSQuentin Casasnovas  * @fromsec: Array of sections to be matched.
1028e5d8f59aSQuentin Casasnovas  *
1029e5d8f59aSQuentin Casasnovas  * @bad_tosec: Relocations applied to a section in @fromsec to a section in
1030e5d8f59aSQuentin Casasnovas  * this array is forbidden (black-list).  Can be empty.
1031e5d8f59aSQuentin Casasnovas  *
1032e5d8f59aSQuentin Casasnovas  * @good_tosec: Relocations applied to a section in @fromsec must be
1033e5d8f59aSQuentin Casasnovas  * targetting sections in this array (white-list).  Can be empty.
1034e5d8f59aSQuentin Casasnovas  *
1035e5d8f59aSQuentin Casasnovas  * @mismatch: Type of mismatch.
1036e5d8f59aSQuentin Casasnovas  *
1037e5d8f59aSQuentin Casasnovas  * @symbol_white_list: Do not match a relocation to a symbol in this list
1038e5d8f59aSQuentin Casasnovas  * even if it is targetting a section in @bad_to_sec.
1039e5d8f59aSQuentin Casasnovas  *
1040e5d8f59aSQuentin Casasnovas  * @handler: Specific handler to call when a match is found.  If NULL,
1041e5d8f59aSQuentin Casasnovas  * default_mismatch_handler() will be called.
1042e5d8f59aSQuentin Casasnovas  *
1043e5d8f59aSQuentin Casasnovas  */
104410668220SSam Ravnborg struct sectioncheck {
104510668220SSam Ravnborg 	const char *fromsec[20];
1046050e57fdSQuentin Casasnovas 	const char *bad_tosec[20];
1047050e57fdSQuentin Casasnovas 	const char *good_tosec[20];
1048588ccd73SSam Ravnborg 	enum mismatch mismatch;
1049af92a82dSUwe Kleine-König 	const char *symbol_white_list[20];
1050644e8f14SQuentin Casasnovas 	void (*handler)(const char *modname, struct elf_info *elf,
1051644e8f14SQuentin Casasnovas 			const struct sectioncheck* const mismatch,
1052644e8f14SQuentin Casasnovas 			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
1053644e8f14SQuentin Casasnovas 
105410668220SSam Ravnborg };
105510668220SSam Ravnborg 
105652dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
105752dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
105852dc0595SQuentin Casasnovas 				     Elf_Rela *r, Elf_Sym *sym,
105952dc0595SQuentin Casasnovas 				     const char *fromsec);
106052dc0595SQuentin Casasnovas 
10617a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = {
106210668220SSam Ravnborg /* Do not reference init/exit code/data from
106310668220SSam Ravnborg  * normal code and data
106410668220SSam Ravnborg  */
106510668220SSam Ravnborg {
1066588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1067050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1068bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_INIT,
1069af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1070588ccd73SSam Ravnborg },
1071588ccd73SSam Ravnborg {
1072588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1073050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
1074bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
1075af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1076588ccd73SSam Ravnborg },
1077588ccd73SSam Ravnborg {
10780db25245SUwe Kleine-König 	.fromsec = { DATA_SECTIONS, NULL },
1079050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
10800db25245SUwe Kleine-König 	.mismatch = DATA_TO_ANY_INIT,
10810db25245SUwe Kleine-König 	.symbol_white_list = {
10820db25245SUwe Kleine-König 		"*_template", "*_timer", "*_sht", "*_ops",
10830db25245SUwe Kleine-König 		"*_probe", "*_probe_one", "*_console", NULL
10840db25245SUwe Kleine-König 	},
10850db25245SUwe Kleine-König },
10860db25245SUwe Kleine-König {
1087588ccd73SSam Ravnborg 	.fromsec = { TEXT_SECTIONS, NULL },
1088050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1089bbd3f4fbSUwe Kleine-König 	.mismatch = TEXT_TO_ANY_EXIT,
1090af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1091588ccd73SSam Ravnborg },
1092588ccd73SSam Ravnborg {
1093588ccd73SSam Ravnborg 	.fromsec = { DATA_SECTIONS, NULL },
1094050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1095bbd3f4fbSUwe Kleine-König 	.mismatch = DATA_TO_ANY_EXIT,
1096af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1097eb8f6890SSam Ravnborg },
1098e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */
1099eb8f6890SSam Ravnborg {
11004a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
1101050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1102bbd3f4fbSUwe Kleine-König 	.mismatch = XXXINIT_TO_SOME_INIT,
1103af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1104eb8f6890SSam Ravnborg },
1105e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */
1106eb8f6890SSam Ravnborg {
11074a31a229SUwe Kleine-König 	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
1108050e57fdSQuentin Casasnovas 	.bad_tosec = { EXIT_SECTIONS, NULL },
1109bbd3f4fbSUwe Kleine-König 	.mismatch = XXXEXIT_TO_SOME_EXIT,
1110af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
111110668220SSam Ravnborg },
111210668220SSam Ravnborg /* Do not use exit code/data from init code */
111310668220SSam Ravnborg {
1114eb8f6890SSam Ravnborg 	.fromsec = { ALL_INIT_SECTIONS, NULL },
1115050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
1116bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1117af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
111810668220SSam Ravnborg },
111910668220SSam Ravnborg /* Do not use init code/data from exit code */
112010668220SSam Ravnborg {
1121eb8f6890SSam Ravnborg 	.fromsec = { ALL_EXIT_SECTIONS, NULL },
1122050e57fdSQuentin Casasnovas 	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
1123bbd3f4fbSUwe Kleine-König 	.mismatch = ANY_EXIT_TO_ANY_INIT,
1124af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
112510668220SSam Ravnborg },
1126bb15d8dbSSebastian Andrzej Siewior {
1127bb15d8dbSSebastian Andrzej Siewior 	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
1128050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, NULL },
1129bb15d8dbSSebastian Andrzej Siewior 	.mismatch = ANY_INIT_TO_ANY_EXIT,
1130bb15d8dbSSebastian Andrzej Siewior 	.symbol_white_list = { NULL },
1131bb15d8dbSSebastian Andrzej Siewior },
113210668220SSam Ravnborg /* Do not export init/exit functions or data */
113310668220SSam Ravnborg {
113410668220SSam Ravnborg 	.fromsec = { "__ksymtab*", NULL },
1135050e57fdSQuentin Casasnovas 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1136af92a82dSUwe Kleine-König 	.mismatch = EXPORT_TO_INIT_EXIT,
1137af92a82dSUwe Kleine-König 	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
113852dc0595SQuentin Casasnovas },
113952dc0595SQuentin Casasnovas {
114052dc0595SQuentin Casasnovas 	.fromsec = { "__ex_table", NULL },
114152dc0595SQuentin Casasnovas 	/* If you're adding any new black-listed sections in here, consider
114252dc0595SQuentin Casasnovas 	 * adding a special 'printer' for them in scripts/check_extable.
114352dc0595SQuentin Casasnovas 	 */
114452dc0595SQuentin Casasnovas 	.bad_tosec = { ".altinstr_replacement", NULL },
114552dc0595SQuentin Casasnovas 	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
114652dc0595SQuentin Casasnovas 	.mismatch = EXTABLE_TO_NON_TEXT,
114752dc0595SQuentin Casasnovas 	.handler = extable_mismatch_handler,
114810668220SSam Ravnborg }
114910668220SSam Ravnborg };
115010668220SSam Ravnborg 
11510d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch(
11520d2a636eSUwe Kleine-König 		const char *fromsec, const char *tosec)
115310668220SSam Ravnborg {
115410668220SSam Ravnborg 	int i;
115510668220SSam Ravnborg 	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
115610668220SSam Ravnborg 	const struct sectioncheck *check = &sectioncheck[0];
115710668220SSam Ravnborg 
1158c5c3439aSQuentin Casasnovas 	/*
1159c5c3439aSQuentin Casasnovas 	 * The target section could be the SHT_NUL section when we're
1160c5c3439aSQuentin Casasnovas 	 * handling relocations to un-resolved symbols, trying to match it
1161739d875dSDavid Howells 	 * doesn't make much sense and causes build failures on parisc
1162739d875dSDavid Howells 	 * architectures.
1163c5c3439aSQuentin Casasnovas 	 */
1164c5c3439aSQuentin Casasnovas 	if (*tosec == '\0')
1165c5c3439aSQuentin Casasnovas 		return NULL;
1166c5c3439aSQuentin Casasnovas 
116710668220SSam Ravnborg 	for (i = 0; i < elems; i++) {
1168050e57fdSQuentin Casasnovas 		if (match(fromsec, check->fromsec)) {
1169050e57fdSQuentin Casasnovas 			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11700d2a636eSUwe Kleine-König 				return check;
1171050e57fdSQuentin Casasnovas 			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
1172050e57fdSQuentin Casasnovas 				return check;
1173050e57fdSQuentin Casasnovas 		}
117410668220SSam Ravnborg 		check++;
117510668220SSam Ravnborg 	}
11760d2a636eSUwe Kleine-König 	return NULL;
117710668220SSam Ravnborg }
117810668220SSam Ravnborg 
11794c8fbca5SSam Ravnborg /**
11804c8fbca5SSam Ravnborg  * Whitelist to allow certain references to pass with no warning.
11810e0d314eSSam Ravnborg  *
11824c8fbca5SSam Ravnborg  * Pattern 1:
11834c8fbca5SSam Ravnborg  *   If a module parameter is declared __initdata and permissions=0
11844c8fbca5SSam Ravnborg  *   then this is legal despite the warning generated.
11854c8fbca5SSam Ravnborg  *   We cannot see value of permissions here, so just ignore
11864c8fbca5SSam Ravnborg  *   this pattern.
11874c8fbca5SSam Ravnborg  *   The pattern is identified by:
11884c8fbca5SSam Ravnborg  *   tosec   = .init.data
11899209aed0SSam Ravnborg  *   fromsec = .data*
11904c8fbca5SSam Ravnborg  *   atsym   =__param*
11914c8fbca5SSam Ravnborg  *
11926a841528SRusty Russell  * Pattern 1a:
11936a841528SRusty Russell  *   module_param_call() ops can refer to __init set function if permissions=0
11946a841528SRusty Russell  *   The pattern is identified by:
11956a841528SRusty Russell  *   tosec   = .init.text
11966a841528SRusty Russell  *   fromsec = .data*
11976a841528SRusty Russell  *   atsym   = __param_ops_*
11986a841528SRusty Russell  *
11994c8fbca5SSam Ravnborg  * Pattern 2:
120072ee59b5SRandy Dunlap  *   Many drivers utilise a *driver container with references to
12014c8fbca5SSam Ravnborg  *   add, remove, probe functions etc.
12024c8fbca5SSam Ravnborg  *   the pattern is identified by:
120383cda2bbSSam Ravnborg  *   tosec   = init or exit section
120483cda2bbSSam Ravnborg  *   fromsec = data section
1205df578e7dSSam Ravnborg  *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
1206df578e7dSSam Ravnborg  *           *probe_one, *_console, *_timer
1207ee6a8545SVivek Goyal  *
1208ee6a8545SVivek Goyal  * Pattern 3:
1209c993971fSSam Ravnborg  *   Whitelist all references from .head.text to any init section
12109bf8cb9bSSam Ravnborg  *
12111d8af559SSam Ravnborg  * Pattern 4:
1212ee6a8545SVivek Goyal  *   Some symbols belong to init section but still it is ok to reference
1213ee6a8545SVivek Goyal  *   these from non-init sections as these symbols don't have any memory
1214ee6a8545SVivek Goyal  *   allocated for them and symbol address and value are same. So even
1215ee6a8545SVivek Goyal  *   if init section is freed, its ok to reference those symbols.
1216ee6a8545SVivek Goyal  *   For ex. symbols marking the init section boundaries.
1217ee6a8545SVivek Goyal  *   This pattern is identified by
1218ee6a8545SVivek Goyal  *   refsymname = __init_begin, _sinittext, _einittext
12199bf8cb9bSSam Ravnborg  *
12204a3893d0SPaul Gortmaker  * Pattern 5:
12214a3893d0SPaul Gortmaker  *   GCC may optimize static inlines when fed constant arg(s) resulting
12224a3893d0SPaul Gortmaker  *   in functions like cpumask_empty() -- generating an associated symbol
12234a3893d0SPaul Gortmaker  *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
12244a3893d0SPaul Gortmaker  *   is passed in comes from __init, like say nmi_ipi_mask, we get a
12254a3893d0SPaul Gortmaker  *   meaningless section warning.  May need to add isra symbols too...
12264a3893d0SPaul Gortmaker  *   This pattern is identified by
12274a3893d0SPaul Gortmaker  *   tosec   = init section
12284a3893d0SPaul Gortmaker  *   fromsec = text section
12294a3893d0SPaul Gortmaker  *   refsymname = *.constprop.*
12304a3893d0SPaul Gortmaker  *
1231a4d26f1aSPaul Walmsley  * Pattern 6:
1232a4d26f1aSPaul Walmsley  *   Hide section mismatch warnings for ELF local symbols.  The goal
1233a4d26f1aSPaul Walmsley  *   is to eliminate false positive modpost warnings caused by
1234a4d26f1aSPaul Walmsley  *   compiler-generated ELF local symbol names such as ".LANCHOR1".
1235a4d26f1aSPaul Walmsley  *   Autogenerated symbol names bypass modpost's "Pattern 2"
1236a4d26f1aSPaul Walmsley  *   whitelisting, which relies on pattern-matching against symbol
1237a4d26f1aSPaul Walmsley  *   names to work.  (One situation where gcc can autogenerate ELF
1238a4d26f1aSPaul Walmsley  *   local symbols is when "-fsection-anchors" is used.)
12394c8fbca5SSam Ravnborg  **/
1240af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch,
1241af92a82dSUwe Kleine-König 			    const char *fromsec, const char *fromsym,
124258fb0d4fSSam Ravnborg 			    const char *tosec, const char *tosym)
12434c8fbca5SSam Ravnborg {
12444c8fbca5SSam Ravnborg 	/* Check for pattern 1 */
12456c5bd235SSam Ravnborg 	if (match(tosec, init_data_sections) &&
12466c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1247d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param"))
124858fb0d4fSSam Ravnborg 		return 0;
12494c8fbca5SSam Ravnborg 
12506a841528SRusty Russell 	/* Check for pattern 1a */
12516a841528SRusty Russell 	if (strcmp(tosec, ".init.text") == 0 &&
12526a841528SRusty Russell 	    match(fromsec, data_sections) &&
1253d62c4765SMasahiro Yamada 	    strstarts(fromsym, "__param_ops_"))
12546a841528SRusty Russell 		return 0;
12556a841528SRusty Russell 
12564c8fbca5SSam Ravnborg 	/* Check for pattern 2 */
12576c5bd235SSam Ravnborg 	if (match(tosec, init_exit_sections) &&
12586c5bd235SSam Ravnborg 	    match(fromsec, data_sections) &&
1259af92a82dSUwe Kleine-König 	    match(fromsym, mismatch->symbol_white_list))
126058fb0d4fSSam Ravnborg 		return 0;
12614c8fbca5SSam Ravnborg 
12629bf8cb9bSSam Ravnborg 	/* Check for pattern 3 */
12636c5bd235SSam Ravnborg 	if (match(fromsec, head_sections) &&
12646c5bd235SSam Ravnborg 	    match(tosec, init_sections))
126558fb0d4fSSam Ravnborg 		return 0;
1266f8657e1bSVivek Goyal 
12671d8af559SSam Ravnborg 	/* Check for pattern 4 */
126858fb0d4fSSam Ravnborg 	if (match(tosym, linker_symbols))
126993659af1SSam Ravnborg 		return 0;
127058fb0d4fSSam Ravnborg 
12714a3893d0SPaul Gortmaker 	/* Check for pattern 5 */
12724a3893d0SPaul Gortmaker 	if (match(fromsec, text_sections) &&
12734a3893d0SPaul Gortmaker 	    match(tosec, init_sections) &&
12744a3893d0SPaul Gortmaker 	    match(fromsym, optim_symbols))
12754a3893d0SPaul Gortmaker 		return 0;
12764a3893d0SPaul Gortmaker 
1277a4d26f1aSPaul Walmsley 	/* Check for pattern 6 */
1278a4d26f1aSPaul Walmsley 	if (strstarts(fromsym, ".L"))
1279a4d26f1aSPaul Walmsley 		return 0;
1280a4d26f1aSPaul Walmsley 
128158fb0d4fSSam Ravnborg 	return 1;
12824c8fbca5SSam Ravnborg }
12834c8fbca5SSam Ravnborg 
12845818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str)
12855818c683SSami Tolvanen {
12865818c683SSami Tolvanen 	return str[0] == '$' && strchr("axtd", str[1])
12875818c683SSami Tolvanen 	       && (str[2] == '\0' || str[2] == '.');
12885818c683SSami Tolvanen }
12895818c683SSami Tolvanen 
12905818c683SSami Tolvanen /*
12915818c683SSami Tolvanen  * If there's no name there, ignore it; likewise, ignore it if it's
12925818c683SSami Tolvanen  * one of the magic symbols emitted used by current ARM tools.
12935818c683SSami Tolvanen  *
12945818c683SSami Tolvanen  * Otherwise if find_symbols_between() returns those symbols, they'll
12955818c683SSami Tolvanen  * fail the whitelist tests and cause lots of false alarms ... fixable
12965818c683SSami Tolvanen  * only by merging __exit and __init sections into __text, bloating
12975818c683SSami Tolvanen  * the kernel (which is especially evil on embedded platforms).
12985818c683SSami Tolvanen  */
12995818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
13005818c683SSami Tolvanen {
13015818c683SSami Tolvanen 	const char *name = elf->strtab + sym->st_name;
13025818c683SSami Tolvanen 
13035818c683SSami Tolvanen 	if (!name || !strlen(name))
13045818c683SSami Tolvanen 		return 0;
13055818c683SSami Tolvanen 	return !is_arm_mapping_symbol(name);
13065818c683SSami Tolvanen }
13075818c683SSami Tolvanen 
13084c8fbca5SSam Ravnborg /**
130993684d3bSSam Ravnborg  * Find symbol based on relocation record info.
131093684d3bSSam Ravnborg  * In some cases the symbol supplied is a valid symbol so
131193684d3bSSam Ravnborg  * return refsym. If st_name != 0 we assume this is a valid symbol.
131293684d3bSSam Ravnborg  * In other cases the symbol needs to be looked up in the symbol table
131393684d3bSSam Ravnborg  * based on section and address.
131493684d3bSSam Ravnborg  *  **/
13159ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
131693684d3bSSam Ravnborg 				Elf_Sym *relsym)
131793684d3bSSam Ravnborg {
131893684d3bSSam Ravnborg 	Elf_Sym *sym;
13199ad21c3fSSam Ravnborg 	Elf_Sym *near = NULL;
13209ad21c3fSSam Ravnborg 	Elf64_Sword distance = 20;
13219ad21c3fSSam Ravnborg 	Elf64_Sword d;
13221ce53adfSDenys Vlasenko 	unsigned int relsym_secindex;
132393684d3bSSam Ravnborg 
132493684d3bSSam Ravnborg 	if (relsym->st_name != 0)
132593684d3bSSam Ravnborg 		return relsym;
13261ce53adfSDenys Vlasenko 
13271ce53adfSDenys Vlasenko 	relsym_secindex = get_secindex(elf, relsym);
132893684d3bSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
13291ce53adfSDenys Vlasenko 		if (get_secindex(elf, sym) != relsym_secindex)
133093684d3bSSam Ravnborg 			continue;
1331ae4ac123SAtsushi Nemoto 		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
1332ae4ac123SAtsushi Nemoto 			continue;
13335818c683SSami Tolvanen 		if (!is_valid_name(elf, sym))
13345818c683SSami Tolvanen 			continue;
133593684d3bSSam Ravnborg 		if (sym->st_value == addr)
133693684d3bSSam Ravnborg 			return sym;
13379ad21c3fSSam Ravnborg 		/* Find a symbol nearby - addr are maybe negative */
13389ad21c3fSSam Ravnborg 		d = sym->st_value - addr;
13399ad21c3fSSam Ravnborg 		if (d < 0)
13409ad21c3fSSam Ravnborg 			d = addr - sym->st_value;
13419ad21c3fSSam Ravnborg 		if (d < distance) {
13429ad21c3fSSam Ravnborg 			distance = d;
13439ad21c3fSSam Ravnborg 			near = sym;
134493684d3bSSam Ravnborg 		}
13459ad21c3fSSam Ravnborg 	}
13469ad21c3fSSam Ravnborg 	/* We need a close match */
13479ad21c3fSSam Ravnborg 	if (distance < 20)
13489ad21c3fSSam Ravnborg 		return near;
13499ad21c3fSSam Ravnborg 	else
135093684d3bSSam Ravnborg 		return NULL;
135193684d3bSSam Ravnborg }
135293684d3bSSam Ravnborg 
1353b39927cfSSam Ravnborg /*
135443c74d17SSam Ravnborg  * Find symbols before or equal addr and after addr - in the section sec.
135543c74d17SSam Ravnborg  * If we find two symbols with equal offset prefer one with a valid name.
135643c74d17SSam Ravnborg  * The ELF format may have a better way to detect what type of symbol
135743c74d17SSam Ravnborg  * it is, but this works for now.
1358b39927cfSSam Ravnborg  **/
1359157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
1360157c23c8SSam Ravnborg 				 const char *sec)
1361b39927cfSSam Ravnborg {
1362b39927cfSSam Ravnborg 	Elf_Sym *sym;
1363157c23c8SSam Ravnborg 	Elf_Sym *near = NULL;
1364157c23c8SSam Ravnborg 	Elf_Addr distance = ~0;
1365b39927cfSSam Ravnborg 
1366b39927cfSSam Ravnborg 	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
1367b39927cfSSam Ravnborg 		const char *symsec;
1368b39927cfSSam Ravnborg 
13691ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1370b39927cfSSam Ravnborg 			continue;
13711ce53adfSDenys Vlasenko 		symsec = sec_name(elf, get_secindex(elf, sym));
1372b39927cfSSam Ravnborg 		if (strcmp(symsec, sec) != 0)
1373b39927cfSSam Ravnborg 			continue;
1374da68d61fSDavid Brownell 		if (!is_valid_name(elf, sym))
1375da68d61fSDavid Brownell 			continue;
1376b39927cfSSam Ravnborg 		if (sym->st_value <= addr) {
1377157c23c8SSam Ravnborg 			if ((addr - sym->st_value) < distance) {
1378157c23c8SSam Ravnborg 				distance = addr - sym->st_value;
1379157c23c8SSam Ravnborg 				near = sym;
1380157c23c8SSam Ravnborg 			} else if ((addr - sym->st_value) == distance) {
1381157c23c8SSam Ravnborg 				near = sym;
138243c74d17SSam Ravnborg 			}
1383b39927cfSSam Ravnborg 		}
1384b39927cfSSam Ravnborg 	}
1385157c23c8SSam Ravnborg 	return near;
1386157c23c8SSam Ravnborg }
1387b39927cfSSam Ravnborg 
138858fb0d4fSSam Ravnborg /*
1389588ccd73SSam Ravnborg  * Convert a section name to the function/data attribute
1390588ccd73SSam Ravnborg  * .init.text => __init
1391588ccd73SSam Ravnborg  * .memexitconst => __memconst
1392588ccd73SSam Ravnborg  * etc.
1393cbcf14a9SAndy Shevchenko  *
1394cbcf14a9SAndy Shevchenko  * The memory of returned value has been allocated on a heap. The user of this
1395cbcf14a9SAndy Shevchenko  * method should free it after usage.
1396588ccd73SSam Ravnborg */
1397588ccd73SSam Ravnborg static char *sec2annotation(const char *s)
1398588ccd73SSam Ravnborg {
1399588ccd73SSam Ravnborg 	if (match(s, init_exit_sections)) {
14001f3aa900SRandy Dunlap 		char *p = NOFAIL(malloc(20));
1401588ccd73SSam Ravnborg 		char *r = p;
1402588ccd73SSam Ravnborg 
1403588ccd73SSam Ravnborg 		*p++ = '_';
1404588ccd73SSam Ravnborg 		*p++ = '_';
1405588ccd73SSam Ravnborg 		if (*s == '.')
1406588ccd73SSam Ravnborg 			s++;
1407588ccd73SSam Ravnborg 		while (*s && *s != '.')
1408588ccd73SSam Ravnborg 			*p++ = *s++;
1409588ccd73SSam Ravnborg 		*p = '\0';
1410588ccd73SSam Ravnborg 		if (*s == '.')
1411588ccd73SSam Ravnborg 			s++;
1412588ccd73SSam Ravnborg 		if (strstr(s, "rodata") != NULL)
1413588ccd73SSam Ravnborg 			strcat(p, "const ");
1414588ccd73SSam Ravnborg 		else if (strstr(s, "data") != NULL)
1415588ccd73SSam Ravnborg 			strcat(p, "data ");
1416588ccd73SSam Ravnborg 		else
1417588ccd73SSam Ravnborg 			strcat(p, " ");
1418cbcf14a9SAndy Shevchenko 		return r;
1419588ccd73SSam Ravnborg 	} else {
14201f3aa900SRandy Dunlap 		return NOFAIL(strdup(""));
1421588ccd73SSam Ravnborg 	}
1422588ccd73SSam Ravnborg }
1423588ccd73SSam Ravnborg 
1424588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym)
1425588ccd73SSam Ravnborg {
1426588ccd73SSam Ravnborg 	if (sym)
1427588ccd73SSam Ravnborg 		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
1428588ccd73SSam Ravnborg 	else
1429f666751aSSam Ravnborg 		return -1;
1430588ccd73SSam Ravnborg }
1431588ccd73SSam Ravnborg 
143200759c0eSRandy Dunlap static void print_section_list(const char * const list[20])
143300759c0eSRandy Dunlap {
143400759c0eSRandy Dunlap 	const char *const *s = list;
143500759c0eSRandy Dunlap 
143600759c0eSRandy Dunlap 	while (*s) {
143700759c0eSRandy Dunlap 		fprintf(stderr, "%s", *s);
143800759c0eSRandy Dunlap 		s++;
143900759c0eSRandy Dunlap 		if (*s)
144000759c0eSRandy Dunlap 			fprintf(stderr, ", ");
144100759c0eSRandy Dunlap 	}
144200759c0eSRandy Dunlap 	fprintf(stderr, "\n");
144300759c0eSRandy Dunlap }
144400759c0eSRandy Dunlap 
1445356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
1446356ad538SQuentin Casasnovas {
1447356ad538SQuentin Casasnovas 	switch (is_func) {
1448356ad538SQuentin Casasnovas 	case 0:	*name = "variable"; *name_p = ""; break;
1449356ad538SQuentin Casasnovas 	case 1:	*name = "function"; *name_p = "()"; break;
1450356ad538SQuentin Casasnovas 	default: *name = "(unknown reference)"; *name_p = ""; break;
1451356ad538SQuentin Casasnovas 	}
1452356ad538SQuentin Casasnovas }
1453356ad538SQuentin Casasnovas 
1454588ccd73SSam Ravnborg /*
1455b39927cfSSam Ravnborg  * Print a warning about a section mismatch.
1456b39927cfSSam Ravnborg  * Try to find symbols near it so user can find it.
14574c8fbca5SSam Ravnborg  * Check whitelist before warning - it may be a false positive.
145858fb0d4fSSam Ravnborg  */
14590d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname,
14600d2a636eSUwe Kleine-König 				const struct sectioncheck *mismatch,
146158fb0d4fSSam Ravnborg 				const char *fromsec,
146258fb0d4fSSam Ravnborg 				unsigned long long fromaddr,
146358fb0d4fSSam Ravnborg 				const char *fromsym,
1464588ccd73SSam Ravnborg 				int from_is_func,
1465588ccd73SSam Ravnborg 				const char *tosec, const char *tosym,
1466588ccd73SSam Ravnborg 				int to_is_func)
1467b39927cfSSam Ravnborg {
1468588ccd73SSam Ravnborg 	const char *from, *from_p;
1469588ccd73SSam Ravnborg 	const char *to, *to_p;
147037ed19d5SAlexey Fomenko 	char *prl_from;
147137ed19d5SAlexey Fomenko 	char *prl_to;
1472f666751aSSam Ravnborg 
1473e5f95c8bSSam Ravnborg 	sec_mismatch_count++;
1474e5f95c8bSSam Ravnborg 
1475356ad538SQuentin Casasnovas 	get_pretty_name(from_is_func, &from, &from_p);
1476356ad538SQuentin Casasnovas 	get_pretty_name(to_is_func, &to, &to_p);
1477356ad538SQuentin Casasnovas 
14787c0ac495SGeert Uytterhoeven 	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14797c0ac495SGeert Uytterhoeven 	     "to the %s %s:%s%s\n",
14807c0ac495SGeert Uytterhoeven 	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14817c0ac495SGeert Uytterhoeven 	     tosym, to_p);
1482588ccd73SSam Ravnborg 
14830d2a636eSUwe Kleine-König 	switch (mismatch->mismatch) {
1484bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_INIT:
148537ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
148637ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1487588ccd73SSam Ravnborg 		fprintf(stderr,
1488588ccd73SSam Ravnborg 		"The function %s%s() references\n"
1489588ccd73SSam Ravnborg 		"the %s %s%s%s.\n"
1490588ccd73SSam Ravnborg 		"This is often because %s lacks a %s\n"
1491588ccd73SSam Ravnborg 		"annotation or the annotation of %s is wrong.\n",
149237ed19d5SAlexey Fomenko 		prl_from, fromsym,
149337ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
149437ed19d5SAlexey Fomenko 		fromsym, prl_to, tosym);
149537ed19d5SAlexey Fomenko 		free(prl_from);
149637ed19d5SAlexey Fomenko 		free(prl_to);
1497588ccd73SSam Ravnborg 		break;
1498bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_INIT: {
149937ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1500588ccd73SSam Ravnborg 		fprintf(stderr,
1501588ccd73SSam Ravnborg 		"The variable %s references\n"
1502588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1503588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
15048b8b76c0SSam Ravnborg 		"variable with __init* or __refdata (see linux/init.h) "
1505588ccd73SSam Ravnborg 		"or name the variable:\n",
150637ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
150700759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
150837ed19d5SAlexey Fomenko 		free(prl_to);
1509588ccd73SSam Ravnborg 		break;
151058fb0d4fSSam Ravnborg 	}
1511bbd3f4fbSUwe Kleine-König 	case TEXT_TO_ANY_EXIT:
151237ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1513588ccd73SSam Ravnborg 		fprintf(stderr,
1514588ccd73SSam Ravnborg 		"The function %s() references a %s in an exit section.\n"
1515588ccd73SSam Ravnborg 		"Often the %s %s%s has valid usage outside the exit section\n"
1516588ccd73SSam Ravnborg 		"and the fix is to remove the %sannotation of %s.\n",
151737ed19d5SAlexey Fomenko 		fromsym, to, to, tosym, to_p, prl_to, tosym);
151837ed19d5SAlexey Fomenko 		free(prl_to);
1519588ccd73SSam Ravnborg 		break;
1520bbd3f4fbSUwe Kleine-König 	case DATA_TO_ANY_EXIT: {
152137ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1522588ccd73SSam Ravnborg 		fprintf(stderr,
1523588ccd73SSam Ravnborg 		"The variable %s references\n"
1524588ccd73SSam Ravnborg 		"the %s %s%s%s\n"
1525588ccd73SSam Ravnborg 		"If the reference is valid then annotate the\n"
1526588ccd73SSam Ravnborg 		"variable with __exit* (see linux/init.h) or "
1527588ccd73SSam Ravnborg 		"name the variable:\n",
152837ed19d5SAlexey Fomenko 		fromsym, to, prl_to, tosym, to_p);
152900759c0eSRandy Dunlap 		print_section_list(mismatch->symbol_white_list);
153037ed19d5SAlexey Fomenko 		free(prl_to);
1531588ccd73SSam Ravnborg 		break;
1532588ccd73SSam Ravnborg 	}
1533bbd3f4fbSUwe Kleine-König 	case XXXINIT_TO_SOME_INIT:
1534bbd3f4fbSUwe Kleine-König 	case XXXEXIT_TO_SOME_EXIT:
153537ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
153637ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1537588ccd73SSam Ravnborg 		fprintf(stderr,
1538588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1539588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1540588ccd73SSam Ravnborg 		"If %s is only used by %s then\n"
1541588ccd73SSam Ravnborg 		"annotate %s with a matching annotation.\n",
154237ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
154337ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
1544b1d2675aSGeert Uytterhoeven 		tosym, fromsym, tosym);
154537ed19d5SAlexey Fomenko 		free(prl_from);
154637ed19d5SAlexey Fomenko 		free(prl_to);
1547588ccd73SSam Ravnborg 		break;
1548bbd3f4fbSUwe Kleine-König 	case ANY_INIT_TO_ANY_EXIT:
154937ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
155037ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1551588ccd73SSam Ravnborg 		fprintf(stderr,
1552588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1553588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1554588ccd73SSam Ravnborg 		"This is often seen when error handling "
1555588ccd73SSam Ravnborg 		"in the init function\n"
1556588ccd73SSam Ravnborg 		"uses functionality in the exit path.\n"
1557588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1558588ccd73SSam Ravnborg 		"%s%s so it may be used outside an exit section.\n",
155937ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
156037ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
15615003bab8SAndrew Morton 		prl_to, tosym, to_p);
156237ed19d5SAlexey Fomenko 		free(prl_from);
156337ed19d5SAlexey Fomenko 		free(prl_to);
1564588ccd73SSam Ravnborg 		break;
1565bbd3f4fbSUwe Kleine-König 	case ANY_EXIT_TO_ANY_INIT:
156637ed19d5SAlexey Fomenko 		prl_from = sec2annotation(fromsec);
156737ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1568588ccd73SSam Ravnborg 		fprintf(stderr,
1569588ccd73SSam Ravnborg 		"The %s %s%s%s references\n"
1570588ccd73SSam Ravnborg 		"a %s %s%s%s.\n"
1571588ccd73SSam Ravnborg 		"This is often seen when error handling "
1572588ccd73SSam Ravnborg 		"in the exit function\n"
1573588ccd73SSam Ravnborg 		"uses functionality in the init path.\n"
1574588ccd73SSam Ravnborg 		"The fix is often to remove the %sannotation of\n"
1575588ccd73SSam Ravnborg 		"%s%s so it may be used outside an init section.\n",
157637ed19d5SAlexey Fomenko 		from, prl_from, fromsym, from_p,
157737ed19d5SAlexey Fomenko 		to, prl_to, tosym, to_p,
157837ed19d5SAlexey Fomenko 		prl_to, tosym, to_p);
157937ed19d5SAlexey Fomenko 		free(prl_from);
158037ed19d5SAlexey Fomenko 		free(prl_to);
1581588ccd73SSam Ravnborg 		break;
1582588ccd73SSam Ravnborg 	case EXPORT_TO_INIT_EXIT:
158337ed19d5SAlexey Fomenko 		prl_to = sec2annotation(tosec);
1584588ccd73SSam Ravnborg 		fprintf(stderr,
1585588ccd73SSam Ravnborg 		"The symbol %s is exported and annotated %s\n"
1586588ccd73SSam Ravnborg 		"Fix this by removing the %sannotation of %s "
1587588ccd73SSam Ravnborg 		"or drop the export.\n",
158837ed19d5SAlexey Fomenko 		tosym, prl_to, prl_to, tosym);
158937ed19d5SAlexey Fomenko 		free(prl_to);
1590588ccd73SSam Ravnborg 		break;
159152dc0595SQuentin Casasnovas 	case EXTABLE_TO_NON_TEXT:
159252dc0595SQuentin Casasnovas 		fatal("There's a special handler for this mismatch type, "
159352dc0595SQuentin Casasnovas 		      "we should never get here.");
159452dc0595SQuentin Casasnovas 		break;
1595588ccd73SSam Ravnborg 	}
1596588ccd73SSam Ravnborg 	fprintf(stderr, "\n");
159758fb0d4fSSam Ravnborg }
159858fb0d4fSSam Ravnborg 
1599644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1600644e8f14SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
160158fb0d4fSSam Ravnborg 				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
160258fb0d4fSSam Ravnborg {
160358fb0d4fSSam Ravnborg 	const char *tosec;
1604588ccd73SSam Ravnborg 	Elf_Sym *to;
1605588ccd73SSam Ravnborg 	Elf_Sym *from;
160658fb0d4fSSam Ravnborg 	const char *tosym;
1607588ccd73SSam Ravnborg 	const char *fromsym;
160858fb0d4fSSam Ravnborg 
1609588ccd73SSam Ravnborg 	from = find_elf_symbol2(elf, r->r_offset, fromsec);
1610588ccd73SSam Ravnborg 	fromsym = sym_name(elf, from);
161158fb0d4fSSam Ravnborg 
1612d62c4765SMasahiro Yamada 	if (strstarts(fromsym, "reference___initcall"))
161377ab21adSAndi Kleen 		return;
161477ab21adSAndi Kleen 
1615c7a65e06SQuentin Casasnovas 	tosec = sec_name(elf, get_secindex(elf, sym));
1616c7a65e06SQuentin Casasnovas 	to = find_elf_symbol(elf, r->r_addend, sym);
1617c7a65e06SQuentin Casasnovas 	tosym = sym_name(elf, to);
1618c7a65e06SQuentin Casasnovas 
161958fb0d4fSSam Ravnborg 	/* check whitelist - we may ignore it */
1620af92a82dSUwe Kleine-König 	if (secref_whitelist(mismatch,
1621af92a82dSUwe Kleine-König 			     fromsec, fromsym, tosec, tosym)) {
1622588ccd73SSam Ravnborg 		report_sec_mismatch(modname, mismatch,
1623588ccd73SSam Ravnborg 				    fromsec, r->r_offset, fromsym,
1624588ccd73SSam Ravnborg 				    is_function(from), tosec, tosym,
1625588ccd73SSam Ravnborg 				    is_function(to));
162658fb0d4fSSam Ravnborg 	}
1627b39927cfSSam Ravnborg }
1628644e8f14SQuentin Casasnovas 
162952dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index)
163052dc0595SQuentin Casasnovas {
163152dc0595SQuentin Casasnovas 	if (section_index > elf->num_sections)
163252dc0595SQuentin Casasnovas 		fatal("section_index is outside elf->num_sections!\n");
163352dc0595SQuentin Casasnovas 
163452dc0595SQuentin Casasnovas 	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
163552dc0595SQuentin Casasnovas }
163652dc0595SQuentin Casasnovas 
163752dc0595SQuentin Casasnovas /*
163852dc0595SQuentin Casasnovas  * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
163952dc0595SQuentin Casasnovas  * to know the sizeof(struct exception_table_entry) for the target architecture.
164052dc0595SQuentin Casasnovas  */
164152dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0;
1642e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
164352dc0595SQuentin Casasnovas {
164452dc0595SQuentin Casasnovas 	/*
164552dc0595SQuentin Casasnovas 	 * If we're currently checking the second relocation within __ex_table,
164652dc0595SQuentin Casasnovas 	 * that relocation offset tells us the offsetof(struct
164752dc0595SQuentin Casasnovas 	 * exception_table_entry, fixup) which is equal to sizeof(struct
164852dc0595SQuentin Casasnovas 	 * exception_table_entry) divided by two.  We use that to our advantage
164952dc0595SQuentin Casasnovas 	 * since there's no portable way to get that size as every architecture
165052dc0595SQuentin Casasnovas 	 * seems to go with different sized types.  Not pretty but better than
165152dc0595SQuentin Casasnovas 	 * hard-coding the size for every architecture..
165252dc0595SQuentin Casasnovas 	 */
1653e84048aaSQuentin Casasnovas 	if (!extable_entry_size)
165452dc0595SQuentin Casasnovas 		extable_entry_size = r->r_offset * 2;
165552dc0595SQuentin Casasnovas }
1656e84048aaSQuentin Casasnovas 
165752dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r)
165852dc0595SQuentin Casasnovas {
1659d3df4de7SQuentin Casasnovas 	/*
1660d3df4de7SQuentin Casasnovas 	 * extable_entry_size is only discovered after we've handled the
1661d3df4de7SQuentin Casasnovas 	 * _second_ relocation in __ex_table, so only abort when we're not
1662d3df4de7SQuentin Casasnovas 	 * handling the first reloc and extable_entry_size is zero.
1663d3df4de7SQuentin Casasnovas 	 */
1664d3df4de7SQuentin Casasnovas 	if (r->r_offset && extable_entry_size == 0)
166552dc0595SQuentin Casasnovas 		fatal("extable_entry size hasn't been discovered!\n");
166652dc0595SQuentin Casasnovas 
166752dc0595SQuentin Casasnovas 	return ((r->r_offset == 0) ||
166852dc0595SQuentin Casasnovas 		(r->r_offset % extable_entry_size == 0));
166952dc0595SQuentin Casasnovas }
167052dc0595SQuentin Casasnovas 
1671e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec)			\
1672e84048aaSQuentin Casasnovas 	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
1673e84048aaSQuentin Casasnovas 
167452dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf,
167552dc0595SQuentin Casasnovas 				    const struct sectioncheck* const mismatch,
167652dc0595SQuentin Casasnovas 				    Elf_Rela* r, Elf_Sym* sym,
167752dc0595SQuentin Casasnovas 				    const char* fromsec, const char* tosec)
167852dc0595SQuentin Casasnovas {
167952dc0595SQuentin Casasnovas 	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
168052dc0595SQuentin Casasnovas 	const char* fromsym_name = sym_name(elf, fromsym);
168152dc0595SQuentin Casasnovas 	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
168252dc0595SQuentin Casasnovas 	const char* tosym_name = sym_name(elf, tosym);
168352dc0595SQuentin Casasnovas 	const char* from_pretty_name;
168452dc0595SQuentin Casasnovas 	const char* from_pretty_name_p;
168552dc0595SQuentin Casasnovas 	const char* to_pretty_name;
168652dc0595SQuentin Casasnovas 	const char* to_pretty_name_p;
168752dc0595SQuentin Casasnovas 
168852dc0595SQuentin Casasnovas 	get_pretty_name(is_function(fromsym),
168952dc0595SQuentin Casasnovas 			&from_pretty_name, &from_pretty_name_p);
169052dc0595SQuentin Casasnovas 	get_pretty_name(is_function(tosym),
169152dc0595SQuentin Casasnovas 			&to_pretty_name, &to_pretty_name_p);
169252dc0595SQuentin Casasnovas 
169352dc0595SQuentin Casasnovas 	warn("%s(%s+0x%lx): Section mismatch in reference"
169452dc0595SQuentin Casasnovas 	     " from the %s %s%s to the %s %s:%s%s\n",
169552dc0595SQuentin Casasnovas 	     modname, fromsec, (long)r->r_offset, from_pretty_name,
169652dc0595SQuentin Casasnovas 	     fromsym_name, from_pretty_name_p,
169752dc0595SQuentin Casasnovas 	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
169852dc0595SQuentin Casasnovas 
169952dc0595SQuentin Casasnovas 	if (!match(tosec, mismatch->bad_tosec) &&
170052dc0595SQuentin Casasnovas 	    is_executable_section(elf, get_secindex(elf, sym)))
170152dc0595SQuentin Casasnovas 		fprintf(stderr,
170252dc0595SQuentin Casasnovas 			"The relocation at %s+0x%lx references\n"
170352dc0595SQuentin Casasnovas 			"section \"%s\" which is not in the list of\n"
170452dc0595SQuentin Casasnovas 			"authorized sections.  If you're adding a new section\n"
170552dc0595SQuentin Casasnovas 			"and/or if this reference is valid, add \"%s\" to the\n"
170652dc0595SQuentin Casasnovas 			"list of authorized sections to jump to on fault.\n"
170752dc0595SQuentin Casasnovas 			"This can be achieved by adding \"%s\" to \n"
170852dc0595SQuentin Casasnovas 			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
170952dc0595SQuentin Casasnovas 			fromsec, (long)r->r_offset, tosec, tosec, tosec);
171052dc0595SQuentin Casasnovas }
171152dc0595SQuentin Casasnovas 
171252dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
171352dc0595SQuentin Casasnovas 				     const struct sectioncheck* const mismatch,
171452dc0595SQuentin Casasnovas 				     Elf_Rela* r, Elf_Sym* sym,
171552dc0595SQuentin Casasnovas 				     const char *fromsec)
171652dc0595SQuentin Casasnovas {
171752dc0595SQuentin Casasnovas 	const char* tosec = sec_name(elf, get_secindex(elf, sym));
171852dc0595SQuentin Casasnovas 
171952dc0595SQuentin Casasnovas 	sec_mismatch_count++;
172052dc0595SQuentin Casasnovas 
172146c7dd56SMasahiro Yamada 	report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
172252dc0595SQuentin Casasnovas 
172352dc0595SQuentin Casasnovas 	if (match(tosec, mismatch->bad_tosec))
172452dc0595SQuentin Casasnovas 		fatal("The relocation at %s+0x%lx references\n"
172552dc0595SQuentin Casasnovas 		      "section \"%s\" which is black-listed.\n"
172652dc0595SQuentin Casasnovas 		      "Something is seriously wrong and should be fixed.\n"
172752dc0595SQuentin Casasnovas 		      "You might get more information about where this is\n"
172852dc0595SQuentin Casasnovas 		      "coming from by using scripts/check_extable.sh %s\n",
172952dc0595SQuentin Casasnovas 		      fromsec, (long)r->r_offset, tosec, modname);
173052dc0595SQuentin Casasnovas 	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
173152dc0595SQuentin Casasnovas 		if (is_extable_fault_address(r))
173252dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
173352dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
173452dc0595SQuentin Casasnovas 			      "it is not possible for the kernel to fault\n"
173552dc0595SQuentin Casasnovas 			      "at that address.  Something is seriously wrong\n"
173652dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
173752dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
173852dc0595SQuentin Casasnovas 		else
173952dc0595SQuentin Casasnovas 			fatal("The relocation at %s+0x%lx references\n"
174052dc0595SQuentin Casasnovas 			      "section \"%s\" which is not executable, IOW\n"
174152dc0595SQuentin Casasnovas 			      "the kernel will fault if it ever tries to\n"
174252dc0595SQuentin Casasnovas 			      "jump to it.  Something is seriously wrong\n"
174352dc0595SQuentin Casasnovas 			      "and should be fixed.\n",
174452dc0595SQuentin Casasnovas 			      fromsec, (long)r->r_offset, tosec);
174552dc0595SQuentin Casasnovas 	}
174652dc0595SQuentin Casasnovas }
174752dc0595SQuentin Casasnovas 
1748644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf,
1749644e8f14SQuentin Casasnovas 				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1750644e8f14SQuentin Casasnovas {
17510cad61d7SLuis de Bethencourt 	const char *tosec = sec_name(elf, get_secindex(elf, sym));
1752644e8f14SQuentin Casasnovas 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
1753644e8f14SQuentin Casasnovas 
1754644e8f14SQuentin Casasnovas 	if (mismatch) {
1755644e8f14SQuentin Casasnovas 		if (mismatch->handler)
1756644e8f14SQuentin Casasnovas 			mismatch->handler(modname, elf,  mismatch,
1757644e8f14SQuentin Casasnovas 					  r, sym, fromsec);
1758644e8f14SQuentin Casasnovas 		else
1759644e8f14SQuentin Casasnovas 			default_mismatch_handler(modname, elf, mismatch,
1760644e8f14SQuentin Casasnovas 						 r, sym, fromsec);
1761644e8f14SQuentin Casasnovas 	}
1762b39927cfSSam Ravnborg }
1763b39927cfSSam Ravnborg 
1764ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf,
17655b24c071SSam Ravnborg 				    Elf_Shdr *sechdr, Elf_Rela *r)
1766ae4ac123SAtsushi Nemoto {
1767ae4ac123SAtsushi Nemoto 	Elf_Shdr *sechdrs = elf->sechdrs;
17686845756bSAnders Kaseorg 	int section = sechdr->sh_info;
1769ae4ac123SAtsushi Nemoto 
1770ae4ac123SAtsushi Nemoto 	return (void *)elf->hdr + sechdrs[section].sh_offset +
1771731ece41SOlof Johansson 		r->r_offset;
1772ae4ac123SAtsushi Nemoto }
1773ae4ac123SAtsushi Nemoto 
17745b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1775ae4ac123SAtsushi Nemoto {
1776ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17775b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1778ae4ac123SAtsushi Nemoto 
1779ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1780ae4ac123SAtsushi Nemoto 	case R_386_32:
1781ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location);
1782ae4ac123SAtsushi Nemoto 		break;
1783ae4ac123SAtsushi Nemoto 	case R_386_PC32:
1784ae4ac123SAtsushi Nemoto 		r->r_addend = TO_NATIVE(*location) + 4;
1785ae4ac123SAtsushi Nemoto 		/* For CONFIG_RELOCATABLE=y */
1786ae4ac123SAtsushi Nemoto 		if (elf->hdr->e_type == ET_EXEC)
1787ae4ac123SAtsushi Nemoto 			r->r_addend += r->r_offset;
1788ae4ac123SAtsushi Nemoto 		break;
1789ae4ac123SAtsushi Nemoto 	}
1790ae4ac123SAtsushi Nemoto 	return 0;
1791ae4ac123SAtsushi Nemoto }
1792ae4ac123SAtsushi Nemoto 
17936e2e340bSTony Lindgren #ifndef R_ARM_CALL
17946e2e340bSTony Lindgren #define R_ARM_CALL	28
17956e2e340bSTony Lindgren #endif
17966e2e340bSTony Lindgren #ifndef R_ARM_JUMP24
17976e2e340bSTony Lindgren #define R_ARM_JUMP24	29
17986e2e340bSTony Lindgren #endif
17996e2e340bSTony Lindgren 
1800c9698e5cSDavid A. Long #ifndef	R_ARM_THM_CALL
1801c9698e5cSDavid A. Long #define	R_ARM_THM_CALL		10
1802c9698e5cSDavid A. Long #endif
1803c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP24
1804c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP24	30
1805c9698e5cSDavid A. Long #endif
1806c9698e5cSDavid A. Long #ifndef	R_ARM_THM_JUMP19
1807c9698e5cSDavid A. Long #define	R_ARM_THM_JUMP19	51
1808c9698e5cSDavid A. Long #endif
1809c9698e5cSDavid A. Long 
18105b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
181156a974faSSam Ravnborg {
181256a974faSSam Ravnborg 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
181356a974faSSam Ravnborg 
181456a974faSSam Ravnborg 	switch (r_typ) {
181556a974faSSam Ravnborg 	case R_ARM_ABS32:
181656a974faSSam Ravnborg 		/* From ARM ABI: (S + A) | T */
1817df578e7dSSam Ravnborg 		r->r_addend = (int)(long)
1818df578e7dSSam Ravnborg 			      (elf->symtab_start + ELF_R_SYM(r->r_info));
181956a974faSSam Ravnborg 		break;
182056a974faSSam Ravnborg 	case R_ARM_PC24:
18216e2e340bSTony Lindgren 	case R_ARM_CALL:
18226e2e340bSTony Lindgren 	case R_ARM_JUMP24:
1823c9698e5cSDavid A. Long 	case R_ARM_THM_CALL:
1824c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP24:
1825c9698e5cSDavid A. Long 	case R_ARM_THM_JUMP19:
182656a974faSSam Ravnborg 		/* From ARM ABI: ((S + A) | T) - P */
1827df578e7dSSam Ravnborg 		r->r_addend = (int)(long)(elf->hdr +
18285b24c071SSam Ravnborg 			      sechdr->sh_offset +
18295b24c071SSam Ravnborg 			      (r->r_offset - sechdr->sh_addr));
183056a974faSSam Ravnborg 		break;
183156a974faSSam Ravnborg 	default:
183256a974faSSam Ravnborg 		return 1;
183356a974faSSam Ravnborg 	}
183456a974faSSam Ravnborg 	return 0;
183556a974faSSam Ravnborg }
183656a974faSSam Ravnborg 
18375b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
1838ae4ac123SAtsushi Nemoto {
1839ae4ac123SAtsushi Nemoto 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
18405b24c071SSam Ravnborg 	unsigned int *location = reloc_location(elf, sechdr, r);
1841ae4ac123SAtsushi Nemoto 	unsigned int inst;
1842ae4ac123SAtsushi Nemoto 
1843ae4ac123SAtsushi Nemoto 	if (r_typ == R_MIPS_HI16)
1844ae4ac123SAtsushi Nemoto 		return 1;	/* skip this */
1845ae4ac123SAtsushi Nemoto 	inst = TO_NATIVE(*location);
1846ae4ac123SAtsushi Nemoto 	switch (r_typ) {
1847ae4ac123SAtsushi Nemoto 	case R_MIPS_LO16:
1848ae4ac123SAtsushi Nemoto 		r->r_addend = inst & 0xffff;
1849ae4ac123SAtsushi Nemoto 		break;
1850ae4ac123SAtsushi Nemoto 	case R_MIPS_26:
1851ae4ac123SAtsushi Nemoto 		r->r_addend = (inst & 0x03ffffff) << 2;
1852ae4ac123SAtsushi Nemoto 		break;
1853ae4ac123SAtsushi Nemoto 	case R_MIPS_32:
1854ae4ac123SAtsushi Nemoto 		r->r_addend = inst;
1855ae4ac123SAtsushi Nemoto 		break;
1856ae4ac123SAtsushi Nemoto 	}
1857ae4ac123SAtsushi Nemoto 	return 0;
1858ae4ac123SAtsushi Nemoto }
1859ae4ac123SAtsushi Nemoto 
18605b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf,
186110668220SSam Ravnborg 			 Elf_Shdr *sechdr)
1862b39927cfSSam Ravnborg {
1863b39927cfSSam Ravnborg 	Elf_Sym  *sym;
18645b24c071SSam Ravnborg 	Elf_Rela *rela;
18652c1a51f3SAtsushi Nemoto 	Elf_Rela r;
1866eae07ac6SAtsushi Nemoto 	unsigned int r_sym;
18675b24c071SSam Ravnborg 	const char *fromsec;
18685b24c071SSam Ravnborg 
1869ff13f926SSam Ravnborg 	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18705b24c071SSam Ravnborg 	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18715b24c071SSam Ravnborg 
1872ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
18735b24c071SSam Ravnborg 	fromsec += strlen(".rela");
18745b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1875b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
18765b24c071SSam Ravnborg 		return;
1877e241a630SSam Ravnborg 
1878b39927cfSSam Ravnborg 	for (rela = start; rela < stop; rela++) {
1879b39927cfSSam Ravnborg 		r.r_offset = TO_NATIVE(rela->r_offset);
1880eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1881ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1882ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1883eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
1884eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1885ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1886ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1887eae07ac6SAtsushi Nemoto 		} else {
1888601e7f02SLinus Torvalds 			r.r_info = TO_NATIVE(rela->r_info);
1889eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1890eae07ac6SAtsushi Nemoto 		}
1891eae07ac6SAtsushi Nemoto #else
1892eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rela->r_info);
1893eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1894eae07ac6SAtsushi Nemoto #endif
189593684d3bSSam Ravnborg 		r.r_addend = TO_NATIVE(rela->r_addend);
1896eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
1897b39927cfSSam Ravnborg 		/* Skip special sections */
18981ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
1899b39927cfSSam Ravnborg 			continue;
1900e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rela, fromsec))
1901e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
190258fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19032c1a51f3SAtsushi Nemoto 	}
19045b24c071SSam Ravnborg }
19055b24c071SSam Ravnborg 
19065b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf,
190710668220SSam Ravnborg 			Elf_Shdr *sechdr)
19085b24c071SSam Ravnborg {
19095b24c071SSam Ravnborg 	Elf_Sym *sym;
19102c1a51f3SAtsushi Nemoto 	Elf_Rel *rel;
19115b24c071SSam Ravnborg 	Elf_Rela r;
19125b24c071SSam Ravnborg 	unsigned int r_sym;
19135b24c071SSam Ravnborg 	const char *fromsec;
19145b24c071SSam Ravnborg 
1915ff13f926SSam Ravnborg 	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
19165b24c071SSam Ravnborg 	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
19175b24c071SSam Ravnborg 
1918ff13f926SSam Ravnborg 	fromsec = sech_name(elf, sechdr);
19195b24c071SSam Ravnborg 	fromsec += strlen(".rel");
19205b24c071SSam Ravnborg 	/* if from section (name) is know good then skip it */
1921b614a697SAnders Kaseorg 	if (match(fromsec, section_white_list))
19225b24c071SSam Ravnborg 		return;
19232c1a51f3SAtsushi Nemoto 
19242c1a51f3SAtsushi Nemoto 	for (rel = start; rel < stop; rel++) {
19252c1a51f3SAtsushi Nemoto 		r.r_offset = TO_NATIVE(rel->r_offset);
1926eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64
1927ff13f926SSam Ravnborg 		if (elf->hdr->e_machine == EM_MIPS) {
1928ae4ac123SAtsushi Nemoto 			unsigned int r_typ;
1929eae07ac6SAtsushi Nemoto 			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
1930eae07ac6SAtsushi Nemoto 			r_sym = TO_NATIVE(r_sym);
1931ae4ac123SAtsushi Nemoto 			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1932ae4ac123SAtsushi Nemoto 			r.r_info = ELF64_R_INFO(r_sym, r_typ);
1933eae07ac6SAtsushi Nemoto 		} else {
19342c1a51f3SAtsushi Nemoto 			r.r_info = TO_NATIVE(rel->r_info);
1935eae07ac6SAtsushi Nemoto 			r_sym = ELF_R_SYM(r.r_info);
1936eae07ac6SAtsushi Nemoto 		}
1937eae07ac6SAtsushi Nemoto #else
1938eae07ac6SAtsushi Nemoto 		r.r_info = TO_NATIVE(rel->r_info);
1939eae07ac6SAtsushi Nemoto 		r_sym = ELF_R_SYM(r.r_info);
1940eae07ac6SAtsushi Nemoto #endif
19412c1a51f3SAtsushi Nemoto 		r.r_addend = 0;
1942ff13f926SSam Ravnborg 		switch (elf->hdr->e_machine) {
1943ae4ac123SAtsushi Nemoto 		case EM_386:
19445b24c071SSam Ravnborg 			if (addend_386_rel(elf, sechdr, &r))
1945ae4ac123SAtsushi Nemoto 				continue;
1946ae4ac123SAtsushi Nemoto 			break;
194756a974faSSam Ravnborg 		case EM_ARM:
19485b24c071SSam Ravnborg 			if (addend_arm_rel(elf, sechdr, &r))
194956a974faSSam Ravnborg 				continue;
195056a974faSSam Ravnborg 			break;
1951ae4ac123SAtsushi Nemoto 		case EM_MIPS:
19525b24c071SSam Ravnborg 			if (addend_mips_rel(elf, sechdr, &r))
1953ae4ac123SAtsushi Nemoto 				continue;
1954ae4ac123SAtsushi Nemoto 			break;
1955ae4ac123SAtsushi Nemoto 		}
1956eae07ac6SAtsushi Nemoto 		sym = elf->symtab_start + r_sym;
19572c1a51f3SAtsushi Nemoto 		/* Skip special sections */
19581ce53adfSDenys Vlasenko 		if (is_shndx_special(sym->st_shndx))
19592c1a51f3SAtsushi Nemoto 			continue;
1960e84048aaSQuentin Casasnovas 		if (is_second_extable_reloc(start, rel, fromsec))
1961e84048aaSQuentin Casasnovas 			find_extable_entry_size(fromsec, &r);
196258fb0d4fSSam Ravnborg 		check_section_mismatch(modname, elf, &r, sym, fromsec);
19632c1a51f3SAtsushi Nemoto 	}
1964b39927cfSSam Ravnborg }
19655b24c071SSam Ravnborg 
19665b24c071SSam Ravnborg /**
19675b24c071SSam Ravnborg  * A module includes a number of sections that are discarded
19685b24c071SSam Ravnborg  * either when loaded or when used as built-in.
19695b24c071SSam Ravnborg  * For loaded modules all functions marked __init and all data
1970b595076aSUwe Kleine-König  * marked __initdata will be discarded when the module has been initialized.
19715b24c071SSam Ravnborg  * Likewise for modules used built-in the sections marked __exit
19725b24c071SSam Ravnborg  * are discarded because __exit marked function are supposed to be called
197332be1d22SBen Dooks  * only when a module is unloaded which never happens for built-in modules.
19745b24c071SSam Ravnborg  * The check_sec_ref() function traverses all relocation records
19755b24c071SSam Ravnborg  * to find all references to a section that reference a section that will
19765b24c071SSam Ravnborg  * be discarded and warns about it.
19775b24c071SSam Ravnborg  **/
19785b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname,
197910668220SSam Ravnborg 			  struct elf_info *elf)
19805b24c071SSam Ravnborg {
19815b24c071SSam Ravnborg 	int i;
19825b24c071SSam Ravnborg 	Elf_Shdr *sechdrs = elf->sechdrs;
19835b24c071SSam Ravnborg 
19845b24c071SSam Ravnborg 	/* Walk through all sections */
19851ce53adfSDenys Vlasenko 	for (i = 0; i < elf->num_sections; i++) {
1986b614a697SAnders Kaseorg 		check_section(modname, elf, &elf->sechdrs[i]);
19875b24c071SSam Ravnborg 		/* We want to process only relocation sections and not .init */
19885b24c071SSam Ravnborg 		if (sechdrs[i].sh_type == SHT_RELA)
198910668220SSam Ravnborg 			section_rela(modname, elf, &elf->sechdrs[i]);
19905b24c071SSam Ravnborg 		else if (sechdrs[i].sh_type == SHT_REL)
199110668220SSam Ravnborg 			section_rel(modname, elf, &elf->sechdrs[i]);
1992b39927cfSSam Ravnborg 	}
1993b39927cfSSam Ravnborg }
1994b39927cfSSam Ravnborg 
19957d02b490SAndi Kleen static char *remove_dot(char *s)
19967d02b490SAndi Kleen {
1997fcd38ed0SMichal Nazarewicz 	size_t n = strcspn(s, ".");
19987d02b490SAndi Kleen 
1999fcd38ed0SMichal Nazarewicz 	if (n && s[n]) {
2000fcd38ed0SMichal Nazarewicz 		size_t m = strspn(s + n + 1, "0123456789");
2001fcd38ed0SMichal Nazarewicz 		if (m && (s[n + m] == '.' || s[n + m] == 0))
20027d02b490SAndi Kleen 			s[n] = 0;
20037d02b490SAndi Kleen 	}
20047d02b490SAndi Kleen 	return s;
20057d02b490SAndi Kleen }
20067d02b490SAndi Kleen 
20078b185743SMasahiro Yamada static void read_symbols(const char *modname)
20081da177e4SLinus Torvalds {
20091da177e4SLinus Torvalds 	const char *symname;
20101da177e4SLinus Torvalds 	char *version;
2011b817f6feSSam Ravnborg 	char *license;
2012cb9b55d2SMatthias Maennich 	char *namespace;
20131da177e4SLinus Torvalds 	struct module *mod;
20141da177e4SLinus Torvalds 	struct elf_info info = { };
20151da177e4SLinus Torvalds 	Elf_Sym *sym;
20161da177e4SLinus Torvalds 
201785bd2fddSSam Ravnborg 	if (!parse_elf(&info, modname))
201885bd2fddSSam Ravnborg 		return;
20191da177e4SLinus Torvalds 
20201da177e4SLinus Torvalds 	mod = new_module(modname);
20211da177e4SLinus Torvalds 
20221da177e4SLinus Torvalds 	/* When there's no vmlinux, don't print warnings about
20231da177e4SLinus Torvalds 	 * unresolved symbols (since there'll be too many ;) */
20241da177e4SLinus Torvalds 	if (is_vmlinux(modname)) {
20251da177e4SLinus Torvalds 		have_vmlinux = 1;
20261da177e4SLinus Torvalds 		mod->skip = 1;
20271da177e4SLinus Torvalds 	}
20281da177e4SLinus Torvalds 
2029bca2cceeSMasahiro Yamada 	license = get_modinfo(&info, "license");
2030ba1029c9SRandy Dunlap 	if (!license && !is_vmlinux(modname))
20312fa36568SSam Ravnborg 		warn("modpost: missing MODULE_LICENSE() in %s\n"
2032eed7d279SSam Ravnborg 		     "see include/linux/module.h for "
2033eed7d279SSam Ravnborg 		     "more information\n", modname);
2034b817f6feSSam Ravnborg 	while (license) {
2035b817f6feSSam Ravnborg 		if (license_is_gpl_compatible(license))
2036b817f6feSSam Ravnborg 			mod->gpl_compatible = 1;
2037b817f6feSSam Ravnborg 		else {
2038b817f6feSSam Ravnborg 			mod->gpl_compatible = 0;
2039b817f6feSSam Ravnborg 			break;
2040b817f6feSSam Ravnborg 		}
2041bca2cceeSMasahiro Yamada 		license = get_next_modinfo(&info, "license", license);
2042b817f6feSSam Ravnborg 	}
2043b817f6feSSam Ravnborg 
2044cb9b55d2SMatthias Maennich 	namespace = get_modinfo(&info, "import_ns");
2045cb9b55d2SMatthias Maennich 	while (namespace) {
2046cb9b55d2SMatthias Maennich 		add_namespace(&mod->imported_namespaces, namespace);
2047cb9b55d2SMatthias Maennich 		namespace = get_next_modinfo(&info, "import_ns", namespace);
2048cb9b55d2SMatthias Maennich 	}
2049cb9b55d2SMatthias Maennich 
20501da177e4SLinus Torvalds 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
20517d02b490SAndi Kleen 		symname = remove_dot(info.strtab + sym->st_name);
20521da177e4SLinus Torvalds 
20531da177e4SLinus Torvalds 		handle_modversions(mod, &info, sym, symname);
20541da177e4SLinus Torvalds 		handle_moddevtable(mod, &info, sym, symname);
20551da177e4SLinus Torvalds 	}
205615bfc234SDenis Efremov 
2057*69923208SMatthias Maennich 	/* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
2058*69923208SMatthias Maennich 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
2059*69923208SMatthias Maennich 		symname = remove_dot(info.strtab + sym->st_name);
2060*69923208SMatthias Maennich 
2061*69923208SMatthias Maennich 		if (strstarts(symname, "__kstrtabns_"))
2062*69923208SMatthias Maennich 			sym_update_namespace(symname + strlen("__kstrtabns_"),
2063*69923208SMatthias Maennich 					     namespace_from_kstrtabns(&info,
2064*69923208SMatthias Maennich 								      sym));
2065*69923208SMatthias Maennich 	}
2066*69923208SMatthias Maennich 
206715bfc234SDenis Efremov 	// check for static EXPORT_SYMBOL_* functions && global vars
206815bfc234SDenis Efremov 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
206915bfc234SDenis Efremov 		unsigned char bind = ELF_ST_BIND(sym->st_info);
207015bfc234SDenis Efremov 
207115bfc234SDenis Efremov 		if (bind == STB_GLOBAL || bind == STB_WEAK) {
207215bfc234SDenis Efremov 			struct symbol *s =
207315bfc234SDenis Efremov 				find_symbol(remove_dot(info.strtab +
207415bfc234SDenis Efremov 						       sym->st_name));
207515bfc234SDenis Efremov 
207615bfc234SDenis Efremov 			if (s)
207715bfc234SDenis Efremov 				s->is_static = 0;
207815bfc234SDenis Efremov 		}
207915bfc234SDenis Efremov 	}
208015bfc234SDenis Efremov 
2081074a04f5SMasahiro Yamada 	if (!is_vmlinux(modname) || vmlinux_section_warnings)
208210668220SSam Ravnborg 		check_sec_ref(mod, modname, &info);
20831da177e4SLinus Torvalds 
2084bca2cceeSMasahiro Yamada 	version = get_modinfo(&info, "version");
20851da177e4SLinus Torvalds 	if (version)
20861da177e4SLinus Torvalds 		maybe_frob_rcs_version(modname, version, info.modinfo,
20871da177e4SLinus Torvalds 				       version - (char *)info.hdr);
20881da177e4SLinus Torvalds 	if (version || (all_versions && !is_vmlinux(modname)))
20891da177e4SLinus Torvalds 		get_src_version(modname, mod->srcversion,
20901da177e4SLinus Torvalds 				sizeof(mod->srcversion)-1);
20911da177e4SLinus Torvalds 
20921da177e4SLinus Torvalds 	parse_elf_finish(&info);
20931da177e4SLinus Torvalds 
20948c8ef42aSRusty Russell 	/* Our trick to get versioning for module struct etc. - it's
20951da177e4SLinus Torvalds 	 * never passed as an argument to an exported function, so
20961da177e4SLinus Torvalds 	 * the automatic versioning doesn't pick it up, but it's really
20971da177e4SLinus Torvalds 	 * important anyhow */
20981da177e4SLinus Torvalds 	if (modversions)
20998c8ef42aSRusty Russell 		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
21001da177e4SLinus Torvalds }
21011da177e4SLinus Torvalds 
2102712f9b46SRusty Russell static void read_symbols_from_files(const char *filename)
2103712f9b46SRusty Russell {
2104712f9b46SRusty Russell 	FILE *in = stdin;
2105712f9b46SRusty Russell 	char fname[PATH_MAX];
2106712f9b46SRusty Russell 
2107712f9b46SRusty Russell 	if (strcmp(filename, "-") != 0) {
2108712f9b46SRusty Russell 		in = fopen(filename, "r");
2109712f9b46SRusty Russell 		if (!in)
2110712f9b46SRusty Russell 			fatal("Can't open filenames file %s: %m", filename);
2111712f9b46SRusty Russell 	}
2112712f9b46SRusty Russell 
2113712f9b46SRusty Russell 	while (fgets(fname, PATH_MAX, in) != NULL) {
2114712f9b46SRusty Russell 		if (strends(fname, "\n"))
2115712f9b46SRusty Russell 			fname[strlen(fname)-1] = '\0';
2116712f9b46SRusty Russell 		read_symbols(fname);
2117712f9b46SRusty Russell 	}
2118712f9b46SRusty Russell 
2119712f9b46SRusty Russell 	if (in != stdin)
2120712f9b46SRusty Russell 		fclose(in);
2121712f9b46SRusty Russell }
2122712f9b46SRusty Russell 
21231da177e4SLinus Torvalds #define SZ 500
21241da177e4SLinus Torvalds 
21251da177e4SLinus Torvalds /* We first write the generated file into memory using the
21261da177e4SLinus Torvalds  * following helper, then compare to the file on disk and
21271da177e4SLinus Torvalds  * only update the later if anything changed */
21281da177e4SLinus Torvalds 
21295c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
21305c3ead8cSSam Ravnborg 						      const char *fmt, ...)
21311da177e4SLinus Torvalds {
21321da177e4SLinus Torvalds 	char tmp[SZ];
21331da177e4SLinus Torvalds 	int len;
21341da177e4SLinus Torvalds 	va_list ap;
21351da177e4SLinus Torvalds 
21361da177e4SLinus Torvalds 	va_start(ap, fmt);
21371da177e4SLinus Torvalds 	len = vsnprintf(tmp, SZ, fmt, ap);
21387670f023SSam Ravnborg 	buf_write(buf, tmp, len);
21391da177e4SLinus Torvalds 	va_end(ap);
21401da177e4SLinus Torvalds }
21411da177e4SLinus Torvalds 
21425c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len)
21431da177e4SLinus Torvalds {
21441da177e4SLinus Torvalds 	if (buf->size - buf->pos < len) {
21457670f023SSam Ravnborg 		buf->size += len + SZ;
21461f3aa900SRandy Dunlap 		buf->p = NOFAIL(realloc(buf->p, buf->size));
21471da177e4SLinus Torvalds 	}
21481da177e4SLinus Torvalds 	strncpy(buf->p + buf->pos, s, len);
21491da177e4SLinus Torvalds 	buf->pos += len;
21501da177e4SLinus Torvalds }
21511da177e4SLinus Torvalds 
2152c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
2153c96fca21SSam Ravnborg {
2154c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2155c96fca21SSam Ravnborg 
2156c96fca21SSam Ravnborg 	switch (exp) {
2157c96fca21SSam Ravnborg 	case export_gpl:
2158c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2159c96fca21SSam Ravnborg 		      "uses GPL-only symbol '%s'\n", m, e, s);
2160c96fca21SSam Ravnborg 		break;
2161c96fca21SSam Ravnborg 	case export_unused_gpl:
2162c96fca21SSam Ravnborg 		fatal("modpost: GPL-incompatible module %s%s "
2163c96fca21SSam Ravnborg 		      "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
2164c96fca21SSam Ravnborg 		break;
2165c96fca21SSam Ravnborg 	case export_gpl_future:
2166c96fca21SSam Ravnborg 		warn("modpost: GPL-incompatible module %s%s "
2167c96fca21SSam Ravnborg 		      "uses future GPL-only symbol '%s'\n", m, e, s);
2168c96fca21SSam Ravnborg 		break;
2169c96fca21SSam Ravnborg 	case export_plain:
2170c96fca21SSam Ravnborg 	case export_unused:
2171c96fca21SSam Ravnborg 	case export_unknown:
2172c96fca21SSam Ravnborg 		/* ignore */
2173c96fca21SSam Ravnborg 		break;
2174c96fca21SSam Ravnborg 	}
2175c96fca21SSam Ravnborg }
2176c96fca21SSam Ravnborg 
2177c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s)
2178c96fca21SSam Ravnborg {
2179c96fca21SSam Ravnborg 	const char *e = is_vmlinux(m) ?"":".ko";
2180c96fca21SSam Ravnborg 
2181c96fca21SSam Ravnborg 	switch (exp) {
2182c96fca21SSam Ravnborg 	case export_unused:
2183c96fca21SSam Ravnborg 	case export_unused_gpl:
2184c96fca21SSam Ravnborg 		warn("modpost: module %s%s "
2185c96fca21SSam Ravnborg 		      "uses symbol '%s' marked UNUSED\n", m, e, s);
2186c96fca21SSam Ravnborg 		break;
2187c96fca21SSam Ravnborg 	default:
2188c96fca21SSam Ravnborg 		/* ignore */
2189c96fca21SSam Ravnborg 		break;
2190c96fca21SSam Ravnborg 	}
2191c96fca21SSam Ravnborg }
2192c96fca21SSam Ravnborg 
21933b415288SMasahiro Yamada static int check_exports(struct module *mod)
2194b817f6feSSam Ravnborg {
2195b817f6feSSam Ravnborg 	struct symbol *s, *exp;
21963b415288SMasahiro Yamada 	int err = 0;
2197b817f6feSSam Ravnborg 
2198b817f6feSSam Ravnborg 	for (s = mod->unres; s; s = s->next) {
21996449bd62SAndrew Morton 		const char *basename;
2200b817f6feSSam Ravnborg 		exp = find_symbol(s->name);
22013b415288SMasahiro Yamada 		if (!exp || exp->module == mod) {
22023b415288SMasahiro Yamada 			if (have_vmlinux && !s->weak) {
22033b415288SMasahiro Yamada 				if (warn_unresolved) {
22043b415288SMasahiro Yamada 					warn("\"%s\" [%s.ko] undefined!\n",
22053b415288SMasahiro Yamada 					     s->name, mod->name);
22063b415288SMasahiro Yamada 				} else {
22073b415288SMasahiro Yamada 					merror("\"%s\" [%s.ko] undefined!\n",
22083b415288SMasahiro Yamada 					       s->name, mod->name);
22093b415288SMasahiro Yamada 					err = 1;
22103b415288SMasahiro Yamada 				}
22113b415288SMasahiro Yamada 			}
2212b817f6feSSam Ravnborg 			continue;
22133b415288SMasahiro Yamada 		}
22146449bd62SAndrew Morton 		basename = strrchr(mod->name, '/');
2215b817f6feSSam Ravnborg 		if (basename)
2216b817f6feSSam Ravnborg 			basename++;
2217c96fca21SSam Ravnborg 		else
2218c96fca21SSam Ravnborg 			basename = mod->name;
2219cb9b55d2SMatthias Maennich 
2220a2b11184SMatthias Maennich 		if (exp->namespace) {
22211d082773SMatthias Maennich 			add_namespace(&mod->required_namespaces,
22221d082773SMatthias Maennich 				      exp->namespace);
22231d082773SMatthias Maennich 
22241d082773SMatthias Maennich 			if (!write_namespace_deps &&
2225cb9b55d2SMatthias Maennich 			    !module_imports_namespace(mod, exp->namespace)) {
2226cb9b55d2SMatthias Maennich 				warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
2227cb9b55d2SMatthias Maennich 				     basename, exp->name, exp->namespace);
2228cb9b55d2SMatthias Maennich 			}
22291d082773SMatthias Maennich 		}
2230cb9b55d2SMatthias Maennich 
2231c96fca21SSam Ravnborg 		if (!mod->gpl_compatible)
2232c96fca21SSam Ravnborg 			check_for_gpl_usage(exp->export, basename, exp->name);
2233c96fca21SSam Ravnborg 		check_for_unused(exp->export, basename, exp->name);
2234b817f6feSSam Ravnborg 	}
22353b415288SMasahiro Yamada 
22363b415288SMasahiro Yamada 	return err;
2237b817f6feSSam Ravnborg }
2238b817f6feSSam Ravnborg 
22394fd3e4efSWanlong Gao static int check_modname_len(struct module *mod)
22404fd3e4efSWanlong Gao {
22414fd3e4efSWanlong Gao 	const char *mod_name;
22424fd3e4efSWanlong Gao 
22434fd3e4efSWanlong Gao 	mod_name = strrchr(mod->name, '/');
22444fd3e4efSWanlong Gao 	if (mod_name == NULL)
22454fd3e4efSWanlong Gao 		mod_name = mod->name;
22464fd3e4efSWanlong Gao 	else
22474fd3e4efSWanlong Gao 		mod_name++;
22484fd3e4efSWanlong Gao 	if (strlen(mod_name) >= MODULE_NAME_LEN) {
22494fd3e4efSWanlong Gao 		merror("module name is too long [%s.ko]\n", mod->name);
22504fd3e4efSWanlong Gao 		return 1;
22514fd3e4efSWanlong Gao 	}
22524fd3e4efSWanlong Gao 
22534fd3e4efSWanlong Gao 	return 0;
22544fd3e4efSWanlong Gao }
22554fd3e4efSWanlong Gao 
22565c3ead8cSSam Ravnborg /**
22575c3ead8cSSam Ravnborg  * Header for the generated file
22585c3ead8cSSam Ravnborg  **/
22595c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod)
22601da177e4SLinus Torvalds {
22619afb719eSLaura Abbott 	buf_printf(b, "#include <linux/build-salt.h>\n");
22621da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/module.h>\n");
22631da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/vermagic.h>\n");
22641da177e4SLinus Torvalds 	buf_printf(b, "#include <linux/compiler.h>\n");
22651da177e4SLinus Torvalds 	buf_printf(b, "\n");
22669afb719eSLaura Abbott 	buf_printf(b, "BUILD_SALT;\n");
22679afb719eSLaura Abbott 	buf_printf(b, "\n");
22681da177e4SLinus Torvalds 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
22693e2e857fSKees Cook 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
22701da177e4SLinus Torvalds 	buf_printf(b, "\n");
2271e0f244c6SAndi Kleen 	buf_printf(b, "__visible struct module __this_module\n");
2272a3d0cb04SMasahiro Yamada 	buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
22733c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
22741da177e4SLinus Torvalds 	if (mod->has_init)
22753c7ec94dSGreg Kroah-Hartman 		buf_printf(b, "\t.init = init_module,\n");
22761da177e4SLinus Torvalds 	if (mod->has_cleanup)
22771da177e4SLinus Torvalds 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
22783c7ec94dSGreg Kroah-Hartman 			      "\t.exit = cleanup_module,\n"
22791da177e4SLinus Torvalds 			      "#endif\n");
22803c7ec94dSGreg Kroah-Hartman 	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
22811da177e4SLinus Torvalds 	buf_printf(b, "};\n");
22821da177e4SLinus Torvalds }
22831da177e4SLinus Torvalds 
22842449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree)
22852449b8baSBen Hutchings {
22862449b8baSBen Hutchings 	if (is_intree)
22872449b8baSBen Hutchings 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
22882449b8baSBen Hutchings }
22892449b8baSBen Hutchings 
2290caf7501aSAndi Kleen /* Cannot check for assembler */
2291caf7501aSAndi Kleen static void add_retpoline(struct buffer *b)
2292caf7501aSAndi Kleen {
2293e4f35891SWANG Chao 	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
2294caf7501aSAndi Kleen 	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
2295caf7501aSAndi Kleen 	buf_printf(b, "#endif\n");
2296caf7501aSAndi Kleen }
2297caf7501aSAndi Kleen 
22985c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name)
2299a9860bf0SGreg Kroah-Hartman {
2300d62c4765SMasahiro Yamada 	if (strstarts(name, "drivers/staging"))
2301a9860bf0SGreg Kroah-Hartman 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
2302a9860bf0SGreg Kroah-Hartman }
2303a9860bf0SGreg Kroah-Hartman 
23045c3ead8cSSam Ravnborg /**
23055c3ead8cSSam Ravnborg  * Record CRCs for unresolved symbols
23065c3ead8cSSam Ravnborg  **/
2307c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod)
23081da177e4SLinus Torvalds {
23091da177e4SLinus Torvalds 	struct symbol *s, *exp;
2310c53ddacdSKirill Korotaev 	int err = 0;
23111da177e4SLinus Torvalds 
23121da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
23131da177e4SLinus Torvalds 		exp = find_symbol(s->name);
23143b415288SMasahiro Yamada 		if (!exp || exp->module == mod)
23151da177e4SLinus Torvalds 			continue;
23161da177e4SLinus Torvalds 		s->module = exp->module;
23171da177e4SLinus Torvalds 		s->crc_valid = exp->crc_valid;
23181da177e4SLinus Torvalds 		s->crc = exp->crc;
23191da177e4SLinus Torvalds 	}
23201da177e4SLinus Torvalds 
23211da177e4SLinus Torvalds 	if (!modversions)
2322c53ddacdSKirill Korotaev 		return err;
23231da177e4SLinus Torvalds 
23241da177e4SLinus Torvalds 	buf_printf(b, "\n");
23251da177e4SLinus Torvalds 	buf_printf(b, "static const struct modversion_info ____versions[]\n");
2326a3d0cb04SMasahiro Yamada 	buf_printf(b, "__used __section(__versions) = {\n");
23271da177e4SLinus Torvalds 
23281da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2329df578e7dSSam Ravnborg 		if (!s->module)
23301da177e4SLinus Torvalds 			continue;
23311da177e4SLinus Torvalds 		if (!s->crc_valid) {
2332cb80514dSSam Ravnborg 			warn("\"%s\" [%s.ko] has no CRC!\n",
23331da177e4SLinus Torvalds 				s->name, mod->name);
23341da177e4SLinus Torvalds 			continue;
23351da177e4SLinus Torvalds 		}
23365cfb203aSTakashi Iwai 		if (strlen(s->name) >= MODULE_NAME_LEN) {
23375cfb203aSTakashi Iwai 			merror("too long symbol \"%s\" [%s.ko]\n",
23385cfb203aSTakashi Iwai 			       s->name, mod->name);
23395cfb203aSTakashi Iwai 			err = 1;
23405cfb203aSTakashi Iwai 			break;
23415cfb203aSTakashi Iwai 		}
2342b2c5cdcfSMasahiro Yamada 		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
2343a4b6a77bSJames Hogan 			   s->crc, s->name);
23441da177e4SLinus Torvalds 	}
23451da177e4SLinus Torvalds 
23461da177e4SLinus Torvalds 	buf_printf(b, "};\n");
2347c53ddacdSKirill Korotaev 
2348c53ddacdSKirill Korotaev 	return err;
23491da177e4SLinus Torvalds }
23501da177e4SLinus Torvalds 
2351d2665ca8SMasahiro Yamada static void add_depends(struct buffer *b, struct module *mod)
23521da177e4SLinus Torvalds {
23531da177e4SLinus Torvalds 	struct symbol *s;
23541da177e4SLinus Torvalds 	int first = 1;
23551da177e4SLinus Torvalds 
2356d2665ca8SMasahiro Yamada 	/* Clear ->seen flag of modules that own symbols needed by this. */
2357d2665ca8SMasahiro Yamada 	for (s = mod->unres; s; s = s->next)
2358d2665ca8SMasahiro Yamada 		if (s->module)
2359d2665ca8SMasahiro Yamada 			s->module->seen = is_vmlinux(s->module->name);
23601da177e4SLinus Torvalds 
23611da177e4SLinus Torvalds 	buf_printf(b, "\n");
23626df7e1ecSMasahiro Yamada 	buf_printf(b, "MODULE_INFO(depends, \"");
23631da177e4SLinus Torvalds 	for (s = mod->unres; s; s = s->next) {
2364a61b2dfdSSam Ravnborg 		const char *p;
23651da177e4SLinus Torvalds 		if (!s->module)
23661da177e4SLinus Torvalds 			continue;
23671da177e4SLinus Torvalds 
23681da177e4SLinus Torvalds 		if (s->module->seen)
23691da177e4SLinus Torvalds 			continue;
23701da177e4SLinus Torvalds 
23711da177e4SLinus Torvalds 		s->module->seen = 1;
2372df578e7dSSam Ravnborg 		p = strrchr(s->module->name, '/');
2373df578e7dSSam Ravnborg 		if (p)
2374a61b2dfdSSam Ravnborg 			p++;
2375a61b2dfdSSam Ravnborg 		else
2376a61b2dfdSSam Ravnborg 			p = s->module->name;
2377a61b2dfdSSam Ravnborg 		buf_printf(b, "%s%s", first ? "" : ",", p);
23781da177e4SLinus Torvalds 		first = 0;
23791da177e4SLinus Torvalds 	}
23806df7e1ecSMasahiro Yamada 	buf_printf(b, "\");\n");
23811da177e4SLinus Torvalds }
23821da177e4SLinus Torvalds 
23835c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod)
23841da177e4SLinus Torvalds {
23851da177e4SLinus Torvalds 	if (mod->srcversion[0]) {
23861da177e4SLinus Torvalds 		buf_printf(b, "\n");
23871da177e4SLinus Torvalds 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
23881da177e4SLinus Torvalds 			   mod->srcversion);
23891da177e4SLinus Torvalds 	}
23901da177e4SLinus Torvalds }
23911da177e4SLinus Torvalds 
23925c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname)
23931da177e4SLinus Torvalds {
23941da177e4SLinus Torvalds 	char *tmp;
23951da177e4SLinus Torvalds 	FILE *file;
23961da177e4SLinus Torvalds 	struct stat st;
23971da177e4SLinus Torvalds 
23981da177e4SLinus Torvalds 	file = fopen(fname, "r");
23991da177e4SLinus Torvalds 	if (!file)
24001da177e4SLinus Torvalds 		goto write;
24011da177e4SLinus Torvalds 
24021da177e4SLinus Torvalds 	if (fstat(fileno(file), &st) < 0)
24031da177e4SLinus Torvalds 		goto close_write;
24041da177e4SLinus Torvalds 
24051da177e4SLinus Torvalds 	if (st.st_size != b->pos)
24061da177e4SLinus Torvalds 		goto close_write;
24071da177e4SLinus Torvalds 
24081da177e4SLinus Torvalds 	tmp = NOFAIL(malloc(b->pos));
24091da177e4SLinus Torvalds 	if (fread(tmp, 1, b->pos, file) != b->pos)
24101da177e4SLinus Torvalds 		goto free_write;
24111da177e4SLinus Torvalds 
24121da177e4SLinus Torvalds 	if (memcmp(tmp, b->p, b->pos) != 0)
24131da177e4SLinus Torvalds 		goto free_write;
24141da177e4SLinus Torvalds 
24151da177e4SLinus Torvalds 	free(tmp);
24161da177e4SLinus Torvalds 	fclose(file);
24171da177e4SLinus Torvalds 	return;
24181da177e4SLinus Torvalds 
24191da177e4SLinus Torvalds  free_write:
24201da177e4SLinus Torvalds 	free(tmp);
24211da177e4SLinus Torvalds  close_write:
24221da177e4SLinus Torvalds 	fclose(file);
24231da177e4SLinus Torvalds  write:
24241da177e4SLinus Torvalds 	file = fopen(fname, "w");
24251da177e4SLinus Torvalds 	if (!file) {
24261da177e4SLinus Torvalds 		perror(fname);
24271da177e4SLinus Torvalds 		exit(1);
24281da177e4SLinus Torvalds 	}
24291da177e4SLinus Torvalds 	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
24301da177e4SLinus Torvalds 		perror(fname);
24311da177e4SLinus Torvalds 		exit(1);
24321da177e4SLinus Torvalds 	}
24331da177e4SLinus Torvalds 	fclose(file);
24341da177e4SLinus Torvalds }
24351da177e4SLinus Torvalds 
2436bd5cbcedSRam Pai /* parse Module.symvers file. line format:
2437534b89a9SSam Ravnborg  * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
2438bd5cbcedSRam Pai  **/
2439040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel)
24401da177e4SLinus Torvalds {
24411da177e4SLinus Torvalds 	unsigned long size, pos = 0;
24421da177e4SLinus Torvalds 	void *file = grab_file(fname, &size);
24431da177e4SLinus Torvalds 	char *line;
24441da177e4SLinus Torvalds 
24451da177e4SLinus Torvalds 	if (!file)
24461da177e4SLinus Torvalds 		/* No symbol versions, silently ignore */
24471da177e4SLinus Torvalds 		return;
24481da177e4SLinus Torvalds 
24491da177e4SLinus Torvalds 	while ((line = get_next_line(&pos, file, size))) {
2450cb9b55d2SMatthias Maennich 		char *symname, *namespace, *modname, *d, *export, *end;
24511da177e4SLinus Torvalds 		unsigned int crc;
24521da177e4SLinus Torvalds 		struct module *mod;
2453040fcc81SSam Ravnborg 		struct symbol *s;
24541da177e4SLinus Torvalds 
24551da177e4SLinus Torvalds 		if (!(symname = strchr(line, '\t')))
24561da177e4SLinus Torvalds 			goto fail;
24571da177e4SLinus Torvalds 		*symname++ = '\0';
2458cb9b55d2SMatthias Maennich 		if (!(namespace = strchr(symname, '\t')))
2459cb9b55d2SMatthias Maennich 			goto fail;
2460cb9b55d2SMatthias Maennich 		*namespace++ = '\0';
2461cb9b55d2SMatthias Maennich 		if (!(modname = strchr(namespace, '\t')))
24621da177e4SLinus Torvalds 			goto fail;
24631da177e4SLinus Torvalds 		*modname++ = '\0';
24649ac545b0SLaurent Riffard 		if ((export = strchr(modname, '\t')) != NULL)
2465bd5cbcedSRam Pai 			*export++ = '\0';
2466534b89a9SSam Ravnborg 		if (export && ((end = strchr(export, '\t')) != NULL))
2467534b89a9SSam Ravnborg 			*end = '\0';
24681da177e4SLinus Torvalds 		crc = strtoul(line, &d, 16);
24691da177e4SLinus Torvalds 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
24701da177e4SLinus Torvalds 			goto fail;
2471df578e7dSSam Ravnborg 		mod = find_module(modname);
2472df578e7dSSam Ravnborg 		if (!mod) {
2473df578e7dSSam Ravnborg 			if (is_vmlinux(modname))
24741da177e4SLinus Torvalds 				have_vmlinux = 1;
24750fa3a88cSJan Beulich 			mod = new_module(modname);
24761da177e4SLinus Torvalds 			mod->skip = 1;
24771da177e4SLinus Torvalds 		}
24789ae5bd18SMatthias Maennich 		s = sym_add_exported(symname, mod, export_no(export));
2479040fcc81SSam Ravnborg 		s->kernel    = kernel;
24808e70c458SSam Ravnborg 		s->preloaded = 1;
248115bfc234SDenis Efremov 		s->is_static = 0;
2482bd5cbcedSRam Pai 		sym_update_crc(symname, mod, crc, export_no(export));
24839ae5bd18SMatthias Maennich 		sym_update_namespace(symname, namespace);
24841da177e4SLinus Torvalds 	}
24852ee41e62SChristian Engelmayer 	release_file(file, size);
24861da177e4SLinus Torvalds 	return;
24871da177e4SLinus Torvalds fail:
24882ee41e62SChristian Engelmayer 	release_file(file, size);
24891da177e4SLinus Torvalds 	fatal("parse error in symbol dump file\n");
24901da177e4SLinus Torvalds }
24911da177e4SLinus Torvalds 
2492040fcc81SSam Ravnborg /* For normal builds always dump all symbols.
2493040fcc81SSam Ravnborg  * For external modules only dump symbols
2494040fcc81SSam Ravnborg  * that are not read from kernel Module.symvers.
2495040fcc81SSam Ravnborg  **/
2496040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym)
2497040fcc81SSam Ravnborg {
2498040fcc81SSam Ravnborg 	if (!external_module)
2499040fcc81SSam Ravnborg 		return 1;
2500040fcc81SSam Ravnborg 	if (sym->vmlinux || sym->kernel)
2501040fcc81SSam Ravnborg 		return 0;
2502040fcc81SSam Ravnborg 	return 1;
2503040fcc81SSam Ravnborg }
2504040fcc81SSam Ravnborg 
25055c3ead8cSSam Ravnborg static void write_dump(const char *fname)
25061da177e4SLinus Torvalds {
25071da177e4SLinus Torvalds 	struct buffer buf = { };
25081da177e4SLinus Torvalds 	struct symbol *symbol;
2509cb9b55d2SMatthias Maennich 	const char *namespace;
25101da177e4SLinus Torvalds 	int n;
25111da177e4SLinus Torvalds 
25121da177e4SLinus Torvalds 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
25131da177e4SLinus Torvalds 		symbol = symbolhash[n];
25141da177e4SLinus Torvalds 		while (symbol) {
2515cb9b55d2SMatthias Maennich 			if (dump_sym(symbol)) {
2516cb9b55d2SMatthias Maennich 				namespace = symbol->namespace;
2517cb9b55d2SMatthias Maennich 				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
2518040fcc81SSam Ravnborg 					   symbol->crc, symbol->name,
2519cb9b55d2SMatthias Maennich 					   namespace ? namespace : "",
2520bd5cbcedSRam Pai 					   symbol->module->name,
2521bd5cbcedSRam Pai 					   export_str(symbol->export));
2522cb9b55d2SMatthias Maennich 			}
25231da177e4SLinus Torvalds 			symbol = symbol->next;
25241da177e4SLinus Torvalds 		}
25251da177e4SLinus Torvalds 	}
25261da177e4SLinus Torvalds 	write_if_changed(&buf, fname);
2527c7d47f26SHeinrich Schuchardt 	free(buf.p);
25281da177e4SLinus Torvalds }
25291da177e4SLinus Torvalds 
25301d082773SMatthias Maennich static void write_namespace_deps_files(void)
25311d082773SMatthias Maennich {
25321d082773SMatthias Maennich 	struct module *mod;
25331d082773SMatthias Maennich 	struct namespace_list *ns;
25341d082773SMatthias Maennich 	struct buffer ns_deps_buf = {};
25351d082773SMatthias Maennich 
25361d082773SMatthias Maennich 	for (mod = modules; mod; mod = mod->next) {
25371d082773SMatthias Maennich 		char fname[PATH_MAX];
25381d082773SMatthias Maennich 
25391d082773SMatthias Maennich 		if (mod->skip)
25401d082773SMatthias Maennich 			continue;
25411d082773SMatthias Maennich 
25421d082773SMatthias Maennich 		ns_deps_buf.pos = 0;
25431d082773SMatthias Maennich 
25441d082773SMatthias Maennich 		for (ns = mod->required_namespaces; ns; ns = ns->next)
25451d082773SMatthias Maennich 			buf_printf(&ns_deps_buf, "%s\n", ns->namespace);
25461d082773SMatthias Maennich 
25471d082773SMatthias Maennich 		if (ns_deps_buf.pos == 0)
25481d082773SMatthias Maennich 			continue;
25491d082773SMatthias Maennich 
25501d082773SMatthias Maennich 		sprintf(fname, "%s.ns_deps", mod->name);
25511d082773SMatthias Maennich 		write_if_changed(&ns_deps_buf, fname);
25521d082773SMatthias Maennich 	}
25531d082773SMatthias Maennich }
25541d082773SMatthias Maennich 
25552d04b5aeSRichard Hacker struct ext_sym_list {
25562d04b5aeSRichard Hacker 	struct ext_sym_list *next;
25572d04b5aeSRichard Hacker 	const char *file;
25582d04b5aeSRichard Hacker };
25592d04b5aeSRichard Hacker 
25605c3ead8cSSam Ravnborg int main(int argc, char **argv)
25611da177e4SLinus Torvalds {
25621da177e4SLinus Torvalds 	struct module *mod;
25631da177e4SLinus Torvalds 	struct buffer buf = { };
2564040fcc81SSam Ravnborg 	char *kernel_read = NULL, *module_read = NULL;
2565712f9b46SRusty Russell 	char *dump_write = NULL, *files_source = NULL;
25661da177e4SLinus Torvalds 	int opt;
2567c53ddacdSKirill Korotaev 	int err;
256815bfc234SDenis Efremov 	int n;
25692d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_iter;
25702d04b5aeSRichard Hacker 	struct ext_sym_list *extsym_start = NULL;
25711da177e4SLinus Torvalds 
25721d082773SMatthias Maennich 	while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {
25731da177e4SLinus Torvalds 		switch (opt) {
25741da177e4SLinus Torvalds 		case 'i':
2575040fcc81SSam Ravnborg 			kernel_read = optarg;
2576040fcc81SSam Ravnborg 			break;
2577040fcc81SSam Ravnborg 		case 'I':
2578040fcc81SSam Ravnborg 			module_read = optarg;
2579040fcc81SSam Ravnborg 			external_module = 1;
25801da177e4SLinus Torvalds 			break;
25812d04b5aeSRichard Hacker 		case 'e':
25822d04b5aeSRichard Hacker 			external_module = 1;
25832d04b5aeSRichard Hacker 			extsym_iter =
25842d04b5aeSRichard Hacker 			   NOFAIL(malloc(sizeof(*extsym_iter)));
25852d04b5aeSRichard Hacker 			extsym_iter->next = extsym_start;
25862d04b5aeSRichard Hacker 			extsym_iter->file = optarg;
25872d04b5aeSRichard Hacker 			extsym_start = extsym_iter;
25882d04b5aeSRichard Hacker 			break;
25891da177e4SLinus Torvalds 		case 'm':
25901da177e4SLinus Torvalds 			modversions = 1;
25911da177e4SLinus Torvalds 			break;
2592eed380f3SGuenter Roeck 		case 'n':
2593eed380f3SGuenter Roeck 			ignore_missing_files = 1;
2594eed380f3SGuenter Roeck 			break;
25951da177e4SLinus Torvalds 		case 'o':
25961da177e4SLinus Torvalds 			dump_write = optarg;
25971da177e4SLinus Torvalds 			break;
25981da177e4SLinus Torvalds 		case 'a':
25991da177e4SLinus Torvalds 			all_versions = 1;
26001da177e4SLinus Torvalds 			break;
26018d8d8289SSam Ravnborg 		case 's':
26028d8d8289SSam Ravnborg 			vmlinux_section_warnings = 0;
26038d8d8289SSam Ravnborg 			break;
2604712f9b46SRusty Russell 		case 'T':
2605712f9b46SRusty Russell 			files_source = optarg;
2606712f9b46SRusty Russell 			break;
2607c53ddacdSKirill Korotaev 		case 'w':
2608c53ddacdSKirill Korotaev 			warn_unresolved = 1;
2609c53ddacdSKirill Korotaev 			break;
261047490ec1SNicolas Boichat 		case 'E':
261147490ec1SNicolas Boichat 			sec_mismatch_fatal = 1;
261247490ec1SNicolas Boichat 			break;
26131d082773SMatthias Maennich 		case 'd':
26141d082773SMatthias Maennich 			write_namespace_deps = 1;
26151d082773SMatthias Maennich 			break;
26161da177e4SLinus Torvalds 		default:
26171da177e4SLinus Torvalds 			exit(1);
26181da177e4SLinus Torvalds 		}
26191da177e4SLinus Torvalds 	}
26201da177e4SLinus Torvalds 
2621040fcc81SSam Ravnborg 	if (kernel_read)
2622040fcc81SSam Ravnborg 		read_dump(kernel_read, 1);
2623040fcc81SSam Ravnborg 	if (module_read)
2624040fcc81SSam Ravnborg 		read_dump(module_read, 0);
26252d04b5aeSRichard Hacker 	while (extsym_start) {
26262d04b5aeSRichard Hacker 		read_dump(extsym_start->file, 0);
26272d04b5aeSRichard Hacker 		extsym_iter = extsym_start->next;
26282d04b5aeSRichard Hacker 		free(extsym_start);
26292d04b5aeSRichard Hacker 		extsym_start = extsym_iter;
26302d04b5aeSRichard Hacker 	}
26311da177e4SLinus Torvalds 
2632df578e7dSSam Ravnborg 	while (optind < argc)
26331da177e4SLinus Torvalds 		read_symbols(argv[optind++]);
26341da177e4SLinus Torvalds 
2635712f9b46SRusty Russell 	if (files_source)
2636712f9b46SRusty Russell 		read_symbols_from_files(files_source);
2637712f9b46SRusty Russell 
2638c53ddacdSKirill Korotaev 	err = 0;
2639c53ddacdSKirill Korotaev 
2640b817f6feSSam Ravnborg 	for (mod = modules; mod; mod = mod->next) {
2641d93e1719SMathias Krause 		char fname[PATH_MAX];
2642666ab414SAndi Kleen 
2643b817f6feSSam Ravnborg 		if (mod->skip)
2644b817f6feSSam Ravnborg 			continue;
26451da177e4SLinus Torvalds 
26461da177e4SLinus Torvalds 		buf.pos = 0;
26471da177e4SLinus Torvalds 
26484fd3e4efSWanlong Gao 		err |= check_modname_len(mod);
26493b415288SMasahiro Yamada 		err |= check_exports(mod);
26501d082773SMatthias Maennich 		if (write_namespace_deps)
26511d082773SMatthias Maennich 			continue;
26521d082773SMatthias Maennich 
26531da177e4SLinus Torvalds 		add_header(&buf, mod);
26542449b8baSBen Hutchings 		add_intree_flag(&buf, !external_module);
2655caf7501aSAndi Kleen 		add_retpoline(&buf);
2656a9860bf0SGreg Kroah-Hartman 		add_staging_flag(&buf, mod->name);
2657c53ddacdSKirill Korotaev 		err |= add_versions(&buf, mod);
2658d2665ca8SMasahiro Yamada 		add_depends(&buf, mod);
26591da177e4SLinus Torvalds 		add_moddevtable(&buf, mod);
26601da177e4SLinus Torvalds 		add_srcversion(&buf, mod);
26611da177e4SLinus Torvalds 
26621da177e4SLinus Torvalds 		sprintf(fname, "%s.mod.c", mod->name);
26631da177e4SLinus Torvalds 		write_if_changed(&buf, fname);
26641da177e4SLinus Torvalds 	}
26651d082773SMatthias Maennich 
26661d082773SMatthias Maennich 	if (write_namespace_deps) {
26671d082773SMatthias Maennich 		write_namespace_deps_files();
26681d082773SMatthias Maennich 		return 0;
26691d082773SMatthias Maennich 	}
26701d082773SMatthias Maennich 
26711da177e4SLinus Torvalds 	if (dump_write)
26721da177e4SLinus Torvalds 		write_dump(dump_write);
267346c7dd56SMasahiro Yamada 	if (sec_mismatch_count && sec_mismatch_fatal)
267447490ec1SNicolas Boichat 		fatal("modpost: Section mismatches detected.\n"
267547490ec1SNicolas Boichat 		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
267615bfc234SDenis Efremov 	for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
267747346e96SMasahiro Yamada 		struct symbol *s;
267815bfc234SDenis Efremov 
267947346e96SMasahiro Yamada 		for (s = symbolhash[n]; s; s = s->next) {
268047346e96SMasahiro Yamada 			/*
268147346e96SMasahiro Yamada 			 * Do not check "vmlinux". This avoids the same warnings
268247346e96SMasahiro Yamada 			 * shown twice, and false-positives for ARCH=um.
268347346e96SMasahiro Yamada 			 */
268447346e96SMasahiro Yamada 			if (is_vmlinux(s->module->name) && !s->module->is_dot_o)
268547346e96SMasahiro Yamada 				continue;
268647346e96SMasahiro Yamada 
268715bfc234SDenis Efremov 			if (s->is_static)
268815bfc234SDenis Efremov 				warn("\"%s\" [%s] is a static %s\n",
268915bfc234SDenis Efremov 				     s->name, s->module->name,
269015bfc234SDenis Efremov 				     export_str(s->export));
269115bfc234SDenis Efremov 		}
269215bfc234SDenis Efremov 	}
269315bfc234SDenis Efremov 
2694c7d47f26SHeinrich Schuchardt 	free(buf.p);
26951da177e4SLinus Torvalds 
2696c53ddacdSKirill Korotaev 	return err;
26971da177e4SLinus Torvalds }
2698