Commit f864c7c2 authored by Kai Germaschewski's avatar Kai Germaschewski

kbuild: Merge file2alias into scripts/modpost.c

Up to now, we called "nm" to find the symbol table in vmlinux / modules.
Using code from scripts/file2alias.c allows us to do that parsing ourselves,
which is faster and will give us the opportunity to merge the
MODULE_DEVICE_TABLE() parsing into modpost, too.
parent cbc98ae5
...@@ -9,9 +9,11 @@ ...@@ -9,9 +9,11 @@
# conmakehash: Create arrays for initializing the kernel console tables # conmakehash: Create arrays for initializing the kernel console tables
host-progs := fixdep split-include conmakehash docproc kallsyms modpost \ host-progs := fixdep split-include conmakehash docproc kallsyms modpost \
file2alias mk_elfconfig mk_elfconfig
build-targets := $(host-progs) empty.o build-targets := $(host-progs) empty.o
modpost-objs := modpost.o file2alias.o
# Let clean descend into subdirs # Let clean descend into subdirs
subdir- := lxdialog kconfig subdir- := lxdialog kconfig
...@@ -20,12 +22,12 @@ $(addprefix $(obj)/,$(filter-out fixdep,$(host-progs))): $(obj)/fixdep ...@@ -20,12 +22,12 @@ $(addprefix $(obj)/,$(filter-out fixdep,$(host-progs))): $(obj)/fixdep
# dependencies on generated files need to be listed explicitly # dependencies on generated files need to be listed explicitly
$(obj)/file2alias: $(obj)/elfconfig.h $(obj)/modpost.o $(obj)/file2alias.o: $(obj)/elfconfig.h
quiet_cmd_elfconfig = MKTARGET $@ quiet_cmd_elfconfig = MKELF $@
cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@ cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@
$(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE $(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE
$(call if_changed,elfconfig) $(call if_changed,elfconfig)
targets += $(obj)/target.h targets += $(obj)/elfconfig.h
...@@ -27,7 +27,7 @@ quiet_cmd_ld_ko_o = LD [M] $@ ...@@ -27,7 +27,7 @@ quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
$(filter-out FORCE,$^) $(filter-out FORCE,$^)
$(modules): %.ko :%.o %.ver.o $(if CONFIG_HOTPLUG,%.aliases.o) FORCE $(modules): %.ko :%.o %.ver.o FORCE
$(call if_changed,ld_ko_o) $(call if_changed,ld_ko_o)
targets += $(modules) targets += $(modules)
...@@ -45,21 +45,6 @@ $(modules:.ko=.ver.o): %.ver.o: %.ver.c include/linux/compile.h FORCE ...@@ -45,21 +45,6 @@ $(modules:.ko=.ver.o): %.ver.o: %.ver.c include/linux/compile.h FORCE
targets += $(modules:.ko=.ver.o) targets += $(modules:.ko=.ver.o)
$(modules:.ko=.aliases.o): %.aliases.o: %.aliases.c FORCE
$(call if_changed,cc_o_c)
targets += $(modules:.ko=.aliases.o)
# Generate aliases
quiet_cmd_file2alias = ALIAS $@
cmd_file2alias = scripts/file2alias $< > $@
$(modules:.ko=.aliases.c): %.aliases.c: %.o FORCE
$(call if_changed,file2alias)
targets += $(modules:.ko=.aliases.c)
# All the .ver.c files are generated using the helper "modpost" # All the .ver.c files are generated using the helper "modpost"
.PHONY: __modpost .PHONY: __modpost
...@@ -69,7 +54,7 @@ $(modules:.ko=.ver.c): __modpost ; ...@@ -69,7 +54,7 @@ $(modules:.ko=.ver.c): __modpost ;
# Extract all checksums for all exported symbols # Extract all checksums for all exported symbols
quiet_cmd_modpost = MODPOST quiet_cmd_modpost = MODPOST
cmd_modpost = scripts/modpost $(NM) $^ cmd_modpost = scripts/modpost $^
__modpost: $(wildcard vmlinux) $(modules:.ko=.o) __modpost: $(wildcard vmlinux) $(modules:.ko=.o)
$(call if_changed,modpost) $(call if_changed,modpost)
......
/* Simple code to turn various tables in an ELF file into alias definitions. /* Simple code to turn various tables in an ELF file into alias definitions.
This deals with kernel datastructures where they should be * This deals with kernel datastructures where they should be
dealt with: in the kernel source. * dealt with: in the kernel source.
(C) 2002 Rusty Russell IBM Corporation. *
*/ * Copyright 2002-2003 Rusty Russell, IBM Corporation
#include <stdio.h> * 2003 Kai Germaschewski
#include <fcntl.h> *
#include <string.h> *
#include <errno.h> * This software may be used and distributed according to the terms
#include <unistd.h> * of the GNU General Public License, incorporated herein by reference.
#include <stdlib.h> */
#include <string.h>
#include <elf.h> #include "modpost.h"
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <endian.h>
#include "elfconfig.h"
/* We use the ELF typedefs, since we can't rely on stdint.h being present. */ /* We use the ELF typedefs, since we can't rely on stdint.h being present. */
...@@ -36,45 +29,6 @@ typedef unsigned char __u8; ...@@ -36,45 +29,6 @@ typedef unsigned char __u8;
* we handle those differences explicitly below */ * we handle those differences explicitly below */
#include "../include/linux/mod_devicetable.h" #include "../include/linux/mod_devicetable.h"
#if KERNEL_ELFCLASS == ELFCLASS32
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#else
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#endif
#if KERNEL_ELFDATA != HOST_ELFDATA
static void __endian(const void *src, void *dest, unsigned int size)
{
unsigned int i;
for (i = 0; i < size; i++)
((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
}
#define TO_NATIVE(x) \
({ \
typeof(x) __x; \
__endian(&(x), &(__x), sizeof(__x)); \
__x; \
})
#else /* endianness matches */
#define TO_NATIVE(x) (x)
#endif
#define ADD(str, sep, cond, field) \ #define ADD(str, sep, cond, field) \
do { \ do { \
strcat(str, sep); \ strcat(str, sep); \
...@@ -145,7 +99,7 @@ static int do_pci_entry(const char *filename, ...@@ -145,7 +99,7 @@ static int do_pci_entry(const char *filename,
ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice); ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice);
if (id->class_mask != 0 && id->class_mask != ~0) { if (id->class_mask != 0 && id->class_mask != ~0) {
fprintf(stderr, fprintf(stderr,
"file2alias: Can't handle class_mask in %s:%04X\n", "*** Warning: Can't handle class_mask in %s:%04X\n",
filename, id->class_mask); filename, id->class_mask);
return 0; return 0;
} }
...@@ -164,155 +118,61 @@ static inline int sym_is(const char *symbol, const char *name) ...@@ -164,155 +118,61 @@ static inline int sym_is(const char *symbol, const char *name)
return match[strlen(symbol)] == '\0'; return match[strlen(symbol)] == '\0';
} }
/* Returns 1 if we output anything. */ static void do_table(void *symval, unsigned long size,
static int do_table(void *symval, unsigned long size,
unsigned long id_size, unsigned long id_size,
void *function, void *function,
const char *filename, int *first) struct module *mod)
{ {
unsigned int i; unsigned int i;
char alias[500]; char alias[500];
int (*do_entry)(const char *, void *entry, char *alias) = function; int (*do_entry)(const char *, void *entry, char *alias) = function;
int wrote = 0;
if (size % id_size || size < id_size) { if (size % id_size || size < id_size) {
fprintf(stderr, "WARNING: %s ids %lu bad size (each on %lu)\n", fprintf(stderr, "*** Warning: %s ids %lu bad size "
filename, size, id_size); "(each on %lu)\n", mod->name, size, id_size);
return 0;
} }
/* Leave last one: it's the terminator. */ /* Leave last one: it's the terminator. */
size -= id_size; size -= id_size;
for (i = 0; i < size; i += id_size) { for (i = 0; i < size; i += id_size) {
if (do_entry(filename, symval+i, alias)) { if (do_entry(mod->name, symval+i, alias)) {
/* Always end in a wildcard, for future extension */ /* Always end in a wildcard, for future extension */
if (alias[strlen(alias)-1] != '*') if (alias[strlen(alias)-1] != '*')
strcat(alias, "*"); strcat(alias, "*");
if (*first) { buf_printf(&mod->dev_table_buf,
printf("#include <linux/module.h>\n\n"); "MODULE_ALIAS(\"%s\");\n", alias);
*first = 0;
}
printf("MODULE_ALIAS(\"%s\");\n", alias);
wrote = 1;
} }
} }
return wrote;
} }
/* This contains the cookie-cutter code for ELF handling (32 v 64). */ /* Create MODULE_ALIAS() statements.
static void analyze_file(Elf_Ehdr *hdr, * At this time, we cannot write the actual output C source yet,
unsigned int size, * so we write into the mod->dev_table_buf buffer. */
const char *filename) void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname)
{ {
unsigned int i, num_syms = 0;
Elf_Shdr *sechdrs;
Elf_Sym *syms = NULL;
char *secstrings, *strtab = NULL;
int first = 1;
if (size < sizeof(*hdr))
goto truncated;
sechdrs = (void *)hdr + TO_NATIVE(hdr->e_shoff);
hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
for (i = 0; i < hdr->e_shnum; i++) {
sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
}
/* Find symbol table. */
secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
for (i = 1; i < hdr->e_shnum; i++) {
if (sechdrs[i].sh_offset > size)
goto truncated;
if (sechdrs[i].sh_type == SHT_SYMTAB) {
syms = (void *)hdr + sechdrs[i].sh_offset;
num_syms = sechdrs[i].sh_size / sizeof(syms[0]);
} else if (sechdrs[i].sh_type == SHT_STRTAB)
strtab = (void *)hdr + sechdrs[i].sh_offset;
}
if (!strtab || !syms) {
fprintf(stderr, "table2alias: %s no symtab?\n", filename);
abort();
}
for (i = 0; i < num_syms; i++) {
const char *symname;
void *symval; void *symval;
syms[i].st_shndx = TO_NATIVE(syms[i].st_shndx); /* We're looking for a section relative symbol */
syms[i].st_name = TO_NATIVE(syms[i].st_name); if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum)
syms[i].st_value = TO_NATIVE(syms[i].st_value); return;
syms[i].st_size = TO_NATIVE(syms[i].st_size);
if (!syms[i].st_shndx || syms[i].st_shndx >= hdr->e_shnum) symval = (void *)info->hdr
continue; + info->sechdrs[sym->st_shndx].sh_offset
+ sym->st_value;
symname = strtab + syms[i].st_name;
symval = (void *)hdr
+ sechdrs[syms[i].st_shndx].sh_offset
+ syms[i].st_value;
if (sym_is(symname, "__mod_pci_device_table")) if (sym_is(symname, "__mod_pci_device_table"))
do_table(symval, syms[i].st_size, do_table(symval, sym->st_size, sizeof(struct pci_device_id),
sizeof(struct pci_device_id), do_pci_entry, mod);
do_pci_entry, filename, &first);
else if (sym_is(symname, "__mod_usb_device_table")) else if (sym_is(symname, "__mod_usb_device_table"))
do_table(symval, syms[i].st_size, do_table(symval, sym->st_size, sizeof(struct usb_device_id),
sizeof(struct usb_device_id), do_usb_entry, mod);
do_usb_entry, filename, &first);
}
return;
truncated:
fprintf(stderr, "table2alias: %s is truncated.\n", filename);
abort();
} }
static void *grab_file(const char *filename, unsigned long *size) /* Now add out buffered information to the generated C source */
void add_moddevtable(struct buffer *buf, struct module *mod)
{ {
struct stat st; buf_printf(buf, "\n");
void *map; buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
int fd; free(mod->dev_table_buf.p);
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
if (fstat(fd, &st) != 0) {
close(fd);
return NULL;
}
*size = st.st_size;
map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
if (mmap == MAP_FAILED) {
close(fd);
return NULL;
}
close(fd);
return map;
}
/* Look through files for __mod_*_device_table: emit alias definitions
for compiling in. */
int main(int argc, char *argv[])
{
void *file;
unsigned long size;
for (; argv[1]; argv++) {
file = grab_file(argv[1], &size);
if (!file) {
fprintf(stderr, "file2alias: opening %s: %s\n",
argv[1], strerror(errno));
abort();
}
analyze_file(file, size, argv[1]);
munmap(file, size);
}
return 0;
} }
/* Postprocess module symbol versions /* Postprocess module symbol versions
* *
* Copyright 2003 Kai Germaschewski * Copyright 2003 Kai Germaschewski
* 2002 Rusty Russell IBM Corporation * 2002-2003 Rusty Russell, IBM Corporation
* *
* Based in part on module-init-tools/depmod.c * Based in part on module-init-tools/depmod.c,file2alias
* *
* This software may be used and distributed according to the terms * This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference. * of the GNU General Public License, incorporated herein by reference.
* *
* Usage: modpost $(NM) vmlinux module1.o module2.o ... * Usage: modpost vmlinux module1.o module2.o ...
*/ */
#include <stdio.h> #include "modpost.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* nm command */
const char *nm;
/* Are we using CONFIG_MODVERSIONS? */ /* Are we using CONFIG_MODVERSIONS? */
int modversions = 0; int modversions = 0;
void
usage(void)
{
fprintf(stderr, "Usage: modpost $(NM) vmlinux module1.o module2.o\n");
exit(1);
}
void void
fatal(const char *fmt, ...) fatal(const char *fmt, ...)
{ {
...@@ -71,15 +55,30 @@ void *do_nofail(void *ptr, const char *file, int line, const char *expr) ...@@ -71,15 +55,30 @@ void *do_nofail(void *ptr, const char *file, int line, const char *expr)
/* A list of all modules we processed */ /* A list of all modules we processed */
struct module {
struct module *next;
const char *name;
struct symbol *unres;
int seen;
};
static struct module *modules; static struct module *modules;
struct module *
new_module(char *modname)
{
struct module *mod;
char *p;
/* strip trailing .o */
p = strstr(modname, ".o");
if (p)
*p = 0;
mod = NOFAIL(malloc(sizeof(*mod)));
memset(mod, 0, sizeof(*mod));
mod->name = modname;
/* add to list */
mod->next = modules;
modules = mod;
return mod;
}
/* A hash of all exported symbols, /* A hash of all exported symbols,
* struct symbol is also used for lists of unresolved symbols */ * struct symbol is also used for lists of unresolved symbols */
...@@ -159,7 +158,7 @@ find_symbol(const char *name) ...@@ -159,7 +158,7 @@ find_symbol(const char *name)
/* Add an exported symbol - it may have already been added without a /* Add an exported symbol - it may have already been added without a
* CRC, in this case just update the CRC */ * CRC, in this case just update the CRC */
void void
add_symbol(const char *name, struct module *module, unsigned int *crc) add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
{ {
struct symbol *s = find_symbol(name); struct symbol *s = find_symbol(name);
...@@ -173,74 +172,162 @@ add_symbol(const char *name, struct module *module, unsigned int *crc) ...@@ -173,74 +172,162 @@ add_symbol(const char *name, struct module *module, unsigned int *crc)
} }
} }
#define SZ 500 void *
grab_file(const char *filename, unsigned long *size)
{
struct stat st;
void *map;
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror(filename);
abort();
}
if (fstat(fd, &st) != 0) {
perror(filename);
abort();
}
*size = st.st_size;
map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
if (mmap == MAP_FAILED) {
perror(filename);
abort();
}
close(fd);
return map;
}
void void
read_symbols(char *modname) parse_elf(struct elf_info *info, const char *filename)
{ {
struct module *mod; unsigned int i;
struct symbol *s; Elf_Ehdr *hdr = info->hdr;
char buf[SZ], sym[SZ], *p; Elf_Shdr *sechdrs;
FILE *pipe; Elf_Sym *sym;
unsigned int crc;
int rc; hdr = grab_file(filename, &info->size);
info->hdr = hdr;
if (info->size < sizeof(*hdr))
goto truncated;
/* Fix endianness in ELF header */
hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
sechdrs = (void *)hdr + hdr->e_shoff;
info->sechdrs = sechdrs;
/* Fix endianness in section headers */
for (i = 0; i < hdr->e_shnum; i++) {
sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
}
/* Find symbol table. */
for (i = 1; i < hdr->e_shnum; i++) {
if (sechdrs[i].sh_offset > info->size)
goto truncated;
if (sechdrs[i].sh_type != SHT_SYMTAB)
continue;
/* read nm output */ info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
snprintf(buf, SZ, "%s --no-sort %s", nm, modname); info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset
pipe = NOFAIL(popen(buf, "r")); + sechdrs[i].sh_size;
info->strtab = (void *)hdr +
sechdrs[sechdrs[i].sh_link].sh_offset;
}
if (!info->symtab_start) {
fprintf(stderr, "modpost: %s no symtab?\n", filename);
abort();
}
/* Fix endianness in symbols */
for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
sym->st_shndx = TO_NATIVE(sym->st_shndx);
sym->st_name = TO_NATIVE(sym->st_name);
sym->st_value = TO_NATIVE(sym->st_value);
sym->st_size = TO_NATIVE(sym->st_size);
}
return;
/* strip trailing .o */ truncated:
p = strstr(modname, ".o"); fprintf(stderr, "modpost: %s is truncated.\n", filename);
if (p) abort();
*p = 0; }
mod = NOFAIL(malloc(sizeof(*mod))); void
mod->name = modname; parse_elf_finish(struct elf_info *info)
/* add to list */ {
mod->next = modules; munmap(info->hdr, info->size);
modules = mod; }
while (fgets(buf, SZ, pipe)) { void
/* actual CRCs */ handle_modversions(struct module *mod, struct elf_info *info,
rc = sscanf(buf, "%x A __crc_%s\n", &crc, sym); Elf_Sym *sym, const char *symname)
if (rc == 2) { {
add_symbol(sym, mod, &crc); struct symbol *s;
modversions = 1;
continue;
}
/* all exported symbols */ switch (sym->st_shndx) {
rc = sscanf(buf, "%x r __ksymtab_%s", &crc, sym); case SHN_COMMON:
if (rc == 2) { fprintf(stderr, "*** Warning: \"%s\" [%s] is COMMON symbol\n",
add_symbol(sym, mod, NULL); symname, mod->name);
continue; break;
case SHN_ABS:
/* CRC'd symbol */
if (memcmp(symname, "__crc_", 6) == 0) {
add_exported_symbol(symname+6, mod, &sym->st_value);
modversions = 1;
} }
break;
case SHN_UNDEF:
/* undefined symbol */
if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL)
break;
/* all unresolved symbols */ s = alloc_symbol(symname);
rc = sscanf(buf, " U %s\n", sym);
if (rc == 1) {
s = alloc_symbol(sym);
/* add to list */ /* add to list */
s->next = mod->unres; s->next = mod->unres;
mod->unres = s; mod->unres = s;
continue; break;
default:
/* All exported symbols */
if (memcmp(symname, "__ksymtab_", 10) == 0) {
add_exported_symbol(symname+10, mod, NULL);
}
break;
}
}
void
read_symbols(char *modname)
{
const char *symname;
struct module *mod;
struct elf_info info = { };
Elf_Sym *sym;
parse_elf(&info, modname);
mod = new_module(modname);
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
symname = info.strtab + sym->st_name;
handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname);
} }
}; parse_elf_finish(&info);
pclose(pipe);
} }
#define SZ 500
/* We first write the generated file into memory using the /* We first write the generated file into memory using the
* following helper, then compare to the file on disk and * following helper, then compare to the file on disk and
* only update the later if anything changed */ * only update the later if anything changed */
struct buffer { void __attribute__((format(printf, 2, 3)))
char *p;
int pos;
int size;
};
void
__attribute__((format(printf, 2, 3)))
buf_printf(struct buffer *buf, const char *fmt, ...) buf_printf(struct buffer *buf, const char *fmt, ...)
{ {
char tmp[SZ]; char tmp[SZ];
...@@ -250,11 +337,7 @@ buf_printf(struct buffer *buf, const char *fmt, ...) ...@@ -250,11 +337,7 @@ buf_printf(struct buffer *buf, const char *fmt, ...)
va_start(ap, fmt); va_start(ap, fmt);
len = vsnprintf(tmp, SZ, fmt, ap); len = vsnprintf(tmp, SZ, fmt, ap);
if (buf->size - buf->pos < len + 1) { if (buf->size - buf->pos < len + 1) {
if (buf->size == 0) buf->size += 128;
buf->size = 1024;
else
buf->size *= 2;
buf->p = realloc(buf->p, buf->size); buf->p = realloc(buf->p, buf->size);
} }
strncpy(buf->p + buf->pos, tmp, len + 1); strncpy(buf->p + buf->pos, tmp, len + 1);
...@@ -262,6 +345,17 @@ buf_printf(struct buffer *buf, const char *fmt, ...) ...@@ -262,6 +345,17 @@ buf_printf(struct buffer *buf, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
void
buf_write(struct buffer *buf, const char *s, int len)
{
if (buf->size - buf->pos < len) {
buf->size += len;
buf->p = realloc(buf->p, buf->size);
}
strncpy(buf->p + buf->pos, s, len);
buf->pos += len;
}
/* Header for the generated file */ /* Header for the generated file */
void void
...@@ -399,18 +493,12 @@ write_if_changed(struct buffer *b, const char *fname) ...@@ -399,18 +493,12 @@ write_if_changed(struct buffer *b, const char *fname)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int i;
struct module *mod; struct module *mod;
struct buffer buf = { }; struct buffer buf = { };
char fname[SZ]; char fname[SZ];
if (argc < 3) for (; argv[1]; argv++) {
usage(); read_symbols(argv[1]);
nm = argv[1];
for (i = 2; i < argc; i++) {
read_symbols(argv[i]);
} }
for (mod = modules; mod; mod = mod->next) { for (mod = modules; mod; mod = mod->next) {
...@@ -422,6 +510,7 @@ main(int argc, char **argv) ...@@ -422,6 +510,7 @@ main(int argc, char **argv)
add_header(&buf); add_header(&buf);
add_versions(&buf, mod); add_versions(&buf, mod);
add_depends(&buf, mod, modules); add_depends(&buf, mod, modules);
add_moddevtable(&buf, mod);
sprintf(fname, "%s.ver.c", mod->name); sprintf(fname, "%s.ver.c", mod->name);
write_if_changed(&buf, fname); write_if_changed(&buf, fname);
......
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <elf.h>
#include "elfconfig.h"
#if KERNEL_ELFCLASS == ELFCLASS32
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define ELF_ST_BIND ELF32_ST_BIND
#else
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define ELF_ST_BIND ELF64_ST_BIND
#endif
#if KERNEL_ELFDATA != HOST_ELFDATA
static void __endian(const void *src, void *dest, unsigned int size)
{
unsigned int i;
for (i = 0; i < size; i++)
((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
}
#define TO_NATIVE(x) \
({ \
typeof(x) __x; \
__endian(&(x), &(__x), sizeof(__x)); \
__x; \
})
#else /* endianness matches */
#define TO_NATIVE(x) (x)
#endif
struct buffer {
char *p;
int pos;
int size;
};
void __attribute__((format(printf, 2, 3)))
buf_printf(struct buffer *buf, const char *fmt, ...);
void
buf_write(struct buffer *buf, const char *s, int len);
struct module {
struct module *next;
const char *name;
struct symbol *unres;
int seen;
struct buffer dev_table_buf;
};
struct elf_info {
unsigned long size;
Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
Elf_Sym *symtab_start;
Elf_Sym *symtab_stop;
const char *strtab;
};
void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname);
void add_moddevtable(struct buffer *buf, struct module *mod);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment