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; 61262a26356SAlessio Igor Bogani 613258f7426SFrank Rowand if ((!is_vmlinux(mod->name) || mod->is_dot_o) && 614258f7426SFrank Rowand strncmp(symname, "__ksymtab", 9) == 0) 61562a26356SAlessio Igor Bogani export = export_from_secname(info, get_secindex(info, sym)); 61662a26356SAlessio Igor Bogani else 61762a26356SAlessio Igor Bogani export = export_from_sec(info, get_secindex(info, sym)); 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* CRC'd symbol */ 6208d99513cSMichal Marek if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { 6211da177e4SLinus Torvalds crc = (unsigned int) sym->st_value; 622bd5cbcedSRam Pai sym_update_crc(symname + strlen(CRC_PFX), mod, crc, 623bd5cbcedSRam Pai export); 6241da177e4SLinus Torvalds } 625b5064654SAndi Kleen 626b5064654SAndi Kleen switch (sym->st_shndx) { 627b5064654SAndi Kleen case SHN_COMMON: 628ef178f92SAndi Kleen if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) { 629ef178f92SAndi Kleen /* Should warn here, but modpost runs before the linker */ 630ef178f92SAndi Kleen } else 631b5064654SAndi Kleen warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); 6321da177e4SLinus Torvalds break; 6331da177e4SLinus Torvalds case SHN_UNDEF: 6341da177e4SLinus Torvalds /* undefined symbol */ 6351da177e4SLinus Torvalds if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && 6361da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) != STB_WEAK) 6371da177e4SLinus Torvalds break; 6384d7365d6SSam Ravnborg if (ignore_undef_symbol(info, symname)) 6391da177e4SLinus Torvalds break; 6408d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ 6418d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) 6428d529014SBen Colline /* add compatibility with older glibc */ 6438d529014SBen Colline #ifndef STT_SPARC_REGISTER 6448d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER 6458d529014SBen Colline #endif 6461da177e4SLinus Torvalds if (info->hdr->e_machine == EM_SPARC || 6471da177e4SLinus Torvalds info->hdr->e_machine == EM_SPARCV9) { 6481da177e4SLinus Torvalds /* Ignore register directives. */ 6498d529014SBen Colline if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) 6501da177e4SLinus Torvalds break; 6517caaeabbSAl Viro if (symname[0] == '.') { 6527caaeabbSAl Viro char *munged = strdup(symname); 6537caaeabbSAl Viro munged[0] = '_'; 6547caaeabbSAl Viro munged[1] = toupper(munged[1]); 6557caaeabbSAl Viro symname = munged; 6567caaeabbSAl Viro } 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds #endif 6591da177e4SLinus Torvalds 660b92021b0SRusty Russell #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX 661b92021b0SRusty Russell if (symname[0] != '_') 662b92021b0SRusty Russell break; 663b92021b0SRusty Russell else 664b92021b0SRusty Russell symname++; 665b92021b0SRusty Russell #endif 666b92021b0SRusty Russell mod->unres = alloc_symbol(symname, 6671da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) == STB_WEAK, 6681da177e4SLinus Torvalds mod->unres); 6691da177e4SLinus Torvalds break; 6701da177e4SLinus Torvalds default: 6711da177e4SLinus Torvalds /* All exported symbols */ 6728d99513cSMichal Marek if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { 673bd5cbcedSRam Pai sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, 674bd5cbcedSRam Pai export); 6751da177e4SLinus Torvalds } 676b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0) 6771da177e4SLinus Torvalds mod->has_init = 1; 678b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0) 6791da177e4SLinus Torvalds mod->has_cleanup = 1; 6801da177e4SLinus Torvalds break; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds } 6831da177e4SLinus Torvalds 6845c3ead8cSSam Ravnborg /** 6855c3ead8cSSam Ravnborg * Parse tag=value strings from .modinfo section 6865c3ead8cSSam Ravnborg **/ 6871da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize) 6881da177e4SLinus Torvalds { 6891da177e4SLinus Torvalds /* Skip non-zero chars */ 6901da177e4SLinus Torvalds while (string[0]) { 6911da177e4SLinus Torvalds string++; 6921da177e4SLinus Torvalds if ((*secsize)-- <= 1) 6931da177e4SLinus Torvalds return NULL; 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds /* Skip any zero padding. */ 6971da177e4SLinus Torvalds while (!string[0]) { 6981da177e4SLinus Torvalds string++; 6991da177e4SLinus Torvalds if ((*secsize)-- <= 1) 7001da177e4SLinus Torvalds return NULL; 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds return string; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 705b817f6feSSam Ravnborg static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, 706b817f6feSSam Ravnborg const char *tag, char *info) 7071da177e4SLinus Torvalds { 7081da177e4SLinus Torvalds char *p; 7091da177e4SLinus Torvalds unsigned int taglen = strlen(tag); 7101da177e4SLinus Torvalds unsigned long size = modinfo_len; 7111da177e4SLinus Torvalds 712b817f6feSSam Ravnborg if (info) { 713b817f6feSSam Ravnborg size -= info - (char *)modinfo; 714b817f6feSSam Ravnborg modinfo = next_string(info, &size); 715b817f6feSSam Ravnborg } 716b817f6feSSam Ravnborg 7171da177e4SLinus Torvalds for (p = modinfo; p; p = next_string(p, &size)) { 7181da177e4SLinus Torvalds if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') 7191da177e4SLinus Torvalds return p + taglen + 1; 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds return NULL; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 724b817f6feSSam Ravnborg static char *get_modinfo(void *modinfo, unsigned long modinfo_len, 725b817f6feSSam Ravnborg const char *tag) 726b817f6feSSam Ravnborg 727b817f6feSSam Ravnborg { 728b817f6feSSam Ravnborg return get_next_modinfo(modinfo, modinfo_len, tag, NULL); 729b817f6feSSam Ravnborg } 730b817f6feSSam Ravnborg 73193684d3bSSam Ravnborg /** 7324c8fbca5SSam Ravnborg * Test if string s ends in string sub 7334c8fbca5SSam Ravnborg * return 0 if match 7344c8fbca5SSam Ravnborg **/ 7354c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub) 7364c8fbca5SSam Ravnborg { 7374c8fbca5SSam Ravnborg int slen, sublen; 7384c8fbca5SSam Ravnborg 7394c8fbca5SSam Ravnborg if (!s || !sub) 7404c8fbca5SSam Ravnborg return 1; 7414c8fbca5SSam Ravnborg 7424c8fbca5SSam Ravnborg slen = strlen(s); 7434c8fbca5SSam Ravnborg sublen = strlen(sub); 7444c8fbca5SSam Ravnborg 7454c8fbca5SSam Ravnborg if ((slen == 0) || (sublen == 0)) 7464c8fbca5SSam Ravnborg return 1; 7474c8fbca5SSam Ravnborg 7484c8fbca5SSam Ravnborg if (sublen > slen) 7494c8fbca5SSam Ravnborg return 1; 7504c8fbca5SSam Ravnborg 7514c8fbca5SSam Ravnborg return memcmp(s + slen - sublen, sub, sublen); 7524c8fbca5SSam Ravnborg } 7534c8fbca5SSam Ravnborg 754ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) 755ff13f926SSam Ravnborg { 75658fb0d4fSSam Ravnborg if (sym) 757ff13f926SSam Ravnborg return elf->strtab + sym->st_name; 75858fb0d4fSSam Ravnborg else 759f666751aSSam Ravnborg return "(unknown)"; 760ff13f926SSam Ravnborg } 761ff13f926SSam Ravnborg 7621ce53adfSDenys Vlasenko static const char *sec_name(struct elf_info *elf, int secindex) 763ff13f926SSam Ravnborg { 764ff13f926SSam Ravnborg Elf_Shdr *sechdrs = elf->sechdrs; 765ff13f926SSam Ravnborg return (void *)elf->hdr + 7661ce53adfSDenys Vlasenko elf->sechdrs[elf->secindex_strings].sh_offset + 7671ce53adfSDenys Vlasenko sechdrs[secindex].sh_name; 768ff13f926SSam Ravnborg } 769ff13f926SSam Ravnborg 770ff13f926SSam Ravnborg static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) 771ff13f926SSam Ravnborg { 772ff13f926SSam Ravnborg return (void *)elf->hdr + 7731ce53adfSDenys Vlasenko elf->sechdrs[elf->secindex_strings].sh_offset + 774ff13f926SSam Ravnborg sechdr->sh_name; 775ff13f926SSam Ravnborg } 776ff13f926SSam Ravnborg 77710668220SSam Ravnborg /* The pattern is an array of simple patterns. 77810668220SSam Ravnborg * "foo" will match an exact string equal to "foo" 7796c5bd235SSam Ravnborg * "*foo" will match a string that ends with "foo" 78010668220SSam Ravnborg * "foo*" will match a string that begins with "foo" 78109c20c03SPaul Gortmaker * "*foo*" will match a string that contains "foo" 78210668220SSam Ravnborg */ 7835c725138STrevor Keith static int match(const char *sym, const char * const pat[]) 78410668220SSam Ravnborg { 78510668220SSam Ravnborg const char *p; 78610668220SSam Ravnborg while (*pat) { 78710668220SSam Ravnborg p = *pat++; 78810668220SSam Ravnborg const char *endp = p + strlen(p) - 1; 78910668220SSam Ravnborg 79009c20c03SPaul Gortmaker /* "*foo*" */ 79109c20c03SPaul Gortmaker if (*p == '*' && *endp == '*') { 79209c20c03SPaul Gortmaker char *here, *bare = strndup(p + 1, strlen(p) - 2); 79309c20c03SPaul Gortmaker 79409c20c03SPaul Gortmaker here = strstr(sym, bare); 79509c20c03SPaul Gortmaker free(bare); 79609c20c03SPaul Gortmaker if (here != NULL) 79709c20c03SPaul Gortmaker return 1; 79809c20c03SPaul Gortmaker } 7996c5bd235SSam Ravnborg /* "*foo" */ 80009c20c03SPaul Gortmaker else if (*p == '*') { 8016c5bd235SSam Ravnborg if (strrcmp(sym, p + 1) == 0) 8026c5bd235SSam Ravnborg return 1; 8036c5bd235SSam Ravnborg } 80410668220SSam Ravnborg /* "foo*" */ 8056c5bd235SSam Ravnborg else if (*endp == '*') { 80610668220SSam Ravnborg if (strncmp(sym, p, strlen(p) - 1) == 0) 80710668220SSam Ravnborg return 1; 80810668220SSam Ravnborg } 80910668220SSam Ravnborg /* no wildcards */ 81010668220SSam Ravnborg else { 81110668220SSam Ravnborg if (strcmp(p, sym) == 0) 81210668220SSam Ravnborg return 1; 81310668220SSam Ravnborg } 81410668220SSam Ravnborg } 81510668220SSam Ravnborg /* no match */ 81610668220SSam Ravnborg return 0; 81710668220SSam Ravnborg } 81810668220SSam Ravnborg 81910668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */ 8207a3ee753SMathias Krause static const char *const section_white_list[] = 8214391ed6aSSam Ravnborg { 8224391ed6aSSam Ravnborg ".comment*", 8234391ed6aSSam Ravnborg ".debug*", 8244d10c223SChen Gang ".cranges", /* sh64 */ 8251121584fSH.J. Lu ".zdebug*", /* Compressed debug sections. */ 826019fca84SDavid Howells ".GCC-command-line", /* mn10300 */ 82776b27645SJonathan Kliegman ".GCC.command.line", /* record-gcc-switches, non mn10300 */ 8284391ed6aSSam Ravnborg ".mdebug*", /* alpha, score, mips etc. */ 8294391ed6aSSam Ravnborg ".pdr", /* alpha, score, mips etc. */ 8304391ed6aSSam Ravnborg ".stab*", 8314391ed6aSSam Ravnborg ".note*", 8324391ed6aSSam Ravnborg ".got*", 8334391ed6aSSam Ravnborg ".toc*", 834af42e970SMax Filippov ".xt.prop", /* xtensa */ 835af42e970SMax Filippov ".xt.lit", /* xtensa */ 836f2e207f3SVineet Gupta ".arcextmap*", /* arc */ 837f2e207f3SVineet Gupta ".gnu.linkonce.arcext*", /* arc : modules */ 838d1189c63SNoam Camus ".cmem*", /* EZchip */ 839d1189c63SNoam Camus ".fmt_slot*", /* EZchip */ 840ef178f92SAndi Kleen ".gnu.lto*", 8414391ed6aSSam Ravnborg NULL 8424391ed6aSSam Ravnborg }; 84310668220SSam Ravnborg 844e241a630SSam Ravnborg /* 845b614a697SAnders Kaseorg * This is used to find sections missing the SHF_ALLOC flag. 846e241a630SSam Ravnborg * The cause of this is often a section specified in assembler 847b614a697SAnders Kaseorg * without "ax" / "aw". 848e241a630SSam Ravnborg */ 849b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf, 850b614a697SAnders Kaseorg Elf_Shdr *sechdr) 851e241a630SSam Ravnborg { 852b614a697SAnders Kaseorg const char *sec = sech_name(elf, sechdr); 853e241a630SSam Ravnborg 854b614a697SAnders Kaseorg if (sechdr->sh_type == SHT_PROGBITS && 855b614a697SAnders Kaseorg !(sechdr->sh_flags & SHF_ALLOC) && 856b614a697SAnders Kaseorg !match(sec, section_white_list)) { 857b614a697SAnders Kaseorg warn("%s (%s): unexpected non-allocatable section.\n" 858b614a697SAnders Kaseorg "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" 859e241a630SSam Ravnborg "Note that for example <linux/init.h> contains\n" 860e241a630SSam Ravnborg "section definitions for use in .S files.\n\n", 861e241a630SSam Ravnborg modname, sec); 862e241a630SSam Ravnborg } 863e241a630SSam Ravnborg } 864e241a630SSam Ravnborg 865e241a630SSam Ravnborg 866e241a630SSam Ravnborg 867eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \ 868a0d8f803SRasmus Villemoes ".init.setup", ".init.rodata", ".meminit.rodata", \ 869a0d8f803SRasmus Villemoes ".init.data", ".meminit.data" 870eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \ 871a0d8f803SRasmus Villemoes ".exit.data", ".memexit.data" 87210668220SSam Ravnborg 873eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \ 874a0d8f803SRasmus Villemoes ".init.text", ".meminit.text" 875eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \ 876a0d8f803SRasmus Villemoes ".exit.text", ".memexit.text" 87710668220SSam Ravnborg 878bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS \ 879a0d8f803SRasmus Villemoes ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \ 880a0d8f803SRasmus Villemoes ".pci_fixup_enable", ".pci_fixup_resume", \ 881a0d8f803SRasmus Villemoes ".pci_fixup_resume_early", ".pci_fixup_suspend" 882bb15d8dbSSebastian Andrzej Siewior 883e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS 884e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS 8854a31a229SUwe Kleine-König 8864a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS 8874a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS 88810668220SSam Ravnborg 889a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel" 890157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ 891*6727ad9eSChris Metcalf ".kprobes.text", ".cpuidle.text" 89252dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ 893673c2c34SChris Metcalf ".fixup", ".entry.text", ".exception.text", ".text.*", \ 894673c2c34SChris Metcalf ".coldtext" 89510668220SSam Ravnborg 896fd6c3a8dSJan Beulich #define INIT_SECTIONS ".init.*" 897fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS ".meminit.*" 898eb8f6890SSam Ravnborg 899fd6c3a8dSJan Beulich #define EXIT_SECTIONS ".exit.*" 900fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS ".memexit.*" 901eb8f6890SSam Ravnborg 90252dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \ 90352dc0595SQuentin Casasnovas TEXT_SECTIONS, OTHER_TEXT_SECTIONS 90452dc0595SQuentin Casasnovas 9056c5bd235SSam Ravnborg /* init data sections */ 9067a3ee753SMathias Krause static const char *const init_data_sections[] = 9077a3ee753SMathias Krause { ALL_INIT_DATA_SECTIONS, NULL }; 9086c5bd235SSam Ravnborg 9096c5bd235SSam Ravnborg /* all init sections */ 9107a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; 9116c5bd235SSam Ravnborg 9126c5bd235SSam Ravnborg /* All init and exit sections (code + data) */ 9137a3ee753SMathias Krause static const char *const init_exit_sections[] = 914eb8f6890SSam Ravnborg {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; 9156c5bd235SSam Ravnborg 9164a3893d0SPaul Gortmaker /* all text sections */ 9174a3893d0SPaul Gortmaker static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL }; 9184a3893d0SPaul Gortmaker 9196c5bd235SSam Ravnborg /* data section */ 9207a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL }; 9216c5bd235SSam Ravnborg 9226c5bd235SSam Ravnborg 9236c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */ 924af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST \ 925af92a82dSUwe Kleine-König "*driver", \ 926af92a82dSUwe Kleine-König "*_template", /* scsi uses *_template a lot */ \ 927af92a82dSUwe Kleine-König "*_timer", /* arm uses ops structures named _timer a lot */ \ 928af92a82dSUwe Kleine-König "*_sht", /* scsi also used *_sht to some extent */ \ 929af92a82dSUwe Kleine-König "*_ops", \ 930af92a82dSUwe Kleine-König "*_probe", \ 931af92a82dSUwe Kleine-König "*_probe_one", \ 932af92a82dSUwe Kleine-König "*_console" 9336c5bd235SSam Ravnborg 9347a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL }; 9357a3ee753SMathias Krause static const char *const linker_symbols[] = 9366c5bd235SSam Ravnborg { "__init_begin", "_sinittext", "_einittext", NULL }; 9374a3893d0SPaul Gortmaker static const char *const optim_symbols[] = { "*.constprop.*", NULL }; 9386c5bd235SSam Ravnborg 939588ccd73SSam Ravnborg enum mismatch { 940bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_INIT, 941bbd3f4fbSUwe Kleine-König DATA_TO_ANY_INIT, 942bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_EXIT, 943bbd3f4fbSUwe Kleine-König DATA_TO_ANY_EXIT, 944bbd3f4fbSUwe Kleine-König XXXINIT_TO_SOME_INIT, 945bbd3f4fbSUwe Kleine-König XXXEXIT_TO_SOME_EXIT, 946bbd3f4fbSUwe Kleine-König ANY_INIT_TO_ANY_EXIT, 947bbd3f4fbSUwe Kleine-König ANY_EXIT_TO_ANY_INIT, 948588ccd73SSam Ravnborg EXPORT_TO_INIT_EXIT, 94952dc0595SQuentin Casasnovas EXTABLE_TO_NON_TEXT, 950588ccd73SSam Ravnborg }; 951588ccd73SSam Ravnborg 952e5d8f59aSQuentin Casasnovas /** 953e5d8f59aSQuentin Casasnovas * Describe how to match sections on different criterias: 954e5d8f59aSQuentin Casasnovas * 955e5d8f59aSQuentin Casasnovas * @fromsec: Array of sections to be matched. 956e5d8f59aSQuentin Casasnovas * 957e5d8f59aSQuentin Casasnovas * @bad_tosec: Relocations applied to a section in @fromsec to a section in 958e5d8f59aSQuentin Casasnovas * this array is forbidden (black-list). Can be empty. 959e5d8f59aSQuentin Casasnovas * 960e5d8f59aSQuentin Casasnovas * @good_tosec: Relocations applied to a section in @fromsec must be 961e5d8f59aSQuentin Casasnovas * targetting sections in this array (white-list). Can be empty. 962e5d8f59aSQuentin Casasnovas * 963e5d8f59aSQuentin Casasnovas * @mismatch: Type of mismatch. 964e5d8f59aSQuentin Casasnovas * 965e5d8f59aSQuentin Casasnovas * @symbol_white_list: Do not match a relocation to a symbol in this list 966e5d8f59aSQuentin Casasnovas * even if it is targetting a section in @bad_to_sec. 967e5d8f59aSQuentin Casasnovas * 968e5d8f59aSQuentin Casasnovas * @handler: Specific handler to call when a match is found. If NULL, 969e5d8f59aSQuentin Casasnovas * default_mismatch_handler() will be called. 970e5d8f59aSQuentin Casasnovas * 971e5d8f59aSQuentin Casasnovas */ 97210668220SSam Ravnborg struct sectioncheck { 97310668220SSam Ravnborg const char *fromsec[20]; 974050e57fdSQuentin Casasnovas const char *bad_tosec[20]; 975050e57fdSQuentin Casasnovas const char *good_tosec[20]; 976588ccd73SSam Ravnborg enum mismatch mismatch; 977af92a82dSUwe Kleine-König const char *symbol_white_list[20]; 978644e8f14SQuentin Casasnovas void (*handler)(const char *modname, struct elf_info *elf, 979644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 980644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec); 981644e8f14SQuentin Casasnovas 98210668220SSam Ravnborg }; 98310668220SSam Ravnborg 98452dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf, 98552dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 98652dc0595SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, 98752dc0595SQuentin Casasnovas const char *fromsec); 98852dc0595SQuentin Casasnovas 9897a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = { 99010668220SSam Ravnborg /* Do not reference init/exit code/data from 99110668220SSam Ravnborg * normal code and data 99210668220SSam Ravnborg */ 99310668220SSam Ravnborg { 994588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 995050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 996bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_INIT, 997af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 998588ccd73SSam Ravnborg }, 999588ccd73SSam Ravnborg { 1000588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 1001050e57fdSQuentin Casasnovas .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, 1002bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 1003af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1004588ccd73SSam Ravnborg }, 1005588ccd73SSam Ravnborg { 10060db25245SUwe Kleine-König .fromsec = { DATA_SECTIONS, NULL }, 1007050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 10080db25245SUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 10090db25245SUwe Kleine-König .symbol_white_list = { 10100db25245SUwe Kleine-König "*_template", "*_timer", "*_sht", "*_ops", 10110db25245SUwe Kleine-König "*_probe", "*_probe_one", "*_console", NULL 10120db25245SUwe Kleine-König }, 10130db25245SUwe Kleine-König }, 10140db25245SUwe Kleine-König { 1015588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 1016050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1017bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_EXIT, 1018af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1019588ccd73SSam Ravnborg }, 1020588ccd73SSam Ravnborg { 1021588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 1022050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1023bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_EXIT, 1024af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1025eb8f6890SSam Ravnborg }, 1026e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */ 1027eb8f6890SSam Ravnborg { 10284a31a229SUwe Kleine-König .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, 1029050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1030bbd3f4fbSUwe Kleine-König .mismatch = XXXINIT_TO_SOME_INIT, 1031af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1032eb8f6890SSam Ravnborg }, 1033e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */ 1034eb8f6890SSam Ravnborg { 10354a31a229SUwe Kleine-König .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, 1036050e57fdSQuentin Casasnovas .bad_tosec = { EXIT_SECTIONS, NULL }, 1037bbd3f4fbSUwe Kleine-König .mismatch = XXXEXIT_TO_SOME_EXIT, 1038af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 103910668220SSam Ravnborg }, 104010668220SSam Ravnborg /* Do not use exit code/data from init code */ 104110668220SSam Ravnborg { 1042eb8f6890SSam Ravnborg .fromsec = { ALL_INIT_SECTIONS, NULL }, 1043050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1044bbd3f4fbSUwe Kleine-König .mismatch = ANY_INIT_TO_ANY_EXIT, 1045af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 104610668220SSam Ravnborg }, 104710668220SSam Ravnborg /* Do not use init code/data from exit code */ 104810668220SSam Ravnborg { 1049eb8f6890SSam Ravnborg .fromsec = { ALL_EXIT_SECTIONS, NULL }, 1050050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 1051bbd3f4fbSUwe Kleine-König .mismatch = ANY_EXIT_TO_ANY_INIT, 1052af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 105310668220SSam Ravnborg }, 1054bb15d8dbSSebastian Andrzej Siewior { 1055bb15d8dbSSebastian Andrzej Siewior .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, 1056050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1057bb15d8dbSSebastian Andrzej Siewior .mismatch = ANY_INIT_TO_ANY_EXIT, 1058bb15d8dbSSebastian Andrzej Siewior .symbol_white_list = { NULL }, 1059bb15d8dbSSebastian Andrzej Siewior }, 106010668220SSam Ravnborg /* Do not export init/exit functions or data */ 106110668220SSam Ravnborg { 106210668220SSam Ravnborg .fromsec = { "__ksymtab*", NULL }, 1063050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, 1064af92a82dSUwe Kleine-König .mismatch = EXPORT_TO_INIT_EXIT, 1065af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 106652dc0595SQuentin Casasnovas }, 106752dc0595SQuentin Casasnovas { 106852dc0595SQuentin Casasnovas .fromsec = { "__ex_table", NULL }, 106952dc0595SQuentin Casasnovas /* If you're adding any new black-listed sections in here, consider 107052dc0595SQuentin Casasnovas * adding a special 'printer' for them in scripts/check_extable. 107152dc0595SQuentin Casasnovas */ 107252dc0595SQuentin Casasnovas .bad_tosec = { ".altinstr_replacement", NULL }, 107352dc0595SQuentin Casasnovas .good_tosec = {ALL_TEXT_SECTIONS , NULL}, 107452dc0595SQuentin Casasnovas .mismatch = EXTABLE_TO_NON_TEXT, 107552dc0595SQuentin Casasnovas .handler = extable_mismatch_handler, 107610668220SSam Ravnborg } 107710668220SSam Ravnborg }; 107810668220SSam Ravnborg 10790d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch( 10800d2a636eSUwe Kleine-König const char *fromsec, const char *tosec) 108110668220SSam Ravnborg { 108210668220SSam Ravnborg int i; 108310668220SSam Ravnborg int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); 108410668220SSam Ravnborg const struct sectioncheck *check = §ioncheck[0]; 108510668220SSam Ravnborg 1086c5c3439aSQuentin Casasnovas /* 1087c5c3439aSQuentin Casasnovas * The target section could be the SHT_NUL section when we're 1088c5c3439aSQuentin Casasnovas * handling relocations to un-resolved symbols, trying to match it 1089c5c3439aSQuentin Casasnovas * doesn't make much sense and causes build failures on parisc and 1090c5c3439aSQuentin Casasnovas * mn10300 architectures. 1091c5c3439aSQuentin Casasnovas */ 1092c5c3439aSQuentin Casasnovas if (*tosec == '\0') 1093c5c3439aSQuentin Casasnovas return NULL; 1094c5c3439aSQuentin Casasnovas 109510668220SSam Ravnborg for (i = 0; i < elems; i++) { 1096050e57fdSQuentin Casasnovas if (match(fromsec, check->fromsec)) { 1097050e57fdSQuentin Casasnovas if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) 10980d2a636eSUwe Kleine-König return check; 1099050e57fdSQuentin Casasnovas if (check->good_tosec[0] && !match(tosec, check->good_tosec)) 1100050e57fdSQuentin Casasnovas return check; 1101050e57fdSQuentin Casasnovas } 110210668220SSam Ravnborg check++; 110310668220SSam Ravnborg } 11040d2a636eSUwe Kleine-König return NULL; 110510668220SSam Ravnborg } 110610668220SSam Ravnborg 11074c8fbca5SSam Ravnborg /** 11084c8fbca5SSam Ravnborg * Whitelist to allow certain references to pass with no warning. 11090e0d314eSSam Ravnborg * 11104c8fbca5SSam Ravnborg * Pattern 1: 11114c8fbca5SSam Ravnborg * If a module parameter is declared __initdata and permissions=0 11124c8fbca5SSam Ravnborg * then this is legal despite the warning generated. 11134c8fbca5SSam Ravnborg * We cannot see value of permissions here, so just ignore 11144c8fbca5SSam Ravnborg * this pattern. 11154c8fbca5SSam Ravnborg * The pattern is identified by: 11164c8fbca5SSam Ravnborg * tosec = .init.data 11179209aed0SSam Ravnborg * fromsec = .data* 11184c8fbca5SSam Ravnborg * atsym =__param* 11194c8fbca5SSam Ravnborg * 11206a841528SRusty Russell * Pattern 1a: 11216a841528SRusty Russell * module_param_call() ops can refer to __init set function if permissions=0 11226a841528SRusty Russell * The pattern is identified by: 11236a841528SRusty Russell * tosec = .init.text 11246a841528SRusty Russell * fromsec = .data* 11256a841528SRusty Russell * atsym = __param_ops_* 11266a841528SRusty Russell * 11274c8fbca5SSam Ravnborg * Pattern 2: 112872ee59b5SRandy Dunlap * Many drivers utilise a *driver container with references to 11294c8fbca5SSam Ravnborg * add, remove, probe functions etc. 11304c8fbca5SSam Ravnborg * the pattern is identified by: 113183cda2bbSSam Ravnborg * tosec = init or exit section 113283cda2bbSSam Ravnborg * fromsec = data section 1133df578e7dSSam Ravnborg * atsym = *driver, *_template, *_sht, *_ops, *_probe, 1134df578e7dSSam Ravnborg * *probe_one, *_console, *_timer 1135ee6a8545SVivek Goyal * 1136ee6a8545SVivek Goyal * Pattern 3: 1137c993971fSSam Ravnborg * Whitelist all references from .head.text to any init section 11389bf8cb9bSSam Ravnborg * 11391d8af559SSam Ravnborg * Pattern 4: 1140ee6a8545SVivek Goyal * Some symbols belong to init section but still it is ok to reference 1141ee6a8545SVivek Goyal * these from non-init sections as these symbols don't have any memory 1142ee6a8545SVivek Goyal * allocated for them and symbol address and value are same. So even 1143ee6a8545SVivek Goyal * if init section is freed, its ok to reference those symbols. 1144ee6a8545SVivek Goyal * For ex. symbols marking the init section boundaries. 1145ee6a8545SVivek Goyal * This pattern is identified by 1146ee6a8545SVivek Goyal * refsymname = __init_begin, _sinittext, _einittext 11479bf8cb9bSSam Ravnborg * 11484a3893d0SPaul Gortmaker * Pattern 5: 11494a3893d0SPaul Gortmaker * GCC may optimize static inlines when fed constant arg(s) resulting 11504a3893d0SPaul Gortmaker * in functions like cpumask_empty() -- generating an associated symbol 11514a3893d0SPaul Gortmaker * cpumask_empty.constprop.3 that appears in the audit. If the const that 11524a3893d0SPaul Gortmaker * is passed in comes from __init, like say nmi_ipi_mask, we get a 11534a3893d0SPaul Gortmaker * meaningless section warning. May need to add isra symbols too... 11544a3893d0SPaul Gortmaker * This pattern is identified by 11554a3893d0SPaul Gortmaker * tosec = init section 11564a3893d0SPaul Gortmaker * fromsec = text section 11574a3893d0SPaul Gortmaker * refsymname = *.constprop.* 11584a3893d0SPaul Gortmaker * 11594c8fbca5SSam Ravnborg **/ 1160af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch, 1161af92a82dSUwe Kleine-König const char *fromsec, const char *fromsym, 116258fb0d4fSSam Ravnborg const char *tosec, const char *tosym) 11634c8fbca5SSam Ravnborg { 11644c8fbca5SSam Ravnborg /* Check for pattern 1 */ 11656c5bd235SSam Ravnborg if (match(tosec, init_data_sections) && 11666c5bd235SSam Ravnborg match(fromsec, data_sections) && 116758fb0d4fSSam Ravnborg (strncmp(fromsym, "__param", strlen("__param")) == 0)) 116858fb0d4fSSam Ravnborg return 0; 11694c8fbca5SSam Ravnborg 11706a841528SRusty Russell /* Check for pattern 1a */ 11716a841528SRusty Russell if (strcmp(tosec, ".init.text") == 0 && 11726a841528SRusty Russell match(fromsec, data_sections) && 11736a841528SRusty Russell (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0)) 11746a841528SRusty Russell return 0; 11756a841528SRusty Russell 11764c8fbca5SSam Ravnborg /* Check for pattern 2 */ 11776c5bd235SSam Ravnborg if (match(tosec, init_exit_sections) && 11786c5bd235SSam Ravnborg match(fromsec, data_sections) && 1179af92a82dSUwe Kleine-König match(fromsym, mismatch->symbol_white_list)) 118058fb0d4fSSam Ravnborg return 0; 11814c8fbca5SSam Ravnborg 11829bf8cb9bSSam Ravnborg /* Check for pattern 3 */ 11836c5bd235SSam Ravnborg if (match(fromsec, head_sections) && 11846c5bd235SSam Ravnborg match(tosec, init_sections)) 118558fb0d4fSSam Ravnborg return 0; 1186f8657e1bSVivek Goyal 11871d8af559SSam Ravnborg /* Check for pattern 4 */ 118858fb0d4fSSam Ravnborg if (match(tosym, linker_symbols)) 118993659af1SSam Ravnborg return 0; 119058fb0d4fSSam Ravnborg 11914a3893d0SPaul Gortmaker /* Check for pattern 5 */ 11924a3893d0SPaul Gortmaker if (match(fromsec, text_sections) && 11934a3893d0SPaul Gortmaker match(tosec, init_sections) && 11944a3893d0SPaul Gortmaker match(fromsym, optim_symbols)) 11954a3893d0SPaul Gortmaker return 0; 11964a3893d0SPaul Gortmaker 119758fb0d4fSSam Ravnborg return 1; 11984c8fbca5SSam Ravnborg } 11994c8fbca5SSam Ravnborg 12004c8fbca5SSam Ravnborg /** 120193684d3bSSam Ravnborg * Find symbol based on relocation record info. 120293684d3bSSam Ravnborg * In some cases the symbol supplied is a valid symbol so 120393684d3bSSam Ravnborg * return refsym. If st_name != 0 we assume this is a valid symbol. 120493684d3bSSam Ravnborg * In other cases the symbol needs to be looked up in the symbol table 120593684d3bSSam Ravnborg * based on section and address. 120693684d3bSSam Ravnborg * **/ 12079ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, 120893684d3bSSam Ravnborg Elf_Sym *relsym) 120993684d3bSSam Ravnborg { 121093684d3bSSam Ravnborg Elf_Sym *sym; 12119ad21c3fSSam Ravnborg Elf_Sym *near = NULL; 12129ad21c3fSSam Ravnborg Elf64_Sword distance = 20; 12139ad21c3fSSam Ravnborg Elf64_Sword d; 12141ce53adfSDenys Vlasenko unsigned int relsym_secindex; 121593684d3bSSam Ravnborg 121693684d3bSSam Ravnborg if (relsym->st_name != 0) 121793684d3bSSam Ravnborg return relsym; 12181ce53adfSDenys Vlasenko 12191ce53adfSDenys Vlasenko relsym_secindex = get_secindex(elf, relsym); 122093684d3bSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 12211ce53adfSDenys Vlasenko if (get_secindex(elf, sym) != relsym_secindex) 122293684d3bSSam Ravnborg continue; 1223ae4ac123SAtsushi Nemoto if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) 1224ae4ac123SAtsushi Nemoto continue; 122593684d3bSSam Ravnborg if (sym->st_value == addr) 122693684d3bSSam Ravnborg return sym; 12279ad21c3fSSam Ravnborg /* Find a symbol nearby - addr are maybe negative */ 12289ad21c3fSSam Ravnborg d = sym->st_value - addr; 12299ad21c3fSSam Ravnborg if (d < 0) 12309ad21c3fSSam Ravnborg d = addr - sym->st_value; 12319ad21c3fSSam Ravnborg if (d < distance) { 12329ad21c3fSSam Ravnborg distance = d; 12339ad21c3fSSam Ravnborg near = sym; 123493684d3bSSam Ravnborg } 12359ad21c3fSSam Ravnborg } 12369ad21c3fSSam Ravnborg /* We need a close match */ 12379ad21c3fSSam Ravnborg if (distance < 20) 12389ad21c3fSSam Ravnborg return near; 12399ad21c3fSSam Ravnborg else 124093684d3bSSam Ravnborg return NULL; 124193684d3bSSam Ravnborg } 124293684d3bSSam Ravnborg 1243da68d61fSDavid Brownell static inline int is_arm_mapping_symbol(const char *str) 1244da68d61fSDavid Brownell { 12456c34f1f5SKyle McMartin return str[0] == '$' && strchr("axtd", str[1]) 1246da68d61fSDavid Brownell && (str[2] == '\0' || str[2] == '.'); 1247da68d61fSDavid Brownell } 1248da68d61fSDavid Brownell 1249da68d61fSDavid Brownell /* 1250da68d61fSDavid Brownell * If there's no name there, ignore it; likewise, ignore it if it's 1251da68d61fSDavid Brownell * one of the magic symbols emitted used by current ARM tools. 1252da68d61fSDavid Brownell * 1253da68d61fSDavid Brownell * Otherwise if find_symbols_between() returns those symbols, they'll 1254da68d61fSDavid Brownell * fail the whitelist tests and cause lots of false alarms ... fixable 1255da68d61fSDavid Brownell * only by merging __exit and __init sections into __text, bloating 1256da68d61fSDavid Brownell * the kernel (which is especially evil on embedded platforms). 1257da68d61fSDavid Brownell */ 1258da68d61fSDavid Brownell static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym) 1259da68d61fSDavid Brownell { 1260da68d61fSDavid Brownell const char *name = elf->strtab + sym->st_name; 1261da68d61fSDavid Brownell 1262da68d61fSDavid Brownell if (!name || !strlen(name)) 1263da68d61fSDavid Brownell return 0; 1264da68d61fSDavid Brownell return !is_arm_mapping_symbol(name); 1265da68d61fSDavid Brownell } 1266da68d61fSDavid Brownell 1267b39927cfSSam Ravnborg /* 126843c74d17SSam Ravnborg * Find symbols before or equal addr and after addr - in the section sec. 126943c74d17SSam Ravnborg * If we find two symbols with equal offset prefer one with a valid name. 127043c74d17SSam Ravnborg * The ELF format may have a better way to detect what type of symbol 127143c74d17SSam Ravnborg * it is, but this works for now. 1272b39927cfSSam Ravnborg **/ 1273157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, 1274157c23c8SSam Ravnborg const char *sec) 1275b39927cfSSam Ravnborg { 1276b39927cfSSam Ravnborg Elf_Sym *sym; 1277157c23c8SSam Ravnborg Elf_Sym *near = NULL; 1278157c23c8SSam Ravnborg Elf_Addr distance = ~0; 1279b39927cfSSam Ravnborg 1280b39927cfSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 1281b39927cfSSam Ravnborg const char *symsec; 1282b39927cfSSam Ravnborg 12831ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1284b39927cfSSam Ravnborg continue; 12851ce53adfSDenys Vlasenko symsec = sec_name(elf, get_secindex(elf, sym)); 1286b39927cfSSam Ravnborg if (strcmp(symsec, sec) != 0) 1287b39927cfSSam Ravnborg continue; 1288da68d61fSDavid Brownell if (!is_valid_name(elf, sym)) 1289da68d61fSDavid Brownell continue; 1290b39927cfSSam Ravnborg if (sym->st_value <= addr) { 1291157c23c8SSam Ravnborg if ((addr - sym->st_value) < distance) { 1292157c23c8SSam Ravnborg distance = addr - sym->st_value; 1293157c23c8SSam Ravnborg near = sym; 1294157c23c8SSam Ravnborg } else if ((addr - sym->st_value) == distance) { 1295157c23c8SSam Ravnborg near = sym; 129643c74d17SSam Ravnborg } 1297b39927cfSSam Ravnborg } 1298b39927cfSSam Ravnborg } 1299157c23c8SSam Ravnborg return near; 1300157c23c8SSam Ravnborg } 1301b39927cfSSam Ravnborg 130258fb0d4fSSam Ravnborg /* 1303588ccd73SSam Ravnborg * Convert a section name to the function/data attribute 1304588ccd73SSam Ravnborg * .init.text => __init 1305588ccd73SSam Ravnborg * .memexitconst => __memconst 1306588ccd73SSam Ravnborg * etc. 1307cbcf14a9SAndy Shevchenko * 1308cbcf14a9SAndy Shevchenko * The memory of returned value has been allocated on a heap. The user of this 1309cbcf14a9SAndy Shevchenko * method should free it after usage. 1310588ccd73SSam Ravnborg */ 1311588ccd73SSam Ravnborg static char *sec2annotation(const char *s) 1312588ccd73SSam Ravnborg { 1313588ccd73SSam Ravnborg if (match(s, init_exit_sections)) { 1314588ccd73SSam Ravnborg char *p = malloc(20); 1315588ccd73SSam Ravnborg char *r = p; 1316588ccd73SSam Ravnborg 1317588ccd73SSam Ravnborg *p++ = '_'; 1318588ccd73SSam Ravnborg *p++ = '_'; 1319588ccd73SSam Ravnborg if (*s == '.') 1320588ccd73SSam Ravnborg s++; 1321588ccd73SSam Ravnborg while (*s && *s != '.') 1322588ccd73SSam Ravnborg *p++ = *s++; 1323588ccd73SSam Ravnborg *p = '\0'; 1324588ccd73SSam Ravnborg if (*s == '.') 1325588ccd73SSam Ravnborg s++; 1326588ccd73SSam Ravnborg if (strstr(s, "rodata") != NULL) 1327588ccd73SSam Ravnborg strcat(p, "const "); 1328588ccd73SSam Ravnborg else if (strstr(s, "data") != NULL) 1329588ccd73SSam Ravnborg strcat(p, "data "); 1330588ccd73SSam Ravnborg else 1331588ccd73SSam Ravnborg strcat(p, " "); 1332cbcf14a9SAndy Shevchenko return r; 1333588ccd73SSam Ravnborg } else { 13345003bab8SAndrew Morton return strdup(""); 1335588ccd73SSam Ravnborg } 1336588ccd73SSam Ravnborg } 1337588ccd73SSam Ravnborg 1338588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym) 1339588ccd73SSam Ravnborg { 1340588ccd73SSam Ravnborg if (sym) 1341588ccd73SSam Ravnborg return ELF_ST_TYPE(sym->st_info) == STT_FUNC; 1342588ccd73SSam Ravnborg else 1343f666751aSSam Ravnborg return -1; 1344588ccd73SSam Ravnborg } 1345588ccd73SSam Ravnborg 134600759c0eSRandy Dunlap static void print_section_list(const char * const list[20]) 134700759c0eSRandy Dunlap { 134800759c0eSRandy Dunlap const char *const *s = list; 134900759c0eSRandy Dunlap 135000759c0eSRandy Dunlap while (*s) { 135100759c0eSRandy Dunlap fprintf(stderr, "%s", *s); 135200759c0eSRandy Dunlap s++; 135300759c0eSRandy Dunlap if (*s) 135400759c0eSRandy Dunlap fprintf(stderr, ", "); 135500759c0eSRandy Dunlap } 135600759c0eSRandy Dunlap fprintf(stderr, "\n"); 135700759c0eSRandy Dunlap } 135800759c0eSRandy Dunlap 1359356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p) 1360356ad538SQuentin Casasnovas { 1361356ad538SQuentin Casasnovas switch (is_func) { 1362356ad538SQuentin Casasnovas case 0: *name = "variable"; *name_p = ""; break; 1363356ad538SQuentin Casasnovas case 1: *name = "function"; *name_p = "()"; break; 1364356ad538SQuentin Casasnovas default: *name = "(unknown reference)"; *name_p = ""; break; 1365356ad538SQuentin Casasnovas } 1366356ad538SQuentin Casasnovas } 1367356ad538SQuentin Casasnovas 1368588ccd73SSam Ravnborg /* 1369b39927cfSSam Ravnborg * Print a warning about a section mismatch. 1370b39927cfSSam Ravnborg * Try to find symbols near it so user can find it. 13714c8fbca5SSam Ravnborg * Check whitelist before warning - it may be a false positive. 137258fb0d4fSSam Ravnborg */ 13730d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname, 13740d2a636eSUwe Kleine-König const struct sectioncheck *mismatch, 137558fb0d4fSSam Ravnborg const char *fromsec, 137658fb0d4fSSam Ravnborg unsigned long long fromaddr, 137758fb0d4fSSam Ravnborg const char *fromsym, 1378588ccd73SSam Ravnborg int from_is_func, 1379588ccd73SSam Ravnborg const char *tosec, const char *tosym, 1380588ccd73SSam Ravnborg int to_is_func) 1381b39927cfSSam Ravnborg { 1382588ccd73SSam Ravnborg const char *from, *from_p; 1383588ccd73SSam Ravnborg const char *to, *to_p; 138437ed19d5SAlexey Fomenko char *prl_from; 138537ed19d5SAlexey Fomenko char *prl_to; 1386f666751aSSam Ravnborg 1387e5f95c8bSSam Ravnborg sec_mismatch_count++; 1388e5f95c8bSSam Ravnborg if (!sec_mismatch_verbose) 1389e5f95c8bSSam Ravnborg return; 1390e5f95c8bSSam Ravnborg 1391356ad538SQuentin Casasnovas get_pretty_name(from_is_func, &from, &from_p); 1392356ad538SQuentin Casasnovas get_pretty_name(to_is_func, &to, &to_p); 1393356ad538SQuentin Casasnovas 13947c0ac495SGeert Uytterhoeven warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " 13957c0ac495SGeert Uytterhoeven "to the %s %s:%s%s\n", 13967c0ac495SGeert Uytterhoeven modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, 13977c0ac495SGeert Uytterhoeven tosym, to_p); 1398588ccd73SSam Ravnborg 13990d2a636eSUwe Kleine-König switch (mismatch->mismatch) { 1400bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_INIT: 140137ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 140237ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1403588ccd73SSam Ravnborg fprintf(stderr, 1404588ccd73SSam Ravnborg "The function %s%s() references\n" 1405588ccd73SSam Ravnborg "the %s %s%s%s.\n" 1406588ccd73SSam Ravnborg "This is often because %s lacks a %s\n" 1407588ccd73SSam Ravnborg "annotation or the annotation of %s is wrong.\n", 140837ed19d5SAlexey Fomenko prl_from, fromsym, 140937ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 141037ed19d5SAlexey Fomenko fromsym, prl_to, tosym); 141137ed19d5SAlexey Fomenko free(prl_from); 141237ed19d5SAlexey Fomenko free(prl_to); 1413588ccd73SSam Ravnborg break; 1414bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_INIT: { 141537ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1416588ccd73SSam Ravnborg fprintf(stderr, 1417588ccd73SSam Ravnborg "The variable %s references\n" 1418588ccd73SSam Ravnborg "the %s %s%s%s\n" 1419588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 14208b8b76c0SSam Ravnborg "variable with __init* or __refdata (see linux/init.h) " 1421588ccd73SSam Ravnborg "or name the variable:\n", 142237ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 142300759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 142437ed19d5SAlexey Fomenko free(prl_to); 1425588ccd73SSam Ravnborg break; 142658fb0d4fSSam Ravnborg } 1427bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_EXIT: 142837ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1429588ccd73SSam Ravnborg fprintf(stderr, 1430588ccd73SSam Ravnborg "The function %s() references a %s in an exit section.\n" 1431588ccd73SSam Ravnborg "Often the %s %s%s has valid usage outside the exit section\n" 1432588ccd73SSam Ravnborg "and the fix is to remove the %sannotation of %s.\n", 143337ed19d5SAlexey Fomenko fromsym, to, to, tosym, to_p, prl_to, tosym); 143437ed19d5SAlexey Fomenko free(prl_to); 1435588ccd73SSam Ravnborg break; 1436bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_EXIT: { 143737ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1438588ccd73SSam Ravnborg fprintf(stderr, 1439588ccd73SSam Ravnborg "The variable %s references\n" 1440588ccd73SSam Ravnborg "the %s %s%s%s\n" 1441588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 1442588ccd73SSam Ravnborg "variable with __exit* (see linux/init.h) or " 1443588ccd73SSam Ravnborg "name the variable:\n", 144437ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 144500759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 144637ed19d5SAlexey Fomenko free(prl_to); 1447588ccd73SSam Ravnborg break; 1448588ccd73SSam Ravnborg } 1449bbd3f4fbSUwe Kleine-König case XXXINIT_TO_SOME_INIT: 1450bbd3f4fbSUwe Kleine-König case XXXEXIT_TO_SOME_EXIT: 145137ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 145237ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1453588ccd73SSam Ravnborg fprintf(stderr, 1454588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1455588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1456588ccd73SSam Ravnborg "If %s is only used by %s then\n" 1457588ccd73SSam Ravnborg "annotate %s with a matching annotation.\n", 145837ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 145937ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 1460b1d2675aSGeert Uytterhoeven tosym, fromsym, tosym); 146137ed19d5SAlexey Fomenko free(prl_from); 146237ed19d5SAlexey Fomenko free(prl_to); 1463588ccd73SSam Ravnborg break; 1464bbd3f4fbSUwe Kleine-König case ANY_INIT_TO_ANY_EXIT: 146537ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 146637ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1467588ccd73SSam Ravnborg fprintf(stderr, 1468588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1469588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1470588ccd73SSam Ravnborg "This is often seen when error handling " 1471588ccd73SSam Ravnborg "in the init function\n" 1472588ccd73SSam Ravnborg "uses functionality in the exit path.\n" 1473588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1474588ccd73SSam Ravnborg "%s%s so it may be used outside an exit section.\n", 147537ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 147637ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 14775003bab8SAndrew Morton prl_to, tosym, to_p); 147837ed19d5SAlexey Fomenko free(prl_from); 147937ed19d5SAlexey Fomenko free(prl_to); 1480588ccd73SSam Ravnborg break; 1481bbd3f4fbSUwe Kleine-König case ANY_EXIT_TO_ANY_INIT: 148237ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 148337ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1484588ccd73SSam Ravnborg fprintf(stderr, 1485588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1486588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1487588ccd73SSam Ravnborg "This is often seen when error handling " 1488588ccd73SSam Ravnborg "in the exit function\n" 1489588ccd73SSam Ravnborg "uses functionality in the init path.\n" 1490588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1491588ccd73SSam Ravnborg "%s%s so it may be used outside an init section.\n", 149237ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 149337ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 149437ed19d5SAlexey Fomenko prl_to, tosym, to_p); 149537ed19d5SAlexey Fomenko free(prl_from); 149637ed19d5SAlexey Fomenko free(prl_to); 1497588ccd73SSam Ravnborg break; 1498588ccd73SSam Ravnborg case EXPORT_TO_INIT_EXIT: 149937ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1500588ccd73SSam Ravnborg fprintf(stderr, 1501588ccd73SSam Ravnborg "The symbol %s is exported and annotated %s\n" 1502588ccd73SSam Ravnborg "Fix this by removing the %sannotation of %s " 1503588ccd73SSam Ravnborg "or drop the export.\n", 150437ed19d5SAlexey Fomenko tosym, prl_to, prl_to, tosym); 150537ed19d5SAlexey Fomenko free(prl_to); 1506588ccd73SSam Ravnborg break; 150752dc0595SQuentin Casasnovas case EXTABLE_TO_NON_TEXT: 150852dc0595SQuentin Casasnovas fatal("There's a special handler for this mismatch type, " 150952dc0595SQuentin Casasnovas "we should never get here."); 151052dc0595SQuentin Casasnovas break; 1511588ccd73SSam Ravnborg } 1512588ccd73SSam Ravnborg fprintf(stderr, "\n"); 151358fb0d4fSSam Ravnborg } 151458fb0d4fSSam Ravnborg 1515644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf, 1516644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 151758fb0d4fSSam Ravnborg Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 151858fb0d4fSSam Ravnborg { 151958fb0d4fSSam Ravnborg const char *tosec; 1520588ccd73SSam Ravnborg Elf_Sym *to; 1521588ccd73SSam Ravnborg Elf_Sym *from; 152258fb0d4fSSam Ravnborg const char *tosym; 1523588ccd73SSam Ravnborg const char *fromsym; 152458fb0d4fSSam Ravnborg 1525588ccd73SSam Ravnborg from = find_elf_symbol2(elf, r->r_offset, fromsec); 1526588ccd73SSam Ravnborg fromsym = sym_name(elf, from); 152758fb0d4fSSam Ravnborg 152877ab21adSAndi Kleen if (!strncmp(fromsym, "reference___initcall", 152977ab21adSAndi Kleen sizeof("reference___initcall")-1)) 153077ab21adSAndi Kleen return; 153177ab21adSAndi Kleen 1532c7a65e06SQuentin Casasnovas tosec = sec_name(elf, get_secindex(elf, sym)); 1533c7a65e06SQuentin Casasnovas to = find_elf_symbol(elf, r->r_addend, sym); 1534c7a65e06SQuentin Casasnovas tosym = sym_name(elf, to); 1535c7a65e06SQuentin Casasnovas 153658fb0d4fSSam Ravnborg /* check whitelist - we may ignore it */ 1537af92a82dSUwe Kleine-König if (secref_whitelist(mismatch, 1538af92a82dSUwe Kleine-König fromsec, fromsym, tosec, tosym)) { 1539588ccd73SSam Ravnborg report_sec_mismatch(modname, mismatch, 1540588ccd73SSam Ravnborg fromsec, r->r_offset, fromsym, 1541588ccd73SSam Ravnborg is_function(from), tosec, tosym, 1542588ccd73SSam Ravnborg is_function(to)); 154358fb0d4fSSam Ravnborg } 1544b39927cfSSam Ravnborg } 1545644e8f14SQuentin Casasnovas 154652dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index) 154752dc0595SQuentin Casasnovas { 154852dc0595SQuentin Casasnovas if (section_index > elf->num_sections) 154952dc0595SQuentin Casasnovas fatal("section_index is outside elf->num_sections!\n"); 155052dc0595SQuentin Casasnovas 155152dc0595SQuentin Casasnovas return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); 155252dc0595SQuentin Casasnovas } 155352dc0595SQuentin Casasnovas 155452dc0595SQuentin Casasnovas /* 155552dc0595SQuentin Casasnovas * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size() 155652dc0595SQuentin Casasnovas * to know the sizeof(struct exception_table_entry) for the target architecture. 155752dc0595SQuentin Casasnovas */ 155852dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0; 1559e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r) 156052dc0595SQuentin Casasnovas { 156152dc0595SQuentin Casasnovas /* 156252dc0595SQuentin Casasnovas * If we're currently checking the second relocation within __ex_table, 156352dc0595SQuentin Casasnovas * that relocation offset tells us the offsetof(struct 156452dc0595SQuentin Casasnovas * exception_table_entry, fixup) which is equal to sizeof(struct 156552dc0595SQuentin Casasnovas * exception_table_entry) divided by two. We use that to our advantage 156652dc0595SQuentin Casasnovas * since there's no portable way to get that size as every architecture 156752dc0595SQuentin Casasnovas * seems to go with different sized types. Not pretty but better than 156852dc0595SQuentin Casasnovas * hard-coding the size for every architecture.. 156952dc0595SQuentin Casasnovas */ 1570e84048aaSQuentin Casasnovas if (!extable_entry_size) 157152dc0595SQuentin Casasnovas extable_entry_size = r->r_offset * 2; 157252dc0595SQuentin Casasnovas } 1573e84048aaSQuentin Casasnovas 157452dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r) 157552dc0595SQuentin Casasnovas { 1576d3df4de7SQuentin Casasnovas /* 1577d3df4de7SQuentin Casasnovas * extable_entry_size is only discovered after we've handled the 1578d3df4de7SQuentin Casasnovas * _second_ relocation in __ex_table, so only abort when we're not 1579d3df4de7SQuentin Casasnovas * handling the first reloc and extable_entry_size is zero. 1580d3df4de7SQuentin Casasnovas */ 1581d3df4de7SQuentin Casasnovas if (r->r_offset && extable_entry_size == 0) 158252dc0595SQuentin Casasnovas fatal("extable_entry size hasn't been discovered!\n"); 158352dc0595SQuentin Casasnovas 158452dc0595SQuentin Casasnovas return ((r->r_offset == 0) || 158552dc0595SQuentin Casasnovas (r->r_offset % extable_entry_size == 0)); 158652dc0595SQuentin Casasnovas } 158752dc0595SQuentin Casasnovas 1588e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec) \ 1589e84048aaSQuentin Casasnovas (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0)) 1590e84048aaSQuentin Casasnovas 159152dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf, 159252dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 159352dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 159452dc0595SQuentin Casasnovas const char* fromsec, const char* tosec) 159552dc0595SQuentin Casasnovas { 159652dc0595SQuentin Casasnovas Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec); 159752dc0595SQuentin Casasnovas const char* fromsym_name = sym_name(elf, fromsym); 159852dc0595SQuentin Casasnovas Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym); 159952dc0595SQuentin Casasnovas const char* tosym_name = sym_name(elf, tosym); 160052dc0595SQuentin Casasnovas const char* from_pretty_name; 160152dc0595SQuentin Casasnovas const char* from_pretty_name_p; 160252dc0595SQuentin Casasnovas const char* to_pretty_name; 160352dc0595SQuentin Casasnovas const char* to_pretty_name_p; 160452dc0595SQuentin Casasnovas 160552dc0595SQuentin Casasnovas get_pretty_name(is_function(fromsym), 160652dc0595SQuentin Casasnovas &from_pretty_name, &from_pretty_name_p); 160752dc0595SQuentin Casasnovas get_pretty_name(is_function(tosym), 160852dc0595SQuentin Casasnovas &to_pretty_name, &to_pretty_name_p); 160952dc0595SQuentin Casasnovas 161052dc0595SQuentin Casasnovas warn("%s(%s+0x%lx): Section mismatch in reference" 161152dc0595SQuentin Casasnovas " from the %s %s%s to the %s %s:%s%s\n", 161252dc0595SQuentin Casasnovas modname, fromsec, (long)r->r_offset, from_pretty_name, 161352dc0595SQuentin Casasnovas fromsym_name, from_pretty_name_p, 161452dc0595SQuentin Casasnovas to_pretty_name, tosec, tosym_name, to_pretty_name_p); 161552dc0595SQuentin Casasnovas 161652dc0595SQuentin Casasnovas if (!match(tosec, mismatch->bad_tosec) && 161752dc0595SQuentin Casasnovas is_executable_section(elf, get_secindex(elf, sym))) 161852dc0595SQuentin Casasnovas fprintf(stderr, 161952dc0595SQuentin Casasnovas "The relocation at %s+0x%lx references\n" 162052dc0595SQuentin Casasnovas "section \"%s\" which is not in the list of\n" 162152dc0595SQuentin Casasnovas "authorized sections. If you're adding a new section\n" 162252dc0595SQuentin Casasnovas "and/or if this reference is valid, add \"%s\" to the\n" 162352dc0595SQuentin Casasnovas "list of authorized sections to jump to on fault.\n" 162452dc0595SQuentin Casasnovas "This can be achieved by adding \"%s\" to \n" 162552dc0595SQuentin Casasnovas "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n", 162652dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, tosec, tosec); 162752dc0595SQuentin Casasnovas } 162852dc0595SQuentin Casasnovas 162952dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf, 163052dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 163152dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 163252dc0595SQuentin Casasnovas const char *fromsec) 163352dc0595SQuentin Casasnovas { 163452dc0595SQuentin Casasnovas const char* tosec = sec_name(elf, get_secindex(elf, sym)); 163552dc0595SQuentin Casasnovas 163652dc0595SQuentin Casasnovas sec_mismatch_count++; 163752dc0595SQuentin Casasnovas 163852dc0595SQuentin Casasnovas if (sec_mismatch_verbose) 163952dc0595SQuentin Casasnovas report_extable_warnings(modname, elf, mismatch, r, sym, 164052dc0595SQuentin Casasnovas fromsec, tosec); 164152dc0595SQuentin Casasnovas 164252dc0595SQuentin Casasnovas if (match(tosec, mismatch->bad_tosec)) 164352dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 164452dc0595SQuentin Casasnovas "section \"%s\" which is black-listed.\n" 164552dc0595SQuentin Casasnovas "Something is seriously wrong and should be fixed.\n" 164652dc0595SQuentin Casasnovas "You might get more information about where this is\n" 164752dc0595SQuentin Casasnovas "coming from by using scripts/check_extable.sh %s\n", 164852dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, modname); 164952dc0595SQuentin Casasnovas else if (!is_executable_section(elf, get_secindex(elf, sym))) { 165052dc0595SQuentin Casasnovas if (is_extable_fault_address(r)) 165152dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 165252dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 165352dc0595SQuentin Casasnovas "it is not possible for the kernel to fault\n" 165452dc0595SQuentin Casasnovas "at that address. Something is seriously wrong\n" 165552dc0595SQuentin Casasnovas "and should be fixed.\n", 165652dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 165752dc0595SQuentin Casasnovas else 165852dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 165952dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 166052dc0595SQuentin Casasnovas "the kernel will fault if it ever tries to\n" 166152dc0595SQuentin Casasnovas "jump to it. Something is seriously wrong\n" 166252dc0595SQuentin Casasnovas "and should be fixed.\n", 166352dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 166452dc0595SQuentin Casasnovas } 166552dc0595SQuentin Casasnovas } 166652dc0595SQuentin Casasnovas 1667644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf, 1668644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 1669644e8f14SQuentin Casasnovas { 1670644e8f14SQuentin Casasnovas const char *tosec = sec_name(elf, get_secindex(elf, sym));; 1671644e8f14SQuentin Casasnovas const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec); 1672644e8f14SQuentin Casasnovas 1673644e8f14SQuentin Casasnovas if (mismatch) { 1674644e8f14SQuentin Casasnovas if (mismatch->handler) 1675644e8f14SQuentin Casasnovas mismatch->handler(modname, elf, mismatch, 1676644e8f14SQuentin Casasnovas r, sym, fromsec); 1677644e8f14SQuentin Casasnovas else 1678644e8f14SQuentin Casasnovas default_mismatch_handler(modname, elf, mismatch, 1679644e8f14SQuentin Casasnovas r, sym, fromsec); 1680644e8f14SQuentin Casasnovas } 1681b39927cfSSam Ravnborg } 1682b39927cfSSam Ravnborg 1683ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf, 16845b24c071SSam Ravnborg Elf_Shdr *sechdr, Elf_Rela *r) 1685ae4ac123SAtsushi Nemoto { 1686ae4ac123SAtsushi Nemoto Elf_Shdr *sechdrs = elf->sechdrs; 16876845756bSAnders Kaseorg int section = sechdr->sh_info; 1688ae4ac123SAtsushi Nemoto 1689ae4ac123SAtsushi Nemoto return (void *)elf->hdr + sechdrs[section].sh_offset + 1690731ece41SOlof Johansson r->r_offset; 1691ae4ac123SAtsushi Nemoto } 1692ae4ac123SAtsushi Nemoto 16935b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1694ae4ac123SAtsushi Nemoto { 1695ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 16965b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1697ae4ac123SAtsushi Nemoto 1698ae4ac123SAtsushi Nemoto switch (r_typ) { 1699ae4ac123SAtsushi Nemoto case R_386_32: 1700ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location); 1701ae4ac123SAtsushi Nemoto break; 1702ae4ac123SAtsushi Nemoto case R_386_PC32: 1703ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location) + 4; 1704ae4ac123SAtsushi Nemoto /* For CONFIG_RELOCATABLE=y */ 1705ae4ac123SAtsushi Nemoto if (elf->hdr->e_type == ET_EXEC) 1706ae4ac123SAtsushi Nemoto r->r_addend += r->r_offset; 1707ae4ac123SAtsushi Nemoto break; 1708ae4ac123SAtsushi Nemoto } 1709ae4ac123SAtsushi Nemoto return 0; 1710ae4ac123SAtsushi Nemoto } 1711ae4ac123SAtsushi Nemoto 17126e2e340bSTony Lindgren #ifndef R_ARM_CALL 17136e2e340bSTony Lindgren #define R_ARM_CALL 28 17146e2e340bSTony Lindgren #endif 17156e2e340bSTony Lindgren #ifndef R_ARM_JUMP24 17166e2e340bSTony Lindgren #define R_ARM_JUMP24 29 17176e2e340bSTony Lindgren #endif 17186e2e340bSTony Lindgren 1719c9698e5cSDavid A. Long #ifndef R_ARM_THM_CALL 1720c9698e5cSDavid A. Long #define R_ARM_THM_CALL 10 1721c9698e5cSDavid A. Long #endif 1722c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP24 1723c9698e5cSDavid A. Long #define R_ARM_THM_JUMP24 30 1724c9698e5cSDavid A. Long #endif 1725c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP19 1726c9698e5cSDavid A. Long #define R_ARM_THM_JUMP19 51 1727c9698e5cSDavid A. Long #endif 1728c9698e5cSDavid A. Long 17295b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 173056a974faSSam Ravnborg { 173156a974faSSam Ravnborg unsigned int r_typ = ELF_R_TYPE(r->r_info); 173256a974faSSam Ravnborg 173356a974faSSam Ravnborg switch (r_typ) { 173456a974faSSam Ravnborg case R_ARM_ABS32: 173556a974faSSam Ravnborg /* From ARM ABI: (S + A) | T */ 1736df578e7dSSam Ravnborg r->r_addend = (int)(long) 1737df578e7dSSam Ravnborg (elf->symtab_start + ELF_R_SYM(r->r_info)); 173856a974faSSam Ravnborg break; 173956a974faSSam Ravnborg case R_ARM_PC24: 17406e2e340bSTony Lindgren case R_ARM_CALL: 17416e2e340bSTony Lindgren case R_ARM_JUMP24: 1742c9698e5cSDavid A. Long case R_ARM_THM_CALL: 1743c9698e5cSDavid A. Long case R_ARM_THM_JUMP24: 1744c9698e5cSDavid A. Long case R_ARM_THM_JUMP19: 174556a974faSSam Ravnborg /* From ARM ABI: ((S + A) | T) - P */ 1746df578e7dSSam Ravnborg r->r_addend = (int)(long)(elf->hdr + 17475b24c071SSam Ravnborg sechdr->sh_offset + 17485b24c071SSam Ravnborg (r->r_offset - sechdr->sh_addr)); 174956a974faSSam Ravnborg break; 175056a974faSSam Ravnborg default: 175156a974faSSam Ravnborg return 1; 175256a974faSSam Ravnborg } 175356a974faSSam Ravnborg return 0; 175456a974faSSam Ravnborg } 175556a974faSSam Ravnborg 17565b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1757ae4ac123SAtsushi Nemoto { 1758ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 17595b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1760ae4ac123SAtsushi Nemoto unsigned int inst; 1761ae4ac123SAtsushi Nemoto 1762ae4ac123SAtsushi Nemoto if (r_typ == R_MIPS_HI16) 1763ae4ac123SAtsushi Nemoto return 1; /* skip this */ 1764ae4ac123SAtsushi Nemoto inst = TO_NATIVE(*location); 1765ae4ac123SAtsushi Nemoto switch (r_typ) { 1766ae4ac123SAtsushi Nemoto case R_MIPS_LO16: 1767ae4ac123SAtsushi Nemoto r->r_addend = inst & 0xffff; 1768ae4ac123SAtsushi Nemoto break; 1769ae4ac123SAtsushi Nemoto case R_MIPS_26: 1770ae4ac123SAtsushi Nemoto r->r_addend = (inst & 0x03ffffff) << 2; 1771ae4ac123SAtsushi Nemoto break; 1772ae4ac123SAtsushi Nemoto case R_MIPS_32: 1773ae4ac123SAtsushi Nemoto r->r_addend = inst; 1774ae4ac123SAtsushi Nemoto break; 1775ae4ac123SAtsushi Nemoto } 1776ae4ac123SAtsushi Nemoto return 0; 1777ae4ac123SAtsushi Nemoto } 1778ae4ac123SAtsushi Nemoto 17795b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf, 178010668220SSam Ravnborg Elf_Shdr *sechdr) 1781b39927cfSSam Ravnborg { 1782b39927cfSSam Ravnborg Elf_Sym *sym; 17835b24c071SSam Ravnborg Elf_Rela *rela; 17842c1a51f3SAtsushi Nemoto Elf_Rela r; 1785eae07ac6SAtsushi Nemoto unsigned int r_sym; 17865b24c071SSam Ravnborg const char *fromsec; 17875b24c071SSam Ravnborg 1788ff13f926SSam Ravnborg Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; 17895b24c071SSam Ravnborg Elf_Rela *stop = (void *)start + sechdr->sh_size; 17905b24c071SSam Ravnborg 1791ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 17925b24c071SSam Ravnborg fromsec += strlen(".rela"); 17935b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1794b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 17955b24c071SSam Ravnborg return; 1796e241a630SSam Ravnborg 1797b39927cfSSam Ravnborg for (rela = start; rela < stop; rela++) { 1798b39927cfSSam Ravnborg r.r_offset = TO_NATIVE(rela->r_offset); 1799eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1800ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1801ae4ac123SAtsushi Nemoto unsigned int r_typ; 1802eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rela->r_info); 1803eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1804ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rela->r_info); 1805ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1806eae07ac6SAtsushi Nemoto } else { 1807601e7f02SLinus Torvalds r.r_info = TO_NATIVE(rela->r_info); 1808eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1809eae07ac6SAtsushi Nemoto } 1810eae07ac6SAtsushi Nemoto #else 1811eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rela->r_info); 1812eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1813eae07ac6SAtsushi Nemoto #endif 181493684d3bSSam Ravnborg r.r_addend = TO_NATIVE(rela->r_addend); 1815eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 1816b39927cfSSam Ravnborg /* Skip special sections */ 18171ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1818b39927cfSSam Ravnborg continue; 1819e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rela, fromsec)) 1820e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 182158fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 18222c1a51f3SAtsushi Nemoto } 18235b24c071SSam Ravnborg } 18245b24c071SSam Ravnborg 18255b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf, 182610668220SSam Ravnborg Elf_Shdr *sechdr) 18275b24c071SSam Ravnborg { 18285b24c071SSam Ravnborg Elf_Sym *sym; 18292c1a51f3SAtsushi Nemoto Elf_Rel *rel; 18305b24c071SSam Ravnborg Elf_Rela r; 18315b24c071SSam Ravnborg unsigned int r_sym; 18325b24c071SSam Ravnborg const char *fromsec; 18335b24c071SSam Ravnborg 1834ff13f926SSam Ravnborg Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; 18355b24c071SSam Ravnborg Elf_Rel *stop = (void *)start + sechdr->sh_size; 18365b24c071SSam Ravnborg 1837ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 18385b24c071SSam Ravnborg fromsec += strlen(".rel"); 18395b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1840b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 18415b24c071SSam Ravnborg return; 18422c1a51f3SAtsushi Nemoto 18432c1a51f3SAtsushi Nemoto for (rel = start; rel < stop; rel++) { 18442c1a51f3SAtsushi Nemoto r.r_offset = TO_NATIVE(rel->r_offset); 1845eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1846ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1847ae4ac123SAtsushi Nemoto unsigned int r_typ; 1848eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rel->r_info); 1849eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1850ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rel->r_info); 1851ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1852eae07ac6SAtsushi Nemoto } else { 18532c1a51f3SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1854eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1855eae07ac6SAtsushi Nemoto } 1856eae07ac6SAtsushi Nemoto #else 1857eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1858eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1859eae07ac6SAtsushi Nemoto #endif 18602c1a51f3SAtsushi Nemoto r.r_addend = 0; 1861ff13f926SSam Ravnborg switch (elf->hdr->e_machine) { 1862ae4ac123SAtsushi Nemoto case EM_386: 18635b24c071SSam Ravnborg if (addend_386_rel(elf, sechdr, &r)) 1864ae4ac123SAtsushi Nemoto continue; 1865ae4ac123SAtsushi Nemoto break; 186656a974faSSam Ravnborg case EM_ARM: 18675b24c071SSam Ravnborg if (addend_arm_rel(elf, sechdr, &r)) 186856a974faSSam Ravnborg continue; 186956a974faSSam Ravnborg break; 1870ae4ac123SAtsushi Nemoto case EM_MIPS: 18715b24c071SSam Ravnborg if (addend_mips_rel(elf, sechdr, &r)) 1872ae4ac123SAtsushi Nemoto continue; 1873ae4ac123SAtsushi Nemoto break; 1874ae4ac123SAtsushi Nemoto } 1875eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 18762c1a51f3SAtsushi Nemoto /* Skip special sections */ 18771ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 18782c1a51f3SAtsushi Nemoto continue; 1879e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rel, fromsec)) 1880e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 188158fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 18822c1a51f3SAtsushi Nemoto } 1883b39927cfSSam Ravnborg } 18845b24c071SSam Ravnborg 18855b24c071SSam Ravnborg /** 18865b24c071SSam Ravnborg * A module includes a number of sections that are discarded 18875b24c071SSam Ravnborg * either when loaded or when used as built-in. 18885b24c071SSam Ravnborg * For loaded modules all functions marked __init and all data 1889b595076aSUwe Kleine-König * marked __initdata will be discarded when the module has been initialized. 18905b24c071SSam Ravnborg * Likewise for modules used built-in the sections marked __exit 18915b24c071SSam Ravnborg * are discarded because __exit marked function are supposed to be called 189232be1d22SBen Dooks * only when a module is unloaded which never happens for built-in modules. 18935b24c071SSam Ravnborg * The check_sec_ref() function traverses all relocation records 18945b24c071SSam Ravnborg * to find all references to a section that reference a section that will 18955b24c071SSam Ravnborg * be discarded and warns about it. 18965b24c071SSam Ravnborg **/ 18975b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname, 189810668220SSam Ravnborg struct elf_info *elf) 18995b24c071SSam Ravnborg { 19005b24c071SSam Ravnborg int i; 19015b24c071SSam Ravnborg Elf_Shdr *sechdrs = elf->sechdrs; 19025b24c071SSam Ravnborg 19035b24c071SSam Ravnborg /* Walk through all sections */ 19041ce53adfSDenys Vlasenko for (i = 0; i < elf->num_sections; i++) { 1905b614a697SAnders Kaseorg check_section(modname, elf, &elf->sechdrs[i]); 19065b24c071SSam Ravnborg /* We want to process only relocation sections and not .init */ 19075b24c071SSam Ravnborg if (sechdrs[i].sh_type == SHT_RELA) 190810668220SSam Ravnborg section_rela(modname, elf, &elf->sechdrs[i]); 19095b24c071SSam Ravnborg else if (sechdrs[i].sh_type == SHT_REL) 191010668220SSam Ravnborg section_rel(modname, elf, &elf->sechdrs[i]); 1911b39927cfSSam Ravnborg } 1912b39927cfSSam Ravnborg } 1913b39927cfSSam Ravnborg 19147d02b490SAndi Kleen static char *remove_dot(char *s) 19157d02b490SAndi Kleen { 1916fcd38ed0SMichal Nazarewicz size_t n = strcspn(s, "."); 19177d02b490SAndi Kleen 1918fcd38ed0SMichal Nazarewicz if (n && s[n]) { 1919fcd38ed0SMichal Nazarewicz size_t m = strspn(s + n + 1, "0123456789"); 1920fcd38ed0SMichal Nazarewicz if (m && (s[n + m] == '.' || s[n + m] == 0)) 19217d02b490SAndi Kleen s[n] = 0; 19227d02b490SAndi Kleen } 19237d02b490SAndi Kleen return s; 19247d02b490SAndi Kleen } 19257d02b490SAndi Kleen 19265c3ead8cSSam Ravnborg static void read_symbols(char *modname) 19271da177e4SLinus Torvalds { 19281da177e4SLinus Torvalds const char *symname; 19291da177e4SLinus Torvalds char *version; 1930b817f6feSSam Ravnborg char *license; 19311da177e4SLinus Torvalds struct module *mod; 19321da177e4SLinus Torvalds struct elf_info info = { }; 19331da177e4SLinus Torvalds Elf_Sym *sym; 19341da177e4SLinus Torvalds 193585bd2fddSSam Ravnborg if (!parse_elf(&info, modname)) 193685bd2fddSSam Ravnborg return; 19371da177e4SLinus Torvalds 19381da177e4SLinus Torvalds mod = new_module(modname); 19391da177e4SLinus Torvalds 19401da177e4SLinus Torvalds /* When there's no vmlinux, don't print warnings about 19411da177e4SLinus Torvalds * unresolved symbols (since there'll be too many ;) */ 19421da177e4SLinus Torvalds if (is_vmlinux(modname)) { 19431da177e4SLinus Torvalds have_vmlinux = 1; 19441da177e4SLinus Torvalds mod->skip = 1; 19451da177e4SLinus Torvalds } 19461da177e4SLinus Torvalds 1947b817f6feSSam Ravnborg license = get_modinfo(info.modinfo, info.modinfo_len, "license"); 19482fa36568SSam Ravnborg if (info.modinfo && !license && !is_vmlinux(modname)) 19492fa36568SSam Ravnborg warn("modpost: missing MODULE_LICENSE() in %s\n" 1950eed7d279SSam Ravnborg "see include/linux/module.h for " 1951eed7d279SSam Ravnborg "more information\n", modname); 1952b817f6feSSam Ravnborg while (license) { 1953b817f6feSSam Ravnborg if (license_is_gpl_compatible(license)) 1954b817f6feSSam Ravnborg mod->gpl_compatible = 1; 1955b817f6feSSam Ravnborg else { 1956b817f6feSSam Ravnborg mod->gpl_compatible = 0; 1957b817f6feSSam Ravnborg break; 1958b817f6feSSam Ravnborg } 1959b817f6feSSam Ravnborg license = get_next_modinfo(info.modinfo, info.modinfo_len, 1960b817f6feSSam Ravnborg "license", license); 1961b817f6feSSam Ravnborg } 1962b817f6feSSam Ravnborg 19631da177e4SLinus Torvalds for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { 19647d02b490SAndi Kleen symname = remove_dot(info.strtab + sym->st_name); 19651da177e4SLinus Torvalds 19661da177e4SLinus Torvalds handle_modversions(mod, &info, sym, symname); 19671da177e4SLinus Torvalds handle_moddevtable(mod, &info, sym, symname); 19681da177e4SLinus Torvalds } 1969d1f25e66SSam Ravnborg if (!is_vmlinux(modname) || 197010668220SSam Ravnborg (is_vmlinux(modname) && vmlinux_section_warnings)) 197110668220SSam Ravnborg check_sec_ref(mod, modname, &info); 19721da177e4SLinus Torvalds 19731da177e4SLinus Torvalds version = get_modinfo(info.modinfo, info.modinfo_len, "version"); 19741da177e4SLinus Torvalds if (version) 19751da177e4SLinus Torvalds maybe_frob_rcs_version(modname, version, info.modinfo, 19761da177e4SLinus Torvalds version - (char *)info.hdr); 19771da177e4SLinus Torvalds if (version || (all_versions && !is_vmlinux(modname))) 19781da177e4SLinus Torvalds get_src_version(modname, mod->srcversion, 19791da177e4SLinus Torvalds sizeof(mod->srcversion)-1); 19801da177e4SLinus Torvalds 19811da177e4SLinus Torvalds parse_elf_finish(&info); 19821da177e4SLinus Torvalds 19838c8ef42aSRusty Russell /* Our trick to get versioning for module struct etc. - it's 19841da177e4SLinus Torvalds * never passed as an argument to an exported function, so 19851da177e4SLinus Torvalds * the automatic versioning doesn't pick it up, but it's really 19861da177e4SLinus Torvalds * important anyhow */ 19871da177e4SLinus Torvalds if (modversions) 19888c8ef42aSRusty Russell mod->unres = alloc_symbol("module_layout", 0, mod->unres); 19891da177e4SLinus Torvalds } 19901da177e4SLinus Torvalds 1991712f9b46SRusty Russell static void read_symbols_from_files(const char *filename) 1992712f9b46SRusty Russell { 1993712f9b46SRusty Russell FILE *in = stdin; 1994712f9b46SRusty Russell char fname[PATH_MAX]; 1995712f9b46SRusty Russell 1996712f9b46SRusty Russell if (strcmp(filename, "-") != 0) { 1997712f9b46SRusty Russell in = fopen(filename, "r"); 1998712f9b46SRusty Russell if (!in) 1999712f9b46SRusty Russell fatal("Can't open filenames file %s: %m", filename); 2000712f9b46SRusty Russell } 2001712f9b46SRusty Russell 2002712f9b46SRusty Russell while (fgets(fname, PATH_MAX, in) != NULL) { 2003712f9b46SRusty Russell if (strends(fname, "\n")) 2004712f9b46SRusty Russell fname[strlen(fname)-1] = '\0'; 2005712f9b46SRusty Russell read_symbols(fname); 2006712f9b46SRusty Russell } 2007712f9b46SRusty Russell 2008712f9b46SRusty Russell if (in != stdin) 2009712f9b46SRusty Russell fclose(in); 2010712f9b46SRusty Russell } 2011712f9b46SRusty Russell 20121da177e4SLinus Torvalds #define SZ 500 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds /* We first write the generated file into memory using the 20151da177e4SLinus Torvalds * following helper, then compare to the file on disk and 20161da177e4SLinus Torvalds * only update the later if anything changed */ 20171da177e4SLinus Torvalds 20185c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, 20195c3ead8cSSam Ravnborg const char *fmt, ...) 20201da177e4SLinus Torvalds { 20211da177e4SLinus Torvalds char tmp[SZ]; 20221da177e4SLinus Torvalds int len; 20231da177e4SLinus Torvalds va_list ap; 20241da177e4SLinus Torvalds 20251da177e4SLinus Torvalds va_start(ap, fmt); 20261da177e4SLinus Torvalds len = vsnprintf(tmp, SZ, fmt, ap); 20277670f023SSam Ravnborg buf_write(buf, tmp, len); 20281da177e4SLinus Torvalds va_end(ap); 20291da177e4SLinus Torvalds } 20301da177e4SLinus Torvalds 20315c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len) 20321da177e4SLinus Torvalds { 20331da177e4SLinus Torvalds if (buf->size - buf->pos < len) { 20347670f023SSam Ravnborg buf->size += len + SZ; 20351da177e4SLinus Torvalds buf->p = realloc(buf->p, buf->size); 20361da177e4SLinus Torvalds } 20371da177e4SLinus Torvalds strncpy(buf->p + buf->pos, s, len); 20381da177e4SLinus Torvalds buf->pos += len; 20391da177e4SLinus Torvalds } 20401da177e4SLinus Torvalds 2041c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s) 2042c96fca21SSam Ravnborg { 2043c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2044c96fca21SSam Ravnborg 2045c96fca21SSam Ravnborg switch (exp) { 2046c96fca21SSam Ravnborg case export_gpl: 2047c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2048c96fca21SSam Ravnborg "uses GPL-only symbol '%s'\n", m, e, s); 2049c96fca21SSam Ravnborg break; 2050c96fca21SSam Ravnborg case export_unused_gpl: 2051c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2052c96fca21SSam Ravnborg "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); 2053c96fca21SSam Ravnborg break; 2054c96fca21SSam Ravnborg case export_gpl_future: 2055c96fca21SSam Ravnborg warn("modpost: GPL-incompatible module %s%s " 2056c96fca21SSam Ravnborg "uses future GPL-only symbol '%s'\n", m, e, s); 2057c96fca21SSam Ravnborg break; 2058c96fca21SSam Ravnborg case export_plain: 2059c96fca21SSam Ravnborg case export_unused: 2060c96fca21SSam Ravnborg case export_unknown: 2061c96fca21SSam Ravnborg /* ignore */ 2062c96fca21SSam Ravnborg break; 2063c96fca21SSam Ravnborg } 2064c96fca21SSam Ravnborg } 2065c96fca21SSam Ravnborg 2066c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s) 2067c96fca21SSam Ravnborg { 2068c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2069c96fca21SSam Ravnborg 2070c96fca21SSam Ravnborg switch (exp) { 2071c96fca21SSam Ravnborg case export_unused: 2072c96fca21SSam Ravnborg case export_unused_gpl: 2073c96fca21SSam Ravnborg warn("modpost: module %s%s " 2074c96fca21SSam Ravnborg "uses symbol '%s' marked UNUSED\n", m, e, s); 2075c96fca21SSam Ravnborg break; 2076c96fca21SSam Ravnborg default: 2077c96fca21SSam Ravnborg /* ignore */ 2078c96fca21SSam Ravnborg break; 2079c96fca21SSam Ravnborg } 2080c96fca21SSam Ravnborg } 2081c96fca21SSam Ravnborg 2082c96fca21SSam Ravnborg static void check_exports(struct module *mod) 2083b817f6feSSam Ravnborg { 2084b817f6feSSam Ravnborg struct symbol *s, *exp; 2085b817f6feSSam Ravnborg 2086b817f6feSSam Ravnborg for (s = mod->unres; s; s = s->next) { 20876449bd62SAndrew Morton const char *basename; 2088b817f6feSSam Ravnborg exp = find_symbol(s->name); 2089b817f6feSSam Ravnborg if (!exp || exp->module == mod) 2090b817f6feSSam Ravnborg continue; 20916449bd62SAndrew Morton basename = strrchr(mod->name, '/'); 2092b817f6feSSam Ravnborg if (basename) 2093b817f6feSSam Ravnborg basename++; 2094c96fca21SSam Ravnborg else 2095c96fca21SSam Ravnborg basename = mod->name; 2096c96fca21SSam Ravnborg if (!mod->gpl_compatible) 2097c96fca21SSam Ravnborg check_for_gpl_usage(exp->export, basename, exp->name); 2098c96fca21SSam Ravnborg check_for_unused(exp->export, basename, exp->name); 2099b817f6feSSam Ravnborg } 2100b817f6feSSam Ravnborg } 2101b817f6feSSam Ravnborg 21025c3ead8cSSam Ravnborg /** 21035c3ead8cSSam Ravnborg * Header for the generated file 21045c3ead8cSSam Ravnborg **/ 21055c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod) 21061da177e4SLinus Torvalds { 21071da177e4SLinus Torvalds buf_printf(b, "#include <linux/module.h>\n"); 21081da177e4SLinus Torvalds buf_printf(b, "#include <linux/vermagic.h>\n"); 21091da177e4SLinus Torvalds buf_printf(b, "#include <linux/compiler.h>\n"); 21101da177e4SLinus Torvalds buf_printf(b, "\n"); 21111da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); 21121da177e4SLinus Torvalds buf_printf(b, "\n"); 2113e0f244c6SAndi Kleen buf_printf(b, "__visible struct module __this_module\n"); 21141da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); 21153c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); 21161da177e4SLinus Torvalds if (mod->has_init) 21173c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.init = init_module,\n"); 21181da177e4SLinus Torvalds if (mod->has_cleanup) 21191da177e4SLinus Torvalds buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" 21203c7ec94dSGreg Kroah-Hartman "\t.exit = cleanup_module,\n" 21211da177e4SLinus Torvalds "#endif\n"); 21223c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); 21231da177e4SLinus Torvalds buf_printf(b, "};\n"); 21241da177e4SLinus Torvalds } 21251da177e4SLinus Torvalds 21262449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree) 21272449b8baSBen Hutchings { 21282449b8baSBen Hutchings if (is_intree) 21292449b8baSBen Hutchings buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); 21302449b8baSBen Hutchings } 21312449b8baSBen Hutchings 21325c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name) 2133a9860bf0SGreg Kroah-Hartman { 2134a9860bf0SGreg Kroah-Hartman static const char *staging_dir = "drivers/staging"; 2135a9860bf0SGreg Kroah-Hartman 2136a9860bf0SGreg Kroah-Hartman if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) 2137a9860bf0SGreg Kroah-Hartman buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); 2138a9860bf0SGreg Kroah-Hartman } 2139a9860bf0SGreg Kroah-Hartman 21405cfb203aSTakashi Iwai /* In kernel, this size is defined in linux/module.h; 21415cfb203aSTakashi Iwai * here we use Elf_Addr instead of long for covering cross-compile 21425cfb203aSTakashi Iwai */ 21435cfb203aSTakashi Iwai #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) 21445cfb203aSTakashi Iwai 21455c3ead8cSSam Ravnborg /** 21465c3ead8cSSam Ravnborg * Record CRCs for unresolved symbols 21475c3ead8cSSam Ravnborg **/ 2148c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod) 21491da177e4SLinus Torvalds { 21501da177e4SLinus Torvalds struct symbol *s, *exp; 2151c53ddacdSKirill Korotaev int err = 0; 21521da177e4SLinus Torvalds 21531da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 21541da177e4SLinus Torvalds exp = find_symbol(s->name); 21551da177e4SLinus Torvalds if (!exp || exp->module == mod) { 2156c53ddacdSKirill Korotaev if (have_vmlinux && !s->weak) { 21572a116659SMatthew Wilcox if (warn_unresolved) { 2158cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] undefined!\n", 2159cb80514dSSam Ravnborg s->name, mod->name); 21602a116659SMatthew Wilcox } else { 21612a116659SMatthew Wilcox merror("\"%s\" [%s.ko] undefined!\n", 21622a116659SMatthew Wilcox s->name, mod->name); 21632a116659SMatthew Wilcox err = 1; 21642a116659SMatthew Wilcox } 2165c53ddacdSKirill Korotaev } 21661da177e4SLinus Torvalds continue; 21671da177e4SLinus Torvalds } 21681da177e4SLinus Torvalds s->module = exp->module; 21691da177e4SLinus Torvalds s->crc_valid = exp->crc_valid; 21701da177e4SLinus Torvalds s->crc = exp->crc; 21711da177e4SLinus Torvalds } 21721da177e4SLinus Torvalds 21731da177e4SLinus Torvalds if (!modversions) 2174c53ddacdSKirill Korotaev return err; 21751da177e4SLinus Torvalds 21761da177e4SLinus Torvalds buf_printf(b, "\n"); 21771da177e4SLinus Torvalds buf_printf(b, "static const struct modversion_info ____versions[]\n"); 21783ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 21791da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); 21801da177e4SLinus Torvalds 21811da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2182df578e7dSSam Ravnborg if (!s->module) 21831da177e4SLinus Torvalds continue; 21841da177e4SLinus Torvalds if (!s->crc_valid) { 2185cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] has no CRC!\n", 21861da177e4SLinus Torvalds s->name, mod->name); 21871da177e4SLinus Torvalds continue; 21881da177e4SLinus Torvalds } 21895cfb203aSTakashi Iwai if (strlen(s->name) >= MODULE_NAME_LEN) { 21905cfb203aSTakashi Iwai merror("too long symbol \"%s\" [%s.ko]\n", 21915cfb203aSTakashi Iwai s->name, mod->name); 21925cfb203aSTakashi Iwai err = 1; 21935cfb203aSTakashi Iwai break; 21945cfb203aSTakashi Iwai } 2195a53a11f3SJames Hogan buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", 2196a4b6a77bSJames Hogan s->crc, s->name); 21971da177e4SLinus Torvalds } 21981da177e4SLinus Torvalds 21991da177e4SLinus Torvalds buf_printf(b, "};\n"); 2200c53ddacdSKirill Korotaev 2201c53ddacdSKirill Korotaev return err; 22021da177e4SLinus Torvalds } 22031da177e4SLinus Torvalds 22045c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod, 22055c3ead8cSSam Ravnborg struct module *modules) 22061da177e4SLinus Torvalds { 22071da177e4SLinus Torvalds struct symbol *s; 22081da177e4SLinus Torvalds struct module *m; 22091da177e4SLinus Torvalds int first = 1; 22101da177e4SLinus Torvalds 2211df578e7dSSam Ravnborg for (m = modules; m; m = m->next) 22121da177e4SLinus Torvalds m->seen = is_vmlinux(m->name); 22131da177e4SLinus Torvalds 22141da177e4SLinus Torvalds buf_printf(b, "\n"); 22151da177e4SLinus Torvalds buf_printf(b, "static const char __module_depends[]\n"); 22163ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 22171da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); 22181da177e4SLinus Torvalds buf_printf(b, "\"depends="); 22191da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2220a61b2dfdSSam Ravnborg const char *p; 22211da177e4SLinus Torvalds if (!s->module) 22221da177e4SLinus Torvalds continue; 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds if (s->module->seen) 22251da177e4SLinus Torvalds continue; 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds s->module->seen = 1; 2228df578e7dSSam Ravnborg p = strrchr(s->module->name, '/'); 2229df578e7dSSam Ravnborg if (p) 2230a61b2dfdSSam Ravnborg p++; 2231a61b2dfdSSam Ravnborg else 2232a61b2dfdSSam Ravnborg p = s->module->name; 2233a61b2dfdSSam Ravnborg buf_printf(b, "%s%s", first ? "" : ",", p); 22341da177e4SLinus Torvalds first = 0; 22351da177e4SLinus Torvalds } 22361da177e4SLinus Torvalds buf_printf(b, "\";\n"); 22371da177e4SLinus Torvalds } 22381da177e4SLinus Torvalds 22395c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod) 22401da177e4SLinus Torvalds { 22411da177e4SLinus Torvalds if (mod->srcversion[0]) { 22421da177e4SLinus Torvalds buf_printf(b, "\n"); 22431da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", 22441da177e4SLinus Torvalds mod->srcversion); 22451da177e4SLinus Torvalds } 22461da177e4SLinus Torvalds } 22471da177e4SLinus Torvalds 22485c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname) 22491da177e4SLinus Torvalds { 22501da177e4SLinus Torvalds char *tmp; 22511da177e4SLinus Torvalds FILE *file; 22521da177e4SLinus Torvalds struct stat st; 22531da177e4SLinus Torvalds 22541da177e4SLinus Torvalds file = fopen(fname, "r"); 22551da177e4SLinus Torvalds if (!file) 22561da177e4SLinus Torvalds goto write; 22571da177e4SLinus Torvalds 22581da177e4SLinus Torvalds if (fstat(fileno(file), &st) < 0) 22591da177e4SLinus Torvalds goto close_write; 22601da177e4SLinus Torvalds 22611da177e4SLinus Torvalds if (st.st_size != b->pos) 22621da177e4SLinus Torvalds goto close_write; 22631da177e4SLinus Torvalds 22641da177e4SLinus Torvalds tmp = NOFAIL(malloc(b->pos)); 22651da177e4SLinus Torvalds if (fread(tmp, 1, b->pos, file) != b->pos) 22661da177e4SLinus Torvalds goto free_write; 22671da177e4SLinus Torvalds 22681da177e4SLinus Torvalds if (memcmp(tmp, b->p, b->pos) != 0) 22691da177e4SLinus Torvalds goto free_write; 22701da177e4SLinus Torvalds 22711da177e4SLinus Torvalds free(tmp); 22721da177e4SLinus Torvalds fclose(file); 22731da177e4SLinus Torvalds return; 22741da177e4SLinus Torvalds 22751da177e4SLinus Torvalds free_write: 22761da177e4SLinus Torvalds free(tmp); 22771da177e4SLinus Torvalds close_write: 22781da177e4SLinus Torvalds fclose(file); 22791da177e4SLinus Torvalds write: 22801da177e4SLinus Torvalds file = fopen(fname, "w"); 22811da177e4SLinus Torvalds if (!file) { 22821da177e4SLinus Torvalds perror(fname); 22831da177e4SLinus Torvalds exit(1); 22841da177e4SLinus Torvalds } 22851da177e4SLinus Torvalds if (fwrite(b->p, 1, b->pos, file) != b->pos) { 22861da177e4SLinus Torvalds perror(fname); 22871da177e4SLinus Torvalds exit(1); 22881da177e4SLinus Torvalds } 22891da177e4SLinus Torvalds fclose(file); 22901da177e4SLinus Torvalds } 22911da177e4SLinus Torvalds 2292bd5cbcedSRam Pai /* parse Module.symvers file. line format: 2293534b89a9SSam Ravnborg * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] 2294bd5cbcedSRam Pai **/ 2295040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel) 22961da177e4SLinus Torvalds { 22971da177e4SLinus Torvalds unsigned long size, pos = 0; 22981da177e4SLinus Torvalds void *file = grab_file(fname, &size); 22991da177e4SLinus Torvalds char *line; 23001da177e4SLinus Torvalds 23011da177e4SLinus Torvalds if (!file) 23021da177e4SLinus Torvalds /* No symbol versions, silently ignore */ 23031da177e4SLinus Torvalds return; 23041da177e4SLinus Torvalds 23051da177e4SLinus Torvalds while ((line = get_next_line(&pos, file, size))) { 2306534b89a9SSam Ravnborg char *symname, *modname, *d, *export, *end; 23071da177e4SLinus Torvalds unsigned int crc; 23081da177e4SLinus Torvalds struct module *mod; 2309040fcc81SSam Ravnborg struct symbol *s; 23101da177e4SLinus Torvalds 23111da177e4SLinus Torvalds if (!(symname = strchr(line, '\t'))) 23121da177e4SLinus Torvalds goto fail; 23131da177e4SLinus Torvalds *symname++ = '\0'; 23141da177e4SLinus Torvalds if (!(modname = strchr(symname, '\t'))) 23151da177e4SLinus Torvalds goto fail; 23161da177e4SLinus Torvalds *modname++ = '\0'; 23179ac545b0SLaurent Riffard if ((export = strchr(modname, '\t')) != NULL) 2318bd5cbcedSRam Pai *export++ = '\0'; 2319534b89a9SSam Ravnborg if (export && ((end = strchr(export, '\t')) != NULL)) 2320534b89a9SSam Ravnborg *end = '\0'; 23211da177e4SLinus Torvalds crc = strtoul(line, &d, 16); 23221da177e4SLinus Torvalds if (*symname == '\0' || *modname == '\0' || *d != '\0') 23231da177e4SLinus Torvalds goto fail; 2324df578e7dSSam Ravnborg mod = find_module(modname); 2325df578e7dSSam Ravnborg if (!mod) { 2326df578e7dSSam Ravnborg if (is_vmlinux(modname)) 23271da177e4SLinus Torvalds have_vmlinux = 1; 23280fa3a88cSJan Beulich mod = new_module(modname); 23291da177e4SLinus Torvalds mod->skip = 1; 23301da177e4SLinus Torvalds } 2331bd5cbcedSRam Pai s = sym_add_exported(symname, mod, export_no(export)); 2332040fcc81SSam Ravnborg s->kernel = kernel; 23338e70c458SSam Ravnborg s->preloaded = 1; 2334bd5cbcedSRam Pai sym_update_crc(symname, mod, crc, export_no(export)); 23351da177e4SLinus Torvalds } 23362ee41e62SChristian Engelmayer release_file(file, size); 23371da177e4SLinus Torvalds return; 23381da177e4SLinus Torvalds fail: 23392ee41e62SChristian Engelmayer release_file(file, size); 23401da177e4SLinus Torvalds fatal("parse error in symbol dump file\n"); 23411da177e4SLinus Torvalds } 23421da177e4SLinus Torvalds 2343040fcc81SSam Ravnborg /* For normal builds always dump all symbols. 2344040fcc81SSam Ravnborg * For external modules only dump symbols 2345040fcc81SSam Ravnborg * that are not read from kernel Module.symvers. 2346040fcc81SSam Ravnborg **/ 2347040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym) 2348040fcc81SSam Ravnborg { 2349040fcc81SSam Ravnborg if (!external_module) 2350040fcc81SSam Ravnborg return 1; 2351040fcc81SSam Ravnborg if (sym->vmlinux || sym->kernel) 2352040fcc81SSam Ravnborg return 0; 2353040fcc81SSam Ravnborg return 1; 2354040fcc81SSam Ravnborg } 2355040fcc81SSam Ravnborg 23565c3ead8cSSam Ravnborg static void write_dump(const char *fname) 23571da177e4SLinus Torvalds { 23581da177e4SLinus Torvalds struct buffer buf = { }; 23591da177e4SLinus Torvalds struct symbol *symbol; 23601da177e4SLinus Torvalds int n; 23611da177e4SLinus Torvalds 23621da177e4SLinus Torvalds for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { 23631da177e4SLinus Torvalds symbol = symbolhash[n]; 23641da177e4SLinus Torvalds while (symbol) { 2365040fcc81SSam Ravnborg if (dump_sym(symbol)) 2366bd5cbcedSRam Pai buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", 2367040fcc81SSam Ravnborg symbol->crc, symbol->name, 2368bd5cbcedSRam Pai symbol->module->name, 2369bd5cbcedSRam Pai export_str(symbol->export)); 23701da177e4SLinus Torvalds symbol = symbol->next; 23711da177e4SLinus Torvalds } 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds write_if_changed(&buf, fname); 23741da177e4SLinus Torvalds } 23751da177e4SLinus Torvalds 23762d04b5aeSRichard Hacker struct ext_sym_list { 23772d04b5aeSRichard Hacker struct ext_sym_list *next; 23782d04b5aeSRichard Hacker const char *file; 23792d04b5aeSRichard Hacker }; 23802d04b5aeSRichard Hacker 23815c3ead8cSSam Ravnborg int main(int argc, char **argv) 23821da177e4SLinus Torvalds { 23831da177e4SLinus Torvalds struct module *mod; 23841da177e4SLinus Torvalds struct buffer buf = { }; 2385040fcc81SSam Ravnborg char *kernel_read = NULL, *module_read = NULL; 2386712f9b46SRusty Russell char *dump_write = NULL, *files_source = NULL; 23871da177e4SLinus Torvalds int opt; 2388c53ddacdSKirill Korotaev int err; 23892d04b5aeSRichard Hacker struct ext_sym_list *extsym_iter; 23902d04b5aeSRichard Hacker struct ext_sym_list *extsym_start = NULL; 23911da177e4SLinus Torvalds 239247490ec1SNicolas Boichat while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:E")) != -1) { 23931da177e4SLinus Torvalds switch (opt) { 23941da177e4SLinus Torvalds case 'i': 2395040fcc81SSam Ravnborg kernel_read = optarg; 2396040fcc81SSam Ravnborg break; 2397040fcc81SSam Ravnborg case 'I': 2398040fcc81SSam Ravnborg module_read = optarg; 2399040fcc81SSam Ravnborg external_module = 1; 24001da177e4SLinus Torvalds break; 24012d04b5aeSRichard Hacker case 'e': 24022d04b5aeSRichard Hacker external_module = 1; 24032d04b5aeSRichard Hacker extsym_iter = 24042d04b5aeSRichard Hacker NOFAIL(malloc(sizeof(*extsym_iter))); 24052d04b5aeSRichard Hacker extsym_iter->next = extsym_start; 24062d04b5aeSRichard Hacker extsym_iter->file = optarg; 24072d04b5aeSRichard Hacker extsym_start = extsym_iter; 24082d04b5aeSRichard Hacker break; 24091da177e4SLinus Torvalds case 'm': 24101da177e4SLinus Torvalds modversions = 1; 24111da177e4SLinus Torvalds break; 2412eed380f3SGuenter Roeck case 'n': 2413eed380f3SGuenter Roeck ignore_missing_files = 1; 2414eed380f3SGuenter Roeck break; 24151da177e4SLinus Torvalds case 'o': 24161da177e4SLinus Torvalds dump_write = optarg; 24171da177e4SLinus Torvalds break; 24181da177e4SLinus Torvalds case 'a': 24191da177e4SLinus Torvalds all_versions = 1; 24201da177e4SLinus Torvalds break; 24218d8d8289SSam Ravnborg case 's': 24228d8d8289SSam Ravnborg vmlinux_section_warnings = 0; 24238d8d8289SSam Ravnborg break; 2424588ccd73SSam Ravnborg case 'S': 2425588ccd73SSam Ravnborg sec_mismatch_verbose = 0; 2426588ccd73SSam Ravnborg break; 2427712f9b46SRusty Russell case 'T': 2428712f9b46SRusty Russell files_source = optarg; 2429712f9b46SRusty Russell break; 2430c53ddacdSKirill Korotaev case 'w': 2431c53ddacdSKirill Korotaev warn_unresolved = 1; 2432c53ddacdSKirill Korotaev break; 243347490ec1SNicolas Boichat case 'E': 243447490ec1SNicolas Boichat sec_mismatch_fatal = 1; 243547490ec1SNicolas Boichat break; 24361da177e4SLinus Torvalds default: 24371da177e4SLinus Torvalds exit(1); 24381da177e4SLinus Torvalds } 24391da177e4SLinus Torvalds } 24401da177e4SLinus Torvalds 2441040fcc81SSam Ravnborg if (kernel_read) 2442040fcc81SSam Ravnborg read_dump(kernel_read, 1); 2443040fcc81SSam Ravnborg if (module_read) 2444040fcc81SSam Ravnborg read_dump(module_read, 0); 24452d04b5aeSRichard Hacker while (extsym_start) { 24462d04b5aeSRichard Hacker read_dump(extsym_start->file, 0); 24472d04b5aeSRichard Hacker extsym_iter = extsym_start->next; 24482d04b5aeSRichard Hacker free(extsym_start); 24492d04b5aeSRichard Hacker extsym_start = extsym_iter; 24502d04b5aeSRichard Hacker } 24511da177e4SLinus Torvalds 2452df578e7dSSam Ravnborg while (optind < argc) 24531da177e4SLinus Torvalds read_symbols(argv[optind++]); 24541da177e4SLinus Torvalds 2455712f9b46SRusty Russell if (files_source) 2456712f9b46SRusty Russell read_symbols_from_files(files_source); 2457712f9b46SRusty Russell 24581da177e4SLinus Torvalds for (mod = modules; mod; mod = mod->next) { 24591da177e4SLinus Torvalds if (mod->skip) 24601da177e4SLinus Torvalds continue; 2461c96fca21SSam Ravnborg check_exports(mod); 2462b817f6feSSam Ravnborg } 2463b817f6feSSam Ravnborg 2464c53ddacdSKirill Korotaev err = 0; 2465c53ddacdSKirill Korotaev 2466b817f6feSSam Ravnborg for (mod = modules; mod; mod = mod->next) { 2467d93e1719SMathias Krause char fname[PATH_MAX]; 2468666ab414SAndi Kleen 2469b817f6feSSam Ravnborg if (mod->skip) 2470b817f6feSSam Ravnborg continue; 24711da177e4SLinus Torvalds 24721da177e4SLinus Torvalds buf.pos = 0; 24731da177e4SLinus Torvalds 24741da177e4SLinus Torvalds add_header(&buf, mod); 24752449b8baSBen Hutchings add_intree_flag(&buf, !external_module); 2476a9860bf0SGreg Kroah-Hartman add_staging_flag(&buf, mod->name); 2477c53ddacdSKirill Korotaev err |= add_versions(&buf, mod); 24781da177e4SLinus Torvalds add_depends(&buf, mod, modules); 24791da177e4SLinus Torvalds add_moddevtable(&buf, mod); 24801da177e4SLinus Torvalds add_srcversion(&buf, mod); 24811da177e4SLinus Torvalds 24821da177e4SLinus Torvalds sprintf(fname, "%s.mod.c", mod->name); 24831da177e4SLinus Torvalds write_if_changed(&buf, fname); 24841da177e4SLinus Torvalds } 24851da177e4SLinus Torvalds if (dump_write) 24861da177e4SLinus Torvalds write_dump(dump_write); 248747490ec1SNicolas Boichat if (sec_mismatch_count) { 248847490ec1SNicolas Boichat if (!sec_mismatch_verbose) { 24897c0ac495SGeert Uytterhoeven warn("modpost: Found %d section mismatch(es).\n" 2490e5f95c8bSSam Ravnborg "To see full details build your kernel with:\n" 2491e5f95c8bSSam Ravnborg "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", 2492e5f95c8bSSam Ravnborg sec_mismatch_count); 249347490ec1SNicolas Boichat } 249447490ec1SNicolas Boichat if (sec_mismatch_fatal) { 249547490ec1SNicolas Boichat fatal("modpost: Section mismatches detected.\n" 249647490ec1SNicolas Boichat "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); 249747490ec1SNicolas Boichat } 249847490ec1SNicolas Boichat } 24991da177e4SLinus Torvalds 2500c53ddacdSKirill Korotaev return err; 25011da177e4SLinus Torvalds } 2502