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; 41eed380f3SGuenter Roeck /* ignore missing files */ 42eed380f3SGuenter Roeck static int ignore_missing_files; 43588ccd73SSam Ravnborg 44c96fca21SSam Ravnborg enum export { 45c96fca21SSam Ravnborg export_plain, export_unused, export_gpl, 46c96fca21SSam Ravnborg export_unused_gpl, export_gpl_future, export_unknown 47c96fca21SSam Ravnborg }; 481da177e4SLinus Torvalds 496d9a89eaSAndi Kleen #define PRINTF __attribute__ ((format (printf, 1, 2))) 506d9a89eaSAndi Kleen 516d9a89eaSAndi Kleen PRINTF void fatal(const char *fmt, ...) 521da177e4SLinus Torvalds { 531da177e4SLinus Torvalds va_list arglist; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds fprintf(stderr, "FATAL: "); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds va_start(arglist, fmt); 581da177e4SLinus Torvalds vfprintf(stderr, fmt, arglist); 591da177e4SLinus Torvalds va_end(arglist); 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds exit(1); 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 646d9a89eaSAndi Kleen PRINTF void warn(const char *fmt, ...) 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds va_list arglist; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds fprintf(stderr, "WARNING: "); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds va_start(arglist, fmt); 711da177e4SLinus Torvalds vfprintf(stderr, fmt, arglist); 721da177e4SLinus Torvalds va_end(arglist); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 756d9a89eaSAndi Kleen PRINTF void merror(const char *fmt, ...) 762a116659SMatthew Wilcox { 772a116659SMatthew Wilcox va_list arglist; 782a116659SMatthew Wilcox 792a116659SMatthew Wilcox fprintf(stderr, "ERROR: "); 802a116659SMatthew Wilcox 812a116659SMatthew Wilcox va_start(arglist, fmt); 822a116659SMatthew Wilcox vfprintf(stderr, fmt, arglist); 832a116659SMatthew Wilcox va_end(arglist); 842a116659SMatthew Wilcox } 852a116659SMatthew Wilcox 86d4ef1c30SRusty Russell static inline bool strends(const char *str, const char *postfix) 87d4ef1c30SRusty Russell { 88d4ef1c30SRusty Russell if (strlen(str) < strlen(postfix)) 89d4ef1c30SRusty Russell return false; 90d4ef1c30SRusty Russell 91d4ef1c30SRusty Russell return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; 92d4ef1c30SRusty Russell } 93d4ef1c30SRusty Russell 94040fcc81SSam Ravnborg static int is_vmlinux(const char *modname) 95040fcc81SSam Ravnborg { 96040fcc81SSam Ravnborg const char *myname; 97040fcc81SSam Ravnborg 98df578e7dSSam Ravnborg myname = strrchr(modname, '/'); 99df578e7dSSam Ravnborg if (myname) 100040fcc81SSam Ravnborg myname++; 101040fcc81SSam Ravnborg else 102040fcc81SSam Ravnborg myname = modname; 103040fcc81SSam Ravnborg 104741f98feSSam Ravnborg return (strcmp(myname, "vmlinux") == 0) || 105741f98feSSam Ravnborg (strcmp(myname, "vmlinux.o") == 0); 106040fcc81SSam Ravnborg } 107040fcc81SSam Ravnborg 1081da177e4SLinus Torvalds void *do_nofail(void *ptr, const char *expr) 1091da177e4SLinus Torvalds { 110df578e7dSSam Ravnborg if (!ptr) 1111da177e4SLinus Torvalds fatal("modpost: Memory allocation failure: %s.\n", expr); 112df578e7dSSam Ravnborg 1131da177e4SLinus Torvalds return ptr; 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* A list of all modules we processed */ 1171da177e4SLinus Torvalds static struct module *modules; 1181da177e4SLinus Torvalds 1195c3ead8cSSam Ravnborg static struct module *find_module(char *modname) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds struct module *mod; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds for (mod = modules; mod; mod = mod->next) 1241da177e4SLinus Torvalds if (strcmp(mod->name, modname) == 0) 1251da177e4SLinus Torvalds break; 1261da177e4SLinus Torvalds return mod; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 129d4ef1c30SRusty Russell static struct module *new_module(const char *modname) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds struct module *mod; 132d4ef1c30SRusty Russell char *p; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds mod = NOFAIL(malloc(sizeof(*mod))); 1351da177e4SLinus Torvalds memset(mod, 0, sizeof(*mod)); 1361da177e4SLinus Torvalds p = NOFAIL(strdup(modname)); 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /* strip trailing .o */ 139d4ef1c30SRusty Russell if (strends(p, ".o")) { 140d4ef1c30SRusty Russell p[strlen(p) - 2] = '\0'; 141258f7426SFrank Rowand mod->is_dot_o = 1; 142258f7426SFrank Rowand } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* add to list */ 1451da177e4SLinus Torvalds mod->name = p; 146b817f6feSSam Ravnborg mod->gpl_compatible = -1; 1471da177e4SLinus Torvalds mod->next = modules; 1481da177e4SLinus Torvalds modules = mod; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds return mod; 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds /* A hash of all exported symbols, 1541da177e4SLinus Torvalds * struct symbol is also used for lists of unresolved symbols */ 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds #define SYMBOL_HASH_SIZE 1024 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds struct symbol { 1591da177e4SLinus Torvalds struct symbol *next; 1601da177e4SLinus Torvalds struct module *module; 1611da177e4SLinus Torvalds unsigned int crc; 1621da177e4SLinus Torvalds int crc_valid; 1631da177e4SLinus Torvalds unsigned int weak:1; 164040fcc81SSam Ravnborg unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ 165040fcc81SSam Ravnborg unsigned int kernel:1; /* 1 if symbol is from kernel 166040fcc81SSam Ravnborg * (only for external modules) **/ 167b6568b1aSRusty Russell unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */ 168bd5cbcedSRam Pai enum export export; /* Type of export */ 1691da177e4SLinus Torvalds char name[0]; 1701da177e4SLinus Torvalds }; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds /* This is based on the hash agorithm from gdbm, via tdb */ 1751da177e4SLinus Torvalds static inline unsigned int tdb_hash(const char *name) 1761da177e4SLinus Torvalds { 1771da177e4SLinus Torvalds unsigned value; /* Used to compute the hash value. */ 1781da177e4SLinus Torvalds unsigned i; /* Used to cycle through random values. */ 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds /* Set the initial value from the key size. */ 1811da177e4SLinus Torvalds for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) 1821da177e4SLinus Torvalds value = (value + (((unsigned char *)name)[i] << (i*5 % 24))); 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds return (1103515243 * value + 12345); 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds 1875c3ead8cSSam Ravnborg /** 1885c3ead8cSSam Ravnborg * Allocate a new symbols for use in the hash of exported symbols or 1895c3ead8cSSam Ravnborg * the list of unresolved symbols per module 1905c3ead8cSSam Ravnborg **/ 1915c3ead8cSSam Ravnborg static struct symbol *alloc_symbol(const char *name, unsigned int weak, 1925c3ead8cSSam Ravnborg struct symbol *next) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds memset(s, 0, sizeof(*s)); 1971da177e4SLinus Torvalds strcpy(s->name, name); 1981da177e4SLinus Torvalds s->weak = weak; 1991da177e4SLinus Torvalds s->next = next; 2001da177e4SLinus Torvalds return s; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* For the hash of exported symbols */ 204bd5cbcedSRam Pai static struct symbol *new_symbol(const char *name, struct module *module, 205bd5cbcedSRam Pai enum export export) 2061da177e4SLinus Torvalds { 2071da177e4SLinus Torvalds unsigned int hash; 2081da177e4SLinus Torvalds struct symbol *new; 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds hash = tdb_hash(name) % SYMBOL_HASH_SIZE; 2111da177e4SLinus Torvalds new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); 2121da177e4SLinus Torvalds new->module = module; 213bd5cbcedSRam Pai new->export = export; 214040fcc81SSam Ravnborg return new; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2175c3ead8cSSam Ravnborg static struct symbol *find_symbol(const char *name) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds struct symbol *s; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /* For our purposes, .foo matches foo. PPC64 needs this. */ 2221da177e4SLinus Torvalds if (name[0] == '.') 2231da177e4SLinus Torvalds name++; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) { 2261da177e4SLinus Torvalds if (strcmp(s->name, name) == 0) 2271da177e4SLinus Torvalds return s; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds return NULL; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2327a3ee753SMathias Krause static const struct { 233bd5cbcedSRam Pai const char *str; 234bd5cbcedSRam Pai enum export export; 235bd5cbcedSRam Pai } export_list[] = { 236bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL", .export = export_plain }, 237c96fca21SSam Ravnborg { .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused }, 238bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, 239c96fca21SSam Ravnborg { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl }, 240bd5cbcedSRam Pai { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future }, 241bd5cbcedSRam Pai { .str = "(unknown)", .export = export_unknown }, 242bd5cbcedSRam Pai }; 243bd5cbcedSRam Pai 244bd5cbcedSRam Pai 245bd5cbcedSRam Pai static const char *export_str(enum export ex) 246bd5cbcedSRam Pai { 247bd5cbcedSRam Pai return export_list[ex].str; 248bd5cbcedSRam Pai } 249bd5cbcedSRam Pai 250bd5cbcedSRam Pai static enum export export_no(const char *s) 251bd5cbcedSRam Pai { 252bd5cbcedSRam Pai int i; 253df578e7dSSam Ravnborg 254534b89a9SSam Ravnborg if (!s) 255534b89a9SSam Ravnborg return export_unknown; 256bd5cbcedSRam Pai for (i = 0; export_list[i].export != export_unknown; i++) { 257bd5cbcedSRam Pai if (strcmp(export_list[i].str, s) == 0) 258bd5cbcedSRam Pai return export_list[i].export; 259bd5cbcedSRam Pai } 260bd5cbcedSRam Pai return export_unknown; 261bd5cbcedSRam Pai } 262bd5cbcedSRam Pai 26362a26356SAlessio Igor Bogani static const char *sec_name(struct elf_info *elf, int secindex); 26462a26356SAlessio Igor Bogani 26562a26356SAlessio Igor Bogani #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) 26662a26356SAlessio Igor Bogani 26762a26356SAlessio Igor Bogani static enum export export_from_secname(struct elf_info *elf, unsigned int sec) 26862a26356SAlessio Igor Bogani { 26962a26356SAlessio Igor Bogani const char *secname = sec_name(elf, sec); 27062a26356SAlessio Igor Bogani 27162a26356SAlessio Igor Bogani if (strstarts(secname, "___ksymtab+")) 27262a26356SAlessio Igor Bogani return export_plain; 27362a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_unused+")) 27462a26356SAlessio Igor Bogani return export_unused; 27562a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_gpl+")) 27662a26356SAlessio Igor Bogani return export_gpl; 27762a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_unused_gpl+")) 27862a26356SAlessio Igor Bogani return export_unused_gpl; 27962a26356SAlessio Igor Bogani else if (strstarts(secname, "___ksymtab_gpl_future+")) 28062a26356SAlessio Igor Bogani return export_gpl_future; 28162a26356SAlessio Igor Bogani else 28262a26356SAlessio Igor Bogani return export_unknown; 28362a26356SAlessio Igor Bogani } 28462a26356SAlessio Igor Bogani 2851ce53adfSDenys Vlasenko static enum export export_from_sec(struct elf_info *elf, unsigned int sec) 286bd5cbcedSRam Pai { 287bd5cbcedSRam Pai if (sec == elf->export_sec) 288bd5cbcedSRam Pai return export_plain; 289c96fca21SSam Ravnborg else if (sec == elf->export_unused_sec) 290c96fca21SSam Ravnborg return export_unused; 291bd5cbcedSRam Pai else if (sec == elf->export_gpl_sec) 292bd5cbcedSRam Pai return export_gpl; 293c96fca21SSam Ravnborg else if (sec == elf->export_unused_gpl_sec) 294c96fca21SSam Ravnborg return export_unused_gpl; 295bd5cbcedSRam Pai else if (sec == elf->export_gpl_future_sec) 296bd5cbcedSRam Pai return export_gpl_future; 297bd5cbcedSRam Pai else 298bd5cbcedSRam Pai return export_unknown; 299bd5cbcedSRam Pai } 300bd5cbcedSRam Pai 3015c3ead8cSSam Ravnborg /** 3025c3ead8cSSam Ravnborg * Add an exported symbol - it may have already been added without a 3035c3ead8cSSam Ravnborg * CRC, in this case just update the CRC 3045c3ead8cSSam Ravnborg **/ 305bd5cbcedSRam Pai static struct symbol *sym_add_exported(const char *name, struct module *mod, 306bd5cbcedSRam Pai enum export export) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds struct symbol *s = find_symbol(name); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds if (!s) { 311bd5cbcedSRam Pai s = new_symbol(name, mod, export); 3128e70c458SSam Ravnborg } else { 3138e70c458SSam Ravnborg if (!s->preloaded) { 3147b75b13cSSam Ravnborg warn("%s: '%s' exported twice. Previous export " 3158e70c458SSam Ravnborg "was in %s%s\n", mod->name, name, 3168e70c458SSam Ravnborg s->module->name, 3178e70c458SSam Ravnborg is_vmlinux(s->module->name) ?"":".ko"); 3184b21960fSTrent Piepho } else { 319baec30e4SPaul Bolle /* In case Module.symvers was out of date */ 3204b21960fSTrent Piepho s->module = mod; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds } 3238e70c458SSam Ravnborg s->preloaded = 0; 324040fcc81SSam Ravnborg s->vmlinux = is_vmlinux(mod->name); 325040fcc81SSam Ravnborg s->kernel = 0; 326bd5cbcedSRam Pai s->export = export; 327040fcc81SSam Ravnborg return s; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 330040fcc81SSam Ravnborg static void sym_update_crc(const char *name, struct module *mod, 331bd5cbcedSRam Pai unsigned int crc, enum export export) 332040fcc81SSam Ravnborg { 333040fcc81SSam Ravnborg struct symbol *s = find_symbol(name); 334040fcc81SSam Ravnborg 335b6568b1aSRusty Russell if (!s) { 336bd5cbcedSRam Pai s = new_symbol(name, mod, export); 337b6568b1aSRusty Russell /* Don't complain when we find it later. */ 338b6568b1aSRusty Russell s->preloaded = 1; 339b6568b1aSRusty Russell } 340040fcc81SSam Ravnborg s->crc = crc; 3411da177e4SLinus Torvalds s->crc_valid = 1; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds 3445c3ead8cSSam Ravnborg void *grab_file(const char *filename, unsigned long *size) 3451da177e4SLinus Torvalds { 3461da177e4SLinus Torvalds struct stat st; 347eb3d5cc6SJesper Juhl void *map = MAP_FAILED; 3481da177e4SLinus Torvalds int fd; 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds fd = open(filename, O_RDONLY); 351eb3d5cc6SJesper Juhl if (fd < 0) 3521da177e4SLinus Torvalds return NULL; 353eb3d5cc6SJesper Juhl if (fstat(fd, &st)) 354eb3d5cc6SJesper Juhl goto failed; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds *size = st.st_size; 3571da177e4SLinus Torvalds map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 3581da177e4SLinus Torvalds 359eb3d5cc6SJesper Juhl failed: 360eb3d5cc6SJesper Juhl close(fd); 3611da177e4SLinus Torvalds if (map == MAP_FAILED) 3621da177e4SLinus Torvalds return NULL; 3631da177e4SLinus Torvalds return map; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3665c3ead8cSSam Ravnborg /** 3675c3ead8cSSam Ravnborg * Return a copy of the next line in a mmap'ed file. 3685c3ead8cSSam Ravnborg * spaces in the beginning of the line is trimmed away. 3695c3ead8cSSam Ravnborg * Return a pointer to a static buffer. 3705c3ead8cSSam Ravnborg **/ 3715c3ead8cSSam Ravnborg char *get_next_line(unsigned long *pos, void *file, unsigned long size) 3721da177e4SLinus Torvalds { 3731da177e4SLinus Torvalds static char line[4096]; 3741da177e4SLinus Torvalds int skip = 1; 3751da177e4SLinus Torvalds size_t len = 0; 3761da177e4SLinus Torvalds signed char *p = (signed char *)file + *pos; 3771da177e4SLinus Torvalds char *s = line; 3781da177e4SLinus Torvalds 379df578e7dSSam Ravnborg for (; *pos < size ; (*pos)++) { 3801da177e4SLinus Torvalds if (skip && isspace(*p)) { 3811da177e4SLinus Torvalds p++; 3821da177e4SLinus Torvalds continue; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds skip = 0; 3851da177e4SLinus Torvalds if (*p != '\n' && (*pos < size)) { 3861da177e4SLinus Torvalds len++; 3871da177e4SLinus Torvalds *s++ = *p++; 3881da177e4SLinus Torvalds if (len > 4095) 3891da177e4SLinus Torvalds break; /* Too long, stop */ 3901da177e4SLinus Torvalds } else { 3911da177e4SLinus Torvalds /* End of string */ 3921da177e4SLinus Torvalds *s = '\0'; 3931da177e4SLinus Torvalds return line; 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds /* End of buffer */ 3971da177e4SLinus Torvalds return NULL; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4005c3ead8cSSam Ravnborg void release_file(void *file, unsigned long size) 4011da177e4SLinus Torvalds { 4021da177e4SLinus Torvalds munmap(file, size); 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 40585bd2fddSSam Ravnborg static int parse_elf(struct elf_info *info, const char *filename) 4061da177e4SLinus Torvalds { 4071da177e4SLinus Torvalds unsigned int i; 40885bd2fddSSam Ravnborg Elf_Ehdr *hdr; 4091da177e4SLinus Torvalds Elf_Shdr *sechdrs; 4101da177e4SLinus Torvalds Elf_Sym *sym; 4111ce53adfSDenys Vlasenko const char *secstrings; 4121ce53adfSDenys Vlasenko unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds hdr = grab_file(filename, &info->size); 4151da177e4SLinus Torvalds if (!hdr) { 416eed380f3SGuenter Roeck if (ignore_missing_files) { 417eed380f3SGuenter Roeck fprintf(stderr, "%s: %s (ignored)\n", filename, 418eed380f3SGuenter Roeck strerror(errno)); 419eed380f3SGuenter Roeck return 0; 420eed380f3SGuenter Roeck } 4211da177e4SLinus Torvalds perror(filename); 4226803dc0eSSam Ravnborg exit(1); 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds info->hdr = hdr; 42585bd2fddSSam Ravnborg if (info->size < sizeof(*hdr)) { 42685bd2fddSSam Ravnborg /* file too small, assume this is an empty .o file */ 42785bd2fddSSam Ravnborg return 0; 42885bd2fddSSam Ravnborg } 42985bd2fddSSam Ravnborg /* Is this a valid ELF file? */ 43085bd2fddSSam Ravnborg if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || 43185bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG1] != ELFMAG1) || 43285bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG2] != ELFMAG2) || 43385bd2fddSSam Ravnborg (hdr->e_ident[EI_MAG3] != ELFMAG3)) { 43485bd2fddSSam Ravnborg /* Not an ELF file - silently ignore it */ 43585bd2fddSSam Ravnborg return 0; 43685bd2fddSSam Ravnborg } 4371da177e4SLinus Torvalds /* Fix endianness in ELF header */ 438ae4ac123SAtsushi Nemoto hdr->e_type = TO_NATIVE(hdr->e_type); 4397d875a02SAnders Kaseorg hdr->e_machine = TO_NATIVE(hdr->e_machine); 4407d875a02SAnders Kaseorg hdr->e_version = TO_NATIVE(hdr->e_version); 4417d875a02SAnders Kaseorg hdr->e_entry = TO_NATIVE(hdr->e_entry); 4427d875a02SAnders Kaseorg hdr->e_phoff = TO_NATIVE(hdr->e_phoff); 4437d875a02SAnders Kaseorg hdr->e_shoff = TO_NATIVE(hdr->e_shoff); 4447d875a02SAnders Kaseorg hdr->e_flags = TO_NATIVE(hdr->e_flags); 4457d875a02SAnders Kaseorg hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize); 4467d875a02SAnders Kaseorg hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize); 4477d875a02SAnders Kaseorg hdr->e_phnum = TO_NATIVE(hdr->e_phnum); 4487d875a02SAnders Kaseorg hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize); 4497d875a02SAnders Kaseorg hdr->e_shnum = TO_NATIVE(hdr->e_shnum); 4507d875a02SAnders Kaseorg hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); 4511da177e4SLinus Torvalds sechdrs = (void *)hdr + hdr->e_shoff; 4521da177e4SLinus Torvalds info->sechdrs = sechdrs; 4531da177e4SLinus Torvalds 454a83710e5SPetr Stetiar /* Check if file offset is correct */ 455a83710e5SPetr Stetiar if (hdr->e_shoff > info->size) { 456df578e7dSSam Ravnborg fatal("section header offset=%lu in file '%s' is bigger than " 457df578e7dSSam Ravnborg "filesize=%lu\n", (unsigned long)hdr->e_shoff, 458df578e7dSSam Ravnborg filename, info->size); 459a83710e5SPetr Stetiar return 0; 460a83710e5SPetr Stetiar } 461a83710e5SPetr Stetiar 4626845756bSAnders Kaseorg if (hdr->e_shnum == SHN_UNDEF) { 4631ce53adfSDenys Vlasenko /* 4641ce53adfSDenys Vlasenko * There are more than 64k sections, 4651ce53adfSDenys Vlasenko * read count from .sh_size. 4661ce53adfSDenys Vlasenko */ 4671ce53adfSDenys Vlasenko info->num_sections = TO_NATIVE(sechdrs[0].sh_size); 4681ce53adfSDenys Vlasenko } 4691ce53adfSDenys Vlasenko else { 4701ce53adfSDenys Vlasenko info->num_sections = hdr->e_shnum; 4711ce53adfSDenys Vlasenko } 4721ce53adfSDenys Vlasenko if (hdr->e_shstrndx == SHN_XINDEX) { 4736845756bSAnders Kaseorg info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link); 4741ce53adfSDenys Vlasenko } 4751ce53adfSDenys Vlasenko else { 4761ce53adfSDenys Vlasenko info->secindex_strings = hdr->e_shstrndx; 4771ce53adfSDenys Vlasenko } 4781ce53adfSDenys Vlasenko 4791da177e4SLinus Torvalds /* Fix endianness in section headers */ 4801ce53adfSDenys Vlasenko for (i = 0; i < info->num_sections; i++) { 4817d875a02SAnders Kaseorg sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); 4821da177e4SLinus Torvalds sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); 4837d875a02SAnders Kaseorg sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); 4847d875a02SAnders Kaseorg sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); 4851da177e4SLinus Torvalds sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); 4861da177e4SLinus Torvalds sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); 4871da177e4SLinus Torvalds sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); 488ae4ac123SAtsushi Nemoto sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); 4897d875a02SAnders Kaseorg sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign); 4907d875a02SAnders Kaseorg sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds /* Find symbol table. */ 4931ce53adfSDenys Vlasenko secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; 4941ce53adfSDenys Vlasenko for (i = 1; i < info->num_sections; i++) { 495bd5cbcedSRam Pai const char *secname; 49656fc82c5STejun Heo int nobits = sechdrs[i].sh_type == SHT_NOBITS; 4971da177e4SLinus Torvalds 49856fc82c5STejun Heo if (!nobits && sechdrs[i].sh_offset > info->size) { 499df578e7dSSam Ravnborg fatal("%s is truncated. sechdrs[i].sh_offset=%lu > " 500df578e7dSSam Ravnborg "sizeof(*hrd)=%zu\n", filename, 501df578e7dSSam Ravnborg (unsigned long)sechdrs[i].sh_offset, 502df578e7dSSam Ravnborg sizeof(*hdr)); 50385bd2fddSSam Ravnborg return 0; 50485bd2fddSSam Ravnborg } 505bd5cbcedSRam Pai secname = secstrings + sechdrs[i].sh_name; 506bd5cbcedSRam Pai if (strcmp(secname, ".modinfo") == 0) { 50756fc82c5STejun Heo if (nobits) 50856fc82c5STejun Heo fatal("%s has NOBITS .modinfo\n", filename); 5091da177e4SLinus Torvalds info->modinfo = (void *)hdr + sechdrs[i].sh_offset; 5101da177e4SLinus Torvalds info->modinfo_len = sechdrs[i].sh_size; 511bd5cbcedSRam Pai } else if (strcmp(secname, "__ksymtab") == 0) 512bd5cbcedSRam Pai info->export_sec = i; 513c96fca21SSam Ravnborg else if (strcmp(secname, "__ksymtab_unused") == 0) 514c96fca21SSam Ravnborg info->export_unused_sec = i; 515bd5cbcedSRam Pai else if (strcmp(secname, "__ksymtab_gpl") == 0) 516bd5cbcedSRam Pai info->export_gpl_sec = i; 517c96fca21SSam Ravnborg else if (strcmp(secname, "__ksymtab_unused_gpl") == 0) 518c96fca21SSam Ravnborg info->export_unused_gpl_sec = i; 519bd5cbcedSRam Pai else if (strcmp(secname, "__ksymtab_gpl_future") == 0) 520bd5cbcedSRam Pai info->export_gpl_future_sec = i; 521bd5cbcedSRam Pai 5221ce53adfSDenys Vlasenko if (sechdrs[i].sh_type == SHT_SYMTAB) { 5231ce53adfSDenys Vlasenko unsigned int sh_link_idx; 5241ce53adfSDenys Vlasenko symtab_idx = i; 5251ce53adfSDenys Vlasenko info->symtab_start = (void *)hdr + 5261ce53adfSDenys Vlasenko sechdrs[i].sh_offset; 5271ce53adfSDenys Vlasenko info->symtab_stop = (void *)hdr + 5281ce53adfSDenys Vlasenko sechdrs[i].sh_offset + sechdrs[i].sh_size; 5296845756bSAnders Kaseorg sh_link_idx = sechdrs[i].sh_link; 5301da177e4SLinus Torvalds info->strtab = (void *)hdr + 5311ce53adfSDenys Vlasenko sechdrs[sh_link_idx].sh_offset; 5321ce53adfSDenys Vlasenko } 5331ce53adfSDenys Vlasenko 5341ce53adfSDenys Vlasenko /* 32bit section no. table? ("more than 64k sections") */ 5351ce53adfSDenys Vlasenko if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { 5361ce53adfSDenys Vlasenko symtab_shndx_idx = i; 5371ce53adfSDenys Vlasenko info->symtab_shndx_start = (void *)hdr + 5381ce53adfSDenys Vlasenko sechdrs[i].sh_offset; 5391ce53adfSDenys Vlasenko info->symtab_shndx_stop = (void *)hdr + 5401ce53adfSDenys Vlasenko sechdrs[i].sh_offset + sechdrs[i].sh_size; 5411ce53adfSDenys Vlasenko } 5421da177e4SLinus Torvalds } 543df578e7dSSam Ravnborg if (!info->symtab_start) 544cb80514dSSam Ravnborg fatal("%s has no symtab?\n", filename); 545df578e7dSSam Ravnborg 5461da177e4SLinus Torvalds /* Fix endianness in symbols */ 5471da177e4SLinus Torvalds for (sym = info->symtab_start; sym < info->symtab_stop; sym++) { 5481da177e4SLinus Torvalds sym->st_shndx = TO_NATIVE(sym->st_shndx); 5491da177e4SLinus Torvalds sym->st_name = TO_NATIVE(sym->st_name); 5501da177e4SLinus Torvalds sym->st_value = TO_NATIVE(sym->st_value); 5511da177e4SLinus Torvalds sym->st_size = TO_NATIVE(sym->st_size); 5521da177e4SLinus Torvalds } 5531ce53adfSDenys Vlasenko 5541ce53adfSDenys Vlasenko if (symtab_shndx_idx != ~0U) { 5551ce53adfSDenys Vlasenko Elf32_Word *p; 5566845756bSAnders Kaseorg if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link) 5571ce53adfSDenys Vlasenko fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", 5586845756bSAnders Kaseorg filename, sechdrs[symtab_shndx_idx].sh_link, 5591ce53adfSDenys Vlasenko symtab_idx); 5601ce53adfSDenys Vlasenko /* Fix endianness */ 5611ce53adfSDenys Vlasenko for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; 5621ce53adfSDenys Vlasenko p++) 5631ce53adfSDenys Vlasenko *p = TO_NATIVE(*p); 5641ce53adfSDenys Vlasenko } 5651ce53adfSDenys Vlasenko 56685bd2fddSSam Ravnborg return 1; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 5695c3ead8cSSam Ravnborg static void parse_elf_finish(struct elf_info *info) 5701da177e4SLinus Torvalds { 5711da177e4SLinus Torvalds release_file(info->hdr, info->size); 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds 5744d7365d6SSam Ravnborg static int ignore_undef_symbol(struct elf_info *info, const char *symname) 5754d7365d6SSam Ravnborg { 5764d7365d6SSam Ravnborg /* ignore __this_module, it will be resolved shortly */ 577b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0) 5784d7365d6SSam Ravnborg return 1; 5794d7365d6SSam Ravnborg /* ignore global offset table */ 5804d7365d6SSam Ravnborg if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) 5814d7365d6SSam Ravnborg return 1; 5824d7365d6SSam Ravnborg if (info->hdr->e_machine == EM_PPC) 5834d7365d6SSam Ravnborg /* Special register function linked on all modules during final link of .ko */ 5844d7365d6SSam Ravnborg if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 || 5854d7365d6SSam Ravnborg strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 || 5864d7365d6SSam Ravnborg strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || 5878fe9c93eSAndreas Schwab strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 || 5888fe9c93eSAndreas Schwab strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || 5898fe9c93eSAndreas Schwab strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) 5904d7365d6SSam Ravnborg return 1; 5917fca5dc8SStephen Rothwell if (info->hdr->e_machine == EM_PPC64) 5927fca5dc8SStephen Rothwell /* Special register function linked on all modules during final link of .ko */ 5937fca5dc8SStephen Rothwell if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || 5948fe9c93eSAndreas Schwab strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || 5958fe9c93eSAndreas Schwab strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || 5968fe9c93eSAndreas Schwab strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) 5977fca5dc8SStephen Rothwell return 1; 5984d7365d6SSam Ravnborg /* Do not ignore this symbol */ 5994d7365d6SSam Ravnborg return 0; 6004d7365d6SSam Ravnborg } 6014d7365d6SSam Ravnborg 602b92021b0SRusty Russell #define CRC_PFX VMLINUX_SYMBOL_STR(__crc_) 603b92021b0SRusty Russell #define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_) 6041da177e4SLinus Torvalds 6055c3ead8cSSam Ravnborg static void handle_modversions(struct module *mod, struct elf_info *info, 6061da177e4SLinus Torvalds Elf_Sym *sym, const char *symname) 6071da177e4SLinus Torvalds { 6081da177e4SLinus Torvalds unsigned int crc; 60962a26356SAlessio Igor Bogani enum export export; 61062a26356SAlessio Igor Bogani 611258f7426SFrank Rowand if ((!is_vmlinux(mod->name) || mod->is_dot_o) && 612258f7426SFrank Rowand strncmp(symname, "__ksymtab", 9) == 0) 61362a26356SAlessio Igor Bogani export = export_from_secname(info, get_secindex(info, sym)); 61462a26356SAlessio Igor Bogani else 61562a26356SAlessio Igor Bogani export = export_from_sec(info, get_secindex(info, sym)); 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds /* CRC'd symbol */ 6188d99513cSMichal Marek if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { 6191da177e4SLinus Torvalds crc = (unsigned int) sym->st_value; 620bd5cbcedSRam Pai sym_update_crc(symname + strlen(CRC_PFX), mod, crc, 621bd5cbcedSRam Pai export); 6221da177e4SLinus Torvalds } 623b5064654SAndi Kleen 624b5064654SAndi Kleen switch (sym->st_shndx) { 625b5064654SAndi Kleen case SHN_COMMON: 626ef178f92SAndi Kleen if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) { 627ef178f92SAndi Kleen /* Should warn here, but modpost runs before the linker */ 628ef178f92SAndi Kleen } else 629b5064654SAndi Kleen warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); 6301da177e4SLinus Torvalds break; 6311da177e4SLinus Torvalds case SHN_UNDEF: 6321da177e4SLinus Torvalds /* undefined symbol */ 6331da177e4SLinus Torvalds if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && 6341da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) != STB_WEAK) 6351da177e4SLinus Torvalds break; 6364d7365d6SSam Ravnborg if (ignore_undef_symbol(info, symname)) 6371da177e4SLinus Torvalds break; 6388d529014SBen Colline /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ 6398d529014SBen Colline #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) 6408d529014SBen Colline /* add compatibility with older glibc */ 6418d529014SBen Colline #ifndef STT_SPARC_REGISTER 6428d529014SBen Colline #define STT_SPARC_REGISTER STT_REGISTER 6438d529014SBen Colline #endif 6441da177e4SLinus Torvalds if (info->hdr->e_machine == EM_SPARC || 6451da177e4SLinus Torvalds info->hdr->e_machine == EM_SPARCV9) { 6461da177e4SLinus Torvalds /* Ignore register directives. */ 6478d529014SBen Colline if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) 6481da177e4SLinus Torvalds break; 6497caaeabbSAl Viro if (symname[0] == '.') { 6507caaeabbSAl Viro char *munged = strdup(symname); 6517caaeabbSAl Viro munged[0] = '_'; 6527caaeabbSAl Viro munged[1] = toupper(munged[1]); 6537caaeabbSAl Viro symname = munged; 6547caaeabbSAl Viro } 6551da177e4SLinus Torvalds } 6561da177e4SLinus Torvalds #endif 6571da177e4SLinus Torvalds 658b92021b0SRusty Russell #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX 659b92021b0SRusty Russell if (symname[0] != '_') 660b92021b0SRusty Russell break; 661b92021b0SRusty Russell else 662b92021b0SRusty Russell symname++; 663b92021b0SRusty Russell #endif 664b92021b0SRusty Russell mod->unres = alloc_symbol(symname, 6651da177e4SLinus Torvalds ELF_ST_BIND(sym->st_info) == STB_WEAK, 6661da177e4SLinus Torvalds mod->unres); 6671da177e4SLinus Torvalds break; 6681da177e4SLinus Torvalds default: 6691da177e4SLinus Torvalds /* All exported symbols */ 6708d99513cSMichal Marek if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { 671bd5cbcedSRam Pai sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, 672bd5cbcedSRam Pai export); 6731da177e4SLinus Torvalds } 674b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0) 6751da177e4SLinus Torvalds mod->has_init = 1; 676b92021b0SRusty Russell if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0) 6771da177e4SLinus Torvalds mod->has_cleanup = 1; 6781da177e4SLinus Torvalds break; 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds 6825c3ead8cSSam Ravnborg /** 6835c3ead8cSSam Ravnborg * Parse tag=value strings from .modinfo section 6845c3ead8cSSam Ravnborg **/ 6851da177e4SLinus Torvalds static char *next_string(char *string, unsigned long *secsize) 6861da177e4SLinus Torvalds { 6871da177e4SLinus Torvalds /* Skip non-zero chars */ 6881da177e4SLinus Torvalds while (string[0]) { 6891da177e4SLinus Torvalds string++; 6901da177e4SLinus Torvalds if ((*secsize)-- <= 1) 6911da177e4SLinus Torvalds return NULL; 6921da177e4SLinus Torvalds } 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds /* Skip any zero padding. */ 6951da177e4SLinus Torvalds while (!string[0]) { 6961da177e4SLinus Torvalds string++; 6971da177e4SLinus Torvalds if ((*secsize)-- <= 1) 6981da177e4SLinus Torvalds return NULL; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds return string; 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds 703b817f6feSSam Ravnborg static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, 704b817f6feSSam Ravnborg const char *tag, char *info) 7051da177e4SLinus Torvalds { 7061da177e4SLinus Torvalds char *p; 7071da177e4SLinus Torvalds unsigned int taglen = strlen(tag); 7081da177e4SLinus Torvalds unsigned long size = modinfo_len; 7091da177e4SLinus Torvalds 710b817f6feSSam Ravnborg if (info) { 711b817f6feSSam Ravnborg size -= info - (char *)modinfo; 712b817f6feSSam Ravnborg modinfo = next_string(info, &size); 713b817f6feSSam Ravnborg } 714b817f6feSSam Ravnborg 7151da177e4SLinus Torvalds for (p = modinfo; p; p = next_string(p, &size)) { 7161da177e4SLinus Torvalds if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') 7171da177e4SLinus Torvalds return p + taglen + 1; 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds return NULL; 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds 722b817f6feSSam Ravnborg static char *get_modinfo(void *modinfo, unsigned long modinfo_len, 723b817f6feSSam Ravnborg const char *tag) 724b817f6feSSam Ravnborg 725b817f6feSSam Ravnborg { 726b817f6feSSam Ravnborg return get_next_modinfo(modinfo, modinfo_len, tag, NULL); 727b817f6feSSam Ravnborg } 728b817f6feSSam Ravnborg 72993684d3bSSam Ravnborg /** 7304c8fbca5SSam Ravnborg * Test if string s ends in string sub 7314c8fbca5SSam Ravnborg * return 0 if match 7324c8fbca5SSam Ravnborg **/ 7334c8fbca5SSam Ravnborg static int strrcmp(const char *s, const char *sub) 7344c8fbca5SSam Ravnborg { 7354c8fbca5SSam Ravnborg int slen, sublen; 7364c8fbca5SSam Ravnborg 7374c8fbca5SSam Ravnborg if (!s || !sub) 7384c8fbca5SSam Ravnborg return 1; 7394c8fbca5SSam Ravnborg 7404c8fbca5SSam Ravnborg slen = strlen(s); 7414c8fbca5SSam Ravnborg sublen = strlen(sub); 7424c8fbca5SSam Ravnborg 7434c8fbca5SSam Ravnborg if ((slen == 0) || (sublen == 0)) 7444c8fbca5SSam Ravnborg return 1; 7454c8fbca5SSam Ravnborg 7464c8fbca5SSam Ravnborg if (sublen > slen) 7474c8fbca5SSam Ravnborg return 1; 7484c8fbca5SSam Ravnborg 7494c8fbca5SSam Ravnborg return memcmp(s + slen - sublen, sub, sublen); 7504c8fbca5SSam Ravnborg } 7514c8fbca5SSam Ravnborg 752ff13f926SSam Ravnborg static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) 753ff13f926SSam Ravnborg { 75458fb0d4fSSam Ravnborg if (sym) 755ff13f926SSam Ravnborg return elf->strtab + sym->st_name; 75658fb0d4fSSam Ravnborg else 757f666751aSSam Ravnborg return "(unknown)"; 758ff13f926SSam Ravnborg } 759ff13f926SSam Ravnborg 7601ce53adfSDenys Vlasenko static const char *sec_name(struct elf_info *elf, int secindex) 761ff13f926SSam Ravnborg { 762ff13f926SSam Ravnborg Elf_Shdr *sechdrs = elf->sechdrs; 763ff13f926SSam Ravnborg return (void *)elf->hdr + 7641ce53adfSDenys Vlasenko elf->sechdrs[elf->secindex_strings].sh_offset + 7651ce53adfSDenys Vlasenko sechdrs[secindex].sh_name; 766ff13f926SSam Ravnborg } 767ff13f926SSam Ravnborg 768ff13f926SSam Ravnborg static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) 769ff13f926SSam Ravnborg { 770ff13f926SSam Ravnborg return (void *)elf->hdr + 7711ce53adfSDenys Vlasenko elf->sechdrs[elf->secindex_strings].sh_offset + 772ff13f926SSam Ravnborg sechdr->sh_name; 773ff13f926SSam Ravnborg } 774ff13f926SSam Ravnborg 77510668220SSam Ravnborg /* The pattern is an array of simple patterns. 77610668220SSam Ravnborg * "foo" will match an exact string equal to "foo" 7776c5bd235SSam Ravnborg * "*foo" will match a string that ends with "foo" 77810668220SSam Ravnborg * "foo*" will match a string that begins with "foo" 779*09c20c03SPaul Gortmaker * "*foo*" will match a string that contains "foo" 78010668220SSam Ravnborg */ 7815c725138STrevor Keith static int match(const char *sym, const char * const pat[]) 78210668220SSam Ravnborg { 78310668220SSam Ravnborg const char *p; 78410668220SSam Ravnborg while (*pat) { 78510668220SSam Ravnborg p = *pat++; 78610668220SSam Ravnborg const char *endp = p + strlen(p) - 1; 78710668220SSam Ravnborg 788*09c20c03SPaul Gortmaker /* "*foo*" */ 789*09c20c03SPaul Gortmaker if (*p == '*' && *endp == '*') { 790*09c20c03SPaul Gortmaker char *here, *bare = strndup(p + 1, strlen(p) - 2); 791*09c20c03SPaul Gortmaker 792*09c20c03SPaul Gortmaker here = strstr(sym, bare); 793*09c20c03SPaul Gortmaker free(bare); 794*09c20c03SPaul Gortmaker if (here != NULL) 795*09c20c03SPaul Gortmaker return 1; 796*09c20c03SPaul Gortmaker } 7976c5bd235SSam Ravnborg /* "*foo" */ 798*09c20c03SPaul Gortmaker else if (*p == '*') { 7996c5bd235SSam Ravnborg if (strrcmp(sym, p + 1) == 0) 8006c5bd235SSam Ravnborg return 1; 8016c5bd235SSam Ravnborg } 80210668220SSam Ravnborg /* "foo*" */ 8036c5bd235SSam Ravnborg else if (*endp == '*') { 80410668220SSam Ravnborg if (strncmp(sym, p, strlen(p) - 1) == 0) 80510668220SSam Ravnborg return 1; 80610668220SSam Ravnborg } 80710668220SSam Ravnborg /* no wildcards */ 80810668220SSam Ravnborg else { 80910668220SSam Ravnborg if (strcmp(p, sym) == 0) 81010668220SSam Ravnborg return 1; 81110668220SSam Ravnborg } 81210668220SSam Ravnborg } 81310668220SSam Ravnborg /* no match */ 81410668220SSam Ravnborg return 0; 81510668220SSam Ravnborg } 81610668220SSam Ravnborg 81710668220SSam Ravnborg /* sections that we do not want to do full section mismatch check on */ 8187a3ee753SMathias Krause static const char *const section_white_list[] = 8194391ed6aSSam Ravnborg { 8204391ed6aSSam Ravnborg ".comment*", 8214391ed6aSSam Ravnborg ".debug*", 8224d10c223SChen Gang ".cranges", /* sh64 */ 8231121584fSH.J. Lu ".zdebug*", /* Compressed debug sections. */ 824019fca84SDavid Howells ".GCC-command-line", /* mn10300 */ 82576b27645SJonathan Kliegman ".GCC.command.line", /* record-gcc-switches, non mn10300 */ 8264391ed6aSSam Ravnborg ".mdebug*", /* alpha, score, mips etc. */ 8274391ed6aSSam Ravnborg ".pdr", /* alpha, score, mips etc. */ 8284391ed6aSSam Ravnborg ".stab*", 8294391ed6aSSam Ravnborg ".note*", 8304391ed6aSSam Ravnborg ".got*", 8314391ed6aSSam Ravnborg ".toc*", 832af42e970SMax Filippov ".xt.prop", /* xtensa */ 833af42e970SMax Filippov ".xt.lit", /* xtensa */ 834f2e207f3SVineet Gupta ".arcextmap*", /* arc */ 835f2e207f3SVineet Gupta ".gnu.linkonce.arcext*", /* arc : modules */ 836ef178f92SAndi Kleen ".gnu.lto*", 8374391ed6aSSam Ravnborg NULL 8384391ed6aSSam Ravnborg }; 83910668220SSam Ravnborg 840e241a630SSam Ravnborg /* 841b614a697SAnders Kaseorg * This is used to find sections missing the SHF_ALLOC flag. 842e241a630SSam Ravnborg * The cause of this is often a section specified in assembler 843b614a697SAnders Kaseorg * without "ax" / "aw". 844e241a630SSam Ravnborg */ 845b614a697SAnders Kaseorg static void check_section(const char *modname, struct elf_info *elf, 846b614a697SAnders Kaseorg Elf_Shdr *sechdr) 847e241a630SSam Ravnborg { 848b614a697SAnders Kaseorg const char *sec = sech_name(elf, sechdr); 849e241a630SSam Ravnborg 850b614a697SAnders Kaseorg if (sechdr->sh_type == SHT_PROGBITS && 851b614a697SAnders Kaseorg !(sechdr->sh_flags & SHF_ALLOC) && 852b614a697SAnders Kaseorg !match(sec, section_white_list)) { 853b614a697SAnders Kaseorg warn("%s (%s): unexpected non-allocatable section.\n" 854b614a697SAnders Kaseorg "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" 855e241a630SSam Ravnborg "Note that for example <linux/init.h> contains\n" 856e241a630SSam Ravnborg "section definitions for use in .S files.\n\n", 857e241a630SSam Ravnborg modname, sec); 858e241a630SSam Ravnborg } 859e241a630SSam Ravnborg } 860e241a630SSam Ravnborg 861e241a630SSam Ravnborg 862e241a630SSam Ravnborg 863eb8f6890SSam Ravnborg #define ALL_INIT_DATA_SECTIONS \ 864a0d8f803SRasmus Villemoes ".init.setup", ".init.rodata", ".meminit.rodata", \ 865a0d8f803SRasmus Villemoes ".init.data", ".meminit.data" 866eb8f6890SSam Ravnborg #define ALL_EXIT_DATA_SECTIONS \ 867a0d8f803SRasmus Villemoes ".exit.data", ".memexit.data" 86810668220SSam Ravnborg 869eb8f6890SSam Ravnborg #define ALL_INIT_TEXT_SECTIONS \ 870a0d8f803SRasmus Villemoes ".init.text", ".meminit.text" 871eb8f6890SSam Ravnborg #define ALL_EXIT_TEXT_SECTIONS \ 872a0d8f803SRasmus Villemoes ".exit.text", ".memexit.text" 87310668220SSam Ravnborg 874bb15d8dbSSebastian Andrzej Siewior #define ALL_PCI_INIT_SECTIONS \ 875a0d8f803SRasmus Villemoes ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \ 876a0d8f803SRasmus Villemoes ".pci_fixup_enable", ".pci_fixup_resume", \ 877a0d8f803SRasmus Villemoes ".pci_fixup_resume_early", ".pci_fixup_suspend" 878bb15d8dbSSebastian Andrzej Siewior 879e24f6628SPaul Gortmaker #define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS 880e24f6628SPaul Gortmaker #define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS 8814a31a229SUwe Kleine-König 8824a31a229SUwe Kleine-König #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS 8834a31a229SUwe Kleine-König #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS 88410668220SSam Ravnborg 885a0d8f803SRasmus Villemoes #define DATA_SECTIONS ".data", ".data.rel" 886157d1972SQuentin Casasnovas #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ 887157d1972SQuentin Casasnovas ".kprobes.text" 88852dc0595SQuentin Casasnovas #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ 8896c730bfcSRusty Russell ".fixup", ".entry.text", ".exception.text", ".text.*" 89010668220SSam Ravnborg 891fd6c3a8dSJan Beulich #define INIT_SECTIONS ".init.*" 892fd6c3a8dSJan Beulich #define MEM_INIT_SECTIONS ".meminit.*" 893eb8f6890SSam Ravnborg 894fd6c3a8dSJan Beulich #define EXIT_SECTIONS ".exit.*" 895fd6c3a8dSJan Beulich #define MEM_EXIT_SECTIONS ".memexit.*" 896eb8f6890SSam Ravnborg 89752dc0595SQuentin Casasnovas #define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \ 89852dc0595SQuentin Casasnovas TEXT_SECTIONS, OTHER_TEXT_SECTIONS 89952dc0595SQuentin Casasnovas 9006c5bd235SSam Ravnborg /* init data sections */ 9017a3ee753SMathias Krause static const char *const init_data_sections[] = 9027a3ee753SMathias Krause { ALL_INIT_DATA_SECTIONS, NULL }; 9036c5bd235SSam Ravnborg 9046c5bd235SSam Ravnborg /* all init sections */ 9057a3ee753SMathias Krause static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; 9066c5bd235SSam Ravnborg 9076c5bd235SSam Ravnborg /* All init and exit sections (code + data) */ 9087a3ee753SMathias Krause static const char *const init_exit_sections[] = 909eb8f6890SSam Ravnborg {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; 9106c5bd235SSam Ravnborg 9116c5bd235SSam Ravnborg /* data section */ 9127a3ee753SMathias Krause static const char *const data_sections[] = { DATA_SECTIONS, NULL }; 9136c5bd235SSam Ravnborg 9146c5bd235SSam Ravnborg 9156c5bd235SSam Ravnborg /* symbols in .data that may refer to init/exit sections */ 916af92a82dSUwe Kleine-König #define DEFAULT_SYMBOL_WHITE_LIST \ 917af92a82dSUwe Kleine-König "*driver", \ 918af92a82dSUwe Kleine-König "*_template", /* scsi uses *_template a lot */ \ 919af92a82dSUwe Kleine-König "*_timer", /* arm uses ops structures named _timer a lot */ \ 920af92a82dSUwe Kleine-König "*_sht", /* scsi also used *_sht to some extent */ \ 921af92a82dSUwe Kleine-König "*_ops", \ 922af92a82dSUwe Kleine-König "*_probe", \ 923af92a82dSUwe Kleine-König "*_probe_one", \ 924af92a82dSUwe Kleine-König "*_console" 9256c5bd235SSam Ravnborg 9267a3ee753SMathias Krause static const char *const head_sections[] = { ".head.text*", NULL }; 9277a3ee753SMathias Krause static const char *const linker_symbols[] = 9286c5bd235SSam Ravnborg { "__init_begin", "_sinittext", "_einittext", NULL }; 9296c5bd235SSam Ravnborg 930588ccd73SSam Ravnborg enum mismatch { 931bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_INIT, 932bbd3f4fbSUwe Kleine-König DATA_TO_ANY_INIT, 933bbd3f4fbSUwe Kleine-König TEXT_TO_ANY_EXIT, 934bbd3f4fbSUwe Kleine-König DATA_TO_ANY_EXIT, 935bbd3f4fbSUwe Kleine-König XXXINIT_TO_SOME_INIT, 936bbd3f4fbSUwe Kleine-König XXXEXIT_TO_SOME_EXIT, 937bbd3f4fbSUwe Kleine-König ANY_INIT_TO_ANY_EXIT, 938bbd3f4fbSUwe Kleine-König ANY_EXIT_TO_ANY_INIT, 939588ccd73SSam Ravnborg EXPORT_TO_INIT_EXIT, 94052dc0595SQuentin Casasnovas EXTABLE_TO_NON_TEXT, 941588ccd73SSam Ravnborg }; 942588ccd73SSam Ravnborg 943e5d8f59aSQuentin Casasnovas /** 944e5d8f59aSQuentin Casasnovas * Describe how to match sections on different criterias: 945e5d8f59aSQuentin Casasnovas * 946e5d8f59aSQuentin Casasnovas * @fromsec: Array of sections to be matched. 947e5d8f59aSQuentin Casasnovas * 948e5d8f59aSQuentin Casasnovas * @bad_tosec: Relocations applied to a section in @fromsec to a section in 949e5d8f59aSQuentin Casasnovas * this array is forbidden (black-list). Can be empty. 950e5d8f59aSQuentin Casasnovas * 951e5d8f59aSQuentin Casasnovas * @good_tosec: Relocations applied to a section in @fromsec must be 952e5d8f59aSQuentin Casasnovas * targetting sections in this array (white-list). Can be empty. 953e5d8f59aSQuentin Casasnovas * 954e5d8f59aSQuentin Casasnovas * @mismatch: Type of mismatch. 955e5d8f59aSQuentin Casasnovas * 956e5d8f59aSQuentin Casasnovas * @symbol_white_list: Do not match a relocation to a symbol in this list 957e5d8f59aSQuentin Casasnovas * even if it is targetting a section in @bad_to_sec. 958e5d8f59aSQuentin Casasnovas * 959e5d8f59aSQuentin Casasnovas * @handler: Specific handler to call when a match is found. If NULL, 960e5d8f59aSQuentin Casasnovas * default_mismatch_handler() will be called. 961e5d8f59aSQuentin Casasnovas * 962e5d8f59aSQuentin Casasnovas */ 96310668220SSam Ravnborg struct sectioncheck { 96410668220SSam Ravnborg const char *fromsec[20]; 965050e57fdSQuentin Casasnovas const char *bad_tosec[20]; 966050e57fdSQuentin Casasnovas const char *good_tosec[20]; 967588ccd73SSam Ravnborg enum mismatch mismatch; 968af92a82dSUwe Kleine-König const char *symbol_white_list[20]; 969644e8f14SQuentin Casasnovas void (*handler)(const char *modname, struct elf_info *elf, 970644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 971644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec); 972644e8f14SQuentin Casasnovas 97310668220SSam Ravnborg }; 97410668220SSam Ravnborg 97552dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char *modname, struct elf_info *elf, 97652dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 97752dc0595SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, 97852dc0595SQuentin Casasnovas const char *fromsec); 97952dc0595SQuentin Casasnovas 9807a3ee753SMathias Krause static const struct sectioncheck sectioncheck[] = { 98110668220SSam Ravnborg /* Do not reference init/exit code/data from 98210668220SSam Ravnborg * normal code and data 98310668220SSam Ravnborg */ 98410668220SSam Ravnborg { 985588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 986050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 987bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_INIT, 988af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 989588ccd73SSam Ravnborg }, 990588ccd73SSam Ravnborg { 991588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 992050e57fdSQuentin Casasnovas .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, 993bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 994af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 995588ccd73SSam Ravnborg }, 996588ccd73SSam Ravnborg { 9970db25245SUwe Kleine-König .fromsec = { DATA_SECTIONS, NULL }, 998050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 9990db25245SUwe Kleine-König .mismatch = DATA_TO_ANY_INIT, 10000db25245SUwe Kleine-König .symbol_white_list = { 10010db25245SUwe Kleine-König "*_template", "*_timer", "*_sht", "*_ops", 10020db25245SUwe Kleine-König "*_probe", "*_probe_one", "*_console", NULL 10030db25245SUwe Kleine-König }, 10040db25245SUwe Kleine-König }, 10050db25245SUwe Kleine-König { 1006588ccd73SSam Ravnborg .fromsec = { TEXT_SECTIONS, NULL }, 1007050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1008bbd3f4fbSUwe Kleine-König .mismatch = TEXT_TO_ANY_EXIT, 1009af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1010588ccd73SSam Ravnborg }, 1011588ccd73SSam Ravnborg { 1012588ccd73SSam Ravnborg .fromsec = { DATA_SECTIONS, NULL }, 1013050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1014bbd3f4fbSUwe Kleine-König .mismatch = DATA_TO_ANY_EXIT, 1015af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1016eb8f6890SSam Ravnborg }, 1017e24f6628SPaul Gortmaker /* Do not reference init code/data from meminit code/data */ 1018eb8f6890SSam Ravnborg { 10194a31a229SUwe Kleine-König .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, 1020050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1021bbd3f4fbSUwe Kleine-König .mismatch = XXXINIT_TO_SOME_INIT, 1022af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1023eb8f6890SSam Ravnborg }, 1024e24f6628SPaul Gortmaker /* Do not reference exit code/data from memexit code/data */ 1025eb8f6890SSam Ravnborg { 10264a31a229SUwe Kleine-König .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, 1027050e57fdSQuentin Casasnovas .bad_tosec = { EXIT_SECTIONS, NULL }, 1028bbd3f4fbSUwe Kleine-König .mismatch = XXXEXIT_TO_SOME_EXIT, 1029af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 103010668220SSam Ravnborg }, 103110668220SSam Ravnborg /* Do not use exit code/data from init code */ 103210668220SSam Ravnborg { 1033eb8f6890SSam Ravnborg .fromsec = { ALL_INIT_SECTIONS, NULL }, 1034050e57fdSQuentin Casasnovas .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, 1035bbd3f4fbSUwe Kleine-König .mismatch = ANY_INIT_TO_ANY_EXIT, 1036af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 103710668220SSam Ravnborg }, 103810668220SSam Ravnborg /* Do not use init code/data from exit code */ 103910668220SSam Ravnborg { 1040eb8f6890SSam Ravnborg .fromsec = { ALL_EXIT_SECTIONS, NULL }, 1041050e57fdSQuentin Casasnovas .bad_tosec = { ALL_INIT_SECTIONS, NULL }, 1042bbd3f4fbSUwe Kleine-König .mismatch = ANY_EXIT_TO_ANY_INIT, 1043af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 104410668220SSam Ravnborg }, 1045bb15d8dbSSebastian Andrzej Siewior { 1046bb15d8dbSSebastian Andrzej Siewior .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, 1047050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, NULL }, 1048bb15d8dbSSebastian Andrzej Siewior .mismatch = ANY_INIT_TO_ANY_EXIT, 1049bb15d8dbSSebastian Andrzej Siewior .symbol_white_list = { NULL }, 1050bb15d8dbSSebastian Andrzej Siewior }, 105110668220SSam Ravnborg /* Do not export init/exit functions or data */ 105210668220SSam Ravnborg { 105310668220SSam Ravnborg .fromsec = { "__ksymtab*", NULL }, 1054050e57fdSQuentin Casasnovas .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, 1055af92a82dSUwe Kleine-König .mismatch = EXPORT_TO_INIT_EXIT, 1056af92a82dSUwe Kleine-König .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 105752dc0595SQuentin Casasnovas }, 105852dc0595SQuentin Casasnovas { 105952dc0595SQuentin Casasnovas .fromsec = { "__ex_table", NULL }, 106052dc0595SQuentin Casasnovas /* If you're adding any new black-listed sections in here, consider 106152dc0595SQuentin Casasnovas * adding a special 'printer' for them in scripts/check_extable. 106252dc0595SQuentin Casasnovas */ 106352dc0595SQuentin Casasnovas .bad_tosec = { ".altinstr_replacement", NULL }, 106452dc0595SQuentin Casasnovas .good_tosec = {ALL_TEXT_SECTIONS , NULL}, 106552dc0595SQuentin Casasnovas .mismatch = EXTABLE_TO_NON_TEXT, 106652dc0595SQuentin Casasnovas .handler = extable_mismatch_handler, 106710668220SSam Ravnborg } 106810668220SSam Ravnborg }; 106910668220SSam Ravnborg 10700d2a636eSUwe Kleine-König static const struct sectioncheck *section_mismatch( 10710d2a636eSUwe Kleine-König const char *fromsec, const char *tosec) 107210668220SSam Ravnborg { 107310668220SSam Ravnborg int i; 107410668220SSam Ravnborg int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); 107510668220SSam Ravnborg const struct sectioncheck *check = §ioncheck[0]; 107610668220SSam Ravnborg 1077c5c3439aSQuentin Casasnovas /* 1078c5c3439aSQuentin Casasnovas * The target section could be the SHT_NUL section when we're 1079c5c3439aSQuentin Casasnovas * handling relocations to un-resolved symbols, trying to match it 1080c5c3439aSQuentin Casasnovas * doesn't make much sense and causes build failures on parisc and 1081c5c3439aSQuentin Casasnovas * mn10300 architectures. 1082c5c3439aSQuentin Casasnovas */ 1083c5c3439aSQuentin Casasnovas if (*tosec == '\0') 1084c5c3439aSQuentin Casasnovas return NULL; 1085c5c3439aSQuentin Casasnovas 108610668220SSam Ravnborg for (i = 0; i < elems; i++) { 1087050e57fdSQuentin Casasnovas if (match(fromsec, check->fromsec)) { 1088050e57fdSQuentin Casasnovas if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) 10890d2a636eSUwe Kleine-König return check; 1090050e57fdSQuentin Casasnovas if (check->good_tosec[0] && !match(tosec, check->good_tosec)) 1091050e57fdSQuentin Casasnovas return check; 1092050e57fdSQuentin Casasnovas } 109310668220SSam Ravnborg check++; 109410668220SSam Ravnborg } 10950d2a636eSUwe Kleine-König return NULL; 109610668220SSam Ravnborg } 109710668220SSam Ravnborg 10984c8fbca5SSam Ravnborg /** 10994c8fbca5SSam Ravnborg * Whitelist to allow certain references to pass with no warning. 11000e0d314eSSam Ravnborg * 11014c8fbca5SSam Ravnborg * Pattern 1: 11024c8fbca5SSam Ravnborg * If a module parameter is declared __initdata and permissions=0 11034c8fbca5SSam Ravnborg * then this is legal despite the warning generated. 11044c8fbca5SSam Ravnborg * We cannot see value of permissions here, so just ignore 11054c8fbca5SSam Ravnborg * this pattern. 11064c8fbca5SSam Ravnborg * The pattern is identified by: 11074c8fbca5SSam Ravnborg * tosec = .init.data 11089209aed0SSam Ravnborg * fromsec = .data* 11094c8fbca5SSam Ravnborg * atsym =__param* 11104c8fbca5SSam Ravnborg * 11116a841528SRusty Russell * Pattern 1a: 11126a841528SRusty Russell * module_param_call() ops can refer to __init set function if permissions=0 11136a841528SRusty Russell * The pattern is identified by: 11146a841528SRusty Russell * tosec = .init.text 11156a841528SRusty Russell * fromsec = .data* 11166a841528SRusty Russell * atsym = __param_ops_* 11176a841528SRusty Russell * 11184c8fbca5SSam Ravnborg * Pattern 2: 111972ee59b5SRandy Dunlap * Many drivers utilise a *driver container with references to 11204c8fbca5SSam Ravnborg * add, remove, probe functions etc. 11214c8fbca5SSam Ravnborg * the pattern is identified by: 112283cda2bbSSam Ravnborg * tosec = init or exit section 112383cda2bbSSam Ravnborg * fromsec = data section 1124df578e7dSSam Ravnborg * atsym = *driver, *_template, *_sht, *_ops, *_probe, 1125df578e7dSSam Ravnborg * *probe_one, *_console, *_timer 1126ee6a8545SVivek Goyal * 1127ee6a8545SVivek Goyal * Pattern 3: 1128c993971fSSam Ravnborg * Whitelist all references from .head.text to any init section 11299bf8cb9bSSam Ravnborg * 11301d8af559SSam Ravnborg * Pattern 4: 1131ee6a8545SVivek Goyal * Some symbols belong to init section but still it is ok to reference 1132ee6a8545SVivek Goyal * these from non-init sections as these symbols don't have any memory 1133ee6a8545SVivek Goyal * allocated for them and symbol address and value are same. So even 1134ee6a8545SVivek Goyal * if init section is freed, its ok to reference those symbols. 1135ee6a8545SVivek Goyal * For ex. symbols marking the init section boundaries. 1136ee6a8545SVivek Goyal * This pattern is identified by 1137ee6a8545SVivek Goyal * refsymname = __init_begin, _sinittext, _einittext 11389bf8cb9bSSam Ravnborg * 11394c8fbca5SSam Ravnborg **/ 1140af92a82dSUwe Kleine-König static int secref_whitelist(const struct sectioncheck *mismatch, 1141af92a82dSUwe Kleine-König const char *fromsec, const char *fromsym, 114258fb0d4fSSam Ravnborg const char *tosec, const char *tosym) 11434c8fbca5SSam Ravnborg { 11444c8fbca5SSam Ravnborg /* Check for pattern 1 */ 11456c5bd235SSam Ravnborg if (match(tosec, init_data_sections) && 11466c5bd235SSam Ravnborg match(fromsec, data_sections) && 114758fb0d4fSSam Ravnborg (strncmp(fromsym, "__param", strlen("__param")) == 0)) 114858fb0d4fSSam Ravnborg return 0; 11494c8fbca5SSam Ravnborg 11506a841528SRusty Russell /* Check for pattern 1a */ 11516a841528SRusty Russell if (strcmp(tosec, ".init.text") == 0 && 11526a841528SRusty Russell match(fromsec, data_sections) && 11536a841528SRusty Russell (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0)) 11546a841528SRusty Russell return 0; 11556a841528SRusty Russell 11564c8fbca5SSam Ravnborg /* Check for pattern 2 */ 11576c5bd235SSam Ravnborg if (match(tosec, init_exit_sections) && 11586c5bd235SSam Ravnborg match(fromsec, data_sections) && 1159af92a82dSUwe Kleine-König match(fromsym, mismatch->symbol_white_list)) 116058fb0d4fSSam Ravnborg return 0; 11614c8fbca5SSam Ravnborg 11629bf8cb9bSSam Ravnborg /* Check for pattern 3 */ 11636c5bd235SSam Ravnborg if (match(fromsec, head_sections) && 11646c5bd235SSam Ravnborg match(tosec, init_sections)) 116558fb0d4fSSam Ravnborg return 0; 1166f8657e1bSVivek Goyal 11671d8af559SSam Ravnborg /* Check for pattern 4 */ 116858fb0d4fSSam Ravnborg if (match(tosym, linker_symbols)) 116993659af1SSam Ravnborg return 0; 117058fb0d4fSSam Ravnborg 117158fb0d4fSSam Ravnborg return 1; 11724c8fbca5SSam Ravnborg } 11734c8fbca5SSam Ravnborg 11744c8fbca5SSam Ravnborg /** 117593684d3bSSam Ravnborg * Find symbol based on relocation record info. 117693684d3bSSam Ravnborg * In some cases the symbol supplied is a valid symbol so 117793684d3bSSam Ravnborg * return refsym. If st_name != 0 we assume this is a valid symbol. 117893684d3bSSam Ravnborg * In other cases the symbol needs to be looked up in the symbol table 117993684d3bSSam Ravnborg * based on section and address. 118093684d3bSSam Ravnborg * **/ 11819ad21c3fSSam Ravnborg static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, 118293684d3bSSam Ravnborg Elf_Sym *relsym) 118393684d3bSSam Ravnborg { 118493684d3bSSam Ravnborg Elf_Sym *sym; 11859ad21c3fSSam Ravnborg Elf_Sym *near = NULL; 11869ad21c3fSSam Ravnborg Elf64_Sword distance = 20; 11879ad21c3fSSam Ravnborg Elf64_Sword d; 11881ce53adfSDenys Vlasenko unsigned int relsym_secindex; 118993684d3bSSam Ravnborg 119093684d3bSSam Ravnborg if (relsym->st_name != 0) 119193684d3bSSam Ravnborg return relsym; 11921ce53adfSDenys Vlasenko 11931ce53adfSDenys Vlasenko relsym_secindex = get_secindex(elf, relsym); 119493684d3bSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 11951ce53adfSDenys Vlasenko if (get_secindex(elf, sym) != relsym_secindex) 119693684d3bSSam Ravnborg continue; 1197ae4ac123SAtsushi Nemoto if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) 1198ae4ac123SAtsushi Nemoto continue; 119993684d3bSSam Ravnborg if (sym->st_value == addr) 120093684d3bSSam Ravnborg return sym; 12019ad21c3fSSam Ravnborg /* Find a symbol nearby - addr are maybe negative */ 12029ad21c3fSSam Ravnborg d = sym->st_value - addr; 12039ad21c3fSSam Ravnborg if (d < 0) 12049ad21c3fSSam Ravnborg d = addr - sym->st_value; 12059ad21c3fSSam Ravnborg if (d < distance) { 12069ad21c3fSSam Ravnborg distance = d; 12079ad21c3fSSam Ravnborg near = sym; 120893684d3bSSam Ravnborg } 12099ad21c3fSSam Ravnborg } 12109ad21c3fSSam Ravnborg /* We need a close match */ 12119ad21c3fSSam Ravnborg if (distance < 20) 12129ad21c3fSSam Ravnborg return near; 12139ad21c3fSSam Ravnborg else 121493684d3bSSam Ravnborg return NULL; 121593684d3bSSam Ravnborg } 121693684d3bSSam Ravnborg 1217da68d61fSDavid Brownell static inline int is_arm_mapping_symbol(const char *str) 1218da68d61fSDavid Brownell { 12196c34f1f5SKyle McMartin return str[0] == '$' && strchr("axtd", str[1]) 1220da68d61fSDavid Brownell && (str[2] == '\0' || str[2] == '.'); 1221da68d61fSDavid Brownell } 1222da68d61fSDavid Brownell 1223da68d61fSDavid Brownell /* 1224da68d61fSDavid Brownell * If there's no name there, ignore it; likewise, ignore it if it's 1225da68d61fSDavid Brownell * one of the magic symbols emitted used by current ARM tools. 1226da68d61fSDavid Brownell * 1227da68d61fSDavid Brownell * Otherwise if find_symbols_between() returns those symbols, they'll 1228da68d61fSDavid Brownell * fail the whitelist tests and cause lots of false alarms ... fixable 1229da68d61fSDavid Brownell * only by merging __exit and __init sections into __text, bloating 1230da68d61fSDavid Brownell * the kernel (which is especially evil on embedded platforms). 1231da68d61fSDavid Brownell */ 1232da68d61fSDavid Brownell static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym) 1233da68d61fSDavid Brownell { 1234da68d61fSDavid Brownell const char *name = elf->strtab + sym->st_name; 1235da68d61fSDavid Brownell 1236da68d61fSDavid Brownell if (!name || !strlen(name)) 1237da68d61fSDavid Brownell return 0; 1238da68d61fSDavid Brownell return !is_arm_mapping_symbol(name); 1239da68d61fSDavid Brownell } 1240da68d61fSDavid Brownell 1241b39927cfSSam Ravnborg /* 124243c74d17SSam Ravnborg * Find symbols before or equal addr and after addr - in the section sec. 124343c74d17SSam Ravnborg * If we find two symbols with equal offset prefer one with a valid name. 124443c74d17SSam Ravnborg * The ELF format may have a better way to detect what type of symbol 124543c74d17SSam Ravnborg * it is, but this works for now. 1246b39927cfSSam Ravnborg **/ 1247157c23c8SSam Ravnborg static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, 1248157c23c8SSam Ravnborg const char *sec) 1249b39927cfSSam Ravnborg { 1250b39927cfSSam Ravnborg Elf_Sym *sym; 1251157c23c8SSam Ravnborg Elf_Sym *near = NULL; 1252157c23c8SSam Ravnborg Elf_Addr distance = ~0; 1253b39927cfSSam Ravnborg 1254b39927cfSSam Ravnborg for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 1255b39927cfSSam Ravnborg const char *symsec; 1256b39927cfSSam Ravnborg 12571ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1258b39927cfSSam Ravnborg continue; 12591ce53adfSDenys Vlasenko symsec = sec_name(elf, get_secindex(elf, sym)); 1260b39927cfSSam Ravnborg if (strcmp(symsec, sec) != 0) 1261b39927cfSSam Ravnborg continue; 1262da68d61fSDavid Brownell if (!is_valid_name(elf, sym)) 1263da68d61fSDavid Brownell continue; 1264b39927cfSSam Ravnborg if (sym->st_value <= addr) { 1265157c23c8SSam Ravnborg if ((addr - sym->st_value) < distance) { 1266157c23c8SSam Ravnborg distance = addr - sym->st_value; 1267157c23c8SSam Ravnborg near = sym; 1268157c23c8SSam Ravnborg } else if ((addr - sym->st_value) == distance) { 1269157c23c8SSam Ravnborg near = sym; 127043c74d17SSam Ravnborg } 1271b39927cfSSam Ravnborg } 1272b39927cfSSam Ravnborg } 1273157c23c8SSam Ravnborg return near; 1274157c23c8SSam Ravnborg } 1275b39927cfSSam Ravnborg 127658fb0d4fSSam Ravnborg /* 1277588ccd73SSam Ravnborg * Convert a section name to the function/data attribute 1278588ccd73SSam Ravnborg * .init.text => __init 1279588ccd73SSam Ravnborg * .memexitconst => __memconst 1280588ccd73SSam Ravnborg * etc. 1281cbcf14a9SAndy Shevchenko * 1282cbcf14a9SAndy Shevchenko * The memory of returned value has been allocated on a heap. The user of this 1283cbcf14a9SAndy Shevchenko * method should free it after usage. 1284588ccd73SSam Ravnborg */ 1285588ccd73SSam Ravnborg static char *sec2annotation(const char *s) 1286588ccd73SSam Ravnborg { 1287588ccd73SSam Ravnborg if (match(s, init_exit_sections)) { 1288588ccd73SSam Ravnborg char *p = malloc(20); 1289588ccd73SSam Ravnborg char *r = p; 1290588ccd73SSam Ravnborg 1291588ccd73SSam Ravnborg *p++ = '_'; 1292588ccd73SSam Ravnborg *p++ = '_'; 1293588ccd73SSam Ravnborg if (*s == '.') 1294588ccd73SSam Ravnborg s++; 1295588ccd73SSam Ravnborg while (*s && *s != '.') 1296588ccd73SSam Ravnborg *p++ = *s++; 1297588ccd73SSam Ravnborg *p = '\0'; 1298588ccd73SSam Ravnborg if (*s == '.') 1299588ccd73SSam Ravnborg s++; 1300588ccd73SSam Ravnborg if (strstr(s, "rodata") != NULL) 1301588ccd73SSam Ravnborg strcat(p, "const "); 1302588ccd73SSam Ravnborg else if (strstr(s, "data") != NULL) 1303588ccd73SSam Ravnborg strcat(p, "data "); 1304588ccd73SSam Ravnborg else 1305588ccd73SSam Ravnborg strcat(p, " "); 1306cbcf14a9SAndy Shevchenko return r; 1307588ccd73SSam Ravnborg } else { 13085003bab8SAndrew Morton return strdup(""); 1309588ccd73SSam Ravnborg } 1310588ccd73SSam Ravnborg } 1311588ccd73SSam Ravnborg 1312588ccd73SSam Ravnborg static int is_function(Elf_Sym *sym) 1313588ccd73SSam Ravnborg { 1314588ccd73SSam Ravnborg if (sym) 1315588ccd73SSam Ravnborg return ELF_ST_TYPE(sym->st_info) == STT_FUNC; 1316588ccd73SSam Ravnborg else 1317f666751aSSam Ravnborg return -1; 1318588ccd73SSam Ravnborg } 1319588ccd73SSam Ravnborg 132000759c0eSRandy Dunlap static void print_section_list(const char * const list[20]) 132100759c0eSRandy Dunlap { 132200759c0eSRandy Dunlap const char *const *s = list; 132300759c0eSRandy Dunlap 132400759c0eSRandy Dunlap while (*s) { 132500759c0eSRandy Dunlap fprintf(stderr, "%s", *s); 132600759c0eSRandy Dunlap s++; 132700759c0eSRandy Dunlap if (*s) 132800759c0eSRandy Dunlap fprintf(stderr, ", "); 132900759c0eSRandy Dunlap } 133000759c0eSRandy Dunlap fprintf(stderr, "\n"); 133100759c0eSRandy Dunlap } 133200759c0eSRandy Dunlap 1333356ad538SQuentin Casasnovas static inline void get_pretty_name(int is_func, const char** name, const char** name_p) 1334356ad538SQuentin Casasnovas { 1335356ad538SQuentin Casasnovas switch (is_func) { 1336356ad538SQuentin Casasnovas case 0: *name = "variable"; *name_p = ""; break; 1337356ad538SQuentin Casasnovas case 1: *name = "function"; *name_p = "()"; break; 1338356ad538SQuentin Casasnovas default: *name = "(unknown reference)"; *name_p = ""; break; 1339356ad538SQuentin Casasnovas } 1340356ad538SQuentin Casasnovas } 1341356ad538SQuentin Casasnovas 1342588ccd73SSam Ravnborg /* 1343b39927cfSSam Ravnborg * Print a warning about a section mismatch. 1344b39927cfSSam Ravnborg * Try to find symbols near it so user can find it. 13454c8fbca5SSam Ravnborg * Check whitelist before warning - it may be a false positive. 134658fb0d4fSSam Ravnborg */ 13470d2a636eSUwe Kleine-König static void report_sec_mismatch(const char *modname, 13480d2a636eSUwe Kleine-König const struct sectioncheck *mismatch, 134958fb0d4fSSam Ravnborg const char *fromsec, 135058fb0d4fSSam Ravnborg unsigned long long fromaddr, 135158fb0d4fSSam Ravnborg const char *fromsym, 1352588ccd73SSam Ravnborg int from_is_func, 1353588ccd73SSam Ravnborg const char *tosec, const char *tosym, 1354588ccd73SSam Ravnborg int to_is_func) 1355b39927cfSSam Ravnborg { 1356588ccd73SSam Ravnborg const char *from, *from_p; 1357588ccd73SSam Ravnborg const char *to, *to_p; 135837ed19d5SAlexey Fomenko char *prl_from; 135937ed19d5SAlexey Fomenko char *prl_to; 1360f666751aSSam Ravnborg 1361e5f95c8bSSam Ravnborg sec_mismatch_count++; 1362e5f95c8bSSam Ravnborg if (!sec_mismatch_verbose) 1363e5f95c8bSSam Ravnborg return; 1364e5f95c8bSSam Ravnborg 1365356ad538SQuentin Casasnovas get_pretty_name(from_is_func, &from, &from_p); 1366356ad538SQuentin Casasnovas get_pretty_name(to_is_func, &to, &to_p); 1367356ad538SQuentin Casasnovas 13687c0ac495SGeert Uytterhoeven warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " 13697c0ac495SGeert Uytterhoeven "to the %s %s:%s%s\n", 13707c0ac495SGeert Uytterhoeven modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, 13717c0ac495SGeert Uytterhoeven tosym, to_p); 1372588ccd73SSam Ravnborg 13730d2a636eSUwe Kleine-König switch (mismatch->mismatch) { 1374bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_INIT: 137537ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 137637ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1377588ccd73SSam Ravnborg fprintf(stderr, 1378588ccd73SSam Ravnborg "The function %s%s() references\n" 1379588ccd73SSam Ravnborg "the %s %s%s%s.\n" 1380588ccd73SSam Ravnborg "This is often because %s lacks a %s\n" 1381588ccd73SSam Ravnborg "annotation or the annotation of %s is wrong.\n", 138237ed19d5SAlexey Fomenko prl_from, fromsym, 138337ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 138437ed19d5SAlexey Fomenko fromsym, prl_to, tosym); 138537ed19d5SAlexey Fomenko free(prl_from); 138637ed19d5SAlexey Fomenko free(prl_to); 1387588ccd73SSam Ravnborg break; 1388bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_INIT: { 138937ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1390588ccd73SSam Ravnborg fprintf(stderr, 1391588ccd73SSam Ravnborg "The variable %s references\n" 1392588ccd73SSam Ravnborg "the %s %s%s%s\n" 1393588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 13948b8b76c0SSam Ravnborg "variable with __init* or __refdata (see linux/init.h) " 1395588ccd73SSam Ravnborg "or name the variable:\n", 139637ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 139700759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 139837ed19d5SAlexey Fomenko free(prl_to); 1399588ccd73SSam Ravnborg break; 140058fb0d4fSSam Ravnborg } 1401bbd3f4fbSUwe Kleine-König case TEXT_TO_ANY_EXIT: 140237ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1403588ccd73SSam Ravnborg fprintf(stderr, 1404588ccd73SSam Ravnborg "The function %s() references a %s in an exit section.\n" 1405588ccd73SSam Ravnborg "Often the %s %s%s has valid usage outside the exit section\n" 1406588ccd73SSam Ravnborg "and the fix is to remove the %sannotation of %s.\n", 140737ed19d5SAlexey Fomenko fromsym, to, to, tosym, to_p, prl_to, tosym); 140837ed19d5SAlexey Fomenko free(prl_to); 1409588ccd73SSam Ravnborg break; 1410bbd3f4fbSUwe Kleine-König case DATA_TO_ANY_EXIT: { 141137ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1412588ccd73SSam Ravnborg fprintf(stderr, 1413588ccd73SSam Ravnborg "The variable %s references\n" 1414588ccd73SSam Ravnborg "the %s %s%s%s\n" 1415588ccd73SSam Ravnborg "If the reference is valid then annotate the\n" 1416588ccd73SSam Ravnborg "variable with __exit* (see linux/init.h) or " 1417588ccd73SSam Ravnborg "name the variable:\n", 141837ed19d5SAlexey Fomenko fromsym, to, prl_to, tosym, to_p); 141900759c0eSRandy Dunlap print_section_list(mismatch->symbol_white_list); 142037ed19d5SAlexey Fomenko free(prl_to); 1421588ccd73SSam Ravnborg break; 1422588ccd73SSam Ravnborg } 1423bbd3f4fbSUwe Kleine-König case XXXINIT_TO_SOME_INIT: 1424bbd3f4fbSUwe Kleine-König case XXXEXIT_TO_SOME_EXIT: 142537ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 142637ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1427588ccd73SSam Ravnborg fprintf(stderr, 1428588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1429588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1430588ccd73SSam Ravnborg "If %s is only used by %s then\n" 1431588ccd73SSam Ravnborg "annotate %s with a matching annotation.\n", 143237ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 143337ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 1434b1d2675aSGeert Uytterhoeven tosym, fromsym, tosym); 143537ed19d5SAlexey Fomenko free(prl_from); 143637ed19d5SAlexey Fomenko free(prl_to); 1437588ccd73SSam Ravnborg break; 1438bbd3f4fbSUwe Kleine-König case ANY_INIT_TO_ANY_EXIT: 143937ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 144037ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1441588ccd73SSam Ravnborg fprintf(stderr, 1442588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1443588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1444588ccd73SSam Ravnborg "This is often seen when error handling " 1445588ccd73SSam Ravnborg "in the init function\n" 1446588ccd73SSam Ravnborg "uses functionality in the exit path.\n" 1447588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1448588ccd73SSam Ravnborg "%s%s so it may be used outside an exit section.\n", 144937ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 145037ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 14515003bab8SAndrew Morton prl_to, tosym, to_p); 145237ed19d5SAlexey Fomenko free(prl_from); 145337ed19d5SAlexey Fomenko free(prl_to); 1454588ccd73SSam Ravnborg break; 1455bbd3f4fbSUwe Kleine-König case ANY_EXIT_TO_ANY_INIT: 145637ed19d5SAlexey Fomenko prl_from = sec2annotation(fromsec); 145737ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1458588ccd73SSam Ravnborg fprintf(stderr, 1459588ccd73SSam Ravnborg "The %s %s%s%s references\n" 1460588ccd73SSam Ravnborg "a %s %s%s%s.\n" 1461588ccd73SSam Ravnborg "This is often seen when error handling " 1462588ccd73SSam Ravnborg "in the exit function\n" 1463588ccd73SSam Ravnborg "uses functionality in the init path.\n" 1464588ccd73SSam Ravnborg "The fix is often to remove the %sannotation of\n" 1465588ccd73SSam Ravnborg "%s%s so it may be used outside an init section.\n", 146637ed19d5SAlexey Fomenko from, prl_from, fromsym, from_p, 146737ed19d5SAlexey Fomenko to, prl_to, tosym, to_p, 146837ed19d5SAlexey Fomenko prl_to, tosym, to_p); 146937ed19d5SAlexey Fomenko free(prl_from); 147037ed19d5SAlexey Fomenko free(prl_to); 1471588ccd73SSam Ravnborg break; 1472588ccd73SSam Ravnborg case EXPORT_TO_INIT_EXIT: 147337ed19d5SAlexey Fomenko prl_to = sec2annotation(tosec); 1474588ccd73SSam Ravnborg fprintf(stderr, 1475588ccd73SSam Ravnborg "The symbol %s is exported and annotated %s\n" 1476588ccd73SSam Ravnborg "Fix this by removing the %sannotation of %s " 1477588ccd73SSam Ravnborg "or drop the export.\n", 147837ed19d5SAlexey Fomenko tosym, prl_to, prl_to, tosym); 147937ed19d5SAlexey Fomenko free(prl_to); 1480588ccd73SSam Ravnborg break; 148152dc0595SQuentin Casasnovas case EXTABLE_TO_NON_TEXT: 148252dc0595SQuentin Casasnovas fatal("There's a special handler for this mismatch type, " 148352dc0595SQuentin Casasnovas "we should never get here."); 148452dc0595SQuentin Casasnovas break; 1485588ccd73SSam Ravnborg } 1486588ccd73SSam Ravnborg fprintf(stderr, "\n"); 148758fb0d4fSSam Ravnborg } 148858fb0d4fSSam Ravnborg 1489644e8f14SQuentin Casasnovas static void default_mismatch_handler(const char *modname, struct elf_info *elf, 1490644e8f14SQuentin Casasnovas const struct sectioncheck* const mismatch, 149158fb0d4fSSam Ravnborg Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 149258fb0d4fSSam Ravnborg { 149358fb0d4fSSam Ravnborg const char *tosec; 1494588ccd73SSam Ravnborg Elf_Sym *to; 1495588ccd73SSam Ravnborg Elf_Sym *from; 149658fb0d4fSSam Ravnborg const char *tosym; 1497588ccd73SSam Ravnborg const char *fromsym; 149858fb0d4fSSam Ravnborg 1499588ccd73SSam Ravnborg from = find_elf_symbol2(elf, r->r_offset, fromsec); 1500588ccd73SSam Ravnborg fromsym = sym_name(elf, from); 150158fb0d4fSSam Ravnborg 150277ab21adSAndi Kleen if (!strncmp(fromsym, "reference___initcall", 150377ab21adSAndi Kleen sizeof("reference___initcall")-1)) 150477ab21adSAndi Kleen return; 150577ab21adSAndi Kleen 1506c7a65e06SQuentin Casasnovas tosec = sec_name(elf, get_secindex(elf, sym)); 1507c7a65e06SQuentin Casasnovas to = find_elf_symbol(elf, r->r_addend, sym); 1508c7a65e06SQuentin Casasnovas tosym = sym_name(elf, to); 1509c7a65e06SQuentin Casasnovas 151058fb0d4fSSam Ravnborg /* check whitelist - we may ignore it */ 1511af92a82dSUwe Kleine-König if (secref_whitelist(mismatch, 1512af92a82dSUwe Kleine-König fromsec, fromsym, tosec, tosym)) { 1513588ccd73SSam Ravnborg report_sec_mismatch(modname, mismatch, 1514588ccd73SSam Ravnborg fromsec, r->r_offset, fromsym, 1515588ccd73SSam Ravnborg is_function(from), tosec, tosym, 1516588ccd73SSam Ravnborg is_function(to)); 151758fb0d4fSSam Ravnborg } 1518b39927cfSSam Ravnborg } 1519644e8f14SQuentin Casasnovas 152052dc0595SQuentin Casasnovas static int is_executable_section(struct elf_info* elf, unsigned int section_index) 152152dc0595SQuentin Casasnovas { 152252dc0595SQuentin Casasnovas if (section_index > elf->num_sections) 152352dc0595SQuentin Casasnovas fatal("section_index is outside elf->num_sections!\n"); 152452dc0595SQuentin Casasnovas 152552dc0595SQuentin Casasnovas return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); 152652dc0595SQuentin Casasnovas } 152752dc0595SQuentin Casasnovas 152852dc0595SQuentin Casasnovas /* 152952dc0595SQuentin Casasnovas * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size() 153052dc0595SQuentin Casasnovas * to know the sizeof(struct exception_table_entry) for the target architecture. 153152dc0595SQuentin Casasnovas */ 153252dc0595SQuentin Casasnovas static unsigned int extable_entry_size = 0; 1533e84048aaSQuentin Casasnovas static void find_extable_entry_size(const char* const sec, const Elf_Rela* r) 153452dc0595SQuentin Casasnovas { 153552dc0595SQuentin Casasnovas /* 153652dc0595SQuentin Casasnovas * If we're currently checking the second relocation within __ex_table, 153752dc0595SQuentin Casasnovas * that relocation offset tells us the offsetof(struct 153852dc0595SQuentin Casasnovas * exception_table_entry, fixup) which is equal to sizeof(struct 153952dc0595SQuentin Casasnovas * exception_table_entry) divided by two. We use that to our advantage 154052dc0595SQuentin Casasnovas * since there's no portable way to get that size as every architecture 154152dc0595SQuentin Casasnovas * seems to go with different sized types. Not pretty but better than 154252dc0595SQuentin Casasnovas * hard-coding the size for every architecture.. 154352dc0595SQuentin Casasnovas */ 1544e84048aaSQuentin Casasnovas if (!extable_entry_size) 154552dc0595SQuentin Casasnovas extable_entry_size = r->r_offset * 2; 154652dc0595SQuentin Casasnovas } 1547e84048aaSQuentin Casasnovas 154852dc0595SQuentin Casasnovas static inline bool is_extable_fault_address(Elf_Rela *r) 154952dc0595SQuentin Casasnovas { 1550d3df4de7SQuentin Casasnovas /* 1551d3df4de7SQuentin Casasnovas * extable_entry_size is only discovered after we've handled the 1552d3df4de7SQuentin Casasnovas * _second_ relocation in __ex_table, so only abort when we're not 1553d3df4de7SQuentin Casasnovas * handling the first reloc and extable_entry_size is zero. 1554d3df4de7SQuentin Casasnovas */ 1555d3df4de7SQuentin Casasnovas if (r->r_offset && extable_entry_size == 0) 155652dc0595SQuentin Casasnovas fatal("extable_entry size hasn't been discovered!\n"); 155752dc0595SQuentin Casasnovas 155852dc0595SQuentin Casasnovas return ((r->r_offset == 0) || 155952dc0595SQuentin Casasnovas (r->r_offset % extable_entry_size == 0)); 156052dc0595SQuentin Casasnovas } 156152dc0595SQuentin Casasnovas 1562e84048aaSQuentin Casasnovas #define is_second_extable_reloc(Start, Cur, Sec) \ 1563e84048aaSQuentin Casasnovas (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0)) 1564e84048aaSQuentin Casasnovas 156552dc0595SQuentin Casasnovas static void report_extable_warnings(const char* modname, struct elf_info* elf, 156652dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 156752dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 156852dc0595SQuentin Casasnovas const char* fromsec, const char* tosec) 156952dc0595SQuentin Casasnovas { 157052dc0595SQuentin Casasnovas Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec); 157152dc0595SQuentin Casasnovas const char* fromsym_name = sym_name(elf, fromsym); 157252dc0595SQuentin Casasnovas Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym); 157352dc0595SQuentin Casasnovas const char* tosym_name = sym_name(elf, tosym); 157452dc0595SQuentin Casasnovas const char* from_pretty_name; 157552dc0595SQuentin Casasnovas const char* from_pretty_name_p; 157652dc0595SQuentin Casasnovas const char* to_pretty_name; 157752dc0595SQuentin Casasnovas const char* to_pretty_name_p; 157852dc0595SQuentin Casasnovas 157952dc0595SQuentin Casasnovas get_pretty_name(is_function(fromsym), 158052dc0595SQuentin Casasnovas &from_pretty_name, &from_pretty_name_p); 158152dc0595SQuentin Casasnovas get_pretty_name(is_function(tosym), 158252dc0595SQuentin Casasnovas &to_pretty_name, &to_pretty_name_p); 158352dc0595SQuentin Casasnovas 158452dc0595SQuentin Casasnovas warn("%s(%s+0x%lx): Section mismatch in reference" 158552dc0595SQuentin Casasnovas " from the %s %s%s to the %s %s:%s%s\n", 158652dc0595SQuentin Casasnovas modname, fromsec, (long)r->r_offset, from_pretty_name, 158752dc0595SQuentin Casasnovas fromsym_name, from_pretty_name_p, 158852dc0595SQuentin Casasnovas to_pretty_name, tosec, tosym_name, to_pretty_name_p); 158952dc0595SQuentin Casasnovas 159052dc0595SQuentin Casasnovas if (!match(tosec, mismatch->bad_tosec) && 159152dc0595SQuentin Casasnovas is_executable_section(elf, get_secindex(elf, sym))) 159252dc0595SQuentin Casasnovas fprintf(stderr, 159352dc0595SQuentin Casasnovas "The relocation at %s+0x%lx references\n" 159452dc0595SQuentin Casasnovas "section \"%s\" which is not in the list of\n" 159552dc0595SQuentin Casasnovas "authorized sections. If you're adding a new section\n" 159652dc0595SQuentin Casasnovas "and/or if this reference is valid, add \"%s\" to the\n" 159752dc0595SQuentin Casasnovas "list of authorized sections to jump to on fault.\n" 159852dc0595SQuentin Casasnovas "This can be achieved by adding \"%s\" to \n" 159952dc0595SQuentin Casasnovas "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n", 160052dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, tosec, tosec); 160152dc0595SQuentin Casasnovas } 160252dc0595SQuentin Casasnovas 160352dc0595SQuentin Casasnovas static void extable_mismatch_handler(const char* modname, struct elf_info *elf, 160452dc0595SQuentin Casasnovas const struct sectioncheck* const mismatch, 160552dc0595SQuentin Casasnovas Elf_Rela* r, Elf_Sym* sym, 160652dc0595SQuentin Casasnovas const char *fromsec) 160752dc0595SQuentin Casasnovas { 160852dc0595SQuentin Casasnovas const char* tosec = sec_name(elf, get_secindex(elf, sym)); 160952dc0595SQuentin Casasnovas 161052dc0595SQuentin Casasnovas sec_mismatch_count++; 161152dc0595SQuentin Casasnovas 161252dc0595SQuentin Casasnovas if (sec_mismatch_verbose) 161352dc0595SQuentin Casasnovas report_extable_warnings(modname, elf, mismatch, r, sym, 161452dc0595SQuentin Casasnovas fromsec, tosec); 161552dc0595SQuentin Casasnovas 161652dc0595SQuentin Casasnovas if (match(tosec, mismatch->bad_tosec)) 161752dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 161852dc0595SQuentin Casasnovas "section \"%s\" which is black-listed.\n" 161952dc0595SQuentin Casasnovas "Something is seriously wrong and should be fixed.\n" 162052dc0595SQuentin Casasnovas "You might get more information about where this is\n" 162152dc0595SQuentin Casasnovas "coming from by using scripts/check_extable.sh %s\n", 162252dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec, modname); 162352dc0595SQuentin Casasnovas else if (!is_executable_section(elf, get_secindex(elf, sym))) { 162452dc0595SQuentin Casasnovas if (is_extable_fault_address(r)) 162552dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 162652dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 162752dc0595SQuentin Casasnovas "it is not possible for the kernel to fault\n" 162852dc0595SQuentin Casasnovas "at that address. Something is seriously wrong\n" 162952dc0595SQuentin Casasnovas "and should be fixed.\n", 163052dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 163152dc0595SQuentin Casasnovas else 163252dc0595SQuentin Casasnovas fatal("The relocation at %s+0x%lx references\n" 163352dc0595SQuentin Casasnovas "section \"%s\" which is not executable, IOW\n" 163452dc0595SQuentin Casasnovas "the kernel will fault if it ever tries to\n" 163552dc0595SQuentin Casasnovas "jump to it. Something is seriously wrong\n" 163652dc0595SQuentin Casasnovas "and should be fixed.\n", 163752dc0595SQuentin Casasnovas fromsec, (long)r->r_offset, tosec); 163852dc0595SQuentin Casasnovas } 163952dc0595SQuentin Casasnovas } 164052dc0595SQuentin Casasnovas 1641644e8f14SQuentin Casasnovas static void check_section_mismatch(const char *modname, struct elf_info *elf, 1642644e8f14SQuentin Casasnovas Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 1643644e8f14SQuentin Casasnovas { 1644644e8f14SQuentin Casasnovas const char *tosec = sec_name(elf, get_secindex(elf, sym));; 1645644e8f14SQuentin Casasnovas const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec); 1646644e8f14SQuentin Casasnovas 1647644e8f14SQuentin Casasnovas if (mismatch) { 1648644e8f14SQuentin Casasnovas if (mismatch->handler) 1649644e8f14SQuentin Casasnovas mismatch->handler(modname, elf, mismatch, 1650644e8f14SQuentin Casasnovas r, sym, fromsec); 1651644e8f14SQuentin Casasnovas else 1652644e8f14SQuentin Casasnovas default_mismatch_handler(modname, elf, mismatch, 1653644e8f14SQuentin Casasnovas r, sym, fromsec); 1654644e8f14SQuentin Casasnovas } 1655b39927cfSSam Ravnborg } 1656b39927cfSSam Ravnborg 1657ae4ac123SAtsushi Nemoto static unsigned int *reloc_location(struct elf_info *elf, 16585b24c071SSam Ravnborg Elf_Shdr *sechdr, Elf_Rela *r) 1659ae4ac123SAtsushi Nemoto { 1660ae4ac123SAtsushi Nemoto Elf_Shdr *sechdrs = elf->sechdrs; 16616845756bSAnders Kaseorg int section = sechdr->sh_info; 1662ae4ac123SAtsushi Nemoto 1663ae4ac123SAtsushi Nemoto return (void *)elf->hdr + sechdrs[section].sh_offset + 1664731ece41SOlof Johansson r->r_offset; 1665ae4ac123SAtsushi Nemoto } 1666ae4ac123SAtsushi Nemoto 16675b24c071SSam Ravnborg static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1668ae4ac123SAtsushi Nemoto { 1669ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 16705b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1671ae4ac123SAtsushi Nemoto 1672ae4ac123SAtsushi Nemoto switch (r_typ) { 1673ae4ac123SAtsushi Nemoto case R_386_32: 1674ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location); 1675ae4ac123SAtsushi Nemoto break; 1676ae4ac123SAtsushi Nemoto case R_386_PC32: 1677ae4ac123SAtsushi Nemoto r->r_addend = TO_NATIVE(*location) + 4; 1678ae4ac123SAtsushi Nemoto /* For CONFIG_RELOCATABLE=y */ 1679ae4ac123SAtsushi Nemoto if (elf->hdr->e_type == ET_EXEC) 1680ae4ac123SAtsushi Nemoto r->r_addend += r->r_offset; 1681ae4ac123SAtsushi Nemoto break; 1682ae4ac123SAtsushi Nemoto } 1683ae4ac123SAtsushi Nemoto return 0; 1684ae4ac123SAtsushi Nemoto } 1685ae4ac123SAtsushi Nemoto 16866e2e340bSTony Lindgren #ifndef R_ARM_CALL 16876e2e340bSTony Lindgren #define R_ARM_CALL 28 16886e2e340bSTony Lindgren #endif 16896e2e340bSTony Lindgren #ifndef R_ARM_JUMP24 16906e2e340bSTony Lindgren #define R_ARM_JUMP24 29 16916e2e340bSTony Lindgren #endif 16926e2e340bSTony Lindgren 1693c9698e5cSDavid A. Long #ifndef R_ARM_THM_CALL 1694c9698e5cSDavid A. Long #define R_ARM_THM_CALL 10 1695c9698e5cSDavid A. Long #endif 1696c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP24 1697c9698e5cSDavid A. Long #define R_ARM_THM_JUMP24 30 1698c9698e5cSDavid A. Long #endif 1699c9698e5cSDavid A. Long #ifndef R_ARM_THM_JUMP19 1700c9698e5cSDavid A. Long #define R_ARM_THM_JUMP19 51 1701c9698e5cSDavid A. Long #endif 1702c9698e5cSDavid A. Long 17035b24c071SSam Ravnborg static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 170456a974faSSam Ravnborg { 170556a974faSSam Ravnborg unsigned int r_typ = ELF_R_TYPE(r->r_info); 170656a974faSSam Ravnborg 170756a974faSSam Ravnborg switch (r_typ) { 170856a974faSSam Ravnborg case R_ARM_ABS32: 170956a974faSSam Ravnborg /* From ARM ABI: (S + A) | T */ 1710df578e7dSSam Ravnborg r->r_addend = (int)(long) 1711df578e7dSSam Ravnborg (elf->symtab_start + ELF_R_SYM(r->r_info)); 171256a974faSSam Ravnborg break; 171356a974faSSam Ravnborg case R_ARM_PC24: 17146e2e340bSTony Lindgren case R_ARM_CALL: 17156e2e340bSTony Lindgren case R_ARM_JUMP24: 1716c9698e5cSDavid A. Long case R_ARM_THM_CALL: 1717c9698e5cSDavid A. Long case R_ARM_THM_JUMP24: 1718c9698e5cSDavid A. Long case R_ARM_THM_JUMP19: 171956a974faSSam Ravnborg /* From ARM ABI: ((S + A) | T) - P */ 1720df578e7dSSam Ravnborg r->r_addend = (int)(long)(elf->hdr + 17215b24c071SSam Ravnborg sechdr->sh_offset + 17225b24c071SSam Ravnborg (r->r_offset - sechdr->sh_addr)); 172356a974faSSam Ravnborg break; 172456a974faSSam Ravnborg default: 172556a974faSSam Ravnborg return 1; 172656a974faSSam Ravnborg } 172756a974faSSam Ravnborg return 0; 172856a974faSSam Ravnborg } 172956a974faSSam Ravnborg 17305b24c071SSam Ravnborg static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) 1731ae4ac123SAtsushi Nemoto { 1732ae4ac123SAtsushi Nemoto unsigned int r_typ = ELF_R_TYPE(r->r_info); 17335b24c071SSam Ravnborg unsigned int *location = reloc_location(elf, sechdr, r); 1734ae4ac123SAtsushi Nemoto unsigned int inst; 1735ae4ac123SAtsushi Nemoto 1736ae4ac123SAtsushi Nemoto if (r_typ == R_MIPS_HI16) 1737ae4ac123SAtsushi Nemoto return 1; /* skip this */ 1738ae4ac123SAtsushi Nemoto inst = TO_NATIVE(*location); 1739ae4ac123SAtsushi Nemoto switch (r_typ) { 1740ae4ac123SAtsushi Nemoto case R_MIPS_LO16: 1741ae4ac123SAtsushi Nemoto r->r_addend = inst & 0xffff; 1742ae4ac123SAtsushi Nemoto break; 1743ae4ac123SAtsushi Nemoto case R_MIPS_26: 1744ae4ac123SAtsushi Nemoto r->r_addend = (inst & 0x03ffffff) << 2; 1745ae4ac123SAtsushi Nemoto break; 1746ae4ac123SAtsushi Nemoto case R_MIPS_32: 1747ae4ac123SAtsushi Nemoto r->r_addend = inst; 1748ae4ac123SAtsushi Nemoto break; 1749ae4ac123SAtsushi Nemoto } 1750ae4ac123SAtsushi Nemoto return 0; 1751ae4ac123SAtsushi Nemoto } 1752ae4ac123SAtsushi Nemoto 17535b24c071SSam Ravnborg static void section_rela(const char *modname, struct elf_info *elf, 175410668220SSam Ravnborg Elf_Shdr *sechdr) 1755b39927cfSSam Ravnborg { 1756b39927cfSSam Ravnborg Elf_Sym *sym; 17575b24c071SSam Ravnborg Elf_Rela *rela; 17582c1a51f3SAtsushi Nemoto Elf_Rela r; 1759eae07ac6SAtsushi Nemoto unsigned int r_sym; 17605b24c071SSam Ravnborg const char *fromsec; 17615b24c071SSam Ravnborg 1762ff13f926SSam Ravnborg Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; 17635b24c071SSam Ravnborg Elf_Rela *stop = (void *)start + sechdr->sh_size; 17645b24c071SSam Ravnborg 1765ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 17665b24c071SSam Ravnborg fromsec += strlen(".rela"); 17675b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1768b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 17695b24c071SSam Ravnborg return; 1770e241a630SSam Ravnborg 1771b39927cfSSam Ravnborg for (rela = start; rela < stop; rela++) { 1772b39927cfSSam Ravnborg r.r_offset = TO_NATIVE(rela->r_offset); 1773eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1774ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1775ae4ac123SAtsushi Nemoto unsigned int r_typ; 1776eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rela->r_info); 1777eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1778ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rela->r_info); 1779ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1780eae07ac6SAtsushi Nemoto } else { 1781601e7f02SLinus Torvalds r.r_info = TO_NATIVE(rela->r_info); 1782eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1783eae07ac6SAtsushi Nemoto } 1784eae07ac6SAtsushi Nemoto #else 1785eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rela->r_info); 1786eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1787eae07ac6SAtsushi Nemoto #endif 178893684d3bSSam Ravnborg r.r_addend = TO_NATIVE(rela->r_addend); 1789eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 1790b39927cfSSam Ravnborg /* Skip special sections */ 17911ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 1792b39927cfSSam Ravnborg continue; 1793e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rela, fromsec)) 1794e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 179558fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 17962c1a51f3SAtsushi Nemoto } 17975b24c071SSam Ravnborg } 17985b24c071SSam Ravnborg 17995b24c071SSam Ravnborg static void section_rel(const char *modname, struct elf_info *elf, 180010668220SSam Ravnborg Elf_Shdr *sechdr) 18015b24c071SSam Ravnborg { 18025b24c071SSam Ravnborg Elf_Sym *sym; 18032c1a51f3SAtsushi Nemoto Elf_Rel *rel; 18045b24c071SSam Ravnborg Elf_Rela r; 18055b24c071SSam Ravnborg unsigned int r_sym; 18065b24c071SSam Ravnborg const char *fromsec; 18075b24c071SSam Ravnborg 1808ff13f926SSam Ravnborg Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; 18095b24c071SSam Ravnborg Elf_Rel *stop = (void *)start + sechdr->sh_size; 18105b24c071SSam Ravnborg 1811ff13f926SSam Ravnborg fromsec = sech_name(elf, sechdr); 18125b24c071SSam Ravnborg fromsec += strlen(".rel"); 18135b24c071SSam Ravnborg /* if from section (name) is know good then skip it */ 1814b614a697SAnders Kaseorg if (match(fromsec, section_white_list)) 18155b24c071SSam Ravnborg return; 18162c1a51f3SAtsushi Nemoto 18172c1a51f3SAtsushi Nemoto for (rel = start; rel < stop; rel++) { 18182c1a51f3SAtsushi Nemoto r.r_offset = TO_NATIVE(rel->r_offset); 1819eae07ac6SAtsushi Nemoto #if KERNEL_ELFCLASS == ELFCLASS64 1820ff13f926SSam Ravnborg if (elf->hdr->e_machine == EM_MIPS) { 1821ae4ac123SAtsushi Nemoto unsigned int r_typ; 1822eae07ac6SAtsushi Nemoto r_sym = ELF64_MIPS_R_SYM(rel->r_info); 1823eae07ac6SAtsushi Nemoto r_sym = TO_NATIVE(r_sym); 1824ae4ac123SAtsushi Nemoto r_typ = ELF64_MIPS_R_TYPE(rel->r_info); 1825ae4ac123SAtsushi Nemoto r.r_info = ELF64_R_INFO(r_sym, r_typ); 1826eae07ac6SAtsushi Nemoto } else { 18272c1a51f3SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1828eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1829eae07ac6SAtsushi Nemoto } 1830eae07ac6SAtsushi Nemoto #else 1831eae07ac6SAtsushi Nemoto r.r_info = TO_NATIVE(rel->r_info); 1832eae07ac6SAtsushi Nemoto r_sym = ELF_R_SYM(r.r_info); 1833eae07ac6SAtsushi Nemoto #endif 18342c1a51f3SAtsushi Nemoto r.r_addend = 0; 1835ff13f926SSam Ravnborg switch (elf->hdr->e_machine) { 1836ae4ac123SAtsushi Nemoto case EM_386: 18375b24c071SSam Ravnborg if (addend_386_rel(elf, sechdr, &r)) 1838ae4ac123SAtsushi Nemoto continue; 1839ae4ac123SAtsushi Nemoto break; 184056a974faSSam Ravnborg case EM_ARM: 18415b24c071SSam Ravnborg if (addend_arm_rel(elf, sechdr, &r)) 184256a974faSSam Ravnborg continue; 184356a974faSSam Ravnborg break; 1844ae4ac123SAtsushi Nemoto case EM_MIPS: 18455b24c071SSam Ravnborg if (addend_mips_rel(elf, sechdr, &r)) 1846ae4ac123SAtsushi Nemoto continue; 1847ae4ac123SAtsushi Nemoto break; 1848ae4ac123SAtsushi Nemoto } 1849eae07ac6SAtsushi Nemoto sym = elf->symtab_start + r_sym; 18502c1a51f3SAtsushi Nemoto /* Skip special sections */ 18511ce53adfSDenys Vlasenko if (is_shndx_special(sym->st_shndx)) 18522c1a51f3SAtsushi Nemoto continue; 1853e84048aaSQuentin Casasnovas if (is_second_extable_reloc(start, rel, fromsec)) 1854e84048aaSQuentin Casasnovas find_extable_entry_size(fromsec, &r); 185558fb0d4fSSam Ravnborg check_section_mismatch(modname, elf, &r, sym, fromsec); 18562c1a51f3SAtsushi Nemoto } 1857b39927cfSSam Ravnborg } 18585b24c071SSam Ravnborg 18595b24c071SSam Ravnborg /** 18605b24c071SSam Ravnborg * A module includes a number of sections that are discarded 18615b24c071SSam Ravnborg * either when loaded or when used as built-in. 18625b24c071SSam Ravnborg * For loaded modules all functions marked __init and all data 1863b595076aSUwe Kleine-König * marked __initdata will be discarded when the module has been initialized. 18645b24c071SSam Ravnborg * Likewise for modules used built-in the sections marked __exit 18655b24c071SSam Ravnborg * are discarded because __exit marked function are supposed to be called 186632be1d22SBen Dooks * only when a module is unloaded which never happens for built-in modules. 18675b24c071SSam Ravnborg * The check_sec_ref() function traverses all relocation records 18685b24c071SSam Ravnborg * to find all references to a section that reference a section that will 18695b24c071SSam Ravnborg * be discarded and warns about it. 18705b24c071SSam Ravnborg **/ 18715b24c071SSam Ravnborg static void check_sec_ref(struct module *mod, const char *modname, 187210668220SSam Ravnborg struct elf_info *elf) 18735b24c071SSam Ravnborg { 18745b24c071SSam Ravnborg int i; 18755b24c071SSam Ravnborg Elf_Shdr *sechdrs = elf->sechdrs; 18765b24c071SSam Ravnborg 18775b24c071SSam Ravnborg /* Walk through all sections */ 18781ce53adfSDenys Vlasenko for (i = 0; i < elf->num_sections; i++) { 1879b614a697SAnders Kaseorg check_section(modname, elf, &elf->sechdrs[i]); 18805b24c071SSam Ravnborg /* We want to process only relocation sections and not .init */ 18815b24c071SSam Ravnborg if (sechdrs[i].sh_type == SHT_RELA) 188210668220SSam Ravnborg section_rela(modname, elf, &elf->sechdrs[i]); 18835b24c071SSam Ravnborg else if (sechdrs[i].sh_type == SHT_REL) 188410668220SSam Ravnborg section_rel(modname, elf, &elf->sechdrs[i]); 1885b39927cfSSam Ravnborg } 1886b39927cfSSam Ravnborg } 1887b39927cfSSam Ravnborg 18887d02b490SAndi Kleen static char *remove_dot(char *s) 18897d02b490SAndi Kleen { 1890fcd38ed0SMichal Nazarewicz size_t n = strcspn(s, "."); 18917d02b490SAndi Kleen 1892fcd38ed0SMichal Nazarewicz if (n && s[n]) { 1893fcd38ed0SMichal Nazarewicz size_t m = strspn(s + n + 1, "0123456789"); 1894fcd38ed0SMichal Nazarewicz if (m && (s[n + m] == '.' || s[n + m] == 0)) 18957d02b490SAndi Kleen s[n] = 0; 18967d02b490SAndi Kleen } 18977d02b490SAndi Kleen return s; 18987d02b490SAndi Kleen } 18997d02b490SAndi Kleen 19005c3ead8cSSam Ravnborg static void read_symbols(char *modname) 19011da177e4SLinus Torvalds { 19021da177e4SLinus Torvalds const char *symname; 19031da177e4SLinus Torvalds char *version; 1904b817f6feSSam Ravnborg char *license; 19051da177e4SLinus Torvalds struct module *mod; 19061da177e4SLinus Torvalds struct elf_info info = { }; 19071da177e4SLinus Torvalds Elf_Sym *sym; 19081da177e4SLinus Torvalds 190985bd2fddSSam Ravnborg if (!parse_elf(&info, modname)) 191085bd2fddSSam Ravnborg return; 19111da177e4SLinus Torvalds 19121da177e4SLinus Torvalds mod = new_module(modname); 19131da177e4SLinus Torvalds 19141da177e4SLinus Torvalds /* When there's no vmlinux, don't print warnings about 19151da177e4SLinus Torvalds * unresolved symbols (since there'll be too many ;) */ 19161da177e4SLinus Torvalds if (is_vmlinux(modname)) { 19171da177e4SLinus Torvalds have_vmlinux = 1; 19181da177e4SLinus Torvalds mod->skip = 1; 19191da177e4SLinus Torvalds } 19201da177e4SLinus Torvalds 1921b817f6feSSam Ravnborg license = get_modinfo(info.modinfo, info.modinfo_len, "license"); 19222fa36568SSam Ravnborg if (info.modinfo && !license && !is_vmlinux(modname)) 19232fa36568SSam Ravnborg warn("modpost: missing MODULE_LICENSE() in %s\n" 1924eed7d279SSam Ravnborg "see include/linux/module.h for " 1925eed7d279SSam Ravnborg "more information\n", modname); 1926b817f6feSSam Ravnborg while (license) { 1927b817f6feSSam Ravnborg if (license_is_gpl_compatible(license)) 1928b817f6feSSam Ravnborg mod->gpl_compatible = 1; 1929b817f6feSSam Ravnborg else { 1930b817f6feSSam Ravnborg mod->gpl_compatible = 0; 1931b817f6feSSam Ravnborg break; 1932b817f6feSSam Ravnborg } 1933b817f6feSSam Ravnborg license = get_next_modinfo(info.modinfo, info.modinfo_len, 1934b817f6feSSam Ravnborg "license", license); 1935b817f6feSSam Ravnborg } 1936b817f6feSSam Ravnborg 19371da177e4SLinus Torvalds for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { 19387d02b490SAndi Kleen symname = remove_dot(info.strtab + sym->st_name); 19391da177e4SLinus Torvalds 19401da177e4SLinus Torvalds handle_modversions(mod, &info, sym, symname); 19411da177e4SLinus Torvalds handle_moddevtable(mod, &info, sym, symname); 19421da177e4SLinus Torvalds } 1943d1f25e66SSam Ravnborg if (!is_vmlinux(modname) || 194410668220SSam Ravnborg (is_vmlinux(modname) && vmlinux_section_warnings)) 194510668220SSam Ravnborg check_sec_ref(mod, modname, &info); 19461da177e4SLinus Torvalds 19471da177e4SLinus Torvalds version = get_modinfo(info.modinfo, info.modinfo_len, "version"); 19481da177e4SLinus Torvalds if (version) 19491da177e4SLinus Torvalds maybe_frob_rcs_version(modname, version, info.modinfo, 19501da177e4SLinus Torvalds version - (char *)info.hdr); 19511da177e4SLinus Torvalds if (version || (all_versions && !is_vmlinux(modname))) 19521da177e4SLinus Torvalds get_src_version(modname, mod->srcversion, 19531da177e4SLinus Torvalds sizeof(mod->srcversion)-1); 19541da177e4SLinus Torvalds 19551da177e4SLinus Torvalds parse_elf_finish(&info); 19561da177e4SLinus Torvalds 19578c8ef42aSRusty Russell /* Our trick to get versioning for module struct etc. - it's 19581da177e4SLinus Torvalds * never passed as an argument to an exported function, so 19591da177e4SLinus Torvalds * the automatic versioning doesn't pick it up, but it's really 19601da177e4SLinus Torvalds * important anyhow */ 19611da177e4SLinus Torvalds if (modversions) 19628c8ef42aSRusty Russell mod->unres = alloc_symbol("module_layout", 0, mod->unres); 19631da177e4SLinus Torvalds } 19641da177e4SLinus Torvalds 1965712f9b46SRusty Russell static void read_symbols_from_files(const char *filename) 1966712f9b46SRusty Russell { 1967712f9b46SRusty Russell FILE *in = stdin; 1968712f9b46SRusty Russell char fname[PATH_MAX]; 1969712f9b46SRusty Russell 1970712f9b46SRusty Russell if (strcmp(filename, "-") != 0) { 1971712f9b46SRusty Russell in = fopen(filename, "r"); 1972712f9b46SRusty Russell if (!in) 1973712f9b46SRusty Russell fatal("Can't open filenames file %s: %m", filename); 1974712f9b46SRusty Russell } 1975712f9b46SRusty Russell 1976712f9b46SRusty Russell while (fgets(fname, PATH_MAX, in) != NULL) { 1977712f9b46SRusty Russell if (strends(fname, "\n")) 1978712f9b46SRusty Russell fname[strlen(fname)-1] = '\0'; 1979712f9b46SRusty Russell read_symbols(fname); 1980712f9b46SRusty Russell } 1981712f9b46SRusty Russell 1982712f9b46SRusty Russell if (in != stdin) 1983712f9b46SRusty Russell fclose(in); 1984712f9b46SRusty Russell } 1985712f9b46SRusty Russell 19861da177e4SLinus Torvalds #define SZ 500 19871da177e4SLinus Torvalds 19881da177e4SLinus Torvalds /* We first write the generated file into memory using the 19891da177e4SLinus Torvalds * following helper, then compare to the file on disk and 19901da177e4SLinus Torvalds * only update the later if anything changed */ 19911da177e4SLinus Torvalds 19925c3ead8cSSam Ravnborg void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, 19935c3ead8cSSam Ravnborg const char *fmt, ...) 19941da177e4SLinus Torvalds { 19951da177e4SLinus Torvalds char tmp[SZ]; 19961da177e4SLinus Torvalds int len; 19971da177e4SLinus Torvalds va_list ap; 19981da177e4SLinus Torvalds 19991da177e4SLinus Torvalds va_start(ap, fmt); 20001da177e4SLinus Torvalds len = vsnprintf(tmp, SZ, fmt, ap); 20017670f023SSam Ravnborg buf_write(buf, tmp, len); 20021da177e4SLinus Torvalds va_end(ap); 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds 20055c3ead8cSSam Ravnborg void buf_write(struct buffer *buf, const char *s, int len) 20061da177e4SLinus Torvalds { 20071da177e4SLinus Torvalds if (buf->size - buf->pos < len) { 20087670f023SSam Ravnborg buf->size += len + SZ; 20091da177e4SLinus Torvalds buf->p = realloc(buf->p, buf->size); 20101da177e4SLinus Torvalds } 20111da177e4SLinus Torvalds strncpy(buf->p + buf->pos, s, len); 20121da177e4SLinus Torvalds buf->pos += len; 20131da177e4SLinus Torvalds } 20141da177e4SLinus Torvalds 2015c96fca21SSam Ravnborg static void check_for_gpl_usage(enum export exp, const char *m, const char *s) 2016c96fca21SSam Ravnborg { 2017c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2018c96fca21SSam Ravnborg 2019c96fca21SSam Ravnborg switch (exp) { 2020c96fca21SSam Ravnborg case export_gpl: 2021c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2022c96fca21SSam Ravnborg "uses GPL-only symbol '%s'\n", m, e, s); 2023c96fca21SSam Ravnborg break; 2024c96fca21SSam Ravnborg case export_unused_gpl: 2025c96fca21SSam Ravnborg fatal("modpost: GPL-incompatible module %s%s " 2026c96fca21SSam Ravnborg "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); 2027c96fca21SSam Ravnborg break; 2028c96fca21SSam Ravnborg case export_gpl_future: 2029c96fca21SSam Ravnborg warn("modpost: GPL-incompatible module %s%s " 2030c96fca21SSam Ravnborg "uses future GPL-only symbol '%s'\n", m, e, s); 2031c96fca21SSam Ravnborg break; 2032c96fca21SSam Ravnborg case export_plain: 2033c96fca21SSam Ravnborg case export_unused: 2034c96fca21SSam Ravnborg case export_unknown: 2035c96fca21SSam Ravnborg /* ignore */ 2036c96fca21SSam Ravnborg break; 2037c96fca21SSam Ravnborg } 2038c96fca21SSam Ravnborg } 2039c96fca21SSam Ravnborg 2040c96fca21SSam Ravnborg static void check_for_unused(enum export exp, const char *m, const char *s) 2041c96fca21SSam Ravnborg { 2042c96fca21SSam Ravnborg const char *e = is_vmlinux(m) ?"":".ko"; 2043c96fca21SSam Ravnborg 2044c96fca21SSam Ravnborg switch (exp) { 2045c96fca21SSam Ravnborg case export_unused: 2046c96fca21SSam Ravnborg case export_unused_gpl: 2047c96fca21SSam Ravnborg warn("modpost: module %s%s " 2048c96fca21SSam Ravnborg "uses symbol '%s' marked UNUSED\n", m, e, s); 2049c96fca21SSam Ravnborg break; 2050c96fca21SSam Ravnborg default: 2051c96fca21SSam Ravnborg /* ignore */ 2052c96fca21SSam Ravnborg break; 2053c96fca21SSam Ravnborg } 2054c96fca21SSam Ravnborg } 2055c96fca21SSam Ravnborg 2056c96fca21SSam Ravnborg static void check_exports(struct module *mod) 2057b817f6feSSam Ravnborg { 2058b817f6feSSam Ravnborg struct symbol *s, *exp; 2059b817f6feSSam Ravnborg 2060b817f6feSSam Ravnborg for (s = mod->unres; s; s = s->next) { 20616449bd62SAndrew Morton const char *basename; 2062b817f6feSSam Ravnborg exp = find_symbol(s->name); 2063b817f6feSSam Ravnborg if (!exp || exp->module == mod) 2064b817f6feSSam Ravnborg continue; 20656449bd62SAndrew Morton basename = strrchr(mod->name, '/'); 2066b817f6feSSam Ravnborg if (basename) 2067b817f6feSSam Ravnborg basename++; 2068c96fca21SSam Ravnborg else 2069c96fca21SSam Ravnborg basename = mod->name; 2070c96fca21SSam Ravnborg if (!mod->gpl_compatible) 2071c96fca21SSam Ravnborg check_for_gpl_usage(exp->export, basename, exp->name); 2072c96fca21SSam Ravnborg check_for_unused(exp->export, basename, exp->name); 2073b817f6feSSam Ravnborg } 2074b817f6feSSam Ravnborg } 2075b817f6feSSam Ravnborg 20765c3ead8cSSam Ravnborg /** 20775c3ead8cSSam Ravnborg * Header for the generated file 20785c3ead8cSSam Ravnborg **/ 20795c3ead8cSSam Ravnborg static void add_header(struct buffer *b, struct module *mod) 20801da177e4SLinus Torvalds { 20811da177e4SLinus Torvalds buf_printf(b, "#include <linux/module.h>\n"); 20821da177e4SLinus Torvalds buf_printf(b, "#include <linux/vermagic.h>\n"); 20831da177e4SLinus Torvalds buf_printf(b, "#include <linux/compiler.h>\n"); 20841da177e4SLinus Torvalds buf_printf(b, "\n"); 20851da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); 20861da177e4SLinus Torvalds buf_printf(b, "\n"); 2087e0f244c6SAndi Kleen buf_printf(b, "__visible struct module __this_module\n"); 20881da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); 20893c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); 20901da177e4SLinus Torvalds if (mod->has_init) 20913c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.init = init_module,\n"); 20921da177e4SLinus Torvalds if (mod->has_cleanup) 20931da177e4SLinus Torvalds buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" 20943c7ec94dSGreg Kroah-Hartman "\t.exit = cleanup_module,\n" 20951da177e4SLinus Torvalds "#endif\n"); 20963c7ec94dSGreg Kroah-Hartman buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); 20971da177e4SLinus Torvalds buf_printf(b, "};\n"); 20981da177e4SLinus Torvalds } 20991da177e4SLinus Torvalds 21002449b8baSBen Hutchings static void add_intree_flag(struct buffer *b, int is_intree) 21012449b8baSBen Hutchings { 21022449b8baSBen Hutchings if (is_intree) 21032449b8baSBen Hutchings buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); 21042449b8baSBen Hutchings } 21052449b8baSBen Hutchings 21065c725138STrevor Keith static void add_staging_flag(struct buffer *b, const char *name) 2107a9860bf0SGreg Kroah-Hartman { 2108a9860bf0SGreg Kroah-Hartman static const char *staging_dir = "drivers/staging"; 2109a9860bf0SGreg Kroah-Hartman 2110a9860bf0SGreg Kroah-Hartman if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) 2111a9860bf0SGreg Kroah-Hartman buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); 2112a9860bf0SGreg Kroah-Hartman } 2113a9860bf0SGreg Kroah-Hartman 21145c3ead8cSSam Ravnborg /** 21155c3ead8cSSam Ravnborg * Record CRCs for unresolved symbols 21165c3ead8cSSam Ravnborg **/ 2117c53ddacdSKirill Korotaev static int add_versions(struct buffer *b, struct module *mod) 21181da177e4SLinus Torvalds { 21191da177e4SLinus Torvalds struct symbol *s, *exp; 2120c53ddacdSKirill Korotaev int err = 0; 21211da177e4SLinus Torvalds 21221da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 21231da177e4SLinus Torvalds exp = find_symbol(s->name); 21241da177e4SLinus Torvalds if (!exp || exp->module == mod) { 2125c53ddacdSKirill Korotaev if (have_vmlinux && !s->weak) { 21262a116659SMatthew Wilcox if (warn_unresolved) { 2127cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] undefined!\n", 2128cb80514dSSam Ravnborg s->name, mod->name); 21292a116659SMatthew Wilcox } else { 21302a116659SMatthew Wilcox merror("\"%s\" [%s.ko] undefined!\n", 21312a116659SMatthew Wilcox s->name, mod->name); 21322a116659SMatthew Wilcox err = 1; 21332a116659SMatthew Wilcox } 2134c53ddacdSKirill Korotaev } 21351da177e4SLinus Torvalds continue; 21361da177e4SLinus Torvalds } 21371da177e4SLinus Torvalds s->module = exp->module; 21381da177e4SLinus Torvalds s->crc_valid = exp->crc_valid; 21391da177e4SLinus Torvalds s->crc = exp->crc; 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds 21421da177e4SLinus Torvalds if (!modversions) 2143c53ddacdSKirill Korotaev return err; 21441da177e4SLinus Torvalds 21451da177e4SLinus Torvalds buf_printf(b, "\n"); 21461da177e4SLinus Torvalds buf_printf(b, "static const struct modversion_info ____versions[]\n"); 21473ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 21481da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); 21491da177e4SLinus Torvalds 21501da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2151df578e7dSSam Ravnborg if (!s->module) 21521da177e4SLinus Torvalds continue; 21531da177e4SLinus Torvalds if (!s->crc_valid) { 2154cb80514dSSam Ravnborg warn("\"%s\" [%s.ko] has no CRC!\n", 21551da177e4SLinus Torvalds s->name, mod->name); 21561da177e4SLinus Torvalds continue; 21571da177e4SLinus Torvalds } 2158a53a11f3SJames Hogan buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", 2159a4b6a77bSJames Hogan s->crc, s->name); 21601da177e4SLinus Torvalds } 21611da177e4SLinus Torvalds 21621da177e4SLinus Torvalds buf_printf(b, "};\n"); 2163c53ddacdSKirill Korotaev 2164c53ddacdSKirill Korotaev return err; 21651da177e4SLinus Torvalds } 21661da177e4SLinus Torvalds 21675c3ead8cSSam Ravnborg static void add_depends(struct buffer *b, struct module *mod, 21685c3ead8cSSam Ravnborg struct module *modules) 21691da177e4SLinus Torvalds { 21701da177e4SLinus Torvalds struct symbol *s; 21711da177e4SLinus Torvalds struct module *m; 21721da177e4SLinus Torvalds int first = 1; 21731da177e4SLinus Torvalds 2174df578e7dSSam Ravnborg for (m = modules; m; m = m->next) 21751da177e4SLinus Torvalds m->seen = is_vmlinux(m->name); 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds buf_printf(b, "\n"); 21781da177e4SLinus Torvalds buf_printf(b, "static const char __module_depends[]\n"); 21793ff6eeccSAdrian Bunk buf_printf(b, "__used\n"); 21801da177e4SLinus Torvalds buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); 21811da177e4SLinus Torvalds buf_printf(b, "\"depends="); 21821da177e4SLinus Torvalds for (s = mod->unres; s; s = s->next) { 2183a61b2dfdSSam Ravnborg const char *p; 21841da177e4SLinus Torvalds if (!s->module) 21851da177e4SLinus Torvalds continue; 21861da177e4SLinus Torvalds 21871da177e4SLinus Torvalds if (s->module->seen) 21881da177e4SLinus Torvalds continue; 21891da177e4SLinus Torvalds 21901da177e4SLinus Torvalds s->module->seen = 1; 2191df578e7dSSam Ravnborg p = strrchr(s->module->name, '/'); 2192df578e7dSSam Ravnborg if (p) 2193a61b2dfdSSam Ravnborg p++; 2194a61b2dfdSSam Ravnborg else 2195a61b2dfdSSam Ravnborg p = s->module->name; 2196a61b2dfdSSam Ravnborg buf_printf(b, "%s%s", first ? "" : ",", p); 21971da177e4SLinus Torvalds first = 0; 21981da177e4SLinus Torvalds } 21991da177e4SLinus Torvalds buf_printf(b, "\";\n"); 22001da177e4SLinus Torvalds } 22011da177e4SLinus Torvalds 22025c3ead8cSSam Ravnborg static void add_srcversion(struct buffer *b, struct module *mod) 22031da177e4SLinus Torvalds { 22041da177e4SLinus Torvalds if (mod->srcversion[0]) { 22051da177e4SLinus Torvalds buf_printf(b, "\n"); 22061da177e4SLinus Torvalds buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", 22071da177e4SLinus Torvalds mod->srcversion); 22081da177e4SLinus Torvalds } 22091da177e4SLinus Torvalds } 22101da177e4SLinus Torvalds 22115c3ead8cSSam Ravnborg static void write_if_changed(struct buffer *b, const char *fname) 22121da177e4SLinus Torvalds { 22131da177e4SLinus Torvalds char *tmp; 22141da177e4SLinus Torvalds FILE *file; 22151da177e4SLinus Torvalds struct stat st; 22161da177e4SLinus Torvalds 22171da177e4SLinus Torvalds file = fopen(fname, "r"); 22181da177e4SLinus Torvalds if (!file) 22191da177e4SLinus Torvalds goto write; 22201da177e4SLinus Torvalds 22211da177e4SLinus Torvalds if (fstat(fileno(file), &st) < 0) 22221da177e4SLinus Torvalds goto close_write; 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds if (st.st_size != b->pos) 22251da177e4SLinus Torvalds goto close_write; 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds tmp = NOFAIL(malloc(b->pos)); 22281da177e4SLinus Torvalds if (fread(tmp, 1, b->pos, file) != b->pos) 22291da177e4SLinus Torvalds goto free_write; 22301da177e4SLinus Torvalds 22311da177e4SLinus Torvalds if (memcmp(tmp, b->p, b->pos) != 0) 22321da177e4SLinus Torvalds goto free_write; 22331da177e4SLinus Torvalds 22341da177e4SLinus Torvalds free(tmp); 22351da177e4SLinus Torvalds fclose(file); 22361da177e4SLinus Torvalds return; 22371da177e4SLinus Torvalds 22381da177e4SLinus Torvalds free_write: 22391da177e4SLinus Torvalds free(tmp); 22401da177e4SLinus Torvalds close_write: 22411da177e4SLinus Torvalds fclose(file); 22421da177e4SLinus Torvalds write: 22431da177e4SLinus Torvalds file = fopen(fname, "w"); 22441da177e4SLinus Torvalds if (!file) { 22451da177e4SLinus Torvalds perror(fname); 22461da177e4SLinus Torvalds exit(1); 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds if (fwrite(b->p, 1, b->pos, file) != b->pos) { 22491da177e4SLinus Torvalds perror(fname); 22501da177e4SLinus Torvalds exit(1); 22511da177e4SLinus Torvalds } 22521da177e4SLinus Torvalds fclose(file); 22531da177e4SLinus Torvalds } 22541da177e4SLinus Torvalds 2255bd5cbcedSRam Pai /* parse Module.symvers file. line format: 2256534b89a9SSam Ravnborg * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] 2257bd5cbcedSRam Pai **/ 2258040fcc81SSam Ravnborg static void read_dump(const char *fname, unsigned int kernel) 22591da177e4SLinus Torvalds { 22601da177e4SLinus Torvalds unsigned long size, pos = 0; 22611da177e4SLinus Torvalds void *file = grab_file(fname, &size); 22621da177e4SLinus Torvalds char *line; 22631da177e4SLinus Torvalds 22641da177e4SLinus Torvalds if (!file) 22651da177e4SLinus Torvalds /* No symbol versions, silently ignore */ 22661da177e4SLinus Torvalds return; 22671da177e4SLinus Torvalds 22681da177e4SLinus Torvalds while ((line = get_next_line(&pos, file, size))) { 2269534b89a9SSam Ravnborg char *symname, *modname, *d, *export, *end; 22701da177e4SLinus Torvalds unsigned int crc; 22711da177e4SLinus Torvalds struct module *mod; 2272040fcc81SSam Ravnborg struct symbol *s; 22731da177e4SLinus Torvalds 22741da177e4SLinus Torvalds if (!(symname = strchr(line, '\t'))) 22751da177e4SLinus Torvalds goto fail; 22761da177e4SLinus Torvalds *symname++ = '\0'; 22771da177e4SLinus Torvalds if (!(modname = strchr(symname, '\t'))) 22781da177e4SLinus Torvalds goto fail; 22791da177e4SLinus Torvalds *modname++ = '\0'; 22809ac545b0SLaurent Riffard if ((export = strchr(modname, '\t')) != NULL) 2281bd5cbcedSRam Pai *export++ = '\0'; 2282534b89a9SSam Ravnborg if (export && ((end = strchr(export, '\t')) != NULL)) 2283534b89a9SSam Ravnborg *end = '\0'; 22841da177e4SLinus Torvalds crc = strtoul(line, &d, 16); 22851da177e4SLinus Torvalds if (*symname == '\0' || *modname == '\0' || *d != '\0') 22861da177e4SLinus Torvalds goto fail; 2287df578e7dSSam Ravnborg mod = find_module(modname); 2288df578e7dSSam Ravnborg if (!mod) { 2289df578e7dSSam Ravnborg if (is_vmlinux(modname)) 22901da177e4SLinus Torvalds have_vmlinux = 1; 22910fa3a88cSJan Beulich mod = new_module(modname); 22921da177e4SLinus Torvalds mod->skip = 1; 22931da177e4SLinus Torvalds } 2294bd5cbcedSRam Pai s = sym_add_exported(symname, mod, export_no(export)); 2295040fcc81SSam Ravnborg s->kernel = kernel; 22968e70c458SSam Ravnborg s->preloaded = 1; 2297bd5cbcedSRam Pai sym_update_crc(symname, mod, crc, export_no(export)); 22981da177e4SLinus Torvalds } 22992ee41e62SChristian Engelmayer release_file(file, size); 23001da177e4SLinus Torvalds return; 23011da177e4SLinus Torvalds fail: 23022ee41e62SChristian Engelmayer release_file(file, size); 23031da177e4SLinus Torvalds fatal("parse error in symbol dump file\n"); 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds 2306040fcc81SSam Ravnborg /* For normal builds always dump all symbols. 2307040fcc81SSam Ravnborg * For external modules only dump symbols 2308040fcc81SSam Ravnborg * that are not read from kernel Module.symvers. 2309040fcc81SSam Ravnborg **/ 2310040fcc81SSam Ravnborg static int dump_sym(struct symbol *sym) 2311040fcc81SSam Ravnborg { 2312040fcc81SSam Ravnborg if (!external_module) 2313040fcc81SSam Ravnborg return 1; 2314040fcc81SSam Ravnborg if (sym->vmlinux || sym->kernel) 2315040fcc81SSam Ravnborg return 0; 2316040fcc81SSam Ravnborg return 1; 2317040fcc81SSam Ravnborg } 2318040fcc81SSam Ravnborg 23195c3ead8cSSam Ravnborg static void write_dump(const char *fname) 23201da177e4SLinus Torvalds { 23211da177e4SLinus Torvalds struct buffer buf = { }; 23221da177e4SLinus Torvalds struct symbol *symbol; 23231da177e4SLinus Torvalds int n; 23241da177e4SLinus Torvalds 23251da177e4SLinus Torvalds for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { 23261da177e4SLinus Torvalds symbol = symbolhash[n]; 23271da177e4SLinus Torvalds while (symbol) { 2328040fcc81SSam Ravnborg if (dump_sym(symbol)) 2329bd5cbcedSRam Pai buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", 2330040fcc81SSam Ravnborg symbol->crc, symbol->name, 2331bd5cbcedSRam Pai symbol->module->name, 2332bd5cbcedSRam Pai export_str(symbol->export)); 23331da177e4SLinus Torvalds symbol = symbol->next; 23341da177e4SLinus Torvalds } 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds write_if_changed(&buf, fname); 23371da177e4SLinus Torvalds } 23381da177e4SLinus Torvalds 23392d04b5aeSRichard Hacker struct ext_sym_list { 23402d04b5aeSRichard Hacker struct ext_sym_list *next; 23412d04b5aeSRichard Hacker const char *file; 23422d04b5aeSRichard Hacker }; 23432d04b5aeSRichard Hacker 23445c3ead8cSSam Ravnborg int main(int argc, char **argv) 23451da177e4SLinus Torvalds { 23461da177e4SLinus Torvalds struct module *mod; 23471da177e4SLinus Torvalds struct buffer buf = { }; 2348040fcc81SSam Ravnborg char *kernel_read = NULL, *module_read = NULL; 2349712f9b46SRusty Russell char *dump_write = NULL, *files_source = NULL; 23501da177e4SLinus Torvalds int opt; 2351c53ddacdSKirill Korotaev int err; 23522d04b5aeSRichard Hacker struct ext_sym_list *extsym_iter; 23532d04b5aeSRichard Hacker struct ext_sym_list *extsym_start = NULL; 23541da177e4SLinus Torvalds 2355eed380f3SGuenter Roeck while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:")) != -1) { 23561da177e4SLinus Torvalds switch (opt) { 23571da177e4SLinus Torvalds case 'i': 2358040fcc81SSam Ravnborg kernel_read = optarg; 2359040fcc81SSam Ravnborg break; 2360040fcc81SSam Ravnborg case 'I': 2361040fcc81SSam Ravnborg module_read = optarg; 2362040fcc81SSam Ravnborg external_module = 1; 23631da177e4SLinus Torvalds break; 23642d04b5aeSRichard Hacker case 'e': 23652d04b5aeSRichard Hacker external_module = 1; 23662d04b5aeSRichard Hacker extsym_iter = 23672d04b5aeSRichard Hacker NOFAIL(malloc(sizeof(*extsym_iter))); 23682d04b5aeSRichard Hacker extsym_iter->next = extsym_start; 23692d04b5aeSRichard Hacker extsym_iter->file = optarg; 23702d04b5aeSRichard Hacker extsym_start = extsym_iter; 23712d04b5aeSRichard Hacker break; 23721da177e4SLinus Torvalds case 'm': 23731da177e4SLinus Torvalds modversions = 1; 23741da177e4SLinus Torvalds break; 2375eed380f3SGuenter Roeck case 'n': 2376eed380f3SGuenter Roeck ignore_missing_files = 1; 2377eed380f3SGuenter Roeck break; 23781da177e4SLinus Torvalds case 'o': 23791da177e4SLinus Torvalds dump_write = optarg; 23801da177e4SLinus Torvalds break; 23811da177e4SLinus Torvalds case 'a': 23821da177e4SLinus Torvalds all_versions = 1; 23831da177e4SLinus Torvalds break; 23848d8d8289SSam Ravnborg case 's': 23858d8d8289SSam Ravnborg vmlinux_section_warnings = 0; 23868d8d8289SSam Ravnborg break; 2387588ccd73SSam Ravnborg case 'S': 2388588ccd73SSam Ravnborg sec_mismatch_verbose = 0; 2389588ccd73SSam Ravnborg break; 2390712f9b46SRusty Russell case 'T': 2391712f9b46SRusty Russell files_source = optarg; 2392712f9b46SRusty Russell break; 2393c53ddacdSKirill Korotaev case 'w': 2394c53ddacdSKirill Korotaev warn_unresolved = 1; 2395c53ddacdSKirill Korotaev break; 23961da177e4SLinus Torvalds default: 23971da177e4SLinus Torvalds exit(1); 23981da177e4SLinus Torvalds } 23991da177e4SLinus Torvalds } 24001da177e4SLinus Torvalds 2401040fcc81SSam Ravnborg if (kernel_read) 2402040fcc81SSam Ravnborg read_dump(kernel_read, 1); 2403040fcc81SSam Ravnborg if (module_read) 2404040fcc81SSam Ravnborg read_dump(module_read, 0); 24052d04b5aeSRichard Hacker while (extsym_start) { 24062d04b5aeSRichard Hacker read_dump(extsym_start->file, 0); 24072d04b5aeSRichard Hacker extsym_iter = extsym_start->next; 24082d04b5aeSRichard Hacker free(extsym_start); 24092d04b5aeSRichard Hacker extsym_start = extsym_iter; 24102d04b5aeSRichard Hacker } 24111da177e4SLinus Torvalds 2412df578e7dSSam Ravnborg while (optind < argc) 24131da177e4SLinus Torvalds read_symbols(argv[optind++]); 24141da177e4SLinus Torvalds 2415712f9b46SRusty Russell if (files_source) 2416712f9b46SRusty Russell read_symbols_from_files(files_source); 2417712f9b46SRusty Russell 24181da177e4SLinus Torvalds for (mod = modules; mod; mod = mod->next) { 24191da177e4SLinus Torvalds if (mod->skip) 24201da177e4SLinus Torvalds continue; 2421c96fca21SSam Ravnborg check_exports(mod); 2422b817f6feSSam Ravnborg } 2423b817f6feSSam Ravnborg 2424c53ddacdSKirill Korotaev err = 0; 2425c53ddacdSKirill Korotaev 2426b817f6feSSam Ravnborg for (mod = modules; mod; mod = mod->next) { 2427d93e1719SMathias Krause char fname[PATH_MAX]; 2428666ab414SAndi Kleen 2429b817f6feSSam Ravnborg if (mod->skip) 2430b817f6feSSam Ravnborg continue; 24311da177e4SLinus Torvalds 24321da177e4SLinus Torvalds buf.pos = 0; 24331da177e4SLinus Torvalds 24341da177e4SLinus Torvalds add_header(&buf, mod); 24352449b8baSBen Hutchings add_intree_flag(&buf, !external_module); 2436a9860bf0SGreg Kroah-Hartman add_staging_flag(&buf, mod->name); 2437c53ddacdSKirill Korotaev err |= add_versions(&buf, mod); 24381da177e4SLinus Torvalds add_depends(&buf, mod, modules); 24391da177e4SLinus Torvalds add_moddevtable(&buf, mod); 24401da177e4SLinus Torvalds add_srcversion(&buf, mod); 24411da177e4SLinus Torvalds 24421da177e4SLinus Torvalds sprintf(fname, "%s.mod.c", mod->name); 24431da177e4SLinus Torvalds write_if_changed(&buf, fname); 24441da177e4SLinus Torvalds } 24451da177e4SLinus Torvalds 24461da177e4SLinus Torvalds if (dump_write) 24471da177e4SLinus Torvalds write_dump(dump_write); 2448588ccd73SSam Ravnborg if (sec_mismatch_count && !sec_mismatch_verbose) 24497c0ac495SGeert Uytterhoeven warn("modpost: Found %d section mismatch(es).\n" 2450e5f95c8bSSam Ravnborg "To see full details build your kernel with:\n" 2451e5f95c8bSSam Ravnborg "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", 2452e5f95c8bSSam Ravnborg sec_mismatch_count); 24531da177e4SLinus Torvalds 2454c53ddacdSKirill Korotaev return err; 24551da177e4SLinus Torvalds } 2456