Merge master.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild

* master.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild: (46 commits)
  kbuild: remove obsoleted scripts/reference_* files
  kbuild: fix make help & make *pkg
  kconfig: fix time ordering of writes to .kconfig.d and include/linux/autoconf.h
  Kconfig: remove the CONFIG_CC_ALIGN_* options
  kbuild: add -fverbose-asm to i386 Makefile
  kbuild: clean-up genksyms
  kbuild: Lindent genksyms.c
  kbuild: fix genksyms build error
  kbuild: in makefile.txt note that Makefile is preferred name for kbuild files
  kbuild: replace PHONY with FORCE
  kbuild: Fix bug in crc symbol generating of kernel and modules
  kbuild: change kbuild to not rely on incorrect GNU make behavior
  kbuild: when warning symbols exported twice now tell user this is the problem
  kbuild: fix make dir/file.xx when asm symlink is missing
  kbuild: in the section mismatch check try harder to find symbols
  kbuild: fix section mismatch check for unwind on IA64
  kbuild: kill false positives from section mismatch warnings for powerpc
  kbuild: kill trailing whitespace in modpost & friends
  kbuild: small update of allnoconfig description
  kbuild: make namespace.pl CROSS_COMPILE happy
  ...

Trivial conflict in arch/ppc/boot/Makefile manually fixed up
This commit is contained in:
Linus Torvalds
2006-03-25 08:48:48 -08:00
52 changed files with 1509 additions and 1268 deletions

View File

