elf_file encapsulates an in-memory ELF file and related operations needed by depmod, modprobe and other tools. This class is based on struct module, as defined in depmod.h and will gradually replace moduleops.c In this commit, elf_file has no users, but compiles cleanly. Signed-off-by: Andreas Robinson <andr345@xxxxxxxxx> --- elf_core.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ elfops.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ elfops.h | 31 ++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 0 deletions(-) diff --git a/elf_core.c b/elf_core.c index 5280b5d..bfd81a5 100644 --- a/elf_core.c +++ b/elf_core.c @@ -4,12 +4,22 @@ #define ElfPERBIT(x) Elf32_##x #define ELFPERBIT(x) ELF32_##x +struct kernel_symbol32 { + char value[4]; + char name[64 - 4]; +}; + #elif defined(ELF64BIT) #define PERBIT(x) x##64 #define ElfPERBIT(x) Elf64_##x #define ELFPERBIT(x) ELF64_##x +struct kernel_symbol64 { + char value[8]; + char name[64 - 8]; +}; + #else # error "Undefined ELF word length" #endif @@ -57,6 +67,67 @@ void *PERBIT(get_section)(void *file, return NULL; } +static void *PERBIT(load_section)(struct elf_file *file, + const char *secname, + unsigned long *secsize) +{ + return PERBIT(get_section)(file->data, 0, secname, secsize, file->conv); +} + +static int PERBIT(load_strings)(struct elf_file *file, + const char *secname, + void (*callback)(const char *str, void *cb_data), + void *cb_data) +{ + unsigned long secsize; + const char *strings; + int n = 0; + + strings = PERBIT(load_section)(file, secname, &secsize); + if (strings) { + /* Skip any zero padding. */ + for (; !*strings; strings++) + if (--secsize == 0) + return 0; + for (; strings; strings = next_string(strings, &secsize), n++) + callback(strings, cb_data); + } + return n; +} + +static int PERBIT(load_symbols)(struct elf_file *file, + void (*callback)(const char *str, void *cb_data), + void *cb_data) +{ + struct PERBIT(kernel_symbol) *ksyms; + unsigned long i, size; + int n; + + /* New-style: strings are in this section. */ + n = PERBIT(load_strings)(file, "__ksymtab_strings", callback, cb_data); + if (n > 0) { + /* GPL symbols too */ + n += PERBIT(load_strings)(file, "__ksymtab_strings_gpl", + callback, cb_data); + return n; + } + + /* Old-style. */ + ksyms = PERBIT(load_section)(file, "__ksymtab", &size); + for (i = 0; i < size / sizeof(struct PERBIT(kernel_symbol)); i++, n++) + callback(ksyms[i].name, cb_data); + ksyms = PERBIT(load_section)(file, "__gpl_ksymtab", &size); + for (i = 0; i < size / sizeof(struct PERBIT(kernel_symbol)); i++, n++) + callback(ksyms[i].name, cb_data); + return n; +} + +struct elf_ops PERBIT(elf_ops) = { + .load_section = PERBIT(load_section), + .load_strings = PERBIT(load_strings), + .load_symbols = PERBIT(load_symbols), +}; + #undef PERBIT #undef ElfPERBIT #undef ELFPERBIT diff --git a/elfops.c b/elfops.c index 550266c..1c4ff3a 100644 --- a/elfops.c +++ b/elfops.c @@ -50,3 +50,64 @@ void *get_section(void *file, unsigned long filesize, return NULL; } } + +struct elf_file *grab_elf_fd(const char *pathname, int fd) +{ + struct elf_file *file; + + file = NOFAIL(malloc(sizeof(*file) + strlen(pathname) + 1)); + strcpy(file->pathname, pathname); + + file->data = grab_fd(fd, &file->len); + if (!file->data) { + warn("Could not read '%s': %s\n", + file->pathname, strerror(errno)); + goto fail; + } + switch (elf_ident(file->data, file->len, &file->conv)) { + case ELFCLASS32: + file->ops = &elf_ops32; + break; + case ELFCLASS64: + file->ops = &elf_ops64; + break; + case -ENOEXEC: + warn("Module %s is not an ELF object\n", file->pathname); + goto fail; + case -EINVAL: + warn("Module %s has unknown endianness\n", file->pathname); + goto fail; + default: + warn("Module %s has unknown word size\n", file->pathname); + goto fail; + } + return file; + +fail: + release_elf_file(file); + return NULL; +} + +struct elf_file *grab_elf_file(char *pathname) +{ + struct elf_file *file; + int fd = open(pathname, O_RDONLY, 0); + if (fd < 0) { + warn("Could not open '%s': %s\n", pathname, strerror(errno)); + return NULL; + } + file = grab_elf_fd(pathname, fd); + close(fd); + return file; +} + +void release_elf_file(struct elf_file *file) +{ + if (!file) + return; + release_file(file->data, file->len); + file->data = NULL; + file->len = 0; + free(file); +} + diff --git a/elfops.h b/elfops.h index 41ea8b4..54b3e0d 100644 --- a/elfops.h +++ b/elfops.h @@ -1,6 +1,33 @@ #ifndef MODINITTOOLS_ELFOPS_H #define MODINITTOOLS_ELFOPS_H +struct elf_file; + +struct elf_ops +{ + void *(*load_section)(struct elf_file *file, + const char *name, unsigned long *size); + int (*load_strings)(struct elf_file *file, const char *secname, + void (*callback)(const char *str, void *cb_data), void *cb_data); + int (*load_symbols)(struct elf_file *file, + void (*callback)(const char *str, void *cb_data), void *cb_data); +}; + +struct elf_file +{ + /* 64 or 32 bit? */ + struct elf_ops *ops; + + /* Convert endianness? */ + int conv; + + /* File contents and length. */ + void *data; + unsigned long len; + + char pathname[0]; +}; + int elf_ident(void *file, unsigned long fsize, int *conv); void *get_section(void *file, unsigned long filesize, const char *secname, unsigned long *secsize); @@ -9,5 +36,9 @@ void *get_section32(void *file, unsigned long filesize, void *get_section64(void *file, unsigned long filesize, const char *secname, unsigned long *secsize, int conv); +struct elf_file *grab_elf_file(char *pathname); +struct elf_file *grab_elf_fd(const char *pathname, int fd); +void release_elf_file(struct elf_file *file); + #endif /* MODINITTOOLS_ELFOPS_H */ -- 1.6.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-modules" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html