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; 38588ccd73SSam Ravnborg static int sec_mismatch_verbose = 1; 3947490ec1SNicolas Boichat static int sec_mismatch_fatal = 0; 40eed380f3SGuenter Roeck /* ignore missing files */ 41eed380f3SGuenter Roeck static int ignore_missing_files; 42588ccd73SSam Ravnborg 43c96fca21SSam Ravnborg enum export { 44c96fca21SSam Ravnborg export_plain, export_unused, export_gpl, 45c96fca21SSam Ravnborg export_unused_gpl, export_gpl_future, export_unknown 46c96fca21SSam Ravnborg }; 471da177e4SLinus Torvalds 484fd3e4efSWanlong Gao /* In kernel, this size is defined in linux/module.h; 494fd3e4efSWanlong Gao * here we use Elf_Addr instead of long for covering cross-compile 504fd3e4efSWanlong Gao */ 514fd3e4efSWanlong Gao 524fd3e4efSWanlong Gao #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) 534fd3e4efSWanlong Gao 546d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2))) 556d9a89eaSAndi Kleen 566d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...) 571da177e4SLinus Torvalds { 581da177e4SLinus Torvalds va_list arglist; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds fprintf(stderr, "FATAL: "); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds va_start(arglist, fmt); 631da177e4SLinus Torvalds vfprintf(stderr, fmt, arglist); 641da177e4SLinus Torvalds va_end(arglist); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds exit(1); 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 696d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds va_list arglist; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds fprintf(stderr, "WARNING: "); 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds va_start(arglist, fmt); 761da177e4SLinus Torvalds vfprintf(stderr, fmt, arglist); 771da177e4SLinus Torvalds va_end(arglist); 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 806d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...) 812a116659SMatthew Wilcox { 822a116659SMatthew Wilcox va_list arglist; 832a116659SMatthew Wilcox 842a116659SMatthew Wilcox fprintf(stderr, "ERROR: "); 852a116659SMatthew Wilcox 862a116659SMatthew Wilcox va_start(arglist, fmt); 872a116659SMatthew Wilcox vfprintf(stderr, fmt, arglist); 882a116659SMatthew Wilcox va_end(arglist); 892a116659SMatthew Wilcox } 902a116659SMatthew Wilcox 91d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix) 92d4ef1c30SRusty Russell { 93d4ef1c30SRusty Russell if (strlen(str) < strlen(postfix)) 94d4ef1c30SRusty Russell return false; 95d4ef1c30SRusty Russell 96d4ef1c30SRusty Russell return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; 97d4ef1c30SRusty Russell } 98d4ef1c30SRusty Russell 99040fcc81SSam Ravnborg static int is_vmlinux(const char *modname) 100040fcc81SSam Ravnborg { 101040fcc81SSam Ravnborg const char *myname; 102040fcc81SSam Ravnborg 103df578e7dSSam Ravnborg myname = strrchr(modname, '/'); 104df578e7dSSam Ravnborg if (myname) 105040fcc81SSam Ravnborg myname++; 106040fcc81SSam Ravnborg else 107040fcc81SSam Ravnborg myname = modname; 108040fcc81SSam Ravnborg 109741f98feSSam Ravnborg return (strcmp(myname, "vmlinux") == 0) || 110741f98feSSam Ravnborg (strcmp(myname, "vmlinux.o") == 0); 111040fcc81SSam Ravnborg } 112040fcc81SSam Ravnborg 1131da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr) 1141da177e4SLinus Torvalds { 115df578e7dSSam Ravnborg if (!ptr) 1161da177e4SLinus Torvalds fatal("modpost: Memory allocation failure: %s.\n", expr); 117df578e7dSSam Ravnborg 1181da177e4SLinus Torvalds return ptr; 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* A list of all modules we processed */ 1221da177e4SLinus Torvalds static struct module *modules; 1231da177e4SLinus Torvalds 1248b185743SMasahiro Yamada static struct module *find_module(const char *modname) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds struct module *mod; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds for (mod = modules; mod; mod = mod->next) 1291da177e4SLinus Torvalds if (strcmp(mod->name, modname) == 0) 1301da177e4SLinus Torvalds break; 1311da177e4SLinus Torvalds return mod; 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 134d4ef1c30SRusty Russell static struct module *new_module(const char *modname) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds struct module *mod; 137d4ef1c30SRusty Russell char *p; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds mod = NOFAIL(malloc(sizeof(*mod))); 1401da177e4SLinus Torvalds memset(mod, 0, sizeof(*mod)); 1411da177e4SLinus Torvalds p = NOFAIL(strdup(modname)); 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds /* strip trailing .o */ 144d4ef1c30SRusty Russell if (strends(p, ".o")) { 145d4ef1c30SRusty Russell p[strlen(p) - 2] = '\0'; 146258f7426SFrank Rowand mod->is_dot_o = 1; 147258f7426SFrank Rowand } 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds /* add to list */ 1501da177e4SLinus Torvalds mod->name = p; 151b817f6feSSam Ravnborg mod->gpl_compatible = -1; 1521da177e4SLinus Torvalds mod->next = modules; 1531da177e4SLinus Torvalds modules = mod; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds return mod; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds /* A hash of all exported symbols, 1591da177e4SLinus Torvalds * struct symbol is also used for lists of unresolved symbols */ 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds struct symbol { 1641da177e4SLinus Torvalds struct symbol *next; 1651da177e4SLinus Torvalds struct module *module; 1661da177e4SLinus Torvalds unsigned int crc; 1671da177e4SLinus Torvalds int crc_valid; 1681da177e4SLinus Torvalds unsigned int weak:1; 169040fcc81SSam Ravnborg unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ 170040fcc81SSam Ravnborg unsigned int kernel:1; /* 1 if symbol is from kernel 171040fcc81SSam Ravnborg * (only for external modules) **/ 172b6568b1aSRusty Russell unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */ 173bd5cbcedSRam Pai enum export export; /* Type of export */ 1741da177e4SLinus Torvalds char name[0]; 1751da177e4SLinus Torvalds }; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */ 1801da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds unsigned value; /* Used to compute the hash value. */ 1831da177e4SLinus Torvalds unsigned i; /* Used to cycle through random values. */ 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds /* Set the initial value from the key size. */ 1861da177e4SLinus Torvalds for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) 1871da177e4SLinus Torvalds value = (value + (((unsigned char *)name)[i] << (i*5 % 24))); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds return (1103515243 * value + 12345); 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1925c3ead8cSSam Ravnborg /** 1935c3ead8cSSam Ravnborg * Allocate a new symbols for use in the hash of exported symbols or 1945c3ead8cSSam Ravnborg * the list of unresolved symbols per module 1955c3ead8cSSam Ravnborg **/ 1965c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak, 1975c3ead8cSSam Ravnborg struct symbol *next) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds memset(s, 0, sizeof(*s)); 2021da177e4SLinus Torvalds strcpy(s->name, name); 2031da177e4SLinus Torvalds s->weak = weak; 2041da177e4SLinus Torvalds s->next = next; 2051da177e4SLinus Torvalds return s; 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* For the hash of exported symbols */ 209bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module, 210bd5cbcedSRam Pai enum export export) 2111da177e4SLinus Torvalds { 2121da177e4SLinus Torvalds unsigned int hash; 2131da177e4SLinus Torvalds struct symbol *new; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds hash = tdb_hash(name) % SYMBOL_HASH_SIZE; 2161da177e4SLinus Torvalds new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); 2171da177e4SLinus Torvalds new->module = module; 218bd5cbcedSRam Pai new->export = export; 219040fcc81SSam Ravnborg return new; 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 2225c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name) 2231da177e4SLinus Torvalds { 2241da177e4SLinus Torvalds struct symbol *s; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* For our purposes, .foo matches foo. PPC64 needs this. */ 2271da177e4SLinus Torvalds if (name[0] == '.') 2281da177e4SLinus Torvalds name++; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) { 2311da177e4SLinus Torvalds if (strcmp(s->name, name) == 0) 2321da177e4SLinus Torvalds return s; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds return NULL; 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2377a3ee753SMathias Krause static const struct { 238bd5cbcedSRam Pai const char *str; 239bd5cbcedSRam Pai enum export export; 240bd5cbcedSRam Pai } export_list[] = { 241bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL", .export = export_plain }, 242c96fca21SSam Ravnborg { .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused }, 243bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, 244c96fca21SSam Ravnborg { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl }, 245bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future }, 246bd5cbcedSRam Pai { .str = "(unknown)", .export = export_unknown }, 247bd5cbcedSRam Pai }; 248bd5cbcedSRam Pai 249bd5cbcedSRam Pai 250bd5cbcedSRam Pai static const char *export_str(enum export ex) 251bd5cbcedSRam Pai { 252bd5cbcedSRam Pai return export_list[ex].str; 253bd5cbcedSRam Pai } 254bd5cbcedSRam Pai 255bd5cbcedSRam Pai static enum export export_no(const char *s) 256bd5cbcedSRam Pai { 257bd5cbcedSRam Pai int i; 258df578e7dSSam Ravnborg 259534b89a9SSam Ravnborg if (!s) 260534b89a9SSam Ravnborg return export_unknown; 261bd5cbcedSRam Pai for (i = 0; export_list[i].export != export_unknown; i++) { 262bd5cbcedSRam Pai if (strcmp(export_list[i].str, s) == 0) 263bd5cbcedSRam Pai return export_list[i].export; 264bd5cbcedSRam Pai } 265bd5cbcedSRam Pai return export_unknown; 266bd5cbcedSRam Pai } 267bd5cbcedSRam Pai 2686124c04cSMasahiro Yamada static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) 2696124c04cSMasahiro Yamada { 2706124c04cSMasahiro Yamada return (void *)elf->hdr + 2716124c04cSMasahiro Yamada elf->sechdrs[elf->secindex_strings].sh_offset + 2726124c04cSMasahiro Yamada sechdr->sh_name; 2736124c04cSMasahiro Yamada } 2746124c04cSMasahiro Yamada 2756124c04cSMasahiro Yamada static const char *sec_name(struct elf_info *elf, int secindex) 2766124c04cSMasahiro Yamada { 2776124c04cSMasahiro Yamada return sech_name(elf, &elf->sechdrs[secindex]); 2786124c04cSMasahiro Yamada } 27962a26356SAlessio Igor Bogani 28062a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) 28162a26356SAlessio Igor Bogani 28262a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec) 28362a26356SAlessio Igor Bogani { 28462a26356SAlessio Igor Bogani const char *secname = sec_name(elf, sec); 28562a26356SAlessio Igor Bogani 28662a26356SAlessio Igor Bogani if (strstarts(secname, "___ksymtab+")) 28762a26356SAlessio Igor Bogani return export_plain; 28862a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_unused+")) 28962a26356SAlessio Igor Bogani return export_unused; 29062a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_gpl+")) 29162a26356SAlessio Igor Bogani return export_gpl; 29262a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_unused_gpl+")) 29362a26356SAlessio Igor Bogani return export_unused_gpl; 29462a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_gpl_future+")) 29562a26356SAlessio Igor Bogani return export_gpl_future; 29662a26356SAlessio Igor Bogani else 29762a26356SAlessio Igor Bogani return export_unknown; 29862a26356SAlessio Igor Bogani } 29962a26356SAlessio Igor Bogani 3001ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec) 301bd5cbcedSRam Pai { 302bd5cbcedSRam Pai if (sec == elf->export_sec) 303bd5cbcedSRam Pai return export_plain; 304c96fca21SSam Ravnborg else if (sec == elf->export_unused_sec) 305c96fca21SSam Ravnborg return export_unused; 306bd5cbcedSRam Pai else if (sec == elf->export_gpl_sec) 307bd5cbcedSRam Pai return export_gpl; 308c96fca21SSam Ravnborg else if (sec == elf->export_unused_gpl_sec) 309c96fca21SSam Ravnborg return export_unused_gpl; 310bd5cbcedSRam Pai else if (sec == elf->export_gpl_future_sec) 311bd5cbcedSRam Pai return export_gpl_future; 312bd5cbcedSRam Pai else 313bd5cbcedSRam Pai return export_unknown; 314bd5cbcedSRam Pai } 315bd5cbcedSRam Pai 3165c3ead8cSSam Ravnborg /** 3175c3ead8cSSam Ravnborg * Add an exported symbol - it may have already been added without a 3185c3ead8cSSam Ravnborg * CRC, in this case just update the CRC 3195c3ead8cSSam Ravnborg **/ 320bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod, 321bd5cbcedSRam Pai enum export export) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds struct symbol *s = find_symbol(name); 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds if (!s) { 326bd5cbcedSRam Pai s = new_symbol(name, mod, export); 3278e70c458SSam Ravnborg } else { 3288e70c458SSam Ravnborg if (!s->preloaded) { 3297b75b13cSSam Ravnborg warn("%s: '%s' exported twice. Previous export " 3308e70c458SSam Ravnborg "was in %s%s\n", mod->name, name, 3318e70c458SSam Ravnborg s->module->name, 3328e70c458SSam Ravnborg is_vmlinux(s->module->name) ?"":".ko"); 3334b21960fSTrent Piepho } else { 334baec30e4SPaul Bolle /* In case Module.symvers was out of date */ 3354b21960fSTrent Piepho s->module = mod; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds } 3388e70c458SSam Ravnborg s->preloaded = 0; 339040fcc81SSam Ravnborg s->vmlinux = is_vmlinux(mod->name); 340040fcc81SSam Ravnborg s->kernel = 0; 341bd5cbcedSRam Pai s->export = export; 342040fcc81SSam Ravnborg return s; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 345040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod, 346bd5cbcedSRam Pai unsigned int crc, enum export export) 347040fcc81SSam Ravnborg { 348040fcc81SSam Ravnborg struct symbol *s = find_symbol(name); 349040fcc81SSam Ravnborg 350b6568b1aSRusty Russell if (!s) { 351bd5cbcedSRam Pai s = new_symbol(name, mod, export); 352b6568b1aSRusty Russell /* Don't complain when we find it later. */ 353b6568b1aSRusty Russell s->preloaded = 1; 354b6568b1aSRusty Russell } 355040fcc81SSam Ravnborg s->crc = crc; 3561da177e4SLinus Torvalds s->crc_valid = 1; 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 3595c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size) 3601da177e4SLinus Torvalds { 3611da177e4SLinus Torvalds struct stat st; 362eb3d5cc6SJesper Juhl void *map = MAP_FAILED; 3631da177e4SLinus Torvalds int fd; 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds fd = open(filename, O_RDONLY); 366eb3d5cc6SJesper Juhl if (fd < 0) 3671da177e4SLinus Torvalds return NULL; 368eb3d5cc6SJesper Juhl if (fstat(fd, &st)) 369eb3d5cc6SJesper Juhl goto failed; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds *size = st.st_size; 3721da177e4SLinus Torvalds map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 3731da177e4SLinus Torvalds 374eb3d5cc6SJesper Juhl failed: 375eb3d5cc6SJesper Juhl close(fd); 3761da177e4SLinus Torvalds if (map == MAP_FAILED) 3771da177e4SLinus Torvalds return NULL; 3781da177e4SLinus Torvalds return map; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 3815c3ead8cSSam Ravnborg /** 3825c3ead8cSSam Ravnborg * Return a copy of the next line in a mmap'ed file. 3835c3ead8cSSam Ravnborg * spaces in the beginning of the line is trimmed away. 3845c3ead8cSSam Ravnborg * Return a pointer to a static buffer. 3855c3ead8cSSam Ravnborg **/ 3865c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds static char line[4096]; 3891da177e4SLinus Torvalds int skip = 1; 3901da177e4SLinus Torvalds size_t len = 0; 3911da177e4SLinus Torvalds signed char *p = (signed char *)file + *pos; 3921da177e4SLinus Torvalds char *s = line; 3931da177e4SLinus Torvalds 394df578e7dSSam Ravnborg for (; *pos < size ; (*pos)++) { 3951da177e4SLinus Torvalds if (skip && isspace(*p)) { 3961da177e4SLinus Torvalds p++; 3971da177e4SLinus Torvalds continue; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds skip = 0; 4001da177e4SLinus Torvalds if (*p != '\n' && (*pos < size)) { 4011da177e4SLinus Torvalds len++; 4021da177e4SLinus Torvalds *s++ = *p++; 4031da177e4SLinus Torvalds if (len > 4095) 4041da177e4SLinus Torvalds break; /* Too long, stop */ 4051da177e4SLinus Torvalds } else { 4061da177e4SLinus Torvalds /* End of string */ 4071da177e4SLinus Torvalds *s = '\0'; 4081da177e4SLinus Torvalds return line; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds /* End of buffer */ 4121da177e4SLinus Torvalds return NULL; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4155c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size) 4161da177e4SLinus Torvalds { 4171da177e4SLinus Torvalds munmap(file, size); 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 42085bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename) 4211da177e4SLinus Torvalds { 4221da177e4SLinus Torvalds unsigned int i; 42385bd2fddSSam Ravnborg Elf_Ehdr *hdr; 4241da177e4SLinus Torvalds Elf_Shdr *sechdrs; 4251da177e4SLinus Torvalds Elf_Sym *sym; 4261ce53adfSDenys Vlasenko const char *secstrings; 4271ce53adfSDenys Vlasenko unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds hdr = grab_file(filename, &info->size); 4301da177e4SLinus Torvalds if (!hdr) { 431eed380f3SGuenter Roeck if (ignore_missing_files) { 432eed380f3SGuenter Roeck fprintf(stderr, "%s: %s (ignored)\n", filename, 433eed380f3SGuenter Roeck strerror(errno)); 434eed380f3SGuenter Roeck return 0; 435eed380f3SGuenter Roeck } 4361da177e4SLinus Torvalds perror(filename); 4376803dc0eSSam Ravnborg exit(1); 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds info->hdr = hdr; 44085bd2fddSSam Ravnborg if (info->size < sizeof(*hdr)) { 44185bd2fddSSam Ravnborg /* file too small, assume this is an empty .o file */ 44285bd2fddSSam Ravnborg return 0; 44385bd2fddSSam Ravnborg } 44485bd2fddSSam Ravnborg /* Is this a valid ELF file? */ 44585bd2fddSSam Ravnborg if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || 44685bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG1] != ELFMAG1) || 44785bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG2] != ELFMAG2) || 44885bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG3] != ELFMAG3)) { 44985bd2fddSSam Ravnborg /* Not an ELF file - silently ignore it */ 45085bd2fddSSam Ravnborg return 0; 45185bd2fddSSam Ravnborg } 4521da177e4SLinus Torvalds /* Fix endianness in ELF header */ 453ae4ac123SAtsushi Nemoto hdr->e_type = TO_NATIVE(hdr->e_type); 4547d875a02SAnders Kaseorg hdr->e_machine = TO_NATIVE(hdr->e_machine); 4557d875a02SAnders Kaseorg hdr->e_version = TO_NATIVE(hdr->e_version); 4567d875a02SAnders Kaseorg hdr->e_entry = TO_NATIVE(hdr->e_entry); 4577d875a02SAnders Kaseorg hdr->e_phoff = TO_NATIVE(hdr->e_phoff); 4587d875a02SAnders Kaseorg hdr->e_shoff = TO_NATIVE(hdr->e_shoff); 4597d875a02SAnders Kaseorg hdr->e_flags = TO_NATIVE(hdr->e_flags); 4607d875a02SAnders Kaseorg hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize); 4617d875a02SAnders Kaseorg hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize); 4627d875a02SAnders Kaseorg hdr->e_phnum = TO_NATIVE(hdr->e_phnum); 4637d875a02SAnders Kaseorg hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize); 4647d875a02SAnders Kaseorg hdr->e_shnum = TO_NATIVE(hdr->e_shnum); 4657d875a02SAnders Kaseorg hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); 4661da177e4SLinus Torvalds sechdrs = (void *)hdr + hdr->e_shoff; 4671da177e4SLinus Torvalds info->sechdrs = sechdrs; 4681da177e4SLinus Torvalds 469a83710e5SPetr Stetiar /* Check if file offset is correct */ 470a83710e5SPetr Stetiar if (hdr->e_shoff > info->size) { 471df578e7dSSam Ravnborg fatal("section header offset=%lu in file '%s' is bigger than " 472df578e7dSSam Ravnborg "filesize=%lu\n", (unsigned long)hdr->e_shoff, 473df578e7dSSam Ravnborg filename, info->size); 474a83710e5SPetr Stetiar return 0; 475a83710e5SPetr Stetiar } 476a83710e5SPetr Stetiar 4776845756bSAnders Kaseorg if (hdr->e_shnum == SHN_UNDEF) { 4781ce53adfSDenys Vlasenko /* 4791ce53adfSDenys Vlasenko * There are more than 64k sections, 4801ce53adfSDenys Vlasenko * read count from .sh_size. 4811ce53adfSDenys Vlasenko */ 4821ce53adfSDenys Vlasenko info->num_sections = TO_NATIVE(sechdrs[0].sh_size); 4831ce53adfSDenys Vlasenko } 4841ce53adfSDenys Vlasenko else { 4851ce53adfSDenys Vlasenko info->num_sections = hdr->e_shnum; 4861ce53adfSDenys Vlasenko } 4871ce53adfSDenys Vlasenko if (hdr->e_shstrndx == SHN_XINDEX) { 4886845756bSAnders Kaseorg info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link); 4891ce53adfSDenys Vlasenko } 4901ce53adfSDenys Vlasenko else { 4911ce53adfSDenys Vlasenko info->secindex_strings = hdr->e_shstrndx; 4921ce53adfSDenys Vlasenko } 4931ce53adfSDenys Vlasenko 4941da177e4SLinus Torvalds /* Fix endianness in section headers */ 4951ce53adfSDenys Vlasenko for (i = 0; i < info->num_sections; i++) { 4967d875a02SAnders Kaseorg sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); 4971da177e4SLinus Torvalds sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); 4987d875a02SAnders Kaseorg sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); 4997d875a02SAnders Kaseorg sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); 5001da177e4SLinus Torvalds sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); 5011da177e4SLinus Torvalds sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); 5021da177e4SLinus Torvalds sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); 503ae4ac123SAtsushi Nemoto sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); 5047d875a02SAnders Kaseorg sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign); 5057d875a02SAnders Kaseorg sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds /* Find symbol table. */ 5081ce53adfSDenys Vlasenko secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; 5091ce53adfSDenys Vlasenko for (i = 1; i < info->num_sections; i++) { 510bd5cbcedSRam Pai const char *secname; 51156fc82c5STejun Heo int nobits = sechdrs[i].sh_type == SHT_NOBITS; 5121da177e4SLinus Torvalds 51356fc82c5STejun Heo if (!nobits && sechdrs[i].sh_offset > info->size) { 514df578e7dSSam Ravnborg fatal("%s is truncated. sechdrs[i].sh_offset=%lu > " 515df578e7dSSam Ravnborg "sizeof(*hrd)=%zu\n", filename, 516df578e7dSSam Ravnborg (unsigned long)sechdrs[i].sh_offset, 517df578e7dSSam Ravnborg sizeof(*hdr)); 51885bd2fddSSam Ravnborg return 0; 51985bd2fddSSam Ravnborg } 520bd5cbcedSRam Pai secname = secstrings + sechdrs[i].sh_name; 521bd5cbcedSRam Pai if (strcmp(secname, ".modinfo") == 0) { 52256fc82c5STejun Heo if (nobits) 52356fc82c5STejun Heo fatal("%s has NOBITS .modinfo\n", filename); 5241da177e4SLinus Torvalds info->modinfo = (void *)hdr + sechdrs[i].sh_offset; 5251da177e4SLinus Torvalds info->modinfo_len = sechdrs[i].sh_size; 526bd5cbcedSRam Pai } else if (strcmp(secname, "__ksymtab") == 0) 527bd5cbcedSRam Pai info->export_sec = i; 528c96fca21SSam Ravnborg else if (strcmp(secname, "__ksymtab_unused") == 0) 529c96fca21SSam Ravnborg info->export_unused_sec = i; 530bd5cbcedSRam Pai else if (strcmp(secname, "__ksymtab_gpl") == 0) 531bd5cbcedSRam Pai info->export_gpl_sec = i; 532c96fca21SSam Ravnborg else if (strcmp(secname, "__ksymtab_unused_gpl") == 0) 533c96fca21SSam Ravnborg info->export_unused_gpl_sec = i; 534bd5cbcedSRam Pai else if (strcmp(secname, "__ksymtab_gpl_future") == 0) 535bd5cbcedSRam Pai info->export_gpl_future_sec = i; 536bd5cbcedSRam Pai 5371ce53adfSDenys Vlasenko if (sechdrs[i].sh_type == SHT_SYMTAB) { 5381ce53adfSDenys Vlasenko unsigned int sh_link_idx; 5391ce53adfSDenys Vlasenko symtab_idx = i; 5401ce53adfSDenys Vlasenko info->symtab_start = (void *)hdr + 5411ce53adfSDenys Vlasenko sechdrs[i].sh_offset; 5421ce53adfSDenys Vlasenko info->symtab_stop = (void *)hdr + 5431ce53adfSDenys Vlasenko sechdrs[i].sh_offset + sechdrs[i].sh_size; 5446845756bSAnders Kaseorg sh_link_idx = sechdrs[i].sh_link; 5451da177e4SLinus Torvalds info->strtab = (void *)hdr + 5461ce53adfSDenys Vlasenko sechdrs[sh_link_idx].sh_offset; 5471ce53adfSDenys Vlasenko } 5481ce53adfSDenys Vlasenko 5491ce53adfSDenys Vlasenko /* 32bit section no. table? ("more than 64k sections") */ 5501ce53adfSDenys Vlasenko if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { 5511ce53adfSDenys Vlasenko symtab_shndx_idx = i; 5521ce53adfSDenys Vlasenko info->symtab_shndx_start = (void *)hdr + 5531ce53adfSDenys Vlasenko sechdrs[i].sh_offset; 5541ce53adfSDenys Vlasenko info->symtab_shndx_stop = (void *)hdr + 5551ce53adfSDenys Vlasenko sechdrs[i].sh_offset + sechdrs[i].sh_size; 5561ce53adfSDenys Vlasenko } 5571da177e4SLinus Torvalds } 558df578e7dSSam Ravnborg if (!info->symtab_start) 559cb80514dSSam Ravnborg fatal("%s has no symtab?\n", filename); 560df578e7dSSam Ravnborg 5611da177e4SLinus Torvalds /* Fix endianness in symbols */ 5621da177e4SLinus Torvalds for (sym = info->symtab_start; sym < info->symtab_stop; sym++) { 5631da177e4SLinus Torvalds sym->st_shndx = TO_NATIVE(sym->st_shndx); 5641da177e4SLinus Torvalds sym->st_name = TO_NATIVE(sym->st_name); 5651da177e4SLinus Torvalds sym->st_value = TO_NATIVE(sym->st_value); 5661da177e4SLinus Torvalds sym->st_size = TO_NATIVE(sym->st_size); 5671da177e4SLinus Torvalds } 5681ce53adfSDenys Vlasenko 5691ce53adfSDenys Vlasenko if (symtab_shndx_idx != ~0U) { 5701ce53adfSDenys Vlasenko Elf32_Word *p; 5716845756bSAnders Kaseorg if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link) 5721ce53adfSDenys Vlasenko fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", 5736845756bSAnders Kaseorg filename, sechdrs[symtab_shndx_idx].sh_link, 5741ce53adfSDenys Vlasenko symtab_idx); 5751ce53adfSDenys Vlasenko /* Fix endianness */ 5761ce53adfSDenys Vlasenko for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; 5771ce53adfSDenys Vlasenko p++) 5781ce53adfSDenys Vlasenko *p = TO_NATIVE(*p); 5791ce53adfSDenys Vlasenko } 5801ce53adfSDenys Vlasenko 58185bd2fddSSam Ravnborg return 1; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 5845c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info) 5851da177e4SLinus Torvalds { 5861da177e4SLinus Torvalds release_file(info->hdr, info->size); 5871da177e4SLinus Torvalds } 5881da177e4SLinus Torvalds 5894d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname) 5904d7365d6SSam Ravnborg { 5914d7365d6SSam Ravnborg /* ignore __this_module, it will be resolved shortly */ 592b2c5cdcfSMasahiro Yamada if (strcmp(symname, "__this_module") == 0) 5934d7365d6SSam Ravnborg return 1; 5944d7365d6SSam Ravnborg /* ignore global offset table */ 5954d7365d6SSam Ravnborg if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) 5964d7365d6SSam Ravnborg return 1; 5974d7365d6SSam Ravnborg if (info->hdr->e_machine == EM_PPC) 5984d7365d6SSam Ravnborg /* Special register function linked on all modules during final link of .ko */ 599d62c4765SMasahiro Yamada if (strstarts(symname, "_restgpr_") || 600d62c4765SMasahiro Yamada strstarts(symname, "_savegpr_") || 601d62c4765SMasahiro Yamada strstarts(symname, "_rest32gpr_") || 602d62c4765SMasahiro Yamada strstarts(symname, "_save32gpr_") || 603d62c4765SMasahiro Yamada strstarts(symname, "_restvr_") || 604d62c4765SMasahiro Yamada strstarts(symname, "_savevr_")) 6054d7365d6SSam Ravnborg return 1; 6067fca5dc8SStephen Rothwell if (info->hdr->e_machine == EM_PPC64) 6077fca5dc8SStephen Rothwell /* Special register function linked on all modules during final link of .ko */ 608d62c4765SMasahiro Yamada if (strstarts(symname, "_restgpr0_") || 609d62c4765SMasahiro Yamada strstarts(symname, "_savegpr0_") || 610d62c4765SMasahiro Yamada strstarts(symname, "_restvr_") || 611d62c4765SMasahiro Yamada strstarts(symname, "_savevr_") || 612c153693dSAlan Modra strcmp(symname, ".TOC.") == 0) 6137fca5dc8SStephen Rothwell return 1; 6144d7365d6SSam Ravnborg /* Do not ignore this symbol */ 6154d7365d6SSam Ravnborg return 0; 6164d7365d6SSam Ravnborg } 6174d7365d6SSam Ravnborg 6185c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info, 6191da177e4SLinus Torvalds Elf_Sym *sym, const char *symname) 6201da177e4SLinus Torvalds { 6211da177e4SLinus Torvalds unsigned int crc; 62262a26356SAlessio Igor Bogani enum export export; 623d8c1eb86SNicholas Piggin bool is_crc = false; 62462a26356SAlessio Igor Bogani 625258f7426SFrank Rowand if ((!is_vmlinux(mod->name) || mod->is_dot_o) && 626d62c4765SMasahiro Yamada strstarts(symname, "__ksymtab")) 62762a26356SAlessio Igor Bogani export = export_from_secname(info, get_secindex(info, sym)); 62862a26356SAlessio Igor Bogani else 62962a26356SAlessio Igor Bogani export = export_from_sec(info, get_secindex(info, sym)); 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds /* CRC'd symbol */ 632d62c4765SMasahiro Yamada if (strstarts(symname, "__crc_")) { 633d8c1eb86SNicholas Piggin is_crc = true; 6341da177e4SLinus Torvalds crc = (unsigned int) sym->st_value; 63556067812SArd Biesheuvel if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) { 63656067812SArd Biesheuvel unsigned int *crcp; 63756067812SArd Biesheuvel 63856067812SArd Biesheuvel /* symbol points to the CRC in the ELF object */ 63956067812SArd Biesheuvel crcp = (void *)info->hdr + sym->st_value + 64056067812SArd Biesheuvel info->sechdrs[sym->st_shndx].sh_offset - 64156067812SArd Biesheuvel (info->hdr->e_type != ET_REL ? 64256067812SArd Biesheuvel info->sechdrs[sym->st_shndx].sh_addr : 0); 64356067812SArd Biesheuvel crc = *crcp; 64456067812SArd Biesheuvel } 645b2c5cdcfSMasahiro Yamada sym_update_crc(symname + strlen("__crc_"), mod, crc, 646bd5cbcedSRam Pai export); 6471da177e4SLinus Torvalds } 648b5064654SAndi Kleen 649b5064654SAndi Kleen switch (sym->st_shndx) { 650b5064654SAndi Kleen case SHN_COMMON: 651d62c4765SMasahiro Yamada if (strstarts(symname, "__gnu_lto_")) { 652ef178f92SAndi Kleen /* Should warn here, but modpost runs before the linker */ 653ef178f92SAndi Kleen } else 654b5064654SAndi Kleen warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); 6551da177e4SLinus Torvalds break; 6561da177e4SLinus Torvalds case SHN_UNDEF: 6571da177e4SLinus Torvalds /* undefined symbol */ 6581da177e4SLinus Torvalds if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && 6591da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) != STB_WEAK) 6601da177e4SLinus Torvalds break; 6614d7365d6SSam Ravnborg if (ignore_undef_symbol(info, symname)) 6621da177e4SLinus Torvalds break; 6638d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ 6648d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) 6658d529014SBen Colline /* add compatibility with older glibc */ 6668d529014SBen Colline #ifndef STT_SPARC_REGISTER 6678d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER 6688d529014SBen Colline #endif 6691da177e4SLinus Torvalds if (info->hdr->e_machine == EM_SPARC || 6701da177e4SLinus Torvalds info->hdr->e_machine == EM_SPARCV9) { 6711da177e4SLinus Torvalds /* Ignore register directives. */ 6728d529014SBen Colline if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) 6731da177e4SLinus Torvalds break; 6747caaeabbSAl Viro if (symname[0] == '.') { 6751f3aa900SRandy Dunlap char *munged = NOFAIL(strdup(symname)); 6767caaeabbSAl Viro munged[0] = '_'; 6777caaeabbSAl Viro munged[1] = toupper(munged[1]); 6787caaeabbSAl Viro symname = munged; 6797caaeabbSAl Viro } 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds #endif 6821da177e4SLinus Torvalds 683d8c1eb86SNicholas Piggin if (is_crc) { 684d8c1eb86SNicholas Piggin const char *e = is_vmlinux(mod->name) ?"":".ko"; 685b2c5cdcfSMasahiro Yamada warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", 686b2c5cdcfSMasahiro Yamada symname + strlen("__crc_"), mod->name, e); 687d8c1eb86SNicholas Piggin } 688b92021b0SRusty Russell mod->unres = alloc_symbol(symname, 6891da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) == STB_WEAK, 6901da177e4SLinus Torvalds mod->unres); 6911da177e4SLinus Torvalds break; 6921da177e4SLinus Torvalds default: 6931da177e4SLinus Torvalds /* All exported symbols */ 694d62c4765SMasahiro Yamada if (strstarts(symname, "__ksymtab_")) { 695b2c5cdcfSMasahiro Yamada sym_add_exported(symname + strlen("__ksymtab_"), mod, 696bd5cbcedSRam Pai export); 6971da177e4SLinus Torvalds } 698b2c5cdcfSMasahiro Yamada if (strcmp(symname, "init_module") == 0) 6991da177e4SLinus Torvalds mod->has_init = 1; 700b2c5cdcfSMasahiro Yamada if (strcmp(symname, "cleanup_module") == 0) 7011da177e4SLinus Torvalds mod->has_cleanup = 1; 7021da177e4SLinus Torvalds break; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 7065c3ead8cSSam Ravnborg /** 7075c3ead8cSSam Ravnborg * Parse tag=value strings from .modinfo section 7085c3ead8cSSam Ravnborg **/ 7091da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize) 7101da177e4SLinus Torvalds { 7111da177e4SLinus Torvalds /* Skip non-zero chars */ 7121da177e4SLinus Torvalds while (string[0]) { 7131da177e4SLinus Torvalds string++; 7141da177e4SLinus Torvalds if ((*secsize)-- <= 1) 7151da177e4SLinus Torvalds return NULL; 7161da177e4SLinus Torvalds } 7171da177e4SLinus Torvalds 7181da177e4SLinus Torvalds /* Skip any zero padding. */ 7191da177e4SLinus Torvalds while (!string[0]) { 7201da177e4SLinus Torvalds string++; 7211da177e4SLinus Torvalds if ((*secsize)-- <= 1) 7221da177e4SLinus Torvalds return NULL; 7231da177e4SLinus Torvalds } 7241da177e4SLinus Torvalds return string; 7251da177e4SLinus Torvalds } 7261da177e4SLinus Torvalds 727bca2cceeSMasahiro Yamada static char *get_next_modinfo(struct elf_info *info, const char *tag, 728bca2cceeSMasahiro Yamada char *prev) 7291da177e4SLinus Torvalds { 7301da177e4SLinus Torvalds char *p; 7311da177e4SLinus Torvalds unsigned int taglen = strlen(tag); 732bca2cceeSMasahiro Yamada char *modinfo = info->modinfo; 733bca2cceeSMasahiro Yamada unsigned long size = info->modinfo_len; 7341da177e4SLinus Torvalds 735bca2cceeSMasahiro Yamada if (prev) { 736bca2cceeSMasahiro Yamada size -= prev - modinfo; 737bca2cceeSMasahiro Yamada modinfo = next_string(prev, &size); 738b817f6feSSam Ravnborg } 739b817f6feSSam Ravnborg 7401da177e4SLinus Torvalds for (p = modinfo; p; p = next_string(p, &size)) { 7411da177e4SLinus Torvalds if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') 7421da177e4SLinus Torvalds return p + taglen + 1; 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds return NULL; 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds 747bca2cceeSMasahiro Yamada static char *get_modinfo(struct elf_info *info, const char *tag) 748b817f6feSSam Ravnborg 749b817f6feSSam Ravnborg { 750bca2cceeSMasahiro Yamada return get_next_modinfo(info, tag, NULL); 751b817f6feSSam Ravnborg } 752b817f6feSSam Ravnborg 75393684d3bSSam Ravnborg /** 7544c8fbca5SSam Ravnborg * Test if string s ends in string sub 7554c8fbca5SSam Ravnborg * return 0 if match 7564c8fbca5SSam Ravnborg **/ 7574c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub) 7584c8fbca5SSam Ravnborg { 7594c8fbca5SSam Ravnborg int slen, sublen; 7604c8fbca5SSam Ravnborg 7614c8fbca5SSam Ravnborg if (!s || !sub) 7624c8fbca5SSam Ravnborg return 1; 7634c8fbca5SSam Ravnborg 7644c8fbca5SSam Ravnborg slen = strlen(s); 7654c8fbca5SSam Ravnborg sublen = strlen(sub); 7664c8fbca5SSam Ravnborg 7674c8fbca5SSam Ravnborg if ((slen == 0) || (sublen == 0)) 7684c8fbca5SSam Ravnborg return 1; 7694c8fbca5SSam Ravnborg 7704c8fbca5SSam Ravnborg if (sublen > slen) 7714c8fbca5SSam Ravnborg return 1; 7724c8fbca5SSam Ravnborg 7734c8fbca5SSam Ravnborg return memcmp(s + slen - sublen, sub, sublen); 7744c8fbca5SSam Ravnborg } 7754c8fbca5SSam Ravnborg 776ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) 777ff13f926SSam Ravnborg { 77858fb0d4fSSam Ravnborg if (sym) 779ff13f926SSam Ravnborg return elf->strtab + sym->st_name; 78058fb0d4fSSam Ravnborg else 781f666751aSSam Ravnborg return "(unknown)"; 782ff13f926SSam Ravnborg } 783ff13f926SSam Ravnborg 78410668220SSam Ravnborg /* The pattern is an array of simple patterns. 78510668220SSam Ravnborg * "foo" will match an exact string equal to "foo" 7866c5bd235SSam Ravnborg * "*foo" will match a string that ends with "foo" 78710668220SSam Ravnborg * "foo*" will match a string that begins with "foo" 78809c20c03SPaul Gortmaker * "*foo*" will match a string that contains "foo" 78910668220SSam Ravnborg */ 7905c725138STrevor Keith static int match(const char *sym, const char * const pat[]) 79110668220SSam Ravnborg { 79210668220SSam Ravnborg const char *p; 79310668220SSam Ravnborg while (*pat) { 79410668220SSam Ravnborg p = *pat++; 79510668220SSam Ravnborg const char *endp = p + strlen(p) - 1; 79610668220SSam Ravnborg 79709c20c03SPaul Gortmaker /* "*foo*" */ 79809c20c03SPaul Gortmaker if (*p == '*' && *endp == '*') { 79909c20c03SPaul Gortmaker char *here, *bare = strndup(p + 1, strlen(p) - 2); 80009c20c03SPaul Gortmaker 80109c20c03SPaul Gortmaker here = strstr(sym, bare); 80209c20c03SPaul Gortmaker free(bare); 80309c20c03SPaul Gortmaker if (here != NULL) 80409c20c03SPaul Gortmaker return 1; 80509c20c03SPaul Gortmaker } 8066c5bd235SSam Ravnborg /* "*foo" */ 80709c20c03SPaul Gortmaker else if (*p == '*') { 8086c5bd235SSam Ravnborg if (strrcmp(sym, p + 1) == 0) 8096c5bd235SSam Ravnborg return 1; 8106c5bd235SSam Ravnborg } 81110668220SSam Ravnborg /* "foo*" */ 8126c5bd235SSam Ravnborg else if (*endp == '*') { 81310668220SSam Ravnborg if (strncmp(sym, p, strlen(p) - 1) == 0) 81410668220SSam Ravnborg return 1; 81510668220SSam Ravnborg } 81610668220SSam Ravnborg /* no wildcards */ 81710668220SSam Ravnborg else { 81810668220SSam Ravnborg if (strcmp(p, sym) == 0) 81910668220SSam Ravnborg return 1; 82010668220SSam Ravnborg } 82110668220SSam Ravnborg } 82210668220SSam Ravnborg /* no match */ 82310668220SSam Ravnborg return 0; 82410668220SSam Ravnborg } 82510668220SSam Ravnborg 82610668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */ 8277a3ee753SMathias Krause static const char *const section_white_list[] = 8284391ed6aSSam Ravnborg { 8294391ed6aSSam Ravnborg ".comment*", 8304391ed6aSSam Ravnborg ".debug*", 8314d10c223SChen Gang ".cranges", /* sh64 */ 8321121584fSH.J. Lu ".zdebug*", /* Compressed debug sections. */ 833739d875dSDavid Howells ".GCC.command.line", /* record-gcc-switches */ 8344391ed6aSSam Ravnborg ".mdebug*", /* alpha, score, mips etc. */ 8354391ed6aSSam Ravnborg ".pdr", /* alpha, score, mips etc. */ 8364391ed6aSSam Ravnborg ".stab*", 8374391ed6aSSam Ravnborg ".note*", 8384391ed6aSSam Ravnborg ".got*", 8394391ed6aSSam Ravnborg ".toc*", 840af42e970SMax Filippov ".xt.prop", /* xtensa */ 841af42e970SMax Filippov ".xt.lit", /* xtensa */ 842f2e207f3SVineet Gupta ".arcextmap*", /* arc */ 843f2e207f3SVineet Gupta ".gnu.linkonce.arcext*", /* arc : modules */ 844d1189c63SNoam Camus ".cmem*", /* EZchip */ 845d1189c63SNoam Camus ".fmt_slot*", /* EZchip */ 846ef178f92SAndi Kleen ".gnu.lto*", 847e390f9a9SJosh Poimboeuf ".discard.*", 8484391ed6aSSam Ravnborg NULL 8494391ed6aSSam Ravnborg }; 85010668220SSam Ravnborg 851e241a630SSam Ravnborg /* 852b614a697SAnders Kaseorg * This is used to find sections missing the SHF_ALLOC flag. 853e241a630SSam Ravnborg * The cause of this is often a section specified in assembler 854b614a697SAnders Kaseorg * without "ax" / "aw". 855e241a630SSam Ravnborg */ 856b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf, 857b614a697SAnders Kaseorg Elf_Shdr *sechdr) 858e241a630SSam Ravnborg { 859b614a697SAnders Kaseorg const char *sec = sech_name(elf, sechdr); 860e241a630SSam Ravnborg 861b614a697SAnders Kaseorg if (sechdr->sh_type == SHT_PROGBITS && 862b614a697SAnders Kaseorg !(sechdr->sh_flags & SHF_ALLOC) && 863b614a697SAnders Kaseorg !match(sec, section_white_list)) { 864b614a697SAnders Kaseorg warn("%s (%s): unexpected non-allocatable section.\n" 865b614a697SAnders Kaseorg "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" 866e241a630SSam Ravnborg "Note that for example <linux/init.h> contains\n" 867e241a630SSam Ravnborg "section definitions for use in .S files.\n\n", 868e241a630SSam Ravnborg modname, sec); 869e241a630SSam Ravnborg } 870e241a630SSam Ravnborg } 871e241a630SSam Ravnborg 872e241a630SSam Ravnborg 873e241a630SSam Ravnborg 874eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \ 875a0d8f803SRasmus Villemoes ".init.setup", ".init.rodata", ".meminit.rodata", \ 876a0d8f803SRasmus Villemoes ".init.data", ".meminit.data" 877eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \ 878a0d8f803SRasmus Villemoes ".exit.data", ".memexit.data" 87910668220SSam Ravnborg 880eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \ 881a0d8f803SRasmus Villemoes ".init.text", ".meminit.text" 882eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \ 883a0d8f803SRasmus Villemoes ".exit.text", ".memexit.text" 88410668220SSam Ravnborg 885bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS \ 886a0d8f803SRasmus Villemoes ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \ 887a0d8f803SRasmus Villemoes ".pci_fixup_enable", ".pci_fixup_resume", \ 888a0d8f803SRasmus Villemoes ".pci_fixup_resume_early", ".pci_fixup_suspend" 889bb15d8dbSSebastian Andrzej Siewior 890e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS 891e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS 8924a31a229SUwe Kleine-König 8934a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS 8944a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS 89510668220SSam Ravnborg 896a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel" 897157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ 8986727ad9eSChris Metcalf ".kprobes.text", ".cpuidle.text" 89952dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ 900673c2c34SChris Metcalf ".fixup", ".entry.text", ".exception.text", ".text.*", \ 901673c2c34SChris Metcalf ".coldtext" 90210668220SSam Ravnborg 903fd6c3a8dSJan Beulich #define INIT_SECTIONS ".init.*" 904fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS ".meminit.*" 905eb8f6890SSam Ravnborg 906fd6c3a8dSJan Beulich #define EXIT_SECTIONS ".exit.*" 907fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS ".memexit.*" 908eb8f6890SSam Ravnborg 90952dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \ 91052dc0595SQuentin Casasnovas TEXT_SECTIONS, OTHER_TEXT_SECTIONS 91152dc0595SQuentin Casasnovas 9126c5bd235SSam Ravnborg /* init data sections */ 9137a3ee753SMathias Krause static const char *const init_data_sections[] = 9147a3ee753SMathias Krause { ALL_INIT_DATA_SECTIONS, NULL }; 9156c5bd235SSam Ravnborg 9166c5bd235SSam Ravnborg /* all init sections */ 9177a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; 9186c5bd235SSam Ravnborg 9196c5bd235SSam Ravnborg /* All init and exit sections (code + data) */ 9207a3ee753SMathias Krause static const char *const init_exit_sections[] = 921eb8f6890SSam Ravnborg {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; 9226c5bd235SSam Ravnborg 9234a3893d0SPaul Gortmaker /* all text sections */ 9244a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL }; 9254a3893d0SPaul Gortmaker 9266c5bd235SSam Ravnborg /* data section */ 9277a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL }; 9286c5bd235SSam Ravnborg 9296c5bd235SSam Ravnborg 9306c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */ 931af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST \ 932af92a82dSUwe Kleine-König "*driver", \ 933af92a82dSUwe Kleine-König "*_template", /* scsi uses *_template a lot */ \ 934af92a82dSUwe Kleine-König "*_timer", /* arm uses ops structures named _timer a lot */ \ 935af92a82dSUwe Kleine-König "*_sht", /* scsi also used *_sht to some extent */ \ 936af92a82dSUwe Kleine-König "*_ops", \ 937af92a82dSUwe Kleine-König "*_probe", \ 938af92a82dSUwe Kleine-König "*_probe_one", \ 939af92a82dSUwe Kleine-König "*_console" 9406c5bd235SSam Ravnborg 9417a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL }; 9427a3ee753SMathias Krause static const char *const linker_symbols[] = 9436c5bd235SSam Ravnborg { "__init_begin", "_sinittext", "_einittext", NULL }; 9444a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL }; 9456c5bd235SSam Ravnborg 946588ccd73SSam Ravnborg enum mismatch { 947bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_INIT, 948bbd3f4fbSUwe Kleine-König DATA_TO_ANY_INIT, 949bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_EXIT, 950bbd3f4fbSUwe Kleine-König DATA_TO_ANY_EXIT, 951bbd3f4fbSUwe Kleine-König XXXINIT_TO_SOME_INIT, 952bbd3f4fbSUwe Kleine-König XXXEXIT_TO_SOME_EXIT, 953bbd3f4fbSUwe Kleine-König ANY_INIT_TO_ANY_EXIT, 954bbd3f4fbSUwe Kleine-König ANY_EXIT_TO_ANY_INIT, 955588ccd73SSam Ravnborg EXPORT_TO_INIT_EXIT, 95652dc0595SQuentin Casasnovas EXTABLE_TO_NON_TEXT, 957588ccd73SSam Ravnborg }; 958588ccd73SSam Ravnborg 959e5d8f59aSQuentin Casasnovas /** 960e5d8f59aSQuentin Casasnovas * Describe how to match sections on different criterias: 961e5d8f59aSQuentin Casasnovas * 962e5d8f59aSQuentin Casasnovas * @fromsec: Array of sections to be matched. 963e5d8f59aSQuentin Casasnovas * 964e5d8f59aSQuentin Casasnovas * @bad_tosec: Relocations applied to a section in @fromsec to a section in 965e5d8f59aSQuentin Casasnovas * this array is forbidden (black-list). Can be empty. 966e5d8f59aSQuentin Casasnovas * 967e5d8f59aSQuentin Casasnovas * @good_tosec: Relocations applied to a section in @fromsec must be 968e5d8f59aSQuentin Casasnovas * targetting sections in this array (white-list). Can be empty. 969e5d8f59aSQuentin Casasnovas * 970e5d8f59aSQuentin Casasnovas * @mismatch: Type of mismatch. 971e5d8f59aSQuentin Casasnovas * 972e5d8f59aSQuentin Casasnovas * @symbol_white_list: Do not match a relocation to a symbol in this list 973e5d8f59aSQuentin Casasnovas * even if it is targetting a section in @bad_to_sec. 974e5d8f59aSQuentin Casasnovas * 975e5d8f59aSQuentin Casasnovas * @handler: Specific handler to call when a match is found. If NULL, 976e5d8f59aSQuentin Casasnovas * default_mismatch_handler() will be called. 977e5d8f59aSQuentin Casasnovas * 978e5d8f59aSQuentin Casasnovas */ 97910668220SSam Ravnborg struct sectioncheck { 98010668220SSam Ravnborg const char *fromsec[20]; 981050e57fdSQuentin Casasnovas const char *bad_tosec[20]; 982050e57fdSQuentin Casasnovas const char *good_tosec[20]; 983588ccd73SSam Ravnborg enum mismatch mismatch; 984af92a82dSUwe Kleine-König const char *symbol_white_list[20]; 985644e8f14SQuentin Casasnovas void (*handler)(const char *modname, struct elf_info *elf, 986644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 987644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec); 988644e8f14SQuentin Casasnovas 98910668220SSam Ravnborg }; 99010668220SSam Ravnborg 99152dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf, 99252dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 99352dc0595SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, 99452dc0595SQuentin Casasnovas const char *fromsec); 99552dc0595SQuentin Casasnovas 9967a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = { 99710668220SSam Ravnborg /* Do not reference init/exit code/data from 99810668220SSam Ravnborg * normal code and data 99910668220SSam Ravnborg */ 100010668220SSam Ravnborg { 1001588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 1002050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 1003bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_INIT, 1004af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1005588ccd73SSam Ravnborg }, 1006588ccd73SSam Ravnborg { 1007588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 1008050e57fdSQuentin Casasnovas .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, 1009bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 1010af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1011588ccd73SSam Ravnborg }, 1012588ccd73SSam Ravnborg { 10130db25245SUwe Kleine-König .fromsec = { DATA_SECTIONS, NULL }, 1014050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 10150db25245SUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 10160db25245SUwe Kleine-König .symbol_white_list = { 10170db25245SUwe Kleine-König "*_template", "*_timer", "*_sht", "*_ops", 10180db25245SUwe Kleine-König "*_probe", "*_probe_one", "*_console", NULL 10190db25245SUwe Kleine-König }, 10200db25245SUwe Kleine-König }, 10210db25245SUwe Kleine-König { 1022588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 1023050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1024bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_EXIT, 1025af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1026588ccd73SSam Ravnborg }, 1027588ccd73SSam Ravnborg { 1028588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 1029050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1030bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_EXIT, 1031af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1032eb8f6890SSam Ravnborg }, 1033e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */ 1034eb8f6890SSam Ravnborg { 10354a31a229SUwe Kleine-König .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, 1036050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1037bbd3f4fbSUwe Kleine-König .mismatch = XXXINIT_TO_SOME_INIT, 1038af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1039eb8f6890SSam Ravnborg }, 1040e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */ 1041eb8f6890SSam Ravnborg { 10424a31a229SUwe Kleine-König .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, 1043050e57fdSQuentin Casasnovas .bad_tosec = { EXIT_SECTIONS, NULL }, 1044bbd3f4fbSUwe Kleine-König .mismatch = XXXEXIT_TO_SOME_EXIT, 1045af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 104610668220SSam Ravnborg }, 104710668220SSam Ravnborg /* Do not use exit code/data from init code */ 104810668220SSam Ravnborg { 1049eb8f6890SSam Ravnborg .fromsec = { ALL_INIT_SECTIONS, NULL }, 1050050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1051bbd3f4fbSUwe Kleine-König .mismatch = ANY_INIT_TO_ANY_EXIT, 1052af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 105310668220SSam Ravnborg }, 105410668220SSam Ravnborg /* Do not use init code/data from exit code */ 105510668220SSam Ravnborg { 1056eb8f6890SSam Ravnborg .fromsec = { ALL_EXIT_SECTIONS, NULL }, 1057050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 1058bbd3f4fbSUwe Kleine-König .mismatch = ANY_EXIT_TO_ANY_INIT, 1059af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 106010668220SSam Ravnborg }, 1061bb15d8dbSSebastian Andrzej Siewior { 1062bb15d8dbSSebastian Andrzej Siewior .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, 1063050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1064bb15d8dbSSebastian Andrzej Siewior .mismatch = ANY_INIT_TO_ANY_EXIT, 1065bb15d8dbSSebastian Andrzej Siewior .symbol_white_list = { NULL }, 1066bb15d8dbSSebastian Andrzej Siewior }, 106710668220SSam Ravnborg /* Do not export init/exit functions or data */ 106810668220SSam Ravnborg { 106910668220SSam Ravnborg .fromsec = { "__ksymtab*", NULL }, 1070050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, 1071af92a82dSUwe Kleine-König .mismatch = EXPORT_TO_INIT_EXIT, 1072af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 107352dc0595SQuentin Casasnovas }, 107452dc0595SQuentin Casasnovas { 107552dc0595SQuentin Casasnovas .fromsec = { "__ex_table", NULL }, 107652dc0595SQuentin Casasnovas /* If you're adding any new black-listed sections in here, consider 107752dc0595SQuentin Casasnovas * adding a special 'printer' for them in scripts/check_extable. 107852dc0595SQuentin Casasnovas */ 107952dc0595SQuentin Casasnovas .bad_tosec = { ".altinstr_replacement", NULL }, 108052dc0595SQuentin Casasnovas .good_tosec = {ALL_TEXT_SECTIONS , NULL}, 108152dc0595SQuentin Casasnovas .mismatch = EXTABLE_TO_NON_TEXT, 108252dc0595SQuentin Casasnovas .handler = extable_mismatch_handler, 108310668220SSam Ravnborg } 108410668220SSam Ravnborg }; 108510668220SSam Ravnborg 10860d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch( 10870d2a636eSUwe Kleine-König const char *fromsec, const char *tosec) 108810668220SSam Ravnborg { 108910668220SSam Ravnborg int i; 109010668220SSam Ravnborg int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); 109110668220SSam Ravnborg const struct sectioncheck *check = §ioncheck[0]; 109210668220SSam Ravnborg 1093c5c3439aSQuentin Casasnovas /* 1094c5c3439aSQuentin Casasnovas * The target section could be the SHT_NUL section when we're 1095c5c3439aSQuentin Casasnovas * handling relocations to un-resolved symbols, trying to match it 1096739d875dSDavid Howells * doesn't make much sense and causes build failures on parisc 1097739d875dSDavid Howells * architectures. 1098c5c3439aSQuentin Casasnovas */ 1099c5c3439aSQuentin Casasnovas if (*tosec == '\0') 1100c5c3439aSQuentin Casasnovas return NULL; 1101c5c3439aSQuentin Casasnovas 110210668220SSam Ravnborg for (i = 0; i < elems; i++) { 1103050e57fdSQuentin Casasnovas if (match(fromsec, check->fromsec)) { 1104050e57fdSQuentin Casasnovas if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) 11050d2a636eSUwe Kleine-König return check; 1106050e57fdSQuentin Casasnovas if (check->good_tosec[0] && !match(tosec, check->good_tosec)) 1107050e57fdSQuentin Casasnovas return check; 1108050e57fdSQuentin Casasnovas } 110910668220SSam Ravnborg check++; 111010668220SSam Ravnborg } 11110d2a636eSUwe Kleine-König return NULL; 111210668220SSam Ravnborg } 111310668220SSam Ravnborg 11144c8fbca5SSam Ravnborg /** 11154c8fbca5SSam Ravnborg * Whitelist to allow certain references to pass with no warning. 11160e0d314eSSam Ravnborg * 11174c8fbca5SSam Ravnborg * Pattern 1: 11184c8fbca5SSam Ravnborg * If a module parameter is declared __initdata and permissions=0 11194c8fbca5SSam Ravnborg * then this is legal despite the warning generated. 11204c8fbca5SSam Ravnborg * We cannot see value of permissions here, so just ignore 11214c8fbca5SSam Ravnborg * this pattern. 11224c8fbca5SSam Ravnborg * The pattern is identified by: 11234c8fbca5SSam Ravnborg * tosec = .init.data 11249209aed0SSam Ravnborg * fromsec = .data* 11254c8fbca5SSam Ravnborg * atsym =__param* 11264c8fbca5SSam Ravnborg * 11276a841528SRusty Russell * Pattern 1a: 11286a841528SRusty Russell * module_param_call() ops can refer to __init set function if permissions=0 11296a841528SRusty Russell * The pattern is identified by: 11306a841528SRusty Russell * tosec = .init.text 11316a841528SRusty Russell * fromsec = .data* 11326a841528SRusty Russell * atsym = __param_ops_* 11336a841528SRusty Russell * 11344c8fbca5SSam Ravnborg * Pattern 2: 113572ee59b5SRandy Dunlap * Many drivers utilise a *driver container with references to 11364c8fbca5SSam Ravnborg * add, remove, probe functions etc. 11374c8fbca5SSam Ravnborg * the pattern is identified by: 113883cda2bbSSam Ravnborg * tosec = init or exit section 113983cda2bbSSam Ravnborg * fromsec = data section 1140df578e7dSSam Ravnborg * atsym = *driver, *_template, *_sht, *_ops, *_probe, 1141df578e7dSSam Ravnborg * *probe_one, *_console, *_timer 1142ee6a8545SVivek Goyal * 1143ee6a8545SVivek Goyal * Pattern 3: 1144c993971fSSam Ravnborg * Whitelist all references from .head.text to any init section 11459bf8cb9bSSam Ravnborg * 11461d8af559SSam Ravnborg * Pattern 4: 1147ee6a8545SVivek Goyal * Some symbols belong to init section but still it is ok to reference 1148ee6a8545SVivek Goyal * these from non-init sections as these symbols don't have any memory 1149ee6a8545SVivek Goyal * allocated for them and symbol address and value are same. So even 1150ee6a8545SVivek Goyal * if init section is freed, its ok to reference those symbols. 1151ee6a8545SVivek Goyal * For ex. symbols marking the init section boundaries. 1152ee6a8545SVivek Goyal * This pattern is identified by 1153ee6a8545SVivek Goyal * refsymname = __init_begin, _sinittext, _einittext 11549bf8cb9bSSam Ravnborg * 11554a3893d0SPaul Gortmaker * Pattern 5: 11564a3893d0SPaul Gortmaker * GCC may optimize static inlines when fed constant arg(s) resulting 11574a3893d0SPaul Gortmaker * in functions like cpumask_empty() -- generating an associated symbol 11584a3893d0SPaul Gortmaker * cpumask_empty.constprop.3 that appears in the audit. If the const that 11594a3893d0SPaul Gortmaker * is passed in comes from __init, like say nmi_ipi_mask, we get a 11604a3893d0SPaul Gortmaker * meaningless section warning. May need to add isra symbols too... 11614a3893d0SPaul Gortmaker * This pattern is identified by 11624a3893d0SPaul Gortmaker * tosec = init section 11634a3893d0SPaul Gortmaker * fromsec = text section 11644a3893d0SPaul Gortmaker * refsymname = *.constprop.* 11654a3893d0SPaul Gortmaker * 11664c8fbca5SSam Ravnborg **/ 1167af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch, 1168af92a82dSUwe Kleine-König const char *fromsec, const char *fromsym, 116958fb0d4fSSam Ravnborg const char *tosec, const char *tosym) 11704c8fbca5SSam Ravnborg { 11714c8fbca5SSam Ravnborg /* Check for pattern 1 */ 11726c5bd235SSam Ravnborg if (match(tosec, init_data_sections) && 11736c5bd235SSam Ravnborg match(fromsec, data_sections) && 1174d62c4765SMasahiro Yamada strstarts(fromsym, "__param")) 117558fb0d4fSSam Ravnborg return 0; 11764c8fbca5SSam Ravnborg 11776a841528SRusty Russell /* Check for pattern 1a */ 11786a841528SRusty Russell if (strcmp(tosec, ".init.text") == 0 && 11796a841528SRusty Russell match(fromsec, data_sections) && 1180d62c4765SMasahiro Yamada strstarts(fromsym, "__param_ops_")) 11816a841528SRusty Russell return 0; 11826a841528SRusty Russell 11834c8fbca5SSam Ravnborg /* Check for pattern 2 */ 11846c5bd235SSam Ravnborg if (match(tosec, init_exit_sections) && 11856c5bd235SSam Ravnborg match(fromsec, data_sections) && 1186af92a82dSUwe Kleine-König match(fromsym, mismatch->symbol_white_list)) 118758fb0d4fSSam Ravnborg return 0; 11884c8fbca5SSam Ravnborg 11899bf8cb9bSSam Ravnborg /* Check for pattern 3 */ 11906c5bd235SSam Ravnborg if (match(fromsec, head_sections) && 11916c5bd235SSam Ravnborg match(tosec, init_sections)) 119258fb0d4fSSam Ravnborg return 0; 1193f8657e1bSVivek Goyal 11941d8af559SSam Ravnborg /* Check for pattern 4 */ 119558fb0d4fSSam Ravnborg if (match(tosym, linker_symbols)) 119693659af1SSam Ravnborg return 0; 119758fb0d4fSSam Ravnborg 11984a3893d0SPaul Gortmaker /* Check for pattern 5 */ 11994a3893d0SPaul Gortmaker if (match(fromsec, text_sections) && 12004a3893d0SPaul Gortmaker match(tosec, init_sections) && 12014a3893d0SPaul Gortmaker match(fromsym, optim_symbols)) 12024a3893d0SPaul Gortmaker return 0; 12034a3893d0SPaul Gortmaker 120458fb0d4fSSam Ravnborg return 1; 12054c8fbca5SSam Ravnborg } 12064c8fbca5SSam Ravnborg 12075818c683SSami Tolvanen static inline int is_arm_mapping_symbol(const char *str) 12085818c683SSami Tolvanen { 12095818c683SSami Tolvanen return str[0] == '$' && strchr("axtd", str[1]) 12105818c683SSami Tolvanen && (str[2] == '\0' || str[2] == '.'); 12115818c683SSami Tolvanen } 12125818c683SSami Tolvanen 12135818c683SSami Tolvanen /* 12145818c683SSami Tolvanen * If there's no name there, ignore it; likewise, ignore it if it's 12155818c683SSami Tolvanen * one of the magic symbols emitted used by current ARM tools. 12165818c683SSami Tolvanen * 12175818c683SSami Tolvanen * Otherwise if find_symbols_between() returns those symbols, they'll 12185818c683SSami Tolvanen * fail the whitelist tests and cause lots of false alarms ... fixable 12195818c683SSami Tolvanen * only by merging __exit and __init sections into __text, bloating 12205818c683SSami Tolvanen * the kernel (which is especially evil on embedded platforms). 12215818c683SSami Tolvanen */ 12225818c683SSami Tolvanen static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym) 12235818c683SSami Tolvanen { 12245818c683SSami Tolvanen const char *name = elf->strtab + sym->st_name; 12255818c683SSami Tolvanen 12265818c683SSami Tolvanen if (!name || !strlen(name)) 12275818c683SSami Tolvanen return 0; 12285818c683SSami Tolvanen return !is_arm_mapping_symbol(name); 12295818c683SSami Tolvanen } 12305818c683SSami Tolvanen 12314c8fbca5SSam Ravnborg /** 123293684d3bSSam Ravnborg * Find symbol based on relocation record info. 123393684d3bSSam Ravnborg * In some cases the symbol supplied is a valid symbol so 123493684d3bSSam Ravnborg * return refsym. If st_name != 0 we assume this is a valid symbol. 123593684d3bSSam Ravnborg * In other cases the symbol needs to be looked up in the symbol table 123693684d3bSSam Ravnborg * based on section and address. 123793684d3bSSam Ravnborg * **/ 12389ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, 123993684d3bSSam Ravnborg Elf_Sym *relsym) 124093684d3bSSam Ravnborg { 124193684d3bSSam Ravnborg Elf_Sym *sym; 12429ad21c3fSSam Ravnborg Elf_Sym *near = NULL; 12439ad21c3fSSam Ravnborg Elf64_Sword distance = 20; 12449ad21c3fSSam Ravnborg Elf64_Sword d; 12451ce53adfSDenys Vlasenko unsigned int relsym_secindex; 124693684d3bSSam Ravnborg 124793684d3bSSam Ravnborg if (relsym->st_name != 0) 124893684d3bSSam Ravnborg return relsym; 12491ce53adfSDenys Vlasenko 12501ce53adfSDenys Vlasenko relsym_secindex = get_secindex(elf, relsym); 125193684d3bSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 12521ce53adfSDenys Vlasenko if (get_secindex(elf, sym) != relsym_secindex) 125393684d3bSSam Ravnborg continue; 1254ae4ac123SAtsushi Nemoto if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) 1255ae4ac123SAtsushi Nemoto continue; 12565818c683SSami Tolvanen if (!is_valid_name(elf, sym)) 12575818c683SSami Tolvanen continue; 125893684d3bSSam Ravnborg if (sym->st_value == addr) 125993684d3bSSam Ravnborg return sym; 12609ad21c3fSSam Ravnborg /* Find a symbol nearby - addr are maybe negative */ 12619ad21c3fSSam Ravnborg d = sym->st_value - addr; 12629ad21c3fSSam Ravnborg if (d < 0) 12639ad21c3fSSam Ravnborg d = addr - sym->st_value; 12649ad21c3fSSam Ravnborg if (d < distance) { 12659ad21c3fSSam Ravnborg distance = d; 12669ad21c3fSSam Ravnborg near = sym; 126793684d3bSSam Ravnborg } 12689ad21c3fSSam Ravnborg } 12699ad21c3fSSam Ravnborg /* We need a close match */ 12709ad21c3fSSam Ravnborg if (distance < 20) 12719ad21c3fSSam Ravnborg return near; 12729ad21c3fSSam Ravnborg else 127393684d3bSSam Ravnborg return NULL; 127493684d3bSSam Ravnborg } 127593684d3bSSam Ravnborg 1276b39927cfSSam Ravnborg /* 127743c74d17SSam Ravnborg * Find symbols before or equal addr and after addr - in the section sec. 127843c74d17SSam Ravnborg * If we find two symbols with equal offset prefer one with a valid name. 127943c74d17SSam Ravnborg * The ELF format may have a better way to detect what type of symbol 128043c74d17SSam Ravnborg * it is, but this works for now. 1281b39927cfSSam Ravnborg **/ 1282157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, 1283157c23c8SSam Ravnborg const char *sec) 1284b39927cfSSam Ravnborg { 1285b39927cfSSam Ravnborg Elf_Sym *sym; 1286157c23c8SSam Ravnborg Elf_Sym *near = NULL; 1287157c23c8SSam Ravnborg Elf_Addr distance = ~0; 1288b39927cfSSam Ravnborg 1289b39927cfSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 1290b39927cfSSam Ravnborg const char *symsec; 1291b39927cfSSam Ravnborg 12921ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1293b39927cfSSam Ravnborg continue; 12941ce53adfSDenys Vlasenko symsec = sec_name(elf, get_secindex(elf, sym)); 1295b39927cfSSam Ravnborg if (strcmp(symsec, sec) != 0) 1296b39927cfSSam Ravnborg continue; 1297da68d61fSDavid Brownell if (!is_valid_name(elf, sym)) 1298da68d61fSDavid Brownell continue; 1299b39927cfSSam Ravnborg if (sym->st_value <= addr) { 1300157c23c8SSam Ravnborg if ((addr - sym->st_value) < distance) { 1301157c23c8SSam Ravnborg distance = addr - sym->st_value; 1302157c23c8SSam Ravnborg near = sym; 1303157c23c8SSam Ravnborg } else if ((addr - sym->st_value) == distance) { 1304157c23c8SSam Ravnborg near = sym; 130543c74d17SSam Ravnborg } 1306b39927cfSSam Ravnborg } 1307b39927cfSSam Ravnborg } 1308157c23c8SSam Ravnborg return near; 1309157c23c8SSam Ravnborg } 1310b39927cfSSam Ravnborg 131158fb0d4fSSam Ravnborg /* 1312588ccd73SSam Ravnborg * Convert a section name to the function/data attribute 1313588ccd73SSam Ravnborg * .init.text => __init 1314588ccd73SSam Ravnborg * .memexitconst => __memconst 1315588ccd73SSam Ravnborg * etc. 1316cbcf14a9SAndy Shevchenko * 1317cbcf14a9SAndy Shevchenko * The memory of returned value has been allocated on a heap. The user of this 1318cbcf14a9SAndy Shevchenko * method should free it after usage. 1319588ccd73SSam Ravnborg */ 1320588ccd73SSam Ravnborg static char *sec2annotation(const char *s) 1321588ccd73SSam Ravnborg { 1322588ccd73SSam Ravnborg if (match(s, init_exit_sections)) { 13231f3aa900SRandy Dunlap char *p = NOFAIL(malloc(20)); 1324588ccd73SSam Ravnborg char *r = p; 1325588ccd73SSam Ravnborg 1326588ccd73SSam Ravnborg *p++ = '_'; 1327588ccd73SSam Ravnborg *p++ = '_'; 1328588ccd73SSam Ravnborg if (*s == '.') 1329588ccd73SSam Ravnborg s++; 1330588ccd73SSam Ravnborg while (*s && *s != '.') 1331588ccd73SSam Ravnborg *p++ = *s++; 1332588ccd73SSam Ravnborg *p = '\0'; 1333588ccd73SSam Ravnborg if (*s == '.') 1334588ccd73SSam Ravnborg s++; 1335588ccd73SSam Ravnborg if (strstr(s, "rodata") != NULL) 1336588ccd73SSam Ravnborg strcat(p, "const "); 1337588ccd73SSam Ravnborg else if (strstr(s, "data") != NULL) 1338588ccd73SSam Ravnborg strcat(p, "data "); 1339588ccd73SSam Ravnborg else 1340588ccd73SSam Ravnborg strcat(p, " "); 1341cbcf14a9SAndy Shevchenko return r; 1342588ccd73SSam Ravnborg } else { 13431f3aa900SRandy Dunlap return NOFAIL(strdup("")); 1344588ccd73SSam Ravnborg } 1345588ccd73SSam Ravnborg } 1346588ccd73SSam Ravnborg 1347588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym) 1348588ccd73SSam Ravnborg { 1349588ccd73SSam Ravnborg if (sym) 1350588ccd73SSam Ravnborg return ELF_ST_TYPE(sym->st_info) == STT_FUNC; 1351588ccd73SSam Ravnborg else 1352f666751aSSam Ravnborg return -1; 1353588ccd73SSam Ravnborg } 1354588ccd73SSam Ravnborg 135500759c0eSRandy Dunlap static void print_section_list(const char * const list[20]) 135600759c0eSRandy Dunlap { 135700759c0eSRandy Dunlap const char *const *s = list; 135800759c0eSRandy Dunlap 135900759c0eSRandy Dunlap while (*s) { 136000759c0eSRandy Dunlap fprintf(stderr, "%s", *s); 136100759c0eSRandy Dunlap s++; 136200759c0eSRandy Dunlap if (*s) 136300759c0eSRandy Dunlap fprintf(stderr, ", "); 136400759c0eSRandy Dunlap } 136500759c0eSRandy Dunlap fprintf(stderr, "\n"); 136600759c0eSRandy Dunlap } 136700759c0eSRandy Dunlap 1368356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p) 1369356ad538SQuentin Casasnovas { 1370356ad538SQuentin Casasnovas switch (is_func) { 1371356ad538SQuentin Casasnovas case 0: *name = "variable"; *name_p = ""; break; 1372356ad538SQuentin Casasnovas case 1: *name = "function"; *name_p = "()"; break; 1373356ad538SQuentin Casasnovas default: *name = "(unknown reference)"; *name_p = ""; break; 1374356ad538SQuentin Casasnovas } 1375356ad538SQuentin Casasnovas } 1376356ad538SQuentin Casasnovas 1377588ccd73SSam Ravnborg /* 1378b39927cfSSam Ravnborg * Print a warning about a section mismatch. 1379b39927cfSSam Ravnborg * Try to find symbols near it so user can find it. 13804c8fbca5SSam Ravnborg * Check whitelist before warning - it may be a false positive. 138158fb0d4fSSam Ravnborg */ 13820d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname, 13830d2a636eSUwe Kleine-König const struct sectioncheck *mismatch, 138458fb0d4fSSam Ravnborg const char *fromsec, 138558fb0d4fSSam Ravnborg unsigned long long fromaddr, 138658fb0d4fSSam Ravnborg const char *fromsym, 1387588ccd73SSam Ravnborg int from_is_func, 1388588ccd73SSam Ravnborg const char *tosec, const char *tosym, 1389588ccd73SSam Ravnborg int to_is_func) 1390b39927cfSSam Ravnborg { 1391588ccd73SSam Ravnborg const char *from, *from_p; 1392588ccd73SSam Ravnborg const char *to, *to_p; 139337ed19d5SAlexey Fomenko char *prl_from; 139437ed19d5SAlexey Fomenko char *prl_to; 1395f666751aSSam Ravnborg 1396e5f95c8bSSam Ravnborg sec_mismatch_count++; 1397e5f95c8bSSam Ravnborg if (!sec_mismatch_verbose) 1398e5f95c8bSSam Ravnborg return; 1399e5f95c8bSSam Ravnborg 1400356ad538SQuentin Casasnovas get_pretty_name(from_is_func, &from, &from_p); 1401356ad538SQuentin Casasnovas get_pretty_name(to_is_func, &to, &to_p); 1402356ad538SQuentin Casasnovas 14037c0ac495SGeert Uytterhoeven warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " 14047c0ac495SGeert Uytterhoeven "to the %s %s:%s%s\n", 14057c0ac495SGeert Uytterhoeven modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, 14067c0ac495SGeert Uytterhoeven tosym, to_p); 1407588ccd73SSam Ravnborg 14080d2a636eSUwe Kleine-König switch (mismatch->mismatch) { 1409bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_INIT: 141037ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 141137ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1412588ccd73SSam Ravnborg fprintf(stderr, 1413588ccd73SSam Ravnborg "The function %s%s() references\n" 1414588ccd73SSam Ravnborg "the %s %s%s%s.\n" 1415588ccd73SSam Ravnborg "This is often because %s lacks a %s\n" 1416588ccd73SSam Ravnborg "annotation or the annotation of %s is wrong.\n", 141737ed19d5SAlexey Fomenko prl_from, fromsym, 141837ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 141937ed19d5SAlexey Fomenko fromsym, prl_to, tosym); 142037ed19d5SAlexey Fomenko free(prl_from); 142137ed19d5SAlexey Fomenko free(prl_to); 1422588ccd73SSam Ravnborg break; 1423bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_INIT: { 142437ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1425588ccd73SSam Ravnborg fprintf(stderr, 1426588ccd73SSam Ravnborg "The variable %s references\n" 1427588ccd73SSam Ravnborg "the %s %s%s%s\n" 1428588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 14298b8b76c0SSam Ravnborg "variable with __init* or __refdata (see linux/init.h) " 1430588ccd73SSam Ravnborg "or name the variable:\n", 143137ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 143200759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 143337ed19d5SAlexey Fomenko free(prl_to); 1434588ccd73SSam Ravnborg break; 143558fb0d4fSSam Ravnborg } 1436bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_EXIT: 143737ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1438588ccd73SSam Ravnborg fprintf(stderr, 1439588ccd73SSam Ravnborg "The function %s() references a %s in an exit section.\n" 1440588ccd73SSam Ravnborg "Often the %s %s%s has valid usage outside the exit section\n" 1441588ccd73SSam Ravnborg "and the fix is to remove the %sannotation of %s.\n", 144237ed19d5SAlexey Fomenko fromsym, to, to, tosym, to_p, prl_to, tosym); 144337ed19d5SAlexey Fomenko free(prl_to); 1444588ccd73SSam Ravnborg break; 1445bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_EXIT: { 144637ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1447588ccd73SSam Ravnborg fprintf(stderr, 1448588ccd73SSam Ravnborg "The variable %s references\n" 1449588ccd73SSam Ravnborg "the %s %s%s%s\n" 1450588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 1451588ccd73SSam Ravnborg "variable with __exit* (see linux/init.h) or " 1452588ccd73SSam Ravnborg "name the variable:\n", 145337ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 145400759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 145537ed19d5SAlexey Fomenko free(prl_to); 1456588ccd73SSam Ravnborg break; 1457588ccd73SSam Ravnborg } 1458bbd3f4fbSUwe Kleine-König case XXXINIT_TO_SOME_INIT: 1459bbd3f4fbSUwe Kleine-König case XXXEXIT_TO_SOME_EXIT: 146037ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 146137ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1462588ccd73SSam Ravnborg fprintf(stderr, 1463588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1464588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1465588ccd73SSam Ravnborg "If %s is only used by %s then\n" 1466588ccd73SSam Ravnborg "annotate %s with a matching annotation.\n", 146737ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 146837ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 1469b1d2675aSGeert Uytterhoeven tosym, fromsym, tosym); 147037ed19d5SAlexey Fomenko free(prl_from); 147137ed19d5SAlexey Fomenko free(prl_to); 1472588ccd73SSam Ravnborg break; 1473bbd3f4fbSUwe Kleine-König case ANY_INIT_TO_ANY_EXIT: 147437ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 147537ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1476588ccd73SSam Ravnborg fprintf(stderr, 1477588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1478588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1479588ccd73SSam Ravnborg "This is often seen when error handling " 1480588ccd73SSam Ravnborg "in the init function\n" 1481588ccd73SSam Ravnborg "uses functionality in the exit path.\n" 1482588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1483588ccd73SSam Ravnborg "%s%s so it may be used outside an exit section.\n", 148437ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 148537ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 14865003bab8SAndrew Morton prl_to, tosym, to_p); 148737ed19d5SAlexey Fomenko free(prl_from); 148837ed19d5SAlexey Fomenko free(prl_to); 1489588ccd73SSam Ravnborg break; 1490bbd3f4fbSUwe Kleine-König case ANY_EXIT_TO_ANY_INIT: 149137ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 149237ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1493588ccd73SSam Ravnborg fprintf(stderr, 1494588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1495588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1496588ccd73SSam Ravnborg "This is often seen when error handling " 1497588ccd73SSam Ravnborg "in the exit function\n" 1498588ccd73SSam Ravnborg "uses functionality in the init path.\n" 1499588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1500588ccd73SSam Ravnborg "%s%s so it may be used outside an init section.\n", 150137ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 150237ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 150337ed19d5SAlexey Fomenko prl_to, tosym, to_p); 150437ed19d5SAlexey Fomenko free(prl_from); 150537ed19d5SAlexey Fomenko free(prl_to); 1506588ccd73SSam Ravnborg break; 1507588ccd73SSam Ravnborg case EXPORT_TO_INIT_EXIT: 150837ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1509588ccd73SSam Ravnborg fprintf(stderr, 1510588ccd73SSam Ravnborg "The symbol %s is exported and annotated %s\n" 1511588ccd73SSam Ravnborg "Fix this by removing the %sannotation of %s " 1512588ccd73SSam Ravnborg "or drop the export.\n", 151337ed19d5SAlexey Fomenko tosym, prl_to, prl_to, tosym); 151437ed19d5SAlexey Fomenko free(prl_to); 1515588ccd73SSam Ravnborg break; 151652dc0595SQuentin Casasnovas case EXTABLE_TO_NON_TEXT: 151752dc0595SQuentin Casasnovas fatal("There's a special handler for this mismatch type, " 151852dc0595SQuentin Casasnovas "we should never get here."); 151952dc0595SQuentin Casasnovas break; 1520588ccd73SSam Ravnborg } 1521588ccd73SSam Ravnborg fprintf(stderr, "\n"); 152258fb0d4fSSam Ravnborg } 152358fb0d4fSSam Ravnborg 1524644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf, 1525644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 152658fb0d4fSSam Ravnborg Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 152758fb0d4fSSam Ravnborg { 152858fb0d4fSSam Ravnborg const char *tosec; 1529588ccd73SSam Ravnborg Elf_Sym *to; 1530588ccd73SSam Ravnborg Elf_Sym *from; 153158fb0d4fSSam Ravnborg const char *tosym; 1532588ccd73SSam Ravnborg const char *fromsym; 153358fb0d4fSSam Ravnborg 1534588ccd73SSam Ravnborg from = find_elf_symbol2(elf, r->r_offset, fromsec); 1535588ccd73SSam Ravnborg fromsym = sym_name(elf, from); 153658fb0d4fSSam Ravnborg 1537d62c4765SMasahiro Yamada if (strstarts(fromsym, "reference___initcall")) 153877ab21adSAndi Kleen return; 153977ab21adSAndi Kleen 1540c7a65e06SQuentin Casasnovas tosec = sec_name(elf, get_secindex(elf, sym)); 1541c7a65e06SQuentin Casasnovas to = find_elf_symbol(elf, r->r_addend, sym); 1542c7a65e06SQuentin Casasnovas tosym = sym_name(elf, to); 1543c7a65e06SQuentin Casasnovas 154458fb0d4fSSam Ravnborg /* check whitelist - we may ignore it */ 1545af92a82dSUwe Kleine-König if (secref_whitelist(mismatch, 1546af92a82dSUwe Kleine-König fromsec, fromsym, tosec, tosym)) { 1547588ccd73SSam Ravnborg report_sec_mismatch(modname, mismatch, 1548588ccd73SSam Ravnborg fromsec, r->r_offset, fromsym, 1549588ccd73SSam Ravnborg is_function(from), tosec, tosym, 1550588ccd73SSam Ravnborg is_function(to)); 155158fb0d4fSSam Ravnborg } 1552b39927cfSSam Ravnborg } 1553644e8f14SQuentin Casasnovas 155452dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index) 155552dc0595SQuentin Casasnovas { 155652dc0595SQuentin Casasnovas if (section_index > elf->num_sections) 155752dc0595SQuentin Casasnovas fatal("section_index is outside elf->num_sections!\n"); 155852dc0595SQuentin Casasnovas 155952dc0595SQuentin Casasnovas return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); 156052dc0595SQuentin Casasnovas } 156152dc0595SQuentin Casasnovas 156252dc0595SQuentin Casasnovas /* 156352dc0595SQuentin Casasnovas * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size() 156452dc0595SQuentin Casasnovas * to know the sizeof(struct exception_table_entry) for the target architecture. 156552dc0595SQuentin Casasnovas */ 156652dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0; 1567e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r) 156852dc0595SQuentin Casasnovas { 156952dc0595SQuentin Casasnovas /* 157052dc0595SQuentin Casasnovas * If we're currently checking the second relocation within __ex_table, 157152dc0595SQuentin Casasnovas * that relocation offset tells us the offsetof(struct 157252dc0595SQuentin Casasnovas * exception_table_entry, fixup) which is equal to sizeof(struct 157352dc0595SQuentin Casasnovas * exception_table_entry) divided by two. We use that to our advantage 157452dc0595SQuentin Casasnovas * since there's no portable way to get that size as every architecture 157552dc0595SQuentin Casasnovas * seems to go with different sized types. Not pretty but better than 157652dc0595SQuentin Casasnovas * hard-coding the size for every architecture.. 157752dc0595SQuentin Casasnovas */ 1578e84048aaSQuentin Casasnovas if (!extable_entry_size) 157952dc0595SQuentin Casasnovas extable_entry_size = r->r_offset * 2; 158052dc0595SQuentin Casasnovas } 1581e84048aaSQuentin Casasnovas 158252dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r) 158352dc0595SQuentin Casasnovas { 1584d3df4de7SQuentin Casasnovas /* 1585d3df4de7SQuentin Casasnovas * extable_entry_size is only discovered after we've handled the 1586d3df4de7SQuentin Casasnovas * _second_ relocation in __ex_table, so only abort when we're not 1587d3df4de7SQuentin Casasnovas * handling the first reloc and extable_entry_size is zero. 1588d3df4de7SQuentin Casasnovas */ 1589d3df4de7SQuentin Casasnovas if (r->r_offset && extable_entry_size == 0) 159052dc0595SQuentin Casasnovas fatal("extable_entry size hasn't been discovered!\n"); 159152dc0595SQuentin Casasnovas 159252dc0595SQuentin Casasnovas return ((r->r_offset == 0) || 159352dc0595SQuentin Casasnovas (r->r_offset % extable_entry_size == 0)); 159452dc0595SQuentin Casasnovas } 159552dc0595SQuentin Casasnovas 1596e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec) \ 1597e84048aaSQuentin Casasnovas (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0)) 1598e84048aaSQuentin Casasnovas 159952dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf, 160052dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 160152dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 160252dc0595SQuentin Casasnovas const char* fromsec, const char* tosec) 160352dc0595SQuentin Casasnovas { 160452dc0595SQuentin Casasnovas Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec); 160552dc0595SQuentin Casasnovas const char* fromsym_name = sym_name(elf, fromsym); 160652dc0595SQuentin Casasnovas Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym); 160752dc0595SQuentin Casasnovas const char* tosym_name = sym_name(elf, tosym); 160852dc0595SQuentin Casasnovas const char* from_pretty_name; 160952dc0595SQuentin Casasnovas const char* from_pretty_name_p; 161052dc0595SQuentin Casasnovas const char* to_pretty_name; 161152dc0595SQuentin Casasnovas const char* to_pretty_name_p; 161252dc0595SQuentin Casasnovas 161352dc0595SQuentin Casasnovas get_pretty_name(is_function(fromsym), 161452dc0595SQuentin Casasnovas &from_pretty_name, &from_pretty_name_p); 161552dc0595SQuentin Casasnovas get_pretty_name(is_function(tosym), 161652dc0595SQuentin Casasnovas &to_pretty_name, &to_pretty_name_p); 161752dc0595SQuentin Casasnovas 161852dc0595SQuentin Casasnovas warn("%s(%s+0x%lx): Section mismatch in reference" 161952dc0595SQuentin Casasnovas " from the %s %s%s to the %s %s:%s%s\n", 162052dc0595SQuentin Casasnovas modname, fromsec, (long)r->r_offset, from_pretty_name, 162152dc0595SQuentin Casasnovas fromsym_name, from_pretty_name_p, 162252dc0595SQuentin Casasnovas to_pretty_name, tosec, tosym_name, to_pretty_name_p); 162352dc0595SQuentin Casasnovas 162452dc0595SQuentin Casasnovas if (!match(tosec, mismatch->bad_tosec) && 162552dc0595SQuentin Casasnovas is_executable_section(elf, get_secindex(elf, sym))) 162652dc0595SQuentin Casasnovas fprintf(stderr, 162752dc0595SQuentin Casasnovas "The relocation at %s+0x%lx references\n" 162852dc0595SQuentin Casasnovas "section \"%s\" which is not in the list of\n" 162952dc0595SQuentin Casasnovas "authorized sections. If you're adding a new section\n" 163052dc0595SQuentin Casasnovas "and/or if this reference is valid, add \"%s\" to the\n" 163152dc0595SQuentin Casasnovas "list of authorized sections to jump to on fault.\n" 163252dc0595SQuentin Casasnovas "This can be achieved by adding \"%s\" to \n" 163352dc0595SQuentin Casasnovas "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n", 163452dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, tosec, tosec); 163552dc0595SQuentin Casasnovas } 163652dc0595SQuentin Casasnovas 163752dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf, 163852dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 163952dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 164052dc0595SQuentin Casasnovas const char *fromsec) 164152dc0595SQuentin Casasnovas { 164252dc0595SQuentin Casasnovas const char* tosec = sec_name(elf, get_secindex(elf, sym)); 164352dc0595SQuentin Casasnovas 164452dc0595SQuentin Casasnovas sec_mismatch_count++; 164552dc0595SQuentin Casasnovas 164652dc0595SQuentin Casasnovas if (sec_mismatch_verbose) 164752dc0595SQuentin Casasnovas report_extable_warnings(modname, elf, mismatch, r, sym, 164852dc0595SQuentin Casasnovas fromsec, tosec); 164952dc0595SQuentin Casasnovas 165052dc0595SQuentin Casasnovas if (match(tosec, mismatch->bad_tosec)) 165152dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 165252dc0595SQuentin Casasnovas "section \"%s\" which is black-listed.\n" 165352dc0595SQuentin Casasnovas "Something is seriously wrong and should be fixed.\n" 165452dc0595SQuentin Casasnovas "You might get more information about where this is\n" 165552dc0595SQuentin Casasnovas "coming from by using scripts/check_extable.sh %s\n", 165652dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, modname); 165752dc0595SQuentin Casasnovas else if (!is_executable_section(elf, get_secindex(elf, sym))) { 165852dc0595SQuentin Casasnovas if (is_extable_fault_address(r)) 165952dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 166052dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 166152dc0595SQuentin Casasnovas "it is not possible for the kernel to fault\n" 166252dc0595SQuentin Casasnovas "at that address. Something is seriously wrong\n" 166352dc0595SQuentin Casasnovas "and should be fixed.\n", 166452dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 166552dc0595SQuentin Casasnovas else 166652dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 166752dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 166852dc0595SQuentin Casasnovas "the kernel will fault if it ever tries to\n" 166952dc0595SQuentin Casasnovas "jump to it. Something is seriously wrong\n" 167052dc0595SQuentin Casasnovas "and should be fixed.\n", 167152dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 167252dc0595SQuentin Casasnovas } 167352dc0595SQuentin Casasnovas } 167452dc0595SQuentin Casasnovas 1675644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf, 1676644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 1677644e8f14SQuentin Casasnovas { 16780cad61d7SLuis de Bethencourt const char *tosec = sec_name(elf, get_secindex(elf, sym)); 1679644e8f14SQuentin Casasnovas const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec); 1680644e8f14SQuentin Casasnovas 1681644e8f14SQuentin Casasnovas if (mismatch) { 1682644e8f14SQuentin Casasnovas if (mismatch->handler) 1683644e8f14SQuentin Casasnovas mismatch->handler(modname, elf, mismatch, 1684644e8f14SQuentin Casasnovas r, sym, fromsec); 1685644e8f14SQuentin Casasnovas else 1686644e8f14SQuentin Casasnovas default_mismatch_handler(modname, elf, mismatch, 1687644e8f14SQuentin Casasnovas r, sym, fromsec); 1688644e8f14SQuentin Casasnovas } 1689b39927cfSSam Ravnborg } 1690b39927cfSSam Ravnborg 1691ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf, 16925b24c071SSam Ravnborg Elf_Shdr *sechdr, Elf_Rela *r) 1693ae4ac123SAtsushi Nemoto { 1694ae4ac123SAtsushi Nemoto Elf_Shdr *sechdrs = elf->sechdrs; 16956845756bSAnders Kaseorg int section = sechdr->sh_info; 1696ae4ac123SAtsushi Nemoto 1697ae4ac123SAtsushi Nemoto return (void *)elf->hdr + sechdrs[section].sh_offset + 1698731ece41SOlof Johansson r->r_offset; 1699ae4ac123SAtsushi Nemoto } 1700ae4ac123SAtsushi Nemoto 17015b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1702ae4ac123SAtsushi Nemoto { 1703ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 17045b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1705ae4ac123SAtsushi Nemoto 1706ae4ac123SAtsushi Nemoto switch (r_typ) { 1707ae4ac123SAtsushi Nemoto case R_386_32: 1708ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location); 1709ae4ac123SAtsushi Nemoto break; 1710ae4ac123SAtsushi Nemoto case R_386_PC32: 1711ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location) + 4; 1712ae4ac123SAtsushi Nemoto /* For CONFIG_RELOCATABLE=y */ 1713ae4ac123SAtsushi Nemoto if (elf->hdr->e_type == ET_EXEC) 1714ae4ac123SAtsushi Nemoto r->r_addend += r->r_offset; 1715ae4ac123SAtsushi Nemoto break; 1716ae4ac123SAtsushi Nemoto } 1717ae4ac123SAtsushi Nemoto return 0; 1718ae4ac123SAtsushi Nemoto } 1719ae4ac123SAtsushi Nemoto 17206e2e340bSTony Lindgren #ifndef R_ARM_CALL 17216e2e340bSTony Lindgren #define R_ARM_CALL 28 17226e2e340bSTony Lindgren #endif 17236e2e340bSTony Lindgren #ifndef R_ARM_JUMP24 17246e2e340bSTony Lindgren #define R_ARM_JUMP24 29 17256e2e340bSTony Lindgren #endif 17266e2e340bSTony Lindgren 1727c9698e5cSDavid A. Long #ifndef R_ARM_THM_CALL 1728c9698e5cSDavid A. Long #define R_ARM_THM_CALL 10 1729c9698e5cSDavid A. Long #endif 1730c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP24 1731c9698e5cSDavid A. Long #define R_ARM_THM_JUMP24 30 1732c9698e5cSDavid A. Long #endif 1733c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP19 1734c9698e5cSDavid A. Long #define R_ARM_THM_JUMP19 51 1735c9698e5cSDavid A. Long #endif 1736c9698e5cSDavid A. Long 17375b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 173856a974faSSam Ravnborg { 173956a974faSSam Ravnborg unsigned int r_typ = ELF_R_TYPE(r->r_info); 174056a974faSSam Ravnborg 174156a974faSSam Ravnborg switch (r_typ) { 174256a974faSSam Ravnborg case R_ARM_ABS32: 174356a974faSSam Ravnborg /* From ARM ABI: (S + A) | T */ 1744df578e7dSSam Ravnborg r->r_addend = (int)(long) 1745df578e7dSSam Ravnborg (elf->symtab_start + ELF_R_SYM(r->r_info)); 174656a974faSSam Ravnborg break; 174756a974faSSam Ravnborg case R_ARM_PC24: 17486e2e340bSTony Lindgren case R_ARM_CALL: 17496e2e340bSTony Lindgren case R_ARM_JUMP24: 1750c9698e5cSDavid A. Long case R_ARM_THM_CALL: 1751c9698e5cSDavid A. Long case R_ARM_THM_JUMP24: 1752c9698e5cSDavid A. Long case R_ARM_THM_JUMP19: 175356a974faSSam Ravnborg /* From ARM ABI: ((S + A) | T) - P */ 1754df578e7dSSam Ravnborg r->r_addend = (int)(long)(elf->hdr + 17555b24c071SSam Ravnborg sechdr->sh_offset + 17565b24c071SSam Ravnborg (r->r_offset - sechdr->sh_addr)); 175756a974faSSam Ravnborg break; 175856a974faSSam Ravnborg default: 175956a974faSSam Ravnborg return 1; 176056a974faSSam Ravnborg } 176156a974faSSam Ravnborg return 0; 176256a974faSSam Ravnborg } 176356a974faSSam Ravnborg 17645b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1765ae4ac123SAtsushi Nemoto { 1766ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 17675b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1768ae4ac123SAtsushi Nemoto unsigned int inst; 1769ae4ac123SAtsushi Nemoto 1770ae4ac123SAtsushi Nemoto if (r_typ == R_MIPS_HI16) 1771ae4ac123SAtsushi Nemoto return 1; /* skip this */ 1772ae4ac123SAtsushi Nemoto inst = TO_NATIVE(*location); 1773ae4ac123SAtsushi Nemoto switch (r_typ) { 1774ae4ac123SAtsushi Nemoto case R_MIPS_LO16: 1775ae4ac123SAtsushi Nemoto r->r_addend = inst & 0xffff; 1776ae4ac123SAtsushi Nemoto break; 1777ae4ac123SAtsushi Nemoto case R_MIPS_26: 1778ae4ac123SAtsushi Nemoto r->r_addend = (inst & 0x03ffffff) << 2; 1779ae4ac123SAtsushi Nemoto break; 1780ae4ac123SAtsushi Nemoto case R_MIPS_32: 1781ae4ac123SAtsushi Nemoto r->r_addend = inst; 1782ae4ac123SAtsushi Nemoto break; 1783ae4ac123SAtsushi Nemoto } 1784ae4ac123SAtsushi Nemoto return 0; 1785ae4ac123SAtsushi Nemoto } 1786ae4ac123SAtsushi Nemoto 17875b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf, 178810668220SSam Ravnborg Elf_Shdr *sechdr) 1789b39927cfSSam Ravnborg { 1790b39927cfSSam Ravnborg Elf_Sym *sym; 17915b24c071SSam Ravnborg Elf_Rela *rela; 17922c1a51f3SAtsushi Nemoto Elf_Rela r; 1793eae07ac6SAtsushi Nemoto unsigned int r_sym; 17945b24c071SSam Ravnborg const char *fromsec; 17955b24c071SSam Ravnborg 1796ff13f926SSam Ravnborg Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; 17975b24c071SSam Ravnborg Elf_Rela *stop = (void *)start + sechdr->sh_size; 17985b24c071SSam Ravnborg 1799ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 18005b24c071SSam Ravnborg fromsec += strlen(".rela"); 18015b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1802b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 18035b24c071SSam Ravnborg return; 1804e241a630SSam Ravnborg 1805b39927cfSSam Ravnborg for (rela = start; rela < stop; rela++) { 1806b39927cfSSam Ravnborg r.r_offset = TO_NATIVE(rela->r_offset); 1807eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1808ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1809ae4ac123SAtsushi Nemoto unsigned int r_typ; 1810eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rela->r_info); 1811eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1812ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rela->r_info); 1813ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1814eae07ac6SAtsushi Nemoto } else { 1815601e7f02SLinus Torvalds r.r_info = TO_NATIVE(rela->r_info); 1816eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1817eae07ac6SAtsushi Nemoto } 1818eae07ac6SAtsushi Nemoto #else 1819eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rela->r_info); 1820eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1821eae07ac6SAtsushi Nemoto #endif 182293684d3bSSam Ravnborg r.r_addend = TO_NATIVE(rela->r_addend); 1823eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 1824b39927cfSSam Ravnborg /* Skip special sections */ 18251ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1826b39927cfSSam Ravnborg continue; 1827e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rela, fromsec)) 1828e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 182958fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 18302c1a51f3SAtsushi Nemoto } 18315b24c071SSam Ravnborg } 18325b24c071SSam Ravnborg 18335b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf, 183410668220SSam Ravnborg Elf_Shdr *sechdr) 18355b24c071SSam Ravnborg { 18365b24c071SSam Ravnborg Elf_Sym *sym; 18372c1a51f3SAtsushi Nemoto Elf_Rel *rel; 18385b24c071SSam Ravnborg Elf_Rela r; 18395b24c071SSam Ravnborg unsigned int r_sym; 18405b24c071SSam Ravnborg const char *fromsec; 18415b24c071SSam Ravnborg 1842ff13f926SSam Ravnborg Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; 18435b24c071SSam Ravnborg Elf_Rel *stop = (void *)start + sechdr->sh_size; 18445b24c071SSam Ravnborg 1845ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 18465b24c071SSam Ravnborg fromsec += strlen(".rel"); 18475b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1848b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 18495b24c071SSam Ravnborg return; 18502c1a51f3SAtsushi Nemoto 18512c1a51f3SAtsushi Nemoto for (rel = start; rel < stop; rel++) { 18522c1a51f3SAtsushi Nemoto r.r_offset = TO_NATIVE(rel->r_offset); 1853eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1854ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1855ae4ac123SAtsushi Nemoto unsigned int r_typ; 1856eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rel->r_info); 1857eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1858ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rel->r_info); 1859ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1860eae07ac6SAtsushi Nemoto } else { 18612c1a51f3SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1862eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1863eae07ac6SAtsushi Nemoto } 1864eae07ac6SAtsushi Nemoto #else 1865eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1866eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1867eae07ac6SAtsushi Nemoto #endif 18682c1a51f3SAtsushi Nemoto r.r_addend = 0; 1869ff13f926SSam Ravnborg switch (elf->hdr->e_machine) { 1870ae4ac123SAtsushi Nemoto case EM_386: 18715b24c071SSam Ravnborg if (addend_386_rel(elf, sechdr, &r)) 1872ae4ac123SAtsushi Nemoto continue; 1873ae4ac123SAtsushi Nemoto break; 187456a974faSSam Ravnborg case EM_ARM: 18755b24c071SSam Ravnborg if (addend_arm_rel(elf, sechdr, &r)) 187656a974faSSam Ravnborg continue; 187756a974faSSam Ravnborg break; 1878ae4ac123SAtsushi Nemoto case EM_MIPS: 18795b24c071SSam Ravnborg if (addend_mips_rel(elf, sechdr, &r)) 1880ae4ac123SAtsushi Nemoto continue; 1881ae4ac123SAtsushi Nemoto break; 1882ae4ac123SAtsushi Nemoto } 1883eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 18842c1a51f3SAtsushi Nemoto /* Skip special sections */ 18851ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 18862c1a51f3SAtsushi Nemoto continue; 1887e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rel, fromsec)) 1888e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 188958fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 18902c1a51f3SAtsushi Nemoto } 1891b39927cfSSam Ravnborg } 18925b24c071SSam Ravnborg 18935b24c071SSam Ravnborg /** 18945b24c071SSam Ravnborg * A module includes a number of sections that are discarded 18955b24c071SSam Ravnborg * either when loaded or when used as built-in. 18965b24c071SSam Ravnborg * For loaded modules all functions marked __init and all data 1897b595076aSUwe Kleine-König * marked __initdata will be discarded when the module has been initialized. 18985b24c071SSam Ravnborg * Likewise for modules used built-in the sections marked __exit 18995b24c071SSam Ravnborg * are discarded because __exit marked function are supposed to be called 190032be1d22SBen Dooks * only when a module is unloaded which never happens for built-in modules. 19015b24c071SSam Ravnborg * The check_sec_ref() function traverses all relocation records 19025b24c071SSam Ravnborg * to find all references to a section that reference a section that will 19035b24c071SSam Ravnborg * be discarded and warns about it. 19045b24c071SSam Ravnborg **/ 19055b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname, 190610668220SSam Ravnborg struct elf_info *elf) 19075b24c071SSam Ravnborg { 19085b24c071SSam Ravnborg int i; 19095b24c071SSam Ravnborg Elf_Shdr *sechdrs = elf->sechdrs; 19105b24c071SSam Ravnborg 19115b24c071SSam Ravnborg /* Walk through all sections */ 19121ce53adfSDenys Vlasenko for (i = 0; i < elf->num_sections; i++) { 1913b614a697SAnders Kaseorg check_section(modname, elf, &elf->sechdrs[i]); 19145b24c071SSam Ravnborg /* We want to process only relocation sections and not .init */ 19155b24c071SSam Ravnborg if (sechdrs[i].sh_type == SHT_RELA) 191610668220SSam Ravnborg section_rela(modname, elf, &elf->sechdrs[i]); 19175b24c071SSam Ravnborg else if (sechdrs[i].sh_type == SHT_REL) 191810668220SSam Ravnborg section_rel(modname, elf, &elf->sechdrs[i]); 1919b39927cfSSam Ravnborg } 1920b39927cfSSam Ravnborg } 1921b39927cfSSam Ravnborg 19227d02b490SAndi Kleen static char *remove_dot(char *s) 19237d02b490SAndi Kleen { 1924fcd38ed0SMichal Nazarewicz size_t n = strcspn(s, "."); 19257d02b490SAndi Kleen 1926fcd38ed0SMichal Nazarewicz if (n && s[n]) { 1927fcd38ed0SMichal Nazarewicz size_t m = strspn(s + n + 1, "0123456789"); 1928fcd38ed0SMichal Nazarewicz if (m && (s[n + m] == '.' || s[n + m] == 0)) 19297d02b490SAndi Kleen s[n] = 0; 19307d02b490SAndi Kleen } 19317d02b490SAndi Kleen return s; 19327d02b490SAndi Kleen } 19337d02b490SAndi Kleen 19348b185743SMasahiro Yamada static void read_symbols(const char *modname) 19351da177e4SLinus Torvalds { 19361da177e4SLinus Torvalds const char *symname; 19371da177e4SLinus Torvalds char *version; 1938b817f6feSSam Ravnborg char *license; 19391da177e4SLinus Torvalds struct module *mod; 19401da177e4SLinus Torvalds struct elf_info info = { }; 19411da177e4SLinus Torvalds Elf_Sym *sym; 19421da177e4SLinus Torvalds 194385bd2fddSSam Ravnborg if (!parse_elf(&info, modname)) 194485bd2fddSSam Ravnborg return; 19451da177e4SLinus Torvalds 19461da177e4SLinus Torvalds mod = new_module(modname); 19471da177e4SLinus Torvalds 19481da177e4SLinus Torvalds /* When there's no vmlinux, don't print warnings about 19491da177e4SLinus Torvalds * unresolved symbols (since there'll be too many ;) */ 19501da177e4SLinus Torvalds if (is_vmlinux(modname)) { 19511da177e4SLinus Torvalds have_vmlinux = 1; 19521da177e4SLinus Torvalds mod->skip = 1; 19531da177e4SLinus Torvalds } 19541da177e4SLinus Torvalds 1955bca2cceeSMasahiro Yamada license = get_modinfo(&info, "license"); 1956ba1029c9SRandy Dunlap if (!license && !is_vmlinux(modname)) 19572fa36568SSam Ravnborg warn("modpost: missing MODULE_LICENSE() in %s\n" 1958eed7d279SSam Ravnborg "see include/linux/module.h for " 1959eed7d279SSam Ravnborg "more information\n", modname); 1960b817f6feSSam Ravnborg while (license) { 1961b817f6feSSam Ravnborg if (license_is_gpl_compatible(license)) 1962b817f6feSSam Ravnborg mod->gpl_compatible = 1; 1963b817f6feSSam Ravnborg else { 1964b817f6feSSam Ravnborg mod->gpl_compatible = 0; 1965b817f6feSSam Ravnborg break; 1966b817f6feSSam Ravnborg } 1967bca2cceeSMasahiro Yamada license = get_next_modinfo(&info, "license", license); 1968b817f6feSSam Ravnborg } 1969b817f6feSSam Ravnborg 19701da177e4SLinus Torvalds for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { 19717d02b490SAndi Kleen symname = remove_dot(info.strtab + sym->st_name); 19721da177e4SLinus Torvalds 19731da177e4SLinus Torvalds handle_modversions(mod, &info, sym, symname); 19741da177e4SLinus Torvalds handle_moddevtable(mod, &info, sym, symname); 19751da177e4SLinus Torvalds } 1976074a04f5SMasahiro Yamada if (!is_vmlinux(modname) || vmlinux_section_warnings) 197710668220SSam Ravnborg check_sec_ref(mod, modname, &info); 19781da177e4SLinus Torvalds 1979bca2cceeSMasahiro Yamada version = get_modinfo(&info, "version"); 19801da177e4SLinus Torvalds if (version) 19811da177e4SLinus Torvalds maybe_frob_rcs_version(modname, version, info.modinfo, 19821da177e4SLinus Torvalds version - (char *)info.hdr); 19831da177e4SLinus Torvalds if (version || (all_versions && !is_vmlinux(modname))) 19841da177e4SLinus Torvalds get_src_version(modname, mod->srcversion, 19851da177e4SLinus Torvalds sizeof(mod->srcversion)-1); 19861da177e4SLinus Torvalds 19871da177e4SLinus Torvalds parse_elf_finish(&info); 19881da177e4SLinus Torvalds 19898c8ef42aSRusty Russell /* Our trick to get versioning for module struct etc. - it's 19901da177e4SLinus Torvalds * never passed as an argument to an exported function, so 19911da177e4SLinus Torvalds * the automatic versioning doesn't pick it up, but it's really 19921da177e4SLinus Torvalds * important anyhow */ 19931da177e4SLinus Torvalds if (modversions) 19948c8ef42aSRusty Russell mod->unres = alloc_symbol("module_layout", 0, mod->unres); 19951da177e4SLinus Torvalds } 19961da177e4SLinus Torvalds 1997712f9b46SRusty Russell static void read_symbols_from_files(const char *filename) 1998712f9b46SRusty Russell { 1999712f9b46SRusty Russell FILE *in = stdin; 2000712f9b46SRusty Russell char fname[PATH_MAX]; 2001712f9b46SRusty Russell 2002712f9b46SRusty Russell if (strcmp(filename, "-") != 0) { 2003712f9b46SRusty Russell in = fopen(filename, "r"); 2004712f9b46SRusty Russell if (!in) 2005712f9b46SRusty Russell fatal("Can't open filenames file %s: %m", filename); 2006712f9b46SRusty Russell } 2007712f9b46SRusty Russell 2008712f9b46SRusty Russell while (fgets(fname, PATH_MAX, in) != NULL) { 2009712f9b46SRusty Russell if (strends(fname, "\n")) 2010712f9b46SRusty Russell fname[strlen(fname)-1] = '\0'; 2011712f9b46SRusty Russell read_symbols(fname); 2012712f9b46SRusty Russell } 2013712f9b46SRusty Russell 2014712f9b46SRusty Russell if (in != stdin) 2015712f9b46SRusty Russell fclose(in); 2016712f9b46SRusty Russell } 2017712f9b46SRusty Russell 20181da177e4SLinus Torvalds #define SZ 500 20191da177e4SLinus Torvalds 20201da177e4SLinus Torvalds /* We first write the generated file into memory using the 20211da177e4SLinus Torvalds * following helper, then compare to the file on disk and 20221da177e4SLinus Torvalds * only update the later if anything changed */ 20231da177e4SLinus Torvalds 20245c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, 20255c3ead8cSSam Ravnborg const char *fmt, ...) 20261da177e4SLinus Torvalds { 20271da177e4SLinus Torvalds char tmp[SZ]; 20281da177e4SLinus Torvalds int len; 20291da177e4SLinus Torvalds va_list ap; 20301da177e4SLinus Torvalds 20311da177e4SLinus Torvalds va_start(ap, fmt); 20321da177e4SLinus Torvalds len = vsnprintf(tmp, SZ, fmt, ap); 20337670f023SSam Ravnborg buf_write(buf, tmp, len); 20341da177e4SLinus Torvalds va_end(ap); 20351da177e4SLinus Torvalds } 20361da177e4SLinus Torvalds 20375c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len) 20381da177e4SLinus Torvalds { 20391da177e4SLinus Torvalds if (buf->size - buf->pos < len) { 20407670f023SSam Ravnborg buf->size += len + SZ; 20411f3aa900SRandy Dunlap buf->p = NOFAIL(realloc(buf->p, buf->size)); 20421da177e4SLinus Torvalds } 20431da177e4SLinus Torvalds strncpy(buf->p + buf->pos, s, len); 20441da177e4SLinus Torvalds buf->pos += len; 20451da177e4SLinus Torvalds } 20461da177e4SLinus Torvalds 2047c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s) 2048c96fca21SSam Ravnborg { 2049c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2050c96fca21SSam Ravnborg 2051c96fca21SSam Ravnborg switch (exp) { 2052c96fca21SSam Ravnborg case export_gpl: 2053c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2054c96fca21SSam Ravnborg "uses GPL-only symbol '%s'\n", m, e, s); 2055c96fca21SSam Ravnborg break; 2056c96fca21SSam Ravnborg case export_unused_gpl: 2057c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2058c96fca21SSam Ravnborg "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); 2059c96fca21SSam Ravnborg break; 2060c96fca21SSam Ravnborg case export_gpl_future: 2061c96fca21SSam Ravnborg warn("modpost: GPL-incompatible module %s%s " 2062c96fca21SSam Ravnborg "uses future GPL-only symbol '%s'\n", m, e, s); 2063c96fca21SSam Ravnborg break; 2064c96fca21SSam Ravnborg case export_plain: 2065c96fca21SSam Ravnborg case export_unused: 2066c96fca21SSam Ravnborg case export_unknown: 2067c96fca21SSam Ravnborg /* ignore */ 2068c96fca21SSam Ravnborg break; 2069c96fca21SSam Ravnborg } 2070c96fca21SSam Ravnborg } 2071c96fca21SSam Ravnborg 2072c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s) 2073c96fca21SSam Ravnborg { 2074c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2075c96fca21SSam Ravnborg 2076c96fca21SSam Ravnborg switch (exp) { 2077c96fca21SSam Ravnborg case export_unused: 2078c96fca21SSam Ravnborg case export_unused_gpl: 2079c96fca21SSam Ravnborg warn("modpost: module %s%s " 2080c96fca21SSam Ravnborg "uses symbol '%s' marked UNUSED\n", m, e, s); 2081c96fca21SSam Ravnborg break; 2082c96fca21SSam Ravnborg default: 2083c96fca21SSam Ravnborg /* ignore */ 2084c96fca21SSam Ravnborg break; 2085c96fca21SSam Ravnborg } 2086c96fca21SSam Ravnborg } 2087c96fca21SSam Ravnborg 2088c96fca21SSam Ravnborg static void check_exports(struct module *mod) 2089b817f6feSSam Ravnborg { 2090b817f6feSSam Ravnborg struct symbol *s, *exp; 2091b817f6feSSam Ravnborg 2092b817f6feSSam Ravnborg for (s = mod->unres; s; s = s->next) { 20936449bd62SAndrew Morton const char *basename; 2094b817f6feSSam Ravnborg exp = find_symbol(s->name); 2095b817f6feSSam Ravnborg if (!exp || exp->module == mod) 2096b817f6feSSam Ravnborg continue; 20976449bd62SAndrew Morton basename = strrchr(mod->name, '/'); 2098b817f6feSSam Ravnborg if (basename) 2099b817f6feSSam Ravnborg basename++; 2100c96fca21SSam Ravnborg else 2101c96fca21SSam Ravnborg basename = mod->name; 2102c96fca21SSam Ravnborg if (!mod->gpl_compatible) 2103c96fca21SSam Ravnborg check_for_gpl_usage(exp->export, basename, exp->name); 2104c96fca21SSam Ravnborg check_for_unused(exp->export, basename, exp->name); 2105b817f6feSSam Ravnborg } 2106b817f6feSSam Ravnborg } 2107b817f6feSSam Ravnborg 21084fd3e4efSWanlong Gao static int check_modname_len(struct module *mod) 21094fd3e4efSWanlong Gao { 21104fd3e4efSWanlong Gao const char *mod_name; 21114fd3e4efSWanlong Gao 21124fd3e4efSWanlong Gao mod_name = strrchr(mod->name, '/'); 21134fd3e4efSWanlong Gao if (mod_name == NULL) 21144fd3e4efSWanlong Gao mod_name = mod->name; 21154fd3e4efSWanlong Gao else 21164fd3e4efSWanlong Gao mod_name++; 21174fd3e4efSWanlong Gao if (strlen(mod_name) >= MODULE_NAME_LEN) { 21184fd3e4efSWanlong Gao merror("module name is too long [%s.ko]\n", mod->name); 21194fd3e4efSWanlong Gao return 1; 21204fd3e4efSWanlong Gao } 21214fd3e4efSWanlong Gao 21224fd3e4efSWanlong Gao return 0; 21234fd3e4efSWanlong Gao } 21244fd3e4efSWanlong Gao 21255c3ead8cSSam Ravnborg /** 21265c3ead8cSSam Ravnborg * Header for the generated file 21275c3ead8cSSam Ravnborg **/ 21285c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod) 21291da177e4SLinus Torvalds { 21309afb719eSLaura Abbott buf_printf(b, "#include <linux/build-salt.h>\n"); 21311da177e4SLinus Torvalds buf_printf(b, "#include <linux/module.h>\n"); 21321da177e4SLinus Torvalds buf_printf(b, "#include <linux/vermagic.h>\n"); 21331da177e4SLinus Torvalds buf_printf(b, "#include <linux/compiler.h>\n"); 21341da177e4SLinus Torvalds buf_printf(b, "\n"); 21359afb719eSLaura Abbott buf_printf(b, "BUILD_SALT;\n"); 21369afb719eSLaura Abbott buf_printf(b, "\n"); 21371da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); 21383e2e857fSKees Cook buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); 21391da177e4SLinus Torvalds buf_printf(b, "\n"); 2140e0f244c6SAndi Kleen buf_printf(b, "__visible struct module __this_module\n"); 21411da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); 21423c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); 21431da177e4SLinus Torvalds if (mod->has_init) 21443c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.init = init_module,\n"); 21451da177e4SLinus Torvalds if (mod->has_cleanup) 21461da177e4SLinus Torvalds buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" 21473c7ec94dSGreg Kroah-Hartman "\t.exit = cleanup_module,\n" 21481da177e4SLinus Torvalds "#endif\n"); 21493c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); 21501da177e4SLinus Torvalds buf_printf(b, "};\n"); 21511da177e4SLinus Torvalds } 21521da177e4SLinus Torvalds 21532449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree) 21542449b8baSBen Hutchings { 21552449b8baSBen Hutchings if (is_intree) 21562449b8baSBen Hutchings buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); 21572449b8baSBen Hutchings } 21582449b8baSBen Hutchings 2159caf7501aSAndi Kleen /* Cannot check for assembler */ 2160caf7501aSAndi Kleen static void add_retpoline(struct buffer *b) 2161caf7501aSAndi Kleen { 2162caf7501aSAndi Kleen buf_printf(b, "\n#ifdef RETPOLINE\n"); 2163caf7501aSAndi Kleen buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n"); 2164caf7501aSAndi Kleen buf_printf(b, "#endif\n"); 2165caf7501aSAndi Kleen } 2166caf7501aSAndi Kleen 21675c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name) 2168a9860bf0SGreg Kroah-Hartman { 2169d62c4765SMasahiro Yamada if (strstarts(name, "drivers/staging")) 2170a9860bf0SGreg Kroah-Hartman buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); 2171a9860bf0SGreg Kroah-Hartman } 2172a9860bf0SGreg Kroah-Hartman 21735c3ead8cSSam Ravnborg /** 21745c3ead8cSSam Ravnborg * Record CRCs for unresolved symbols 21755c3ead8cSSam Ravnborg **/ 2176c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod) 21771da177e4SLinus Torvalds { 21781da177e4SLinus Torvalds struct symbol *s, *exp; 2179c53ddacdSKirill Korotaev int err = 0; 21801da177e4SLinus Torvalds 21811da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 21821da177e4SLinus Torvalds exp = find_symbol(s->name); 21831da177e4SLinus Torvalds if (!exp || exp->module == mod) { 2184c53ddacdSKirill Korotaev if (have_vmlinux && !s->weak) { 21852a116659SMatthew Wilcox if (warn_unresolved) { 2186cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] undefined!\n", 2187cb80514dSSam Ravnborg s->name, mod->name); 21882a116659SMatthew Wilcox } else { 21892a116659SMatthew Wilcox merror("\"%s\" [%s.ko] undefined!\n", 21902a116659SMatthew Wilcox s->name, mod->name); 21912a116659SMatthew Wilcox err = 1; 21922a116659SMatthew Wilcox } 2193c53ddacdSKirill Korotaev } 21941da177e4SLinus Torvalds continue; 21951da177e4SLinus Torvalds } 21961da177e4SLinus Torvalds s->module = exp->module; 21971da177e4SLinus Torvalds s->crc_valid = exp->crc_valid; 21981da177e4SLinus Torvalds s->crc = exp->crc; 21991da177e4SLinus Torvalds } 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds if (!modversions) 2202c53ddacdSKirill Korotaev return err; 22031da177e4SLinus Torvalds 22041da177e4SLinus Torvalds buf_printf(b, "\n"); 22051da177e4SLinus Torvalds buf_printf(b, "static const struct modversion_info ____versions[]\n"); 22063ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 22071da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); 22081da177e4SLinus Torvalds 22091da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2210df578e7dSSam Ravnborg if (!s->module) 22111da177e4SLinus Torvalds continue; 22121da177e4SLinus Torvalds if (!s->crc_valid) { 2213cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] has no CRC!\n", 22141da177e4SLinus Torvalds s->name, mod->name); 22151da177e4SLinus Torvalds continue; 22161da177e4SLinus Torvalds } 22175cfb203aSTakashi Iwai if (strlen(s->name) >= MODULE_NAME_LEN) { 22185cfb203aSTakashi Iwai merror("too long symbol \"%s\" [%s.ko]\n", 22195cfb203aSTakashi Iwai s->name, mod->name); 22205cfb203aSTakashi Iwai err = 1; 22215cfb203aSTakashi Iwai break; 22225cfb203aSTakashi Iwai } 2223b2c5cdcfSMasahiro Yamada buf_printf(b, "\t{ %#8x, \"%s\" },\n", 2224a4b6a77bSJames Hogan s->crc, s->name); 22251da177e4SLinus Torvalds } 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds buf_printf(b, "};\n"); 2228c53ddacdSKirill Korotaev 2229c53ddacdSKirill Korotaev return err; 22301da177e4SLinus Torvalds } 22311da177e4SLinus Torvalds 22325c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod, 22335c3ead8cSSam Ravnborg struct module *modules) 22341da177e4SLinus Torvalds { 22351da177e4SLinus Torvalds struct symbol *s; 22361da177e4SLinus Torvalds struct module *m; 22371da177e4SLinus Torvalds int first = 1; 22381da177e4SLinus Torvalds 2239df578e7dSSam Ravnborg for (m = modules; m; m = m->next) 22401da177e4SLinus Torvalds m->seen = is_vmlinux(m->name); 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds buf_printf(b, "\n"); 22431da177e4SLinus Torvalds buf_printf(b, "static const char __module_depends[]\n"); 22443ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 22451da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); 22461da177e4SLinus Torvalds buf_printf(b, "\"depends="); 22471da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2248a61b2dfdSSam Ravnborg const char *p; 22491da177e4SLinus Torvalds if (!s->module) 22501da177e4SLinus Torvalds continue; 22511da177e4SLinus Torvalds 22521da177e4SLinus Torvalds if (s->module->seen) 22531da177e4SLinus Torvalds continue; 22541da177e4SLinus Torvalds 22551da177e4SLinus Torvalds s->module->seen = 1; 2256df578e7dSSam Ravnborg p = strrchr(s->module->name, '/'); 2257df578e7dSSam Ravnborg if (p) 2258a61b2dfdSSam Ravnborg p++; 2259a61b2dfdSSam Ravnborg else 2260a61b2dfdSSam Ravnborg p = s->module->name; 2261a61b2dfdSSam Ravnborg buf_printf(b, "%s%s", first ? "" : ",", p); 22621da177e4SLinus Torvalds first = 0; 22631da177e4SLinus Torvalds } 22641da177e4SLinus Torvalds buf_printf(b, "\";\n"); 22651da177e4SLinus Torvalds } 22661da177e4SLinus Torvalds 22675c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod) 22681da177e4SLinus Torvalds { 22691da177e4SLinus Torvalds if (mod->srcversion[0]) { 22701da177e4SLinus Torvalds buf_printf(b, "\n"); 22711da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", 22721da177e4SLinus Torvalds mod->srcversion); 22731da177e4SLinus Torvalds } 22741da177e4SLinus Torvalds } 22751da177e4SLinus Torvalds 22765c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname) 22771da177e4SLinus Torvalds { 22781da177e4SLinus Torvalds char *tmp; 22791da177e4SLinus Torvalds FILE *file; 22801da177e4SLinus Torvalds struct stat st; 22811da177e4SLinus Torvalds 22821da177e4SLinus Torvalds file = fopen(fname, "r"); 22831da177e4SLinus Torvalds if (!file) 22841da177e4SLinus Torvalds goto write; 22851da177e4SLinus Torvalds 22861da177e4SLinus Torvalds if (fstat(fileno(file), &st) < 0) 22871da177e4SLinus Torvalds goto close_write; 22881da177e4SLinus Torvalds 22891da177e4SLinus Torvalds if (st.st_size != b->pos) 22901da177e4SLinus Torvalds goto close_write; 22911da177e4SLinus Torvalds 22921da177e4SLinus Torvalds tmp = NOFAIL(malloc(b->pos)); 22931da177e4SLinus Torvalds if (fread(tmp, 1, b->pos, file) != b->pos) 22941da177e4SLinus Torvalds goto free_write; 22951da177e4SLinus Torvalds 22961da177e4SLinus Torvalds if (memcmp(tmp, b->p, b->pos) != 0) 22971da177e4SLinus Torvalds goto free_write; 22981da177e4SLinus Torvalds 22991da177e4SLinus Torvalds free(tmp); 23001da177e4SLinus Torvalds fclose(file); 23011da177e4SLinus Torvalds return; 23021da177e4SLinus Torvalds 23031da177e4SLinus Torvalds free_write: 23041da177e4SLinus Torvalds free(tmp); 23051da177e4SLinus Torvalds close_write: 23061da177e4SLinus Torvalds fclose(file); 23071da177e4SLinus Torvalds write: 23081da177e4SLinus Torvalds file = fopen(fname, "w"); 23091da177e4SLinus Torvalds if (!file) { 23101da177e4SLinus Torvalds perror(fname); 23111da177e4SLinus Torvalds exit(1); 23121da177e4SLinus Torvalds } 23131da177e4SLinus Torvalds if (fwrite(b->p, 1, b->pos, file) != b->pos) { 23141da177e4SLinus Torvalds perror(fname); 23151da177e4SLinus Torvalds exit(1); 23161da177e4SLinus Torvalds } 23171da177e4SLinus Torvalds fclose(file); 23181da177e4SLinus Torvalds } 23191da177e4SLinus Torvalds 2320bd5cbcedSRam Pai /* parse Module.symvers file. line format: 2321534b89a9SSam Ravnborg * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] 2322bd5cbcedSRam Pai **/ 2323040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel) 23241da177e4SLinus Torvalds { 23251da177e4SLinus Torvalds unsigned long size, pos = 0; 23261da177e4SLinus Torvalds void *file = grab_file(fname, &size); 23271da177e4SLinus Torvalds char *line; 23281da177e4SLinus Torvalds 23291da177e4SLinus Torvalds if (!file) 23301da177e4SLinus Torvalds /* No symbol versions, silently ignore */ 23311da177e4SLinus Torvalds return; 23321da177e4SLinus Torvalds 23331da177e4SLinus Torvalds while ((line = get_next_line(&pos, file, size))) { 2334534b89a9SSam Ravnborg char *symname, *modname, *d, *export, *end; 23351da177e4SLinus Torvalds unsigned int crc; 23361da177e4SLinus Torvalds struct module *mod; 2337040fcc81SSam Ravnborg struct symbol *s; 23381da177e4SLinus Torvalds 23391da177e4SLinus Torvalds if (!(symname = strchr(line, '\t'))) 23401da177e4SLinus Torvalds goto fail; 23411da177e4SLinus Torvalds *symname++ = '\0'; 23421da177e4SLinus Torvalds if (!(modname = strchr(symname, '\t'))) 23431da177e4SLinus Torvalds goto fail; 23441da177e4SLinus Torvalds *modname++ = '\0'; 23459ac545b0SLaurent Riffard if ((export = strchr(modname, '\t')) != NULL) 2346bd5cbcedSRam Pai *export++ = '\0'; 2347534b89a9SSam Ravnborg if (export && ((end = strchr(export, '\t')) != NULL)) 2348534b89a9SSam Ravnborg *end = '\0'; 23491da177e4SLinus Torvalds crc = strtoul(line, &d, 16); 23501da177e4SLinus Torvalds if (*symname == '\0' || *modname == '\0' || *d != '\0') 23511da177e4SLinus Torvalds goto fail; 2352df578e7dSSam Ravnborg mod = find_module(modname); 2353df578e7dSSam Ravnborg if (!mod) { 2354df578e7dSSam Ravnborg if (is_vmlinux(modname)) 23551da177e4SLinus Torvalds have_vmlinux = 1; 23560fa3a88cSJan Beulich mod = new_module(modname); 23571da177e4SLinus Torvalds mod->skip = 1; 23581da177e4SLinus Torvalds } 2359bd5cbcedSRam Pai s = sym_add_exported(symname, mod, export_no(export)); 2360040fcc81SSam Ravnborg s->kernel = kernel; 23618e70c458SSam Ravnborg s->preloaded = 1; 2362bd5cbcedSRam Pai sym_update_crc(symname, mod, crc, export_no(export)); 23631da177e4SLinus Torvalds } 23642ee41e62SChristian Engelmayer release_file(file, size); 23651da177e4SLinus Torvalds return; 23661da177e4SLinus Torvalds fail: 23672ee41e62SChristian Engelmayer release_file(file, size); 23681da177e4SLinus Torvalds fatal("parse error in symbol dump file\n"); 23691da177e4SLinus Torvalds } 23701da177e4SLinus Torvalds 2371040fcc81SSam Ravnborg /* For normal builds always dump all symbols. 2372040fcc81SSam Ravnborg * For external modules only dump symbols 2373040fcc81SSam Ravnborg * that are not read from kernel Module.symvers. 2374040fcc81SSam Ravnborg **/ 2375040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym) 2376040fcc81SSam Ravnborg { 2377040fcc81SSam Ravnborg if (!external_module) 2378040fcc81SSam Ravnborg return 1; 2379040fcc81SSam Ravnborg if (sym->vmlinux || sym->kernel) 2380040fcc81SSam Ravnborg return 0; 2381040fcc81SSam Ravnborg return 1; 2382040fcc81SSam Ravnborg } 2383040fcc81SSam Ravnborg 23845c3ead8cSSam Ravnborg static void write_dump(const char *fname) 23851da177e4SLinus Torvalds { 23861da177e4SLinus Torvalds struct buffer buf = { }; 23871da177e4SLinus Torvalds struct symbol *symbol; 23881da177e4SLinus Torvalds int n; 23891da177e4SLinus Torvalds 23901da177e4SLinus Torvalds for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { 23911da177e4SLinus Torvalds symbol = symbolhash[n]; 23921da177e4SLinus Torvalds while (symbol) { 2393040fcc81SSam Ravnborg if (dump_sym(symbol)) 2394bd5cbcedSRam Pai buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", 2395040fcc81SSam Ravnborg symbol->crc, symbol->name, 2396bd5cbcedSRam Pai symbol->module->name, 2397bd5cbcedSRam Pai export_str(symbol->export)); 23981da177e4SLinus Torvalds symbol = symbol->next; 23991da177e4SLinus Torvalds } 24001da177e4SLinus Torvalds } 24011da177e4SLinus Torvalds write_if_changed(&buf, fname); 2402c7d47f26SHeinrich Schuchardt free(buf.p); 24031da177e4SLinus Torvalds } 24041da177e4SLinus Torvalds 24052d04b5aeSRichard Hacker struct ext_sym_list { 24062d04b5aeSRichard Hacker struct ext_sym_list *next; 24072d04b5aeSRichard Hacker const char *file; 24082d04b5aeSRichard Hacker }; 24092d04b5aeSRichard Hacker 24105c3ead8cSSam Ravnborg int main(int argc, char **argv) 24111da177e4SLinus Torvalds { 24121da177e4SLinus Torvalds struct module *mod; 24131da177e4SLinus Torvalds struct buffer buf = { }; 2414040fcc81SSam Ravnborg char *kernel_read = NULL, *module_read = NULL; 2415712f9b46SRusty Russell char *dump_write = NULL, *files_source = NULL; 24161da177e4SLinus Torvalds int opt; 2417c53ddacdSKirill Korotaev int err; 24182d04b5aeSRichard Hacker struct ext_sym_list *extsym_iter; 24192d04b5aeSRichard Hacker struct ext_sym_list *extsym_start = NULL; 24201da177e4SLinus Torvalds 2421*0987abcbSPaul Walmsley while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awE")) != -1) { 24221da177e4SLinus Torvalds switch (opt) { 24231da177e4SLinus Torvalds case 'i': 2424040fcc81SSam Ravnborg kernel_read = optarg; 2425040fcc81SSam Ravnborg break; 2426040fcc81SSam Ravnborg case 'I': 2427040fcc81SSam Ravnborg module_read = optarg; 2428040fcc81SSam Ravnborg external_module = 1; 24291da177e4SLinus Torvalds break; 24302d04b5aeSRichard Hacker case 'e': 24312d04b5aeSRichard Hacker external_module = 1; 24322d04b5aeSRichard Hacker extsym_iter = 24332d04b5aeSRichard Hacker NOFAIL(malloc(sizeof(*extsym_iter))); 24342d04b5aeSRichard Hacker extsym_iter->next = extsym_start; 24352d04b5aeSRichard Hacker extsym_iter->file = optarg; 24362d04b5aeSRichard Hacker extsym_start = extsym_iter; 24372d04b5aeSRichard Hacker break; 24381da177e4SLinus Torvalds case 'm': 24391da177e4SLinus Torvalds modversions = 1; 24401da177e4SLinus Torvalds break; 2441eed380f3SGuenter Roeck case 'n': 2442eed380f3SGuenter Roeck ignore_missing_files = 1; 2443eed380f3SGuenter Roeck break; 24441da177e4SLinus Torvalds case 'o': 24451da177e4SLinus Torvalds dump_write = optarg; 24461da177e4SLinus Torvalds break; 24471da177e4SLinus Torvalds case 'a': 24481da177e4SLinus Torvalds all_versions = 1; 24491da177e4SLinus Torvalds break; 24508d8d8289SSam Ravnborg case 's': 24518d8d8289SSam Ravnborg vmlinux_section_warnings = 0; 24528d8d8289SSam Ravnborg break; 2453588ccd73SSam Ravnborg case 'S': 2454588ccd73SSam Ravnborg sec_mismatch_verbose = 0; 2455588ccd73SSam Ravnborg break; 2456712f9b46SRusty Russell case 'T': 2457712f9b46SRusty Russell files_source = optarg; 2458712f9b46SRusty Russell break; 2459c53ddacdSKirill Korotaev case 'w': 2460c53ddacdSKirill Korotaev warn_unresolved = 1; 2461c53ddacdSKirill Korotaev break; 246247490ec1SNicolas Boichat case 'E': 246347490ec1SNicolas Boichat sec_mismatch_fatal = 1; 246447490ec1SNicolas Boichat break; 24651da177e4SLinus Torvalds default: 24661da177e4SLinus Torvalds exit(1); 24671da177e4SLinus Torvalds } 24681da177e4SLinus Torvalds } 24691da177e4SLinus Torvalds 2470040fcc81SSam Ravnborg if (kernel_read) 2471040fcc81SSam Ravnborg read_dump(kernel_read, 1); 2472040fcc81SSam Ravnborg if (module_read) 2473040fcc81SSam Ravnborg read_dump(module_read, 0); 24742d04b5aeSRichard Hacker while (extsym_start) { 24752d04b5aeSRichard Hacker read_dump(extsym_start->file, 0); 24762d04b5aeSRichard Hacker extsym_iter = extsym_start->next; 24772d04b5aeSRichard Hacker free(extsym_start); 24782d04b5aeSRichard Hacker extsym_start = extsym_iter; 24792d04b5aeSRichard Hacker } 24801da177e4SLinus Torvalds 2481df578e7dSSam Ravnborg while (optind < argc) 24821da177e4SLinus Torvalds read_symbols(argv[optind++]); 24831da177e4SLinus Torvalds 2484712f9b46SRusty Russell if (files_source) 2485712f9b46SRusty Russell read_symbols_from_files(files_source); 2486712f9b46SRusty Russell 24871da177e4SLinus Torvalds for (mod = modules; mod; mod = mod->next) { 24881da177e4SLinus Torvalds if (mod->skip) 24891da177e4SLinus Torvalds continue; 2490c96fca21SSam Ravnborg check_exports(mod); 2491b817f6feSSam Ravnborg } 2492b817f6feSSam Ravnborg 2493c53ddacdSKirill Korotaev err = 0; 2494c53ddacdSKirill Korotaev 2495b817f6feSSam Ravnborg for (mod = modules; mod; mod = mod->next) { 2496d93e1719SMathias Krause char fname[PATH_MAX]; 2497666ab414SAndi Kleen 2498b817f6feSSam Ravnborg if (mod->skip) 2499b817f6feSSam Ravnborg continue; 25001da177e4SLinus Torvalds 25011da177e4SLinus Torvalds buf.pos = 0; 25021da177e4SLinus Torvalds 25034fd3e4efSWanlong Gao err |= check_modname_len(mod); 25041da177e4SLinus Torvalds add_header(&buf, mod); 25052449b8baSBen Hutchings add_intree_flag(&buf, !external_module); 2506caf7501aSAndi Kleen add_retpoline(&buf); 2507a9860bf0SGreg Kroah-Hartman add_staging_flag(&buf, mod->name); 2508c53ddacdSKirill Korotaev err |= add_versions(&buf, mod); 25091da177e4SLinus Torvalds add_depends(&buf, mod, modules); 25101da177e4SLinus Torvalds add_moddevtable(&buf, mod); 25111da177e4SLinus Torvalds add_srcversion(&buf, mod); 25121da177e4SLinus Torvalds 25131da177e4SLinus Torvalds sprintf(fname, "%s.mod.c", mod->name); 25141da177e4SLinus Torvalds write_if_changed(&buf, fname); 25151da177e4SLinus Torvalds } 25161da177e4SLinus Torvalds if (dump_write) 25171da177e4SLinus Torvalds write_dump(dump_write); 251847490ec1SNicolas Boichat if (sec_mismatch_count) { 251947490ec1SNicolas Boichat if (!sec_mismatch_verbose) { 25207c0ac495SGeert Uytterhoeven warn("modpost: Found %d section mismatch(es).\n" 2521e5f95c8bSSam Ravnborg "To see full details build your kernel with:\n" 2522e5f95c8bSSam Ravnborg "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", 2523e5f95c8bSSam Ravnborg sec_mismatch_count); 252447490ec1SNicolas Boichat } 252547490ec1SNicolas Boichat if (sec_mismatch_fatal) { 252647490ec1SNicolas Boichat fatal("modpost: Section mismatches detected.\n" 252747490ec1SNicolas Boichat "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); 252847490ec1SNicolas Boichat } 252947490ec1SNicolas Boichat } 2530c7d47f26SHeinrich Schuchardt free(buf.p); 25311da177e4SLinus Torvalds 2532c53ddacdSKirill Korotaev return err; 25331da177e4SLinus Torvalds } 2534