#include <ctype.h>
#include "modpost.h"
-#include "../../include/linux/license.h"
/* Are we using CONFIG_MODVERSIONS? */
int modversions = 0;
static int all_versions = 0;
/* If we are modposting external module set to 1 */
static int external_module = 0;
-/* How a symbol is exported */
-enum export {
- export_plain, export_unused, export_gpl,
- export_unused_gpl, export_gpl_future, export_unknown
-};
void fatal(const char *fmt, ...)
{
/* add to list */
mod->name = p;
- mod->gpl_compatible = -1;
mod->next = modules;
modules = mod;
unsigned int kernel:1; /* 1 if symbol is from kernel
* (only for external modules) **/
unsigned int preloaded:1; /* 1 if symbol from Module.symvers */
- enum export export; /* Type of export */
char name[0];
};
}
/* For the hash of exported symbols */
-static struct symbol *new_symbol(const char *name, struct module *module,
- enum export export)
+static struct symbol *new_symbol(const char *name, struct module *module)
{
unsigned int hash;
struct symbol *new;
hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
new->module = module;
- new->export = export;
return new;
}
return NULL;
}
-static struct {
- const char *str;
- enum export export;
-} export_list[] = {
- { .str = "EXPORT_SYMBOL", .export = export_plain },
- { .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused },
- { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
- { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
- { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
- { .str = "(unknown)", .export = export_unknown },
-};
-
-
-static const char *export_str(enum export ex)
-{
- return export_list[ex].str;
-}
-
-static enum export export_no(const char * s)
-{
- int i;
- if (!s)
- return export_unknown;
- for (i = 0; export_list[i].export != export_unknown; i++) {
- if (strcmp(export_list[i].str, s) == 0)
- return export_list[i].export;
- }
- return export_unknown;
-}
-
-static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
-{
- if (sec == elf->export_sec)
- return export_plain;
- else if (sec == elf->export_unused_sec)
- return export_unused;
- else if (sec == elf->export_gpl_sec)
- return export_gpl;
- else if (sec == elf->export_unused_gpl_sec)
- return export_unused_gpl;
- else if (sec == elf->export_gpl_future_sec)
- return export_gpl_future;
- else
- return export_unknown;
-}
-
/**
* Add an exported symbol - it may have already been added without a
* CRC, in this case just update the CRC
**/
-static struct symbol *sym_add_exported(const char *name, struct module *mod,
- enum export export)
+static struct symbol *sym_add_exported(const char *name, struct module *mod)
{
struct symbol *s = find_symbol(name);
if (!s) {
- s = new_symbol(name, mod, export);
+ s = new_symbol(name, mod);
} else {
if (!s->preloaded) {
warn("%s: '%s' exported twice. Previous export "
s->preloaded = 0;
s->vmlinux = is_vmlinux(mod->name);
s->kernel = 0;
- s->export = export;
return s;
}
static void sym_update_crc(const char *name, struct module *mod,
- unsigned int crc, enum export export)
+ unsigned int crc)
{
struct symbol *s = find_symbol(name);
if (!s)
- s = new_symbol(name, mod, export);
+ s = new_symbol(name, mod);
s->crc = crc;
s->crc_valid = 1;
}
hdr = grab_file(filename, &info->size);
if (!hdr) {
perror(filename);
- exit(1);
+ abort();
}
info->hdr = hdr;
if (info->size < sizeof(*hdr))
for (i = 1; i < hdr->e_shnum; i++) {
const char *secstrings
= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
- const char *secname;
if (sechdrs[i].sh_offset > info->size)
goto truncated;
- secname = secstrings + sechdrs[i].sh_name;
- if (strcmp(secname, ".modinfo") == 0) {
+ if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
info->modinfo_len = sechdrs[i].sh_size;
- } else if (strcmp(secname, "__ksymtab") == 0)
- info->export_sec = i;
- else if (strcmp(secname, "__ksymtab_unused") == 0)
- info->export_unused_sec = i;
- else if (strcmp(secname, "__ksymtab_gpl") == 0)
- info->export_gpl_sec = i;
- else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
- info->export_unused_gpl_sec = i;
- else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
- info->export_gpl_future_sec = i;
-
+ }
if (sechdrs[i].sh_type != SHT_SYMTAB)
continue;
Elf_Sym *sym, const char *symname)
{
unsigned int crc;
- enum export export = export_from_sec(info, sym->st_shndx);
switch (sym->st_shndx) {
case SHN_COMMON:
/* CRC'd symbol */
if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
crc = (unsigned int) sym->st_value;
- sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
- export);
+ sym_update_crc(symname + strlen(CRC_PFX), mod, crc);
}
break;
case SHN_UNDEF:
default:
/* All exported symbols */
if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
- sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
- export);
+ sym_add_exported(symname + strlen(KSYMTAB_PFX), mod);
}
if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
mod->has_init = 1;
return string;
}
-static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
- const char *tag, char *info)
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+ const char *tag)
{
char *p;
unsigned int taglen = strlen(tag);
unsigned long size = modinfo_len;
- if (info) {
- size -= info - (char *)modinfo;
- modinfo = next_string(info, &size);
- }
-
for (p = modinfo; p; p = next_string(p, &size)) {
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
return p + taglen + 1;
return NULL;
}
-static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
- const char *tag)
-
-{
- return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
-}
-
/**
* Test if string s ends in string sub
* return 0 if match
".pci_fixup_final",
".pdr",
"__param",
- "__ex_table",
- ".fixup",
- ".smp_locks",
- ".plt", /* seen on ARCH=um build on x86_64. Harmless */
NULL
};
/* Start of section names */
for (s = namelist3; *s; s++)
if (strstr(name, *s) != NULL)
return 1;
- if (strrcmp(name, ".init") == 0)
- return 1;
return 0;
}
".exitcall.exit",
".eh_frame",
".stab",
- "__ex_table",
- ".fixup",
- ".smp_locks",
- ".plt", /* seen on ARCH=um build on x86_64. Harmless */
NULL
};
/* Start of section names */
{
const char *symname;
char *version;
- char *license;
struct module *mod;
struct elf_info info = { };
Elf_Sym *sym;
mod->skip = 1;
}
- license = get_modinfo(info.modinfo, info.modinfo_len, "license");
- while (license) {
- if (license_is_gpl_compatible(license))
- mod->gpl_compatible = 1;
- else {
- mod->gpl_compatible = 0;
- break;
- }
- license = get_next_modinfo(info.modinfo, info.modinfo_len,
- "license", license);
- }
-
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
symname = info.strtab + sym->st_name;
buf->pos += len;
}
-static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
-{
- const char *e = is_vmlinux(m) ?"":".ko";
-
- switch (exp) {
- case export_gpl:
- fatal("modpost: GPL-incompatible module %s%s "
- "uses GPL-only symbol '%s'\n", m, e, s);
- break;
- case export_unused_gpl:
- fatal("modpost: GPL-incompatible module %s%s "
- "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
- break;
- case export_gpl_future:
- warn("modpost: GPL-incompatible module %s%s "
- "uses future GPL-only symbol '%s'\n", m, e, s);
- break;
- case export_plain:
- case export_unused:
- case export_unknown:
- /* ignore */
- break;
- }
-}
-
-static void check_for_unused(enum export exp, const char* m, const char* s)
-{
- const char *e = is_vmlinux(m) ?"":".ko";
-
- switch (exp) {
- case export_unused:
- case export_unused_gpl:
- warn("modpost: module %s%s "
- "uses symbol '%s' marked UNUSED\n", m, e, s);
- break;
- default:
- /* ignore */
- break;
- }
-}
-
-static void check_exports(struct module *mod)
-{
- struct symbol *s, *exp;
-
- for (s = mod->unres; s; s = s->next) {
- const char *basename;
- exp = find_symbol(s->name);
- if (!exp || exp->module == mod)
- continue;
- basename = strrchr(mod->name, '/');
- if (basename)
- basename++;
- else
- basename = mod->name;
- if (!mod->gpl_compatible)
- check_for_gpl_usage(exp->export, basename, exp->name);
- check_for_unused(exp->export, basename, exp->name);
- }
-}
-
/**
* Header for the generated file
**/
fclose(file);
}
-/* parse Module.symvers file. line format:
- * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
- **/
static void read_dump(const char *fname, unsigned int kernel)
{
unsigned long size, pos = 0;
return;
while ((line = get_next_line(&pos, file, size))) {
- char *symname, *modname, *d, *export, *end;
+ char *symname, *modname, *d;
unsigned int crc;
struct module *mod;
struct symbol *s;
if (!(modname = strchr(symname, '\t')))
goto fail;
*modname++ = '\0';
- if ((export = strchr(modname, '\t')) != NULL)
- *export++ = '\0';
- if (export && ((end = strchr(export, '\t')) != NULL))
- *end = '\0';
+ if (strchr(modname, '\t'))
+ goto fail;
crc = strtoul(line, &d, 16);
if (*symname == '\0' || *modname == '\0' || *d != '\0')
goto fail;
mod = new_module(NOFAIL(strdup(modname)));
mod->skip = 1;
}
- s = sym_add_exported(symname, mod, export_no(export));
+ s = sym_add_exported(symname, mod);
s->kernel = kernel;
s->preloaded = 1;
- sym_update_crc(symname, mod, crc, export_no(export));
+ sym_update_crc(symname, mod, crc);
}
return;
fail:
symbol = symbolhash[n];
while (symbol) {
if (dump_sym(symbol))
- buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
+ buf_printf(&buf, "0x%08x\t%s\t%s\n",
symbol->crc, symbol->name,
- symbol->module->name,
- export_str(symbol->export));
+ symbol->module->name);
symbol = symbol->next;
}
}
read_symbols(argv[optind++]);
}
- for (mod = modules; mod; mod = mod->next) {
- if (mod->skip)
- continue;
- check_exports(mod);
- }
-
for (mod = modules; mod; mod = mod->next) {
if (mod->skip)
continue;