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