| .. | .. |
|---|
| 12 | 12 | */ |
|---|
| 13 | 13 | |
|---|
| 14 | 14 | #define _GNU_SOURCE |
|---|
| 15 | +#include <elf.h> |
|---|
| 15 | 16 | #include <stdio.h> |
|---|
| 16 | 17 | #include <ctype.h> |
|---|
| 17 | 18 | #include <string.h> |
|---|
| 18 | 19 | #include <limits.h> |
|---|
| 19 | | -#include <stdbool.h> |
|---|
| 20 | 20 | #include <errno.h> |
|---|
| 21 | 21 | #include "modpost.h" |
|---|
| 22 | 22 | #include "../../include/linux/license.h" |
|---|
| .. | .. |
|---|
| 29 | 29 | static int all_versions = 0; |
|---|
| 30 | 30 | /* If we are modposting external module set to 1 */ |
|---|
| 31 | 31 | static int external_module = 0; |
|---|
| 32 | | -/* Warn about section mismatch in vmlinux if set to 1 */ |
|---|
| 33 | | -static int vmlinux_section_warnings = 1; |
|---|
| 32 | +#define MODULE_SCMVERSION_SIZE 64 |
|---|
| 33 | +static char module_scmversion[MODULE_SCMVERSION_SIZE]; |
|---|
| 34 | 34 | /* Only warn about unresolved symbols */ |
|---|
| 35 | 35 | static int warn_unresolved = 0; |
|---|
| 36 | 36 | /* How a symbol is exported */ |
|---|
| 37 | 37 | static int sec_mismatch_count = 0; |
|---|
| 38 | | -static int sec_mismatch_verbose = 1; |
|---|
| 39 | | -static int sec_mismatch_fatal = 0; |
|---|
| 38 | +static int sec_mismatch_warn_only = true; |
|---|
| 40 | 39 | /* ignore missing files */ |
|---|
| 41 | 40 | static int ignore_missing_files; |
|---|
| 41 | +/* If set to 1, only warn (instead of error) about missing ns imports */ |
|---|
| 42 | +static int allow_missing_ns_imports; |
|---|
| 43 | + |
|---|
| 44 | +static bool error_occurred; |
|---|
| 42 | 45 | |
|---|
| 43 | 46 | enum export { |
|---|
| 44 | 47 | export_plain, export_unused, export_gpl, |
|---|
| .. | .. |
|---|
| 51 | 54 | |
|---|
| 52 | 55 | #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) |
|---|
| 53 | 56 | |
|---|
| 54 | | -#define PRINTF __attribute__ ((format (printf, 1, 2))) |
|---|
| 55 | | - |
|---|
| 56 | | -PRINTF void fatal(const char *fmt, ...) |
|---|
| 57 | +void __attribute__((format(printf, 2, 3))) |
|---|
| 58 | +modpost_log(enum loglevel loglevel, const char *fmt, ...) |
|---|
| 57 | 59 | { |
|---|
| 58 | 60 | va_list arglist; |
|---|
| 59 | 61 | |
|---|
| 60 | | - fprintf(stderr, "FATAL: "); |
|---|
| 62 | + switch (loglevel) { |
|---|
| 63 | + case LOG_WARN: |
|---|
| 64 | + fprintf(stderr, "WARNING: "); |
|---|
| 65 | + break; |
|---|
| 66 | + case LOG_ERROR: |
|---|
| 67 | + fprintf(stderr, "ERROR: "); |
|---|
| 68 | + break; |
|---|
| 69 | + case LOG_FATAL: |
|---|
| 70 | + fprintf(stderr, "FATAL: "); |
|---|
| 71 | + break; |
|---|
| 72 | + default: /* invalid loglevel, ignore */ |
|---|
| 73 | + break; |
|---|
| 74 | + } |
|---|
| 75 | + |
|---|
| 76 | + fprintf(stderr, "modpost: "); |
|---|
| 61 | 77 | |
|---|
| 62 | 78 | va_start(arglist, fmt); |
|---|
| 63 | 79 | vfprintf(stderr, fmt, arglist); |
|---|
| 64 | 80 | va_end(arglist); |
|---|
| 65 | 81 | |
|---|
| 66 | | - exit(1); |
|---|
| 67 | | -} |
|---|
| 68 | | - |
|---|
| 69 | | -PRINTF void warn(const char *fmt, ...) |
|---|
| 70 | | -{ |
|---|
| 71 | | - va_list arglist; |
|---|
| 72 | | - |
|---|
| 73 | | - fprintf(stderr, "WARNING: "); |
|---|
| 74 | | - |
|---|
| 75 | | - va_start(arglist, fmt); |
|---|
| 76 | | - vfprintf(stderr, fmt, arglist); |
|---|
| 77 | | - va_end(arglist); |
|---|
| 78 | | -} |
|---|
| 79 | | - |
|---|
| 80 | | -PRINTF void merror(const char *fmt, ...) |
|---|
| 81 | | -{ |
|---|
| 82 | | - va_list arglist; |
|---|
| 83 | | - |
|---|
| 84 | | - fprintf(stderr, "ERROR: "); |
|---|
| 85 | | - |
|---|
| 86 | | - va_start(arglist, fmt); |
|---|
| 87 | | - vfprintf(stderr, fmt, arglist); |
|---|
| 88 | | - va_end(arglist); |
|---|
| 89 | | -} |
|---|
| 90 | | - |
|---|
| 91 | | -static inline bool strends(const char *str, const char *postfix) |
|---|
| 92 | | -{ |
|---|
| 93 | | - if (strlen(str) < strlen(postfix)) |
|---|
| 94 | | - return false; |
|---|
| 95 | | - |
|---|
| 96 | | - return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; |
|---|
| 97 | | -} |
|---|
| 98 | | - |
|---|
| 99 | | -static int is_vmlinux(const char *modname) |
|---|
| 100 | | -{ |
|---|
| 101 | | - const char *myname; |
|---|
| 102 | | - |
|---|
| 103 | | - myname = strrchr(modname, '/'); |
|---|
| 104 | | - if (myname) |
|---|
| 105 | | - myname++; |
|---|
| 106 | | - else |
|---|
| 107 | | - myname = modname; |
|---|
| 108 | | - |
|---|
| 109 | | - return (strcmp(myname, "vmlinux") == 0) || |
|---|
| 110 | | - (strcmp(myname, "vmlinux.o") == 0); |
|---|
| 82 | + if (loglevel == LOG_FATAL) |
|---|
| 83 | + exit(1); |
|---|
| 84 | + if (loglevel == LOG_ERROR) |
|---|
| 85 | + error_occurred = true; |
|---|
| 111 | 86 | } |
|---|
| 112 | 87 | |
|---|
| 113 | 88 | void *do_nofail(void *ptr, const char *expr) |
|---|
| 114 | 89 | { |
|---|
| 115 | 90 | if (!ptr) |
|---|
| 116 | | - fatal("modpost: Memory allocation failure: %s.\n", expr); |
|---|
| 91 | + fatal("Memory allocation failure: %s.\n", expr); |
|---|
| 117 | 92 | |
|---|
| 118 | 93 | return ptr; |
|---|
| 94 | +} |
|---|
| 95 | + |
|---|
| 96 | +char *read_text_file(const char *filename) |
|---|
| 97 | +{ |
|---|
| 98 | + struct stat st; |
|---|
| 99 | + size_t nbytes; |
|---|
| 100 | + int fd; |
|---|
| 101 | + char *buf; |
|---|
| 102 | + |
|---|
| 103 | + fd = open(filename, O_RDONLY); |
|---|
| 104 | + if (fd < 0) { |
|---|
| 105 | + perror(filename); |
|---|
| 106 | + exit(1); |
|---|
| 107 | + } |
|---|
| 108 | + |
|---|
| 109 | + if (fstat(fd, &st) < 0) { |
|---|
| 110 | + perror(filename); |
|---|
| 111 | + exit(1); |
|---|
| 112 | + } |
|---|
| 113 | + |
|---|
| 114 | + buf = NOFAIL(malloc(st.st_size + 1)); |
|---|
| 115 | + |
|---|
| 116 | + nbytes = st.st_size; |
|---|
| 117 | + |
|---|
| 118 | + while (nbytes) { |
|---|
| 119 | + ssize_t bytes_read; |
|---|
| 120 | + |
|---|
| 121 | + bytes_read = read(fd, buf, nbytes); |
|---|
| 122 | + if (bytes_read < 0) { |
|---|
| 123 | + perror(filename); |
|---|
| 124 | + exit(1); |
|---|
| 125 | + } |
|---|
| 126 | + |
|---|
| 127 | + nbytes -= bytes_read; |
|---|
| 128 | + } |
|---|
| 129 | + buf[st.st_size] = '\0'; |
|---|
| 130 | + |
|---|
| 131 | + close(fd); |
|---|
| 132 | + |
|---|
| 133 | + return buf; |
|---|
| 134 | +} |
|---|
| 135 | + |
|---|
| 136 | +char *get_line(char **stringp) |
|---|
| 137 | +{ |
|---|
| 138 | + char *orig = *stringp, *next; |
|---|
| 139 | + |
|---|
| 140 | + /* do not return the unwanted extra line at EOF */ |
|---|
| 141 | + if (!orig || *orig == '\0') |
|---|
| 142 | + return NULL; |
|---|
| 143 | + |
|---|
| 144 | + /* don't use strsep here, it is not available everywhere */ |
|---|
| 145 | + next = strchr(orig, '\n'); |
|---|
| 146 | + if (next) |
|---|
| 147 | + *next++ = '\0'; |
|---|
| 148 | + |
|---|
| 149 | + *stringp = next; |
|---|
| 150 | + |
|---|
| 151 | + return orig; |
|---|
| 119 | 152 | } |
|---|
| 120 | 153 | |
|---|
| 121 | 154 | /* A list of all modules we processed */ |
|---|
| .. | .. |
|---|
| 134 | 167 | static struct module *new_module(const char *modname) |
|---|
| 135 | 168 | { |
|---|
| 136 | 169 | struct module *mod; |
|---|
| 137 | | - char *p; |
|---|
| 138 | 170 | |
|---|
| 139 | | - mod = NOFAIL(malloc(sizeof(*mod))); |
|---|
| 171 | + mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1)); |
|---|
| 140 | 172 | memset(mod, 0, sizeof(*mod)); |
|---|
| 141 | | - p = NOFAIL(strdup(modname)); |
|---|
| 142 | | - |
|---|
| 143 | | - /* strip trailing .o */ |
|---|
| 144 | | - if (strends(p, ".o")) { |
|---|
| 145 | | - p[strlen(p) - 2] = '\0'; |
|---|
| 146 | | - mod->is_dot_o = 1; |
|---|
| 147 | | - } |
|---|
| 148 | | - /* strip trailing .lto */ |
|---|
| 149 | | - if (strends(p, ".lto")) |
|---|
| 150 | | - p[strlen(p) - 4] = '\0'; |
|---|
| 151 | 173 | |
|---|
| 152 | 174 | /* add to list */ |
|---|
| 153 | | - mod->name = p; |
|---|
| 175 | + strcpy(mod->name, modname); |
|---|
| 176 | + mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0); |
|---|
| 154 | 177 | mod->gpl_compatible = -1; |
|---|
| 155 | 178 | mod->next = modules; |
|---|
| 156 | 179 | modules = mod; |
|---|
| 180 | + |
|---|
| 181 | + if (mod->is_vmlinux) |
|---|
| 182 | + have_vmlinux = 1; |
|---|
| 157 | 183 | |
|---|
| 158 | 184 | return mod; |
|---|
| 159 | 185 | } |
|---|
| .. | .. |
|---|
| 168 | 194 | struct module *module; |
|---|
| 169 | 195 | unsigned int crc; |
|---|
| 170 | 196 | int crc_valid; |
|---|
| 197 | + char *namespace; |
|---|
| 171 | 198 | unsigned int weak:1; |
|---|
| 172 | | - unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ |
|---|
| 173 | | - unsigned int kernel:1; /* 1 if symbol is from kernel |
|---|
| 174 | | - * (only for external modules) **/ |
|---|
| 175 | | - unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */ |
|---|
| 199 | + unsigned int is_static:1; /* 1 if symbol is not global */ |
|---|
| 176 | 200 | enum export export; /* Type of export */ |
|---|
| 177 | | - char name[0]; |
|---|
| 201 | + char name[]; |
|---|
| 178 | 202 | }; |
|---|
| 179 | 203 | |
|---|
| 180 | 204 | static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; |
|---|
| .. | .. |
|---|
| 205 | 229 | strcpy(s->name, name); |
|---|
| 206 | 230 | s->weak = weak; |
|---|
| 207 | 231 | s->next = next; |
|---|
| 232 | + s->is_static = 1; |
|---|
| 208 | 233 | return s; |
|---|
| 209 | 234 | } |
|---|
| 210 | 235 | |
|---|
| .. | .. |
|---|
| 213 | 238 | enum export export) |
|---|
| 214 | 239 | { |
|---|
| 215 | 240 | unsigned int hash; |
|---|
| 216 | | - struct symbol *new; |
|---|
| 217 | 241 | |
|---|
| 218 | 242 | hash = tdb_hash(name) % SYMBOL_HASH_SIZE; |
|---|
| 219 | | - new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); |
|---|
| 220 | | - new->module = module; |
|---|
| 221 | | - new->export = export; |
|---|
| 222 | | - return new; |
|---|
| 243 | + symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); |
|---|
| 244 | + |
|---|
| 245 | + return symbolhash[hash]; |
|---|
| 223 | 246 | } |
|---|
| 224 | 247 | |
|---|
| 225 | 248 | static struct symbol *find_symbol(const char *name) |
|---|
| .. | .. |
|---|
| 235 | 258 | return s; |
|---|
| 236 | 259 | } |
|---|
| 237 | 260 | return NULL; |
|---|
| 261 | +} |
|---|
| 262 | + |
|---|
| 263 | +static bool contains_namespace(struct namespace_list *list, |
|---|
| 264 | + const char *namespace) |
|---|
| 265 | +{ |
|---|
| 266 | + for (; list; list = list->next) |
|---|
| 267 | + if (!strcmp(list->namespace, namespace)) |
|---|
| 268 | + return true; |
|---|
| 269 | + |
|---|
| 270 | + return false; |
|---|
| 271 | +} |
|---|
| 272 | + |
|---|
| 273 | +static void add_namespace(struct namespace_list **list, const char *namespace) |
|---|
| 274 | +{ |
|---|
| 275 | + struct namespace_list *ns_entry; |
|---|
| 276 | + |
|---|
| 277 | + if (!contains_namespace(*list, namespace)) { |
|---|
| 278 | + ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) + |
|---|
| 279 | + strlen(namespace) + 1)); |
|---|
| 280 | + strcpy(ns_entry->namespace, namespace); |
|---|
| 281 | + ns_entry->next = *list; |
|---|
| 282 | + *list = ns_entry; |
|---|
| 283 | + } |
|---|
| 284 | +} |
|---|
| 285 | + |
|---|
| 286 | +static bool module_imports_namespace(struct module *module, |
|---|
| 287 | + const char *namespace) |
|---|
| 288 | +{ |
|---|
| 289 | + return contains_namespace(module->imported_namespaces, namespace); |
|---|
| 238 | 290 | } |
|---|
| 239 | 291 | |
|---|
| 240 | 292 | static const struct { |
|---|
| .. | .. |
|---|
| 268 | 320 | return export_unknown; |
|---|
| 269 | 321 | } |
|---|
| 270 | 322 | |
|---|
| 271 | | -static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) |
|---|
| 323 | +static void *sym_get_data_by_offset(const struct elf_info *info, |
|---|
| 324 | + unsigned int secindex, unsigned long offset) |
|---|
| 272 | 325 | { |
|---|
| 273 | | - return (void *)elf->hdr + |
|---|
| 274 | | - elf->sechdrs[elf->secindex_strings].sh_offset + |
|---|
| 275 | | - sechdr->sh_name; |
|---|
| 326 | + Elf_Shdr *sechdr = &info->sechdrs[secindex]; |
|---|
| 327 | + |
|---|
| 328 | + if (info->hdr->e_type != ET_REL) |
|---|
| 329 | + offset -= sechdr->sh_addr; |
|---|
| 330 | + |
|---|
| 331 | + return (void *)info->hdr + sechdr->sh_offset + offset; |
|---|
| 276 | 332 | } |
|---|
| 277 | 333 | |
|---|
| 278 | | -static const char *sec_name(struct elf_info *elf, int secindex) |
|---|
| 334 | +static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) |
|---|
| 279 | 335 | { |
|---|
| 280 | | - return sech_name(elf, &elf->sechdrs[secindex]); |
|---|
| 336 | + return sym_get_data_by_offset(info, get_secindex(info, sym), |
|---|
| 337 | + sym->st_value); |
|---|
| 338 | +} |
|---|
| 339 | + |
|---|
| 340 | +static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr) |
|---|
| 341 | +{ |
|---|
| 342 | + return sym_get_data_by_offset(info, info->secindex_strings, |
|---|
| 343 | + sechdr->sh_name); |
|---|
| 344 | +} |
|---|
| 345 | + |
|---|
| 346 | +static const char *sec_name(const struct elf_info *info, int secindex) |
|---|
| 347 | +{ |
|---|
| 348 | + return sech_name(info, &info->sechdrs[secindex]); |
|---|
| 281 | 349 | } |
|---|
| 282 | 350 | |
|---|
| 283 | 351 | #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) |
|---|
| .. | .. |
|---|
| 316 | 384 | return export_unknown; |
|---|
| 317 | 385 | } |
|---|
| 318 | 386 | |
|---|
| 387 | +static const char *namespace_from_kstrtabns(const struct elf_info *info, |
|---|
| 388 | + const Elf_Sym *sym) |
|---|
| 389 | +{ |
|---|
| 390 | + const char *value = sym_get_data(info, sym); |
|---|
| 391 | + return value[0] ? value : NULL; |
|---|
| 392 | +} |
|---|
| 393 | + |
|---|
| 394 | +static void sym_update_namespace(const char *symname, const char *namespace) |
|---|
| 395 | +{ |
|---|
| 396 | + struct symbol *s = find_symbol(symname); |
|---|
| 397 | + |
|---|
| 398 | + /* |
|---|
| 399 | + * That symbol should have been created earlier and thus this is |
|---|
| 400 | + * actually an assertion. |
|---|
| 401 | + */ |
|---|
| 402 | + if (!s) { |
|---|
| 403 | + error("Could not update namespace(%s) for symbol %s\n", |
|---|
| 404 | + namespace, symname); |
|---|
| 405 | + return; |
|---|
| 406 | + } |
|---|
| 407 | + |
|---|
| 408 | + free(s->namespace); |
|---|
| 409 | + s->namespace = |
|---|
| 410 | + namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL; |
|---|
| 411 | +} |
|---|
| 412 | + |
|---|
| 319 | 413 | /** |
|---|
| 320 | 414 | * Add an exported symbol - it may have already been added without a |
|---|
| 321 | 415 | * CRC, in this case just update the CRC |
|---|
| .. | .. |
|---|
| 327 | 421 | |
|---|
| 328 | 422 | if (!s) { |
|---|
| 329 | 423 | s = new_symbol(name, mod, export); |
|---|
| 330 | | - } else { |
|---|
| 331 | | - if (!s->preloaded) { |
|---|
| 332 | | - warn("%s: '%s' exported twice. Previous export " |
|---|
| 333 | | - "was in %s%s\n", mod->name, name, |
|---|
| 334 | | - s->module->name, |
|---|
| 335 | | - is_vmlinux(s->module->name) ?"":".ko"); |
|---|
| 336 | | - } else { |
|---|
| 337 | | - /* In case Module.symvers was out of date */ |
|---|
| 338 | | - s->module = mod; |
|---|
| 339 | | - } |
|---|
| 424 | + } else if (!external_module || s->module->is_vmlinux || |
|---|
| 425 | + s->module == mod) { |
|---|
| 426 | + fatal("%s: '%s' exported twice. Previous export was in %s%s\n", |
|---|
| 427 | + mod->name, name, s->module->name, |
|---|
| 428 | + s->module->is_vmlinux ? "" : ".ko"); |
|---|
| 340 | 429 | } |
|---|
| 341 | | - s->preloaded = 0; |
|---|
| 342 | | - s->vmlinux = is_vmlinux(mod->name); |
|---|
| 343 | | - s->kernel = 0; |
|---|
| 430 | + |
|---|
| 431 | + s->module = mod; |
|---|
| 344 | 432 | s->export = export; |
|---|
| 345 | 433 | return s; |
|---|
| 346 | 434 | } |
|---|
| 347 | 435 | |
|---|
| 348 | | -static void sym_update_crc(const char *name, struct module *mod, |
|---|
| 349 | | - unsigned int crc, enum export export) |
|---|
| 436 | +static void sym_set_crc(const char *name, unsigned int crc) |
|---|
| 350 | 437 | { |
|---|
| 351 | 438 | struct symbol *s = find_symbol(name); |
|---|
| 352 | 439 | |
|---|
| 353 | | - if (!s) { |
|---|
| 354 | | - s = new_symbol(name, mod, export); |
|---|
| 355 | | - /* Don't complain when we find it later. */ |
|---|
| 356 | | - s->preloaded = 1; |
|---|
| 357 | | - } |
|---|
| 440 | + /* |
|---|
| 441 | + * Ignore stand-alone __crc_*, which might be auto-generated symbols |
|---|
| 442 | + * such as __*_veneer in ARM ELF. |
|---|
| 443 | + */ |
|---|
| 444 | + if (!s) |
|---|
| 445 | + return; |
|---|
| 446 | + |
|---|
| 358 | 447 | s->crc = crc; |
|---|
| 359 | 448 | s->crc_valid = 1; |
|---|
| 360 | 449 | } |
|---|
| 361 | 450 | |
|---|
| 362 | | -void *grab_file(const char *filename, unsigned long *size) |
|---|
| 451 | +static void *grab_file(const char *filename, size_t *size) |
|---|
| 363 | 452 | { |
|---|
| 364 | 453 | struct stat st; |
|---|
| 365 | 454 | void *map = MAP_FAILED; |
|---|
| .. | .. |
|---|
| 381 | 470 | return map; |
|---|
| 382 | 471 | } |
|---|
| 383 | 472 | |
|---|
| 384 | | -/** |
|---|
| 385 | | - * Return a copy of the next line in a mmap'ed file. |
|---|
| 386 | | - * spaces in the beginning of the line is trimmed away. |
|---|
| 387 | | - * Return a pointer to a static buffer. |
|---|
| 388 | | - **/ |
|---|
| 389 | | -char *get_next_line(unsigned long *pos, void *file, unsigned long size) |
|---|
| 390 | | -{ |
|---|
| 391 | | - static char line[4096]; |
|---|
| 392 | | - int skip = 1; |
|---|
| 393 | | - size_t len = 0; |
|---|
| 394 | | - signed char *p = (signed char *)file + *pos; |
|---|
| 395 | | - char *s = line; |
|---|
| 396 | | - |
|---|
| 397 | | - for (; *pos < size ; (*pos)++) { |
|---|
| 398 | | - if (skip && isspace(*p)) { |
|---|
| 399 | | - p++; |
|---|
| 400 | | - continue; |
|---|
| 401 | | - } |
|---|
| 402 | | - skip = 0; |
|---|
| 403 | | - if (*p != '\n' && (*pos < size)) { |
|---|
| 404 | | - len++; |
|---|
| 405 | | - *s++ = *p++; |
|---|
| 406 | | - if (len > 4095) |
|---|
| 407 | | - break; /* Too long, stop */ |
|---|
| 408 | | - } else { |
|---|
| 409 | | - /* End of string */ |
|---|
| 410 | | - *s = '\0'; |
|---|
| 411 | | - return line; |
|---|
| 412 | | - } |
|---|
| 413 | | - } |
|---|
| 414 | | - /* End of buffer */ |
|---|
| 415 | | - return NULL; |
|---|
| 416 | | -} |
|---|
| 417 | | - |
|---|
| 418 | | -void release_file(void *file, unsigned long size) |
|---|
| 473 | +static void release_file(void *file, size_t size) |
|---|
| 419 | 474 | { |
|---|
| 420 | 475 | munmap(file, size); |
|---|
| 421 | 476 | } |
|---|
| .. | .. |
|---|
| 471 | 526 | |
|---|
| 472 | 527 | /* Check if file offset is correct */ |
|---|
| 473 | 528 | if (hdr->e_shoff > info->size) { |
|---|
| 474 | | - fatal("section header offset=%lu in file '%s' is bigger than " |
|---|
| 475 | | - "filesize=%lu\n", (unsigned long)hdr->e_shoff, |
|---|
| 476 | | - filename, info->size); |
|---|
| 529 | + fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n", |
|---|
| 530 | + (unsigned long)hdr->e_shoff, filename, info->size); |
|---|
| 477 | 531 | return 0; |
|---|
| 478 | 532 | } |
|---|
| 479 | 533 | |
|---|
| .. | .. |
|---|
| 618 | 672 | return 0; |
|---|
| 619 | 673 | } |
|---|
| 620 | 674 | |
|---|
| 621 | | -static void handle_modversions(struct module *mod, struct elf_info *info, |
|---|
| 622 | | - Elf_Sym *sym, const char *symname) |
|---|
| 675 | +static void handle_modversion(const struct module *mod, |
|---|
| 676 | + const struct elf_info *info, |
|---|
| 677 | + const Elf_Sym *sym, const char *symname) |
|---|
| 623 | 678 | { |
|---|
| 624 | 679 | unsigned int crc; |
|---|
| 625 | | - enum export export; |
|---|
| 626 | | - bool is_crc = false; |
|---|
| 627 | 680 | |
|---|
| 628 | | - if ((!is_vmlinux(mod->name) || mod->is_dot_o) && |
|---|
| 629 | | - strstarts(symname, "__ksymtab")) |
|---|
| 681 | + if (sym->st_shndx == SHN_UNDEF) { |
|---|
| 682 | + warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", |
|---|
| 683 | + symname, mod->name, mod->is_vmlinux ? "" : ".ko"); |
|---|
| 684 | + return; |
|---|
| 685 | + } |
|---|
| 686 | + |
|---|
| 687 | + if (sym->st_shndx == SHN_ABS) { |
|---|
| 688 | + crc = sym->st_value; |
|---|
| 689 | + } else { |
|---|
| 690 | + unsigned int *crcp; |
|---|
| 691 | + |
|---|
| 692 | + /* symbol points to the CRC in the ELF object */ |
|---|
| 693 | + crcp = sym_get_data(info, sym); |
|---|
| 694 | + crc = TO_NATIVE(*crcp); |
|---|
| 695 | + } |
|---|
| 696 | + sym_set_crc(symname, crc); |
|---|
| 697 | +} |
|---|
| 698 | + |
|---|
| 699 | +static void handle_symbol(struct module *mod, struct elf_info *info, |
|---|
| 700 | + const Elf_Sym *sym, const char *symname) |
|---|
| 701 | +{ |
|---|
| 702 | + enum export export; |
|---|
| 703 | + const char *name; |
|---|
| 704 | + |
|---|
| 705 | + if (strstarts(symname, "__ksymtab")) |
|---|
| 630 | 706 | export = export_from_secname(info, get_secindex(info, sym)); |
|---|
| 631 | 707 | else |
|---|
| 632 | 708 | export = export_from_sec(info, get_secindex(info, sym)); |
|---|
| 633 | | - |
|---|
| 634 | | - /* CRC'd symbol */ |
|---|
| 635 | | - if (strstarts(symname, "__crc_")) { |
|---|
| 636 | | - is_crc = true; |
|---|
| 637 | | - crc = (unsigned int) sym->st_value; |
|---|
| 638 | | - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) { |
|---|
| 639 | | - unsigned int *crcp; |
|---|
| 640 | | - |
|---|
| 641 | | - /* symbol points to the CRC in the ELF object */ |
|---|
| 642 | | - crcp = (void *)info->hdr + sym->st_value + |
|---|
| 643 | | - info->sechdrs[sym->st_shndx].sh_offset - |
|---|
| 644 | | - (info->hdr->e_type != ET_REL ? |
|---|
| 645 | | - info->sechdrs[sym->st_shndx].sh_addr : 0); |
|---|
| 646 | | - crc = TO_NATIVE(*crcp); |
|---|
| 647 | | - } |
|---|
| 648 | | - sym_update_crc(symname + strlen("__crc_"), mod, crc, |
|---|
| 649 | | - export); |
|---|
| 650 | | - } |
|---|
| 651 | 709 | |
|---|
| 652 | 710 | switch (sym->st_shndx) { |
|---|
| 653 | 711 | case SHN_COMMON: |
|---|
| .. | .. |
|---|
| 663 | 721 | break; |
|---|
| 664 | 722 | if (ignore_undef_symbol(info, symname)) |
|---|
| 665 | 723 | break; |
|---|
| 666 | | -/* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ |
|---|
| 667 | | -#if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) |
|---|
| 668 | | -/* add compatibility with older glibc */ |
|---|
| 669 | | -#ifndef STT_SPARC_REGISTER |
|---|
| 670 | | -#define STT_SPARC_REGISTER STT_REGISTER |
|---|
| 671 | | -#endif |
|---|
| 672 | 724 | if (info->hdr->e_machine == EM_SPARC || |
|---|
| 673 | 725 | info->hdr->e_machine == EM_SPARCV9) { |
|---|
| 674 | 726 | /* Ignore register directives. */ |
|---|
| .. | .. |
|---|
| 681 | 733 | symname = munged; |
|---|
| 682 | 734 | } |
|---|
| 683 | 735 | } |
|---|
| 684 | | -#endif |
|---|
| 685 | 736 | |
|---|
| 686 | | - if (is_crc) { |
|---|
| 687 | | - const char *e = is_vmlinux(mod->name) ?"":".ko"; |
|---|
| 688 | | - warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", |
|---|
| 689 | | - symname + strlen("__crc_"), mod->name, e); |
|---|
| 690 | | - } |
|---|
| 691 | 737 | mod->unres = alloc_symbol(symname, |
|---|
| 692 | 738 | ELF_ST_BIND(sym->st_info) == STB_WEAK, |
|---|
| 693 | 739 | mod->unres); |
|---|
| .. | .. |
|---|
| 695 | 741 | default: |
|---|
| 696 | 742 | /* All exported symbols */ |
|---|
| 697 | 743 | if (strstarts(symname, "__ksymtab_")) { |
|---|
| 698 | | - sym_add_exported(symname + strlen("__ksymtab_"), mod, |
|---|
| 699 | | - export); |
|---|
| 744 | + name = symname + strlen("__ksymtab_"); |
|---|
| 745 | + sym_add_exported(name, mod, export); |
|---|
| 700 | 746 | } |
|---|
| 701 | 747 | if (strcmp(symname, "init_module") == 0) |
|---|
| 702 | 748 | mod->has_init = 1; |
|---|
| .. | .. |
|---|
| 799 | 845 | |
|---|
| 800 | 846 | /* "*foo*" */ |
|---|
| 801 | 847 | if (*p == '*' && *endp == '*') { |
|---|
| 802 | | - char *here, *bare = strndup(p + 1, strlen(p) - 2); |
|---|
| 848 | + char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2)); |
|---|
| 849 | + char *here = strstr(sym, bare); |
|---|
| 803 | 850 | |
|---|
| 804 | | - here = strstr(sym, bare); |
|---|
| 805 | 851 | free(bare); |
|---|
| 806 | 852 | if (here != NULL) |
|---|
| 807 | 853 | return 1; |
|---|
| .. | .. |
|---|
| 945 | 991 | static const char *const linker_symbols[] = |
|---|
| 946 | 992 | { "__init_begin", "_sinittext", "_einittext", NULL }; |
|---|
| 947 | 993 | static const char *const optim_symbols[] = { "*.constprop.*", NULL }; |
|---|
| 948 | | -static const char *const cfi_symbols[] = { "*.cfi", NULL }; |
|---|
| 949 | 994 | |
|---|
| 950 | 995 | enum mismatch { |
|---|
| 951 | 996 | TEXT_TO_ANY_INIT, |
|---|
| .. | .. |
|---|
| 1070 | 1115 | }, |
|---|
| 1071 | 1116 | /* Do not export init/exit functions or data */ |
|---|
| 1072 | 1117 | { |
|---|
| 1073 | | - .fromsec = { "__ksymtab*", NULL }, |
|---|
| 1118 | + .fromsec = { "___ksymtab*", NULL }, |
|---|
| 1074 | 1119 | .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, |
|---|
| 1075 | 1120 | .mismatch = EXPORT_TO_INIT_EXIT, |
|---|
| 1076 | 1121 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
|---|
| .. | .. |
|---|
| 1175 | 1220 | * whitelisting, which relies on pattern-matching against symbol |
|---|
| 1176 | 1221 | * names to work. (One situation where gcc can autogenerate ELF |
|---|
| 1177 | 1222 | * local symbols is when "-fsection-anchors" is used.) |
|---|
| 1178 | | - * |
|---|
| 1179 | | - * Pattern 7: |
|---|
| 1180 | | - * With CONFIG_CFI_CLANG, clang appends .cfi to all indirectly called |
|---|
| 1181 | | - * functions and creates a function stub with the original name. This |
|---|
| 1182 | | - * stub is always placed in .text, even if the actual function with the |
|---|
| 1183 | | - * .cfi postfix is in .init.text or .exit.text. |
|---|
| 1184 | | - * This pattern is identified by |
|---|
| 1185 | | - * tosec = init or exit section |
|---|
| 1186 | | - * fromsec = text section |
|---|
| 1187 | | - * tosym = *.cfi |
|---|
| 1188 | | - * |
|---|
| 1189 | 1223 | **/ |
|---|
| 1190 | 1224 | static int secref_whitelist(const struct sectioncheck *mismatch, |
|---|
| 1191 | 1225 | const char *fromsec, const char *fromsym, |
|---|
| .. | .. |
|---|
| 1228 | 1262 | if (strstarts(fromsym, ".L")) |
|---|
| 1229 | 1263 | return 0; |
|---|
| 1230 | 1264 | |
|---|
| 1231 | | - /* Check for pattern 7 */ |
|---|
| 1232 | | - if (match(fromsec, text_sections) && |
|---|
| 1233 | | - match(tosec, init_exit_sections) && |
|---|
| 1234 | | - match(tosym, cfi_symbols)) |
|---|
| 1235 | | - return 0; |
|---|
| 1236 | | - |
|---|
| 1237 | 1265 | return 1; |
|---|
| 1238 | 1266 | } |
|---|
| 1239 | 1267 | |
|---|
| 1240 | 1268 | static inline int is_arm_mapping_symbol(const char *str) |
|---|
| 1241 | 1269 | { |
|---|
| 1242 | | - return str[0] == '$' && strchr("axtd", str[1]) |
|---|
| 1270 | + return str[0] == '$' && |
|---|
| 1271 | + (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x') |
|---|
| 1243 | 1272 | && (str[2] == '\0' || str[2] == '.'); |
|---|
| 1244 | 1273 | } |
|---|
| 1245 | 1274 | |
|---|
| .. | .. |
|---|
| 1280 | 1309 | if (relsym->st_name != 0) |
|---|
| 1281 | 1310 | return relsym; |
|---|
| 1282 | 1311 | |
|---|
| 1312 | + /* |
|---|
| 1313 | + * Strive to find a better symbol name, but the resulting name may not |
|---|
| 1314 | + * match the symbol referenced in the original code. |
|---|
| 1315 | + */ |
|---|
| 1283 | 1316 | relsym_secindex = get_secindex(elf, relsym); |
|---|
| 1284 | 1317 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { |
|---|
| 1285 | 1318 | if (get_secindex(elf, sym) != relsym_secindex) |
|---|
| .. | .. |
|---|
| 1427 | 1460 | char *prl_to; |
|---|
| 1428 | 1461 | |
|---|
| 1429 | 1462 | sec_mismatch_count++; |
|---|
| 1430 | | - if (!sec_mismatch_verbose) |
|---|
| 1431 | | - return; |
|---|
| 1432 | 1463 | |
|---|
| 1433 | 1464 | get_pretty_name(from_is_func, &from, &from_p); |
|---|
| 1434 | 1465 | get_pretty_name(to_is_func, &to, &to_p); |
|---|
| .. | .. |
|---|
| 1586 | 1617 | |
|---|
| 1587 | 1618 | static int is_executable_section(struct elf_info* elf, unsigned int section_index) |
|---|
| 1588 | 1619 | { |
|---|
| 1589 | | - if (section_index > elf->num_sections) |
|---|
| 1620 | + if (section_index >= elf->num_sections) |
|---|
| 1590 | 1621 | fatal("section_index is outside elf->num_sections!\n"); |
|---|
| 1591 | 1622 | |
|---|
| 1592 | 1623 | return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); |
|---|
| .. | .. |
|---|
| 1676 | 1707 | |
|---|
| 1677 | 1708 | sec_mismatch_count++; |
|---|
| 1678 | 1709 | |
|---|
| 1679 | | - if (sec_mismatch_verbose) |
|---|
| 1680 | | - report_extable_warnings(modname, elf, mismatch, r, sym, |
|---|
| 1681 | | - fromsec, tosec); |
|---|
| 1710 | + report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec); |
|---|
| 1682 | 1711 | |
|---|
| 1683 | 1712 | if (match(tosec, mismatch->bad_tosec)) |
|---|
| 1684 | 1713 | fatal("The relocation at %s+0x%lx references\n" |
|---|
| .. | .. |
|---|
| 1724 | 1753 | static unsigned int *reloc_location(struct elf_info *elf, |
|---|
| 1725 | 1754 | Elf_Shdr *sechdr, Elf_Rela *r) |
|---|
| 1726 | 1755 | { |
|---|
| 1727 | | - Elf_Shdr *sechdrs = elf->sechdrs; |
|---|
| 1728 | | - int section = sechdr->sh_info; |
|---|
| 1729 | | - |
|---|
| 1730 | | - return (void *)elf->hdr + sechdrs[section].sh_offset + |
|---|
| 1731 | | - r->r_offset; |
|---|
| 1756 | + return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset); |
|---|
| 1732 | 1757 | } |
|---|
| 1733 | 1758 | |
|---|
| 1734 | 1759 | static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) |
|---|
| .. | .. |
|---|
| 1767 | 1792 | #define R_ARM_THM_JUMP19 51 |
|---|
| 1768 | 1793 | #endif |
|---|
| 1769 | 1794 | |
|---|
| 1795 | +static int32_t sign_extend32(int32_t value, int index) |
|---|
| 1796 | +{ |
|---|
| 1797 | + uint8_t shift = 31 - index; |
|---|
| 1798 | + |
|---|
| 1799 | + return (int32_t)(value << shift) >> shift; |
|---|
| 1800 | +} |
|---|
| 1801 | + |
|---|
| 1770 | 1802 | static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) |
|---|
| 1771 | 1803 | { |
|---|
| 1772 | 1804 | unsigned int r_typ = ELF_R_TYPE(r->r_info); |
|---|
| 1805 | + Elf_Sym *sym = elf->symtab_start + ELF_R_SYM(r->r_info); |
|---|
| 1806 | + void *loc = reloc_location(elf, sechdr, r); |
|---|
| 1807 | + uint32_t inst; |
|---|
| 1808 | + int32_t offset; |
|---|
| 1773 | 1809 | |
|---|
| 1774 | 1810 | switch (r_typ) { |
|---|
| 1775 | 1811 | case R_ARM_ABS32: |
|---|
| 1776 | | - /* From ARM ABI: (S + A) | T */ |
|---|
| 1777 | | - r->r_addend = (int)(long) |
|---|
| 1778 | | - (elf->symtab_start + ELF_R_SYM(r->r_info)); |
|---|
| 1812 | + inst = TO_NATIVE(*(uint32_t *)loc); |
|---|
| 1813 | + r->r_addend = inst + sym->st_value; |
|---|
| 1779 | 1814 | break; |
|---|
| 1780 | 1815 | case R_ARM_PC24: |
|---|
| 1781 | 1816 | case R_ARM_CALL: |
|---|
| 1782 | 1817 | case R_ARM_JUMP24: |
|---|
| 1818 | + inst = TO_NATIVE(*(uint32_t *)loc); |
|---|
| 1819 | + offset = sign_extend32((inst & 0x00ffffff) << 2, 25); |
|---|
| 1820 | + r->r_addend = offset + sym->st_value + 8; |
|---|
| 1821 | + break; |
|---|
| 1783 | 1822 | case R_ARM_THM_CALL: |
|---|
| 1784 | 1823 | case R_ARM_THM_JUMP24: |
|---|
| 1785 | 1824 | case R_ARM_THM_JUMP19: |
|---|
| .. | .. |
|---|
| 1958 | 1997 | |
|---|
| 1959 | 1998 | if (n && s[n]) { |
|---|
| 1960 | 1999 | size_t m = strspn(s + n + 1, "0123456789"); |
|---|
| 1961 | | - if (m && (s[n + m] == '.' || s[n + m] == 0)) |
|---|
| 2000 | + if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0)) |
|---|
| 1962 | 2001 | s[n] = 0; |
|---|
| 1963 | 2002 | |
|---|
| 1964 | 2003 | /* strip trailing .lto */ |
|---|
| .. | .. |
|---|
| 1973 | 2012 | const char *symname; |
|---|
| 1974 | 2013 | char *version; |
|---|
| 1975 | 2014 | char *license; |
|---|
| 2015 | + char *namespace; |
|---|
| 1976 | 2016 | struct module *mod; |
|---|
| 1977 | 2017 | struct elf_info info = { }; |
|---|
| 1978 | 2018 | Elf_Sym *sym; |
|---|
| .. | .. |
|---|
| 1980 | 2020 | if (!parse_elf(&info, modname)) |
|---|
| 1981 | 2021 | return; |
|---|
| 1982 | 2022 | |
|---|
| 1983 | | - mod = new_module(modname); |
|---|
| 2023 | + { |
|---|
| 2024 | + char *tmp; |
|---|
| 1984 | 2025 | |
|---|
| 1985 | | - /* When there's no vmlinux, don't print warnings about |
|---|
| 1986 | | - * unresolved symbols (since there'll be too many ;) */ |
|---|
| 1987 | | - if (is_vmlinux(modname)) { |
|---|
| 1988 | | - have_vmlinux = 1; |
|---|
| 1989 | | - mod->skip = 1; |
|---|
| 2026 | + /* strip trailing .o */ |
|---|
| 2027 | + tmp = NOFAIL(strdup(modname)); |
|---|
| 2028 | + tmp[strlen(tmp) - 2] = '\0'; |
|---|
| 2029 | + /* strip trailing .lto */ |
|---|
| 2030 | + if (strends(tmp, ".lto")) |
|---|
| 2031 | + tmp[strlen(tmp) - 4] = '\0'; |
|---|
| 2032 | + mod = new_module(tmp); |
|---|
| 2033 | + free(tmp); |
|---|
| 1990 | 2034 | } |
|---|
| 1991 | 2035 | |
|---|
| 1992 | | - license = get_modinfo(&info, "license"); |
|---|
| 1993 | | - if (!license && !is_vmlinux(modname)) |
|---|
| 1994 | | - warn("modpost: missing MODULE_LICENSE() in %s\n" |
|---|
| 1995 | | - "see include/linux/module.h for " |
|---|
| 1996 | | - "more information\n", modname); |
|---|
| 1997 | | - while (license) { |
|---|
| 1998 | | - if (license_is_gpl_compatible(license)) |
|---|
| 1999 | | - mod->gpl_compatible = 1; |
|---|
| 2000 | | - else { |
|---|
| 2001 | | - mod->gpl_compatible = 0; |
|---|
| 2002 | | - break; |
|---|
| 2036 | + if (!mod->is_vmlinux) { |
|---|
| 2037 | + license = get_modinfo(&info, "license"); |
|---|
| 2038 | + if (!license) |
|---|
| 2039 | + error("missing MODULE_LICENSE() in %s\n", modname); |
|---|
| 2040 | + while (license) { |
|---|
| 2041 | + if (license_is_gpl_compatible(license)) |
|---|
| 2042 | + mod->gpl_compatible = 1; |
|---|
| 2043 | + else { |
|---|
| 2044 | + mod->gpl_compatible = 0; |
|---|
| 2045 | + break; |
|---|
| 2046 | + } |
|---|
| 2047 | + license = get_next_modinfo(&info, "license", license); |
|---|
| 2003 | 2048 | } |
|---|
| 2004 | | - license = get_next_modinfo(&info, "license", license); |
|---|
| 2049 | + |
|---|
| 2050 | + namespace = get_modinfo(&info, "import_ns"); |
|---|
| 2051 | + while (namespace) { |
|---|
| 2052 | + add_namespace(&mod->imported_namespaces, namespace); |
|---|
| 2053 | + namespace = get_next_modinfo(&info, "import_ns", |
|---|
| 2054 | + namespace); |
|---|
| 2055 | + } |
|---|
| 2005 | 2056 | } |
|---|
| 2006 | 2057 | |
|---|
| 2007 | 2058 | for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
|---|
| 2008 | 2059 | symname = remove_dot(info.strtab + sym->st_name); |
|---|
| 2009 | 2060 | |
|---|
| 2010 | | - handle_modversions(mod, &info, sym, symname); |
|---|
| 2061 | + handle_symbol(mod, &info, sym, symname); |
|---|
| 2011 | 2062 | handle_moddevtable(mod, &info, sym, symname); |
|---|
| 2012 | 2063 | } |
|---|
| 2013 | | - if (!is_vmlinux(modname) || vmlinux_section_warnings) |
|---|
| 2014 | | - check_sec_ref(mod, modname, &info); |
|---|
| 2015 | 2064 | |
|---|
| 2016 | | - version = get_modinfo(&info, "version"); |
|---|
| 2017 | | - if (version) |
|---|
| 2018 | | - maybe_frob_rcs_version(modname, version, info.modinfo, |
|---|
| 2019 | | - version - (char *)info.hdr); |
|---|
| 2020 | | - if (version || (all_versions && !is_vmlinux(modname))) |
|---|
| 2021 | | - get_src_version(modname, mod->srcversion, |
|---|
| 2022 | | - sizeof(mod->srcversion)-1); |
|---|
| 2065 | + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
|---|
| 2066 | + symname = remove_dot(info.strtab + sym->st_name); |
|---|
| 2067 | + |
|---|
| 2068 | + /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */ |
|---|
| 2069 | + if (strstarts(symname, "__kstrtabns_")) |
|---|
| 2070 | + sym_update_namespace(symname + strlen("__kstrtabns_"), |
|---|
| 2071 | + namespace_from_kstrtabns(&info, |
|---|
| 2072 | + sym)); |
|---|
| 2073 | + |
|---|
| 2074 | + if (strstarts(symname, "__crc_")) |
|---|
| 2075 | + handle_modversion(mod, &info, sym, |
|---|
| 2076 | + symname + strlen("__crc_")); |
|---|
| 2077 | + } |
|---|
| 2078 | + |
|---|
| 2079 | + // check for static EXPORT_SYMBOL_* functions && global vars |
|---|
| 2080 | + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
|---|
| 2081 | + unsigned char bind = ELF_ST_BIND(sym->st_info); |
|---|
| 2082 | + |
|---|
| 2083 | + if (bind == STB_GLOBAL || bind == STB_WEAK) { |
|---|
| 2084 | + struct symbol *s = |
|---|
| 2085 | + find_symbol(remove_dot(info.strtab + |
|---|
| 2086 | + sym->st_name)); |
|---|
| 2087 | + |
|---|
| 2088 | + if (s) |
|---|
| 2089 | + s->is_static = 0; |
|---|
| 2090 | + } |
|---|
| 2091 | + } |
|---|
| 2092 | + |
|---|
| 2093 | + check_sec_ref(mod, modname, &info); |
|---|
| 2094 | + |
|---|
| 2095 | + if (!mod->is_vmlinux) { |
|---|
| 2096 | + version = get_modinfo(&info, "version"); |
|---|
| 2097 | + if (version || all_versions) |
|---|
| 2098 | + get_src_version(modname, mod->srcversion, |
|---|
| 2099 | + sizeof(mod->srcversion) - 1); |
|---|
| 2100 | + } |
|---|
| 2023 | 2101 | |
|---|
| 2024 | 2102 | parse_elf_finish(&info); |
|---|
| 2025 | 2103 | |
|---|
| .. | .. |
|---|
| 2083 | 2161 | |
|---|
| 2084 | 2162 | static void check_for_gpl_usage(enum export exp, const char *m, const char *s) |
|---|
| 2085 | 2163 | { |
|---|
| 2086 | | - const char *e = is_vmlinux(m) ?"":".ko"; |
|---|
| 2087 | | - |
|---|
| 2088 | 2164 | switch (exp) { |
|---|
| 2089 | 2165 | case export_gpl: |
|---|
| 2090 | | - fatal("modpost: GPL-incompatible module %s%s " |
|---|
| 2091 | | - "uses GPL-only symbol '%s'\n", m, e, s); |
|---|
| 2166 | + error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", |
|---|
| 2167 | + m, s); |
|---|
| 2092 | 2168 | break; |
|---|
| 2093 | 2169 | case export_unused_gpl: |
|---|
| 2094 | | - fatal("modpost: GPL-incompatible module %s%s " |
|---|
| 2095 | | - "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); |
|---|
| 2170 | + error("GPL-incompatible module %s.ko uses GPL-only symbol marked UNUSED '%s'\n", |
|---|
| 2171 | + m, s); |
|---|
| 2096 | 2172 | break; |
|---|
| 2097 | 2173 | case export_gpl_future: |
|---|
| 2098 | | - warn("modpost: GPL-incompatible module %s%s " |
|---|
| 2099 | | - "uses future GPL-only symbol '%s'\n", m, e, s); |
|---|
| 2174 | + warn("GPL-incompatible module %s.ko uses future GPL-only symbol '%s'\n", |
|---|
| 2175 | + m, s); |
|---|
| 2100 | 2176 | break; |
|---|
| 2101 | 2177 | case export_plain: |
|---|
| 2102 | 2178 | case export_unused: |
|---|
| .. | .. |
|---|
| 2108 | 2184 | |
|---|
| 2109 | 2185 | static void check_for_unused(enum export exp, const char *m, const char *s) |
|---|
| 2110 | 2186 | { |
|---|
| 2111 | | - const char *e = is_vmlinux(m) ?"":".ko"; |
|---|
| 2112 | | - |
|---|
| 2113 | 2187 | switch (exp) { |
|---|
| 2114 | 2188 | case export_unused: |
|---|
| 2115 | 2189 | case export_unused_gpl: |
|---|
| 2116 | | - warn("modpost: module %s%s " |
|---|
| 2117 | | - "uses symbol '%s' marked UNUSED\n", m, e, s); |
|---|
| 2190 | + warn("module %s.ko uses symbol '%s' marked UNUSED\n", |
|---|
| 2191 | + m, s); |
|---|
| 2118 | 2192 | break; |
|---|
| 2119 | 2193 | default: |
|---|
| 2120 | 2194 | /* ignore */ |
|---|
| .. | .. |
|---|
| 2129 | 2203 | for (s = mod->unres; s; s = s->next) { |
|---|
| 2130 | 2204 | const char *basename; |
|---|
| 2131 | 2205 | exp = find_symbol(s->name); |
|---|
| 2132 | | - if (!exp || exp->module == mod) |
|---|
| 2206 | + if (!exp || exp->module == mod) { |
|---|
| 2207 | + if (have_vmlinux && !s->weak) |
|---|
| 2208 | + modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, |
|---|
| 2209 | + "\"%s\" [%s.ko] undefined!\n", |
|---|
| 2210 | + s->name, mod->name); |
|---|
| 2133 | 2211 | continue; |
|---|
| 2212 | + } |
|---|
| 2134 | 2213 | basename = strrchr(mod->name, '/'); |
|---|
| 2135 | 2214 | if (basename) |
|---|
| 2136 | 2215 | basename++; |
|---|
| 2137 | 2216 | else |
|---|
| 2138 | 2217 | basename = mod->name; |
|---|
| 2218 | + |
|---|
| 2219 | + if (exp->namespace && |
|---|
| 2220 | + !module_imports_namespace(mod, exp->namespace)) { |
|---|
| 2221 | + modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR, |
|---|
| 2222 | + "module %s uses symbol %s from namespace %s, but does not import it.\n", |
|---|
| 2223 | + basename, exp->name, exp->namespace); |
|---|
| 2224 | + add_namespace(&mod->missing_namespaces, exp->namespace); |
|---|
| 2225 | + } |
|---|
| 2226 | + |
|---|
| 2139 | 2227 | if (!mod->gpl_compatible) |
|---|
| 2140 | 2228 | check_for_gpl_usage(exp->export, basename, exp->name); |
|---|
| 2141 | 2229 | check_for_unused(exp->export, basename, exp->name); |
|---|
| 2142 | 2230 | } |
|---|
| 2143 | 2231 | } |
|---|
| 2144 | 2232 | |
|---|
| 2145 | | -static int check_modname_len(struct module *mod) |
|---|
| 2233 | +static void check_modname_len(struct module *mod) |
|---|
| 2146 | 2234 | { |
|---|
| 2147 | 2235 | const char *mod_name; |
|---|
| 2148 | 2236 | |
|---|
| .. | .. |
|---|
| 2151 | 2239 | mod_name = mod->name; |
|---|
| 2152 | 2240 | else |
|---|
| 2153 | 2241 | mod_name++; |
|---|
| 2154 | | - if (strlen(mod_name) >= MODULE_NAME_LEN) { |
|---|
| 2155 | | - merror("module name is too long [%s.ko]\n", mod->name); |
|---|
| 2156 | | - return 1; |
|---|
| 2157 | | - } |
|---|
| 2158 | | - |
|---|
| 2159 | | - return 0; |
|---|
| 2242 | + if (strlen(mod_name) >= MODULE_NAME_LEN) |
|---|
| 2243 | + error("module name is too long [%s.ko]\n", mod->name); |
|---|
| 2160 | 2244 | } |
|---|
| 2161 | 2245 | |
|---|
| 2162 | 2246 | /** |
|---|
| .. | .. |
|---|
| 2169 | 2253 | * Include build-salt.h after module.h in order to |
|---|
| 2170 | 2254 | * inherit the definitions. |
|---|
| 2171 | 2255 | */ |
|---|
| 2256 | + buf_printf(b, "#define INCLUDE_VERMAGIC\n"); |
|---|
| 2172 | 2257 | buf_printf(b, "#include <linux/build-salt.h>\n"); |
|---|
| 2173 | 2258 | buf_printf(b, "#include <linux/vermagic.h>\n"); |
|---|
| 2174 | 2259 | buf_printf(b, "#include <linux/compiler.h>\n"); |
|---|
| .. | .. |
|---|
| 2179 | 2264 | buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); |
|---|
| 2180 | 2265 | buf_printf(b, "\n"); |
|---|
| 2181 | 2266 | buf_printf(b, "__visible struct module __this_module\n"); |
|---|
| 2182 | | - buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); |
|---|
| 2267 | + buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); |
|---|
| 2183 | 2268 | buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); |
|---|
| 2184 | 2269 | if (mod->has_init) |
|---|
| 2185 | 2270 | buf_printf(b, "\t.init = init_module,\n"); |
|---|
| .. | .. |
|---|
| 2195 | 2280 | { |
|---|
| 2196 | 2281 | if (is_intree) |
|---|
| 2197 | 2282 | buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); |
|---|
| 2283 | +} |
|---|
| 2284 | + |
|---|
| 2285 | +/** |
|---|
| 2286 | + * add_scmversion() - Adds the MODULE_INFO macro for the scmversion. |
|---|
| 2287 | + * @b: Buffer to append to. |
|---|
| 2288 | + * |
|---|
| 2289 | + * This function fills in the module attribute `scmversion` for the kernel |
|---|
| 2290 | + * module. This is useful for determining a given module's SCM version on |
|---|
| 2291 | + * device via /sys/modules/<module>/scmversion and/or using the modinfo tool. |
|---|
| 2292 | + */ |
|---|
| 2293 | +static void add_scmversion(struct buffer *b) |
|---|
| 2294 | +{ |
|---|
| 2295 | + if (module_scmversion[0] != '\0') |
|---|
| 2296 | + buf_printf(b, "\nMODULE_INFO(scmversion, \"%s\");\n", module_scmversion); |
|---|
| 2198 | 2297 | } |
|---|
| 2199 | 2298 | |
|---|
| 2200 | 2299 | /* Cannot check for assembler */ |
|---|
| .. | .. |
|---|
| 2214 | 2313 | /** |
|---|
| 2215 | 2314 | * Record CRCs for unresolved symbols |
|---|
| 2216 | 2315 | **/ |
|---|
| 2217 | | -static int add_versions(struct buffer *b, struct module *mod) |
|---|
| 2316 | +static void add_versions(struct buffer *b, struct module *mod) |
|---|
| 2218 | 2317 | { |
|---|
| 2219 | 2318 | struct symbol *s, *exp; |
|---|
| 2220 | | - int err = 0; |
|---|
| 2221 | 2319 | |
|---|
| 2222 | 2320 | for (s = mod->unres; s; s = s->next) { |
|---|
| 2223 | 2321 | exp = find_symbol(s->name); |
|---|
| 2224 | | - if (!exp || exp->module == mod) { |
|---|
| 2225 | | - if (have_vmlinux && !s->weak) { |
|---|
| 2226 | | - if (warn_unresolved) { |
|---|
| 2227 | | - warn("\"%s\" [%s.ko] undefined!\n", |
|---|
| 2228 | | - s->name, mod->name); |
|---|
| 2229 | | - } else { |
|---|
| 2230 | | - merror("\"%s\" [%s.ko] undefined!\n", |
|---|
| 2231 | | - s->name, mod->name); |
|---|
| 2232 | | - err = 1; |
|---|
| 2233 | | - } |
|---|
| 2234 | | - } |
|---|
| 2322 | + if (!exp || exp->module == mod) |
|---|
| 2235 | 2323 | continue; |
|---|
| 2236 | | - } |
|---|
| 2237 | 2324 | s->module = exp->module; |
|---|
| 2238 | 2325 | s->crc_valid = exp->crc_valid; |
|---|
| 2239 | 2326 | s->crc = exp->crc; |
|---|
| 2240 | 2327 | } |
|---|
| 2241 | 2328 | |
|---|
| 2242 | 2329 | if (!modversions) |
|---|
| 2243 | | - return err; |
|---|
| 2330 | + return; |
|---|
| 2244 | 2331 | |
|---|
| 2245 | 2332 | buf_printf(b, "\n"); |
|---|
| 2246 | 2333 | buf_printf(b, "static const struct modversion_info ____versions[]\n"); |
|---|
| 2247 | | - buf_printf(b, "__used\n"); |
|---|
| 2248 | | - buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); |
|---|
| 2334 | + buf_printf(b, "__used __section(\"__versions\") = {\n"); |
|---|
| 2249 | 2335 | |
|---|
| 2250 | 2336 | for (s = mod->unres; s; s = s->next) { |
|---|
| 2251 | 2337 | if (!s->module) |
|---|
| .. | .. |
|---|
| 2256 | 2342 | continue; |
|---|
| 2257 | 2343 | } |
|---|
| 2258 | 2344 | if (strlen(s->name) >= MODULE_NAME_LEN) { |
|---|
| 2259 | | - merror("too long symbol \"%s\" [%s.ko]\n", |
|---|
| 2260 | | - s->name, mod->name); |
|---|
| 2261 | | - err = 1; |
|---|
| 2345 | + error("too long symbol \"%s\" [%s.ko]\n", |
|---|
| 2346 | + s->name, mod->name); |
|---|
| 2262 | 2347 | break; |
|---|
| 2263 | 2348 | } |
|---|
| 2264 | 2349 | buf_printf(b, "\t{ %#8x, \"%s\" },\n", |
|---|
| .. | .. |
|---|
| 2266 | 2351 | } |
|---|
| 2267 | 2352 | |
|---|
| 2268 | 2353 | buf_printf(b, "};\n"); |
|---|
| 2269 | | - |
|---|
| 2270 | | - return err; |
|---|
| 2271 | 2354 | } |
|---|
| 2272 | 2355 | |
|---|
| 2273 | | -static void add_depends(struct buffer *b, struct module *mod, |
|---|
| 2274 | | - struct module *modules) |
|---|
| 2356 | +static void add_depends(struct buffer *b, struct module *mod) |
|---|
| 2275 | 2357 | { |
|---|
| 2276 | 2358 | struct symbol *s; |
|---|
| 2277 | | - struct module *m; |
|---|
| 2278 | 2359 | int first = 1; |
|---|
| 2279 | 2360 | |
|---|
| 2280 | | - for (m = modules; m; m = m->next) |
|---|
| 2281 | | - m->seen = is_vmlinux(m->name); |
|---|
| 2361 | + /* Clear ->seen flag of modules that own symbols needed by this. */ |
|---|
| 2362 | + for (s = mod->unres; s; s = s->next) |
|---|
| 2363 | + if (s->module) |
|---|
| 2364 | + s->module->seen = s->module->is_vmlinux; |
|---|
| 2282 | 2365 | |
|---|
| 2283 | 2366 | buf_printf(b, "\n"); |
|---|
| 2284 | | - buf_printf(b, "static const char __module_depends[]\n"); |
|---|
| 2285 | | - buf_printf(b, "__used\n"); |
|---|
| 2286 | | - buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); |
|---|
| 2287 | | - buf_printf(b, "\"depends="); |
|---|
| 2367 | + buf_printf(b, "MODULE_INFO(depends, \""); |
|---|
| 2288 | 2368 | for (s = mod->unres; s; s = s->next) { |
|---|
| 2289 | 2369 | const char *p; |
|---|
| 2290 | 2370 | if (!s->module) |
|---|
| .. | .. |
|---|
| 2302 | 2382 | buf_printf(b, "%s%s", first ? "" : ",", p); |
|---|
| 2303 | 2383 | first = 0; |
|---|
| 2304 | 2384 | } |
|---|
| 2305 | | - buf_printf(b, "\";\n"); |
|---|
| 2385 | + buf_printf(b, "\");\n"); |
|---|
| 2306 | 2386 | } |
|---|
| 2307 | 2387 | |
|---|
| 2308 | 2388 | static void add_srcversion(struct buffer *b, struct module *mod) |
|---|
| .. | .. |
|---|
| 2311 | 2391 | buf_printf(b, "\n"); |
|---|
| 2312 | 2392 | buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", |
|---|
| 2313 | 2393 | mod->srcversion); |
|---|
| 2394 | + } |
|---|
| 2395 | +} |
|---|
| 2396 | + |
|---|
| 2397 | +static void write_buf(struct buffer *b, const char *fname) |
|---|
| 2398 | +{ |
|---|
| 2399 | + FILE *file; |
|---|
| 2400 | + |
|---|
| 2401 | + file = fopen(fname, "w"); |
|---|
| 2402 | + if (!file) { |
|---|
| 2403 | + perror(fname); |
|---|
| 2404 | + exit(1); |
|---|
| 2405 | + } |
|---|
| 2406 | + if (fwrite(b->p, 1, b->pos, file) != b->pos) { |
|---|
| 2407 | + perror(fname); |
|---|
| 2408 | + exit(1); |
|---|
| 2409 | + } |
|---|
| 2410 | + if (fclose(file) != 0) { |
|---|
| 2411 | + perror(fname); |
|---|
| 2412 | + exit(1); |
|---|
| 2314 | 2413 | } |
|---|
| 2315 | 2414 | } |
|---|
| 2316 | 2415 | |
|---|
| .. | .. |
|---|
| 2346 | 2445 | close_write: |
|---|
| 2347 | 2446 | fclose(file); |
|---|
| 2348 | 2447 | write: |
|---|
| 2349 | | - file = fopen(fname, "w"); |
|---|
| 2350 | | - if (!file) { |
|---|
| 2351 | | - perror(fname); |
|---|
| 2352 | | - exit(1); |
|---|
| 2353 | | - } |
|---|
| 2354 | | - if (fwrite(b->p, 1, b->pos, file) != b->pos) { |
|---|
| 2355 | | - perror(fname); |
|---|
| 2356 | | - exit(1); |
|---|
| 2357 | | - } |
|---|
| 2358 | | - fclose(file); |
|---|
| 2448 | + write_buf(b, fname); |
|---|
| 2359 | 2449 | } |
|---|
| 2360 | 2450 | |
|---|
| 2361 | 2451 | /* parse Module.symvers file. line format: |
|---|
| 2362 | | - * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] |
|---|
| 2452 | + * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace |
|---|
| 2363 | 2453 | **/ |
|---|
| 2364 | | -static void read_dump(const char *fname, unsigned int kernel) |
|---|
| 2454 | +static void read_dump(const char *fname) |
|---|
| 2365 | 2455 | { |
|---|
| 2366 | | - unsigned long size, pos = 0; |
|---|
| 2367 | | - void *file = grab_file(fname, &size); |
|---|
| 2368 | | - char *line; |
|---|
| 2456 | + char *buf, *pos, *line; |
|---|
| 2369 | 2457 | |
|---|
| 2370 | | - if (!file) |
|---|
| 2458 | + buf = read_text_file(fname); |
|---|
| 2459 | + if (!buf) |
|---|
| 2371 | 2460 | /* No symbol versions, silently ignore */ |
|---|
| 2372 | 2461 | return; |
|---|
| 2373 | 2462 | |
|---|
| 2374 | | - while ((line = get_next_line(&pos, file, size))) { |
|---|
| 2375 | | - char *symname, *modname, *d, *export, *end; |
|---|
| 2463 | + pos = buf; |
|---|
| 2464 | + |
|---|
| 2465 | + while ((line = get_line(&pos))) { |
|---|
| 2466 | + char *symname, *namespace, *modname, *d, *export; |
|---|
| 2376 | 2467 | unsigned int crc; |
|---|
| 2377 | 2468 | struct module *mod; |
|---|
| 2378 | 2469 | struct symbol *s; |
|---|
| .. | .. |
|---|
| 2383 | 2474 | if (!(modname = strchr(symname, '\t'))) |
|---|
| 2384 | 2475 | goto fail; |
|---|
| 2385 | 2476 | *modname++ = '\0'; |
|---|
| 2386 | | - if ((export = strchr(modname, '\t')) != NULL) |
|---|
| 2387 | | - *export++ = '\0'; |
|---|
| 2388 | | - if (export && ((end = strchr(export, '\t')) != NULL)) |
|---|
| 2389 | | - *end = '\0'; |
|---|
| 2477 | + if (!(export = strchr(modname, '\t'))) |
|---|
| 2478 | + goto fail; |
|---|
| 2479 | + *export++ = '\0'; |
|---|
| 2480 | + if (!(namespace = strchr(export, '\t'))) |
|---|
| 2481 | + goto fail; |
|---|
| 2482 | + *namespace++ = '\0'; |
|---|
| 2483 | + |
|---|
| 2390 | 2484 | crc = strtoul(line, &d, 16); |
|---|
| 2391 | 2485 | if (*symname == '\0' || *modname == '\0' || *d != '\0') |
|---|
| 2392 | 2486 | goto fail; |
|---|
| 2393 | 2487 | mod = find_module(modname); |
|---|
| 2394 | 2488 | if (!mod) { |
|---|
| 2395 | | - if (is_vmlinux(modname)) |
|---|
| 2396 | | - have_vmlinux = 1; |
|---|
| 2397 | 2489 | mod = new_module(modname); |
|---|
| 2398 | | - mod->skip = 1; |
|---|
| 2490 | + mod->from_dump = 1; |
|---|
| 2399 | 2491 | } |
|---|
| 2400 | 2492 | s = sym_add_exported(symname, mod, export_no(export)); |
|---|
| 2401 | | - s->kernel = kernel; |
|---|
| 2402 | | - s->preloaded = 1; |
|---|
| 2403 | | - sym_update_crc(symname, mod, crc, export_no(export)); |
|---|
| 2493 | + s->is_static = 0; |
|---|
| 2494 | + sym_set_crc(symname, crc); |
|---|
| 2495 | + sym_update_namespace(symname, namespace); |
|---|
| 2404 | 2496 | } |
|---|
| 2405 | | - release_file(file, size); |
|---|
| 2497 | + free(buf); |
|---|
| 2406 | 2498 | return; |
|---|
| 2407 | 2499 | fail: |
|---|
| 2408 | | - release_file(file, size); |
|---|
| 2500 | + free(buf); |
|---|
| 2409 | 2501 | fatal("parse error in symbol dump file\n"); |
|---|
| 2410 | | -} |
|---|
| 2411 | | - |
|---|
| 2412 | | -/* For normal builds always dump all symbols. |
|---|
| 2413 | | - * For external modules only dump symbols |
|---|
| 2414 | | - * that are not read from kernel Module.symvers. |
|---|
| 2415 | | - **/ |
|---|
| 2416 | | -static int dump_sym(struct symbol *sym) |
|---|
| 2417 | | -{ |
|---|
| 2418 | | - if (!external_module) |
|---|
| 2419 | | - return 1; |
|---|
| 2420 | | - if (sym->vmlinux || sym->kernel) |
|---|
| 2421 | | - return 0; |
|---|
| 2422 | | - return 1; |
|---|
| 2423 | 2502 | } |
|---|
| 2424 | 2503 | |
|---|
| 2425 | 2504 | static void write_dump(const char *fname) |
|---|
| 2426 | 2505 | { |
|---|
| 2427 | 2506 | struct buffer buf = { }; |
|---|
| 2428 | 2507 | struct symbol *symbol; |
|---|
| 2508 | + const char *namespace; |
|---|
| 2429 | 2509 | int n; |
|---|
| 2430 | 2510 | |
|---|
| 2431 | 2511 | for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { |
|---|
| 2432 | 2512 | symbol = symbolhash[n]; |
|---|
| 2433 | 2513 | while (symbol) { |
|---|
| 2434 | | - if (dump_sym(symbol)) |
|---|
| 2435 | | - buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", |
|---|
| 2436 | | - symbol->crc, symbol->name, |
|---|
| 2437 | | - symbol->module->name, |
|---|
| 2438 | | - export_str(symbol->export)); |
|---|
| 2514 | + if (!symbol->module->from_dump) { |
|---|
| 2515 | + namespace = symbol->namespace; |
|---|
| 2516 | + buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n", |
|---|
| 2517 | + symbol->crc, symbol->name, |
|---|
| 2518 | + symbol->module->name, |
|---|
| 2519 | + export_str(symbol->export), |
|---|
| 2520 | + namespace ? namespace : ""); |
|---|
| 2521 | + } |
|---|
| 2439 | 2522 | symbol = symbol->next; |
|---|
| 2440 | 2523 | } |
|---|
| 2441 | 2524 | } |
|---|
| 2442 | | - write_if_changed(&buf, fname); |
|---|
| 2525 | + write_buf(&buf, fname); |
|---|
| 2443 | 2526 | free(buf.p); |
|---|
| 2444 | 2527 | } |
|---|
| 2445 | 2528 | |
|---|
| 2446 | | -struct ext_sym_list { |
|---|
| 2447 | | - struct ext_sym_list *next; |
|---|
| 2529 | +static void write_namespace_deps_files(const char *fname) |
|---|
| 2530 | +{ |
|---|
| 2531 | + struct module *mod; |
|---|
| 2532 | + struct namespace_list *ns; |
|---|
| 2533 | + struct buffer ns_deps_buf = {}; |
|---|
| 2534 | + |
|---|
| 2535 | + for (mod = modules; mod; mod = mod->next) { |
|---|
| 2536 | + |
|---|
| 2537 | + if (mod->from_dump || !mod->missing_namespaces) |
|---|
| 2538 | + continue; |
|---|
| 2539 | + |
|---|
| 2540 | + buf_printf(&ns_deps_buf, "%s.ko:", mod->name); |
|---|
| 2541 | + |
|---|
| 2542 | + for (ns = mod->missing_namespaces; ns; ns = ns->next) |
|---|
| 2543 | + buf_printf(&ns_deps_buf, " %s", ns->namespace); |
|---|
| 2544 | + |
|---|
| 2545 | + buf_printf(&ns_deps_buf, "\n"); |
|---|
| 2546 | + } |
|---|
| 2547 | + |
|---|
| 2548 | + write_if_changed(&ns_deps_buf, fname); |
|---|
| 2549 | + free(ns_deps_buf.p); |
|---|
| 2550 | +} |
|---|
| 2551 | + |
|---|
| 2552 | +struct dump_list { |
|---|
| 2553 | + struct dump_list *next; |
|---|
| 2448 | 2554 | const char *file; |
|---|
| 2449 | 2555 | }; |
|---|
| 2450 | 2556 | |
|---|
| .. | .. |
|---|
| 2452 | 2558 | { |
|---|
| 2453 | 2559 | struct module *mod; |
|---|
| 2454 | 2560 | struct buffer buf = { }; |
|---|
| 2455 | | - char *kernel_read = NULL, *module_read = NULL; |
|---|
| 2561 | + char *missing_namespace_deps = NULL; |
|---|
| 2456 | 2562 | char *dump_write = NULL, *files_source = NULL; |
|---|
| 2457 | 2563 | int opt; |
|---|
| 2458 | | - int err; |
|---|
| 2459 | | - struct ext_sym_list *extsym_iter; |
|---|
| 2460 | | - struct ext_sym_list *extsym_start = NULL; |
|---|
| 2564 | + int n; |
|---|
| 2565 | + struct dump_list *dump_read_start = NULL; |
|---|
| 2566 | + struct dump_list **dump_read_iter = &dump_read_start; |
|---|
| 2461 | 2567 | |
|---|
| 2462 | | - while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:E")) != -1) { |
|---|
| 2568 | + while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:v:")) != -1) { |
|---|
| 2463 | 2569 | switch (opt) { |
|---|
| 2464 | | - case 'i': |
|---|
| 2465 | | - kernel_read = optarg; |
|---|
| 2466 | | - break; |
|---|
| 2467 | | - case 'I': |
|---|
| 2468 | | - module_read = optarg; |
|---|
| 2469 | | - external_module = 1; |
|---|
| 2470 | | - break; |
|---|
| 2471 | 2570 | case 'e': |
|---|
| 2472 | 2571 | external_module = 1; |
|---|
| 2473 | | - extsym_iter = |
|---|
| 2474 | | - NOFAIL(malloc(sizeof(*extsym_iter))); |
|---|
| 2475 | | - extsym_iter->next = extsym_start; |
|---|
| 2476 | | - extsym_iter->file = optarg; |
|---|
| 2477 | | - extsym_start = extsym_iter; |
|---|
| 2572 | + break; |
|---|
| 2573 | + case 'i': |
|---|
| 2574 | + *dump_read_iter = |
|---|
| 2575 | + NOFAIL(calloc(1, sizeof(**dump_read_iter))); |
|---|
| 2576 | + (*dump_read_iter)->file = optarg; |
|---|
| 2577 | + dump_read_iter = &(*dump_read_iter)->next; |
|---|
| 2478 | 2578 | break; |
|---|
| 2479 | 2579 | case 'm': |
|---|
| 2480 | 2580 | modversions = 1; |
|---|
| .. | .. |
|---|
| 2488 | 2588 | case 'a': |
|---|
| 2489 | 2589 | all_versions = 1; |
|---|
| 2490 | 2590 | break; |
|---|
| 2491 | | - case 's': |
|---|
| 2492 | | - vmlinux_section_warnings = 0; |
|---|
| 2493 | | - break; |
|---|
| 2494 | | - case 'S': |
|---|
| 2495 | | - sec_mismatch_verbose = 0; |
|---|
| 2496 | | - break; |
|---|
| 2497 | 2591 | case 'T': |
|---|
| 2498 | 2592 | files_source = optarg; |
|---|
| 2499 | 2593 | break; |
|---|
| .. | .. |
|---|
| 2501 | 2595 | warn_unresolved = 1; |
|---|
| 2502 | 2596 | break; |
|---|
| 2503 | 2597 | case 'E': |
|---|
| 2504 | | - sec_mismatch_fatal = 1; |
|---|
| 2598 | + sec_mismatch_warn_only = false; |
|---|
| 2599 | + break; |
|---|
| 2600 | + case 'N': |
|---|
| 2601 | + allow_missing_ns_imports = 1; |
|---|
| 2602 | + break; |
|---|
| 2603 | + case 'd': |
|---|
| 2604 | + missing_namespace_deps = optarg; |
|---|
| 2605 | + break; |
|---|
| 2606 | + case 'v': |
|---|
| 2607 | + strncpy(module_scmversion, optarg, sizeof(module_scmversion) - 1); |
|---|
| 2505 | 2608 | break; |
|---|
| 2506 | 2609 | default: |
|---|
| 2507 | 2610 | exit(1); |
|---|
| 2508 | 2611 | } |
|---|
| 2509 | 2612 | } |
|---|
| 2510 | 2613 | |
|---|
| 2511 | | - if (kernel_read) |
|---|
| 2512 | | - read_dump(kernel_read, 1); |
|---|
| 2513 | | - if (module_read) |
|---|
| 2514 | | - read_dump(module_read, 0); |
|---|
| 2515 | | - while (extsym_start) { |
|---|
| 2516 | | - read_dump(extsym_start->file, 0); |
|---|
| 2517 | | - extsym_iter = extsym_start->next; |
|---|
| 2518 | | - free(extsym_start); |
|---|
| 2519 | | - extsym_start = extsym_iter; |
|---|
| 2614 | + while (dump_read_start) { |
|---|
| 2615 | + struct dump_list *tmp; |
|---|
| 2616 | + |
|---|
| 2617 | + read_dump(dump_read_start->file); |
|---|
| 2618 | + tmp = dump_read_start->next; |
|---|
| 2619 | + free(dump_read_start); |
|---|
| 2620 | + dump_read_start = tmp; |
|---|
| 2520 | 2621 | } |
|---|
| 2521 | 2622 | |
|---|
| 2522 | 2623 | while (optind < argc) |
|---|
| .. | .. |
|---|
| 2525 | 2626 | if (files_source) |
|---|
| 2526 | 2627 | read_symbols_from_files(files_source); |
|---|
| 2527 | 2628 | |
|---|
| 2528 | | - for (mod = modules; mod; mod = mod->next) { |
|---|
| 2529 | | - if (mod->skip) |
|---|
| 2530 | | - continue; |
|---|
| 2531 | | - check_exports(mod); |
|---|
| 2532 | | - } |
|---|
| 2533 | | - |
|---|
| 2534 | | - err = 0; |
|---|
| 2629 | + /* |
|---|
| 2630 | + * When there's no vmlinux, don't print warnings about |
|---|
| 2631 | + * unresolved symbols (since there'll be too many ;) |
|---|
| 2632 | + */ |
|---|
| 2633 | + if (!have_vmlinux) |
|---|
| 2634 | + warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n"); |
|---|
| 2535 | 2635 | |
|---|
| 2536 | 2636 | for (mod = modules; mod; mod = mod->next) { |
|---|
| 2537 | 2637 | char fname[PATH_MAX]; |
|---|
| 2538 | 2638 | |
|---|
| 2539 | | - if (mod->skip) |
|---|
| 2639 | + if (mod->is_vmlinux || mod->from_dump) |
|---|
| 2540 | 2640 | continue; |
|---|
| 2541 | 2641 | |
|---|
| 2542 | 2642 | buf.pos = 0; |
|---|
| 2543 | 2643 | |
|---|
| 2544 | | - err |= check_modname_len(mod); |
|---|
| 2644 | + check_modname_len(mod); |
|---|
| 2645 | + check_exports(mod); |
|---|
| 2646 | + |
|---|
| 2545 | 2647 | add_header(&buf, mod); |
|---|
| 2546 | 2648 | add_intree_flag(&buf, !external_module); |
|---|
| 2547 | 2649 | add_retpoline(&buf); |
|---|
| 2548 | 2650 | add_staging_flag(&buf, mod->name); |
|---|
| 2549 | | - err |= add_versions(&buf, mod); |
|---|
| 2550 | | - add_depends(&buf, mod, modules); |
|---|
| 2651 | + add_versions(&buf, mod); |
|---|
| 2652 | + add_depends(&buf, mod); |
|---|
| 2551 | 2653 | add_moddevtable(&buf, mod); |
|---|
| 2552 | 2654 | add_srcversion(&buf, mod); |
|---|
| 2655 | + add_scmversion(&buf); |
|---|
| 2553 | 2656 | |
|---|
| 2554 | 2657 | sprintf(fname, "%s.mod.c", mod->name); |
|---|
| 2555 | 2658 | write_if_changed(&buf, fname); |
|---|
| 2556 | 2659 | } |
|---|
| 2660 | + |
|---|
| 2661 | + if (missing_namespace_deps) |
|---|
| 2662 | + write_namespace_deps_files(missing_namespace_deps); |
|---|
| 2663 | + |
|---|
| 2557 | 2664 | if (dump_write) |
|---|
| 2558 | 2665 | write_dump(dump_write); |
|---|
| 2559 | | - if (sec_mismatch_count) { |
|---|
| 2560 | | - if (!sec_mismatch_verbose) { |
|---|
| 2561 | | - warn("modpost: Found %d section mismatch(es).\n" |
|---|
| 2562 | | - "To see full details build your kernel with:\n" |
|---|
| 2563 | | - "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", |
|---|
| 2564 | | - sec_mismatch_count); |
|---|
| 2565 | | - } |
|---|
| 2566 | | - if (sec_mismatch_fatal) { |
|---|
| 2567 | | - fatal("modpost: Section mismatches detected.\n" |
|---|
| 2568 | | - "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); |
|---|
| 2666 | + if (sec_mismatch_count && !sec_mismatch_warn_only) |
|---|
| 2667 | + error("Section mismatches detected.\n" |
|---|
| 2668 | + "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); |
|---|
| 2669 | + for (n = 0; n < SYMBOL_HASH_SIZE; n++) { |
|---|
| 2670 | + struct symbol *s; |
|---|
| 2671 | + |
|---|
| 2672 | + for (s = symbolhash[n]; s; s = s->next) { |
|---|
| 2673 | + if (s->is_static) |
|---|
| 2674 | + error("\"%s\" [%s] is a static %s\n", |
|---|
| 2675 | + s->name, s->module->name, |
|---|
| 2676 | + export_str(s->export)); |
|---|
| 2569 | 2677 | } |
|---|
| 2570 | 2678 | } |
|---|
| 2679 | + |
|---|
| 2571 | 2680 | free(buf.p); |
|---|
| 2572 | 2681 | |
|---|
| 2573 | | - return err; |
|---|
| 2682 | + return error_occurred ? 1 : 0; |
|---|
| 2574 | 2683 | } |
|---|