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" 225a865c06SLinus Torvalds #include "../../include/generated/autoconf.h" 23b817f6feSSam Ravnborg #include "../../include/linux/license.h" 24b92021b0SRusty Russell #include "../../include/linux/export.h" 259e1b9b80SAlan Jenkins 261da177e4SLinus Torvalds /* Are we using CONFIG_MODVERSIONS? */ 277a3ee753SMathias Krause static int modversions = 0; 281da177e4SLinus Torvalds /* Warn about undefined symbols? (do so if we have vmlinux) */ 297a3ee753SMathias Krause static int have_vmlinux = 0; 301da177e4SLinus Torvalds /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ 311da177e4SLinus Torvalds static int all_versions = 0; 32040fcc81SSam Ravnborg /* If we are modposting external module set to 1 */ 33040fcc81SSam Ravnborg static int external_module = 0; 348d8d8289SSam Ravnborg /* Warn about section mismatch in vmlinux if set to 1 */ 358d8d8289SSam Ravnborg static int vmlinux_section_warnings = 1; 36c53ddacdSKirill Korotaev /* Only warn about unresolved symbols */ 37c53ddacdSKirill Korotaev static int warn_unresolved = 0; 38bd5cbcedSRam Pai /* How a symbol is exported */ 39588ccd73SSam Ravnborg static int sec_mismatch_count = 0; 40588ccd73SSam Ravnborg static int sec_mismatch_verbose = 1; 4147490ec1SNicolas Boichat static int sec_mismatch_fatal = 0; 42eed380f3SGuenter Roeck /* ignore missing files */ 43eed380f3SGuenter Roeck static int ignore_missing_files; 44588ccd73SSam Ravnborg 45c96fca21SSam Ravnborg enum export { 46c96fca21SSam Ravnborg export_plain, export_unused, export_gpl, 47c96fca21SSam Ravnborg export_unused_gpl, export_gpl_future, export_unknown 48c96fca21SSam Ravnborg }; 491da177e4SLinus Torvalds 506d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2))) 516d9a89eaSAndi Kleen 526d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...) 531da177e4SLinus Torvalds { 541da177e4SLinus Torvalds va_list arglist; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds fprintf(stderr, "FATAL: "); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds va_start(arglist, fmt); 591da177e4SLinus Torvalds vfprintf(stderr, fmt, arglist); 601da177e4SLinus Torvalds va_end(arglist); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds exit(1); 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 656d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds va_list arglist; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds fprintf(stderr, "WARNING: "); 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds va_start(arglist, fmt); 721da177e4SLinus Torvalds vfprintf(stderr, fmt, arglist); 731da177e4SLinus Torvalds va_end(arglist); 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 766d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...) 772a116659SMatthew Wilcox { 782a116659SMatthew Wilcox va_list arglist; 792a116659SMatthew Wilcox 802a116659SMatthew Wilcox fprintf(stderr, "ERROR: "); 812a116659SMatthew Wilcox 822a116659SMatthew Wilcox va_start(arglist, fmt); 832a116659SMatthew Wilcox vfprintf(stderr, fmt, arglist); 842a116659SMatthew Wilcox va_end(arglist); 852a116659SMatthew Wilcox } 862a116659SMatthew Wilcox 87d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix) 88d4ef1c30SRusty Russell { 89d4ef1c30SRusty Russell if (strlen(str) < strlen(postfix)) 90d4ef1c30SRusty Russell return false; 91d4ef1c30SRusty Russell 92d4ef1c30SRusty Russell return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; 93d4ef1c30SRusty Russell } 94d4ef1c30SRusty Russell 95040fcc81SSam Ravnborg static int is_vmlinux(const char *modname) 96040fcc81SSam Ravnborg { 97040fcc81SSam Ravnborg const char *myname; 98040fcc81SSam Ravnborg 99df578e7dSSam Ravnborg myname = strrchr(modname, '/'); 100df578e7dSSam Ravnborg if (myname) 101040fcc81SSam Ravnborg myname++; 102040fcc81SSam Ravnborg else 103040fcc81SSam Ravnborg myname = modname; 104040fcc81SSam Ravnborg 105741f98feSSam Ravnborg return (strcmp(myname, "vmlinux") == 0) || 106741f98feSSam Ravnborg (strcmp(myname, "vmlinux.o") == 0); 107040fcc81SSam Ravnborg } 108040fcc81SSam Ravnborg 1091da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr) 1101da177e4SLinus Torvalds { 111df578e7dSSam Ravnborg if (!ptr) 1121da177e4SLinus Torvalds fatal("modpost: Memory allocation failure: %s.\n", expr); 113df578e7dSSam Ravnborg 1141da177e4SLinus Torvalds return ptr; 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds /* A list of all modules we processed */ 1181da177e4SLinus Torvalds static struct module *modules; 1191da177e4SLinus Torvalds 1205c3ead8cSSam Ravnborg static struct module *find_module(char *modname) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds struct module *mod; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds for (mod = modules; mod; mod = mod->next) 1251da177e4SLinus Torvalds if (strcmp(mod->name, modname) == 0) 1261da177e4SLinus Torvalds break; 1271da177e4SLinus Torvalds return mod; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 130d4ef1c30SRusty Russell static struct module *new_module(const char *modname) 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds struct module *mod; 133d4ef1c30SRusty Russell char *p; 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds mod = NOFAIL(malloc(sizeof(*mod))); 1361da177e4SLinus Torvalds memset(mod, 0, sizeof(*mod)); 1371da177e4SLinus Torvalds p = NOFAIL(strdup(modname)); 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* strip trailing .o */ 140d4ef1c30SRusty Russell if (strends(p, ".o")) { 141d4ef1c30SRusty Russell p[strlen(p) - 2] = '\0'; 142258f7426SFrank Rowand mod->is_dot_o = 1; 143258f7426SFrank Rowand } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds /* add to list */ 1461da177e4SLinus Torvalds mod->name = p; 147b817f6feSSam Ravnborg mod->gpl_compatible = -1; 1481da177e4SLinus Torvalds mod->next = modules; 1491da177e4SLinus Torvalds modules = mod; 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds return mod; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* A hash of all exported symbols, 1551da177e4SLinus Torvalds * struct symbol is also used for lists of unresolved symbols */ 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds struct symbol { 1601da177e4SLinus Torvalds struct symbol *next; 1611da177e4SLinus Torvalds struct module *module; 1621da177e4SLinus Torvalds unsigned int crc; 1631da177e4SLinus Torvalds int crc_valid; 1641da177e4SLinus Torvalds unsigned int weak:1; 165040fcc81SSam Ravnborg unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ 166040fcc81SSam Ravnborg unsigned int kernel:1; /* 1 if symbol is from kernel 167040fcc81SSam Ravnborg * (only for external modules) **/ 168b6568b1aSRusty Russell unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */ 169bd5cbcedSRam Pai enum export export; /* Type of export */ 1701da177e4SLinus Torvalds char name[0]; 1711da177e4SLinus Torvalds }; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */ 1761da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name) 1771da177e4SLinus Torvalds { 1781da177e4SLinus Torvalds unsigned value; /* Used to compute the hash value. */ 1791da177e4SLinus Torvalds unsigned i; /* Used to cycle through random values. */ 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* Set the initial value from the key size. */ 1821da177e4SLinus Torvalds for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) 1831da177e4SLinus Torvalds value = (value + (((unsigned char *)name)[i] << (i*5 % 24))); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds return (1103515243 * value + 12345); 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds 1885c3ead8cSSam Ravnborg /** 1895c3ead8cSSam Ravnborg * Allocate a new symbols for use in the hash of exported symbols or 1905c3ead8cSSam Ravnborg * the list of unresolved symbols per module 1915c3ead8cSSam Ravnborg **/ 1925c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak, 1935c3ead8cSSam Ravnborg struct symbol *next) 1941da177e4SLinus Torvalds { 1951da177e4SLinus Torvalds struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds memset(s, 0, sizeof(*s)); 1981da177e4SLinus Torvalds strcpy(s->name, name); 1991da177e4SLinus Torvalds s->weak = weak; 2001da177e4SLinus Torvalds s->next = next; 2011da177e4SLinus Torvalds return s; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* For the hash of exported symbols */ 205bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module, 206bd5cbcedSRam Pai enum export export) 2071da177e4SLinus Torvalds { 2081da177e4SLinus Torvalds unsigned int hash; 2091da177e4SLinus Torvalds struct symbol *new; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds hash = tdb_hash(name) % SYMBOL_HASH_SIZE; 2121da177e4SLinus Torvalds new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); 2131da177e4SLinus Torvalds new->module = module; 214bd5cbcedSRam Pai new->export = export; 215040fcc81SSam Ravnborg return new; 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2185c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds struct symbol *s; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /* For our purposes, .foo matches foo. PPC64 needs this. */ 2231da177e4SLinus Torvalds if (name[0] == '.') 2241da177e4SLinus Torvalds name++; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) { 2271da177e4SLinus Torvalds if (strcmp(s->name, name) == 0) 2281da177e4SLinus Torvalds return s; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds return NULL; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2337a3ee753SMathias Krause static const struct { 234bd5cbcedSRam Pai const char *str; 235bd5cbcedSRam Pai enum export export; 236bd5cbcedSRam Pai } export_list[] = { 237bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL", .export = export_plain }, 238c96fca21SSam Ravnborg { .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused }, 239bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, 240c96fca21SSam Ravnborg { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl }, 241bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future }, 242bd5cbcedSRam Pai { .str = "(unknown)", .export = export_unknown }, 243bd5cbcedSRam Pai }; 244bd5cbcedSRam Pai 245bd5cbcedSRam Pai 246bd5cbcedSRam Pai static const char *export_str(enum export ex) 247bd5cbcedSRam Pai { 248bd5cbcedSRam Pai return export_list[ex].str; 249bd5cbcedSRam Pai } 250bd5cbcedSRam Pai 251bd5cbcedSRam Pai static enum export export_no(const char *s) 252bd5cbcedSRam Pai { 253bd5cbcedSRam Pai int i; 254df578e7dSSam Ravnborg 255534b89a9SSam Ravnborg if (!s) 256534b89a9SSam Ravnborg return export_unknown; 257bd5cbcedSRam Pai for (i = 0; export_list[i].export != export_unknown; i++) { 258bd5cbcedSRam Pai if (strcmp(export_list[i].str, s) == 0) 259bd5cbcedSRam Pai return export_list[i].export; 260bd5cbcedSRam Pai } 261bd5cbcedSRam Pai return export_unknown; 262bd5cbcedSRam Pai } 263bd5cbcedSRam Pai 26462a26356SAlessio Igor Bogani static const char *sec_name(struct elf_info *elf, int secindex); 26562a26356SAlessio Igor Bogani 26662a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) 26762a26356SAlessio Igor Bogani 26862a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec) 26962a26356SAlessio Igor Bogani { 27062a26356SAlessio Igor Bogani const char *secname = sec_name(elf, sec); 27162a26356SAlessio Igor Bogani 27262a26356SAlessio Igor Bogani if (strstarts(secname, "___ksymtab+")) 27362a26356SAlessio Igor Bogani return export_plain; 27462a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_unused+")) 27562a26356SAlessio Igor Bogani return export_unused; 27662a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_gpl+")) 27762a26356SAlessio Igor Bogani return export_gpl; 27862a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_unused_gpl+")) 27962a26356SAlessio Igor Bogani return export_unused_gpl; 28062a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_gpl_future+")) 28162a26356SAlessio Igor Bogani return export_gpl_future; 28262a26356SAlessio Igor Bogani else 28362a26356SAlessio Igor Bogani return export_unknown; 28462a26356SAlessio Igor Bogani } 28562a26356SAlessio Igor Bogani 2861ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec) 287bd5cbcedSRam Pai { 288bd5cbcedSRam Pai if (sec == elf->export_sec) 289bd5cbcedSRam Pai return export_plain; 290c96fca21SSam Ravnborg else if (sec == elf->export_unused_sec) 291c96fca21SSam Ravnborg return export_unused; 292bd5cbcedSRam Pai else if (sec == elf->export_gpl_sec) 293bd5cbcedSRam Pai return export_gpl; 294c96fca21SSam Ravnborg else if (sec == elf->export_unused_gpl_sec) 295c96fca21SSam Ravnborg return export_unused_gpl; 296bd5cbcedSRam Pai else if (sec == elf->export_gpl_future_sec) 297bd5cbcedSRam Pai return export_gpl_future; 298bd5cbcedSRam Pai else 299bd5cbcedSRam Pai return export_unknown; 300bd5cbcedSRam Pai } 301bd5cbcedSRam Pai 3025c3ead8cSSam Ravnborg /** 3035c3ead8cSSam Ravnborg * Add an exported symbol - it may have already been added without a 3045c3ead8cSSam Ravnborg * CRC, in this case just update the CRC 3055c3ead8cSSam Ravnborg **/ 306bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod, 307bd5cbcedSRam Pai enum export export) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds struct symbol *s = find_symbol(name); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds if (!s) { 312bd5cbcedSRam Pai s = new_symbol(name, mod, export); 3138e70c458SSam Ravnborg } else { 3148e70c458SSam Ravnborg if (!s->preloaded) { 3157b75b13cSSam Ravnborg warn("%s: '%s' exported twice. Previous export " 3168e70c458SSam Ravnborg "was in %s%s\n", mod->name, name, 3178e70c458SSam Ravnborg s->module->name, 3188e70c458SSam Ravnborg is_vmlinux(s->module->name) ?"":".ko"); 3194b21960fSTrent Piepho } else { 320baec30e4SPaul Bolle /* In case Module.symvers was out of date */ 3214b21960fSTrent Piepho s->module = mod; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds } 3248e70c458SSam Ravnborg s->preloaded = 0; 325040fcc81SSam Ravnborg s->vmlinux = is_vmlinux(mod->name); 326040fcc81SSam Ravnborg s->kernel = 0; 327bd5cbcedSRam Pai s->export = export; 328040fcc81SSam Ravnborg return s; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 331040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod, 332bd5cbcedSRam Pai unsigned int crc, enum export export) 333040fcc81SSam Ravnborg { 334040fcc81SSam Ravnborg struct symbol *s = find_symbol(name); 335040fcc81SSam Ravnborg 336b6568b1aSRusty Russell if (!s) { 337bd5cbcedSRam Pai s = new_symbol(name, mod, export); 338b6568b1aSRusty Russell /* Don't complain when we find it later. */ 339b6568b1aSRusty Russell s->preloaded = 1; 340b6568b1aSRusty Russell } 341040fcc81SSam Ravnborg s->crc = crc; 3421da177e4SLinus Torvalds s->crc_valid = 1; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3455c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size) 3461da177e4SLinus Torvalds { 3471da177e4SLinus Torvalds struct stat st; 348eb3d5cc6SJesper Juhl void *map = MAP_FAILED; 3491da177e4SLinus Torvalds int fd; 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds fd = open(filename, O_RDONLY); 352eb3d5cc6SJesper Juhl if (fd < 0) 3531da177e4SLinus Torvalds return NULL; 354eb3d5cc6SJesper Juhl if (fstat(fd, &st)) 355eb3d5cc6SJesper Juhl goto failed; 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds *size = st.st_size; 3581da177e4SLinus Torvalds map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 3591da177e4SLinus Torvalds 360eb3d5cc6SJesper Juhl failed: 361eb3d5cc6SJesper Juhl close(fd); 3621da177e4SLinus Torvalds if (map == MAP_FAILED) 3631da177e4SLinus Torvalds return NULL; 3641da177e4SLinus Torvalds return map; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 3675c3ead8cSSam Ravnborg /** 3685c3ead8cSSam Ravnborg * Return a copy of the next line in a mmap'ed file. 3695c3ead8cSSam Ravnborg * spaces in the beginning of the line is trimmed away. 3705c3ead8cSSam Ravnborg * Return a pointer to a static buffer. 3715c3ead8cSSam Ravnborg **/ 3725c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size) 3731da177e4SLinus Torvalds { 3741da177e4SLinus Torvalds static char line[4096]; 3751da177e4SLinus Torvalds int skip = 1; 3761da177e4SLinus Torvalds size_t len = 0; 3771da177e4SLinus Torvalds signed char *p = (signed char *)file + *pos; 3781da177e4SLinus Torvalds char *s = line; 3791da177e4SLinus Torvalds 380df578e7dSSam Ravnborg for (; *pos < size ; (*pos)++) { 3811da177e4SLinus Torvalds if (skip && isspace(*p)) { 3821da177e4SLinus Torvalds p++; 3831da177e4SLinus Torvalds continue; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds skip = 0; 3861da177e4SLinus Torvalds if (*p != '\n' && (*pos < size)) { 3871da177e4SLinus Torvalds len++; 3881da177e4SLinus Torvalds *s++ = *p++; 3891da177e4SLinus Torvalds if (len > 4095) 3901da177e4SLinus Torvalds break; /* Too long, stop */ 3911da177e4SLinus Torvalds } else { 3921da177e4SLinus Torvalds /* End of string */ 3931da177e4SLinus Torvalds *s = '\0'; 3941da177e4SLinus Torvalds return line; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds /* End of buffer */ 3981da177e4SLinus Torvalds return NULL; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 4015c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size) 4021da177e4SLinus Torvalds { 4031da177e4SLinus Torvalds munmap(file, size); 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 40685bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename) 4071da177e4SLinus Torvalds { 4081da177e4SLinus Torvalds unsigned int i; 40985bd2fddSSam Ravnborg Elf_Ehdr *hdr; 4101da177e4SLinus Torvalds Elf_Shdr *sechdrs; 4111da177e4SLinus Torvalds Elf_Sym *sym; 4121ce53adfSDenys Vlasenko const char *secstrings; 4131ce53adfSDenys Vlasenko unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds hdr = grab_file(filename, &info->size); 4161da177e4SLinus Torvalds if (!hdr) { 417eed380f3SGuenter Roeck if (ignore_missing_files) { 418eed380f3SGuenter Roeck fprintf(stderr, "%s: %s (ignored)\n", filename, 419eed380f3SGuenter Roeck strerror(errno)); 420eed380f3SGuenter Roeck return 0; 421eed380f3SGuenter Roeck } 4221da177e4SLinus Torvalds perror(filename); 4236803dc0eSSam Ravnborg exit(1); 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds info->hdr = hdr; 42685bd2fddSSam Ravnborg if (info->size < sizeof(*hdr)) { 42785bd2fddSSam Ravnborg /* file too small, assume this is an empty .o file */ 42885bd2fddSSam Ravnborg return 0; 42985bd2fddSSam Ravnborg } 43085bd2fddSSam Ravnborg /* Is this a valid ELF file? */ 43185bd2fddSSam Ravnborg if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || 43285bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG1] != ELFMAG1) || 43385bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG2] != ELFMAG2) || 43485bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG3] != ELFMAG3)) { 43585bd2fddSSam Ravnborg /* Not an ELF file - silently ignore it */ 43685bd2fddSSam Ravnborg return 0; 43785bd2fddSSam Ravnborg } 4381da177e4SLinus Torvalds /* Fix endianness in ELF header */ 439ae4ac123SAtsushi Nemoto hdr->e_type = TO_NATIVE(hdr->e_type); 4407d875a02SAnders Kaseorg hdr->e_machine = TO_NATIVE(hdr->e_machine); 4417d875a02SAnders Kaseorg hdr->e_version = TO_NATIVE(hdr->e_version); 4427d875a02SAnders Kaseorg hdr->e_entry = TO_NATIVE(hdr->e_entry); 4437d875a02SAnders Kaseorg hdr->e_phoff = TO_NATIVE(hdr->e_phoff); 4447d875a02SAnders Kaseorg hdr->e_shoff = TO_NATIVE(hdr->e_shoff); 4457d875a02SAnders Kaseorg hdr->e_flags = TO_NATIVE(hdr->e_flags); 4467d875a02SAnders Kaseorg hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize); 4477d875a02SAnders Kaseorg hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize); 4487d875a02SAnders Kaseorg hdr->e_phnum = TO_NATIVE(hdr->e_phnum); 4497d875a02SAnders Kaseorg hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize); 4507d875a02SAnders Kaseorg hdr->e_shnum = TO_NATIVE(hdr->e_shnum); 4517d875a02SAnders Kaseorg hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); 4521da177e4SLinus Torvalds sechdrs = (void *)hdr + hdr->e_shoff; 4531da177e4SLinus Torvalds info->sechdrs = sechdrs; 4541da177e4SLinus Torvalds 455a83710e5SPetr Stetiar /* Check if file offset is correct */ 456a83710e5SPetr Stetiar if (hdr->e_shoff > info->size) { 457df578e7dSSam Ravnborg fatal("section header offset=%lu in file '%s' is bigger than " 458df578e7dSSam Ravnborg "filesize=%lu\n", (unsigned long)hdr->e_shoff, 459df578e7dSSam Ravnborg filename, info->size); 460a83710e5SPetr Stetiar return 0; 461a83710e5SPetr Stetiar } 462a83710e5SPetr Stetiar 4636845756bSAnders Kaseorg if (hdr->e_shnum == SHN_UNDEF) { 4641ce53adfSDenys Vlasenko /* 4651ce53adfSDenys Vlasenko * There are more than 64k sections, 4661ce53adfSDenys Vlasenko * read count from .sh_size. 4671ce53adfSDenys Vlasenko */ 4681ce53adfSDenys Vlasenko info->num_sections = TO_NATIVE(sechdrs[0].sh_size); 4691ce53adfSDenys Vlasenko } 4701ce53adfSDenys Vlasenko else { 4711ce53adfSDenys Vlasenko info->num_sections = hdr->e_shnum; 4721ce53adfSDenys Vlasenko } 4731ce53adfSDenys Vlasenko if (hdr->e_shstrndx == SHN_XINDEX) { 4746845756bSAnders Kaseorg info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link); 4751ce53adfSDenys Vlasenko } 4761ce53adfSDenys Vlasenko else { 4771ce53adfSDenys Vlasenko info->secindex_strings = hdr->e_shstrndx; 4781ce53adfSDenys Vlasenko } 4791ce53adfSDenys Vlasenko 4801da177e4SLinus Torvalds /* Fix endianness in section headers */ 4811ce53adfSDenys Vlasenko for (i = 0; i < info->num_sections; i++) { 4827d875a02SAnders Kaseorg sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); 4831da177e4SLinus Torvalds sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); 4847d875a02SAnders Kaseorg sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); 4857d875a02SAnders Kaseorg sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); 4861da177e4SLinus Torvalds sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); 4871da177e4SLinus Torvalds sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); 4881da177e4SLinus Torvalds sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); 489ae4ac123SAtsushi Nemoto sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); 4907d875a02SAnders Kaseorg sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign); 4917d875a02SAnders Kaseorg sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds /* Find symbol table. */ 4941ce53adfSDenys Vlasenko secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; 4951ce53adfSDenys Vlasenko for (i = 1; i < info->num_sections; i++) { 496bd5cbcedSRam Pai const char *secname; 49756fc82c5STejun Heo int nobits = sechdrs[i].sh_type == SHT_NOBITS; 4981da177e4SLinus Torvalds 49956fc82c5STejun Heo if (!nobits && sechdrs[i].sh_offset > info->size) { 500df578e7dSSam Ravnborg fatal("%s is truncated. sechdrs[i].sh_offset=%lu > " 501df578e7dSSam Ravnborg "sizeof(*hrd)=%zu\n", filename, 502df578e7dSSam Ravnborg (unsigned long)sechdrs[i].sh_offset, 503df578e7dSSam Ravnborg sizeof(*hdr)); 50485bd2fddSSam Ravnborg return 0; 50585bd2fddSSam Ravnborg } 506bd5cbcedSRam Pai secname = secstrings + sechdrs[i].sh_name; 507bd5cbcedSRam Pai if (strcmp(secname, ".modinfo") == 0) { 50856fc82c5STejun Heo if (nobits) 50956fc82c5STejun Heo fatal("%s has NOBITS .modinfo\n", filename); 5101da177e4SLinus Torvalds info->modinfo = (void *)hdr + sechdrs[i].sh_offset; 5111da177e4SLinus Torvalds info->modinfo_len = sechdrs[i].sh_size; 512bd5cbcedSRam Pai } else if (strcmp(secname, "__ksymtab") == 0) 513bd5cbcedSRam Pai info->export_sec = i; 514c96fca21SSam Ravnborg else if (strcmp(secname, "__ksymtab_unused") == 0) 515c96fca21SSam Ravnborg info->export_unused_sec = i; 516bd5cbcedSRam Pai else if (strcmp(secname, "__ksymtab_gpl") == 0) 517bd5cbcedSRam Pai info->export_gpl_sec = i; 518c96fca21SSam Ravnborg else if (strcmp(secname, "__ksymtab_unused_gpl") == 0) 519c96fca21SSam Ravnborg info->export_unused_gpl_sec = i; 520bd5cbcedSRam Pai else if (strcmp(secname, "__ksymtab_gpl_future") == 0) 521bd5cbcedSRam Pai info->export_gpl_future_sec = i; 522bd5cbcedSRam Pai 5231ce53adfSDenys Vlasenko if (sechdrs[i].sh_type == SHT_SYMTAB) { 5241ce53adfSDenys Vlasenko unsigned int sh_link_idx; 5251ce53adfSDenys Vlasenko symtab_idx = i; 5261ce53adfSDenys Vlasenko info->symtab_start = (void *)hdr + 5271ce53adfSDenys Vlasenko sechdrs[i].sh_offset; 5281ce53adfSDenys Vlasenko info->symtab_stop = (void *)hdr + 5291ce53adfSDenys Vlasenko sechdrs[i].sh_offset + sechdrs[i].sh_size; 5306845756bSAnders Kaseorg sh_link_idx = sechdrs[i].sh_link; 5311da177e4SLinus Torvalds info->strtab = (void *)hdr + 5321ce53adfSDenys Vlasenko sechdrs[sh_link_idx].sh_offset; 5331ce53adfSDenys Vlasenko } 5341ce53adfSDenys Vlasenko 5351ce53adfSDenys Vlasenko /* 32bit section no. table? ("more than 64k sections") */ 5361ce53adfSDenys Vlasenko if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { 5371ce53adfSDenys Vlasenko symtab_shndx_idx = i; 5381ce53adfSDenys Vlasenko info->symtab_shndx_start = (void *)hdr + 5391ce53adfSDenys Vlasenko sechdrs[i].sh_offset; 5401ce53adfSDenys Vlasenko info->symtab_shndx_stop = (void *)hdr + 5411ce53adfSDenys Vlasenko sechdrs[i].sh_offset + sechdrs[i].sh_size; 5421ce53adfSDenys Vlasenko } 5431da177e4SLinus Torvalds } 544df578e7dSSam Ravnborg if (!info->symtab_start) 545cb80514dSSam Ravnborg fatal("%s has no symtab?\n", filename); 546df578e7dSSam Ravnborg 5471da177e4SLinus Torvalds /* Fix endianness in symbols */ 5481da177e4SLinus Torvalds for (sym = info->symtab_start; sym < info->symtab_stop; sym++) { 5491da177e4SLinus Torvalds sym->st_shndx = TO_NATIVE(sym->st_shndx); 5501da177e4SLinus Torvalds sym->st_name = TO_NATIVE(sym->st_name); 5511da177e4SLinus Torvalds sym->st_value = TO_NATIVE(sym->st_value); 5521da177e4SLinus Torvalds sym->st_size = TO_NATIVE(sym->st_size); 5531da177e4SLinus Torvalds } 5541ce53adfSDenys Vlasenko 5551ce53adfSDenys Vlasenko if (symtab_shndx_idx != ~0U) { 5561ce53adfSDenys Vlasenko Elf32_Word *p; 5576845756bSAnders Kaseorg if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link) 5581ce53adfSDenys Vlasenko fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", 5596845756bSAnders Kaseorg filename, sechdrs[symtab_shndx_idx].sh_link, 5601ce53adfSDenys Vlasenko symtab_idx); 5611ce53adfSDenys Vlasenko /* Fix endianness */ 5621ce53adfSDenys Vlasenko for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; 5631ce53adfSDenys Vlasenko p++) 5641ce53adfSDenys Vlasenko *p = TO_NATIVE(*p); 5651ce53adfSDenys Vlasenko } 5661ce53adfSDenys Vlasenko 56785bd2fddSSam Ravnborg return 1; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5705c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds release_file(info->hdr, info->size); 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5754d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname) 5764d7365d6SSam Ravnborg { 5774d7365d6SSam Ravnborg /* ignore __this_module, it will be resolved shortly */ 578b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0) 5794d7365d6SSam Ravnborg return 1; 5804d7365d6SSam Ravnborg /* ignore global offset table */ 5814d7365d6SSam Ravnborg if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) 5824d7365d6SSam Ravnborg return 1; 5834d7365d6SSam Ravnborg if (info->hdr->e_machine == EM_PPC) 5844d7365d6SSam Ravnborg /* Special register function linked on all modules during final link of .ko */ 5854d7365d6SSam Ravnborg if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 || 5864d7365d6SSam Ravnborg strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 || 5874d7365d6SSam Ravnborg strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || 5888fe9c93eSAndreas Schwab strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 || 5898fe9c93eSAndreas Schwab strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || 5908fe9c93eSAndreas Schwab strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) 5914d7365d6SSam Ravnborg return 1; 5927fca5dc8SStephen Rothwell if (info->hdr->e_machine == EM_PPC64) 5937fca5dc8SStephen Rothwell /* Special register function linked on all modules during final link of .ko */ 5947fca5dc8SStephen Rothwell if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || 5958fe9c93eSAndreas Schwab strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || 5968fe9c93eSAndreas Schwab strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || 597c153693dSAlan Modra strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 || 598c153693dSAlan Modra strcmp(symname, ".TOC.") == 0) 5997fca5dc8SStephen Rothwell return 1; 6004d7365d6SSam Ravnborg /* Do not ignore this symbol */ 6014d7365d6SSam Ravnborg return 0; 6024d7365d6SSam Ravnborg } 6034d7365d6SSam Ravnborg 604b92021b0SRusty Russell #define CRC_PFX VMLINUX_SYMBOL_STR(__crc_) 605b92021b0SRusty Russell #define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_) 6061da177e4SLinus Torvalds 6075c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info, 6081da177e4SLinus Torvalds Elf_Sym *sym, const char *symname) 6091da177e4SLinus Torvalds { 6101da177e4SLinus Torvalds unsigned int crc; 61162a26356SAlessio Igor Bogani enum export export; 612d8c1eb86SNicholas Piggin bool is_crc = false; 61362a26356SAlessio Igor Bogani 614258f7426SFrank Rowand if ((!is_vmlinux(mod->name) || mod->is_dot_o) && 615258f7426SFrank Rowand strncmp(symname, "__ksymtab", 9) == 0) 61662a26356SAlessio Igor Bogani export = export_from_secname(info, get_secindex(info, sym)); 61762a26356SAlessio Igor Bogani else 61862a26356SAlessio Igor Bogani export = export_from_sec(info, get_secindex(info, sym)); 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds /* CRC'd symbol */ 6218d99513cSMichal Marek if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { 622d8c1eb86SNicholas Piggin is_crc = true; 6231da177e4SLinus Torvalds crc = (unsigned int) sym->st_value; 624*56067812SArd Biesheuvel if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) { 625*56067812SArd Biesheuvel unsigned int *crcp; 626*56067812SArd Biesheuvel 627*56067812SArd Biesheuvel /* symbol points to the CRC in the ELF object */ 628*56067812SArd Biesheuvel crcp = (void *)info->hdr + sym->st_value + 629*56067812SArd Biesheuvel info->sechdrs[sym->st_shndx].sh_offset - 630*56067812SArd Biesheuvel (info->hdr->e_type != ET_REL ? 631*56067812SArd Biesheuvel info->sechdrs[sym->st_shndx].sh_addr : 0); 632*56067812SArd Biesheuvel crc = *crcp; 633*56067812SArd Biesheuvel } 634bd5cbcedSRam Pai sym_update_crc(symname + strlen(CRC_PFX), mod, crc, 635bd5cbcedSRam Pai export); 6361da177e4SLinus Torvalds } 637b5064654SAndi Kleen 638b5064654SAndi Kleen switch (sym->st_shndx) { 639b5064654SAndi Kleen case SHN_COMMON: 640ef178f92SAndi Kleen if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) { 641ef178f92SAndi Kleen /* Should warn here, but modpost runs before the linker */ 642ef178f92SAndi Kleen } else 643b5064654SAndi Kleen warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); 6441da177e4SLinus Torvalds break; 6451da177e4SLinus Torvalds case SHN_UNDEF: 6461da177e4SLinus Torvalds /* undefined symbol */ 6471da177e4SLinus Torvalds if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && 6481da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) != STB_WEAK) 6491da177e4SLinus Torvalds break; 6504d7365d6SSam Ravnborg if (ignore_undef_symbol(info, symname)) 6511da177e4SLinus Torvalds break; 6528d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ 6538d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) 6548d529014SBen Colline /* add compatibility with older glibc */ 6558d529014SBen Colline #ifndef STT_SPARC_REGISTER 6568d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER 6578d529014SBen Colline #endif 6581da177e4SLinus Torvalds if (info->hdr->e_machine == EM_SPARC || 6591da177e4SLinus Torvalds info->hdr->e_machine == EM_SPARCV9) { 6601da177e4SLinus Torvalds /* Ignore register directives. */ 6618d529014SBen Colline if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) 6621da177e4SLinus Torvalds break; 6637caaeabbSAl Viro if (symname[0] == '.') { 6647caaeabbSAl Viro char *munged = strdup(symname); 6657caaeabbSAl Viro munged[0] = '_'; 6667caaeabbSAl Viro munged[1] = toupper(munged[1]); 6677caaeabbSAl Viro symname = munged; 6687caaeabbSAl Viro } 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds #endif 6711da177e4SLinus Torvalds 672b92021b0SRusty Russell #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX 673b92021b0SRusty Russell if (symname[0] != '_') 674b92021b0SRusty Russell break; 675b92021b0SRusty Russell else 676b92021b0SRusty Russell symname++; 677b92021b0SRusty Russell #endif 678d8c1eb86SNicholas Piggin if (is_crc) { 679d8c1eb86SNicholas Piggin const char *e = is_vmlinux(mod->name) ?"":".ko"; 680d8c1eb86SNicholas Piggin warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", symname + strlen(CRC_PFX), mod->name, e); 681d8c1eb86SNicholas Piggin } 682b92021b0SRusty Russell mod->unres = alloc_symbol(symname, 6831da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) == STB_WEAK, 6841da177e4SLinus Torvalds mod->unres); 6851da177e4SLinus Torvalds break; 6861da177e4SLinus Torvalds default: 6871da177e4SLinus Torvalds /* All exported symbols */ 6888d99513cSMichal Marek if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { 689bd5cbcedSRam Pai sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, 690bd5cbcedSRam Pai export); 6911da177e4SLinus Torvalds } 692b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0) 6931da177e4SLinus Torvalds mod->has_init = 1; 694b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0) 6951da177e4SLinus Torvalds mod->has_cleanup = 1; 6961da177e4SLinus Torvalds break; 6971da177e4SLinus Torvalds } 6981da177e4SLinus Torvalds } 6991da177e4SLinus Torvalds 7005c3ead8cSSam Ravnborg /** 7015c3ead8cSSam Ravnborg * Parse tag=value strings from .modinfo section 7025c3ead8cSSam Ravnborg **/ 7031da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize) 7041da177e4SLinus Torvalds { 7051da177e4SLinus Torvalds /* Skip non-zero chars */ 7061da177e4SLinus Torvalds while (string[0]) { 7071da177e4SLinus Torvalds string++; 7081da177e4SLinus Torvalds if ((*secsize)-- <= 1) 7091da177e4SLinus Torvalds return NULL; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds /* Skip any zero padding. */ 7131da177e4SLinus Torvalds while (!string[0]) { 7141da177e4SLinus Torvalds string++; 7151da177e4SLinus Torvalds if ((*secsize)-- <= 1) 7161da177e4SLinus Torvalds return NULL; 7171da177e4SLinus Torvalds } 7181da177e4SLinus Torvalds return string; 7191da177e4SLinus Torvalds } 7201da177e4SLinus Torvalds 721b817f6feSSam Ravnborg static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, 722b817f6feSSam Ravnborg const char *tag, char *info) 7231da177e4SLinus Torvalds { 7241da177e4SLinus Torvalds char *p; 7251da177e4SLinus Torvalds unsigned int taglen = strlen(tag); 7261da177e4SLinus Torvalds unsigned long size = modinfo_len; 7271da177e4SLinus Torvalds 728b817f6feSSam Ravnborg if (info) { 729b817f6feSSam Ravnborg size -= info - (char *)modinfo; 730b817f6feSSam Ravnborg modinfo = next_string(info, &size); 731b817f6feSSam Ravnborg } 732b817f6feSSam Ravnborg 7331da177e4SLinus Torvalds for (p = modinfo; p; p = next_string(p, &size)) { 7341da177e4SLinus Torvalds if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') 7351da177e4SLinus Torvalds return p + taglen + 1; 7361da177e4SLinus Torvalds } 7371da177e4SLinus Torvalds return NULL; 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds 740b817f6feSSam Ravnborg static char *get_modinfo(void *modinfo, unsigned long modinfo_len, 741b817f6feSSam Ravnborg const char *tag) 742b817f6feSSam Ravnborg 743b817f6feSSam Ravnborg { 744b817f6feSSam Ravnborg return get_next_modinfo(modinfo, modinfo_len, tag, NULL); 745b817f6feSSam Ravnborg } 746b817f6feSSam Ravnborg 74793684d3bSSam Ravnborg /** 7484c8fbca5SSam Ravnborg * Test if string s ends in string sub 7494c8fbca5SSam Ravnborg * return 0 if match 7504c8fbca5SSam Ravnborg **/ 7514c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub) 7524c8fbca5SSam Ravnborg { 7534c8fbca5SSam Ravnborg int slen, sublen; 7544c8fbca5SSam Ravnborg 7554c8fbca5SSam Ravnborg if (!s || !sub) 7564c8fbca5SSam Ravnborg return 1; 7574c8fbca5SSam Ravnborg 7584c8fbca5SSam Ravnborg slen = strlen(s); 7594c8fbca5SSam Ravnborg sublen = strlen(sub); 7604c8fbca5SSam Ravnborg 7614c8fbca5SSam Ravnborg if ((slen == 0) || (sublen == 0)) 7624c8fbca5SSam Ravnborg return 1; 7634c8fbca5SSam Ravnborg 7644c8fbca5SSam Ravnborg if (sublen > slen) 7654c8fbca5SSam Ravnborg return 1; 7664c8fbca5SSam Ravnborg 7674c8fbca5SSam Ravnborg return memcmp(s + slen - sublen, sub, sublen); 7684c8fbca5SSam Ravnborg } 7694c8fbca5SSam Ravnborg 770ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) 771ff13f926SSam Ravnborg { 77258fb0d4fSSam Ravnborg if (sym) 773ff13f926SSam Ravnborg return elf->strtab + sym->st_name; 77458fb0d4fSSam Ravnborg else 775f666751aSSam Ravnborg return "(unknown)"; 776ff13f926SSam Ravnborg } 777ff13f926SSam Ravnborg 7781ce53adfSDenys Vlasenko static const char *sec_name(struct elf_info *elf, int secindex) 779ff13f926SSam Ravnborg { 780ff13f926SSam Ravnborg Elf_Shdr *sechdrs = elf->sechdrs; 781ff13f926SSam Ravnborg return (void *)elf->hdr + 7821ce53adfSDenys Vlasenko elf->sechdrs[elf->secindex_strings].sh_offset + 7831ce53adfSDenys Vlasenko sechdrs[secindex].sh_name; 784ff13f926SSam Ravnborg } 785ff13f926SSam Ravnborg 786ff13f926SSam Ravnborg static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) 787ff13f926SSam Ravnborg { 788ff13f926SSam Ravnborg return (void *)elf->hdr + 7891ce53adfSDenys Vlasenko elf->sechdrs[elf->secindex_strings].sh_offset + 790ff13f926SSam Ravnborg sechdr->sh_name; 791ff13f926SSam Ravnborg } 792ff13f926SSam Ravnborg 79310668220SSam Ravnborg /* The pattern is an array of simple patterns. 79410668220SSam Ravnborg * "foo" will match an exact string equal to "foo" 7956c5bd235SSam Ravnborg * "*foo" will match a string that ends with "foo" 79610668220SSam Ravnborg * "foo*" will match a string that begins with "foo" 79709c20c03SPaul Gortmaker * "*foo*" will match a string that contains "foo" 79810668220SSam Ravnborg */ 7995c725138STrevor Keith static int match(const char *sym, const char * const pat[]) 80010668220SSam Ravnborg { 80110668220SSam Ravnborg const char *p; 80210668220SSam Ravnborg while (*pat) { 80310668220SSam Ravnborg p = *pat++; 80410668220SSam Ravnborg const char *endp = p + strlen(p) - 1; 80510668220SSam Ravnborg 80609c20c03SPaul Gortmaker /* "*foo*" */ 80709c20c03SPaul Gortmaker if (*p == '*' && *endp == '*') { 80809c20c03SPaul Gortmaker char *here, *bare = strndup(p + 1, strlen(p) - 2); 80909c20c03SPaul Gortmaker 81009c20c03SPaul Gortmaker here = strstr(sym, bare); 81109c20c03SPaul Gortmaker free(bare); 81209c20c03SPaul Gortmaker if (here != NULL) 81309c20c03SPaul Gortmaker return 1; 81409c20c03SPaul Gortmaker } 8156c5bd235SSam Ravnborg /* "*foo" */ 81609c20c03SPaul Gortmaker else if (*p == '*') { 8176c5bd235SSam Ravnborg if (strrcmp(sym, p + 1) == 0) 8186c5bd235SSam Ravnborg return 1; 8196c5bd235SSam Ravnborg } 82010668220SSam Ravnborg /* "foo*" */ 8216c5bd235SSam Ravnborg else if (*endp == '*') { 82210668220SSam Ravnborg if (strncmp(sym, p, strlen(p) - 1) == 0) 82310668220SSam Ravnborg return 1; 82410668220SSam Ravnborg } 82510668220SSam Ravnborg /* no wildcards */ 82610668220SSam Ravnborg else { 82710668220SSam Ravnborg if (strcmp(p, sym) == 0) 82810668220SSam Ravnborg return 1; 82910668220SSam Ravnborg } 83010668220SSam Ravnborg } 83110668220SSam Ravnborg /* no match */ 83210668220SSam Ravnborg return 0; 83310668220SSam Ravnborg } 83410668220SSam Ravnborg 83510668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */ 8367a3ee753SMathias Krause static const char *const section_white_list[] = 8374391ed6aSSam Ravnborg { 8384391ed6aSSam Ravnborg ".comment*", 8394391ed6aSSam Ravnborg ".debug*", 8404d10c223SChen Gang ".cranges", /* sh64 */ 8411121584fSH.J. Lu ".zdebug*", /* Compressed debug sections. */ 842019fca84SDavid Howells ".GCC-command-line", /* mn10300 */ 84376b27645SJonathan Kliegman ".GCC.command.line", /* record-gcc-switches, non mn10300 */ 8444391ed6aSSam Ravnborg ".mdebug*", /* alpha, score, mips etc. */ 8454391ed6aSSam Ravnborg ".pdr", /* alpha, score, mips etc. */ 8464391ed6aSSam Ravnborg ".stab*", 8474391ed6aSSam Ravnborg ".note*", 8484391ed6aSSam Ravnborg ".got*", 8494391ed6aSSam Ravnborg ".toc*", 850af42e970SMax Filippov ".xt.prop", /* xtensa */ 851af42e970SMax Filippov ".xt.lit", /* xtensa */ 852f2e207f3SVineet Gupta ".arcextmap*", /* arc */ 853f2e207f3SVineet Gupta ".gnu.linkonce.arcext*", /* arc : modules */ 854d1189c63SNoam Camus ".cmem*", /* EZchip */ 855d1189c63SNoam Camus ".fmt_slot*", /* EZchip */ 856ef178f92SAndi Kleen ".gnu.lto*", 8574391ed6aSSam Ravnborg NULL 8584391ed6aSSam Ravnborg }; 85910668220SSam Ravnborg 860e241a630SSam Ravnborg /* 861b614a697SAnders Kaseorg * This is used to find sections missing the SHF_ALLOC flag. 862e241a630SSam Ravnborg * The cause of this is often a section specified in assembler 863b614a697SAnders Kaseorg * without "ax" / "aw". 864e241a630SSam Ravnborg */ 865b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf, 866b614a697SAnders Kaseorg Elf_Shdr *sechdr) 867e241a630SSam Ravnborg { 868b614a697SAnders Kaseorg const char *sec = sech_name(elf, sechdr); 869e241a630SSam Ravnborg 870b614a697SAnders Kaseorg if (sechdr->sh_type == SHT_PROGBITS && 871b614a697SAnders Kaseorg !(sechdr->sh_flags & SHF_ALLOC) && 872b614a697SAnders Kaseorg !match(sec, section_white_list)) { 873b614a697SAnders Kaseorg warn("%s (%s): unexpected non-allocatable section.\n" 874b614a697SAnders Kaseorg "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" 875e241a630SSam Ravnborg "Note that for example <linux/init.h> contains\n" 876e241a630SSam Ravnborg "section definitions for use in .S files.\n\n", 877e241a630SSam Ravnborg modname, sec); 878e241a630SSam Ravnborg } 879e241a630SSam Ravnborg } 880e241a630SSam Ravnborg 881e241a630SSam Ravnborg 882e241a630SSam Ravnborg 883eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \ 884a0d8f803SRasmus Villemoes ".init.setup", ".init.rodata", ".meminit.rodata", \ 885a0d8f803SRasmus Villemoes ".init.data", ".meminit.data" 886eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \ 887a0d8f803SRasmus Villemoes ".exit.data", ".memexit.data" 88810668220SSam Ravnborg 889eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \ 890a0d8f803SRasmus Villemoes ".init.text", ".meminit.text" 891eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \ 892a0d8f803SRasmus Villemoes ".exit.text", ".memexit.text" 89310668220SSam Ravnborg 894bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS \ 895a0d8f803SRasmus Villemoes ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \ 896a0d8f803SRasmus Villemoes ".pci_fixup_enable", ".pci_fixup_resume", \ 897a0d8f803SRasmus Villemoes ".pci_fixup_resume_early", ".pci_fixup_suspend" 898bb15d8dbSSebastian Andrzej Siewior 899e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS 900e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS 9014a31a229SUwe Kleine-König 9024a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS 9034a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS 90410668220SSam Ravnborg 905a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel" 906157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ 9076727ad9eSChris Metcalf ".kprobes.text", ".cpuidle.text" 90852dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ 909673c2c34SChris Metcalf ".fixup", ".entry.text", ".exception.text", ".text.*", \ 910673c2c34SChris Metcalf ".coldtext" 91110668220SSam Ravnborg 912fd6c3a8dSJan Beulich #define INIT_SECTIONS ".init.*" 913fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS ".meminit.*" 914eb8f6890SSam Ravnborg 915fd6c3a8dSJan Beulich #define EXIT_SECTIONS ".exit.*" 916fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS ".memexit.*" 917eb8f6890SSam Ravnborg 91852dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \ 91952dc0595SQuentin Casasnovas TEXT_SECTIONS, OTHER_TEXT_SECTIONS 92052dc0595SQuentin Casasnovas 9216c5bd235SSam Ravnborg /* init data sections */ 9227a3ee753SMathias Krause static const char *const init_data_sections[] = 9237a3ee753SMathias Krause { ALL_INIT_DATA_SECTIONS, NULL }; 9246c5bd235SSam Ravnborg 9256c5bd235SSam Ravnborg /* all init sections */ 9267a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; 9276c5bd235SSam Ravnborg 9286c5bd235SSam Ravnborg /* All init and exit sections (code + data) */ 9297a3ee753SMathias Krause static const char *const init_exit_sections[] = 930eb8f6890SSam Ravnborg {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; 9316c5bd235SSam Ravnborg 9324a3893d0SPaul Gortmaker /* all text sections */ 9334a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL }; 9344a3893d0SPaul Gortmaker 9356c5bd235SSam Ravnborg /* data section */ 9367a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL }; 9376c5bd235SSam Ravnborg 9386c5bd235SSam Ravnborg 9396c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */ 940af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST \ 941af92a82dSUwe Kleine-König "*driver", \ 942af92a82dSUwe Kleine-König "*_template", /* scsi uses *_template a lot */ \ 943af92a82dSUwe Kleine-König "*_timer", /* arm uses ops structures named _timer a lot */ \ 944af92a82dSUwe Kleine-König "*_sht", /* scsi also used *_sht to some extent */ \ 945af92a82dSUwe Kleine-König "*_ops", \ 946af92a82dSUwe Kleine-König "*_probe", \ 947af92a82dSUwe Kleine-König "*_probe_one", \ 948af92a82dSUwe Kleine-König "*_console" 9496c5bd235SSam Ravnborg 9507a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL }; 9517a3ee753SMathias Krause static const char *const linker_symbols[] = 9526c5bd235SSam Ravnborg { "__init_begin", "_sinittext", "_einittext", NULL }; 9534a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL }; 9546c5bd235SSam Ravnborg 955588ccd73SSam Ravnborg enum mismatch { 956bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_INIT, 957bbd3f4fbSUwe Kleine-König DATA_TO_ANY_INIT, 958bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_EXIT, 959bbd3f4fbSUwe Kleine-König DATA_TO_ANY_EXIT, 960bbd3f4fbSUwe Kleine-König XXXINIT_TO_SOME_INIT, 961bbd3f4fbSUwe Kleine-König XXXEXIT_TO_SOME_EXIT, 962bbd3f4fbSUwe Kleine-König ANY_INIT_TO_ANY_EXIT, 963bbd3f4fbSUwe Kleine-König ANY_EXIT_TO_ANY_INIT, 964588ccd73SSam Ravnborg EXPORT_TO_INIT_EXIT, 96552dc0595SQuentin Casasnovas EXTABLE_TO_NON_TEXT, 966588ccd73SSam Ravnborg }; 967588ccd73SSam Ravnborg 968e5d8f59aSQuentin Casasnovas /** 969e5d8f59aSQuentin Casasnovas * Describe how to match sections on different criterias: 970e5d8f59aSQuentin Casasnovas * 971e5d8f59aSQuentin Casasnovas * @fromsec: Array of sections to be matched. 972e5d8f59aSQuentin Casasnovas * 973e5d8f59aSQuentin Casasnovas * @bad_tosec: Relocations applied to a section in @fromsec to a section in 974e5d8f59aSQuentin Casasnovas * this array is forbidden (black-list). Can be empty. 975e5d8f59aSQuentin Casasnovas * 976e5d8f59aSQuentin Casasnovas * @good_tosec: Relocations applied to a section in @fromsec must be 977e5d8f59aSQuentin Casasnovas * targetting sections in this array (white-list). Can be empty. 978e5d8f59aSQuentin Casasnovas * 979e5d8f59aSQuentin Casasnovas * @mismatch: Type of mismatch. 980e5d8f59aSQuentin Casasnovas * 981e5d8f59aSQuentin Casasnovas * @symbol_white_list: Do not match a relocation to a symbol in this list 982e5d8f59aSQuentin Casasnovas * even if it is targetting a section in @bad_to_sec. 983e5d8f59aSQuentin Casasnovas * 984e5d8f59aSQuentin Casasnovas * @handler: Specific handler to call when a match is found. If NULL, 985e5d8f59aSQuentin Casasnovas * default_mismatch_handler() will be called. 986e5d8f59aSQuentin Casasnovas * 987e5d8f59aSQuentin Casasnovas */ 98810668220SSam Ravnborg struct sectioncheck { 98910668220SSam Ravnborg const char *fromsec[20]; 990050e57fdSQuentin Casasnovas const char *bad_tosec[20]; 991050e57fdSQuentin Casasnovas const char *good_tosec[20]; 992588ccd73SSam Ravnborg enum mismatch mismatch; 993af92a82dSUwe Kleine-König const char *symbol_white_list[20]; 994644e8f14SQuentin Casasnovas void (*handler)(const char *modname, struct elf_info *elf, 995644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 996644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec); 997644e8f14SQuentin Casasnovas 99810668220SSam Ravnborg }; 99910668220SSam Ravnborg 100052dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf, 100152dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 100252dc0595SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, 100352dc0595SQuentin Casasnovas const char *fromsec); 100452dc0595SQuentin Casasnovas 10057a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = { 100610668220SSam Ravnborg /* Do not reference init/exit code/data from 100710668220SSam Ravnborg * normal code and data 100810668220SSam Ravnborg */ 100910668220SSam Ravnborg { 1010588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 1011050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 1012bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_INIT, 1013af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1014588ccd73SSam Ravnborg }, 1015588ccd73SSam Ravnborg { 1016588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 1017050e57fdSQuentin Casasnovas .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, 1018bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 1019af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1020588ccd73SSam Ravnborg }, 1021588ccd73SSam Ravnborg { 10220db25245SUwe Kleine-König .fromsec = { DATA_SECTIONS, NULL }, 1023050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 10240db25245SUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 10250db25245SUwe Kleine-König .symbol_white_list = { 10260db25245SUwe Kleine-König "*_template", "*_timer", "*_sht", "*_ops", 10270db25245SUwe Kleine-König "*_probe", "*_probe_one", "*_console", NULL 10280db25245SUwe Kleine-König }, 10290db25245SUwe Kleine-König }, 10300db25245SUwe Kleine-König { 1031588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 1032050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1033bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_EXIT, 1034af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1035588ccd73SSam Ravnborg }, 1036588ccd73SSam Ravnborg { 1037588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 1038050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1039bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_EXIT, 1040af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1041eb8f6890SSam Ravnborg }, 1042e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */ 1043eb8f6890SSam Ravnborg { 10444a31a229SUwe Kleine-König .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, 1045050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1046bbd3f4fbSUwe Kleine-König .mismatch = XXXINIT_TO_SOME_INIT, 1047af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1048eb8f6890SSam Ravnborg }, 1049e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */ 1050eb8f6890SSam Ravnborg { 10514a31a229SUwe Kleine-König .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, 1052050e57fdSQuentin Casasnovas .bad_tosec = { EXIT_SECTIONS, NULL }, 1053bbd3f4fbSUwe Kleine-König .mismatch = XXXEXIT_TO_SOME_EXIT, 1054af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 105510668220SSam Ravnborg }, 105610668220SSam Ravnborg /* Do not use exit code/data from init code */ 105710668220SSam Ravnborg { 1058eb8f6890SSam Ravnborg .fromsec = { ALL_INIT_SECTIONS, NULL }, 1059050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1060bbd3f4fbSUwe Kleine-König .mismatch = ANY_INIT_TO_ANY_EXIT, 1061af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 106210668220SSam Ravnborg }, 106310668220SSam Ravnborg /* Do not use init code/data from exit code */ 106410668220SSam Ravnborg { 1065eb8f6890SSam Ravnborg .fromsec = { ALL_EXIT_SECTIONS, NULL }, 1066050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 1067bbd3f4fbSUwe Kleine-König .mismatch = ANY_EXIT_TO_ANY_INIT, 1068af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 106910668220SSam Ravnborg }, 1070bb15d8dbSSebastian Andrzej Siewior { 1071bb15d8dbSSebastian Andrzej Siewior .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, 1072050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1073bb15d8dbSSebastian Andrzej Siewior .mismatch = ANY_INIT_TO_ANY_EXIT, 1074bb15d8dbSSebastian Andrzej Siewior .symbol_white_list = { NULL }, 1075bb15d8dbSSebastian Andrzej Siewior }, 107610668220SSam Ravnborg /* Do not export init/exit functions or data */ 107710668220SSam Ravnborg { 107810668220SSam Ravnborg .fromsec = { "__ksymtab*", NULL }, 1079050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, 1080af92a82dSUwe Kleine-König .mismatch = EXPORT_TO_INIT_EXIT, 1081af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 108252dc0595SQuentin Casasnovas }, 108352dc0595SQuentin Casasnovas { 108452dc0595SQuentin Casasnovas .fromsec = { "__ex_table", NULL }, 108552dc0595SQuentin Casasnovas /* If you're adding any new black-listed sections in here, consider 108652dc0595SQuentin Casasnovas * adding a special 'printer' for them in scripts/check_extable. 108752dc0595SQuentin Casasnovas */ 108852dc0595SQuentin Casasnovas .bad_tosec = { ".altinstr_replacement", NULL }, 108952dc0595SQuentin Casasnovas .good_tosec = {ALL_TEXT_SECTIONS , NULL}, 109052dc0595SQuentin Casasnovas .mismatch = EXTABLE_TO_NON_TEXT, 109152dc0595SQuentin Casasnovas .handler = extable_mismatch_handler, 109210668220SSam Ravnborg } 109310668220SSam Ravnborg }; 109410668220SSam Ravnborg 10950d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch( 10960d2a636eSUwe Kleine-König const char *fromsec, const char *tosec) 109710668220SSam Ravnborg { 109810668220SSam Ravnborg int i; 109910668220SSam Ravnborg int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); 110010668220SSam Ravnborg const struct sectioncheck *check = §ioncheck[0]; 110110668220SSam Ravnborg 1102c5c3439aSQuentin Casasnovas /* 1103c5c3439aSQuentin Casasnovas * The target section could be the SHT_NUL section when we're 1104c5c3439aSQuentin Casasnovas * handling relocations to un-resolved symbols, trying to match it 1105c5c3439aSQuentin Casasnovas * doesn't make much sense and causes build failures on parisc and 1106c5c3439aSQuentin Casasnovas * mn10300 architectures. 1107c5c3439aSQuentin Casasnovas */ 1108c5c3439aSQuentin Casasnovas if (*tosec == '\0') 1109c5c3439aSQuentin Casasnovas return NULL; 1110c5c3439aSQuentin Casasnovas 111110668220SSam Ravnborg for (i = 0; i < elems; i++) { 1112050e57fdSQuentin Casasnovas if (match(fromsec, check->fromsec)) { 1113050e57fdSQuentin Casasnovas if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) 11140d2a636eSUwe Kleine-König return check; 1115050e57fdSQuentin Casasnovas if (check->good_tosec[0] && !match(tosec, check->good_tosec)) 1116050e57fdSQuentin Casasnovas return check; 1117050e57fdSQuentin Casasnovas } 111810668220SSam Ravnborg check++; 111910668220SSam Ravnborg } 11200d2a636eSUwe Kleine-König return NULL; 112110668220SSam Ravnborg } 112210668220SSam Ravnborg 11234c8fbca5SSam Ravnborg /** 11244c8fbca5SSam Ravnborg * Whitelist to allow certain references to pass with no warning. 11250e0d314eSSam Ravnborg * 11264c8fbca5SSam Ravnborg * Pattern 1: 11274c8fbca5SSam Ravnborg * If a module parameter is declared __initdata and permissions=0 11284c8fbca5SSam Ravnborg * then this is legal despite the warning generated. 11294c8fbca5SSam Ravnborg * We cannot see value of permissions here, so just ignore 11304c8fbca5SSam Ravnborg * this pattern. 11314c8fbca5SSam Ravnborg * The pattern is identified by: 11324c8fbca5SSam Ravnborg * tosec = .init.data 11339209aed0SSam Ravnborg * fromsec = .data* 11344c8fbca5SSam Ravnborg * atsym =__param* 11354c8fbca5SSam Ravnborg * 11366a841528SRusty Russell * Pattern 1a: 11376a841528SRusty Russell * module_param_call() ops can refer to __init set function if permissions=0 11386a841528SRusty Russell * The pattern is identified by: 11396a841528SRusty Russell * tosec = .init.text 11406a841528SRusty Russell * fromsec = .data* 11416a841528SRusty Russell * atsym = __param_ops_* 11426a841528SRusty Russell * 11434c8fbca5SSam Ravnborg * Pattern 2: 114472ee59b5SRandy Dunlap * Many drivers utilise a *driver container with references to 11454c8fbca5SSam Ravnborg * add, remove, probe functions etc. 11464c8fbca5SSam Ravnborg * the pattern is identified by: 114783cda2bbSSam Ravnborg * tosec = init or exit section 114883cda2bbSSam Ravnborg * fromsec = data section 1149df578e7dSSam Ravnborg * atsym = *driver, *_template, *_sht, *_ops, *_probe, 1150df578e7dSSam Ravnborg * *probe_one, *_console, *_timer 1151ee6a8545SVivek Goyal * 1152ee6a8545SVivek Goyal * Pattern 3: 1153c993971fSSam Ravnborg * Whitelist all references from .head.text to any init section 11549bf8cb9bSSam Ravnborg * 11551d8af559SSam Ravnborg * Pattern 4: 1156ee6a8545SVivek Goyal * Some symbols belong to init section but still it is ok to reference 1157ee6a8545SVivek Goyal * these from non-init sections as these symbols don't have any memory 1158ee6a8545SVivek Goyal * allocated for them and symbol address and value are same. So even 1159ee6a8545SVivek Goyal * if init section is freed, its ok to reference those symbols. 1160ee6a8545SVivek Goyal * For ex. symbols marking the init section boundaries. 1161ee6a8545SVivek Goyal * This pattern is identified by 1162ee6a8545SVivek Goyal * refsymname = __init_begin, _sinittext, _einittext 11639bf8cb9bSSam Ravnborg * 11644a3893d0SPaul Gortmaker * Pattern 5: 11654a3893d0SPaul Gortmaker * GCC may optimize static inlines when fed constant arg(s) resulting 11664a3893d0SPaul Gortmaker * in functions like cpumask_empty() -- generating an associated symbol 11674a3893d0SPaul Gortmaker * cpumask_empty.constprop.3 that appears in the audit. If the const that 11684a3893d0SPaul Gortmaker * is passed in comes from __init, like say nmi_ipi_mask, we get a 11694a3893d0SPaul Gortmaker * meaningless section warning. May need to add isra symbols too... 11704a3893d0SPaul Gortmaker * This pattern is identified by 11714a3893d0SPaul Gortmaker * tosec = init section 11724a3893d0SPaul Gortmaker * fromsec = text section 11734a3893d0SPaul Gortmaker * refsymname = *.constprop.* 11744a3893d0SPaul Gortmaker * 11754c8fbca5SSam Ravnborg **/ 1176af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch, 1177af92a82dSUwe Kleine-König const char *fromsec, const char *fromsym, 117858fb0d4fSSam Ravnborg const char *tosec, const char *tosym) 11794c8fbca5SSam Ravnborg { 11804c8fbca5SSam Ravnborg /* Check for pattern 1 */ 11816c5bd235SSam Ravnborg if (match(tosec, init_data_sections) && 11826c5bd235SSam Ravnborg match(fromsec, data_sections) && 118358fb0d4fSSam Ravnborg (strncmp(fromsym, "__param", strlen("__param")) == 0)) 118458fb0d4fSSam Ravnborg return 0; 11854c8fbca5SSam Ravnborg 11866a841528SRusty Russell /* Check for pattern 1a */ 11876a841528SRusty Russell if (strcmp(tosec, ".init.text") == 0 && 11886a841528SRusty Russell match(fromsec, data_sections) && 11896a841528SRusty Russell (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0)) 11906a841528SRusty Russell return 0; 11916a841528SRusty Russell 11924c8fbca5SSam Ravnborg /* Check for pattern 2 */ 11936c5bd235SSam Ravnborg if (match(tosec, init_exit_sections) && 11946c5bd235SSam Ravnborg match(fromsec, data_sections) && 1195af92a82dSUwe Kleine-König match(fromsym, mismatch->symbol_white_list)) 119658fb0d4fSSam Ravnborg return 0; 11974c8fbca5SSam Ravnborg 11989bf8cb9bSSam Ravnborg /* Check for pattern 3 */ 11996c5bd235SSam Ravnborg if (match(fromsec, head_sections) && 12006c5bd235SSam Ravnborg match(tosec, init_sections)) 120158fb0d4fSSam Ravnborg return 0; 1202f8657e1bSVivek Goyal 12031d8af559SSam Ravnborg /* Check for pattern 4 */ 120458fb0d4fSSam Ravnborg if (match(tosym, linker_symbols)) 120593659af1SSam Ravnborg return 0; 120658fb0d4fSSam Ravnborg 12074a3893d0SPaul Gortmaker /* Check for pattern 5 */ 12084a3893d0SPaul Gortmaker if (match(fromsec, text_sections) && 12094a3893d0SPaul Gortmaker match(tosec, init_sections) && 12104a3893d0SPaul Gortmaker match(fromsym, optim_symbols)) 12114a3893d0SPaul Gortmaker return 0; 12124a3893d0SPaul Gortmaker 121358fb0d4fSSam Ravnborg return 1; 12144c8fbca5SSam Ravnborg } 12154c8fbca5SSam Ravnborg 12164c8fbca5SSam Ravnborg /** 121793684d3bSSam Ravnborg * Find symbol based on relocation record info. 121893684d3bSSam Ravnborg * In some cases the symbol supplied is a valid symbol so 121993684d3bSSam Ravnborg * return refsym. If st_name != 0 we assume this is a valid symbol. 122093684d3bSSam Ravnborg * In other cases the symbol needs to be looked up in the symbol table 122193684d3bSSam Ravnborg * based on section and address. 122293684d3bSSam Ravnborg * **/ 12239ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, 122493684d3bSSam Ravnborg Elf_Sym *relsym) 122593684d3bSSam Ravnborg { 122693684d3bSSam Ravnborg Elf_Sym *sym; 12279ad21c3fSSam Ravnborg Elf_Sym *near = NULL; 12289ad21c3fSSam Ravnborg Elf64_Sword distance = 20; 12299ad21c3fSSam Ravnborg Elf64_Sword d; 12301ce53adfSDenys Vlasenko unsigned int relsym_secindex; 123193684d3bSSam Ravnborg 123293684d3bSSam Ravnborg if (relsym->st_name != 0) 123393684d3bSSam Ravnborg return relsym; 12341ce53adfSDenys Vlasenko 12351ce53adfSDenys Vlasenko relsym_secindex = get_secindex(elf, relsym); 123693684d3bSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 12371ce53adfSDenys Vlasenko if (get_secindex(elf, sym) != relsym_secindex) 123893684d3bSSam Ravnborg continue; 1239ae4ac123SAtsushi Nemoto if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) 1240ae4ac123SAtsushi Nemoto continue; 124193684d3bSSam Ravnborg if (sym->st_value == addr) 124293684d3bSSam Ravnborg return sym; 12439ad21c3fSSam Ravnborg /* Find a symbol nearby - addr are maybe negative */ 12449ad21c3fSSam Ravnborg d = sym->st_value - addr; 12459ad21c3fSSam Ravnborg if (d < 0) 12469ad21c3fSSam Ravnborg d = addr - sym->st_value; 12479ad21c3fSSam Ravnborg if (d < distance) { 12489ad21c3fSSam Ravnborg distance = d; 12499ad21c3fSSam Ravnborg near = sym; 125093684d3bSSam Ravnborg } 12519ad21c3fSSam Ravnborg } 12529ad21c3fSSam Ravnborg /* We need a close match */ 12539ad21c3fSSam Ravnborg if (distance < 20) 12549ad21c3fSSam Ravnborg return near; 12559ad21c3fSSam Ravnborg else 125693684d3bSSam Ravnborg return NULL; 125793684d3bSSam Ravnborg } 125893684d3bSSam Ravnborg 1259da68d61fSDavid Brownell static inline int is_arm_mapping_symbol(const char *str) 1260da68d61fSDavid Brownell { 12616c34f1f5SKyle McMartin return str[0] == '$' && strchr("axtd", str[1]) 1262da68d61fSDavid Brownell && (str[2] == '\0' || str[2] == '.'); 1263da68d61fSDavid Brownell } 1264da68d61fSDavid Brownell 1265da68d61fSDavid Brownell /* 1266da68d61fSDavid Brownell * If there's no name there, ignore it; likewise, ignore it if it's 1267da68d61fSDavid Brownell * one of the magic symbols emitted used by current ARM tools. 1268da68d61fSDavid Brownell * 1269da68d61fSDavid Brownell * Otherwise if find_symbols_between() returns those symbols, they'll 1270da68d61fSDavid Brownell * fail the whitelist tests and cause lots of false alarms ... fixable 1271da68d61fSDavid Brownell * only by merging __exit and __init sections into __text, bloating 1272da68d61fSDavid Brownell * the kernel (which is especially evil on embedded platforms). 1273da68d61fSDavid Brownell */ 1274da68d61fSDavid Brownell static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym) 1275da68d61fSDavid Brownell { 1276da68d61fSDavid Brownell const char *name = elf->strtab + sym->st_name; 1277da68d61fSDavid Brownell 1278da68d61fSDavid Brownell if (!name || !strlen(name)) 1279da68d61fSDavid Brownell return 0; 1280da68d61fSDavid Brownell return !is_arm_mapping_symbol(name); 1281da68d61fSDavid Brownell } 1282da68d61fSDavid Brownell 1283b39927cfSSam Ravnborg /* 128443c74d17SSam Ravnborg * Find symbols before or equal addr and after addr - in the section sec. 128543c74d17SSam Ravnborg * If we find two symbols with equal offset prefer one with a valid name. 128643c74d17SSam Ravnborg * The ELF format may have a better way to detect what type of symbol 128743c74d17SSam Ravnborg * it is, but this works for now. 1288b39927cfSSam Ravnborg **/ 1289157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, 1290157c23c8SSam Ravnborg const char *sec) 1291b39927cfSSam Ravnborg { 1292b39927cfSSam Ravnborg Elf_Sym *sym; 1293157c23c8SSam Ravnborg Elf_Sym *near = NULL; 1294157c23c8SSam Ravnborg Elf_Addr distance = ~0; 1295b39927cfSSam Ravnborg 1296b39927cfSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 1297b39927cfSSam Ravnborg const char *symsec; 1298b39927cfSSam Ravnborg 12991ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1300b39927cfSSam Ravnborg continue; 13011ce53adfSDenys Vlasenko symsec = sec_name(elf, get_secindex(elf, sym)); 1302b39927cfSSam Ravnborg if (strcmp(symsec, sec) != 0) 1303b39927cfSSam Ravnborg continue; 1304da68d61fSDavid Brownell if (!is_valid_name(elf, sym)) 1305da68d61fSDavid Brownell continue; 1306b39927cfSSam Ravnborg if (sym->st_value <= addr) { 1307157c23c8SSam Ravnborg if ((addr - sym->st_value) < distance) { 1308157c23c8SSam Ravnborg distance = addr - sym->st_value; 1309157c23c8SSam Ravnborg near = sym; 1310157c23c8SSam Ravnborg } else if ((addr - sym->st_value) == distance) { 1311157c23c8SSam Ravnborg near = sym; 131243c74d17SSam Ravnborg } 1313b39927cfSSam Ravnborg } 1314b39927cfSSam Ravnborg } 1315157c23c8SSam Ravnborg return near; 1316157c23c8SSam Ravnborg } 1317b39927cfSSam Ravnborg 131858fb0d4fSSam Ravnborg /* 1319588ccd73SSam Ravnborg * Convert a section name to the function/data attribute 1320588ccd73SSam Ravnborg * .init.text => __init 1321588ccd73SSam Ravnborg * .memexitconst => __memconst 1322588ccd73SSam Ravnborg * etc. 1323cbcf14a9SAndy Shevchenko * 1324cbcf14a9SAndy Shevchenko * The memory of returned value has been allocated on a heap. The user of this 1325cbcf14a9SAndy Shevchenko * method should free it after usage. 1326588ccd73SSam Ravnborg */ 1327588ccd73SSam Ravnborg static char *sec2annotation(const char *s) 1328588ccd73SSam Ravnborg { 1329588ccd73SSam Ravnborg if (match(s, init_exit_sections)) { 1330588ccd73SSam Ravnborg char *p = malloc(20); 1331588ccd73SSam Ravnborg char *r = p; 1332588ccd73SSam Ravnborg 1333588ccd73SSam Ravnborg *p++ = '_'; 1334588ccd73SSam Ravnborg *p++ = '_'; 1335588ccd73SSam Ravnborg if (*s == '.') 1336588ccd73SSam Ravnborg s++; 1337588ccd73SSam Ravnborg while (*s && *s != '.') 1338588ccd73SSam Ravnborg *p++ = *s++; 1339588ccd73SSam Ravnborg *p = '\0'; 1340588ccd73SSam Ravnborg if (*s == '.') 1341588ccd73SSam Ravnborg s++; 1342588ccd73SSam Ravnborg if (strstr(s, "rodata") != NULL) 1343588ccd73SSam Ravnborg strcat(p, "const "); 1344588ccd73SSam Ravnborg else if (strstr(s, "data") != NULL) 1345588ccd73SSam Ravnborg strcat(p, "data "); 1346588ccd73SSam Ravnborg else 1347588ccd73SSam Ravnborg strcat(p, " "); 1348cbcf14a9SAndy Shevchenko return r; 1349588ccd73SSam Ravnborg } else { 13505003bab8SAndrew Morton return strdup(""); 1351588ccd73SSam Ravnborg } 1352588ccd73SSam Ravnborg } 1353588ccd73SSam Ravnborg 1354588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym) 1355588ccd73SSam Ravnborg { 1356588ccd73SSam Ravnborg if (sym) 1357588ccd73SSam Ravnborg return ELF_ST_TYPE(sym->st_info) == STT_FUNC; 1358588ccd73SSam Ravnborg else 1359f666751aSSam Ravnborg return -1; 1360588ccd73SSam Ravnborg } 1361588ccd73SSam Ravnborg 136200759c0eSRandy Dunlap static void print_section_list(const char * const list[20]) 136300759c0eSRandy Dunlap { 136400759c0eSRandy Dunlap const char *const *s = list; 136500759c0eSRandy Dunlap 136600759c0eSRandy Dunlap while (*s) { 136700759c0eSRandy Dunlap fprintf(stderr, "%s", *s); 136800759c0eSRandy Dunlap s++; 136900759c0eSRandy Dunlap if (*s) 137000759c0eSRandy Dunlap fprintf(stderr, ", "); 137100759c0eSRandy Dunlap } 137200759c0eSRandy Dunlap fprintf(stderr, "\n"); 137300759c0eSRandy Dunlap } 137400759c0eSRandy Dunlap 1375356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p) 1376356ad538SQuentin Casasnovas { 1377356ad538SQuentin Casasnovas switch (is_func) { 1378356ad538SQuentin Casasnovas case 0: *name = "variable"; *name_p = ""; break; 1379356ad538SQuentin Casasnovas case 1: *name = "function"; *name_p = "()"; break; 1380356ad538SQuentin Casasnovas default: *name = "(unknown reference)"; *name_p = ""; break; 1381356ad538SQuentin Casasnovas } 1382356ad538SQuentin Casasnovas } 1383356ad538SQuentin Casasnovas 1384588ccd73SSam Ravnborg /* 1385b39927cfSSam Ravnborg * Print a warning about a section mismatch. 1386b39927cfSSam Ravnborg * Try to find symbols near it so user can find it. 13874c8fbca5SSam Ravnborg * Check whitelist before warning - it may be a false positive. 138858fb0d4fSSam Ravnborg */ 13890d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname, 13900d2a636eSUwe Kleine-König const struct sectioncheck *mismatch, 139158fb0d4fSSam Ravnborg const char *fromsec, 139258fb0d4fSSam Ravnborg unsigned long long fromaddr, 139358fb0d4fSSam Ravnborg const char *fromsym, 1394588ccd73SSam Ravnborg int from_is_func, 1395588ccd73SSam Ravnborg const char *tosec, const char *tosym, 1396588ccd73SSam Ravnborg int to_is_func) 1397b39927cfSSam Ravnborg { 1398588ccd73SSam Ravnborg const char *from, *from_p; 1399588ccd73SSam Ravnborg const char *to, *to_p; 140037ed19d5SAlexey Fomenko char *prl_from; 140137ed19d5SAlexey Fomenko char *prl_to; 1402f666751aSSam Ravnborg 1403e5f95c8bSSam Ravnborg sec_mismatch_count++; 1404e5f95c8bSSam Ravnborg if (!sec_mismatch_verbose) 1405e5f95c8bSSam Ravnborg return; 1406e5f95c8bSSam Ravnborg 1407356ad538SQuentin Casasnovas get_pretty_name(from_is_func, &from, &from_p); 1408356ad538SQuentin Casasnovas get_pretty_name(to_is_func, &to, &to_p); 1409356ad538SQuentin Casasnovas 14107c0ac495SGeert Uytterhoeven warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " 14117c0ac495SGeert Uytterhoeven "to the %s %s:%s%s\n", 14127c0ac495SGeert Uytterhoeven modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, 14137c0ac495SGeert Uytterhoeven tosym, to_p); 1414588ccd73SSam Ravnborg 14150d2a636eSUwe Kleine-König switch (mismatch->mismatch) { 1416bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_INIT: 141737ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 141837ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1419588ccd73SSam Ravnborg fprintf(stderr, 1420588ccd73SSam Ravnborg "The function %s%s() references\n" 1421588ccd73SSam Ravnborg "the %s %s%s%s.\n" 1422588ccd73SSam Ravnborg "This is often because %s lacks a %s\n" 1423588ccd73SSam Ravnborg "annotation or the annotation of %s is wrong.\n", 142437ed19d5SAlexey Fomenko prl_from, fromsym, 142537ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 142637ed19d5SAlexey Fomenko fromsym, prl_to, tosym); 142737ed19d5SAlexey Fomenko free(prl_from); 142837ed19d5SAlexey Fomenko free(prl_to); 1429588ccd73SSam Ravnborg break; 1430bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_INIT: { 143137ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1432588ccd73SSam Ravnborg fprintf(stderr, 1433588ccd73SSam Ravnborg "The variable %s references\n" 1434588ccd73SSam Ravnborg "the %s %s%s%s\n" 1435588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 14368b8b76c0SSam Ravnborg "variable with __init* or __refdata (see linux/init.h) " 1437588ccd73SSam Ravnborg "or name the variable:\n", 143837ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 143900759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 144037ed19d5SAlexey Fomenko free(prl_to); 1441588ccd73SSam Ravnborg break; 144258fb0d4fSSam Ravnborg } 1443bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_EXIT: 144437ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1445588ccd73SSam Ravnborg fprintf(stderr, 1446588ccd73SSam Ravnborg "The function %s() references a %s in an exit section.\n" 1447588ccd73SSam Ravnborg "Often the %s %s%s has valid usage outside the exit section\n" 1448588ccd73SSam Ravnborg "and the fix is to remove the %sannotation of %s.\n", 144937ed19d5SAlexey Fomenko fromsym, to, to, tosym, to_p, prl_to, tosym); 145037ed19d5SAlexey Fomenko free(prl_to); 1451588ccd73SSam Ravnborg break; 1452bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_EXIT: { 145337ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1454588ccd73SSam Ravnborg fprintf(stderr, 1455588ccd73SSam Ravnborg "The variable %s references\n" 1456588ccd73SSam Ravnborg "the %s %s%s%s\n" 1457588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 1458588ccd73SSam Ravnborg "variable with __exit* (see linux/init.h) or " 1459588ccd73SSam Ravnborg "name the variable:\n", 146037ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 146100759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 146237ed19d5SAlexey Fomenko free(prl_to); 1463588ccd73SSam Ravnborg break; 1464588ccd73SSam Ravnborg } 1465bbd3f4fbSUwe Kleine-König case XXXINIT_TO_SOME_INIT: 1466bbd3f4fbSUwe Kleine-König case XXXEXIT_TO_SOME_EXIT: 146737ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 146837ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1469588ccd73SSam Ravnborg fprintf(stderr, 1470588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1471588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1472588ccd73SSam Ravnborg "If %s is only used by %s then\n" 1473588ccd73SSam Ravnborg "annotate %s with a matching annotation.\n", 147437ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 147537ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 1476b1d2675aSGeert Uytterhoeven tosym, fromsym, tosym); 147737ed19d5SAlexey Fomenko free(prl_from); 147837ed19d5SAlexey Fomenko free(prl_to); 1479588ccd73SSam Ravnborg break; 1480bbd3f4fbSUwe Kleine-König case ANY_INIT_TO_ANY_EXIT: 148137ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 148237ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1483588ccd73SSam Ravnborg fprintf(stderr, 1484588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1485588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1486588ccd73SSam Ravnborg "This is often seen when error handling " 1487588ccd73SSam Ravnborg "in the init function\n" 1488588ccd73SSam Ravnborg "uses functionality in the exit path.\n" 1489588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1490588ccd73SSam Ravnborg "%s%s so it may be used outside an exit section.\n", 149137ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 149237ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 14935003bab8SAndrew Morton prl_to, tosym, to_p); 149437ed19d5SAlexey Fomenko free(prl_from); 149537ed19d5SAlexey Fomenko free(prl_to); 1496588ccd73SSam Ravnborg break; 1497bbd3f4fbSUwe Kleine-König case ANY_EXIT_TO_ANY_INIT: 149837ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 149937ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1500588ccd73SSam Ravnborg fprintf(stderr, 1501588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1502588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1503588ccd73SSam Ravnborg "This is often seen when error handling " 1504588ccd73SSam Ravnborg "in the exit function\n" 1505588ccd73SSam Ravnborg "uses functionality in the init path.\n" 1506588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1507588ccd73SSam Ravnborg "%s%s so it may be used outside an init section.\n", 150837ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 150937ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 151037ed19d5SAlexey Fomenko prl_to, tosym, to_p); 151137ed19d5SAlexey Fomenko free(prl_from); 151237ed19d5SAlexey Fomenko free(prl_to); 1513588ccd73SSam Ravnborg break; 1514588ccd73SSam Ravnborg case EXPORT_TO_INIT_EXIT: 151537ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1516588ccd73SSam Ravnborg fprintf(stderr, 1517588ccd73SSam Ravnborg "The symbol %s is exported and annotated %s\n" 1518588ccd73SSam Ravnborg "Fix this by removing the %sannotation of %s " 1519588ccd73SSam Ravnborg "or drop the export.\n", 152037ed19d5SAlexey Fomenko tosym, prl_to, prl_to, tosym); 152137ed19d5SAlexey Fomenko free(prl_to); 1522588ccd73SSam Ravnborg break; 152352dc0595SQuentin Casasnovas case EXTABLE_TO_NON_TEXT: 152452dc0595SQuentin Casasnovas fatal("There's a special handler for this mismatch type, " 152552dc0595SQuentin Casasnovas "we should never get here."); 152652dc0595SQuentin Casasnovas break; 1527588ccd73SSam Ravnborg } 1528588ccd73SSam Ravnborg fprintf(stderr, "\n"); 152958fb0d4fSSam Ravnborg } 153058fb0d4fSSam Ravnborg 1531644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf, 1532644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 153358fb0d4fSSam Ravnborg Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 153458fb0d4fSSam Ravnborg { 153558fb0d4fSSam Ravnborg const char *tosec; 1536588ccd73SSam Ravnborg Elf_Sym *to; 1537588ccd73SSam Ravnborg Elf_Sym *from; 153858fb0d4fSSam Ravnborg const char *tosym; 1539588ccd73SSam Ravnborg const char *fromsym; 154058fb0d4fSSam Ravnborg 1541588ccd73SSam Ravnborg from = find_elf_symbol2(elf, r->r_offset, fromsec); 1542588ccd73SSam Ravnborg fromsym = sym_name(elf, from); 154358fb0d4fSSam Ravnborg 154477ab21adSAndi Kleen if (!strncmp(fromsym, "reference___initcall", 154577ab21adSAndi Kleen sizeof("reference___initcall")-1)) 154677ab21adSAndi Kleen return; 154777ab21adSAndi Kleen 1548c7a65e06SQuentin Casasnovas tosec = sec_name(elf, get_secindex(elf, sym)); 1549c7a65e06SQuentin Casasnovas to = find_elf_symbol(elf, r->r_addend, sym); 1550c7a65e06SQuentin Casasnovas tosym = sym_name(elf, to); 1551c7a65e06SQuentin Casasnovas 155258fb0d4fSSam Ravnborg /* check whitelist - we may ignore it */ 1553af92a82dSUwe Kleine-König if (secref_whitelist(mismatch, 1554af92a82dSUwe Kleine-König fromsec, fromsym, tosec, tosym)) { 1555588ccd73SSam Ravnborg report_sec_mismatch(modname, mismatch, 1556588ccd73SSam Ravnborg fromsec, r->r_offset, fromsym, 1557588ccd73SSam Ravnborg is_function(from), tosec, tosym, 1558588ccd73SSam Ravnborg is_function(to)); 155958fb0d4fSSam Ravnborg } 1560b39927cfSSam Ravnborg } 1561644e8f14SQuentin Casasnovas 156252dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index) 156352dc0595SQuentin Casasnovas { 156452dc0595SQuentin Casasnovas if (section_index > elf->num_sections) 156552dc0595SQuentin Casasnovas fatal("section_index is outside elf->num_sections!\n"); 156652dc0595SQuentin Casasnovas 156752dc0595SQuentin Casasnovas return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); 156852dc0595SQuentin Casasnovas } 156952dc0595SQuentin Casasnovas 157052dc0595SQuentin Casasnovas /* 157152dc0595SQuentin Casasnovas * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size() 157252dc0595SQuentin Casasnovas * to know the sizeof(struct exception_table_entry) for the target architecture. 157352dc0595SQuentin Casasnovas */ 157452dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0; 1575e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r) 157652dc0595SQuentin Casasnovas { 157752dc0595SQuentin Casasnovas /* 157852dc0595SQuentin Casasnovas * If we're currently checking the second relocation within __ex_table, 157952dc0595SQuentin Casasnovas * that relocation offset tells us the offsetof(struct 158052dc0595SQuentin Casasnovas * exception_table_entry, fixup) which is equal to sizeof(struct 158152dc0595SQuentin Casasnovas * exception_table_entry) divided by two. We use that to our advantage 158252dc0595SQuentin Casasnovas * since there's no portable way to get that size as every architecture 158352dc0595SQuentin Casasnovas * seems to go with different sized types. Not pretty but better than 158452dc0595SQuentin Casasnovas * hard-coding the size for every architecture.. 158552dc0595SQuentin Casasnovas */ 1586e84048aaSQuentin Casasnovas if (!extable_entry_size) 158752dc0595SQuentin Casasnovas extable_entry_size = r->r_offset * 2; 158852dc0595SQuentin Casasnovas } 1589e84048aaSQuentin Casasnovas 159052dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r) 159152dc0595SQuentin Casasnovas { 1592d3df4de7SQuentin Casasnovas /* 1593d3df4de7SQuentin Casasnovas * extable_entry_size is only discovered after we've handled the 1594d3df4de7SQuentin Casasnovas * _second_ relocation in __ex_table, so only abort when we're not 1595d3df4de7SQuentin Casasnovas * handling the first reloc and extable_entry_size is zero. 1596d3df4de7SQuentin Casasnovas */ 1597d3df4de7SQuentin Casasnovas if (r->r_offset && extable_entry_size == 0) 159852dc0595SQuentin Casasnovas fatal("extable_entry size hasn't been discovered!\n"); 159952dc0595SQuentin Casasnovas 160052dc0595SQuentin Casasnovas return ((r->r_offset == 0) || 160152dc0595SQuentin Casasnovas (r->r_offset % extable_entry_size == 0)); 160252dc0595SQuentin Casasnovas } 160352dc0595SQuentin Casasnovas 1604e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec) \ 1605e84048aaSQuentin Casasnovas (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0)) 1606e84048aaSQuentin Casasnovas 160752dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf, 160852dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 160952dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 161052dc0595SQuentin Casasnovas const char* fromsec, const char* tosec) 161152dc0595SQuentin Casasnovas { 161252dc0595SQuentin Casasnovas Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec); 161352dc0595SQuentin Casasnovas const char* fromsym_name = sym_name(elf, fromsym); 161452dc0595SQuentin Casasnovas Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym); 161552dc0595SQuentin Casasnovas const char* tosym_name = sym_name(elf, tosym); 161652dc0595SQuentin Casasnovas const char* from_pretty_name; 161752dc0595SQuentin Casasnovas const char* from_pretty_name_p; 161852dc0595SQuentin Casasnovas const char* to_pretty_name; 161952dc0595SQuentin Casasnovas const char* to_pretty_name_p; 162052dc0595SQuentin Casasnovas 162152dc0595SQuentin Casasnovas get_pretty_name(is_function(fromsym), 162252dc0595SQuentin Casasnovas &from_pretty_name, &from_pretty_name_p); 162352dc0595SQuentin Casasnovas get_pretty_name(is_function(tosym), 162452dc0595SQuentin Casasnovas &to_pretty_name, &to_pretty_name_p); 162552dc0595SQuentin Casasnovas 162652dc0595SQuentin Casasnovas warn("%s(%s+0x%lx): Section mismatch in reference" 162752dc0595SQuentin Casasnovas " from the %s %s%s to the %s %s:%s%s\n", 162852dc0595SQuentin Casasnovas modname, fromsec, (long)r->r_offset, from_pretty_name, 162952dc0595SQuentin Casasnovas fromsym_name, from_pretty_name_p, 163052dc0595SQuentin Casasnovas to_pretty_name, tosec, tosym_name, to_pretty_name_p); 163152dc0595SQuentin Casasnovas 163252dc0595SQuentin Casasnovas if (!match(tosec, mismatch->bad_tosec) && 163352dc0595SQuentin Casasnovas is_executable_section(elf, get_secindex(elf, sym))) 163452dc0595SQuentin Casasnovas fprintf(stderr, 163552dc0595SQuentin Casasnovas "The relocation at %s+0x%lx references\n" 163652dc0595SQuentin Casasnovas "section \"%s\" which is not in the list of\n" 163752dc0595SQuentin Casasnovas "authorized sections. If you're adding a new section\n" 163852dc0595SQuentin Casasnovas "and/or if this reference is valid, add \"%s\" to the\n" 163952dc0595SQuentin Casasnovas "list of authorized sections to jump to on fault.\n" 164052dc0595SQuentin Casasnovas "This can be achieved by adding \"%s\" to \n" 164152dc0595SQuentin Casasnovas "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n", 164252dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, tosec, tosec); 164352dc0595SQuentin Casasnovas } 164452dc0595SQuentin Casasnovas 164552dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf, 164652dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 164752dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 164852dc0595SQuentin Casasnovas const char *fromsec) 164952dc0595SQuentin Casasnovas { 165052dc0595SQuentin Casasnovas const char* tosec = sec_name(elf, get_secindex(elf, sym)); 165152dc0595SQuentin Casasnovas 165252dc0595SQuentin Casasnovas sec_mismatch_count++; 165352dc0595SQuentin Casasnovas 165452dc0595SQuentin Casasnovas if (sec_mismatch_verbose) 165552dc0595SQuentin Casasnovas report_extable_warnings(modname, elf, mismatch, r, sym, 165652dc0595SQuentin Casasnovas fromsec, tosec); 165752dc0595SQuentin Casasnovas 165852dc0595SQuentin Casasnovas if (match(tosec, mismatch->bad_tosec)) 165952dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 166052dc0595SQuentin Casasnovas "section \"%s\" which is black-listed.\n" 166152dc0595SQuentin Casasnovas "Something is seriously wrong and should be fixed.\n" 166252dc0595SQuentin Casasnovas "You might get more information about where this is\n" 166352dc0595SQuentin Casasnovas "coming from by using scripts/check_extable.sh %s\n", 166452dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, modname); 166552dc0595SQuentin Casasnovas else if (!is_executable_section(elf, get_secindex(elf, sym))) { 166652dc0595SQuentin Casasnovas if (is_extable_fault_address(r)) 166752dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 166852dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 166952dc0595SQuentin Casasnovas "it is not possible for the kernel to fault\n" 167052dc0595SQuentin Casasnovas "at that address. Something is seriously wrong\n" 167152dc0595SQuentin Casasnovas "and should be fixed.\n", 167252dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 167352dc0595SQuentin Casasnovas else 167452dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 167552dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 167652dc0595SQuentin Casasnovas "the kernel will fault if it ever tries to\n" 167752dc0595SQuentin Casasnovas "jump to it. Something is seriously wrong\n" 167852dc0595SQuentin Casasnovas "and should be fixed.\n", 167952dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 168052dc0595SQuentin Casasnovas } 168152dc0595SQuentin Casasnovas } 168252dc0595SQuentin Casasnovas 1683644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf, 1684644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 1685644e8f14SQuentin Casasnovas { 1686644e8f14SQuentin Casasnovas const char *tosec = sec_name(elf, get_secindex(elf, sym));; 1687644e8f14SQuentin Casasnovas const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec); 1688644e8f14SQuentin Casasnovas 1689644e8f14SQuentin Casasnovas if (mismatch) { 1690644e8f14SQuentin Casasnovas if (mismatch->handler) 1691644e8f14SQuentin Casasnovas mismatch->handler(modname, elf, mismatch, 1692644e8f14SQuentin Casasnovas r, sym, fromsec); 1693644e8f14SQuentin Casasnovas else 1694644e8f14SQuentin Casasnovas default_mismatch_handler(modname, elf, mismatch, 1695644e8f14SQuentin Casasnovas r, sym, fromsec); 1696644e8f14SQuentin Casasnovas } 1697b39927cfSSam Ravnborg } 1698b39927cfSSam Ravnborg 1699ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf, 17005b24c071SSam Ravnborg Elf_Shdr *sechdr, Elf_Rela *r) 1701ae4ac123SAtsushi Nemoto { 1702ae4ac123SAtsushi Nemoto Elf_Shdr *sechdrs = elf->sechdrs; 17036845756bSAnders Kaseorg int section = sechdr->sh_info; 1704ae4ac123SAtsushi Nemoto 1705ae4ac123SAtsushi Nemoto return (void *)elf->hdr + sechdrs[section].sh_offset + 1706731ece41SOlof Johansson r->r_offset; 1707ae4ac123SAtsushi Nemoto } 1708ae4ac123SAtsushi Nemoto 17095b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1710ae4ac123SAtsushi Nemoto { 1711ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 17125b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1713ae4ac123SAtsushi Nemoto 1714ae4ac123SAtsushi Nemoto switch (r_typ) { 1715ae4ac123SAtsushi Nemoto case R_386_32: 1716ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location); 1717ae4ac123SAtsushi Nemoto break; 1718ae4ac123SAtsushi Nemoto case R_386_PC32: 1719ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location) + 4; 1720ae4ac123SAtsushi Nemoto /* For CONFIG_RELOCATABLE=y */ 1721ae4ac123SAtsushi Nemoto if (elf->hdr->e_type == ET_EXEC) 1722ae4ac123SAtsushi Nemoto r->r_addend += r->r_offset; 1723ae4ac123SAtsushi Nemoto break; 1724ae4ac123SAtsushi Nemoto } 1725ae4ac123SAtsushi Nemoto return 0; 1726ae4ac123SAtsushi Nemoto } 1727ae4ac123SAtsushi Nemoto 17286e2e340bSTony Lindgren #ifndef R_ARM_CALL 17296e2e340bSTony Lindgren #define R_ARM_CALL 28 17306e2e340bSTony Lindgren #endif 17316e2e340bSTony Lindgren #ifndef R_ARM_JUMP24 17326e2e340bSTony Lindgren #define R_ARM_JUMP24 29 17336e2e340bSTony Lindgren #endif 17346e2e340bSTony Lindgren 1735c9698e5cSDavid A. Long #ifndef R_ARM_THM_CALL 1736c9698e5cSDavid A. Long #define R_ARM_THM_CALL 10 1737c9698e5cSDavid A. Long #endif 1738c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP24 1739c9698e5cSDavid A. Long #define R_ARM_THM_JUMP24 30 1740c9698e5cSDavid A. Long #endif 1741c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP19 1742c9698e5cSDavid A. Long #define R_ARM_THM_JUMP19 51 1743c9698e5cSDavid A. Long #endif 1744c9698e5cSDavid A. Long 17455b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 174656a974faSSam Ravnborg { 174756a974faSSam Ravnborg unsigned int r_typ = ELF_R_TYPE(r->r_info); 174856a974faSSam Ravnborg 174956a974faSSam Ravnborg switch (r_typ) { 175056a974faSSam Ravnborg case R_ARM_ABS32: 175156a974faSSam Ravnborg /* From ARM ABI: (S + A) | T */ 1752df578e7dSSam Ravnborg r->r_addend = (int)(long) 1753df578e7dSSam Ravnborg (elf->symtab_start + ELF_R_SYM(r->r_info)); 175456a974faSSam Ravnborg break; 175556a974faSSam Ravnborg case R_ARM_PC24: 17566e2e340bSTony Lindgren case R_ARM_CALL: 17576e2e340bSTony Lindgren case R_ARM_JUMP24: 1758c9698e5cSDavid A. Long case R_ARM_THM_CALL: 1759c9698e5cSDavid A. Long case R_ARM_THM_JUMP24: 1760c9698e5cSDavid A. Long case R_ARM_THM_JUMP19: 176156a974faSSam Ravnborg /* From ARM ABI: ((S + A) | T) - P */ 1762df578e7dSSam Ravnborg r->r_addend = (int)(long)(elf->hdr + 17635b24c071SSam Ravnborg sechdr->sh_offset + 17645b24c071SSam Ravnborg (r->r_offset - sechdr->sh_addr)); 176556a974faSSam Ravnborg break; 176656a974faSSam Ravnborg default: 176756a974faSSam Ravnborg return 1; 176856a974faSSam Ravnborg } 176956a974faSSam Ravnborg return 0; 177056a974faSSam Ravnborg } 177156a974faSSam Ravnborg 17725b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1773ae4ac123SAtsushi Nemoto { 1774ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 17755b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1776ae4ac123SAtsushi Nemoto unsigned int inst; 1777ae4ac123SAtsushi Nemoto 1778ae4ac123SAtsushi Nemoto if (r_typ == R_MIPS_HI16) 1779ae4ac123SAtsushi Nemoto return 1; /* skip this */ 1780ae4ac123SAtsushi Nemoto inst = TO_NATIVE(*location); 1781ae4ac123SAtsushi Nemoto switch (r_typ) { 1782ae4ac123SAtsushi Nemoto case R_MIPS_LO16: 1783ae4ac123SAtsushi Nemoto r->r_addend = inst & 0xffff; 1784ae4ac123SAtsushi Nemoto break; 1785ae4ac123SAtsushi Nemoto case R_MIPS_26: 1786ae4ac123SAtsushi Nemoto r->r_addend = (inst & 0x03ffffff) << 2; 1787ae4ac123SAtsushi Nemoto break; 1788ae4ac123SAtsushi Nemoto case R_MIPS_32: 1789ae4ac123SAtsushi Nemoto r->r_addend = inst; 1790ae4ac123SAtsushi Nemoto break; 1791ae4ac123SAtsushi Nemoto } 1792ae4ac123SAtsushi Nemoto return 0; 1793ae4ac123SAtsushi Nemoto } 1794ae4ac123SAtsushi Nemoto 17955b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf, 179610668220SSam Ravnborg Elf_Shdr *sechdr) 1797b39927cfSSam Ravnborg { 1798b39927cfSSam Ravnborg Elf_Sym *sym; 17995b24c071SSam Ravnborg Elf_Rela *rela; 18002c1a51f3SAtsushi Nemoto Elf_Rela r; 1801eae07ac6SAtsushi Nemoto unsigned int r_sym; 18025b24c071SSam Ravnborg const char *fromsec; 18035b24c071SSam Ravnborg 1804ff13f926SSam Ravnborg Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; 18055b24c071SSam Ravnborg Elf_Rela *stop = (void *)start + sechdr->sh_size; 18065b24c071SSam Ravnborg 1807ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 18085b24c071SSam Ravnborg fromsec += strlen(".rela"); 18095b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1810b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 18115b24c071SSam Ravnborg return; 1812e241a630SSam Ravnborg 1813b39927cfSSam Ravnborg for (rela = start; rela < stop; rela++) { 1814b39927cfSSam Ravnborg r.r_offset = TO_NATIVE(rela->r_offset); 1815eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1816ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1817ae4ac123SAtsushi Nemoto unsigned int r_typ; 1818eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rela->r_info); 1819eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1820ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rela->r_info); 1821ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1822eae07ac6SAtsushi Nemoto } else { 1823601e7f02SLinus Torvalds r.r_info = TO_NATIVE(rela->r_info); 1824eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1825eae07ac6SAtsushi Nemoto } 1826eae07ac6SAtsushi Nemoto #else 1827eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rela->r_info); 1828eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1829eae07ac6SAtsushi Nemoto #endif 183093684d3bSSam Ravnborg r.r_addend = TO_NATIVE(rela->r_addend); 1831eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 1832b39927cfSSam Ravnborg /* Skip special sections */ 18331ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1834b39927cfSSam Ravnborg continue; 1835e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rela, fromsec)) 1836e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 183758fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 18382c1a51f3SAtsushi Nemoto } 18395b24c071SSam Ravnborg } 18405b24c071SSam Ravnborg 18415b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf, 184210668220SSam Ravnborg Elf_Shdr *sechdr) 18435b24c071SSam Ravnborg { 18445b24c071SSam Ravnborg Elf_Sym *sym; 18452c1a51f3SAtsushi Nemoto Elf_Rel *rel; 18465b24c071SSam Ravnborg Elf_Rela r; 18475b24c071SSam Ravnborg unsigned int r_sym; 18485b24c071SSam Ravnborg const char *fromsec; 18495b24c071SSam Ravnborg 1850ff13f926SSam Ravnborg Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; 18515b24c071SSam Ravnborg Elf_Rel *stop = (void *)start + sechdr->sh_size; 18525b24c071SSam Ravnborg 1853ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 18545b24c071SSam Ravnborg fromsec += strlen(".rel"); 18555b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1856b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 18575b24c071SSam Ravnborg return; 18582c1a51f3SAtsushi Nemoto 18592c1a51f3SAtsushi Nemoto for (rel = start; rel < stop; rel++) { 18602c1a51f3SAtsushi Nemoto r.r_offset = TO_NATIVE(rel->r_offset); 1861eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1862ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1863ae4ac123SAtsushi Nemoto unsigned int r_typ; 1864eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rel->r_info); 1865eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1866ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rel->r_info); 1867ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1868eae07ac6SAtsushi Nemoto } else { 18692c1a51f3SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1870eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1871eae07ac6SAtsushi Nemoto } 1872eae07ac6SAtsushi Nemoto #else 1873eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1874eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1875eae07ac6SAtsushi Nemoto #endif 18762c1a51f3SAtsushi Nemoto r.r_addend = 0; 1877ff13f926SSam Ravnborg switch (elf->hdr->e_machine) { 1878ae4ac123SAtsushi Nemoto case EM_386: 18795b24c071SSam Ravnborg if (addend_386_rel(elf, sechdr, &r)) 1880ae4ac123SAtsushi Nemoto continue; 1881ae4ac123SAtsushi Nemoto break; 188256a974faSSam Ravnborg case EM_ARM: 18835b24c071SSam Ravnborg if (addend_arm_rel(elf, sechdr, &r)) 188456a974faSSam Ravnborg continue; 188556a974faSSam Ravnborg break; 1886ae4ac123SAtsushi Nemoto case EM_MIPS: 18875b24c071SSam Ravnborg if (addend_mips_rel(elf, sechdr, &r)) 1888ae4ac123SAtsushi Nemoto continue; 1889ae4ac123SAtsushi Nemoto break; 1890ae4ac123SAtsushi Nemoto } 1891eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 18922c1a51f3SAtsushi Nemoto /* Skip special sections */ 18931ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 18942c1a51f3SAtsushi Nemoto continue; 1895e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rel, fromsec)) 1896e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 189758fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 18982c1a51f3SAtsushi Nemoto } 1899b39927cfSSam Ravnborg } 19005b24c071SSam Ravnborg 19015b24c071SSam Ravnborg /** 19025b24c071SSam Ravnborg * A module includes a number of sections that are discarded 19035b24c071SSam Ravnborg * either when loaded or when used as built-in. 19045b24c071SSam Ravnborg * For loaded modules all functions marked __init and all data 1905b595076aSUwe Kleine-König * marked __initdata will be discarded when the module has been initialized. 19065b24c071SSam Ravnborg * Likewise for modules used built-in the sections marked __exit 19075b24c071SSam Ravnborg * are discarded because __exit marked function are supposed to be called 190832be1d22SBen Dooks * only when a module is unloaded which never happens for built-in modules. 19095b24c071SSam Ravnborg * The check_sec_ref() function traverses all relocation records 19105b24c071SSam Ravnborg * to find all references to a section that reference a section that will 19115b24c071SSam Ravnborg * be discarded and warns about it. 19125b24c071SSam Ravnborg **/ 19135b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname, 191410668220SSam Ravnborg struct elf_info *elf) 19155b24c071SSam Ravnborg { 19165b24c071SSam Ravnborg int i; 19175b24c071SSam Ravnborg Elf_Shdr *sechdrs = elf->sechdrs; 19185b24c071SSam Ravnborg 19195b24c071SSam Ravnborg /* Walk through all sections */ 19201ce53adfSDenys Vlasenko for (i = 0; i < elf->num_sections; i++) { 1921b614a697SAnders Kaseorg check_section(modname, elf, &elf->sechdrs[i]); 19225b24c071SSam Ravnborg /* We want to process only relocation sections and not .init */ 19235b24c071SSam Ravnborg if (sechdrs[i].sh_type == SHT_RELA) 192410668220SSam Ravnborg section_rela(modname, elf, &elf->sechdrs[i]); 19255b24c071SSam Ravnborg else if (sechdrs[i].sh_type == SHT_REL) 192610668220SSam Ravnborg section_rel(modname, elf, &elf->sechdrs[i]); 1927b39927cfSSam Ravnborg } 1928b39927cfSSam Ravnborg } 1929b39927cfSSam Ravnborg 19307d02b490SAndi Kleen static char *remove_dot(char *s) 19317d02b490SAndi Kleen { 1932fcd38ed0SMichal Nazarewicz size_t n = strcspn(s, "."); 19337d02b490SAndi Kleen 1934fcd38ed0SMichal Nazarewicz if (n && s[n]) { 1935fcd38ed0SMichal Nazarewicz size_t m = strspn(s + n + 1, "0123456789"); 1936fcd38ed0SMichal Nazarewicz if (m && (s[n + m] == '.' || s[n + m] == 0)) 19377d02b490SAndi Kleen s[n] = 0; 19387d02b490SAndi Kleen } 19397d02b490SAndi Kleen return s; 19407d02b490SAndi Kleen } 19417d02b490SAndi Kleen 19425c3ead8cSSam Ravnborg static void read_symbols(char *modname) 19431da177e4SLinus Torvalds { 19441da177e4SLinus Torvalds const char *symname; 19451da177e4SLinus Torvalds char *version; 1946b817f6feSSam Ravnborg char *license; 19471da177e4SLinus Torvalds struct module *mod; 19481da177e4SLinus Torvalds struct elf_info info = { }; 19491da177e4SLinus Torvalds Elf_Sym *sym; 19501da177e4SLinus Torvalds 195185bd2fddSSam Ravnborg if (!parse_elf(&info, modname)) 195285bd2fddSSam Ravnborg return; 19531da177e4SLinus Torvalds 19541da177e4SLinus Torvalds mod = new_module(modname); 19551da177e4SLinus Torvalds 19561da177e4SLinus Torvalds /* When there's no vmlinux, don't print warnings about 19571da177e4SLinus Torvalds * unresolved symbols (since there'll be too many ;) */ 19581da177e4SLinus Torvalds if (is_vmlinux(modname)) { 19591da177e4SLinus Torvalds have_vmlinux = 1; 19601da177e4SLinus Torvalds mod->skip = 1; 19611da177e4SLinus Torvalds } 19621da177e4SLinus Torvalds 1963b817f6feSSam Ravnborg license = get_modinfo(info.modinfo, info.modinfo_len, "license"); 19642fa36568SSam Ravnborg if (info.modinfo && !license && !is_vmlinux(modname)) 19652fa36568SSam Ravnborg warn("modpost: missing MODULE_LICENSE() in %s\n" 1966eed7d279SSam Ravnborg "see include/linux/module.h for " 1967eed7d279SSam Ravnborg "more information\n", modname); 1968b817f6feSSam Ravnborg while (license) { 1969b817f6feSSam Ravnborg if (license_is_gpl_compatible(license)) 1970b817f6feSSam Ravnborg mod->gpl_compatible = 1; 1971b817f6feSSam Ravnborg else { 1972b817f6feSSam Ravnborg mod->gpl_compatible = 0; 1973b817f6feSSam Ravnborg break; 1974b817f6feSSam Ravnborg } 1975b817f6feSSam Ravnborg license = get_next_modinfo(info.modinfo, info.modinfo_len, 1976b817f6feSSam Ravnborg "license", license); 1977b817f6feSSam Ravnborg } 1978b817f6feSSam Ravnborg 19791da177e4SLinus Torvalds for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { 19807d02b490SAndi Kleen symname = remove_dot(info.strtab + sym->st_name); 19811da177e4SLinus Torvalds 19821da177e4SLinus Torvalds handle_modversions(mod, &info, sym, symname); 19831da177e4SLinus Torvalds handle_moddevtable(mod, &info, sym, symname); 19841da177e4SLinus Torvalds } 1985d1f25e66SSam Ravnborg if (!is_vmlinux(modname) || 198610668220SSam Ravnborg (is_vmlinux(modname) && vmlinux_section_warnings)) 198710668220SSam Ravnborg check_sec_ref(mod, modname, &info); 19881da177e4SLinus Torvalds 19891da177e4SLinus Torvalds version = get_modinfo(info.modinfo, info.modinfo_len, "version"); 19901da177e4SLinus Torvalds if (version) 19911da177e4SLinus Torvalds maybe_frob_rcs_version(modname, version, info.modinfo, 19921da177e4SLinus Torvalds version - (char *)info.hdr); 19931da177e4SLinus Torvalds if (version || (all_versions && !is_vmlinux(modname))) 19941da177e4SLinus Torvalds get_src_version(modname, mod->srcversion, 19951da177e4SLinus Torvalds sizeof(mod->srcversion)-1); 19961da177e4SLinus Torvalds 19971da177e4SLinus Torvalds parse_elf_finish(&info); 19981da177e4SLinus Torvalds 19998c8ef42aSRusty Russell /* Our trick to get versioning for module struct etc. - it's 20001da177e4SLinus Torvalds * never passed as an argument to an exported function, so 20011da177e4SLinus Torvalds * the automatic versioning doesn't pick it up, but it's really 20021da177e4SLinus Torvalds * important anyhow */ 20031da177e4SLinus Torvalds if (modversions) 20048c8ef42aSRusty Russell mod->unres = alloc_symbol("module_layout", 0, mod->unres); 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds 2007712f9b46SRusty Russell static void read_symbols_from_files(const char *filename) 2008712f9b46SRusty Russell { 2009712f9b46SRusty Russell FILE *in = stdin; 2010712f9b46SRusty Russell char fname[PATH_MAX]; 2011712f9b46SRusty Russell 2012712f9b46SRusty Russell if (strcmp(filename, "-") != 0) { 2013712f9b46SRusty Russell in = fopen(filename, "r"); 2014712f9b46SRusty Russell if (!in) 2015712f9b46SRusty Russell fatal("Can't open filenames file %s: %m", filename); 2016712f9b46SRusty Russell } 2017712f9b46SRusty Russell 2018712f9b46SRusty Russell while (fgets(fname, PATH_MAX, in) != NULL) { 2019712f9b46SRusty Russell if (strends(fname, "\n")) 2020712f9b46SRusty Russell fname[strlen(fname)-1] = '\0'; 2021712f9b46SRusty Russell read_symbols(fname); 2022712f9b46SRusty Russell } 2023712f9b46SRusty Russell 2024712f9b46SRusty Russell if (in != stdin) 2025712f9b46SRusty Russell fclose(in); 2026712f9b46SRusty Russell } 2027712f9b46SRusty Russell 20281da177e4SLinus Torvalds #define SZ 500 20291da177e4SLinus Torvalds 20301da177e4SLinus Torvalds /* We first write the generated file into memory using the 20311da177e4SLinus Torvalds * following helper, then compare to the file on disk and 20321da177e4SLinus Torvalds * only update the later if anything changed */ 20331da177e4SLinus Torvalds 20345c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, 20355c3ead8cSSam Ravnborg const char *fmt, ...) 20361da177e4SLinus Torvalds { 20371da177e4SLinus Torvalds char tmp[SZ]; 20381da177e4SLinus Torvalds int len; 20391da177e4SLinus Torvalds va_list ap; 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds va_start(ap, fmt); 20421da177e4SLinus Torvalds len = vsnprintf(tmp, SZ, fmt, ap); 20437670f023SSam Ravnborg buf_write(buf, tmp, len); 20441da177e4SLinus Torvalds va_end(ap); 20451da177e4SLinus Torvalds } 20461da177e4SLinus Torvalds 20475c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len) 20481da177e4SLinus Torvalds { 20491da177e4SLinus Torvalds if (buf->size - buf->pos < len) { 20507670f023SSam Ravnborg buf->size += len + SZ; 20511da177e4SLinus Torvalds buf->p = realloc(buf->p, buf->size); 20521da177e4SLinus Torvalds } 20531da177e4SLinus Torvalds strncpy(buf->p + buf->pos, s, len); 20541da177e4SLinus Torvalds buf->pos += len; 20551da177e4SLinus Torvalds } 20561da177e4SLinus Torvalds 2057c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s) 2058c96fca21SSam Ravnborg { 2059c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2060c96fca21SSam Ravnborg 2061c96fca21SSam Ravnborg switch (exp) { 2062c96fca21SSam Ravnborg case export_gpl: 2063c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2064c96fca21SSam Ravnborg "uses GPL-only symbol '%s'\n", m, e, s); 2065c96fca21SSam Ravnborg break; 2066c96fca21SSam Ravnborg case export_unused_gpl: 2067c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2068c96fca21SSam Ravnborg "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); 2069c96fca21SSam Ravnborg break; 2070c96fca21SSam Ravnborg case export_gpl_future: 2071c96fca21SSam Ravnborg warn("modpost: GPL-incompatible module %s%s " 2072c96fca21SSam Ravnborg "uses future GPL-only symbol '%s'\n", m, e, s); 2073c96fca21SSam Ravnborg break; 2074c96fca21SSam Ravnborg case export_plain: 2075c96fca21SSam Ravnborg case export_unused: 2076c96fca21SSam Ravnborg case export_unknown: 2077c96fca21SSam Ravnborg /* ignore */ 2078c96fca21SSam Ravnborg break; 2079c96fca21SSam Ravnborg } 2080c96fca21SSam Ravnborg } 2081c96fca21SSam Ravnborg 2082c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s) 2083c96fca21SSam Ravnborg { 2084c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2085c96fca21SSam Ravnborg 2086c96fca21SSam Ravnborg switch (exp) { 2087c96fca21SSam Ravnborg case export_unused: 2088c96fca21SSam Ravnborg case export_unused_gpl: 2089c96fca21SSam Ravnborg warn("modpost: module %s%s " 2090c96fca21SSam Ravnborg "uses symbol '%s' marked UNUSED\n", m, e, s); 2091c96fca21SSam Ravnborg break; 2092c96fca21SSam Ravnborg default: 2093c96fca21SSam Ravnborg /* ignore */ 2094c96fca21SSam Ravnborg break; 2095c96fca21SSam Ravnborg } 2096c96fca21SSam Ravnborg } 2097c96fca21SSam Ravnborg 2098c96fca21SSam Ravnborg static void check_exports(struct module *mod) 2099b817f6feSSam Ravnborg { 2100b817f6feSSam Ravnborg struct symbol *s, *exp; 2101b817f6feSSam Ravnborg 2102b817f6feSSam Ravnborg for (s = mod->unres; s; s = s->next) { 21036449bd62SAndrew Morton const char *basename; 2104b817f6feSSam Ravnborg exp = find_symbol(s->name); 2105b817f6feSSam Ravnborg if (!exp || exp->module == mod) 2106b817f6feSSam Ravnborg continue; 21076449bd62SAndrew Morton basename = strrchr(mod->name, '/'); 2108b817f6feSSam Ravnborg if (basename) 2109b817f6feSSam Ravnborg basename++; 2110c96fca21SSam Ravnborg else 2111c96fca21SSam Ravnborg basename = mod->name; 2112c96fca21SSam Ravnborg if (!mod->gpl_compatible) 2113c96fca21SSam Ravnborg check_for_gpl_usage(exp->export, basename, exp->name); 2114c96fca21SSam Ravnborg check_for_unused(exp->export, basename, exp->name); 2115b817f6feSSam Ravnborg } 2116b817f6feSSam Ravnborg } 2117b817f6feSSam Ravnborg 21185c3ead8cSSam Ravnborg /** 21195c3ead8cSSam Ravnborg * Header for the generated file 21205c3ead8cSSam Ravnborg **/ 21215c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod) 21221da177e4SLinus Torvalds { 21231da177e4SLinus Torvalds buf_printf(b, "#include <linux/module.h>\n"); 21241da177e4SLinus Torvalds buf_printf(b, "#include <linux/vermagic.h>\n"); 21251da177e4SLinus Torvalds buf_printf(b, "#include <linux/compiler.h>\n"); 21261da177e4SLinus Torvalds buf_printf(b, "\n"); 21271da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); 21281da177e4SLinus Torvalds buf_printf(b, "\n"); 2129e0f244c6SAndi Kleen buf_printf(b, "__visible struct module __this_module\n"); 21301da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); 21313c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); 21321da177e4SLinus Torvalds if (mod->has_init) 21333c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.init = init_module,\n"); 21341da177e4SLinus Torvalds if (mod->has_cleanup) 21351da177e4SLinus Torvalds buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" 21363c7ec94dSGreg Kroah-Hartman "\t.exit = cleanup_module,\n" 21371da177e4SLinus Torvalds "#endif\n"); 21383c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); 21391da177e4SLinus Torvalds buf_printf(b, "};\n"); 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds 21422449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree) 21432449b8baSBen Hutchings { 21442449b8baSBen Hutchings if (is_intree) 21452449b8baSBen Hutchings buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); 21462449b8baSBen Hutchings } 21472449b8baSBen Hutchings 21485c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name) 2149a9860bf0SGreg Kroah-Hartman { 2150a9860bf0SGreg Kroah-Hartman static const char *staging_dir = "drivers/staging"; 2151a9860bf0SGreg Kroah-Hartman 2152a9860bf0SGreg Kroah-Hartman if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) 2153a9860bf0SGreg Kroah-Hartman buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); 2154a9860bf0SGreg Kroah-Hartman } 2155a9860bf0SGreg Kroah-Hartman 21565cfb203aSTakashi Iwai /* In kernel, this size is defined in linux/module.h; 21575cfb203aSTakashi Iwai * here we use Elf_Addr instead of long for covering cross-compile 21585cfb203aSTakashi Iwai */ 21595cfb203aSTakashi Iwai #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) 21605cfb203aSTakashi Iwai 21615c3ead8cSSam Ravnborg /** 21625c3ead8cSSam Ravnborg * Record CRCs for unresolved symbols 21635c3ead8cSSam Ravnborg **/ 2164c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod) 21651da177e4SLinus Torvalds { 21661da177e4SLinus Torvalds struct symbol *s, *exp; 2167c53ddacdSKirill Korotaev int err = 0; 21681da177e4SLinus Torvalds 21691da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 21701da177e4SLinus Torvalds exp = find_symbol(s->name); 21711da177e4SLinus Torvalds if (!exp || exp->module == mod) { 2172c53ddacdSKirill Korotaev if (have_vmlinux && !s->weak) { 21732a116659SMatthew Wilcox if (warn_unresolved) { 2174cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] undefined!\n", 2175cb80514dSSam Ravnborg s->name, mod->name); 21762a116659SMatthew Wilcox } else { 21772a116659SMatthew Wilcox merror("\"%s\" [%s.ko] undefined!\n", 21782a116659SMatthew Wilcox s->name, mod->name); 21792a116659SMatthew Wilcox err = 1; 21802a116659SMatthew Wilcox } 2181c53ddacdSKirill Korotaev } 21821da177e4SLinus Torvalds continue; 21831da177e4SLinus Torvalds } 21841da177e4SLinus Torvalds s->module = exp->module; 21851da177e4SLinus Torvalds s->crc_valid = exp->crc_valid; 21861da177e4SLinus Torvalds s->crc = exp->crc; 21871da177e4SLinus Torvalds } 21881da177e4SLinus Torvalds 21891da177e4SLinus Torvalds if (!modversions) 2190c53ddacdSKirill Korotaev return err; 21911da177e4SLinus Torvalds 21921da177e4SLinus Torvalds buf_printf(b, "\n"); 21931da177e4SLinus Torvalds buf_printf(b, "static const struct modversion_info ____versions[]\n"); 21943ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 21951da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); 21961da177e4SLinus Torvalds 21971da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2198df578e7dSSam Ravnborg if (!s->module) 21991da177e4SLinus Torvalds continue; 22001da177e4SLinus Torvalds if (!s->crc_valid) { 2201cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] has no CRC!\n", 22021da177e4SLinus Torvalds s->name, mod->name); 22031da177e4SLinus Torvalds continue; 22041da177e4SLinus Torvalds } 22055cfb203aSTakashi Iwai if (strlen(s->name) >= MODULE_NAME_LEN) { 22065cfb203aSTakashi Iwai merror("too long symbol \"%s\" [%s.ko]\n", 22075cfb203aSTakashi Iwai s->name, mod->name); 22085cfb203aSTakashi Iwai err = 1; 22095cfb203aSTakashi Iwai break; 22105cfb203aSTakashi Iwai } 2211a53a11f3SJames Hogan buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", 2212a4b6a77bSJames Hogan s->crc, s->name); 22131da177e4SLinus Torvalds } 22141da177e4SLinus Torvalds 22151da177e4SLinus Torvalds buf_printf(b, "};\n"); 2216c53ddacdSKirill Korotaev 2217c53ddacdSKirill Korotaev return err; 22181da177e4SLinus Torvalds } 22191da177e4SLinus Torvalds 22205c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod, 22215c3ead8cSSam Ravnborg struct module *modules) 22221da177e4SLinus Torvalds { 22231da177e4SLinus Torvalds struct symbol *s; 22241da177e4SLinus Torvalds struct module *m; 22251da177e4SLinus Torvalds int first = 1; 22261da177e4SLinus Torvalds 2227df578e7dSSam Ravnborg for (m = modules; m; m = m->next) 22281da177e4SLinus Torvalds m->seen = is_vmlinux(m->name); 22291da177e4SLinus Torvalds 22301da177e4SLinus Torvalds buf_printf(b, "\n"); 22311da177e4SLinus Torvalds buf_printf(b, "static const char __module_depends[]\n"); 22323ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 22331da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); 22341da177e4SLinus Torvalds buf_printf(b, "\"depends="); 22351da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2236a61b2dfdSSam Ravnborg const char *p; 22371da177e4SLinus Torvalds if (!s->module) 22381da177e4SLinus Torvalds continue; 22391da177e4SLinus Torvalds 22401da177e4SLinus Torvalds if (s->module->seen) 22411da177e4SLinus Torvalds continue; 22421da177e4SLinus Torvalds 22431da177e4SLinus Torvalds s->module->seen = 1; 2244df578e7dSSam Ravnborg p = strrchr(s->module->name, '/'); 2245df578e7dSSam Ravnborg if (p) 2246a61b2dfdSSam Ravnborg p++; 2247a61b2dfdSSam Ravnborg else 2248a61b2dfdSSam Ravnborg p = s->module->name; 2249a61b2dfdSSam Ravnborg buf_printf(b, "%s%s", first ? "" : ",", p); 22501da177e4SLinus Torvalds first = 0; 22511da177e4SLinus Torvalds } 22521da177e4SLinus Torvalds buf_printf(b, "\";\n"); 22531da177e4SLinus Torvalds } 22541da177e4SLinus Torvalds 22555c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod) 22561da177e4SLinus Torvalds { 22571da177e4SLinus Torvalds if (mod->srcversion[0]) { 22581da177e4SLinus Torvalds buf_printf(b, "\n"); 22591da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", 22601da177e4SLinus Torvalds mod->srcversion); 22611da177e4SLinus Torvalds } 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 22645c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname) 22651da177e4SLinus Torvalds { 22661da177e4SLinus Torvalds char *tmp; 22671da177e4SLinus Torvalds FILE *file; 22681da177e4SLinus Torvalds struct stat st; 22691da177e4SLinus Torvalds 22701da177e4SLinus Torvalds file = fopen(fname, "r"); 22711da177e4SLinus Torvalds if (!file) 22721da177e4SLinus Torvalds goto write; 22731da177e4SLinus Torvalds 22741da177e4SLinus Torvalds if (fstat(fileno(file), &st) < 0) 22751da177e4SLinus Torvalds goto close_write; 22761da177e4SLinus Torvalds 22771da177e4SLinus Torvalds if (st.st_size != b->pos) 22781da177e4SLinus Torvalds goto close_write; 22791da177e4SLinus Torvalds 22801da177e4SLinus Torvalds tmp = NOFAIL(malloc(b->pos)); 22811da177e4SLinus Torvalds if (fread(tmp, 1, b->pos, file) != b->pos) 22821da177e4SLinus Torvalds goto free_write; 22831da177e4SLinus Torvalds 22841da177e4SLinus Torvalds if (memcmp(tmp, b->p, b->pos) != 0) 22851da177e4SLinus Torvalds goto free_write; 22861da177e4SLinus Torvalds 22871da177e4SLinus Torvalds free(tmp); 22881da177e4SLinus Torvalds fclose(file); 22891da177e4SLinus Torvalds return; 22901da177e4SLinus Torvalds 22911da177e4SLinus Torvalds free_write: 22921da177e4SLinus Torvalds free(tmp); 22931da177e4SLinus Torvalds close_write: 22941da177e4SLinus Torvalds fclose(file); 22951da177e4SLinus Torvalds write: 22961da177e4SLinus Torvalds file = fopen(fname, "w"); 22971da177e4SLinus Torvalds if (!file) { 22981da177e4SLinus Torvalds perror(fname); 22991da177e4SLinus Torvalds exit(1); 23001da177e4SLinus Torvalds } 23011da177e4SLinus Torvalds if (fwrite(b->p, 1, b->pos, file) != b->pos) { 23021da177e4SLinus Torvalds perror(fname); 23031da177e4SLinus Torvalds exit(1); 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds fclose(file); 23061da177e4SLinus Torvalds } 23071da177e4SLinus Torvalds 2308bd5cbcedSRam Pai /* parse Module.symvers file. line format: 2309534b89a9SSam Ravnborg * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] 2310bd5cbcedSRam Pai **/ 2311040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel) 23121da177e4SLinus Torvalds { 23131da177e4SLinus Torvalds unsigned long size, pos = 0; 23141da177e4SLinus Torvalds void *file = grab_file(fname, &size); 23151da177e4SLinus Torvalds char *line; 23161da177e4SLinus Torvalds 23171da177e4SLinus Torvalds if (!file) 23181da177e4SLinus Torvalds /* No symbol versions, silently ignore */ 23191da177e4SLinus Torvalds return; 23201da177e4SLinus Torvalds 23211da177e4SLinus Torvalds while ((line = get_next_line(&pos, file, size))) { 2322534b89a9SSam Ravnborg char *symname, *modname, *d, *export, *end; 23231da177e4SLinus Torvalds unsigned int crc; 23241da177e4SLinus Torvalds struct module *mod; 2325040fcc81SSam Ravnborg struct symbol *s; 23261da177e4SLinus Torvalds 23271da177e4SLinus Torvalds if (!(symname = strchr(line, '\t'))) 23281da177e4SLinus Torvalds goto fail; 23291da177e4SLinus Torvalds *symname++ = '\0'; 23301da177e4SLinus Torvalds if (!(modname = strchr(symname, '\t'))) 23311da177e4SLinus Torvalds goto fail; 23321da177e4SLinus Torvalds *modname++ = '\0'; 23339ac545b0SLaurent Riffard if ((export = strchr(modname, '\t')) != NULL) 2334bd5cbcedSRam Pai *export++ = '\0'; 2335534b89a9SSam Ravnborg if (export && ((end = strchr(export, '\t')) != NULL)) 2336534b89a9SSam Ravnborg *end = '\0'; 23371da177e4SLinus Torvalds crc = strtoul(line, &d, 16); 23381da177e4SLinus Torvalds if (*symname == '\0' || *modname == '\0' || *d != '\0') 23391da177e4SLinus Torvalds goto fail; 2340df578e7dSSam Ravnborg mod = find_module(modname); 2341df578e7dSSam Ravnborg if (!mod) { 2342df578e7dSSam Ravnborg if (is_vmlinux(modname)) 23431da177e4SLinus Torvalds have_vmlinux = 1; 23440fa3a88cSJan Beulich mod = new_module(modname); 23451da177e4SLinus Torvalds mod->skip = 1; 23461da177e4SLinus Torvalds } 2347bd5cbcedSRam Pai s = sym_add_exported(symname, mod, export_no(export)); 2348040fcc81SSam Ravnborg s->kernel = kernel; 23498e70c458SSam Ravnborg s->preloaded = 1; 2350bd5cbcedSRam Pai sym_update_crc(symname, mod, crc, export_no(export)); 23511da177e4SLinus Torvalds } 23522ee41e62SChristian Engelmayer release_file(file, size); 23531da177e4SLinus Torvalds return; 23541da177e4SLinus Torvalds fail: 23552ee41e62SChristian Engelmayer release_file(file, size); 23561da177e4SLinus Torvalds fatal("parse error in symbol dump file\n"); 23571da177e4SLinus Torvalds } 23581da177e4SLinus Torvalds 2359040fcc81SSam Ravnborg /* For normal builds always dump all symbols. 2360040fcc81SSam Ravnborg * For external modules only dump symbols 2361040fcc81SSam Ravnborg * that are not read from kernel Module.symvers. 2362040fcc81SSam Ravnborg **/ 2363040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym) 2364040fcc81SSam Ravnborg { 2365040fcc81SSam Ravnborg if (!external_module) 2366040fcc81SSam Ravnborg return 1; 2367040fcc81SSam Ravnborg if (sym->vmlinux || sym->kernel) 2368040fcc81SSam Ravnborg return 0; 2369040fcc81SSam Ravnborg return 1; 2370040fcc81SSam Ravnborg } 2371040fcc81SSam Ravnborg 23725c3ead8cSSam Ravnborg static void write_dump(const char *fname) 23731da177e4SLinus Torvalds { 23741da177e4SLinus Torvalds struct buffer buf = { }; 23751da177e4SLinus Torvalds struct symbol *symbol; 23761da177e4SLinus Torvalds int n; 23771da177e4SLinus Torvalds 23781da177e4SLinus Torvalds for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { 23791da177e4SLinus Torvalds symbol = symbolhash[n]; 23801da177e4SLinus Torvalds while (symbol) { 2381040fcc81SSam Ravnborg if (dump_sym(symbol)) 2382bd5cbcedSRam Pai buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", 2383040fcc81SSam Ravnborg symbol->crc, symbol->name, 2384bd5cbcedSRam Pai symbol->module->name, 2385bd5cbcedSRam Pai export_str(symbol->export)); 23861da177e4SLinus Torvalds symbol = symbol->next; 23871da177e4SLinus Torvalds } 23881da177e4SLinus Torvalds } 23891da177e4SLinus Torvalds write_if_changed(&buf, fname); 2390c7d47f26SHeinrich Schuchardt free(buf.p); 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds 23932d04b5aeSRichard Hacker struct ext_sym_list { 23942d04b5aeSRichard Hacker struct ext_sym_list *next; 23952d04b5aeSRichard Hacker const char *file; 23962d04b5aeSRichard Hacker }; 23972d04b5aeSRichard Hacker 23985c3ead8cSSam Ravnborg int main(int argc, char **argv) 23991da177e4SLinus Torvalds { 24001da177e4SLinus Torvalds struct module *mod; 24011da177e4SLinus Torvalds struct buffer buf = { }; 2402040fcc81SSam Ravnborg char *kernel_read = NULL, *module_read = NULL; 2403712f9b46SRusty Russell char *dump_write = NULL, *files_source = NULL; 24041da177e4SLinus Torvalds int opt; 2405c53ddacdSKirill Korotaev int err; 24062d04b5aeSRichard Hacker struct ext_sym_list *extsym_iter; 24072d04b5aeSRichard Hacker struct ext_sym_list *extsym_start = NULL; 24081da177e4SLinus Torvalds 240947490ec1SNicolas Boichat while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:E")) != -1) { 24101da177e4SLinus Torvalds switch (opt) { 24111da177e4SLinus Torvalds case 'i': 2412040fcc81SSam Ravnborg kernel_read = optarg; 2413040fcc81SSam Ravnborg break; 2414040fcc81SSam Ravnborg case 'I': 2415040fcc81SSam Ravnborg module_read = optarg; 2416040fcc81SSam Ravnborg external_module = 1; 24171da177e4SLinus Torvalds break; 24182d04b5aeSRichard Hacker case 'e': 24192d04b5aeSRichard Hacker external_module = 1; 24202d04b5aeSRichard Hacker extsym_iter = 24212d04b5aeSRichard Hacker NOFAIL(malloc(sizeof(*extsym_iter))); 24222d04b5aeSRichard Hacker extsym_iter->next = extsym_start; 24232d04b5aeSRichard Hacker extsym_iter->file = optarg; 24242d04b5aeSRichard Hacker extsym_start = extsym_iter; 24252d04b5aeSRichard Hacker break; 24261da177e4SLinus Torvalds case 'm': 24271da177e4SLinus Torvalds modversions = 1; 24281da177e4SLinus Torvalds break; 2429eed380f3SGuenter Roeck case 'n': 2430eed380f3SGuenter Roeck ignore_missing_files = 1; 2431eed380f3SGuenter Roeck break; 24321da177e4SLinus Torvalds case 'o': 24331da177e4SLinus Torvalds dump_write = optarg; 24341da177e4SLinus Torvalds break; 24351da177e4SLinus Torvalds case 'a': 24361da177e4SLinus Torvalds all_versions = 1; 24371da177e4SLinus Torvalds break; 24388d8d8289SSam Ravnborg case 's': 24398d8d8289SSam Ravnborg vmlinux_section_warnings = 0; 24408d8d8289SSam Ravnborg break; 2441588ccd73SSam Ravnborg case 'S': 2442588ccd73SSam Ravnborg sec_mismatch_verbose = 0; 2443588ccd73SSam Ravnborg break; 2444712f9b46SRusty Russell case 'T': 2445712f9b46SRusty Russell files_source = optarg; 2446712f9b46SRusty Russell break; 2447c53ddacdSKirill Korotaev case 'w': 2448c53ddacdSKirill Korotaev warn_unresolved = 1; 2449c53ddacdSKirill Korotaev break; 245047490ec1SNicolas Boichat case 'E': 245147490ec1SNicolas Boichat sec_mismatch_fatal = 1; 245247490ec1SNicolas Boichat break; 24531da177e4SLinus Torvalds default: 24541da177e4SLinus Torvalds exit(1); 24551da177e4SLinus Torvalds } 24561da177e4SLinus Torvalds } 24571da177e4SLinus Torvalds 2458040fcc81SSam Ravnborg if (kernel_read) 2459040fcc81SSam Ravnborg read_dump(kernel_read, 1); 2460040fcc81SSam Ravnborg if (module_read) 2461040fcc81SSam Ravnborg read_dump(module_read, 0); 24622d04b5aeSRichard Hacker while (extsym_start) { 24632d04b5aeSRichard Hacker read_dump(extsym_start->file, 0); 24642d04b5aeSRichard Hacker extsym_iter = extsym_start->next; 24652d04b5aeSRichard Hacker free(extsym_start); 24662d04b5aeSRichard Hacker extsym_start = extsym_iter; 24672d04b5aeSRichard Hacker } 24681da177e4SLinus Torvalds 2469df578e7dSSam Ravnborg while (optind < argc) 24701da177e4SLinus Torvalds read_symbols(argv[optind++]); 24711da177e4SLinus Torvalds 2472712f9b46SRusty Russell if (files_source) 2473712f9b46SRusty Russell read_symbols_from_files(files_source); 2474712f9b46SRusty Russell 24751da177e4SLinus Torvalds for (mod = modules; mod; mod = mod->next) { 24761da177e4SLinus Torvalds if (mod->skip) 24771da177e4SLinus Torvalds continue; 2478c96fca21SSam Ravnborg check_exports(mod); 2479b817f6feSSam Ravnborg } 2480b817f6feSSam Ravnborg 2481c53ddacdSKirill Korotaev err = 0; 2482c53ddacdSKirill Korotaev 2483b817f6feSSam Ravnborg for (mod = modules; mod; mod = mod->next) { 2484d93e1719SMathias Krause char fname[PATH_MAX]; 2485666ab414SAndi Kleen 2486b817f6feSSam Ravnborg if (mod->skip) 2487b817f6feSSam Ravnborg continue; 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds buf.pos = 0; 24901da177e4SLinus Torvalds 24911da177e4SLinus Torvalds add_header(&buf, mod); 24922449b8baSBen Hutchings add_intree_flag(&buf, !external_module); 2493a9860bf0SGreg Kroah-Hartman add_staging_flag(&buf, mod->name); 2494c53ddacdSKirill Korotaev err |= add_versions(&buf, mod); 24951da177e4SLinus Torvalds add_depends(&buf, mod, modules); 24961da177e4SLinus Torvalds add_moddevtable(&buf, mod); 24971da177e4SLinus Torvalds add_srcversion(&buf, mod); 24981da177e4SLinus Torvalds 24991da177e4SLinus Torvalds sprintf(fname, "%s.mod.c", mod->name); 25001da177e4SLinus Torvalds write_if_changed(&buf, fname); 25011da177e4SLinus Torvalds } 25021da177e4SLinus Torvalds if (dump_write) 25031da177e4SLinus Torvalds write_dump(dump_write); 250447490ec1SNicolas Boichat if (sec_mismatch_count) { 250547490ec1SNicolas Boichat if (!sec_mismatch_verbose) { 25067c0ac495SGeert Uytterhoeven warn("modpost: Found %d section mismatch(es).\n" 2507e5f95c8bSSam Ravnborg "To see full details build your kernel with:\n" 2508e5f95c8bSSam Ravnborg "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", 2509e5f95c8bSSam Ravnborg sec_mismatch_count); 251047490ec1SNicolas Boichat } 251147490ec1SNicolas Boichat if (sec_mismatch_fatal) { 251247490ec1SNicolas Boichat fatal("modpost: Section mismatches detected.\n" 251347490ec1SNicolas Boichat "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); 251447490ec1SNicolas Boichat } 251547490ec1SNicolas Boichat } 2516c7d47f26SHeinrich Schuchardt free(buf.p); 25171da177e4SLinus Torvalds 2518c53ddacdSKirill Korotaev return err; 25191da177e4SLinus Torvalds } 2520