@ -2,7 +2,7 @@
*
* Copyright 2003 Kai Germaschewski
* Copyright 2002-2004 Rusty Russell, IBM Corporation
*
* Copyright 2006 Sam Ravnborg
* Based in part on module-init-tools/depmod.c,file2alias
*
* This software may be used and distributed according to the terms
@ -20,9 +20,10 @@ int modversions = 0;
int have_vmlinux = 0;
/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
static int all_versions = 0;
/* If we are modposting external module set to 1 */
static int external_module = 0;
void
fatal(const char *fmt, ...)
void fatal(const char *fmt, ...)
{
va_list arglist;
@ -35,8 +36,7 @@ fatal(const char *fmt, ...)
exit(1);
}
void
warn(const char *fmt, ...)
void warn(const char *fmt, ...)
{
va_list arglist;
@ -47,6 +47,18 @@ warn(const char *fmt, ...)
va_end(arglist);
}
static int is_vmlinux(const char *modname)
{
const char *myname;
if ((myname = strrchr(modname, '/')))
myname++;
else
myname = modname;
return strcmp(myname, "vmlinux") == 0;
}
void *do_nofail(void *ptr, const char *expr)
{
if (!ptr) {
@ -59,8 +71,7 @@ void *do_nofail(void *ptr, const char *expr)
static struct module *modules;
struct module *
find_module(char *modname)
static struct module *find_module(char *modname)
{
struct module *mod;
@ -70,12 +81,11 @@ find_module(char *modname)
return mod;
}
struct module *
new_module(char *modname)
static struct module *new_module(char *modname)
{
struct module *mod;
char *p, *s;
mod = NOFAIL(malloc(sizeof(*mod)));
memset(mod, 0, sizeof(*mod));
p = NOFAIL(strdup(modname));
@ -104,6 +114,10 @@ struct symbol {
unsigned int crc;
int crc_valid;
unsigned int weak:1;
unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
unsigned int kernel:1; /* 1 if symbol is from kernel
* (only for external modules) **/
unsigned int preloaded:1; /* 1 if symbol from Module.symvers */
char name[0];
};
@ -122,11 +136,12 @@ static inline unsigned int tdb_hash(const char *name)
return (1103515243 * value + 12345);
}
/* Allocate a new symbols for use in the hash of exported symbols or
* the list of unresolved symbols per module */
struct symbol *
alloc_symbol(const char *name, unsigned int weak, struct symbol *next)
/**
* Allocate a new symbols for use in the hash of exported symbols or
* the list of unresolved symbols per module
**/
static struct symbol *alloc_symbol(const char *name, unsigned int weak,
struct symbol *next)
{
struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
@ -138,9 +153,7 @@ alloc_symbol(const char *name, unsigned int weak, struct symbol *next)
}
/* For the hash of exported symbols */
void
new_symbol(const char *name, struct module *module, unsigned int *crc)
static struct symbol *new_symbol(const char *name, struct module *module)
{
unsigned int hash;
struct symbol *new;
@ -148,14 +161,10 @@ new_symbol(const char *name, struct module *module, unsigned int *crc)
hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
new->module = module;
if (crc) {
new->crc = *crc;
new->crc_valid = 1;
}
return new;
}
struct symbol *
find_symbol(const char *name)
static struct symbol *find_symbol(const char *name)
{
struct symbol *s;
@ -170,25 +179,42 @@ find_symbol(const char *name)
return NULL;
}
/* Add an exported symbol - it may have already been added without a
* CRC, in this case just update the CRC */
void
add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
/**
* 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)
{
struct symbol *s = find_symbol(name);
if (!s) {
new_symbol(name, module, crc);
return;
}
if (crc) {
s->crc = *crc;
s->crc_valid = 1;
s = new_symbol(name, mod);
} else {
if (!s->preloaded) {
warn("%s: '%s' exported twice. Previous export "
"was in %s%s\n", mod->name, name,
s->module->name,
is_vmlinux(s->module->name) ?"":".ko");
}
}
s->preloaded = 0;
s->vmlinux = is_vmlinux(mod->name);
s->kernel = 0;
return s;
}
void *
grab_file(const char *filename, unsigned long *size)
static void sym_update_crc(const char *name, struct module *mod,
unsigned int crc)
{
struct symbol *s = find_symbol(name);
if (!s)
s = new_symbol(name, mod);
s->crc = crc;
s->crc_valid = 1;
}
void *grab_file(const char *filename, unsigned long *size)
{
struct stat st;
void *map;
@ -207,13 +233,12 @@ grab_file(const char *filename, unsigned long *size)
return map;
}
/*
Return a copy of the next line in a mmap'ed file.
spaces in the beginning of the line is trimmed away.
Return a pointer to a static buffer.
*/
char*
get_next_line(unsigned long *pos, void *file, unsigned long size)
/**
* Return a copy of the next line in a mmap'ed file.
* spaces in the beginning of the line is trimmed away.
* Return a pointer to a static buffer.
**/
char* get_next_line(unsigned long *pos, void *file, unsigned long size)
{
static char line[4096];
int skip = 1;
@ -243,14 +268,12 @@ get_next_line(unsigned long *pos, void *file, unsigned long size)
return NULL;
}
void
release_file(void *file, unsigned long size)
void release_file(void *file, unsigned long size)
{
munmap(file, size);
}
void
parse_elf(struct elf_info *info, const char *filename)
static void parse_elf(struct elf_info *info, const char *filename)
{
unsigned int i;
Elf_Ehdr *hdr = info->hdr;
@ -297,14 +320,13 @@ parse_elf(struct elf_info *info, const char *filename)
continue;
info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset
info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset
+ sechdrs[i].sh_size;
info->strtab = (void *)hdr +
info->strtab = (void *)hdr +
sechdrs[sechdrs[i].sh_link].sh_offset;
}
if (!info->symtab_start) {
fprintf(stderr, "modpost: %s no symtab?\n", filename);
abort();
fatal("%s has no symtab?\n", filename);
}
/* Fix endianness in symbols */
for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
@ -316,36 +338,31 @@ parse_elf(struct elf_info *info, const char *filename)
return;
truncated:
fprintf(stderr, "modpost: %s is truncated.\n", filename);
abort();
fatal("%s is truncated.\n", filename);
}
void
parse_elf_finish(struct elf_info *info)
static void parse_elf_finish(struct elf_info *info)
{
release_file(info->hdr, info->size);
}
#define CRC_PFX "__crc_"
#define KSYMTAB_PFX "__ksymtab_"
#define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_"
#define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_"
void
handle_modversions(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname)
static void handle_modversions(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname)
{
unsigned int crc;
switch (sym->st_shndx) {
case SHN_COMMON:
fprintf(stderr, "*** Warning: \"%s\" [%s] is COMMON symbol\n",
symname, mod->name);
warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
break;
case SHN_ABS:
/* CRC'd symbol */
if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
crc = (unsigned int) sym->st_value;
add_exported_symbol(symname + strlen(CRC_PFX),
mod, &crc);
sym_update_crc(symname + strlen(CRC_PFX), mod, crc);
}
break;
case SHN_UNDEF:
@ -370,15 +387,15 @@ handle_modversions(struct module *mod, struct elf_info *info,
/* Ignore register directives. */
if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
break;
if (symname[0] == '.') {
char *munged = strdup(symname);
munged[0] = '_';
munged[1] = toupper(munged[1]);
symname = munged;
}
if (symname[0] == '.') {
char *munged = strdup(symname);
munged[0] = '_';
munged[1] = toupper(munged[1]);
symname = munged;
}
}
#endif
if (memcmp(symname, MODULE_SYMBOL_PREFIX,
strlen(MODULE_SYMBOL_PREFIX)) == 0)
mod->unres = alloc_symbol(symname +
@ -389,8 +406,7 @@ handle_modversions(struct module *mod, struct elf_info *info,
default:
/* All exported symbols */
if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
add_exported_symbol(symname + strlen(KSYMTAB_PFX),
mod, NULL);
sym_add_exported(symname + strlen(KSYMTAB_PFX), mod);
}
if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
mod->has_init = 1;
@ -400,20 +416,9 @@ handle_modversions(struct module *mod, struct elf_info *info,
}
}
int
is_vmlinux(const char *modname)
{
const char *myname;
if ((myname = strrchr(modname, '/')))
myname++;
else
myname = modname;
return strcmp(myname, "vmlinux") == 0;
}
/* Parse tag=value strings from .modinfo section */
/**
* Parse tag=value strings from .modinfo section
**/
static char *next_string(char *string, unsigned long *secsize)
{
/* Skip non-zero chars */
@ -446,8 +451,418 @@ static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
return NULL;
}
void
read_symbols(char *modname)
/**
* Test if string s ends in string sub
* return 0 if match
**/
static int strrcmp(const char *s, const char *sub)
{
int slen, sublen;
if (!s || !sub)
return 1;
slen = strlen(s);
sublen = strlen(sub);
if ((slen == 0) || (sublen == 0))
return 1;
if (sublen > slen)
return 1;
return memcmp(s + slen - sublen, sub, sublen);
}
/**
* Whitelist to allow certain references to pass with no warning.
* Pattern 1:
* If a module parameter is declared __initdata and permissions=0
* then this is legal despite the warning generated.
* We cannot see value of permissions here, so just ignore
* this pattern.
* The pattern is identified by:
* tosec = .init.data
* fromsec = .data*
* atsym =__param*
*
* Pattern 2:
* Many drivers utilise a *_driver container with references to
* add, remove, probe functions etc.
* These functions may often be marked __init and we do not want to
* warn here.
* the pattern is identified by:
* tosec = .init.text | .exit.text
* fromsec = .data
* atsym = *_driver, *_ops, *_probe, *probe_one
**/
static int secref_whitelist(const char *tosec, const char *fromsec,
const char *atsym)
{
int f1 = 1, f2 = 1;
const char **s;
const char *pat2sym[] = {
"_driver",
"_ops",
"_probe",
"_probe_one",
NULL
};
/* Check for pattern 1 */
if (strcmp(tosec, ".init.data") != 0)
f1 = 0;
if (strncmp(fromsec, ".data", strlen(".data")) != 0)
f1 = 0;
if (strncmp(atsym, "__param", strlen("__param")) != 0)
f1 = 0;
if (f1)
return f1;
/* Check for pattern 2 */
if ((strcmp(tosec, ".init.text") != 0) &&
(strcmp(tosec, ".exit.text") != 0))
f2 = 0;
if (strcmp(fromsec, ".data") != 0)
f2 = 0;
for (s = pat2sym; *s; s++)
if (strrcmp(atsym, *s) == 0)
f1 = 1;
return f1 && f2;
}
/**
* Find symbol based on relocation record info.
* In some cases the symbol supplied is a valid symbol so
* return refsym. If st_name != 0 we assume this is a valid symbol.
* In other cases the symbol needs to be looked up in the symbol table
* based on section and address.
* **/
static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
Elf_Sym *relsym)
{
Elf_Sym *sym;
if (relsym->st_name != 0)
return relsym;
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
if (sym->st_shndx != relsym->st_shndx)
continue;
if (sym->st_value == addr)
return sym;
}
return NULL;
}
/*
* Find symbols before or equal addr and after addr - in the section sec.
* If we find two symbols with equal offset prefer one with a valid name.
* The ELF format may have a better way to detect what type of symbol
* it is, but this works for now.
**/
static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
const char *sec,
Elf_Sym **before, Elf_Sym **after)
{
Elf_Sym *sym;
Elf_Ehdr *hdr = elf->hdr;
Elf_Addr beforediff = ~0;
Elf_Addr afterdiff = ~0;
const char *secstrings = (void *)hdr +
elf->sechdrs[hdr->e_shstrndx].sh_offset;
*before = NULL;
*after = NULL;
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
const char *symsec;
if (sym->st_shndx >= SHN_LORESERVE)
continue;
symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name;
if (strcmp(symsec, sec) != 0)
continue;
if (sym->st_value <= addr) {
if ((addr - sym->st_value) < beforediff) {
beforediff = addr - sym->st_value;
*before = sym;
}
else if ((addr - sym->st_value) == beforediff) {
/* equal offset, valid name? */
const char *name = elf->strtab + sym->st_name;
if (name && strlen(name))
*before = sym;
}
}
else
{
if ((sym->st_value - addr) < afterdiff) {
afterdiff = sym->st_value - addr;
*after = sym;
}
else if ((sym->st_value - addr) == afterdiff) {
/* equal offset, valid name? */
const char *name = elf->strtab + sym->st_name;
if (name && strlen(name))
*after = sym;
}
}
}
}
/**
* Print a warning about a section mismatch.
* Try to find symbols near it so user can find it.
* Check whitelist before warning - it may be a false positive.
**/
static void warn_sec_mismatch(const char *modname, const char *fromsec,
struct elf_info *elf, Elf_Sym *sym, Elf_Rela r)
{
const char *refsymname = "";
Elf_Sym *before, *after;
Elf_Sym *refsym;
Elf_Ehdr *hdr = elf->hdr;
Elf_Shdr *sechdrs = elf->sechdrs;
const char *secstrings = (void *)hdr +
sechdrs[hdr->e_shstrndx].sh_offset;
const char *secname = secstrings + sechdrs[sym->st_shndx].sh_name;
find_symbols_between(elf, r.r_offset, fromsec, &before, &after);
refsym = find_elf_symbol(elf, r.r_addend, sym);
if (refsym && strlen(elf->strtab + refsym->st_name))
refsymname = elf->strtab + refsym->st_name;
/* check whitelist - we may ignore it */
if (before &&
secref_whitelist(secname, fromsec, elf->strtab + before->st_name))
return;
if (before && after) {
warn("%s - Section mismatch: reference to %s:%s from %s "
"between '%s' (at offset 0x%llx) and '%s'\n",
modname, secname, refsymname, fromsec,
elf->strtab + before->st_name,
(long long)r.r_offset,
elf->strtab + after->st_name);
} else if (before) {
warn("%s - Section mismatch: reference to %s:%s from %s "
"after '%s' (at offset 0x%llx)\n",
modname, secname, refsymname, fromsec,
elf->strtab + before->st_name,
(long long)r.r_offset);
} else if (after) {
warn("%s - Section mismatch: reference to %s:%s from %s "
"before '%s' (at offset -0x%llx)\n",
modname, secname, refsymname, fromsec,
elf->strtab + before->st_name,
(long long)r.r_offset);
} else {
warn("%s - Section mismatch: reference to %s:%s from %s "
"(offset 0x%llx)\n",
modname, secname, fromsec, refsymname,
(long long)r.r_offset);
}
}
/**
* A module includes a number of sections that are discarded
* either when loaded or when used as built-in.
* For loaded modules all functions marked __init and all data
* marked __initdata will be discarded when the module has been intialized.
* Likewise for modules used built-in the sections marked __exit
* are discarded because __exit marked function are supposed to be called
* only when a moduel is unloaded which never happes for built-in modules.
* The check_sec_ref() function traverses all relocation records
* to find all references to a section that reference a section that will
* be discarded and warns about it.
**/
static void check_sec_ref(struct module *mod, const char *modname,
struct elf_info *elf,
int section(const char*),
int section_ref_ok(const char *))
{
int i;
Elf_Sym *sym;
Elf_Ehdr *hdr = elf->hdr;
Elf_Shdr *sechdrs = elf->sechdrs;
const char *secstrings = (void *)hdr +
sechdrs[hdr->e_shstrndx].sh_offset;
/* Walk through all sections */
for (i = 0; i < hdr->e_shnum; i++) {
Elf_Rela *rela;
Elf_Rela *start = (void *)hdr + sechdrs[i].sh_offset;
Elf_Rela *stop = (void*)start + sechdrs[i].sh_size;
const char *name = secstrings + sechdrs[i].sh_name +
strlen(".rela");
/* We want to process only relocation sections and not .init */
if (section_ref_ok(name) || (sechdrs[i].sh_type != SHT_RELA))
continue;
for (rela = start; rela < stop; rela++) {
Elf_Rela r;
const char *secname;
r.r_offset = TO_NATIVE(rela->r_offset);
r.r_info = TO_NATIVE(rela->r_info);
r.r_addend = TO_NATIVE(rela->r_addend);
sym = elf->symtab_start + ELF_R_SYM(r.r_info);
/* Skip special sections */
if (sym->st_shndx >= SHN_LORESERVE)
continue;
secname = secstrings + sechdrs[sym->st_shndx].sh_name;
if (section(secname))
warn_sec_mismatch(modname, name, elf, sym, r);
}
}
}
/**
* Functions used only during module init is marked __init and is stored in
* a .init.text section. Likewise data is marked __initdata and stored in
* a .init.data section.
* If this section is one of these sections return 1
* See include/linux/init.h for the details
**/
static int init_section(const char *name)
{
if (strcmp(name, ".init") == 0)
return 1;
if (strncmp(name, ".init.", strlen(".init.")) == 0)
return 1;
return 0;
}
/**
* Identify sections from which references to a .init section is OK.
*
* Unfortunately references to read only data that referenced .init
* sections had to be excluded. Almost all of these are false
* positives, they are created by gcc. The downside of excluding rodata
* is that there really are some user references from rodata to
* init code, e.g. drivers/video/vgacon.c:
*
* const struct consw vga_con = {
* con_startup: vgacon_startup,
*
* where vgacon_startup is __init. If you want to wade through the false
* positives, take out the check for rodata.
**/
static int init_section_ref_ok(const char *name)
{
const char **s;
/* Absolute section names */
const char *namelist1[] = {
".init",
".opd", /* see comment [OPD] at exit_section_ref_ok() */
".toc1", /* used by ppc64 */
".stab",
".rodata",
".text.lock",
"__bug_table", /* used by powerpc for BUG() */
".pci_fixup_header",
".pci_fixup_final",
".pdr",
"__param",
NULL
};
/* Start of section names */
const char *namelist2[] = {
".init.",
".altinstructions",
".eh_frame",
".debug",
NULL
};
/* part of section name */
const char *namelist3 [] = {
".unwind", /* sample: IA_64.unwind.init.text */
NULL
};
for (s = namelist1; *s; s++)
if (strcmp(*s, name) == 0)
return 1;
for (s = namelist2; *s; s++)
if (strncmp(*s, name, strlen(*s)) == 0)
return 1;
for (s = namelist3; *s; s++)
if (strstr(name, *s) != NULL)
return 1;
return 0;
}
/*
* Functions used only during module exit is marked __exit and is stored in
* a .exit.text section. Likewise data is marked __exitdata and stored in
* a .exit.data section.
* If this section is one of these sections return 1
* See include/linux/init.h for the details
**/
static int exit_section(const char *name)
{
if (strcmp(name, ".exit.text") == 0)
return 1;
if (strcmp(name, ".exit.data") == 0)
return 1;
return 0;
}
/*
* Identify sections from which references to a .exit section is OK.
*
* [OPD] Keith Ownes <kaos@sgi.com> commented:
* For our future {in}sanity, add a comment that this is the ppc .opd
* section, not the ia64 .opd section.
* ia64 .opd should not point to discarded sections.
**/
static int exit_section_ref_ok(const char *name)
{
const char **s;
/* Absolute section names */
const char *namelist1[] = {
".exit.text",
".exit.data",
".init.text",
".opd", /* See comment [OPD] */
".toc1", /* used by ppc64 */
".altinstructions",
".pdr",
"__bug_table", /* used by powerpc for BUG() */
".exitcall.exit",
".eh_frame",
".stab",
NULL
};
/* Start of section names */
const char *namelist2[] = {
".debug",
NULL
};
/* part of section name */
const char *namelist3 [] = {
".unwind", /* Sample: IA_64.unwind.exit.text */
NULL
};
for (s = namelist1; *s; s++)
if (strcmp(*s, name) == 0)
return 1;
for (s = namelist2; *s; s++)
if (strncmp(*s, name, strlen(*s)) == 0)
return 1;
for (s = namelist3; *s; s++)
if (strstr(name, *s) != NULL)
return 1;
return 0;
}
static void read_symbols(char *modname)
{
const char *symname;
char *version;
@ -462,9 +877,7 @@ read_symbols(char *modname)
/* When there's no vmlinux, don't print warnings about
* unresolved symbols (since there'll be too many ;) */
if (is_vmlinux(modname)) {
unsigned int fake_crc = 0;
have_vmlinux = 1;
add_exported_symbol("struct_module", mod, &fake_crc);
mod->skip = 1;
}
@ -474,6 +887,8 @@ read_symbols(char *modname)
handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname);
}
check_sec_ref(mod, modname, &info, init_section, init_section_ref_ok);
check_sec_ref(mod, modname, &info, exit_section, exit_section_ref_ok);
version = get_modinfo(info.modinfo, info.modinfo_len, "version");
if (version)
@ -499,21 +914,20 @@ read_symbols(char *modname)
* following helper, then compare to the file on disk and
* only update the later if anything changed */
void __attribute__((format(printf, 2, 3)))
buf_printf(struct buffer *buf, const char *fmt, ...)
void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
const char *fmt, ...)
{
char tmp[SZ];
int len;
va_list ap;
va_start(ap, fmt);
len = vsnprintf(tmp, SZ, fmt, ap);
buf_write(buf, tmp, len);
va_end(ap);
}
void
buf_write(struct buffer *buf, const char *s, int len)
void buf_write(struct buffer *buf, const char *s, int len)
{
if (buf->size - buf->pos < len) {
buf->size += len + SZ;
@ -523,10 +937,10 @@ buf_write(struct buffer *buf, const char *s, int len)
buf->pos += len;
}
/* Header for the generated file */
void
add_header(struct buffer *b, struct module *mod)
/**
* Header for the generated file
**/
static void add_header(struct buffer *b, struct module *mod)
{
buf_printf(b, "#include <linux/module.h>\n");
buf_printf(b, "#include <linux/vermagic.h>\n");
@ -546,10 +960,10 @@ add_header(struct buffer *b, struct module *mod)
buf_printf(b, "};\n");
}
/* Record CRCs for unresolved symbols */
void
add_versions(struct buffer *b, struct module *mod)
/**
* Record CRCs for unresolved symbols
**/
static void add_versions(struct buffer *b, struct module *mod)
{
struct symbol *s, *exp;
@ -557,8 +971,8 @@ add_versions(struct buffer *b, struct module *mod)
exp = find_symbol(s->name);
if (!exp || exp->module == mod) {
if (have_vmlinux && !s->weak)
fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
"undefined!\n", s->name, mod->name);
warn("\"%s\" [%s.ko] undefined!\n",
s->name, mod->name);
continue;
}
s->module = exp->module;
@ -579,8 +993,7 @@ add_versions(struct buffer *b, struct module *mod)
continue;
}
if (!s->crc_valid) {
fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
"has no CRC!\n",
warn("\"%s\" [%s.ko] has no CRC!\n",
s->name, mod->name);
continue;
}
@ -590,8 +1003,8 @@ add_versions(struct buffer *b, struct module *mod)
buf_printf(b, "};\n");
}
void
add_depends(struct buffer *b, struct module *mod, struct module *modules)
static void add_depends(struct buffer *b, struct module *mod,
struct module *modules)
{
struct symbol *s;
struct module *m;
@ -621,8 +1034,7 @@ add_depends(struct buffer *b, struct module *mod, struct module *modules)
buf_printf(b, "\";\n");
}
void
add_srcversion(struct buffer *b, struct module *mod)
static void add_srcversion(struct buffer *b, struct module *mod)
{
if (mod->srcversion[0]) {
buf_printf(b, "\n");
@ -631,8 +1043,7 @@ add_srcversion(struct buffer *b, struct module *mod)
}
}
void
write_if_changed(struct buffer *b, const char *fname)
static void write_if_changed(struct buffer *b, const char *fname)
{
char *tmp;
FILE *file;
@ -676,8 +1087,7 @@ write_if_changed(struct buffer *b, const char *fname)
fclose(file);
}
void
read_dump(const char *fname)
static void read_dump(const char *fname, unsigned int kernel)
{
unsigned long size, pos = 0;
void *file = grab_file(fname, &size);
@ -691,6 +1101,7 @@ read_dump(const char *fname)
char *symname, *modname, *d;
unsigned int crc;
struct module *mod;
struct symbol *s;
if (!(symname = strchr(line, '\t')))
goto fail;
@ -711,15 +1122,30 @@ read_dump(const char *fname)
mod = new_module(NOFAIL(strdup(modname)));
mod->skip = 1;
}
add_exported_symbol(symname, mod, &crc);
s = sym_add_exported(symname, mod);
s->kernel = kernel;
s->preloaded = 1;
sym_update_crc(symname, mod, crc);
}
return;
fail:
fatal("parse error in symbol dump file\n");
}
void
write_dump(const char *fname)
/* For normal builds always dump all symbols.
* For external modules only dump symbols
* that are not read from kernel Module.symvers.
**/
static int dump_sym(struct symbol *sym)
{
if (!external_module)
return 1;
if (sym->vmlinux || sym->kernel)
return 0;
return 1;
}
static void write_dump(const char *fname)
{
struct buffer buf = { };
struct symbol *symbol;
@ -728,34 +1154,33 @@ write_dump(const char *fname)
for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
symbol = symbolhash[n];
while (symbol) {
symbol = symbol->next;
}
}
for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
symbol = symbolhash[n];
while (symbol) {
buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
symbol->name, symbol->module->name);
if (dump_sym(symbol))
buf_printf(&buf, "0x%08x\t%s\t%s\n",
symbol->crc, symbol->name,
symbol->module->name);
symbol = symbol->next;
}
}
write_if_changed(&buf, fname);
}
int
main(int argc, char **argv)
int main(int argc, char **argv)
{
struct module *mod;
struct buffer buf = { };
char fname[SZ];
char *dump_read = NULL, *dump_write = NULL;
char *kernel_read = NULL, *module_read = NULL;
char *dump_write = NULL;
int opt;
while ((opt = getopt(argc, argv, "i:mo:a")) != -1) {
while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) {
switch(opt) {
case 'i':
dump_read = optarg;
kernel_read = optarg;
break;
case 'I':
module_read = optarg;
external_module = 1;
break;
case 'm':
modversions = 1;
@ -771,8 +1196,10 @@ main(int argc, char **argv)
}
}
if (dump_read)
read_dump(dump_read);
if (kernel_read)
read_dump(kernel_read, 1);
if (module_read)
read_dump(module_read, 0);
while (optind < argc) {
read_symbols(argv[optind++]);
@ -799,4 +1226,3 @@ main(int argc, char **argv)
return 0;
}