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 = §ioncheck[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