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