aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Masters <jcm@jonmasters.org>2009-05-19 04:50:10 -0400
committerJon Masters <jcm@jonmasters.org>2009-05-19 04:50:10 -0400
commit2d23075ca0f6560901ddda3645ba49d4c330a867 (patch)
treeea89f07256f93faabfe1e26108364bae3825e0a2
parentaa6fe1585412d5ad603fc81b7075dffb93a8b8f2 (diff)
parent4646064c0335e9c71c9124bacabd6b5e2827e3e9 (diff)
downloadmodule-init-tools-2d23075ca0f6560901ddda3645ba49d4c330a867.tar.gz
Merge branch 'elf_cleanup2' of ../module_init_tools_andr345
-rw-r--r--depmod.c42
-rw-r--r--depmod.h2
-rw-r--r--elfops.c98
-rw-r--r--elfops.h31
-rw-r--r--elfops_core.c87
-rw-r--r--logging.h6
-rw-r--r--modinfo.c120
-rw-r--r--modprobe.c180
-rw-r--r--tables.c19
9 files changed, 305 insertions, 280 deletions
diff --git a/depmod.c b/depmod.c
index a7bd948..e636659 100644
--- a/depmod.c
+++ b/depmod.c
@@ -264,7 +264,6 @@ static int ends_in(const char *name, const char *ext)
static struct module *grab_module(const char *dirname, const char *filename)
{
struct module *new;
- struct elf_file *file;
new = NOFAIL(malloc(sizeof(*new)
+ strlen(dirname?:"") + 1 + strlen(filename) + 1));
@@ -277,39 +276,14 @@ static struct module *grab_module(const char *dirname, const char *filename)
INIT_LIST_HEAD(&new->dep_list);
new->order = INDEX_PRIORITY_MIN;
- file = &new->file;
-
- file->data = grab_file(new->pathname, &file->len);
- if (!file->data) {
+ new->file = grab_elf_file(new->pathname);
+ if (!new->file) {
warn("Can't read module %s: %s\n",
new->pathname, strerror(errno));
- goto fail_data;
+ free(new);
+ return NULL;
}
-
- switch (elf_ident(file->data, file->len, &file->conv)) {
- case ELFCLASS32:
- file->ops = &mod_ops32;
- break;
- case ELFCLASS64:
- file->ops = &mod_ops64;
- break;
- case -ENOEXEC:
- warn("Module %s is not an elf object\n", new->pathname);
- goto fail;
- case -EINVAL:
- warn("Module %s has unknown endianness\n", new->pathname);
- goto fail;
- default:
- warn("Module %s has unknown word size\n", new->pathname);
- goto fail;
- }
return new;
-
-fail:
- release_file(file->data, new->file.len);
-fail_data:
- free(new);
- return NULL;
}
struct module_traverse
@@ -680,7 +654,7 @@ static void calculate_deps(struct module *module)
module->num_deps = 0;
module->deps = NULL;
- file = &module->file;
+ file = module->file;
symnames = file->ops->load_dep_syms(module->pathname, file, &symtypes);
if (!symnames || !symtypes)
@@ -714,7 +688,7 @@ static struct module *parse_modules(struct module *list)
int j;
for (i = list; i; i = i->next) {
- file = &i->file;
+ file = i->file;
syms = file->ops->load_symbols(file);
if (syms) {
for (j = 0; j < syms->cnt; j++)
@@ -803,7 +777,7 @@ static void output_aliases(struct module *modules, FILE *out, char *dirname)
for (i = modules; i; i = i->next) {
char modname[strlen(i->pathname)+1];
- file = &i->file;
+ file = i->file;
filename2modname(modname, i->pathname);
/* Grab from old-style .modalias section. */
@@ -838,7 +812,7 @@ static void output_aliases_bin(struct module *modules, FILE *out, char *dirname)
for (i = modules; i; i = i->next) {
char modname[strlen(i->pathname)+1];
- file = &i->file;
+ file = i->file;
filename2modname(modname, i->pathname);
/* Grab from old-style .modalias section. */
diff --git a/depmod.h b/depmod.h
index be06b7c..d6d61f6 100644
--- a/depmod.h
+++ b/depmod.h
@@ -23,7 +23,7 @@ struct module
/* Tables extracted from module by ops->fetch_tables(). */
struct module_tables tables;
- struct elf_file file;
+ struct elf_file *file;
char *basename; /* points into pathname */
char pathname[0];
diff --git a/elfops.c b/elfops.c
index 9ae77ef..da2740e 100644
--- a/elfops.c
+++ b/elfops.c
@@ -5,16 +5,29 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <fcntl.h>
#include "depmod.h"
#include "util.h"
#include "logging.h"
#include "elfops.h"
#include "tables.h"
+#include "zlibsupport.h"
+
+#include "testing.h"
/* Symbol types, returned by load_dep_syms */
static const char *weak_sym = "W";
static const char *undef_sym = "U";
+/* dump_modversions helper */
+static const char *skip_dot(const char *str)
+{
+ /* For our purposes, .foo matches foo. PPC64 needs this. */
+ if (str && str[0] == '.')
+ return str + 1;
+ return str;
+}
+
#define ELF32BIT
#include "elfops_core.c"
#undef ELF32BIT
@@ -26,7 +39,7 @@ static const char *undef_sym = "U";
/*
* Check ELF file header.
*/
-int elf_ident(void *file, unsigned long fsize, int *conv)
+static int elf_ident(void *file, unsigned long fsize, int *conv)
{
/* "\177ELF" <byte> where byte = 001 for 32-bit, 002 for 64 */
unsigned char *ident = file;
@@ -41,17 +54,84 @@ int elf_ident(void *file, unsigned long fsize, int *conv)
return ident[EI_CLASS];
}
-void *get_section(void *file, unsigned long filesize,
- const char *secname, unsigned long *secsize)
+/*
+ * grab_elf_file - read ELF file into memory
+ * @pathame: file to load
+ *
+ * Returns NULL, and errno set on error.
+ */
+struct elf_file *grab_elf_file(const char *pathname)
+{
+ int fd;
+ int err;
+ struct elf_file *file;
+
+ fd = open(pathname, O_RDONLY, 0);
+ if (fd < 0)
+ return NULL;
+ file = grab_elf_file_fd(pathname, fd);
+
+ err = errno;
+ close(fd);
+ errno = err;
+ return file;
+}
+
+/*
+ * grab_elf_file_fd - read ELF file from file descriptor into memory
+ * @pathame: name of file to load
+ * @fd: file descriptor of file to load
+ *
+ * Returns NULL, and errno set on error.
+ */
+struct elf_file *grab_elf_file_fd(const char *pathname, int fd)
{
- int conv;
+ struct elf_file *file;
- switch (elf_ident(file, filesize, &conv)) {
+ file = malloc(sizeof(*file));
+ if (!file) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ file->pathname = strdup(pathname);
+ if (!file->pathname) {
+ free(file);
+ errno = ENOMEM;
+ return NULL;
+ }
+ file->data = grab_fd(fd, &file->len);
+ if (!file->data)
+ goto fail;
+
+ switch (elf_ident(file->data, file->len, &file->conv)) {
case ELFCLASS32:
- return get_section32(file, filesize, secname, secsize, conv);
+ file->ops = &mod_ops32;
+ break;
case ELFCLASS64:
- return get_section64(file, filesize, secname, secsize, conv);
- default:
- return NULL;
+ file->ops = &mod_ops64;
+ break;
+ case -ENOEXEC: /* Not an ELF object */
+ case -EINVAL: /* Unknown endianness */
+ default: /* Unknown word size */
+ errno = ENOEXEC;
+ goto fail;
}
+ return file;
+fail:
+ release_elf_file(file);
+ return NULL;
+}
+
+void release_elf_file(struct elf_file *file)
+{
+ int err = errno;
+
+ if (!file)
+ return;
+
+ release_file(file->data, file->len);
+ free(file->pathname);
+ free(file);
+
+ errno = err;
}
diff --git a/elfops.h b/elfops.h
index dc10c3d..7069d92 100644
--- a/elfops.h
+++ b/elfops.h
@@ -1,6 +1,7 @@
#ifndef MODINITTOOLS_MODULEOPS_H
#define MODINITTOOLS_MODULEOPS_H
#include <stdio.h>
+#include <stdint.h>
/* All the icky stuff to do with manipulating 64 and 32-bit modules
belongs here. */
@@ -14,8 +15,22 @@ struct kernel_symbol64 {
char name[64 - 8];
};
+struct modver_info32
+{
+ uint32_t crc;
+ char name[64 - sizeof(uint32_t)];
+};
+
+struct modver_info64
+{
+ uint64_t crc;
+ char name[64 - sizeof(uint64_t)];
+};
+
struct elf_file
{
+ char *pathname;
+
/* File operations */
struct module_ops *ops;
@@ -54,8 +69,8 @@ struct module_tables
struct module_ops
{
- struct string_table *(*load_strings)(struct elf_file *module,
- const char *secname, struct string_table *tbl);
+ void *(*load_section)(struct elf_file *module,
+ const char *secname, unsigned long *secsize);
struct string_table *(*load_symbols)(struct elf_file *module);
struct string_table *(*load_dep_syms)(const char *pathname,
struct elf_file *module, struct string_table **types);
@@ -63,16 +78,14 @@ struct module_ops
struct module_tables *tables);
char *(*get_aliases)(struct elf_file *module, unsigned long *size);
char *(*get_modinfo)(struct elf_file *module, unsigned long *size);
+ void (*strip_section)(struct elf_file *module, const char *secname);
+ int (*dump_modvers)(struct elf_file *module);
};
extern struct module_ops mod_ops32, mod_ops64;
-int elf_ident(void *file, unsigned long fsize, int *conv);
-void *get_section(void *file, unsigned long filesize,
- const char *secname, unsigned long *secsize);
-void *get_section32(void *file, unsigned long filesize,
- const char *secname, unsigned long *secsize, int conv);
-void *get_section64(void *file, unsigned long filesize,
- const char *secname, unsigned long *secsize, int conv);
+struct elf_file *grab_elf_file(const char *pathname);
+struct elf_file *grab_elf_file_fd(const char *pathname, int fd);
+void release_elf_file(struct elf_file *file);
#endif /* MODINITTOOLS_MODULEOPS_H */
diff --git a/elfops_core.c b/elfops_core.c
index 8b7f4de..39fd4c3 100644
--- a/elfops_core.c
+++ b/elfops_core.c
@@ -3,54 +3,66 @@
#define PERBIT(x) x##32
#define ElfPERBIT(x) Elf32_##x
#define ELFPERBIT(x) ELF32_##x
+/* 32-bit unsigned integer */
+#define Elf32_Uint Elf32_Word
#elif defined(ELF64BIT)
#define PERBIT(x) x##64
#define ElfPERBIT(x) Elf64_##x
#define ELFPERBIT(x) ELF64_##x
+/* 64-bit unsigned integer */
+#define Elf64_Uint Elf64_Xword
#else
# error "Undefined ELF word length"
#endif
-void *PERBIT(get_section)(void *file,
- unsigned long fsize,
- const char *secname,
- unsigned long *secsize,
- int conv)
+static void *PERBIT(get_section)(struct elf_file *module,
+ const char *secname,
+ ElfPERBIT(Shdr) **sechdr,
+ unsigned long *secsize)
{
+ void *data = module->data;
+ unsigned long len = module->len;
+ int conv = module->conv;
+
ElfPERBIT(Ehdr) *hdr;
ElfPERBIT(Shdr) *sechdrs;
ElfPERBIT(Off) e_shoff;
ElfPERBIT(Half) e_shnum, e_shstrndx;
+ ElfPERBIT(Off) secoffset;
const char *secnames;
unsigned int i;
- if (fsize > 0 && fsize < sizeof(*hdr))
+ if (len <= 0 || len < sizeof(*hdr))
return NULL;
- hdr = file;
+ hdr = data;
e_shoff = END(hdr->e_shoff, conv);
e_shnum = END(hdr->e_shnum, conv);
e_shstrndx = END(hdr->e_shstrndx, conv);
- if (fsize > 0 && fsize < e_shoff + e_shnum * sizeof(sechdrs[0]))
+ if (len < e_shoff + e_shnum * sizeof(sechdrs[0]))
return NULL;
- sechdrs = file + e_shoff;
+ sechdrs = data + e_shoff;
- if (fsize > 0 && fsize < END(sechdrs[e_shstrndx].sh_offset, conv))
+ if (len < END(sechdrs[e_shstrndx].sh_offset, conv))
return NULL;
- /* Find section by name, return pointer and size. */
-
- secnames = file + END(sechdrs[e_shstrndx].sh_offset, conv);
+ /* Find section by name; return header, pointer and size. */
+ secnames = data + END(sechdrs[e_shstrndx].sh_offset, conv);
for (i = 1; i < e_shnum; i++) {
if (streq(secnames + END(sechdrs[i].sh_name, conv), secname)) {
*secsize = END(sechdrs[i].sh_size, conv);
- return file + END(sechdrs[i].sh_offset, conv);
+ secoffset = END(sechdrs[i].sh_offset, conv);
+ if (sechdr)
+ *sechdr = sechdrs + i;
+ if (len < secoffset + *secsize)
+ return NULL;
+ return data + secoffset;
}
}
*secsize = 0;
@@ -62,7 +74,7 @@ static void *PERBIT(load_section)(struct elf_file *module,
const char *secname,
unsigned long *secsize)
{
- return PERBIT(get_section)(module->data, 0, secname, secsize, module->conv);
+ return PERBIT(get_section)(module, secname, NULL, secsize);
}
static struct string_table *PERBIT(load_strings)(struct elf_file *module,
@@ -289,13 +301,56 @@ static void PERBIT(fetch_tables)(struct elf_file *module,
}
}
+/*
+ * strip_section - tell the kernel to ignore the named section
+ */
+static void PERBIT(strip_section)(struct elf_file *module, const char *secname)
+{
+ void *p;
+ ElfPERBIT(Shdr) *sechdr;
+ unsigned long secsize;
+
+ p = PERBIT(get_section)(module, secname, &sechdr, &secsize);
+ if (p) {
+ ElfPERBIT(Uint) mask;
+ mask = ~((ElfPERBIT(Uint))SHF_ALLOC);
+ sechdr->sh_flags &= END(mask, module->conv);
+ }
+}
+
+static int PERBIT(dump_modversions)(struct elf_file *module)
+{
+ unsigned long secsize;
+ struct PERBIT(modver_info) *info;
+ int n = 0;
+
+ info = module->ops->load_section(module, "__versions", &secsize);
+ if (!info)
+ return 0; /* not a kernel module */
+ if (secsize % sizeof(*info) != 0)
+ return -1; /* invalid section size */
+
+ for (n = 0; n < secsize / sizeof(*info); n++) {
+#if defined(ELF32BIT)
+ printf("0x%08lx\t%s\n", (unsigned long)
+#else /* defined(ELF64BIT) */
+ printf("0x%08llx\t%s\n", (unsigned long long)
+#endif
+ END(info[n].crc, module->conv),
+ skip_dot(info[n].name));
+ }
+ return n;
+}
+
struct module_ops PERBIT(mod_ops) = {
- .load_strings = PERBIT(load_strings),
+ .load_section = PERBIT(load_section),
.load_symbols = PERBIT(load_symbols),
.load_dep_syms = PERBIT(load_dep_syms),
.fetch_tables = PERBIT(fetch_tables),
.get_aliases = PERBIT(get_aliases),
.get_modinfo = PERBIT(get_modinfo),
+ .strip_section = PERBIT(strip_section),
+ .dump_modvers = PERBIT(dump_modversions),
};
#undef PERBIT
diff --git a/logging.h b/logging.h
index 4c25f5c..b7227bc 100644
--- a/logging.h
+++ b/logging.h
@@ -27,8 +27,10 @@ static inline void grammar(const char *cmd,
#define NOFAIL(ptr) do_nofail((ptr), __FILE__, __LINE__, #ptr)
-#define nofail_asprintf(ptr, ...) \
- { if (asprintf((ptr), __VA_ARGS__) < 0) do_nofail(NULL, __FILE__, __LINE__, #ptr); }
+#define nofail_asprintf(ptr, ...) \
+ do { if (asprintf((ptr), __VA_ARGS__) < 0) \
+ do_nofail(NULL, __FILE__, __LINE__, #ptr); \
+ } while(0)
static inline void *do_nofail(void *ptr, const char *file, int line, const char *expr)
{
diff --git a/modinfo.c b/modinfo.c
index 4f16c78..d8412db 100644
--- a/modinfo.c
+++ b/modinfo.c
@@ -14,6 +14,7 @@
#include <sys/mman.h>
#include "util.h"
+#include "logging.h"
#include "elfops.h"
#include "zlibsupport.h"
#include "testing.h"
@@ -38,7 +39,7 @@ static struct param *add_param(const char *name, struct param **list)
for (i = *list; i; i = i->next)
if (strncmp(i->name, name, namelen) == 0)
return i;
- i = malloc(sizeof(*i) + namelen+1);
+ i = NOFAIL(malloc(sizeof(*i) + namelen+1));
strncpy((char *)(i + 1), name, namelen);
((char *)(i + 1))[namelen] = '\0';
i->name = (char *)(i + 1);
@@ -178,85 +179,71 @@ static char *next_line(char *p, const char *end)
return (char *)end + 1;
}
-static void *grab_module(const char *name, unsigned long *size, char**filename,
- const char *kernel, const char *basedir)
+static struct elf_file *grab_module(const char *name,
+ const char *kernel,
+ const char *basedir)
{
char *data;
+ unsigned long size;
struct utsname buf;
char *depname, *p, *moddir;
+ struct elf_file *module;
if (strchr(name, '.') || strchr(name, '/')) {
- data = grab_file(name, size);
- if (data) {
- *filename = strdup(name);
- return data;
- } else {
- fprintf(stderr, "modinfo: could not open %s: %s\n",
+ module = grab_elf_file(name);
+ if (!module)
+ error("modinfo: could not open %s: %s\n",
name, strerror(errno));
- return NULL;
- }
+ return module;
}
- if (kernel) {
- if (strlen(basedir))
- asprintf(&moddir, "%s/%s/%s",
- basedir, MODULE_DIR, kernel);
- else
- asprintf(&moddir, "%s/%s",
- MODULE_DIR, kernel);
- } else {
+ if (!kernel) {
uname(&buf);
- if (strlen(basedir))
- asprintf(&moddir, "%s/%s/%s",
- basedir, MODULE_DIR, buf.release);
- else
- asprintf(&moddir, "%s/%s",
- MODULE_DIR, buf.release);
+ kernel = buf.release;
}
- asprintf(&depname, "%s/%s", moddir, "modules.dep");
+ if (strlen(basedir))
+ nofail_asprintf(&moddir, "%s/%s/%s", basedir, MODULE_DIR, kernel);
+ else
+ nofail_asprintf(&moddir, "%s/%s", MODULE_DIR, kernel);
/* Search for it in modules.dep. */
- data = grab_file(depname, size);
+ nofail_asprintf(&depname, "%s/%s", moddir, "modules.dep");
+ data = grab_file(depname, &size);
if (!data) {
- fprintf(stderr, "modinfo: could not open %s\n", depname);
+ error("modinfo: could not open %s\n", depname);
free(depname);
return NULL;
}
free(depname);
- for (p = data; p < data + *size; p = next_line(p, data + *size)) {
- if (name_matches(p, data + *size, name)) {
+ for (p = data; p < data + size; p = next_line(p, data + size)) {
+ if (name_matches(p, data + size, name)) {
int namelen = strcspn(p, ":");
+ const char *dir;
+ char *filename;
+
+ if ('/' == p[0])
+ dir = basedir; /* old style deps - abs. path */
+ else
+ dir = moddir; /* new style - relative path */
- if ('/' == p[0]) { /* old style deps - absolute path */
- *filename = malloc(namelen + strlen(basedir)+2);
- if (strlen(basedir)) {
- sprintf(*filename, "%s/", basedir);
- memcpy(*filename+strlen(basedir)+1,p,
- namelen);
- (*filename)[namelen
- +strlen(basedir)+1] = '\0';
- } else {
- memcpy(*filename,p,namelen);
- (*filename)[namelen] = '\0';
- }
+ if (strlen(dir)) {
+ nofail_asprintf(&filename, "%s/%s", dir, p);
+ filename[namelen + strlen(dir) + 1] = '\0';
} else {
- *filename = malloc(namelen + strlen(moddir)+2);
- sprintf(*filename, "%s/", moddir);
- memcpy(*filename+strlen(moddir)+1, p,namelen);
- (*filename)[namelen+strlen(moddir)+1] ='\0';
+ filename = strndup(p, namelen);
}
- release_file(data, *size);
- data = grab_file(*filename, size);
- if (!data)
- fprintf(stderr,
- "modinfo: could not open %s: %s\n",
+ release_file(data, size);
+ module = grab_elf_file(filename);
+ if (!module)
+ error("modinfo: could not open %s: %s\n",
*filename, strerror(errno));
- return data;
+ free(filename);
+ return module;
}
}
- release_file(data, *size);
- fprintf(stderr, "modinfo: could not find module %s\n", name);
+ release_file(data, size);
+ error("modinfo: could not find module %s\n", name);
return NULL;
}
@@ -276,10 +263,11 @@ int main(int argc, char *argv[])
const char *field = NULL;
const char *kernel = NULL;
char sep = '\n';
- unsigned long infosize = 0;
int opt, ret = 0;
char *basedir = "";
+ logging = 0; /* send messages to stderr */
+
if (native_endianness() == 0)
abort();
@@ -306,29 +294,25 @@ int main(int argc, char *argv[])
}
for (opt = optind; opt < argc; opt++) {
- void *info, *mod;
- unsigned long modulesize;
- char *filename;
+ void *info;
+ unsigned long infosize = 0;
+ struct elf_file *mod;
- mod = grab_module(argv[opt], &modulesize, &filename,
- kernel, basedir);
+ mod = grab_module(argv[opt], kernel, basedir);
if (!mod) {
ret = 1;
continue;
}
-
- info = get_section(mod, modulesize, ".modinfo", &infosize);
+ info = mod->ops->get_modinfo(mod, &infosize);
if (!info) {
- release_file(mod, modulesize);
- free(filename);
+ release_elf_file(mod);
continue;
}
if (field)
- print_tag(field, info, infosize, filename, sep);
+ print_tag(field, info, infosize, mod->pathname, sep);
else
- print_all(info, infosize, filename, sep);
- release_file(mod, modulesize);
- free(filename);
+ print_all(info, infosize, mod->pathname, sep);
+ release_elf_file(mod);
}
return ret;
}
diff --git a/modprobe.c b/modprobe.c
index c0680a7..c6ef155 100644
--- a/modprobe.c
+++ b/modprobe.c
@@ -283,7 +283,7 @@ static const char *remove_moderror(int err)
}
}
-static void replace_modname(struct module *module,
+static void replace_modname(struct elf_file *module,
void *mem, unsigned long len,
const char *oldname, const char *newname)
{
@@ -301,86 +301,40 @@ static void replace_modname(struct module *module,
}
}
- warn("Could not find old name in %s to replace!\n", module->filename);
+ warn("Could not find old name in %s to replace!\n", module->pathname);
}
-static void rename_module(struct module *module,
- void *mod,
- unsigned long len,
+static void rename_module(struct elf_file *module,
+ const char *oldname,
const char *newname)
{
void *modstruct;
- unsigned long modstruct_len;
+ unsigned long len;
/* Old-style */
- modstruct = get_section(mod, len, ".gnu.linkonce.this_module",
- &modstruct_len);
+ modstruct = module->ops->load_section(module,
+ ".gnu.linkonce.this_module", &len);
/* New-style */
if (!modstruct)
- modstruct = get_section(mod, len, "__module", &modstruct_len);
+ modstruct = module->ops->load_section(module, "__module", &len);
if (!modstruct)
warn("Could not find module name to change in %s\n",
- module->filename);
+ module->pathname);
else
- replace_modname(module, modstruct, modstruct_len,
- module->modname, newname);
-}
-
-/* Kernel told to ignore these sections if SHF_ALLOC not set. */
-static void invalidate_section32(void *mod, const char *secname)
-{
- Elf32_Ehdr *hdr = mod;
- Elf32_Shdr *sechdrs = mod + hdr->e_shoff;
- const char *secnames = mod + sechdrs[hdr->e_shstrndx].sh_offset;
- unsigned int i;
-
- for (i = 1; i < hdr->e_shnum; i++)
- if (streq(secnames+sechdrs[i].sh_name, secname))
- sechdrs[i].sh_flags &= ~SHF_ALLOC;
-}
-
-static void invalidate_section64(void *mod, const char *secname)
-{
- Elf64_Ehdr *hdr = mod;
- Elf64_Shdr *sechdrs = mod + hdr->e_shoff;
- const char *secnames = mod + sechdrs[hdr->e_shstrndx].sh_offset;
- unsigned int i;
-
- for (i = 1; i < hdr->e_shnum; i++)
- if (streq(secnames+sechdrs[i].sh_name, secname))
- sechdrs[i].sh_flags &= ~(unsigned long long)SHF_ALLOC;
+ replace_modname(module, modstruct, len, oldname, newname);
}
-static void strip_section(struct module *module,
- void *mod,
- unsigned long len,
- const char *secname)
-{
- switch (elf_ident(mod, len, NULL)) {
- case ELFCLASS32:
- invalidate_section32(mod, secname);
- break;
- case ELFCLASS64:
- invalidate_section64(mod, secname);
- break;
- default:
- warn("Unknown module format in %s: not forcing version\n",
- module->filename);
- }
-}
-
-static void clear_magic(struct module *module, void *mod, unsigned long len)
+static void clear_magic(struct elf_file *module)
{
const char *p;
- unsigned long modlen;
+ unsigned long len;
/* Old-style: __vermagic section */
- strip_section(module, mod, len, "__vermagic");
+ module->ops->strip_section(module, "__vermagic");
/* New-style: in .modinfo section */
- for (p = get_section(mod, len, ".modinfo", &modlen);
- p;
- p = next_string(p, &modlen)) {
+ p = module->ops->get_modinfo(module, &len);
+ for (; p; p = next_string(p, &len)) {
if (strstarts(p, "vermagic=")) {
memset((char *)p, 0, strlen(p));
return;
@@ -667,8 +621,7 @@ static int insmod(struct list_head *list,
const char *cmdline_opts)
{
int ret, fd;
- unsigned long len;
- void *map;
+ struct elf_file *module;
const char *command;
struct module *mod = list_entry(list->next, struct module, list);
int rc = 0;
@@ -712,21 +665,33 @@ static int insmod(struct list_head *list,
goto out_optstring;
}
- map = grab_fd(fd, &len);
- if (!map) {
+ module = grab_elf_file_fd(mod->filename, fd);
+ if (!module) {
+ /* This is an ugly hack that maintains the logic where
+ * init_module() sets errno = ENOEXEC if the file is
+ * not an ELF object.
+ */
+ if (errno == ENOEXEC) {
+ struct stat st;
+ optstring = add_extra_options(mod->modname,
+ optstring, options);
+ if (dry_run)
+ goto out;
+ fstat(fd, &st);
+ ret = init_module(NULL, st.st_size, optstring);
+ goto out_hack;
+ }
+
error("Could not read '%s': %s\n",
mod->filename, strerror(errno));
goto out_unlock;
}
-
- /* Rename it? */
if (newname)
- rename_module(mod, map, len, newname);
-
+ rename_module(module, mod->modname, newname);
if (strip_modversion)
- strip_section(mod, map, len, "__versions");
+ module->ops->strip_section(module, "__versions");
if (strip_vermagic)
- clear_magic(mod, map, len);
+ clear_magic(module);
/* Config file might have given more options */
optstring = add_extra_options(mod->modname, optstring, options);
@@ -736,7 +701,8 @@ static int insmod(struct list_head *list,
if (dry_run)
goto out;
- ret = init_module(map, len, optstring);
+ ret = init_module(module->data, module->len, optstring);
+out_hack:
if (ret != 0) {
if (errno == EEXIST) {
if (first_time)
@@ -753,7 +719,7 @@ static int insmod(struct list_head *list,
rc = 1;
}
out:
- release_file(map, len);
+ release_elf_file(module);
out_unlock:
close_file(fd);
out_optstring:
@@ -826,67 +792,19 @@ nonexistent_module:
goto remove_rest;
}
-struct modver32_info
-{
- uint32_t crc;
- char name[64 - sizeof(uint32_t)];
-};
-
-struct modver64_info
-{
- uint64_t crc;
- char name[64 - sizeof(uint64_t)];
-};
-
-const char *skip_dot(const char *str)
-{
- /* For our purposes, .foo matches foo. PPC64 needs this. */
- if (str && str[0] == '.')
- return str + 1;
- return str;
-}
-
void dump_modversions(const char *filename, errfn_t error)
{
- unsigned long size, secsize;
- void *file = grab_file(filename, &size);
- struct modver32_info *info32;
- struct modver64_info *info64;
- int n;
- int conv;
-
- if (!file) {
- error("%s: %s\n", filename, strerror(errno));
- return;
- }
- switch (elf_ident(file, size, &conv)) {
- case ELFCLASS32:
- info32 = get_section32(file, size, "__versions", &secsize, conv);
- if (!info32)
- return; /* Does not seem to be a kernel module */
- if (secsize % sizeof(struct modver32_info))
- error("Wrong section size in %s\n", filename);
- for (n = 0; n < secsize / sizeof(struct modver32_info); n++)
- printf("0x%08lx\t%s\n", (unsigned long)
- info32[n].crc, skip_dot(info32[n].name));
- break;
-
- case ELFCLASS64:
- info64 = get_section64(file, size, "__versions", &secsize, conv);
- if (!info64)
- return; /* Does not seem to be a kernel module */
- if (secsize % sizeof(struct modver64_info))
- error("Wrong section size in %s\n", filename);
- for (n = 0; n < secsize / sizeof(struct modver64_info); n++)
- printf("0x%08llx\t%s\n", (unsigned long long)
- info64[n].crc, skip_dot(info64[n].name));
- break;
-
- default:
- error("%s: ELF class not recognized\n", filename);
- }
-}
+ struct elf_file *module;
+ module = grab_elf_file(filename);
+ if (!module) {
+ error("%s: %s\n", filename, strerror(errno));
+ return;
+ }
+ if (module->ops->dump_modvers(module) < 0)
+ error("Wrong section size in '%s'\n", filename);
+ release_elf_file(module);
+}
/* Does path contain directory(s) subpath? */
static int type_matches(const char *path, const char *subpath)
diff --git a/tables.c b/tables.c
index ecbf030..2f44450 100644
--- a/tables.c
+++ b/tables.c
@@ -51,7 +51,7 @@ void output_pci_table(struct module *modules, FILE *out, char *dirname)
make_shortname(shortname, i->pathname);
for (e = t->pci_table; e->vendor; e = (void *)e + t->pci_size)
- output_pci_entry(e, shortname, out, i->file.conv);
+ output_pci_entry(e, shortname, out, i->file->conv);
}
}
@@ -102,7 +102,7 @@ void output_usb_table(struct module *modules, FILE *out, char *dirname)
for (e = t->usb_table;
e->idVendor || e->bDeviceClass || e->bInterfaceClass;
e = (void *)e + t->usb_size)
- output_usb_entry(e, shortname, out, i->file.conv);
+ output_usb_entry(e, shortname, out, i->file->conv);
}
}
@@ -136,7 +136,7 @@ void output_ieee1394_table(struct module *modules, FILE *out, char *dirname)
make_shortname(shortname, i->pathname);
for (fw = t->ieee1394_table; fw->match_flags;
fw = (void *) fw + t->ieee1394_size)
- output_ieee1394_entry(fw, shortname, out, i->file.conv);
+ output_ieee1394_entry(fw, shortname, out, i->file->conv);
}
}
@@ -170,7 +170,7 @@ void output_ccw_table(struct module *modules, FILE *out, char *dirname)
for (e = t->ccw_table;
e->cu_type || e->cu_model || e->dev_type || e->dev_model;
e = (void *) e + t->ccw_size)
- output_ccw_entry(e, shortname, out, i->file.conv);
+ output_ccw_entry(e, shortname, out, i->file->conv);
}
}
@@ -425,6 +425,7 @@ void output_input_table(struct module *modules, FILE *out, char *dirname)
char shortname[strlen(i->pathname) + 1];
int done = 0;
struct module_tables *t = &i->tables;
+ int conv = i->file->conv;
if (!t->input_table)
continue;
@@ -449,22 +450,20 @@ void output_input_table(struct module *modules, FILE *out, char *dirname)
case sizeof(struct input_device_id_old_64):
done = output_input_entry_64_old(p,
shortname,
- out,
- i->file.conv);
+ out, conv);
break;
case sizeof(struct input_device_id_64):
done = output_input_entry_64(p, shortname,
- out, i->file.conv);
+ out, conv);
break;
case sizeof(struct input_device_id_old_32):
done = output_input_entry_32_old(p,
shortname,
- out,
- i->file.conv);
+ out, conv);
break;
case sizeof(struct input_device_id_32):
done = output_input_entry_32(p, shortname,
- out, i->file.conv);
+ out, conv);
break;
}
}