18c2ecf20Sopenharmony_ci/* Postprocess module symbol versions
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Copyright 2003       Kai Germaschewski
48c2ecf20Sopenharmony_ci * Copyright 2002-2004  Rusty Russell, IBM Corporation
58c2ecf20Sopenharmony_ci * Copyright 2006-2008  Sam Ravnborg
68c2ecf20Sopenharmony_ci * Based in part on module-init-tools/depmod.c,file2alias
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This software may be used and distributed according to the terms
98c2ecf20Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Usage: modpost vmlinux module1.o module2.o ...
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define _GNU_SOURCE
158c2ecf20Sopenharmony_ci#include <elf.h>
168c2ecf20Sopenharmony_ci#include <stdio.h>
178c2ecf20Sopenharmony_ci#include <ctype.h>
188c2ecf20Sopenharmony_ci#include <string.h>
198c2ecf20Sopenharmony_ci#include <limits.h>
208c2ecf20Sopenharmony_ci#include <stdbool.h>
218c2ecf20Sopenharmony_ci#include <errno.h>
228c2ecf20Sopenharmony_ci#include "modpost.h"
238c2ecf20Sopenharmony_ci#include "../../include/linux/license.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Are we using CONFIG_MODVERSIONS? */
268c2ecf20Sopenharmony_cistatic int modversions = 0;
278c2ecf20Sopenharmony_ci/* Warn about undefined symbols? (do so if we have vmlinux) */
288c2ecf20Sopenharmony_cistatic int have_vmlinux = 0;
298c2ecf20Sopenharmony_ci/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
308c2ecf20Sopenharmony_cistatic int all_versions = 0;
318c2ecf20Sopenharmony_ci/* If we are modposting external module set to 1 */
328c2ecf20Sopenharmony_cistatic int external_module = 0;
338c2ecf20Sopenharmony_ci/* Only warn about unresolved symbols */
348c2ecf20Sopenharmony_cistatic int warn_unresolved = 0;
358c2ecf20Sopenharmony_ci/* How a symbol is exported */
368c2ecf20Sopenharmony_cistatic int sec_mismatch_count = 0;
378c2ecf20Sopenharmony_cistatic int sec_mismatch_fatal = 0;
388c2ecf20Sopenharmony_ci/* ignore missing files */
398c2ecf20Sopenharmony_cistatic int ignore_missing_files;
408c2ecf20Sopenharmony_ci/* If set to 1, only warn (instead of error) about missing ns imports */
418c2ecf20Sopenharmony_cistatic int allow_missing_ns_imports;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cienum export {
448c2ecf20Sopenharmony_ci	export_plain,      export_unused,     export_gpl,
458c2ecf20Sopenharmony_ci	export_unused_gpl, export_gpl_future, export_unknown
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* In kernel, this size is defined in linux/module.h;
498c2ecf20Sopenharmony_ci * here we use Elf_Addr instead of long for covering cross-compile
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr))
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_civoid __attribute__((format(printf, 2, 3)))
558c2ecf20Sopenharmony_cimodpost_log(enum loglevel loglevel, const char *fmt, ...)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	va_list arglist;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	switch (loglevel) {
608c2ecf20Sopenharmony_ci	case LOG_WARN:
618c2ecf20Sopenharmony_ci		fprintf(stderr, "WARNING: ");
628c2ecf20Sopenharmony_ci		break;
638c2ecf20Sopenharmony_ci	case LOG_ERROR:
648c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: ");
658c2ecf20Sopenharmony_ci		break;
668c2ecf20Sopenharmony_ci	case LOG_FATAL:
678c2ecf20Sopenharmony_ci		fprintf(stderr, "FATAL: ");
688c2ecf20Sopenharmony_ci		break;
698c2ecf20Sopenharmony_ci	default: /* invalid loglevel, ignore */
708c2ecf20Sopenharmony_ci		break;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	fprintf(stderr, "modpost: ");
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	va_start(arglist, fmt);
768c2ecf20Sopenharmony_ci	vfprintf(stderr, fmt, arglist);
778c2ecf20Sopenharmony_ci	va_end(arglist);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (loglevel == LOG_FATAL)
808c2ecf20Sopenharmony_ci		exit(1);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_civoid *do_nofail(void *ptr, const char *expr)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	if (!ptr)
868c2ecf20Sopenharmony_ci		fatal("Memory allocation failure: %s.\n", expr);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return ptr;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cichar *read_text_file(const char *filename)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct stat st;
948c2ecf20Sopenharmony_ci	size_t nbytes;
958c2ecf20Sopenharmony_ci	int fd;
968c2ecf20Sopenharmony_ci	char *buf;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	fd = open(filename, O_RDONLY);
998c2ecf20Sopenharmony_ci	if (fd < 0) {
1008c2ecf20Sopenharmony_ci		perror(filename);
1018c2ecf20Sopenharmony_ci		exit(1);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (fstat(fd, &st) < 0) {
1058c2ecf20Sopenharmony_ci		perror(filename);
1068c2ecf20Sopenharmony_ci		exit(1);
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	buf = NOFAIL(malloc(st.st_size + 1));
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	nbytes = st.st_size;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	while (nbytes) {
1148c2ecf20Sopenharmony_ci		ssize_t bytes_read;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		bytes_read = read(fd, buf, nbytes);
1178c2ecf20Sopenharmony_ci		if (bytes_read < 0) {
1188c2ecf20Sopenharmony_ci			perror(filename);
1198c2ecf20Sopenharmony_ci			exit(1);
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		nbytes -= bytes_read;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci	buf[st.st_size] = '\0';
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	close(fd);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return buf;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cichar *get_line(char **stringp)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	char *orig = *stringp, *next;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* do not return the unwanted extra line at EOF */
1368c2ecf20Sopenharmony_ci	if (!orig || *orig == '\0')
1378c2ecf20Sopenharmony_ci		return NULL;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/* don't use strsep here, it is not available everywhere */
1408c2ecf20Sopenharmony_ci	next = strchr(orig, '\n');
1418c2ecf20Sopenharmony_ci	if (next)
1428c2ecf20Sopenharmony_ci		*next++ = '\0';
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	*stringp = next;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return orig;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/* A list of all modules we processed */
1508c2ecf20Sopenharmony_cistatic struct module *modules;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic struct module *find_module(const char *modname)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct module *mod;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	for (mod = modules; mod; mod = mod->next)
1578c2ecf20Sopenharmony_ci		if (strcmp(mod->name, modname) == 0)
1588c2ecf20Sopenharmony_ci			break;
1598c2ecf20Sopenharmony_ci	return mod;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic struct module *new_module(const char *modname)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct module *mod;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1));
1678c2ecf20Sopenharmony_ci	memset(mod, 0, sizeof(*mod));
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* add to list */
1708c2ecf20Sopenharmony_ci	strcpy(mod->name, modname);
1718c2ecf20Sopenharmony_ci	mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0);
1728c2ecf20Sopenharmony_ci	mod->gpl_compatible = -1;
1738c2ecf20Sopenharmony_ci	mod->next = modules;
1748c2ecf20Sopenharmony_ci	modules = mod;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (mod->is_vmlinux)
1778c2ecf20Sopenharmony_ci		have_vmlinux = 1;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return mod;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/* A hash of all exported symbols,
1838c2ecf20Sopenharmony_ci * struct symbol is also used for lists of unresolved symbols */
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci#define SYMBOL_HASH_SIZE 1024
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistruct symbol {
1888c2ecf20Sopenharmony_ci	struct symbol *next;
1898c2ecf20Sopenharmony_ci	struct module *module;
1908c2ecf20Sopenharmony_ci	unsigned int crc;
1918c2ecf20Sopenharmony_ci	int crc_valid;
1928c2ecf20Sopenharmony_ci	char *namespace;
1938c2ecf20Sopenharmony_ci	unsigned int weak:1;
1948c2ecf20Sopenharmony_ci	unsigned int is_static:1;  /* 1 if symbol is not global */
1958c2ecf20Sopenharmony_ci	enum export  export;       /* Type of export */
1968c2ecf20Sopenharmony_ci	char name[];
1978c2ecf20Sopenharmony_ci};
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic struct symbol *symbolhash[SYMBOL_HASH_SIZE];
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/* This is based on the hash agorithm from gdbm, via tdb */
2028c2ecf20Sopenharmony_cistatic inline unsigned int tdb_hash(const char *name)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	unsigned value;	/* Used to compute the hash value.  */
2058c2ecf20Sopenharmony_ci	unsigned   i;	/* Used to cycle through random values. */
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Set the initial value from the key size. */
2088c2ecf20Sopenharmony_ci	for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
2098c2ecf20Sopenharmony_ci		value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	return (1103515243 * value + 12345);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/**
2158c2ecf20Sopenharmony_ci * Allocate a new symbols for use in the hash of exported symbols or
2168c2ecf20Sopenharmony_ci * the list of unresolved symbols per module
2178c2ecf20Sopenharmony_ci **/
2188c2ecf20Sopenharmony_cistatic struct symbol *alloc_symbol(const char *name, unsigned int weak,
2198c2ecf20Sopenharmony_ci				   struct symbol *next)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	memset(s, 0, sizeof(*s));
2248c2ecf20Sopenharmony_ci	strcpy(s->name, name);
2258c2ecf20Sopenharmony_ci	s->weak = weak;
2268c2ecf20Sopenharmony_ci	s->next = next;
2278c2ecf20Sopenharmony_ci	s->is_static = 1;
2288c2ecf20Sopenharmony_ci	return s;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/* For the hash of exported symbols */
2328c2ecf20Sopenharmony_cistatic struct symbol *new_symbol(const char *name, struct module *module,
2338c2ecf20Sopenharmony_ci				 enum export export)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	unsigned int hash;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
2388c2ecf20Sopenharmony_ci	symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return symbolhash[hash];
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic struct symbol *find_symbol(const char *name)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct symbol *s;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/* For our purposes, .foo matches foo.  PPC64 needs this. */
2488c2ecf20Sopenharmony_ci	if (name[0] == '.')
2498c2ecf20Sopenharmony_ci		name++;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
2528c2ecf20Sopenharmony_ci		if (strcmp(s->name, name) == 0)
2538c2ecf20Sopenharmony_ci			return s;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci	return NULL;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic bool contains_namespace(struct namespace_list *list,
2598c2ecf20Sopenharmony_ci			       const char *namespace)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	for (; list; list = list->next)
2628c2ecf20Sopenharmony_ci		if (!strcmp(list->namespace, namespace))
2638c2ecf20Sopenharmony_ci			return true;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return false;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic void add_namespace(struct namespace_list **list, const char *namespace)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct namespace_list *ns_entry;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (!contains_namespace(*list, namespace)) {
2738c2ecf20Sopenharmony_ci		ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
2748c2ecf20Sopenharmony_ci					 strlen(namespace) + 1));
2758c2ecf20Sopenharmony_ci		strcpy(ns_entry->namespace, namespace);
2768c2ecf20Sopenharmony_ci		ns_entry->next = *list;
2778c2ecf20Sopenharmony_ci		*list = ns_entry;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic bool module_imports_namespace(struct module *module,
2828c2ecf20Sopenharmony_ci				     const char *namespace)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	return contains_namespace(module->imported_namespaces, namespace);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic const struct {
2888c2ecf20Sopenharmony_ci	const char *str;
2898c2ecf20Sopenharmony_ci	enum export export;
2908c2ecf20Sopenharmony_ci} export_list[] = {
2918c2ecf20Sopenharmony_ci	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
2928c2ecf20Sopenharmony_ci	{ .str = "EXPORT_UNUSED_SYMBOL",     .export = export_unused },
2938c2ecf20Sopenharmony_ci	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
2948c2ecf20Sopenharmony_ci	{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
2958c2ecf20Sopenharmony_ci	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
2968c2ecf20Sopenharmony_ci	{ .str = "(unknown)",                .export = export_unknown },
2978c2ecf20Sopenharmony_ci};
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic const char *export_str(enum export ex)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	return export_list[ex].str;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic enum export export_no(const char *s)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int i;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (!s)
3108c2ecf20Sopenharmony_ci		return export_unknown;
3118c2ecf20Sopenharmony_ci	for (i = 0; export_list[i].export != export_unknown; i++) {
3128c2ecf20Sopenharmony_ci		if (strcmp(export_list[i].str, s) == 0)
3138c2ecf20Sopenharmony_ci			return export_list[i].export;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci	return export_unknown;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic void *sym_get_data_by_offset(const struct elf_info *info,
3198c2ecf20Sopenharmony_ci				    unsigned int secindex, unsigned long offset)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	Elf_Shdr *sechdr = &info->sechdrs[secindex];
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (info->hdr->e_type != ET_REL)
3248c2ecf20Sopenharmony_ci		offset -= sechdr->sh_addr;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return (void *)info->hdr + sechdr->sh_offset + offset;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	return sym_get_data_by_offset(info, get_secindex(info, sym),
3328c2ecf20Sopenharmony_ci				      sym->st_value);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	return sym_get_data_by_offset(info, info->secindex_strings,
3388c2ecf20Sopenharmony_ci				      sechdr->sh_name);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic const char *sec_name(const struct elf_info *info, int secindex)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	return sech_name(info, &info->sechdrs[secindex]);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic enum export export_from_secname(struct elf_info *elf, unsigned int sec)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	const char *secname = sec_name(elf, sec);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (strstarts(secname, "___ksymtab+"))
3538c2ecf20Sopenharmony_ci		return export_plain;
3548c2ecf20Sopenharmony_ci	else if (strstarts(secname, "___ksymtab_unused+"))
3558c2ecf20Sopenharmony_ci		return export_unused;
3568c2ecf20Sopenharmony_ci	else if (strstarts(secname, "___ksymtab_gpl+"))
3578c2ecf20Sopenharmony_ci		return export_gpl;
3588c2ecf20Sopenharmony_ci	else if (strstarts(secname, "___ksymtab_unused_gpl+"))
3598c2ecf20Sopenharmony_ci		return export_unused_gpl;
3608c2ecf20Sopenharmony_ci	else if (strstarts(secname, "___ksymtab_gpl_future+"))
3618c2ecf20Sopenharmony_ci		return export_gpl_future;
3628c2ecf20Sopenharmony_ci	else
3638c2ecf20Sopenharmony_ci		return export_unknown;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic enum export export_from_sec(struct elf_info *elf, unsigned int sec)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	if (sec == elf->export_sec)
3698c2ecf20Sopenharmony_ci		return export_plain;
3708c2ecf20Sopenharmony_ci	else if (sec == elf->export_unused_sec)
3718c2ecf20Sopenharmony_ci		return export_unused;
3728c2ecf20Sopenharmony_ci	else if (sec == elf->export_gpl_sec)
3738c2ecf20Sopenharmony_ci		return export_gpl;
3748c2ecf20Sopenharmony_ci	else if (sec == elf->export_unused_gpl_sec)
3758c2ecf20Sopenharmony_ci		return export_unused_gpl;
3768c2ecf20Sopenharmony_ci	else if (sec == elf->export_gpl_future_sec)
3778c2ecf20Sopenharmony_ci		return export_gpl_future;
3788c2ecf20Sopenharmony_ci	else
3798c2ecf20Sopenharmony_ci		return export_unknown;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic const char *namespace_from_kstrtabns(const struct elf_info *info,
3838c2ecf20Sopenharmony_ci					    const Elf_Sym *sym)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	const char *value = sym_get_data(info, sym);
3868c2ecf20Sopenharmony_ci	return value[0] ? value : NULL;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic void sym_update_namespace(const char *symname, const char *namespace)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct symbol *s = find_symbol(symname);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/*
3948c2ecf20Sopenharmony_ci	 * That symbol should have been created earlier and thus this is
3958c2ecf20Sopenharmony_ci	 * actually an assertion.
3968c2ecf20Sopenharmony_ci	 */
3978c2ecf20Sopenharmony_ci	if (!s) {
3988c2ecf20Sopenharmony_ci		merror("Could not update namespace(%s) for symbol %s\n",
3998c2ecf20Sopenharmony_ci		       namespace, symname);
4008c2ecf20Sopenharmony_ci		return;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	free(s->namespace);
4048c2ecf20Sopenharmony_ci	s->namespace =
4058c2ecf20Sopenharmony_ci		namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/**
4098c2ecf20Sopenharmony_ci * Add an exported symbol - it may have already been added without a
4108c2ecf20Sopenharmony_ci * CRC, in this case just update the CRC
4118c2ecf20Sopenharmony_ci **/
4128c2ecf20Sopenharmony_cistatic struct symbol *sym_add_exported(const char *name, struct module *mod,
4138c2ecf20Sopenharmony_ci				       enum export export)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct symbol *s = find_symbol(name);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (!s) {
4188c2ecf20Sopenharmony_ci		s = new_symbol(name, mod, export);
4198c2ecf20Sopenharmony_ci	} else if (!external_module || s->module->is_vmlinux ||
4208c2ecf20Sopenharmony_ci		   s->module == mod) {
4218c2ecf20Sopenharmony_ci		warn("%s: '%s' exported twice. Previous export was in %s%s\n",
4228c2ecf20Sopenharmony_ci		     mod->name, name, s->module->name,
4238c2ecf20Sopenharmony_ci		     s->module->is_vmlinux ? "" : ".ko");
4248c2ecf20Sopenharmony_ci		return s;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	s->module = mod;
4288c2ecf20Sopenharmony_ci	s->export    = export;
4298c2ecf20Sopenharmony_ci	return s;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic void sym_set_crc(const char *name, unsigned int crc)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	struct symbol *s = find_symbol(name);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/*
4378c2ecf20Sopenharmony_ci	 * Ignore stand-alone __crc_*, which might be auto-generated symbols
4388c2ecf20Sopenharmony_ci	 * such as __*_veneer in ARM ELF.
4398c2ecf20Sopenharmony_ci	 */
4408c2ecf20Sopenharmony_ci	if (!s)
4418c2ecf20Sopenharmony_ci		return;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	s->crc = crc;
4448c2ecf20Sopenharmony_ci	s->crc_valid = 1;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic void *grab_file(const char *filename, size_t *size)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct stat st;
4508c2ecf20Sopenharmony_ci	void *map = MAP_FAILED;
4518c2ecf20Sopenharmony_ci	int fd;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	fd = open(filename, O_RDONLY);
4548c2ecf20Sopenharmony_ci	if (fd < 0)
4558c2ecf20Sopenharmony_ci		return NULL;
4568c2ecf20Sopenharmony_ci	if (fstat(fd, &st))
4578c2ecf20Sopenharmony_ci		goto failed;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	*size = st.st_size;
4608c2ecf20Sopenharmony_ci	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cifailed:
4638c2ecf20Sopenharmony_ci	close(fd);
4648c2ecf20Sopenharmony_ci	if (map == MAP_FAILED)
4658c2ecf20Sopenharmony_ci		return NULL;
4668c2ecf20Sopenharmony_ci	return map;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic void release_file(void *file, size_t size)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	munmap(file, size);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic int parse_elf(struct elf_info *info, const char *filename)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	unsigned int i;
4778c2ecf20Sopenharmony_ci	Elf_Ehdr *hdr;
4788c2ecf20Sopenharmony_ci	Elf_Shdr *sechdrs;
4798c2ecf20Sopenharmony_ci	Elf_Sym  *sym;
4808c2ecf20Sopenharmony_ci	const char *secstrings;
4818c2ecf20Sopenharmony_ci	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	hdr = grab_file(filename, &info->size);
4848c2ecf20Sopenharmony_ci	if (!hdr) {
4858c2ecf20Sopenharmony_ci		if (ignore_missing_files) {
4868c2ecf20Sopenharmony_ci			fprintf(stderr, "%s: %s (ignored)\n", filename,
4878c2ecf20Sopenharmony_ci				strerror(errno));
4888c2ecf20Sopenharmony_ci			return 0;
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci		perror(filename);
4918c2ecf20Sopenharmony_ci		exit(1);
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci	info->hdr = hdr;
4948c2ecf20Sopenharmony_ci	if (info->size < sizeof(*hdr)) {
4958c2ecf20Sopenharmony_ci		/* file too small, assume this is an empty .o file */
4968c2ecf20Sopenharmony_ci		return 0;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci	/* Is this a valid ELF file? */
4998c2ecf20Sopenharmony_ci	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
5008c2ecf20Sopenharmony_ci	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
5018c2ecf20Sopenharmony_ci	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
5028c2ecf20Sopenharmony_ci	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
5038c2ecf20Sopenharmony_ci		/* Not an ELF file - silently ignore it */
5048c2ecf20Sopenharmony_ci		return 0;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci	/* Fix endianness in ELF header */
5078c2ecf20Sopenharmony_ci	hdr->e_type      = TO_NATIVE(hdr->e_type);
5088c2ecf20Sopenharmony_ci	hdr->e_machine   = TO_NATIVE(hdr->e_machine);
5098c2ecf20Sopenharmony_ci	hdr->e_version   = TO_NATIVE(hdr->e_version);
5108c2ecf20Sopenharmony_ci	hdr->e_entry     = TO_NATIVE(hdr->e_entry);
5118c2ecf20Sopenharmony_ci	hdr->e_phoff     = TO_NATIVE(hdr->e_phoff);
5128c2ecf20Sopenharmony_ci	hdr->e_shoff     = TO_NATIVE(hdr->e_shoff);
5138c2ecf20Sopenharmony_ci	hdr->e_flags     = TO_NATIVE(hdr->e_flags);
5148c2ecf20Sopenharmony_ci	hdr->e_ehsize    = TO_NATIVE(hdr->e_ehsize);
5158c2ecf20Sopenharmony_ci	hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize);
5168c2ecf20Sopenharmony_ci	hdr->e_phnum     = TO_NATIVE(hdr->e_phnum);
5178c2ecf20Sopenharmony_ci	hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize);
5188c2ecf20Sopenharmony_ci	hdr->e_shnum     = TO_NATIVE(hdr->e_shnum);
5198c2ecf20Sopenharmony_ci	hdr->e_shstrndx  = TO_NATIVE(hdr->e_shstrndx);
5208c2ecf20Sopenharmony_ci	sechdrs = (void *)hdr + hdr->e_shoff;
5218c2ecf20Sopenharmony_ci	info->sechdrs = sechdrs;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	/* Check if file offset is correct */
5248c2ecf20Sopenharmony_ci	if (hdr->e_shoff > info->size) {
5258c2ecf20Sopenharmony_ci		fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
5268c2ecf20Sopenharmony_ci		      (unsigned long)hdr->e_shoff, filename, info->size);
5278c2ecf20Sopenharmony_ci		return 0;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (hdr->e_shnum == SHN_UNDEF) {
5318c2ecf20Sopenharmony_ci		/*
5328c2ecf20Sopenharmony_ci		 * There are more than 64k sections,
5338c2ecf20Sopenharmony_ci		 * read count from .sh_size.
5348c2ecf20Sopenharmony_ci		 */
5358c2ecf20Sopenharmony_ci		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci	else {
5388c2ecf20Sopenharmony_ci		info->num_sections = hdr->e_shnum;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci	if (hdr->e_shstrndx == SHN_XINDEX) {
5418c2ecf20Sopenharmony_ci		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci	else {
5448c2ecf20Sopenharmony_ci		info->secindex_strings = hdr->e_shstrndx;
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* Fix endianness in section headers */
5488c2ecf20Sopenharmony_ci	for (i = 0; i < info->num_sections; i++) {
5498c2ecf20Sopenharmony_ci		sechdrs[i].sh_name      = TO_NATIVE(sechdrs[i].sh_name);
5508c2ecf20Sopenharmony_ci		sechdrs[i].sh_type      = TO_NATIVE(sechdrs[i].sh_type);
5518c2ecf20Sopenharmony_ci		sechdrs[i].sh_flags     = TO_NATIVE(sechdrs[i].sh_flags);
5528c2ecf20Sopenharmony_ci		sechdrs[i].sh_addr      = TO_NATIVE(sechdrs[i].sh_addr);
5538c2ecf20Sopenharmony_ci		sechdrs[i].sh_offset    = TO_NATIVE(sechdrs[i].sh_offset);
5548c2ecf20Sopenharmony_ci		sechdrs[i].sh_size      = TO_NATIVE(sechdrs[i].sh_size);
5558c2ecf20Sopenharmony_ci		sechdrs[i].sh_link      = TO_NATIVE(sechdrs[i].sh_link);
5568c2ecf20Sopenharmony_ci		sechdrs[i].sh_info      = TO_NATIVE(sechdrs[i].sh_info);
5578c2ecf20Sopenharmony_ci		sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
5588c2ecf20Sopenharmony_ci		sechdrs[i].sh_entsize   = TO_NATIVE(sechdrs[i].sh_entsize);
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci	/* Find symbol table. */
5618c2ecf20Sopenharmony_ci	secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
5628c2ecf20Sopenharmony_ci	for (i = 1; i < info->num_sections; i++) {
5638c2ecf20Sopenharmony_ci		const char *secname;
5648c2ecf20Sopenharmony_ci		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci		if (!nobits && sechdrs[i].sh_offset > info->size) {
5678c2ecf20Sopenharmony_ci			fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
5688c2ecf20Sopenharmony_ci			      "sizeof(*hrd)=%zu\n", filename,
5698c2ecf20Sopenharmony_ci			      (unsigned long)sechdrs[i].sh_offset,
5708c2ecf20Sopenharmony_ci			      sizeof(*hdr));
5718c2ecf20Sopenharmony_ci			return 0;
5728c2ecf20Sopenharmony_ci		}
5738c2ecf20Sopenharmony_ci		secname = secstrings + sechdrs[i].sh_name;
5748c2ecf20Sopenharmony_ci		if (strcmp(secname, ".modinfo") == 0) {
5758c2ecf20Sopenharmony_ci			if (nobits)
5768c2ecf20Sopenharmony_ci				fatal("%s has NOBITS .modinfo\n", filename);
5778c2ecf20Sopenharmony_ci			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
5788c2ecf20Sopenharmony_ci			info->modinfo_len = sechdrs[i].sh_size;
5798c2ecf20Sopenharmony_ci		} else if (strcmp(secname, "__ksymtab") == 0)
5808c2ecf20Sopenharmony_ci			info->export_sec = i;
5818c2ecf20Sopenharmony_ci		else if (strcmp(secname, "__ksymtab_unused") == 0)
5828c2ecf20Sopenharmony_ci			info->export_unused_sec = i;
5838c2ecf20Sopenharmony_ci		else if (strcmp(secname, "__ksymtab_gpl") == 0)
5848c2ecf20Sopenharmony_ci			info->export_gpl_sec = i;
5858c2ecf20Sopenharmony_ci		else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
5868c2ecf20Sopenharmony_ci			info->export_unused_gpl_sec = i;
5878c2ecf20Sopenharmony_ci		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
5888c2ecf20Sopenharmony_ci			info->export_gpl_future_sec = i;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		if (sechdrs[i].sh_type == SHT_SYMTAB) {
5918c2ecf20Sopenharmony_ci			unsigned int sh_link_idx;
5928c2ecf20Sopenharmony_ci			symtab_idx = i;
5938c2ecf20Sopenharmony_ci			info->symtab_start = (void *)hdr +
5948c2ecf20Sopenharmony_ci			    sechdrs[i].sh_offset;
5958c2ecf20Sopenharmony_ci			info->symtab_stop  = (void *)hdr +
5968c2ecf20Sopenharmony_ci			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
5978c2ecf20Sopenharmony_ci			sh_link_idx = sechdrs[i].sh_link;
5988c2ecf20Sopenharmony_ci			info->strtab       = (void *)hdr +
5998c2ecf20Sopenharmony_ci			    sechdrs[sh_link_idx].sh_offset;
6008c2ecf20Sopenharmony_ci		}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		/* 32bit section no. table? ("more than 64k sections") */
6038c2ecf20Sopenharmony_ci		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
6048c2ecf20Sopenharmony_ci			symtab_shndx_idx = i;
6058c2ecf20Sopenharmony_ci			info->symtab_shndx_start = (void *)hdr +
6068c2ecf20Sopenharmony_ci			    sechdrs[i].sh_offset;
6078c2ecf20Sopenharmony_ci			info->symtab_shndx_stop  = (void *)hdr +
6088c2ecf20Sopenharmony_ci			    sechdrs[i].sh_offset + sechdrs[i].sh_size;
6098c2ecf20Sopenharmony_ci		}
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci	if (!info->symtab_start)
6128c2ecf20Sopenharmony_ci		fatal("%s has no symtab?\n", filename);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	/* Fix endianness in symbols */
6158c2ecf20Sopenharmony_ci	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
6168c2ecf20Sopenharmony_ci		sym->st_shndx = TO_NATIVE(sym->st_shndx);
6178c2ecf20Sopenharmony_ci		sym->st_name  = TO_NATIVE(sym->st_name);
6188c2ecf20Sopenharmony_ci		sym->st_value = TO_NATIVE(sym->st_value);
6198c2ecf20Sopenharmony_ci		sym->st_size  = TO_NATIVE(sym->st_size);
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (symtab_shndx_idx != ~0U) {
6238c2ecf20Sopenharmony_ci		Elf32_Word *p;
6248c2ecf20Sopenharmony_ci		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
6258c2ecf20Sopenharmony_ci			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
6268c2ecf20Sopenharmony_ci			      filename, sechdrs[symtab_shndx_idx].sh_link,
6278c2ecf20Sopenharmony_ci			      symtab_idx);
6288c2ecf20Sopenharmony_ci		/* Fix endianness */
6298c2ecf20Sopenharmony_ci		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
6308c2ecf20Sopenharmony_ci		     p++)
6318c2ecf20Sopenharmony_ci			*p = TO_NATIVE(*p);
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	return 1;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic void parse_elf_finish(struct elf_info *info)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	release_file(info->hdr, info->size);
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int ignore_undef_symbol(struct elf_info *info, const char *symname)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	/* ignore __this_module, it will be resolved shortly */
6458c2ecf20Sopenharmony_ci	if (strcmp(symname, "__this_module") == 0)
6468c2ecf20Sopenharmony_ci		return 1;
6478c2ecf20Sopenharmony_ci	/* ignore global offset table */
6488c2ecf20Sopenharmony_ci	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
6498c2ecf20Sopenharmony_ci		return 1;
6508c2ecf20Sopenharmony_ci	if (info->hdr->e_machine == EM_PPC)
6518c2ecf20Sopenharmony_ci		/* Special register function linked on all modules during final link of .ko */
6528c2ecf20Sopenharmony_ci		if (strstarts(symname, "_restgpr_") ||
6538c2ecf20Sopenharmony_ci		    strstarts(symname, "_savegpr_") ||
6548c2ecf20Sopenharmony_ci		    strstarts(symname, "_rest32gpr_") ||
6558c2ecf20Sopenharmony_ci		    strstarts(symname, "_save32gpr_") ||
6568c2ecf20Sopenharmony_ci		    strstarts(symname, "_restvr_") ||
6578c2ecf20Sopenharmony_ci		    strstarts(symname, "_savevr_"))
6588c2ecf20Sopenharmony_ci			return 1;
6598c2ecf20Sopenharmony_ci	if (info->hdr->e_machine == EM_PPC64)
6608c2ecf20Sopenharmony_ci		/* Special register function linked on all modules during final link of .ko */
6618c2ecf20Sopenharmony_ci		if (strstarts(symname, "_restgpr0_") ||
6628c2ecf20Sopenharmony_ci		    strstarts(symname, "_savegpr0_") ||
6638c2ecf20Sopenharmony_ci		    strstarts(symname, "_restvr_") ||
6648c2ecf20Sopenharmony_ci		    strstarts(symname, "_savevr_") ||
6658c2ecf20Sopenharmony_ci		    strcmp(symname, ".TOC.") == 0)
6668c2ecf20Sopenharmony_ci			return 1;
6678c2ecf20Sopenharmony_ci	/* Do not ignore this symbol */
6688c2ecf20Sopenharmony_ci	return 0;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic void handle_modversion(const struct module *mod,
6728c2ecf20Sopenharmony_ci			      const struct elf_info *info,
6738c2ecf20Sopenharmony_ci			      const Elf_Sym *sym, const char *symname)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	unsigned int crc;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (sym->st_shndx == SHN_UNDEF) {
6788c2ecf20Sopenharmony_ci		warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
6798c2ecf20Sopenharmony_ci		     symname, mod->name, mod->is_vmlinux ? "" : ".ko");
6808c2ecf20Sopenharmony_ci		return;
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	if (sym->st_shndx == SHN_ABS) {
6848c2ecf20Sopenharmony_ci		crc = sym->st_value;
6858c2ecf20Sopenharmony_ci	} else {
6868c2ecf20Sopenharmony_ci		unsigned int *crcp;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		/* symbol points to the CRC in the ELF object */
6898c2ecf20Sopenharmony_ci		crcp = sym_get_data(info, sym);
6908c2ecf20Sopenharmony_ci		crc = TO_NATIVE(*crcp);
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci	sym_set_crc(symname, crc);
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistatic void handle_symbol(struct module *mod, struct elf_info *info,
6968c2ecf20Sopenharmony_ci			  const Elf_Sym *sym, const char *symname)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	enum export export;
6998c2ecf20Sopenharmony_ci	const char *name;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (strstarts(symname, "__ksymtab"))
7028c2ecf20Sopenharmony_ci		export = export_from_secname(info, get_secindex(info, sym));
7038c2ecf20Sopenharmony_ci	else
7048c2ecf20Sopenharmony_ci		export = export_from_sec(info, get_secindex(info, sym));
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	switch (sym->st_shndx) {
7078c2ecf20Sopenharmony_ci	case SHN_COMMON:
7088c2ecf20Sopenharmony_ci		if (strstarts(symname, "__gnu_lto_")) {
7098c2ecf20Sopenharmony_ci			/* Should warn here, but modpost runs before the linker */
7108c2ecf20Sopenharmony_ci		} else
7118c2ecf20Sopenharmony_ci			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
7128c2ecf20Sopenharmony_ci		break;
7138c2ecf20Sopenharmony_ci	case SHN_UNDEF:
7148c2ecf20Sopenharmony_ci		/* undefined symbol */
7158c2ecf20Sopenharmony_ci		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
7168c2ecf20Sopenharmony_ci		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
7178c2ecf20Sopenharmony_ci			break;
7188c2ecf20Sopenharmony_ci		if (ignore_undef_symbol(info, symname))
7198c2ecf20Sopenharmony_ci			break;
7208c2ecf20Sopenharmony_ci		if (info->hdr->e_machine == EM_SPARC ||
7218c2ecf20Sopenharmony_ci		    info->hdr->e_machine == EM_SPARCV9) {
7228c2ecf20Sopenharmony_ci			/* Ignore register directives. */
7238c2ecf20Sopenharmony_ci			if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
7248c2ecf20Sopenharmony_ci				break;
7258c2ecf20Sopenharmony_ci			if (symname[0] == '.') {
7268c2ecf20Sopenharmony_ci				char *munged = NOFAIL(strdup(symname));
7278c2ecf20Sopenharmony_ci				munged[0] = '_';
7288c2ecf20Sopenharmony_ci				munged[1] = toupper(munged[1]);
7298c2ecf20Sopenharmony_ci				symname = munged;
7308c2ecf20Sopenharmony_ci			}
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci		mod->unres = alloc_symbol(symname,
7348c2ecf20Sopenharmony_ci					  ELF_ST_BIND(sym->st_info) == STB_WEAK,
7358c2ecf20Sopenharmony_ci					  mod->unres);
7368c2ecf20Sopenharmony_ci		break;
7378c2ecf20Sopenharmony_ci	default:
7388c2ecf20Sopenharmony_ci		/* All exported symbols */
7398c2ecf20Sopenharmony_ci		if (strstarts(symname, "__ksymtab_")) {
7408c2ecf20Sopenharmony_ci			name = symname + strlen("__ksymtab_");
7418c2ecf20Sopenharmony_ci			sym_add_exported(name, mod, export);
7428c2ecf20Sopenharmony_ci		}
7438c2ecf20Sopenharmony_ci		if (strcmp(symname, "init_module") == 0)
7448c2ecf20Sopenharmony_ci			mod->has_init = 1;
7458c2ecf20Sopenharmony_ci		if (strcmp(symname, "cleanup_module") == 0)
7468c2ecf20Sopenharmony_ci			mod->has_cleanup = 1;
7478c2ecf20Sopenharmony_ci		break;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci/**
7528c2ecf20Sopenharmony_ci * Parse tag=value strings from .modinfo section
7538c2ecf20Sopenharmony_ci **/
7548c2ecf20Sopenharmony_cistatic char *next_string(char *string, unsigned long *secsize)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	/* Skip non-zero chars */
7578c2ecf20Sopenharmony_ci	while (string[0]) {
7588c2ecf20Sopenharmony_ci		string++;
7598c2ecf20Sopenharmony_ci		if ((*secsize)-- <= 1)
7608c2ecf20Sopenharmony_ci			return NULL;
7618c2ecf20Sopenharmony_ci	}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	/* Skip any zero padding. */
7648c2ecf20Sopenharmony_ci	while (!string[0]) {
7658c2ecf20Sopenharmony_ci		string++;
7668c2ecf20Sopenharmony_ci		if ((*secsize)-- <= 1)
7678c2ecf20Sopenharmony_ci			return NULL;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci	return string;
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic char *get_next_modinfo(struct elf_info *info, const char *tag,
7738c2ecf20Sopenharmony_ci			      char *prev)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	char *p;
7768c2ecf20Sopenharmony_ci	unsigned int taglen = strlen(tag);
7778c2ecf20Sopenharmony_ci	char *modinfo = info->modinfo;
7788c2ecf20Sopenharmony_ci	unsigned long size = info->modinfo_len;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (prev) {
7818c2ecf20Sopenharmony_ci		size -= prev - modinfo;
7828c2ecf20Sopenharmony_ci		modinfo = next_string(prev, &size);
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	for (p = modinfo; p; p = next_string(p, &size)) {
7868c2ecf20Sopenharmony_ci		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
7878c2ecf20Sopenharmony_ci			return p + taglen + 1;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci	return NULL;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic char *get_modinfo(struct elf_info *info, const char *tag)
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	return get_next_modinfo(info, tag, NULL);
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci/**
7998c2ecf20Sopenharmony_ci * Test if string s ends in string sub
8008c2ecf20Sopenharmony_ci * return 0 if match
8018c2ecf20Sopenharmony_ci **/
8028c2ecf20Sopenharmony_cistatic int strrcmp(const char *s, const char *sub)
8038c2ecf20Sopenharmony_ci{
8048c2ecf20Sopenharmony_ci	int slen, sublen;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (!s || !sub)
8078c2ecf20Sopenharmony_ci		return 1;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	slen = strlen(s);
8108c2ecf20Sopenharmony_ci	sublen = strlen(sub);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if ((slen == 0) || (sublen == 0))
8138c2ecf20Sopenharmony_ci		return 1;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (sublen > slen)
8168c2ecf20Sopenharmony_ci		return 1;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	return memcmp(s + slen - sublen, sub, sublen);
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_cistatic const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	if (sym)
8248c2ecf20Sopenharmony_ci		return elf->strtab + sym->st_name;
8258c2ecf20Sopenharmony_ci	else
8268c2ecf20Sopenharmony_ci		return "(unknown)";
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci/* The pattern is an array of simple patterns.
8308c2ecf20Sopenharmony_ci * "foo" will match an exact string equal to "foo"
8318c2ecf20Sopenharmony_ci * "*foo" will match a string that ends with "foo"
8328c2ecf20Sopenharmony_ci * "foo*" will match a string that begins with "foo"
8338c2ecf20Sopenharmony_ci * "*foo*" will match a string that contains "foo"
8348c2ecf20Sopenharmony_ci */
8358c2ecf20Sopenharmony_cistatic int match(const char *sym, const char * const pat[])
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	const char *p;
8388c2ecf20Sopenharmony_ci	while (*pat) {
8398c2ecf20Sopenharmony_ci		p = *pat++;
8408c2ecf20Sopenharmony_ci		const char *endp = p + strlen(p) - 1;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci		/* "*foo*" */
8438c2ecf20Sopenharmony_ci		if (*p == '*' && *endp == '*') {
8448c2ecf20Sopenharmony_ci			char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
8458c2ecf20Sopenharmony_ci			char *here = strstr(sym, bare);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci			free(bare);
8488c2ecf20Sopenharmony_ci			if (here != NULL)
8498c2ecf20Sopenharmony_ci				return 1;
8508c2ecf20Sopenharmony_ci		}
8518c2ecf20Sopenharmony_ci		/* "*foo" */
8528c2ecf20Sopenharmony_ci		else if (*p == '*') {
8538c2ecf20Sopenharmony_ci			if (strrcmp(sym, p + 1) == 0)
8548c2ecf20Sopenharmony_ci				return 1;
8558c2ecf20Sopenharmony_ci		}
8568c2ecf20Sopenharmony_ci		/* "foo*" */
8578c2ecf20Sopenharmony_ci		else if (*endp == '*') {
8588c2ecf20Sopenharmony_ci			if (strncmp(sym, p, strlen(p) - 1) == 0)
8598c2ecf20Sopenharmony_ci				return 1;
8608c2ecf20Sopenharmony_ci		}
8618c2ecf20Sopenharmony_ci		/* no wildcards */
8628c2ecf20Sopenharmony_ci		else {
8638c2ecf20Sopenharmony_ci			if (strcmp(p, sym) == 0)
8648c2ecf20Sopenharmony_ci				return 1;
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci	}
8678c2ecf20Sopenharmony_ci	/* no match */
8688c2ecf20Sopenharmony_ci	return 0;
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci/* sections that we do not want to do full section mismatch check on */
8728c2ecf20Sopenharmony_cistatic const char *const section_white_list[] =
8738c2ecf20Sopenharmony_ci{
8748c2ecf20Sopenharmony_ci	".comment*",
8758c2ecf20Sopenharmony_ci	".debug*",
8768c2ecf20Sopenharmony_ci	".cranges",		/* sh64 */
8778c2ecf20Sopenharmony_ci	".zdebug*",		/* Compressed debug sections. */
8788c2ecf20Sopenharmony_ci	".GCC.command.line",	/* record-gcc-switches */
8798c2ecf20Sopenharmony_ci	".mdebug*",        /* alpha, score, mips etc. */
8808c2ecf20Sopenharmony_ci	".pdr",            /* alpha, score, mips etc. */
8818c2ecf20Sopenharmony_ci	".stab*",
8828c2ecf20Sopenharmony_ci	".note*",
8838c2ecf20Sopenharmony_ci	".got*",
8848c2ecf20Sopenharmony_ci	".toc*",
8858c2ecf20Sopenharmony_ci	".xt.prop",				 /* xtensa */
8868c2ecf20Sopenharmony_ci	".xt.lit",         /* xtensa */
8878c2ecf20Sopenharmony_ci	".arcextmap*",			/* arc */
8888c2ecf20Sopenharmony_ci	".gnu.linkonce.arcext*",	/* arc : modules */
8898c2ecf20Sopenharmony_ci	".cmem*",			/* EZchip */
8908c2ecf20Sopenharmony_ci	".fmt_slot*",			/* EZchip */
8918c2ecf20Sopenharmony_ci	".gnu.lto*",
8928c2ecf20Sopenharmony_ci	".discard.*",
8938c2ecf20Sopenharmony_ci	NULL
8948c2ecf20Sopenharmony_ci};
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci/*
8978c2ecf20Sopenharmony_ci * This is used to find sections missing the SHF_ALLOC flag.
8988c2ecf20Sopenharmony_ci * The cause of this is often a section specified in assembler
8998c2ecf20Sopenharmony_ci * without "ax" / "aw".
9008c2ecf20Sopenharmony_ci */
9018c2ecf20Sopenharmony_cistatic void check_section(const char *modname, struct elf_info *elf,
9028c2ecf20Sopenharmony_ci			  Elf_Shdr *sechdr)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	const char *sec = sech_name(elf, sechdr);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	if (sechdr->sh_type == SHT_PROGBITS &&
9078c2ecf20Sopenharmony_ci	    !(sechdr->sh_flags & SHF_ALLOC) &&
9088c2ecf20Sopenharmony_ci	    !match(sec, section_white_list)) {
9098c2ecf20Sopenharmony_ci		warn("%s (%s): unexpected non-allocatable section.\n"
9108c2ecf20Sopenharmony_ci		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
9118c2ecf20Sopenharmony_ci		     "Note that for example <linux/init.h> contains\n"
9128c2ecf20Sopenharmony_ci		     "section definitions for use in .S files.\n\n",
9138c2ecf20Sopenharmony_ci		     modname, sec);
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci#define ALL_INIT_DATA_SECTIONS \
9208c2ecf20Sopenharmony_ci	".init.setup", ".init.rodata", ".meminit.rodata", \
9218c2ecf20Sopenharmony_ci	".init.data", ".meminit.data"
9228c2ecf20Sopenharmony_ci#define ALL_EXIT_DATA_SECTIONS \
9238c2ecf20Sopenharmony_ci	".exit.data", ".memexit.data"
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci#define ALL_INIT_TEXT_SECTIONS \
9268c2ecf20Sopenharmony_ci	".init.text", ".meminit.text"
9278c2ecf20Sopenharmony_ci#define ALL_EXIT_TEXT_SECTIONS \
9288c2ecf20Sopenharmony_ci	".exit.text", ".memexit.text"
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci#define ALL_PCI_INIT_SECTIONS	\
9318c2ecf20Sopenharmony_ci	".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \
9328c2ecf20Sopenharmony_ci	".pci_fixup_enable", ".pci_fixup_resume", \
9338c2ecf20Sopenharmony_ci	".pci_fixup_resume_early", ".pci_fixup_suspend"
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS
9368c2ecf20Sopenharmony_ci#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
9398c2ecf20Sopenharmony_ci#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci#define DATA_SECTIONS ".data", ".data.rel"
9428c2ecf20Sopenharmony_ci#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
9438c2ecf20Sopenharmony_ci		".kprobes.text", ".cpuidle.text", ".noinstr.text"
9448c2ecf20Sopenharmony_ci#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
9458c2ecf20Sopenharmony_ci		".fixup", ".entry.text", ".exception.text", ".text.*", \
9468c2ecf20Sopenharmony_ci		".coldtext"
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci#define INIT_SECTIONS      ".init.*"
9498c2ecf20Sopenharmony_ci#define MEM_INIT_SECTIONS  ".meminit.*"
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci#define EXIT_SECTIONS      ".exit.*"
9528c2ecf20Sopenharmony_ci#define MEM_EXIT_SECTIONS  ".memexit.*"
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci#define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
9558c2ecf20Sopenharmony_ci		TEXT_SECTIONS, OTHER_TEXT_SECTIONS
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci/* init data sections */
9588c2ecf20Sopenharmony_cistatic const char *const init_data_sections[] =
9598c2ecf20Sopenharmony_ci	{ ALL_INIT_DATA_SECTIONS, NULL };
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci/* all init sections */
9628c2ecf20Sopenharmony_cistatic const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci/* All init and exit sections (code + data) */
9658c2ecf20Sopenharmony_cistatic const char *const init_exit_sections[] =
9668c2ecf20Sopenharmony_ci	{ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci/* all text sections */
9698c2ecf20Sopenharmony_cistatic const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci/* data section */
9728c2ecf20Sopenharmony_cistatic const char *const data_sections[] = { DATA_SECTIONS, NULL };
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci/* symbols in .data that may refer to init/exit sections */
9768c2ecf20Sopenharmony_ci#define DEFAULT_SYMBOL_WHITE_LIST					\
9778c2ecf20Sopenharmony_ci	"*driver",							\
9788c2ecf20Sopenharmony_ci	"*_template", /* scsi uses *_template a lot */			\
9798c2ecf20Sopenharmony_ci	"*_timer",    /* arm uses ops structures named _timer a lot */	\
9808c2ecf20Sopenharmony_ci	"*_sht",      /* scsi also used *_sht to some extent */		\
9818c2ecf20Sopenharmony_ci	"*_ops",							\
9828c2ecf20Sopenharmony_ci	"*_probe",							\
9838c2ecf20Sopenharmony_ci	"*_probe_one",							\
9848c2ecf20Sopenharmony_ci	"*_console"
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic const char *const head_sections[] = { ".head.text*", NULL };
9878c2ecf20Sopenharmony_cistatic const char *const linker_symbols[] =
9888c2ecf20Sopenharmony_ci	{ "__init_begin", "_sinittext", "_einittext", NULL };
9898c2ecf20Sopenharmony_cistatic const char *const optim_symbols[] = { "*.constprop.*", NULL };
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_cienum mismatch {
9928c2ecf20Sopenharmony_ci	TEXT_TO_ANY_INIT,
9938c2ecf20Sopenharmony_ci	DATA_TO_ANY_INIT,
9948c2ecf20Sopenharmony_ci	TEXT_TO_ANY_EXIT,
9958c2ecf20Sopenharmony_ci	DATA_TO_ANY_EXIT,
9968c2ecf20Sopenharmony_ci	XXXINIT_TO_SOME_INIT,
9978c2ecf20Sopenharmony_ci	XXXEXIT_TO_SOME_EXIT,
9988c2ecf20Sopenharmony_ci	ANY_INIT_TO_ANY_EXIT,
9998c2ecf20Sopenharmony_ci	ANY_EXIT_TO_ANY_INIT,
10008c2ecf20Sopenharmony_ci	EXPORT_TO_INIT_EXIT,
10018c2ecf20Sopenharmony_ci	EXTABLE_TO_NON_TEXT,
10028c2ecf20Sopenharmony_ci};
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci/**
10058c2ecf20Sopenharmony_ci * Describe how to match sections on different criterias:
10068c2ecf20Sopenharmony_ci *
10078c2ecf20Sopenharmony_ci * @fromsec: Array of sections to be matched.
10088c2ecf20Sopenharmony_ci *
10098c2ecf20Sopenharmony_ci * @bad_tosec: Relocations applied to a section in @fromsec to a section in
10108c2ecf20Sopenharmony_ci * this array is forbidden (black-list).  Can be empty.
10118c2ecf20Sopenharmony_ci *
10128c2ecf20Sopenharmony_ci * @good_tosec: Relocations applied to a section in @fromsec must be
10138c2ecf20Sopenharmony_ci * targetting sections in this array (white-list).  Can be empty.
10148c2ecf20Sopenharmony_ci *
10158c2ecf20Sopenharmony_ci * @mismatch: Type of mismatch.
10168c2ecf20Sopenharmony_ci *
10178c2ecf20Sopenharmony_ci * @symbol_white_list: Do not match a relocation to a symbol in this list
10188c2ecf20Sopenharmony_ci * even if it is targetting a section in @bad_to_sec.
10198c2ecf20Sopenharmony_ci *
10208c2ecf20Sopenharmony_ci * @handler: Specific handler to call when a match is found.  If NULL,
10218c2ecf20Sopenharmony_ci * default_mismatch_handler() will be called.
10228c2ecf20Sopenharmony_ci *
10238c2ecf20Sopenharmony_ci */
10248c2ecf20Sopenharmony_cistruct sectioncheck {
10258c2ecf20Sopenharmony_ci	const char *fromsec[20];
10268c2ecf20Sopenharmony_ci	const char *bad_tosec[20];
10278c2ecf20Sopenharmony_ci	const char *good_tosec[20];
10288c2ecf20Sopenharmony_ci	enum mismatch mismatch;
10298c2ecf20Sopenharmony_ci	const char *symbol_white_list[20];
10308c2ecf20Sopenharmony_ci	void (*handler)(const char *modname, struct elf_info *elf,
10318c2ecf20Sopenharmony_ci			const struct sectioncheck* const mismatch,
10328c2ecf20Sopenharmony_ci			Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci};
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_cistatic void extable_mismatch_handler(const char *modname, struct elf_info *elf,
10378c2ecf20Sopenharmony_ci				     const struct sectioncheck* const mismatch,
10388c2ecf20Sopenharmony_ci				     Elf_Rela *r, Elf_Sym *sym,
10398c2ecf20Sopenharmony_ci				     const char *fromsec);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic const struct sectioncheck sectioncheck[] = {
10428c2ecf20Sopenharmony_ci/* Do not reference init/exit code/data from
10438c2ecf20Sopenharmony_ci * normal code and data
10448c2ecf20Sopenharmony_ci */
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	.fromsec = { TEXT_SECTIONS, NULL },
10478c2ecf20Sopenharmony_ci	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
10488c2ecf20Sopenharmony_ci	.mismatch = TEXT_TO_ANY_INIT,
10498c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
10508c2ecf20Sopenharmony_ci},
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	.fromsec = { DATA_SECTIONS, NULL },
10538c2ecf20Sopenharmony_ci	.bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
10548c2ecf20Sopenharmony_ci	.mismatch = DATA_TO_ANY_INIT,
10558c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
10568c2ecf20Sopenharmony_ci},
10578c2ecf20Sopenharmony_ci{
10588c2ecf20Sopenharmony_ci	.fromsec = { DATA_SECTIONS, NULL },
10598c2ecf20Sopenharmony_ci	.bad_tosec = { INIT_SECTIONS, NULL },
10608c2ecf20Sopenharmony_ci	.mismatch = DATA_TO_ANY_INIT,
10618c2ecf20Sopenharmony_ci	.symbol_white_list = {
10628c2ecf20Sopenharmony_ci		"*_template", "*_timer", "*_sht", "*_ops",
10638c2ecf20Sopenharmony_ci		"*_probe", "*_probe_one", "*_console", NULL
10648c2ecf20Sopenharmony_ci	},
10658c2ecf20Sopenharmony_ci},
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	.fromsec = { TEXT_SECTIONS, NULL },
10688c2ecf20Sopenharmony_ci	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
10698c2ecf20Sopenharmony_ci	.mismatch = TEXT_TO_ANY_EXIT,
10708c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
10718c2ecf20Sopenharmony_ci},
10728c2ecf20Sopenharmony_ci{
10738c2ecf20Sopenharmony_ci	.fromsec = { DATA_SECTIONS, NULL },
10748c2ecf20Sopenharmony_ci	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
10758c2ecf20Sopenharmony_ci	.mismatch = DATA_TO_ANY_EXIT,
10768c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
10778c2ecf20Sopenharmony_ci},
10788c2ecf20Sopenharmony_ci/* Do not reference init code/data from meminit code/data */
10798c2ecf20Sopenharmony_ci{
10808c2ecf20Sopenharmony_ci	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
10818c2ecf20Sopenharmony_ci	.bad_tosec = { INIT_SECTIONS, NULL },
10828c2ecf20Sopenharmony_ci	.mismatch = XXXINIT_TO_SOME_INIT,
10838c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
10848c2ecf20Sopenharmony_ci},
10858c2ecf20Sopenharmony_ci/* Do not reference exit code/data from memexit code/data */
10868c2ecf20Sopenharmony_ci{
10878c2ecf20Sopenharmony_ci	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
10888c2ecf20Sopenharmony_ci	.bad_tosec = { EXIT_SECTIONS, NULL },
10898c2ecf20Sopenharmony_ci	.mismatch = XXXEXIT_TO_SOME_EXIT,
10908c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
10918c2ecf20Sopenharmony_ci},
10928c2ecf20Sopenharmony_ci/* Do not use exit code/data from init code */
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	.fromsec = { ALL_INIT_SECTIONS, NULL },
10958c2ecf20Sopenharmony_ci	.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
10968c2ecf20Sopenharmony_ci	.mismatch = ANY_INIT_TO_ANY_EXIT,
10978c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
10988c2ecf20Sopenharmony_ci},
10998c2ecf20Sopenharmony_ci/* Do not use init code/data from exit code */
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	.fromsec = { ALL_EXIT_SECTIONS, NULL },
11028c2ecf20Sopenharmony_ci	.bad_tosec = { ALL_INIT_SECTIONS, NULL },
11038c2ecf20Sopenharmony_ci	.mismatch = ANY_EXIT_TO_ANY_INIT,
11048c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
11058c2ecf20Sopenharmony_ci},
11068c2ecf20Sopenharmony_ci{
11078c2ecf20Sopenharmony_ci	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
11088c2ecf20Sopenharmony_ci	.bad_tosec = { INIT_SECTIONS, NULL },
11098c2ecf20Sopenharmony_ci	.mismatch = ANY_INIT_TO_ANY_EXIT,
11108c2ecf20Sopenharmony_ci	.symbol_white_list = { NULL },
11118c2ecf20Sopenharmony_ci},
11128c2ecf20Sopenharmony_ci/* Do not export init/exit functions or data */
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	.fromsec = { "___ksymtab*", NULL },
11158c2ecf20Sopenharmony_ci	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
11168c2ecf20Sopenharmony_ci	.mismatch = EXPORT_TO_INIT_EXIT,
11178c2ecf20Sopenharmony_ci	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
11188c2ecf20Sopenharmony_ci},
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	.fromsec = { "__ex_table", NULL },
11218c2ecf20Sopenharmony_ci	/* If you're adding any new black-listed sections in here, consider
11228c2ecf20Sopenharmony_ci	 * adding a special 'printer' for them in scripts/check_extable.
11238c2ecf20Sopenharmony_ci	 */
11248c2ecf20Sopenharmony_ci	.bad_tosec = { ".altinstr_replacement", NULL },
11258c2ecf20Sopenharmony_ci	.good_tosec = {ALL_TEXT_SECTIONS , NULL},
11268c2ecf20Sopenharmony_ci	.mismatch = EXTABLE_TO_NON_TEXT,
11278c2ecf20Sopenharmony_ci	.handler = extable_mismatch_handler,
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci};
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_cistatic const struct sectioncheck *section_mismatch(
11328c2ecf20Sopenharmony_ci		const char *fromsec, const char *tosec)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	int i;
11358c2ecf20Sopenharmony_ci	int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
11368c2ecf20Sopenharmony_ci	const struct sectioncheck *check = &sectioncheck[0];
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	/*
11398c2ecf20Sopenharmony_ci	 * The target section could be the SHT_NUL section when we're
11408c2ecf20Sopenharmony_ci	 * handling relocations to un-resolved symbols, trying to match it
11418c2ecf20Sopenharmony_ci	 * doesn't make much sense and causes build failures on parisc
11428c2ecf20Sopenharmony_ci	 * architectures.
11438c2ecf20Sopenharmony_ci	 */
11448c2ecf20Sopenharmony_ci	if (*tosec == '\0')
11458c2ecf20Sopenharmony_ci		return NULL;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	for (i = 0; i < elems; i++) {
11488c2ecf20Sopenharmony_ci		if (match(fromsec, check->fromsec)) {
11498c2ecf20Sopenharmony_ci			if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
11508c2ecf20Sopenharmony_ci				return check;
11518c2ecf20Sopenharmony_ci			if (check->good_tosec[0] && !match(tosec, check->good_tosec))
11528c2ecf20Sopenharmony_ci				return check;
11538c2ecf20Sopenharmony_ci		}
11548c2ecf20Sopenharmony_ci		check++;
11558c2ecf20Sopenharmony_ci	}
11568c2ecf20Sopenharmony_ci	return NULL;
11578c2ecf20Sopenharmony_ci}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci/**
11608c2ecf20Sopenharmony_ci * Whitelist to allow certain references to pass with no warning.
11618c2ecf20Sopenharmony_ci *
11628c2ecf20Sopenharmony_ci * Pattern 1:
11638c2ecf20Sopenharmony_ci *   If a module parameter is declared __initdata and permissions=0
11648c2ecf20Sopenharmony_ci *   then this is legal despite the warning generated.
11658c2ecf20Sopenharmony_ci *   We cannot see value of permissions here, so just ignore
11668c2ecf20Sopenharmony_ci *   this pattern.
11678c2ecf20Sopenharmony_ci *   The pattern is identified by:
11688c2ecf20Sopenharmony_ci *   tosec   = .init.data
11698c2ecf20Sopenharmony_ci *   fromsec = .data*
11708c2ecf20Sopenharmony_ci *   atsym   =__param*
11718c2ecf20Sopenharmony_ci *
11728c2ecf20Sopenharmony_ci * Pattern 1a:
11738c2ecf20Sopenharmony_ci *   module_param_call() ops can refer to __init set function if permissions=0
11748c2ecf20Sopenharmony_ci *   The pattern is identified by:
11758c2ecf20Sopenharmony_ci *   tosec   = .init.text
11768c2ecf20Sopenharmony_ci *   fromsec = .data*
11778c2ecf20Sopenharmony_ci *   atsym   = __param_ops_*
11788c2ecf20Sopenharmony_ci *
11798c2ecf20Sopenharmony_ci * Pattern 2:
11808c2ecf20Sopenharmony_ci *   Many drivers utilise a *driver container with references to
11818c2ecf20Sopenharmony_ci *   add, remove, probe functions etc.
11828c2ecf20Sopenharmony_ci *   the pattern is identified by:
11838c2ecf20Sopenharmony_ci *   tosec   = init or exit section
11848c2ecf20Sopenharmony_ci *   fromsec = data section
11858c2ecf20Sopenharmony_ci *   atsym = *driver, *_template, *_sht, *_ops, *_probe,
11868c2ecf20Sopenharmony_ci *           *probe_one, *_console, *_timer
11878c2ecf20Sopenharmony_ci *
11888c2ecf20Sopenharmony_ci * Pattern 3:
11898c2ecf20Sopenharmony_ci *   Whitelist all references from .head.text to any init section
11908c2ecf20Sopenharmony_ci *
11918c2ecf20Sopenharmony_ci * Pattern 4:
11928c2ecf20Sopenharmony_ci *   Some symbols belong to init section but still it is ok to reference
11938c2ecf20Sopenharmony_ci *   these from non-init sections as these symbols don't have any memory
11948c2ecf20Sopenharmony_ci *   allocated for them and symbol address and value are same. So even
11958c2ecf20Sopenharmony_ci *   if init section is freed, its ok to reference those symbols.
11968c2ecf20Sopenharmony_ci *   For ex. symbols marking the init section boundaries.
11978c2ecf20Sopenharmony_ci *   This pattern is identified by
11988c2ecf20Sopenharmony_ci *   refsymname = __init_begin, _sinittext, _einittext
11998c2ecf20Sopenharmony_ci *
12008c2ecf20Sopenharmony_ci * Pattern 5:
12018c2ecf20Sopenharmony_ci *   GCC may optimize static inlines when fed constant arg(s) resulting
12028c2ecf20Sopenharmony_ci *   in functions like cpumask_empty() -- generating an associated symbol
12038c2ecf20Sopenharmony_ci *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
12048c2ecf20Sopenharmony_ci *   is passed in comes from __init, like say nmi_ipi_mask, we get a
12058c2ecf20Sopenharmony_ci *   meaningless section warning.  May need to add isra symbols too...
12068c2ecf20Sopenharmony_ci *   This pattern is identified by
12078c2ecf20Sopenharmony_ci *   tosec   = init section
12088c2ecf20Sopenharmony_ci *   fromsec = text section
12098c2ecf20Sopenharmony_ci *   refsymname = *.constprop.*
12108c2ecf20Sopenharmony_ci *
12118c2ecf20Sopenharmony_ci * Pattern 6:
12128c2ecf20Sopenharmony_ci *   Hide section mismatch warnings for ELF local symbols.  The goal
12138c2ecf20Sopenharmony_ci *   is to eliminate false positive modpost warnings caused by
12148c2ecf20Sopenharmony_ci *   compiler-generated ELF local symbol names such as ".LANCHOR1".
12158c2ecf20Sopenharmony_ci *   Autogenerated symbol names bypass modpost's "Pattern 2"
12168c2ecf20Sopenharmony_ci *   whitelisting, which relies on pattern-matching against symbol
12178c2ecf20Sopenharmony_ci *   names to work.  (One situation where gcc can autogenerate ELF
12188c2ecf20Sopenharmony_ci *   local symbols is when "-fsection-anchors" is used.)
12198c2ecf20Sopenharmony_ci **/
12208c2ecf20Sopenharmony_cistatic int secref_whitelist(const struct sectioncheck *mismatch,
12218c2ecf20Sopenharmony_ci			    const char *fromsec, const char *fromsym,
12228c2ecf20Sopenharmony_ci			    const char *tosec, const char *tosym)
12238c2ecf20Sopenharmony_ci{
12248c2ecf20Sopenharmony_ci	/* Check for pattern 1 */
12258c2ecf20Sopenharmony_ci	if (match(tosec, init_data_sections) &&
12268c2ecf20Sopenharmony_ci	    match(fromsec, data_sections) &&
12278c2ecf20Sopenharmony_ci	    strstarts(fromsym, "__param"))
12288c2ecf20Sopenharmony_ci		return 0;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	/* Check for pattern 1a */
12318c2ecf20Sopenharmony_ci	if (strcmp(tosec, ".init.text") == 0 &&
12328c2ecf20Sopenharmony_ci	    match(fromsec, data_sections) &&
12338c2ecf20Sopenharmony_ci	    strstarts(fromsym, "__param_ops_"))
12348c2ecf20Sopenharmony_ci		return 0;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	/* Check for pattern 2 */
12378c2ecf20Sopenharmony_ci	if (match(tosec, init_exit_sections) &&
12388c2ecf20Sopenharmony_ci	    match(fromsec, data_sections) &&
12398c2ecf20Sopenharmony_ci	    match(fromsym, mismatch->symbol_white_list))
12408c2ecf20Sopenharmony_ci		return 0;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	/* Check for pattern 3 */
12438c2ecf20Sopenharmony_ci	if (match(fromsec, head_sections) &&
12448c2ecf20Sopenharmony_ci	    match(tosec, init_sections))
12458c2ecf20Sopenharmony_ci		return 0;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	/* Check for pattern 4 */
12488c2ecf20Sopenharmony_ci	if (match(tosym, linker_symbols))
12498c2ecf20Sopenharmony_ci		return 0;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	/* Check for pattern 5 */
12528c2ecf20Sopenharmony_ci	if (match(fromsec, text_sections) &&
12538c2ecf20Sopenharmony_ci	    match(tosec, init_sections) &&
12548c2ecf20Sopenharmony_ci	    match(fromsym, optim_symbols))
12558c2ecf20Sopenharmony_ci		return 0;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	/* Check for pattern 6 */
12588c2ecf20Sopenharmony_ci	if (strstarts(fromsym, ".L"))
12598c2ecf20Sopenharmony_ci		return 0;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	return 1;
12628c2ecf20Sopenharmony_ci}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_cistatic inline int is_arm_mapping_symbol(const char *str)
12658c2ecf20Sopenharmony_ci{
12668c2ecf20Sopenharmony_ci	return str[0] == '$' &&
12678c2ecf20Sopenharmony_ci	       (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x')
12688c2ecf20Sopenharmony_ci	       && (str[2] == '\0' || str[2] == '.');
12698c2ecf20Sopenharmony_ci}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci/*
12728c2ecf20Sopenharmony_ci * If there's no name there, ignore it; likewise, ignore it if it's
12738c2ecf20Sopenharmony_ci * one of the magic symbols emitted used by current ARM tools.
12748c2ecf20Sopenharmony_ci *
12758c2ecf20Sopenharmony_ci * Otherwise if find_symbols_between() returns those symbols, they'll
12768c2ecf20Sopenharmony_ci * fail the whitelist tests and cause lots of false alarms ... fixable
12778c2ecf20Sopenharmony_ci * only by merging __exit and __init sections into __text, bloating
12788c2ecf20Sopenharmony_ci * the kernel (which is especially evil on embedded platforms).
12798c2ecf20Sopenharmony_ci */
12808c2ecf20Sopenharmony_cistatic inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
12818c2ecf20Sopenharmony_ci{
12828c2ecf20Sopenharmony_ci	const char *name = elf->strtab + sym->st_name;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	if (!name || !strlen(name))
12858c2ecf20Sopenharmony_ci		return 0;
12868c2ecf20Sopenharmony_ci	return !is_arm_mapping_symbol(name);
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci/**
12908c2ecf20Sopenharmony_ci * Find symbol based on relocation record info.
12918c2ecf20Sopenharmony_ci * In some cases the symbol supplied is a valid symbol so
12928c2ecf20Sopenharmony_ci * return refsym. If st_name != 0 we assume this is a valid symbol.
12938c2ecf20Sopenharmony_ci * In other cases the symbol needs to be looked up in the symbol table
12948c2ecf20Sopenharmony_ci * based on section and address.
12958c2ecf20Sopenharmony_ci *  **/
12968c2ecf20Sopenharmony_cistatic Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
12978c2ecf20Sopenharmony_ci				Elf_Sym *relsym)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	Elf_Sym *sym;
13008c2ecf20Sopenharmony_ci	Elf_Sym *near = NULL;
13018c2ecf20Sopenharmony_ci	Elf64_Sword distance = 20;
13028c2ecf20Sopenharmony_ci	Elf64_Sword d;
13038c2ecf20Sopenharmony_ci	unsigned int relsym_secindex;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	if (relsym->st_name != 0)
13068c2ecf20Sopenharmony_ci		return relsym;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	/*
13098c2ecf20Sopenharmony_ci	 * Strive to find a better symbol name, but the resulting name may not
13108c2ecf20Sopenharmony_ci	 * match the symbol referenced in the original code.
13118c2ecf20Sopenharmony_ci	 */
13128c2ecf20Sopenharmony_ci	relsym_secindex = get_secindex(elf, relsym);
13138c2ecf20Sopenharmony_ci	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
13148c2ecf20Sopenharmony_ci		if (get_secindex(elf, sym) != relsym_secindex)
13158c2ecf20Sopenharmony_ci			continue;
13168c2ecf20Sopenharmony_ci		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
13178c2ecf20Sopenharmony_ci			continue;
13188c2ecf20Sopenharmony_ci		if (!is_valid_name(elf, sym))
13198c2ecf20Sopenharmony_ci			continue;
13208c2ecf20Sopenharmony_ci		if (sym->st_value == addr)
13218c2ecf20Sopenharmony_ci			return sym;
13228c2ecf20Sopenharmony_ci		/* Find a symbol nearby - addr are maybe negative */
13238c2ecf20Sopenharmony_ci		d = sym->st_value - addr;
13248c2ecf20Sopenharmony_ci		if (d < 0)
13258c2ecf20Sopenharmony_ci			d = addr - sym->st_value;
13268c2ecf20Sopenharmony_ci		if (d < distance) {
13278c2ecf20Sopenharmony_ci			distance = d;
13288c2ecf20Sopenharmony_ci			near = sym;
13298c2ecf20Sopenharmony_ci		}
13308c2ecf20Sopenharmony_ci	}
13318c2ecf20Sopenharmony_ci	/* We need a close match */
13328c2ecf20Sopenharmony_ci	if (distance < 20)
13338c2ecf20Sopenharmony_ci		return near;
13348c2ecf20Sopenharmony_ci	else
13358c2ecf20Sopenharmony_ci		return NULL;
13368c2ecf20Sopenharmony_ci}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci/*
13398c2ecf20Sopenharmony_ci * Find symbols before or equal addr and after addr - in the section sec.
13408c2ecf20Sopenharmony_ci * If we find two symbols with equal offset prefer one with a valid name.
13418c2ecf20Sopenharmony_ci * The ELF format may have a better way to detect what type of symbol
13428c2ecf20Sopenharmony_ci * it is, but this works for now.
13438c2ecf20Sopenharmony_ci **/
13448c2ecf20Sopenharmony_cistatic Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
13458c2ecf20Sopenharmony_ci				 const char *sec)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	Elf_Sym *sym;
13488c2ecf20Sopenharmony_ci	Elf_Sym *near = NULL;
13498c2ecf20Sopenharmony_ci	Elf_Addr distance = ~0;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
13528c2ecf20Sopenharmony_ci		const char *symsec;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci		if (is_shndx_special(sym->st_shndx))
13558c2ecf20Sopenharmony_ci			continue;
13568c2ecf20Sopenharmony_ci		symsec = sec_name(elf, get_secindex(elf, sym));
13578c2ecf20Sopenharmony_ci		if (strcmp(symsec, sec) != 0)
13588c2ecf20Sopenharmony_ci			continue;
13598c2ecf20Sopenharmony_ci		if (!is_valid_name(elf, sym))
13608c2ecf20Sopenharmony_ci			continue;
13618c2ecf20Sopenharmony_ci		if (sym->st_value <= addr) {
13628c2ecf20Sopenharmony_ci			if ((addr - sym->st_value) < distance) {
13638c2ecf20Sopenharmony_ci				distance = addr - sym->st_value;
13648c2ecf20Sopenharmony_ci				near = sym;
13658c2ecf20Sopenharmony_ci			} else if ((addr - sym->st_value) == distance) {
13668c2ecf20Sopenharmony_ci				near = sym;
13678c2ecf20Sopenharmony_ci			}
13688c2ecf20Sopenharmony_ci		}
13698c2ecf20Sopenharmony_ci	}
13708c2ecf20Sopenharmony_ci	return near;
13718c2ecf20Sopenharmony_ci}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci/*
13748c2ecf20Sopenharmony_ci * Convert a section name to the function/data attribute
13758c2ecf20Sopenharmony_ci * .init.text => __init
13768c2ecf20Sopenharmony_ci * .memexitconst => __memconst
13778c2ecf20Sopenharmony_ci * etc.
13788c2ecf20Sopenharmony_ci *
13798c2ecf20Sopenharmony_ci * The memory of returned value has been allocated on a heap. The user of this
13808c2ecf20Sopenharmony_ci * method should free it after usage.
13818c2ecf20Sopenharmony_ci*/
13828c2ecf20Sopenharmony_cistatic char *sec2annotation(const char *s)
13838c2ecf20Sopenharmony_ci{
13848c2ecf20Sopenharmony_ci	if (match(s, init_exit_sections)) {
13858c2ecf20Sopenharmony_ci		char *p = NOFAIL(malloc(20));
13868c2ecf20Sopenharmony_ci		char *r = p;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci		*p++ = '_';
13898c2ecf20Sopenharmony_ci		*p++ = '_';
13908c2ecf20Sopenharmony_ci		if (*s == '.')
13918c2ecf20Sopenharmony_ci			s++;
13928c2ecf20Sopenharmony_ci		while (*s && *s != '.')
13938c2ecf20Sopenharmony_ci			*p++ = *s++;
13948c2ecf20Sopenharmony_ci		*p = '\0';
13958c2ecf20Sopenharmony_ci		if (*s == '.')
13968c2ecf20Sopenharmony_ci			s++;
13978c2ecf20Sopenharmony_ci		if (strstr(s, "rodata") != NULL)
13988c2ecf20Sopenharmony_ci			strcat(p, "const ");
13998c2ecf20Sopenharmony_ci		else if (strstr(s, "data") != NULL)
14008c2ecf20Sopenharmony_ci			strcat(p, "data ");
14018c2ecf20Sopenharmony_ci		else
14028c2ecf20Sopenharmony_ci			strcat(p, " ");
14038c2ecf20Sopenharmony_ci		return r;
14048c2ecf20Sopenharmony_ci	} else {
14058c2ecf20Sopenharmony_ci		return NOFAIL(strdup(""));
14068c2ecf20Sopenharmony_ci	}
14078c2ecf20Sopenharmony_ci}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_cistatic int is_function(Elf_Sym *sym)
14108c2ecf20Sopenharmony_ci{
14118c2ecf20Sopenharmony_ci	if (sym)
14128c2ecf20Sopenharmony_ci		return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
14138c2ecf20Sopenharmony_ci	else
14148c2ecf20Sopenharmony_ci		return -1;
14158c2ecf20Sopenharmony_ci}
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_cistatic void print_section_list(const char * const list[20])
14188c2ecf20Sopenharmony_ci{
14198c2ecf20Sopenharmony_ci	const char *const *s = list;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	while (*s) {
14228c2ecf20Sopenharmony_ci		fprintf(stderr, "%s", *s);
14238c2ecf20Sopenharmony_ci		s++;
14248c2ecf20Sopenharmony_ci		if (*s)
14258c2ecf20Sopenharmony_ci			fprintf(stderr, ", ");
14268c2ecf20Sopenharmony_ci	}
14278c2ecf20Sopenharmony_ci	fprintf(stderr, "\n");
14288c2ecf20Sopenharmony_ci}
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_cistatic inline void get_pretty_name(int is_func, const char** name, const char** name_p)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	switch (is_func) {
14338c2ecf20Sopenharmony_ci	case 0:	*name = "variable"; *name_p = ""; break;
14348c2ecf20Sopenharmony_ci	case 1:	*name = "function"; *name_p = "()"; break;
14358c2ecf20Sopenharmony_ci	default: *name = "(unknown reference)"; *name_p = ""; break;
14368c2ecf20Sopenharmony_ci	}
14378c2ecf20Sopenharmony_ci}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci/*
14408c2ecf20Sopenharmony_ci * Print a warning about a section mismatch.
14418c2ecf20Sopenharmony_ci * Try to find symbols near it so user can find it.
14428c2ecf20Sopenharmony_ci * Check whitelist before warning - it may be a false positive.
14438c2ecf20Sopenharmony_ci */
14448c2ecf20Sopenharmony_cistatic void report_sec_mismatch(const char *modname,
14458c2ecf20Sopenharmony_ci				const struct sectioncheck *mismatch,
14468c2ecf20Sopenharmony_ci				const char *fromsec,
14478c2ecf20Sopenharmony_ci				unsigned long long fromaddr,
14488c2ecf20Sopenharmony_ci				const char *fromsym,
14498c2ecf20Sopenharmony_ci				int from_is_func,
14508c2ecf20Sopenharmony_ci				const char *tosec, const char *tosym,
14518c2ecf20Sopenharmony_ci				int to_is_func)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	const char *from, *from_p;
14548c2ecf20Sopenharmony_ci	const char *to, *to_p;
14558c2ecf20Sopenharmony_ci	char *prl_from;
14568c2ecf20Sopenharmony_ci	char *prl_to;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	sec_mismatch_count++;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	get_pretty_name(from_is_func, &from, &from_p);
14618c2ecf20Sopenharmony_ci	get_pretty_name(to_is_func, &to, &to_p);
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
14648c2ecf20Sopenharmony_ci	     "to the %s %s:%s%s\n",
14658c2ecf20Sopenharmony_ci	     modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
14668c2ecf20Sopenharmony_ci	     tosym, to_p);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	switch (mismatch->mismatch) {
14698c2ecf20Sopenharmony_ci	case TEXT_TO_ANY_INIT:
14708c2ecf20Sopenharmony_ci		prl_from = sec2annotation(fromsec);
14718c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
14728c2ecf20Sopenharmony_ci		fprintf(stderr,
14738c2ecf20Sopenharmony_ci		"The function %s%s() references\n"
14748c2ecf20Sopenharmony_ci		"the %s %s%s%s.\n"
14758c2ecf20Sopenharmony_ci		"This is often because %s lacks a %s\n"
14768c2ecf20Sopenharmony_ci		"annotation or the annotation of %s is wrong.\n",
14778c2ecf20Sopenharmony_ci		prl_from, fromsym,
14788c2ecf20Sopenharmony_ci		to, prl_to, tosym, to_p,
14798c2ecf20Sopenharmony_ci		fromsym, prl_to, tosym);
14808c2ecf20Sopenharmony_ci		free(prl_from);
14818c2ecf20Sopenharmony_ci		free(prl_to);
14828c2ecf20Sopenharmony_ci		break;
14838c2ecf20Sopenharmony_ci	case DATA_TO_ANY_INIT: {
14848c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
14858c2ecf20Sopenharmony_ci		fprintf(stderr,
14868c2ecf20Sopenharmony_ci		"The variable %s references\n"
14878c2ecf20Sopenharmony_ci		"the %s %s%s%s\n"
14888c2ecf20Sopenharmony_ci		"If the reference is valid then annotate the\n"
14898c2ecf20Sopenharmony_ci		"variable with __init* or __refdata (see linux/init.h) "
14908c2ecf20Sopenharmony_ci		"or name the variable:\n",
14918c2ecf20Sopenharmony_ci		fromsym, to, prl_to, tosym, to_p);
14928c2ecf20Sopenharmony_ci		print_section_list(mismatch->symbol_white_list);
14938c2ecf20Sopenharmony_ci		free(prl_to);
14948c2ecf20Sopenharmony_ci		break;
14958c2ecf20Sopenharmony_ci	}
14968c2ecf20Sopenharmony_ci	case TEXT_TO_ANY_EXIT:
14978c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
14988c2ecf20Sopenharmony_ci		fprintf(stderr,
14998c2ecf20Sopenharmony_ci		"The function %s() references a %s in an exit section.\n"
15008c2ecf20Sopenharmony_ci		"Often the %s %s%s has valid usage outside the exit section\n"
15018c2ecf20Sopenharmony_ci		"and the fix is to remove the %sannotation of %s.\n",
15028c2ecf20Sopenharmony_ci		fromsym, to, to, tosym, to_p, prl_to, tosym);
15038c2ecf20Sopenharmony_ci		free(prl_to);
15048c2ecf20Sopenharmony_ci		break;
15058c2ecf20Sopenharmony_ci	case DATA_TO_ANY_EXIT: {
15068c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
15078c2ecf20Sopenharmony_ci		fprintf(stderr,
15088c2ecf20Sopenharmony_ci		"The variable %s references\n"
15098c2ecf20Sopenharmony_ci		"the %s %s%s%s\n"
15108c2ecf20Sopenharmony_ci		"If the reference is valid then annotate the\n"
15118c2ecf20Sopenharmony_ci		"variable with __exit* (see linux/init.h) or "
15128c2ecf20Sopenharmony_ci		"name the variable:\n",
15138c2ecf20Sopenharmony_ci		fromsym, to, prl_to, tosym, to_p);
15148c2ecf20Sopenharmony_ci		print_section_list(mismatch->symbol_white_list);
15158c2ecf20Sopenharmony_ci		free(prl_to);
15168c2ecf20Sopenharmony_ci		break;
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci	case XXXINIT_TO_SOME_INIT:
15198c2ecf20Sopenharmony_ci	case XXXEXIT_TO_SOME_EXIT:
15208c2ecf20Sopenharmony_ci		prl_from = sec2annotation(fromsec);
15218c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
15228c2ecf20Sopenharmony_ci		fprintf(stderr,
15238c2ecf20Sopenharmony_ci		"The %s %s%s%s references\n"
15248c2ecf20Sopenharmony_ci		"a %s %s%s%s.\n"
15258c2ecf20Sopenharmony_ci		"If %s is only used by %s then\n"
15268c2ecf20Sopenharmony_ci		"annotate %s with a matching annotation.\n",
15278c2ecf20Sopenharmony_ci		from, prl_from, fromsym, from_p,
15288c2ecf20Sopenharmony_ci		to, prl_to, tosym, to_p,
15298c2ecf20Sopenharmony_ci		tosym, fromsym, tosym);
15308c2ecf20Sopenharmony_ci		free(prl_from);
15318c2ecf20Sopenharmony_ci		free(prl_to);
15328c2ecf20Sopenharmony_ci		break;
15338c2ecf20Sopenharmony_ci	case ANY_INIT_TO_ANY_EXIT:
15348c2ecf20Sopenharmony_ci		prl_from = sec2annotation(fromsec);
15358c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
15368c2ecf20Sopenharmony_ci		fprintf(stderr,
15378c2ecf20Sopenharmony_ci		"The %s %s%s%s references\n"
15388c2ecf20Sopenharmony_ci		"a %s %s%s%s.\n"
15398c2ecf20Sopenharmony_ci		"This is often seen when error handling "
15408c2ecf20Sopenharmony_ci		"in the init function\n"
15418c2ecf20Sopenharmony_ci		"uses functionality in the exit path.\n"
15428c2ecf20Sopenharmony_ci		"The fix is often to remove the %sannotation of\n"
15438c2ecf20Sopenharmony_ci		"%s%s so it may be used outside an exit section.\n",
15448c2ecf20Sopenharmony_ci		from, prl_from, fromsym, from_p,
15458c2ecf20Sopenharmony_ci		to, prl_to, tosym, to_p,
15468c2ecf20Sopenharmony_ci		prl_to, tosym, to_p);
15478c2ecf20Sopenharmony_ci		free(prl_from);
15488c2ecf20Sopenharmony_ci		free(prl_to);
15498c2ecf20Sopenharmony_ci		break;
15508c2ecf20Sopenharmony_ci	case ANY_EXIT_TO_ANY_INIT:
15518c2ecf20Sopenharmony_ci		prl_from = sec2annotation(fromsec);
15528c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
15538c2ecf20Sopenharmony_ci		fprintf(stderr,
15548c2ecf20Sopenharmony_ci		"The %s %s%s%s references\n"
15558c2ecf20Sopenharmony_ci		"a %s %s%s%s.\n"
15568c2ecf20Sopenharmony_ci		"This is often seen when error handling "
15578c2ecf20Sopenharmony_ci		"in the exit function\n"
15588c2ecf20Sopenharmony_ci		"uses functionality in the init path.\n"
15598c2ecf20Sopenharmony_ci		"The fix is often to remove the %sannotation of\n"
15608c2ecf20Sopenharmony_ci		"%s%s so it may be used outside an init section.\n",
15618c2ecf20Sopenharmony_ci		from, prl_from, fromsym, from_p,
15628c2ecf20Sopenharmony_ci		to, prl_to, tosym, to_p,
15638c2ecf20Sopenharmony_ci		prl_to, tosym, to_p);
15648c2ecf20Sopenharmony_ci		free(prl_from);
15658c2ecf20Sopenharmony_ci		free(prl_to);
15668c2ecf20Sopenharmony_ci		break;
15678c2ecf20Sopenharmony_ci	case EXPORT_TO_INIT_EXIT:
15688c2ecf20Sopenharmony_ci		prl_to = sec2annotation(tosec);
15698c2ecf20Sopenharmony_ci		fprintf(stderr,
15708c2ecf20Sopenharmony_ci		"The symbol %s is exported and annotated %s\n"
15718c2ecf20Sopenharmony_ci		"Fix this by removing the %sannotation of %s "
15728c2ecf20Sopenharmony_ci		"or drop the export.\n",
15738c2ecf20Sopenharmony_ci		tosym, prl_to, prl_to, tosym);
15748c2ecf20Sopenharmony_ci		free(prl_to);
15758c2ecf20Sopenharmony_ci		break;
15768c2ecf20Sopenharmony_ci	case EXTABLE_TO_NON_TEXT:
15778c2ecf20Sopenharmony_ci		fatal("There's a special handler for this mismatch type, "
15788c2ecf20Sopenharmony_ci		      "we should never get here.");
15798c2ecf20Sopenharmony_ci		break;
15808c2ecf20Sopenharmony_ci	}
15818c2ecf20Sopenharmony_ci	fprintf(stderr, "\n");
15828c2ecf20Sopenharmony_ci}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_cistatic void default_mismatch_handler(const char *modname, struct elf_info *elf,
15858c2ecf20Sopenharmony_ci				     const struct sectioncheck* const mismatch,
15868c2ecf20Sopenharmony_ci				     Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
15878c2ecf20Sopenharmony_ci{
15888c2ecf20Sopenharmony_ci	const char *tosec;
15898c2ecf20Sopenharmony_ci	Elf_Sym *to;
15908c2ecf20Sopenharmony_ci	Elf_Sym *from;
15918c2ecf20Sopenharmony_ci	const char *tosym;
15928c2ecf20Sopenharmony_ci	const char *fromsym;
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	from = find_elf_symbol2(elf, r->r_offset, fromsec);
15958c2ecf20Sopenharmony_ci	fromsym = sym_name(elf, from);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	if (strstarts(fromsym, "reference___initcall"))
15988c2ecf20Sopenharmony_ci		return;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	tosec = sec_name(elf, get_secindex(elf, sym));
16018c2ecf20Sopenharmony_ci	to = find_elf_symbol(elf, r->r_addend, sym);
16028c2ecf20Sopenharmony_ci	tosym = sym_name(elf, to);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	/* check whitelist - we may ignore it */
16058c2ecf20Sopenharmony_ci	if (secref_whitelist(mismatch,
16068c2ecf20Sopenharmony_ci			     fromsec, fromsym, tosec, tosym)) {
16078c2ecf20Sopenharmony_ci		report_sec_mismatch(modname, mismatch,
16088c2ecf20Sopenharmony_ci				    fromsec, r->r_offset, fromsym,
16098c2ecf20Sopenharmony_ci				    is_function(from), tosec, tosym,
16108c2ecf20Sopenharmony_ci				    is_function(to));
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci}
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_cistatic int is_executable_section(struct elf_info* elf, unsigned int section_index)
16158c2ecf20Sopenharmony_ci{
16168c2ecf20Sopenharmony_ci	if (section_index >= elf->num_sections)
16178c2ecf20Sopenharmony_ci		fatal("section_index is outside elf->num_sections!\n");
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci/*
16238c2ecf20Sopenharmony_ci * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
16248c2ecf20Sopenharmony_ci * to know the sizeof(struct exception_table_entry) for the target architecture.
16258c2ecf20Sopenharmony_ci */
16268c2ecf20Sopenharmony_cistatic unsigned int extable_entry_size = 0;
16278c2ecf20Sopenharmony_cistatic void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	/*
16308c2ecf20Sopenharmony_ci	 * If we're currently checking the second relocation within __ex_table,
16318c2ecf20Sopenharmony_ci	 * that relocation offset tells us the offsetof(struct
16328c2ecf20Sopenharmony_ci	 * exception_table_entry, fixup) which is equal to sizeof(struct
16338c2ecf20Sopenharmony_ci	 * exception_table_entry) divided by two.  We use that to our advantage
16348c2ecf20Sopenharmony_ci	 * since there's no portable way to get that size as every architecture
16358c2ecf20Sopenharmony_ci	 * seems to go with different sized types.  Not pretty but better than
16368c2ecf20Sopenharmony_ci	 * hard-coding the size for every architecture..
16378c2ecf20Sopenharmony_ci	 */
16388c2ecf20Sopenharmony_ci	if (!extable_entry_size)
16398c2ecf20Sopenharmony_ci		extable_entry_size = r->r_offset * 2;
16408c2ecf20Sopenharmony_ci}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_cistatic inline bool is_extable_fault_address(Elf_Rela *r)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	/*
16458c2ecf20Sopenharmony_ci	 * extable_entry_size is only discovered after we've handled the
16468c2ecf20Sopenharmony_ci	 * _second_ relocation in __ex_table, so only abort when we're not
16478c2ecf20Sopenharmony_ci	 * handling the first reloc and extable_entry_size is zero.
16488c2ecf20Sopenharmony_ci	 */
16498c2ecf20Sopenharmony_ci	if (r->r_offset && extable_entry_size == 0)
16508c2ecf20Sopenharmony_ci		fatal("extable_entry size hasn't been discovered!\n");
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	return ((r->r_offset == 0) ||
16538c2ecf20Sopenharmony_ci		(r->r_offset % extable_entry_size == 0));
16548c2ecf20Sopenharmony_ci}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci#define is_second_extable_reloc(Start, Cur, Sec)			\
16578c2ecf20Sopenharmony_ci	(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_cistatic void report_extable_warnings(const char* modname, struct elf_info* elf,
16608c2ecf20Sopenharmony_ci				    const struct sectioncheck* const mismatch,
16618c2ecf20Sopenharmony_ci				    Elf_Rela* r, Elf_Sym* sym,
16628c2ecf20Sopenharmony_ci				    const char* fromsec, const char* tosec)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
16658c2ecf20Sopenharmony_ci	const char* fromsym_name = sym_name(elf, fromsym);
16668c2ecf20Sopenharmony_ci	Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
16678c2ecf20Sopenharmony_ci	const char* tosym_name = sym_name(elf, tosym);
16688c2ecf20Sopenharmony_ci	const char* from_pretty_name;
16698c2ecf20Sopenharmony_ci	const char* from_pretty_name_p;
16708c2ecf20Sopenharmony_ci	const char* to_pretty_name;
16718c2ecf20Sopenharmony_ci	const char* to_pretty_name_p;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	get_pretty_name(is_function(fromsym),
16748c2ecf20Sopenharmony_ci			&from_pretty_name, &from_pretty_name_p);
16758c2ecf20Sopenharmony_ci	get_pretty_name(is_function(tosym),
16768c2ecf20Sopenharmony_ci			&to_pretty_name, &to_pretty_name_p);
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	warn("%s(%s+0x%lx): Section mismatch in reference"
16798c2ecf20Sopenharmony_ci	     " from the %s %s%s to the %s %s:%s%s\n",
16808c2ecf20Sopenharmony_ci	     modname, fromsec, (long)r->r_offset, from_pretty_name,
16818c2ecf20Sopenharmony_ci	     fromsym_name, from_pretty_name_p,
16828c2ecf20Sopenharmony_ci	     to_pretty_name, tosec, tosym_name, to_pretty_name_p);
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	if (!match(tosec, mismatch->bad_tosec) &&
16858c2ecf20Sopenharmony_ci	    is_executable_section(elf, get_secindex(elf, sym)))
16868c2ecf20Sopenharmony_ci		fprintf(stderr,
16878c2ecf20Sopenharmony_ci			"The relocation at %s+0x%lx references\n"
16888c2ecf20Sopenharmony_ci			"section \"%s\" which is not in the list of\n"
16898c2ecf20Sopenharmony_ci			"authorized sections.  If you're adding a new section\n"
16908c2ecf20Sopenharmony_ci			"and/or if this reference is valid, add \"%s\" to the\n"
16918c2ecf20Sopenharmony_ci			"list of authorized sections to jump to on fault.\n"
16928c2ecf20Sopenharmony_ci			"This can be achieved by adding \"%s\" to \n"
16938c2ecf20Sopenharmony_ci			"OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
16948c2ecf20Sopenharmony_ci			fromsec, (long)r->r_offset, tosec, tosec, tosec);
16958c2ecf20Sopenharmony_ci}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_cistatic void extable_mismatch_handler(const char* modname, struct elf_info *elf,
16988c2ecf20Sopenharmony_ci				     const struct sectioncheck* const mismatch,
16998c2ecf20Sopenharmony_ci				     Elf_Rela* r, Elf_Sym* sym,
17008c2ecf20Sopenharmony_ci				     const char *fromsec)
17018c2ecf20Sopenharmony_ci{
17028c2ecf20Sopenharmony_ci	const char* tosec = sec_name(elf, get_secindex(elf, sym));
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	sec_mismatch_count++;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	if (match(tosec, mismatch->bad_tosec))
17098c2ecf20Sopenharmony_ci		fatal("The relocation at %s+0x%lx references\n"
17108c2ecf20Sopenharmony_ci		      "section \"%s\" which is black-listed.\n"
17118c2ecf20Sopenharmony_ci		      "Something is seriously wrong and should be fixed.\n"
17128c2ecf20Sopenharmony_ci		      "You might get more information about where this is\n"
17138c2ecf20Sopenharmony_ci		      "coming from by using scripts/check_extable.sh %s\n",
17148c2ecf20Sopenharmony_ci		      fromsec, (long)r->r_offset, tosec, modname);
17158c2ecf20Sopenharmony_ci	else if (!is_executable_section(elf, get_secindex(elf, sym))) {
17168c2ecf20Sopenharmony_ci		if (is_extable_fault_address(r))
17178c2ecf20Sopenharmony_ci			fatal("The relocation at %s+0x%lx references\n"
17188c2ecf20Sopenharmony_ci			      "section \"%s\" which is not executable, IOW\n"
17198c2ecf20Sopenharmony_ci			      "it is not possible for the kernel to fault\n"
17208c2ecf20Sopenharmony_ci			      "at that address.  Something is seriously wrong\n"
17218c2ecf20Sopenharmony_ci			      "and should be fixed.\n",
17228c2ecf20Sopenharmony_ci			      fromsec, (long)r->r_offset, tosec);
17238c2ecf20Sopenharmony_ci		else
17248c2ecf20Sopenharmony_ci			fatal("The relocation at %s+0x%lx references\n"
17258c2ecf20Sopenharmony_ci			      "section \"%s\" which is not executable, IOW\n"
17268c2ecf20Sopenharmony_ci			      "the kernel will fault if it ever tries to\n"
17278c2ecf20Sopenharmony_ci			      "jump to it.  Something is seriously wrong\n"
17288c2ecf20Sopenharmony_ci			      "and should be fixed.\n",
17298c2ecf20Sopenharmony_ci			      fromsec, (long)r->r_offset, tosec);
17308c2ecf20Sopenharmony_ci	}
17318c2ecf20Sopenharmony_ci}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_cistatic void check_section_mismatch(const char *modname, struct elf_info *elf,
17348c2ecf20Sopenharmony_ci				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	const char *tosec = sec_name(elf, get_secindex(elf, sym));
17378c2ecf20Sopenharmony_ci	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	if (mismatch) {
17408c2ecf20Sopenharmony_ci		if (mismatch->handler)
17418c2ecf20Sopenharmony_ci			mismatch->handler(modname, elf,  mismatch,
17428c2ecf20Sopenharmony_ci					  r, sym, fromsec);
17438c2ecf20Sopenharmony_ci		else
17448c2ecf20Sopenharmony_ci			default_mismatch_handler(modname, elf, mismatch,
17458c2ecf20Sopenharmony_ci						 r, sym, fromsec);
17468c2ecf20Sopenharmony_ci	}
17478c2ecf20Sopenharmony_ci}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_cistatic unsigned int *reloc_location(struct elf_info *elf,
17508c2ecf20Sopenharmony_ci				    Elf_Shdr *sechdr, Elf_Rela *r)
17518c2ecf20Sopenharmony_ci{
17528c2ecf20Sopenharmony_ci	return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
17538c2ecf20Sopenharmony_ci}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_cistatic int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
17568c2ecf20Sopenharmony_ci{
17578c2ecf20Sopenharmony_ci	unsigned int r_typ = ELF_R_TYPE(r->r_info);
17588c2ecf20Sopenharmony_ci	unsigned int *location = reloc_location(elf, sechdr, r);
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	switch (r_typ) {
17618c2ecf20Sopenharmony_ci	case R_386_32:
17628c2ecf20Sopenharmony_ci		r->r_addend = TO_NATIVE(*location);
17638c2ecf20Sopenharmony_ci		break;
17648c2ecf20Sopenharmony_ci	case R_386_PC32:
17658c2ecf20Sopenharmony_ci		r->r_addend = TO_NATIVE(*location) + 4;
17668c2ecf20Sopenharmony_ci		/* For CONFIG_RELOCATABLE=y */
17678c2ecf20Sopenharmony_ci		if (elf->hdr->e_type == ET_EXEC)
17688c2ecf20Sopenharmony_ci			r->r_addend += r->r_offset;
17698c2ecf20Sopenharmony_ci		break;
17708c2ecf20Sopenharmony_ci	}
17718c2ecf20Sopenharmony_ci	return 0;
17728c2ecf20Sopenharmony_ci}
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci#ifndef R_ARM_CALL
17758c2ecf20Sopenharmony_ci#define R_ARM_CALL	28
17768c2ecf20Sopenharmony_ci#endif
17778c2ecf20Sopenharmony_ci#ifndef R_ARM_JUMP24
17788c2ecf20Sopenharmony_ci#define R_ARM_JUMP24	29
17798c2ecf20Sopenharmony_ci#endif
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci#ifndef	R_ARM_THM_CALL
17828c2ecf20Sopenharmony_ci#define	R_ARM_THM_CALL		10
17838c2ecf20Sopenharmony_ci#endif
17848c2ecf20Sopenharmony_ci#ifndef	R_ARM_THM_JUMP24
17858c2ecf20Sopenharmony_ci#define	R_ARM_THM_JUMP24	30
17868c2ecf20Sopenharmony_ci#endif
17878c2ecf20Sopenharmony_ci#ifndef	R_ARM_THM_JUMP19
17888c2ecf20Sopenharmony_ci#define	R_ARM_THM_JUMP19	51
17898c2ecf20Sopenharmony_ci#endif
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_cistatic int32_t sign_extend32(int32_t value, int index)
17928c2ecf20Sopenharmony_ci{
17938c2ecf20Sopenharmony_ci	uint8_t shift = 31 - index;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	return (int32_t)(value << shift) >> shift;
17968c2ecf20Sopenharmony_ci}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_cistatic int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
17998c2ecf20Sopenharmony_ci{
18008c2ecf20Sopenharmony_ci	unsigned int r_typ = ELF_R_TYPE(r->r_info);
18018c2ecf20Sopenharmony_ci	Elf_Sym *sym = elf->symtab_start + ELF_R_SYM(r->r_info);
18028c2ecf20Sopenharmony_ci	void *loc = reloc_location(elf, sechdr, r);
18038c2ecf20Sopenharmony_ci	uint32_t inst;
18048c2ecf20Sopenharmony_ci	int32_t offset;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	switch (r_typ) {
18078c2ecf20Sopenharmony_ci	case R_ARM_ABS32:
18088c2ecf20Sopenharmony_ci		inst = TO_NATIVE(*(uint32_t *)loc);
18098c2ecf20Sopenharmony_ci		r->r_addend = inst + sym->st_value;
18108c2ecf20Sopenharmony_ci		break;
18118c2ecf20Sopenharmony_ci	case R_ARM_PC24:
18128c2ecf20Sopenharmony_ci	case R_ARM_CALL:
18138c2ecf20Sopenharmony_ci	case R_ARM_JUMP24:
18148c2ecf20Sopenharmony_ci		inst = TO_NATIVE(*(uint32_t *)loc);
18158c2ecf20Sopenharmony_ci		offset = sign_extend32((inst & 0x00ffffff) << 2, 25);
18168c2ecf20Sopenharmony_ci		r->r_addend = offset + sym->st_value + 8;
18178c2ecf20Sopenharmony_ci		break;
18188c2ecf20Sopenharmony_ci	case R_ARM_THM_CALL:
18198c2ecf20Sopenharmony_ci	case R_ARM_THM_JUMP24:
18208c2ecf20Sopenharmony_ci	case R_ARM_THM_JUMP19:
18218c2ecf20Sopenharmony_ci		/* From ARM ABI: ((S + A) | T) - P */
18228c2ecf20Sopenharmony_ci		r->r_addend = (int)(long)(elf->hdr +
18238c2ecf20Sopenharmony_ci			      sechdr->sh_offset +
18248c2ecf20Sopenharmony_ci			      (r->r_offset - sechdr->sh_addr));
18258c2ecf20Sopenharmony_ci		break;
18268c2ecf20Sopenharmony_ci	default:
18278c2ecf20Sopenharmony_ci		return 1;
18288c2ecf20Sopenharmony_ci	}
18298c2ecf20Sopenharmony_ci	return 0;
18308c2ecf20Sopenharmony_ci}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_cistatic int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
18338c2ecf20Sopenharmony_ci{
18348c2ecf20Sopenharmony_ci	unsigned int r_typ = ELF_R_TYPE(r->r_info);
18358c2ecf20Sopenharmony_ci	unsigned int *location = reloc_location(elf, sechdr, r);
18368c2ecf20Sopenharmony_ci	unsigned int inst;
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	if (r_typ == R_MIPS_HI16)
18398c2ecf20Sopenharmony_ci		return 1;	/* skip this */
18408c2ecf20Sopenharmony_ci	inst = TO_NATIVE(*location);
18418c2ecf20Sopenharmony_ci	switch (r_typ) {
18428c2ecf20Sopenharmony_ci	case R_MIPS_LO16:
18438c2ecf20Sopenharmony_ci		r->r_addend = inst & 0xffff;
18448c2ecf20Sopenharmony_ci		break;
18458c2ecf20Sopenharmony_ci	case R_MIPS_26:
18468c2ecf20Sopenharmony_ci		r->r_addend = (inst & 0x03ffffff) << 2;
18478c2ecf20Sopenharmony_ci		break;
18488c2ecf20Sopenharmony_ci	case R_MIPS_32:
18498c2ecf20Sopenharmony_ci		r->r_addend = inst;
18508c2ecf20Sopenharmony_ci		break;
18518c2ecf20Sopenharmony_ci	}
18528c2ecf20Sopenharmony_ci	return 0;
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci#ifndef EM_LOONGARCH
18568c2ecf20Sopenharmony_ci#define EM_LOONGARCH		258
18578c2ecf20Sopenharmony_ci#endif
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci#ifndef R_LARCH_SUB32
18608c2ecf20Sopenharmony_ci#define R_LARCH_SUB32		55
18618c2ecf20Sopenharmony_ci#endif
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_cistatic void section_rela(const char *modname, struct elf_info *elf,
18648c2ecf20Sopenharmony_ci			 Elf_Shdr *sechdr)
18658c2ecf20Sopenharmony_ci{
18668c2ecf20Sopenharmony_ci	Elf_Sym  *sym;
18678c2ecf20Sopenharmony_ci	Elf_Rela *rela;
18688c2ecf20Sopenharmony_ci	Elf_Rela r;
18698c2ecf20Sopenharmony_ci	unsigned int r_sym;
18708c2ecf20Sopenharmony_ci	const char *fromsec;
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci	Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
18738c2ecf20Sopenharmony_ci	Elf_Rela *stop  = (void *)start + sechdr->sh_size;
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	fromsec = sech_name(elf, sechdr);
18768c2ecf20Sopenharmony_ci	fromsec += strlen(".rela");
18778c2ecf20Sopenharmony_ci	/* if from section (name) is know good then skip it */
18788c2ecf20Sopenharmony_ci	if (match(fromsec, section_white_list))
18798c2ecf20Sopenharmony_ci		return;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	for (rela = start; rela < stop; rela++) {
18828c2ecf20Sopenharmony_ci		r.r_offset = TO_NATIVE(rela->r_offset);
18838c2ecf20Sopenharmony_ci#if KERNEL_ELFCLASS == ELFCLASS64
18848c2ecf20Sopenharmony_ci		if (elf->hdr->e_machine == EM_MIPS) {
18858c2ecf20Sopenharmony_ci			unsigned int r_typ;
18868c2ecf20Sopenharmony_ci			r_sym = ELF64_MIPS_R_SYM(rela->r_info);
18878c2ecf20Sopenharmony_ci			r_sym = TO_NATIVE(r_sym);
18888c2ecf20Sopenharmony_ci			r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
18898c2ecf20Sopenharmony_ci			r.r_info = ELF64_R_INFO(r_sym, r_typ);
18908c2ecf20Sopenharmony_ci		} else {
18918c2ecf20Sopenharmony_ci			r.r_info = TO_NATIVE(rela->r_info);
18928c2ecf20Sopenharmony_ci			r_sym = ELF_R_SYM(r.r_info);
18938c2ecf20Sopenharmony_ci		}
18948c2ecf20Sopenharmony_ci#else
18958c2ecf20Sopenharmony_ci		r.r_info = TO_NATIVE(rela->r_info);
18968c2ecf20Sopenharmony_ci		r_sym = ELF_R_SYM(r.r_info);
18978c2ecf20Sopenharmony_ci#endif
18988c2ecf20Sopenharmony_ci		r.r_addend = TO_NATIVE(rela->r_addend);
18998c2ecf20Sopenharmony_ci		switch (elf->hdr->e_machine) {
19008c2ecf20Sopenharmony_ci		case EM_LOONGARCH:
19018c2ecf20Sopenharmony_ci			if (!strcmp("__ex_table", fromsec) &&
19028c2ecf20Sopenharmony_ci			    ELF_R_TYPE(r.r_info) == R_LARCH_SUB32)
19038c2ecf20Sopenharmony_ci				continue;
19048c2ecf20Sopenharmony_ci			break;
19058c2ecf20Sopenharmony_ci		}
19068c2ecf20Sopenharmony_ci		sym = elf->symtab_start + r_sym;
19078c2ecf20Sopenharmony_ci		/* Skip special sections */
19088c2ecf20Sopenharmony_ci		if (is_shndx_special(sym->st_shndx))
19098c2ecf20Sopenharmony_ci			continue;
19108c2ecf20Sopenharmony_ci		if (is_second_extable_reloc(start, rela, fromsec))
19118c2ecf20Sopenharmony_ci			find_extable_entry_size(fromsec, &r);
19128c2ecf20Sopenharmony_ci		check_section_mismatch(modname, elf, &r, sym, fromsec);
19138c2ecf20Sopenharmony_ci	}
19148c2ecf20Sopenharmony_ci}
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_cistatic void section_rel(const char *modname, struct elf_info *elf,
19178c2ecf20Sopenharmony_ci			Elf_Shdr *sechdr)
19188c2ecf20Sopenharmony_ci{
19198c2ecf20Sopenharmony_ci	Elf_Sym *sym;
19208c2ecf20Sopenharmony_ci	Elf_Rel *rel;
19218c2ecf20Sopenharmony_ci	Elf_Rela r;
19228c2ecf20Sopenharmony_ci	unsigned int r_sym;
19238c2ecf20Sopenharmony_ci	const char *fromsec;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
19268c2ecf20Sopenharmony_ci	Elf_Rel *stop  = (void *)start + sechdr->sh_size;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	fromsec = sech_name(elf, sechdr);
19298c2ecf20Sopenharmony_ci	fromsec += strlen(".rel");
19308c2ecf20Sopenharmony_ci	/* if from section (name) is know good then skip it */
19318c2ecf20Sopenharmony_ci	if (match(fromsec, section_white_list))
19328c2ecf20Sopenharmony_ci		return;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	for (rel = start; rel < stop; rel++) {
19358c2ecf20Sopenharmony_ci		r.r_offset = TO_NATIVE(rel->r_offset);
19368c2ecf20Sopenharmony_ci#if KERNEL_ELFCLASS == ELFCLASS64
19378c2ecf20Sopenharmony_ci		if (elf->hdr->e_machine == EM_MIPS) {
19388c2ecf20Sopenharmony_ci			unsigned int r_typ;
19398c2ecf20Sopenharmony_ci			r_sym = ELF64_MIPS_R_SYM(rel->r_info);
19408c2ecf20Sopenharmony_ci			r_sym = TO_NATIVE(r_sym);
19418c2ecf20Sopenharmony_ci			r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
19428c2ecf20Sopenharmony_ci			r.r_info = ELF64_R_INFO(r_sym, r_typ);
19438c2ecf20Sopenharmony_ci		} else {
19448c2ecf20Sopenharmony_ci			r.r_info = TO_NATIVE(rel->r_info);
19458c2ecf20Sopenharmony_ci			r_sym = ELF_R_SYM(r.r_info);
19468c2ecf20Sopenharmony_ci		}
19478c2ecf20Sopenharmony_ci#else
19488c2ecf20Sopenharmony_ci		r.r_info = TO_NATIVE(rel->r_info);
19498c2ecf20Sopenharmony_ci		r_sym = ELF_R_SYM(r.r_info);
19508c2ecf20Sopenharmony_ci#endif
19518c2ecf20Sopenharmony_ci		r.r_addend = 0;
19528c2ecf20Sopenharmony_ci		switch (elf->hdr->e_machine) {
19538c2ecf20Sopenharmony_ci		case EM_386:
19548c2ecf20Sopenharmony_ci			if (addend_386_rel(elf, sechdr, &r))
19558c2ecf20Sopenharmony_ci				continue;
19568c2ecf20Sopenharmony_ci			break;
19578c2ecf20Sopenharmony_ci		case EM_ARM:
19588c2ecf20Sopenharmony_ci			if (addend_arm_rel(elf, sechdr, &r))
19598c2ecf20Sopenharmony_ci				continue;
19608c2ecf20Sopenharmony_ci			break;
19618c2ecf20Sopenharmony_ci		case EM_MIPS:
19628c2ecf20Sopenharmony_ci			if (addend_mips_rel(elf, sechdr, &r))
19638c2ecf20Sopenharmony_ci				continue;
19648c2ecf20Sopenharmony_ci			break;
19658c2ecf20Sopenharmony_ci		}
19668c2ecf20Sopenharmony_ci		sym = elf->symtab_start + r_sym;
19678c2ecf20Sopenharmony_ci		/* Skip special sections */
19688c2ecf20Sopenharmony_ci		if (is_shndx_special(sym->st_shndx))
19698c2ecf20Sopenharmony_ci			continue;
19708c2ecf20Sopenharmony_ci		if (is_second_extable_reloc(start, rel, fromsec))
19718c2ecf20Sopenharmony_ci			find_extable_entry_size(fromsec, &r);
19728c2ecf20Sopenharmony_ci		check_section_mismatch(modname, elf, &r, sym, fromsec);
19738c2ecf20Sopenharmony_ci	}
19748c2ecf20Sopenharmony_ci}
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci/**
19778c2ecf20Sopenharmony_ci * A module includes a number of sections that are discarded
19788c2ecf20Sopenharmony_ci * either when loaded or when used as built-in.
19798c2ecf20Sopenharmony_ci * For loaded modules all functions marked __init and all data
19808c2ecf20Sopenharmony_ci * marked __initdata will be discarded when the module has been initialized.
19818c2ecf20Sopenharmony_ci * Likewise for modules used built-in the sections marked __exit
19828c2ecf20Sopenharmony_ci * are discarded because __exit marked function are supposed to be called
19838c2ecf20Sopenharmony_ci * only when a module is unloaded which never happens for built-in modules.
19848c2ecf20Sopenharmony_ci * The check_sec_ref() function traverses all relocation records
19858c2ecf20Sopenharmony_ci * to find all references to a section that reference a section that will
19868c2ecf20Sopenharmony_ci * be discarded and warns about it.
19878c2ecf20Sopenharmony_ci **/
19888c2ecf20Sopenharmony_cistatic void check_sec_ref(struct module *mod, const char *modname,
19898c2ecf20Sopenharmony_ci			  struct elf_info *elf)
19908c2ecf20Sopenharmony_ci{
19918c2ecf20Sopenharmony_ci	int i;
19928c2ecf20Sopenharmony_ci	Elf_Shdr *sechdrs = elf->sechdrs;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	/* Walk through all sections */
19958c2ecf20Sopenharmony_ci	for (i = 0; i < elf->num_sections; i++) {
19968c2ecf20Sopenharmony_ci		check_section(modname, elf, &elf->sechdrs[i]);
19978c2ecf20Sopenharmony_ci		/* We want to process only relocation sections and not .init */
19988c2ecf20Sopenharmony_ci		if (sechdrs[i].sh_type == SHT_RELA)
19998c2ecf20Sopenharmony_ci			section_rela(modname, elf, &elf->sechdrs[i]);
20008c2ecf20Sopenharmony_ci		else if (sechdrs[i].sh_type == SHT_REL)
20018c2ecf20Sopenharmony_ci			section_rel(modname, elf, &elf->sechdrs[i]);
20028c2ecf20Sopenharmony_ci	}
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cistatic char *remove_dot(char *s)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	size_t n = strcspn(s, ".");
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	if (n && s[n]) {
20108c2ecf20Sopenharmony_ci		size_t m = strspn(s + n + 1, "0123456789");
20118c2ecf20Sopenharmony_ci		if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
20128c2ecf20Sopenharmony_ci			s[n] = 0;
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci		/* strip trailing .lto */
20158c2ecf20Sopenharmony_ci		if (strends(s, ".lto"))
20168c2ecf20Sopenharmony_ci			s[strlen(s) - 4] = '\0';
20178c2ecf20Sopenharmony_ci	}
20188c2ecf20Sopenharmony_ci	return s;
20198c2ecf20Sopenharmony_ci}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_cistatic void read_symbols(const char *modname)
20228c2ecf20Sopenharmony_ci{
20238c2ecf20Sopenharmony_ci	const char *symname;
20248c2ecf20Sopenharmony_ci	char *version;
20258c2ecf20Sopenharmony_ci	char *license;
20268c2ecf20Sopenharmony_ci	char *namespace;
20278c2ecf20Sopenharmony_ci	struct module *mod;
20288c2ecf20Sopenharmony_ci	struct elf_info info = { };
20298c2ecf20Sopenharmony_ci	Elf_Sym *sym;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	if (!parse_elf(&info, modname))
20328c2ecf20Sopenharmony_ci		return;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci	{
20358c2ecf20Sopenharmony_ci		char *tmp;
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci		/* strip trailing .o */
20388c2ecf20Sopenharmony_ci		tmp = NOFAIL(strdup(modname));
20398c2ecf20Sopenharmony_ci		tmp[strlen(tmp) - 2] = '\0';
20408c2ecf20Sopenharmony_ci		/* strip trailing .lto */
20418c2ecf20Sopenharmony_ci		if (strends(tmp, ".lto"))
20428c2ecf20Sopenharmony_ci			tmp[strlen(tmp) - 4] = '\0';
20438c2ecf20Sopenharmony_ci		mod = new_module(tmp);
20448c2ecf20Sopenharmony_ci		free(tmp);
20458c2ecf20Sopenharmony_ci	}
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	if (!mod->is_vmlinux) {
20488c2ecf20Sopenharmony_ci		license = get_modinfo(&info, "license");
20498c2ecf20Sopenharmony_ci		if (!license)
20508c2ecf20Sopenharmony_ci			warn("missing MODULE_LICENSE() in %s\n", modname);
20518c2ecf20Sopenharmony_ci		while (license) {
20528c2ecf20Sopenharmony_ci			if (license_is_gpl_compatible(license))
20538c2ecf20Sopenharmony_ci				mod->gpl_compatible = 1;
20548c2ecf20Sopenharmony_ci			else {
20558c2ecf20Sopenharmony_ci				mod->gpl_compatible = 0;
20568c2ecf20Sopenharmony_ci				break;
20578c2ecf20Sopenharmony_ci			}
20588c2ecf20Sopenharmony_ci			license = get_next_modinfo(&info, "license", license);
20598c2ecf20Sopenharmony_ci		}
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci		namespace = get_modinfo(&info, "import_ns");
20628c2ecf20Sopenharmony_ci		while (namespace) {
20638c2ecf20Sopenharmony_ci			add_namespace(&mod->imported_namespaces, namespace);
20648c2ecf20Sopenharmony_ci			namespace = get_next_modinfo(&info, "import_ns",
20658c2ecf20Sopenharmony_ci						     namespace);
20668c2ecf20Sopenharmony_ci		}
20678c2ecf20Sopenharmony_ci	}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
20708c2ecf20Sopenharmony_ci		symname = remove_dot(info.strtab + sym->st_name);
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci		handle_symbol(mod, &info, sym, symname);
20738c2ecf20Sopenharmony_ci		handle_moddevtable(mod, &info, sym, symname);
20748c2ecf20Sopenharmony_ci	}
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
20778c2ecf20Sopenharmony_ci		symname = remove_dot(info.strtab + sym->st_name);
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci		/* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
20808c2ecf20Sopenharmony_ci		if (strstarts(symname, "__kstrtabns_"))
20818c2ecf20Sopenharmony_ci			sym_update_namespace(symname + strlen("__kstrtabns_"),
20828c2ecf20Sopenharmony_ci					     namespace_from_kstrtabns(&info,
20838c2ecf20Sopenharmony_ci								      sym));
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci		if (strstarts(symname, "__crc_"))
20868c2ecf20Sopenharmony_ci			handle_modversion(mod, &info, sym,
20878c2ecf20Sopenharmony_ci					  symname + strlen("__crc_"));
20888c2ecf20Sopenharmony_ci	}
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	// check for static EXPORT_SYMBOL_* functions && global vars
20918c2ecf20Sopenharmony_ci	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
20928c2ecf20Sopenharmony_ci		unsigned char bind = ELF_ST_BIND(sym->st_info);
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci		if (bind == STB_GLOBAL || bind == STB_WEAK) {
20958c2ecf20Sopenharmony_ci			struct symbol *s =
20968c2ecf20Sopenharmony_ci				find_symbol(remove_dot(info.strtab +
20978c2ecf20Sopenharmony_ci						       sym->st_name));
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci			if (s)
21008c2ecf20Sopenharmony_ci				s->is_static = 0;
21018c2ecf20Sopenharmony_ci		}
21028c2ecf20Sopenharmony_ci	}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	check_sec_ref(mod, modname, &info);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	if (!mod->is_vmlinux) {
21078c2ecf20Sopenharmony_ci		version = get_modinfo(&info, "version");
21088c2ecf20Sopenharmony_ci		if (version || all_versions)
21098c2ecf20Sopenharmony_ci			get_src_version(modname, mod->srcversion,
21108c2ecf20Sopenharmony_ci					sizeof(mod->srcversion) - 1);
21118c2ecf20Sopenharmony_ci	}
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	parse_elf_finish(&info);
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	/* Our trick to get versioning for module struct etc. - it's
21168c2ecf20Sopenharmony_ci	 * never passed as an argument to an exported function, so
21178c2ecf20Sopenharmony_ci	 * the automatic versioning doesn't pick it up, but it's really
21188c2ecf20Sopenharmony_ci	 * important anyhow */
21198c2ecf20Sopenharmony_ci	if (modversions)
21208c2ecf20Sopenharmony_ci		mod->unres = alloc_symbol("module_layout", 0, mod->unres);
21218c2ecf20Sopenharmony_ci}
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_cistatic void read_symbols_from_files(const char *filename)
21248c2ecf20Sopenharmony_ci{
21258c2ecf20Sopenharmony_ci	FILE *in = stdin;
21268c2ecf20Sopenharmony_ci	char fname[PATH_MAX];
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	if (strcmp(filename, "-") != 0) {
21298c2ecf20Sopenharmony_ci		in = fopen(filename, "r");
21308c2ecf20Sopenharmony_ci		if (!in)
21318c2ecf20Sopenharmony_ci			fatal("Can't open filenames file %s: %m", filename);
21328c2ecf20Sopenharmony_ci	}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	while (fgets(fname, PATH_MAX, in) != NULL) {
21358c2ecf20Sopenharmony_ci		if (strends(fname, "\n"))
21368c2ecf20Sopenharmony_ci			fname[strlen(fname)-1] = '\0';
21378c2ecf20Sopenharmony_ci		read_symbols(fname);
21388c2ecf20Sopenharmony_ci	}
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	if (in != stdin)
21418c2ecf20Sopenharmony_ci		fclose(in);
21428c2ecf20Sopenharmony_ci}
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci#define SZ 500
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci/* We first write the generated file into memory using the
21478c2ecf20Sopenharmony_ci * following helper, then compare to the file on disk and
21488c2ecf20Sopenharmony_ci * only update the later if anything changed */
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_civoid __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
21518c2ecf20Sopenharmony_ci						      const char *fmt, ...)
21528c2ecf20Sopenharmony_ci{
21538c2ecf20Sopenharmony_ci	char tmp[SZ];
21548c2ecf20Sopenharmony_ci	int len;
21558c2ecf20Sopenharmony_ci	va_list ap;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	va_start(ap, fmt);
21588c2ecf20Sopenharmony_ci	len = vsnprintf(tmp, SZ, fmt, ap);
21598c2ecf20Sopenharmony_ci	buf_write(buf, tmp, len);
21608c2ecf20Sopenharmony_ci	va_end(ap);
21618c2ecf20Sopenharmony_ci}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_civoid buf_write(struct buffer *buf, const char *s, int len)
21648c2ecf20Sopenharmony_ci{
21658c2ecf20Sopenharmony_ci	if (buf->size - buf->pos < len) {
21668c2ecf20Sopenharmony_ci		buf->size += len + SZ;
21678c2ecf20Sopenharmony_ci		buf->p = NOFAIL(realloc(buf->p, buf->size));
21688c2ecf20Sopenharmony_ci	}
21698c2ecf20Sopenharmony_ci	strncpy(buf->p + buf->pos, s, len);
21708c2ecf20Sopenharmony_ci	buf->pos += len;
21718c2ecf20Sopenharmony_ci}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_cistatic void check_for_gpl_usage(enum export exp, const char *m, const char *s)
21748c2ecf20Sopenharmony_ci{
21758c2ecf20Sopenharmony_ci	switch (exp) {
21768c2ecf20Sopenharmony_ci	case export_gpl:
21778c2ecf20Sopenharmony_ci		fatal("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
21788c2ecf20Sopenharmony_ci		      m, s);
21798c2ecf20Sopenharmony_ci		break;
21808c2ecf20Sopenharmony_ci	case export_unused_gpl:
21818c2ecf20Sopenharmony_ci		fatal("GPL-incompatible module %s.ko uses GPL-only symbol marked UNUSED '%s'\n",
21828c2ecf20Sopenharmony_ci		      m, s);
21838c2ecf20Sopenharmony_ci		break;
21848c2ecf20Sopenharmony_ci	case export_gpl_future:
21858c2ecf20Sopenharmony_ci		warn("GPL-incompatible module %s.ko uses future GPL-only symbol '%s'\n",
21868c2ecf20Sopenharmony_ci		     m, s);
21878c2ecf20Sopenharmony_ci		break;
21888c2ecf20Sopenharmony_ci	case export_plain:
21898c2ecf20Sopenharmony_ci	case export_unused:
21908c2ecf20Sopenharmony_ci	case export_unknown:
21918c2ecf20Sopenharmony_ci		/* ignore */
21928c2ecf20Sopenharmony_ci		break;
21938c2ecf20Sopenharmony_ci	}
21948c2ecf20Sopenharmony_ci}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_cistatic void check_for_unused(enum export exp, const char *m, const char *s)
21978c2ecf20Sopenharmony_ci{
21988c2ecf20Sopenharmony_ci	switch (exp) {
21998c2ecf20Sopenharmony_ci	case export_unused:
22008c2ecf20Sopenharmony_ci	case export_unused_gpl:
22018c2ecf20Sopenharmony_ci		warn("module %s.ko uses symbol '%s' marked UNUSED\n",
22028c2ecf20Sopenharmony_ci		     m, s);
22038c2ecf20Sopenharmony_ci		break;
22048c2ecf20Sopenharmony_ci	default:
22058c2ecf20Sopenharmony_ci		/* ignore */
22068c2ecf20Sopenharmony_ci		break;
22078c2ecf20Sopenharmony_ci	}
22088c2ecf20Sopenharmony_ci}
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_cistatic int check_exports(struct module *mod)
22118c2ecf20Sopenharmony_ci{
22128c2ecf20Sopenharmony_ci	struct symbol *s, *exp;
22138c2ecf20Sopenharmony_ci	int err = 0;
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	for (s = mod->unres; s; s = s->next) {
22168c2ecf20Sopenharmony_ci		const char *basename;
22178c2ecf20Sopenharmony_ci		exp = find_symbol(s->name);
22188c2ecf20Sopenharmony_ci		if (!exp || exp->module == mod) {
22198c2ecf20Sopenharmony_ci			if (have_vmlinux && !s->weak) {
22208c2ecf20Sopenharmony_ci				modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
22218c2ecf20Sopenharmony_ci					    "\"%s\" [%s.ko] undefined!\n",
22228c2ecf20Sopenharmony_ci					    s->name, mod->name);
22238c2ecf20Sopenharmony_ci				if (!warn_unresolved)
22248c2ecf20Sopenharmony_ci					err = 1;
22258c2ecf20Sopenharmony_ci			}
22268c2ecf20Sopenharmony_ci			continue;
22278c2ecf20Sopenharmony_ci		}
22288c2ecf20Sopenharmony_ci		basename = strrchr(mod->name, '/');
22298c2ecf20Sopenharmony_ci		if (basename)
22308c2ecf20Sopenharmony_ci			basename++;
22318c2ecf20Sopenharmony_ci		else
22328c2ecf20Sopenharmony_ci			basename = mod->name;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci		if (exp->namespace &&
22358c2ecf20Sopenharmony_ci		    !module_imports_namespace(mod, exp->namespace)) {
22368c2ecf20Sopenharmony_ci			modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR,
22378c2ecf20Sopenharmony_ci				    "module %s uses symbol %s from namespace %s, but does not import it.\n",
22388c2ecf20Sopenharmony_ci				    basename, exp->name, exp->namespace);
22398c2ecf20Sopenharmony_ci			if (!allow_missing_ns_imports)
22408c2ecf20Sopenharmony_ci				err = 1;
22418c2ecf20Sopenharmony_ci			add_namespace(&mod->missing_namespaces, exp->namespace);
22428c2ecf20Sopenharmony_ci		}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci		if (!mod->gpl_compatible)
22458c2ecf20Sopenharmony_ci			check_for_gpl_usage(exp->export, basename, exp->name);
22468c2ecf20Sopenharmony_ci		check_for_unused(exp->export, basename, exp->name);
22478c2ecf20Sopenharmony_ci	}
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	return err;
22508c2ecf20Sopenharmony_ci}
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_cistatic int check_modname_len(struct module *mod)
22538c2ecf20Sopenharmony_ci{
22548c2ecf20Sopenharmony_ci	const char *mod_name;
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	mod_name = strrchr(mod->name, '/');
22578c2ecf20Sopenharmony_ci	if (mod_name == NULL)
22588c2ecf20Sopenharmony_ci		mod_name = mod->name;
22598c2ecf20Sopenharmony_ci	else
22608c2ecf20Sopenharmony_ci		mod_name++;
22618c2ecf20Sopenharmony_ci	if (strlen(mod_name) >= MODULE_NAME_LEN) {
22628c2ecf20Sopenharmony_ci		merror("module name is too long [%s.ko]\n", mod->name);
22638c2ecf20Sopenharmony_ci		return 1;
22648c2ecf20Sopenharmony_ci	}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	return 0;
22678c2ecf20Sopenharmony_ci}
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci/**
22708c2ecf20Sopenharmony_ci * Header for the generated file
22718c2ecf20Sopenharmony_ci **/
22728c2ecf20Sopenharmony_cistatic void add_header(struct buffer *b, struct module *mod)
22738c2ecf20Sopenharmony_ci{
22748c2ecf20Sopenharmony_ci	buf_printf(b, "#include <linux/module.h>\n");
22758c2ecf20Sopenharmony_ci	/*
22768c2ecf20Sopenharmony_ci	 * Include build-salt.h after module.h in order to
22778c2ecf20Sopenharmony_ci	 * inherit the definitions.
22788c2ecf20Sopenharmony_ci	 */
22798c2ecf20Sopenharmony_ci	buf_printf(b, "#define INCLUDE_VERMAGIC\n");
22808c2ecf20Sopenharmony_ci	buf_printf(b, "#include <linux/build-salt.h>\n");
22818c2ecf20Sopenharmony_ci	buf_printf(b, "#include <linux/vermagic.h>\n");
22828c2ecf20Sopenharmony_ci	buf_printf(b, "#include <linux/compiler.h>\n");
22838c2ecf20Sopenharmony_ci	buf_printf(b, "\n");
22848c2ecf20Sopenharmony_ci	buf_printf(b, "BUILD_SALT;\n");
22858c2ecf20Sopenharmony_ci	buf_printf(b, "\n");
22868c2ecf20Sopenharmony_ci	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
22878c2ecf20Sopenharmony_ci	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
22888c2ecf20Sopenharmony_ci	buf_printf(b, "\n");
22898c2ecf20Sopenharmony_ci	buf_printf(b, "__visible struct module __this_module\n");
22908c2ecf20Sopenharmony_ci	buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
22918c2ecf20Sopenharmony_ci	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
22928c2ecf20Sopenharmony_ci	if (mod->has_init)
22938c2ecf20Sopenharmony_ci		buf_printf(b, "\t.init = init_module,\n");
22948c2ecf20Sopenharmony_ci	if (mod->has_cleanup)
22958c2ecf20Sopenharmony_ci		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
22968c2ecf20Sopenharmony_ci			      "\t.exit = cleanup_module,\n"
22978c2ecf20Sopenharmony_ci			      "#endif\n");
22988c2ecf20Sopenharmony_ci	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
22998c2ecf20Sopenharmony_ci	buf_printf(b, "};\n");
23008c2ecf20Sopenharmony_ci}
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_cistatic void add_intree_flag(struct buffer *b, int is_intree)
23038c2ecf20Sopenharmony_ci{
23048c2ecf20Sopenharmony_ci	if (is_intree)
23058c2ecf20Sopenharmony_ci		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
23068c2ecf20Sopenharmony_ci}
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci/* Cannot check for assembler */
23098c2ecf20Sopenharmony_cistatic void add_retpoline(struct buffer *b)
23108c2ecf20Sopenharmony_ci{
23118c2ecf20Sopenharmony_ci	buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
23128c2ecf20Sopenharmony_ci	buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
23138c2ecf20Sopenharmony_ci	buf_printf(b, "#endif\n");
23148c2ecf20Sopenharmony_ci}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_cistatic void add_staging_flag(struct buffer *b, const char *name)
23178c2ecf20Sopenharmony_ci{
23188c2ecf20Sopenharmony_ci	if (strstarts(name, "drivers/staging"))
23198c2ecf20Sopenharmony_ci		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
23208c2ecf20Sopenharmony_ci}
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci/**
23238c2ecf20Sopenharmony_ci * Record CRCs for unresolved symbols
23248c2ecf20Sopenharmony_ci **/
23258c2ecf20Sopenharmony_cistatic int add_versions(struct buffer *b, struct module *mod)
23268c2ecf20Sopenharmony_ci{
23278c2ecf20Sopenharmony_ci	struct symbol *s, *exp;
23288c2ecf20Sopenharmony_ci	int err = 0;
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	for (s = mod->unres; s; s = s->next) {
23318c2ecf20Sopenharmony_ci		exp = find_symbol(s->name);
23328c2ecf20Sopenharmony_ci		if (!exp || exp->module == mod)
23338c2ecf20Sopenharmony_ci			continue;
23348c2ecf20Sopenharmony_ci		s->module = exp->module;
23358c2ecf20Sopenharmony_ci		s->crc_valid = exp->crc_valid;
23368c2ecf20Sopenharmony_ci		s->crc = exp->crc;
23378c2ecf20Sopenharmony_ci	}
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	if (!modversions)
23408c2ecf20Sopenharmony_ci		return err;
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	buf_printf(b, "\n");
23438c2ecf20Sopenharmony_ci	buf_printf(b, "static const struct modversion_info ____versions[]\n");
23448c2ecf20Sopenharmony_ci	buf_printf(b, "__used __section(\"__versions\") = {\n");
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	for (s = mod->unres; s; s = s->next) {
23478c2ecf20Sopenharmony_ci		if (!s->module)
23488c2ecf20Sopenharmony_ci			continue;
23498c2ecf20Sopenharmony_ci		if (!s->crc_valid) {
23508c2ecf20Sopenharmony_ci			warn("\"%s\" [%s.ko] has no CRC!\n",
23518c2ecf20Sopenharmony_ci				s->name, mod->name);
23528c2ecf20Sopenharmony_ci			continue;
23538c2ecf20Sopenharmony_ci		}
23548c2ecf20Sopenharmony_ci		if (strlen(s->name) >= MODULE_NAME_LEN) {
23558c2ecf20Sopenharmony_ci			merror("too long symbol \"%s\" [%s.ko]\n",
23568c2ecf20Sopenharmony_ci			       s->name, mod->name);
23578c2ecf20Sopenharmony_ci			err = 1;
23588c2ecf20Sopenharmony_ci			break;
23598c2ecf20Sopenharmony_ci		}
23608c2ecf20Sopenharmony_ci		buf_printf(b, "\t{ %#8x, \"%s\" },\n",
23618c2ecf20Sopenharmony_ci			   s->crc, s->name);
23628c2ecf20Sopenharmony_ci	}
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci	buf_printf(b, "};\n");
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	return err;
23678c2ecf20Sopenharmony_ci}
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_cistatic void add_depends(struct buffer *b, struct module *mod)
23708c2ecf20Sopenharmony_ci{
23718c2ecf20Sopenharmony_ci	struct symbol *s;
23728c2ecf20Sopenharmony_ci	int first = 1;
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	/* Clear ->seen flag of modules that own symbols needed by this. */
23758c2ecf20Sopenharmony_ci	for (s = mod->unres; s; s = s->next)
23768c2ecf20Sopenharmony_ci		if (s->module)
23778c2ecf20Sopenharmony_ci			s->module->seen = s->module->is_vmlinux;
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	buf_printf(b, "\n");
23808c2ecf20Sopenharmony_ci	buf_printf(b, "MODULE_INFO(depends, \"");
23818c2ecf20Sopenharmony_ci	for (s = mod->unres; s; s = s->next) {
23828c2ecf20Sopenharmony_ci		const char *p;
23838c2ecf20Sopenharmony_ci		if (!s->module)
23848c2ecf20Sopenharmony_ci			continue;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci		if (s->module->seen)
23878c2ecf20Sopenharmony_ci			continue;
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci		s->module->seen = 1;
23908c2ecf20Sopenharmony_ci		p = strrchr(s->module->name, '/');
23918c2ecf20Sopenharmony_ci		if (p)
23928c2ecf20Sopenharmony_ci			p++;
23938c2ecf20Sopenharmony_ci		else
23948c2ecf20Sopenharmony_ci			p = s->module->name;
23958c2ecf20Sopenharmony_ci		buf_printf(b, "%s%s", first ? "" : ",", p);
23968c2ecf20Sopenharmony_ci		first = 0;
23978c2ecf20Sopenharmony_ci	}
23988c2ecf20Sopenharmony_ci	buf_printf(b, "\");\n");
23998c2ecf20Sopenharmony_ci}
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_cistatic void add_srcversion(struct buffer *b, struct module *mod)
24028c2ecf20Sopenharmony_ci{
24038c2ecf20Sopenharmony_ci	if (mod->srcversion[0]) {
24048c2ecf20Sopenharmony_ci		buf_printf(b, "\n");
24058c2ecf20Sopenharmony_ci		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
24068c2ecf20Sopenharmony_ci			   mod->srcversion);
24078c2ecf20Sopenharmony_ci	}
24088c2ecf20Sopenharmony_ci}
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_cistatic void write_buf(struct buffer *b, const char *fname)
24118c2ecf20Sopenharmony_ci{
24128c2ecf20Sopenharmony_ci	FILE *file;
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	file = fopen(fname, "w");
24158c2ecf20Sopenharmony_ci	if (!file) {
24168c2ecf20Sopenharmony_ci		perror(fname);
24178c2ecf20Sopenharmony_ci		exit(1);
24188c2ecf20Sopenharmony_ci	}
24198c2ecf20Sopenharmony_ci	if (fwrite(b->p, 1, b->pos, file) != b->pos) {
24208c2ecf20Sopenharmony_ci		perror(fname);
24218c2ecf20Sopenharmony_ci		exit(1);
24228c2ecf20Sopenharmony_ci	}
24238c2ecf20Sopenharmony_ci	if (fclose(file) != 0) {
24248c2ecf20Sopenharmony_ci		perror(fname);
24258c2ecf20Sopenharmony_ci		exit(1);
24268c2ecf20Sopenharmony_ci	}
24278c2ecf20Sopenharmony_ci}
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_cistatic void write_if_changed(struct buffer *b, const char *fname)
24308c2ecf20Sopenharmony_ci{
24318c2ecf20Sopenharmony_ci	char *tmp;
24328c2ecf20Sopenharmony_ci	FILE *file;
24338c2ecf20Sopenharmony_ci	struct stat st;
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci	file = fopen(fname, "r");
24368c2ecf20Sopenharmony_ci	if (!file)
24378c2ecf20Sopenharmony_ci		goto write;
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	if (fstat(fileno(file), &st) < 0)
24408c2ecf20Sopenharmony_ci		goto close_write;
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	if (st.st_size != b->pos)
24438c2ecf20Sopenharmony_ci		goto close_write;
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	tmp = NOFAIL(malloc(b->pos));
24468c2ecf20Sopenharmony_ci	if (fread(tmp, 1, b->pos, file) != b->pos)
24478c2ecf20Sopenharmony_ci		goto free_write;
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	if (memcmp(tmp, b->p, b->pos) != 0)
24508c2ecf20Sopenharmony_ci		goto free_write;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	free(tmp);
24538c2ecf20Sopenharmony_ci	fclose(file);
24548c2ecf20Sopenharmony_ci	return;
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci free_write:
24578c2ecf20Sopenharmony_ci	free(tmp);
24588c2ecf20Sopenharmony_ci close_write:
24598c2ecf20Sopenharmony_ci	fclose(file);
24608c2ecf20Sopenharmony_ci write:
24618c2ecf20Sopenharmony_ci	write_buf(b, fname);
24628c2ecf20Sopenharmony_ci}
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci/* parse Module.symvers file. line format:
24658c2ecf20Sopenharmony_ci * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
24668c2ecf20Sopenharmony_ci **/
24678c2ecf20Sopenharmony_cistatic void read_dump(const char *fname)
24688c2ecf20Sopenharmony_ci{
24698c2ecf20Sopenharmony_ci	char *buf, *pos, *line;
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	buf = read_text_file(fname);
24728c2ecf20Sopenharmony_ci	if (!buf)
24738c2ecf20Sopenharmony_ci		/* No symbol versions, silently ignore */
24748c2ecf20Sopenharmony_ci		return;
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	pos = buf;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	while ((line = get_line(&pos))) {
24798c2ecf20Sopenharmony_ci		char *symname, *namespace, *modname, *d, *export;
24808c2ecf20Sopenharmony_ci		unsigned int crc;
24818c2ecf20Sopenharmony_ci		struct module *mod;
24828c2ecf20Sopenharmony_ci		struct symbol *s;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci		if (!(symname = strchr(line, '\t')))
24858c2ecf20Sopenharmony_ci			goto fail;
24868c2ecf20Sopenharmony_ci		*symname++ = '\0';
24878c2ecf20Sopenharmony_ci		if (!(modname = strchr(symname, '\t')))
24888c2ecf20Sopenharmony_ci			goto fail;
24898c2ecf20Sopenharmony_ci		*modname++ = '\0';
24908c2ecf20Sopenharmony_ci		if (!(export = strchr(modname, '\t')))
24918c2ecf20Sopenharmony_ci			goto fail;
24928c2ecf20Sopenharmony_ci		*export++ = '\0';
24938c2ecf20Sopenharmony_ci		if (!(namespace = strchr(export, '\t')))
24948c2ecf20Sopenharmony_ci			goto fail;
24958c2ecf20Sopenharmony_ci		*namespace++ = '\0';
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci		crc = strtoul(line, &d, 16);
24988c2ecf20Sopenharmony_ci		if (*symname == '\0' || *modname == '\0' || *d != '\0')
24998c2ecf20Sopenharmony_ci			goto fail;
25008c2ecf20Sopenharmony_ci		mod = find_module(modname);
25018c2ecf20Sopenharmony_ci		if (!mod) {
25028c2ecf20Sopenharmony_ci			mod = new_module(modname);
25038c2ecf20Sopenharmony_ci			mod->from_dump = 1;
25048c2ecf20Sopenharmony_ci		}
25058c2ecf20Sopenharmony_ci		s = sym_add_exported(symname, mod, export_no(export));
25068c2ecf20Sopenharmony_ci		s->is_static = 0;
25078c2ecf20Sopenharmony_ci		sym_set_crc(symname, crc);
25088c2ecf20Sopenharmony_ci		sym_update_namespace(symname, namespace);
25098c2ecf20Sopenharmony_ci	}
25108c2ecf20Sopenharmony_ci	free(buf);
25118c2ecf20Sopenharmony_ci	return;
25128c2ecf20Sopenharmony_cifail:
25138c2ecf20Sopenharmony_ci	free(buf);
25148c2ecf20Sopenharmony_ci	fatal("parse error in symbol dump file\n");
25158c2ecf20Sopenharmony_ci}
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_cistatic void write_dump(const char *fname)
25188c2ecf20Sopenharmony_ci{
25198c2ecf20Sopenharmony_ci	struct buffer buf = { };
25208c2ecf20Sopenharmony_ci	struct symbol *symbol;
25218c2ecf20Sopenharmony_ci	const char *namespace;
25228c2ecf20Sopenharmony_ci	int n;
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
25258c2ecf20Sopenharmony_ci		symbol = symbolhash[n];
25268c2ecf20Sopenharmony_ci		while (symbol) {
25278c2ecf20Sopenharmony_ci			if (!symbol->module->from_dump) {
25288c2ecf20Sopenharmony_ci				namespace = symbol->namespace;
25298c2ecf20Sopenharmony_ci				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
25308c2ecf20Sopenharmony_ci					   symbol->crc, symbol->name,
25318c2ecf20Sopenharmony_ci					   symbol->module->name,
25328c2ecf20Sopenharmony_ci					   export_str(symbol->export),
25338c2ecf20Sopenharmony_ci					   namespace ? namespace : "");
25348c2ecf20Sopenharmony_ci			}
25358c2ecf20Sopenharmony_ci			symbol = symbol->next;
25368c2ecf20Sopenharmony_ci		}
25378c2ecf20Sopenharmony_ci	}
25388c2ecf20Sopenharmony_ci	write_buf(&buf, fname);
25398c2ecf20Sopenharmony_ci	free(buf.p);
25408c2ecf20Sopenharmony_ci}
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_cistatic void write_namespace_deps_files(const char *fname)
25438c2ecf20Sopenharmony_ci{
25448c2ecf20Sopenharmony_ci	struct module *mod;
25458c2ecf20Sopenharmony_ci	struct namespace_list *ns;
25468c2ecf20Sopenharmony_ci	struct buffer ns_deps_buf = {};
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	for (mod = modules; mod; mod = mod->next) {
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci		if (mod->from_dump || !mod->missing_namespaces)
25518c2ecf20Sopenharmony_ci			continue;
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci		buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci		for (ns = mod->missing_namespaces; ns; ns = ns->next)
25568c2ecf20Sopenharmony_ci			buf_printf(&ns_deps_buf, " %s", ns->namespace);
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci		buf_printf(&ns_deps_buf, "\n");
25598c2ecf20Sopenharmony_ci	}
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci	write_if_changed(&ns_deps_buf, fname);
25628c2ecf20Sopenharmony_ci	free(ns_deps_buf.p);
25638c2ecf20Sopenharmony_ci}
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_cistruct dump_list {
25668c2ecf20Sopenharmony_ci	struct dump_list *next;
25678c2ecf20Sopenharmony_ci	const char *file;
25688c2ecf20Sopenharmony_ci};
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ciint main(int argc, char **argv)
25718c2ecf20Sopenharmony_ci{
25728c2ecf20Sopenharmony_ci	struct module *mod;
25738c2ecf20Sopenharmony_ci	struct buffer buf = { };
25748c2ecf20Sopenharmony_ci	char *missing_namespace_deps = NULL;
25758c2ecf20Sopenharmony_ci	char *dump_write = NULL, *files_source = NULL;
25768c2ecf20Sopenharmony_ci	int opt;
25778c2ecf20Sopenharmony_ci	int err;
25788c2ecf20Sopenharmony_ci	int n;
25798c2ecf20Sopenharmony_ci	struct dump_list *dump_read_start = NULL;
25808c2ecf20Sopenharmony_ci	struct dump_list **dump_read_iter = &dump_read_start;
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
25838c2ecf20Sopenharmony_ci		switch (opt) {
25848c2ecf20Sopenharmony_ci		case 'e':
25858c2ecf20Sopenharmony_ci			external_module = 1;
25868c2ecf20Sopenharmony_ci			break;
25878c2ecf20Sopenharmony_ci		case 'i':
25888c2ecf20Sopenharmony_ci			*dump_read_iter =
25898c2ecf20Sopenharmony_ci				NOFAIL(calloc(1, sizeof(**dump_read_iter)));
25908c2ecf20Sopenharmony_ci			(*dump_read_iter)->file = optarg;
25918c2ecf20Sopenharmony_ci			dump_read_iter = &(*dump_read_iter)->next;
25928c2ecf20Sopenharmony_ci			break;
25938c2ecf20Sopenharmony_ci		case 'm':
25948c2ecf20Sopenharmony_ci			modversions = 1;
25958c2ecf20Sopenharmony_ci			break;
25968c2ecf20Sopenharmony_ci		case 'n':
25978c2ecf20Sopenharmony_ci			ignore_missing_files = 1;
25988c2ecf20Sopenharmony_ci			break;
25998c2ecf20Sopenharmony_ci		case 'o':
26008c2ecf20Sopenharmony_ci			dump_write = optarg;
26018c2ecf20Sopenharmony_ci			break;
26028c2ecf20Sopenharmony_ci		case 'a':
26038c2ecf20Sopenharmony_ci			all_versions = 1;
26048c2ecf20Sopenharmony_ci			break;
26058c2ecf20Sopenharmony_ci		case 'T':
26068c2ecf20Sopenharmony_ci			files_source = optarg;
26078c2ecf20Sopenharmony_ci			break;
26088c2ecf20Sopenharmony_ci		case 'w':
26098c2ecf20Sopenharmony_ci			warn_unresolved = 1;
26108c2ecf20Sopenharmony_ci			break;
26118c2ecf20Sopenharmony_ci		case 'E':
26128c2ecf20Sopenharmony_ci			sec_mismatch_fatal = 1;
26138c2ecf20Sopenharmony_ci			break;
26148c2ecf20Sopenharmony_ci		case 'N':
26158c2ecf20Sopenharmony_ci			allow_missing_ns_imports = 1;
26168c2ecf20Sopenharmony_ci			break;
26178c2ecf20Sopenharmony_ci		case 'd':
26188c2ecf20Sopenharmony_ci			missing_namespace_deps = optarg;
26198c2ecf20Sopenharmony_ci			break;
26208c2ecf20Sopenharmony_ci		default:
26218c2ecf20Sopenharmony_ci			exit(1);
26228c2ecf20Sopenharmony_ci		}
26238c2ecf20Sopenharmony_ci	}
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	while (dump_read_start) {
26268c2ecf20Sopenharmony_ci		struct dump_list *tmp;
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci		read_dump(dump_read_start->file);
26298c2ecf20Sopenharmony_ci		tmp = dump_read_start->next;
26308c2ecf20Sopenharmony_ci		free(dump_read_start);
26318c2ecf20Sopenharmony_ci		dump_read_start = tmp;
26328c2ecf20Sopenharmony_ci	}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci	while (optind < argc)
26358c2ecf20Sopenharmony_ci		read_symbols(argv[optind++]);
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	if (files_source)
26388c2ecf20Sopenharmony_ci		read_symbols_from_files(files_source);
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	/*
26418c2ecf20Sopenharmony_ci	 * When there's no vmlinux, don't print warnings about
26428c2ecf20Sopenharmony_ci	 * unresolved symbols (since there'll be too many ;)
26438c2ecf20Sopenharmony_ci	 */
26448c2ecf20Sopenharmony_ci	if (!have_vmlinux)
26458c2ecf20Sopenharmony_ci		warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n");
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci	err = 0;
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci	for (mod = modules; mod; mod = mod->next) {
26508c2ecf20Sopenharmony_ci		char fname[PATH_MAX];
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci		if (mod->is_vmlinux || mod->from_dump)
26538c2ecf20Sopenharmony_ci			continue;
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci		buf.pos = 0;
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci		err |= check_modname_len(mod);
26588c2ecf20Sopenharmony_ci		err |= check_exports(mod);
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci		add_header(&buf, mod);
26618c2ecf20Sopenharmony_ci		add_intree_flag(&buf, !external_module);
26628c2ecf20Sopenharmony_ci		add_retpoline(&buf);
26638c2ecf20Sopenharmony_ci		add_staging_flag(&buf, mod->name);
26648c2ecf20Sopenharmony_ci		err |= add_versions(&buf, mod);
26658c2ecf20Sopenharmony_ci		add_depends(&buf, mod);
26668c2ecf20Sopenharmony_ci		add_moddevtable(&buf, mod);
26678c2ecf20Sopenharmony_ci		add_srcversion(&buf, mod);
26688c2ecf20Sopenharmony_ci
26698c2ecf20Sopenharmony_ci		sprintf(fname, "%s.mod.c", mod->name);
26708c2ecf20Sopenharmony_ci		write_if_changed(&buf, fname);
26718c2ecf20Sopenharmony_ci	}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	if (missing_namespace_deps)
26748c2ecf20Sopenharmony_ci		write_namespace_deps_files(missing_namespace_deps);
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	if (dump_write)
26778c2ecf20Sopenharmony_ci		write_dump(dump_write);
26788c2ecf20Sopenharmony_ci	if (sec_mismatch_count && sec_mismatch_fatal)
26798c2ecf20Sopenharmony_ci		fatal("Section mismatches detected.\n"
26808c2ecf20Sopenharmony_ci		      "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
26818c2ecf20Sopenharmony_ci	for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
26828c2ecf20Sopenharmony_ci		struct symbol *s;
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci		for (s = symbolhash[n]; s; s = s->next) {
26858c2ecf20Sopenharmony_ci			if (s->is_static)
26868c2ecf20Sopenharmony_ci				warn("\"%s\" [%s] is a static %s\n",
26878c2ecf20Sopenharmony_ci				     s->name, s->module->name,
26888c2ecf20Sopenharmony_ci				     export_str(s->export));
26898c2ecf20Sopenharmony_ci		}
26908c2ecf20Sopenharmony_ci	}
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	free(buf.p);
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	return err;
26958c2ecf20Sopenharmony_ci}
2696