aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Robinson <andr345@gmail.com>2009-05-14 10:34:24 +0200
committerAndreas Robinson <andr345@gmail.com>2009-05-15 14:53:30 +0200
commit1f7b3782ba4292c821fbb2a7ce9ed19f568b8b04 (patch)
tree0a49cb55b09d8485f83246f68feb30386637b28e
parent49724cc9c9ea30d802a45d88adbcefabf6059f08 (diff)
downloadmodule-init-tools-1f7b3782ba4292c821fbb2a7ce9ed19f568b8b04.tar.gz
elfops, depmod: add elf_file grab/release functions
This introduces constructor and destructor for struct elf_file, following the grab/release naming pattern used elsewhere. Care is taken to ensure the constructor returns a valid errno on failure. The first user is grab_module() in depmod.c Signed-off-by: Andreas Robinson <andr345@gmail.com>
-rw-r--r--depmod.c42
-rw-r--r--depmod.h2
-rw-r--r--elfops.c87
-rw-r--r--elfops.h6
-rw-r--r--tables.c19
5 files changed, 111 insertions, 45 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..ac33c96 100644
--- a/elfops.c
+++ b/elfops.c
@@ -5,11 +5,15 @@
#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";
@@ -55,3 +59,86 @@ void *get_section(void *file, unsigned long filesize,
return NULL;
}
}
+
+/*
+ * 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)
+{
+ struct elf_file *file;
+
+ 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:
+ file->ops = &mod_ops32;
+ break;
+ case ELFCLASS64:
+ 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 24ebc07..dffd9f5 100644
--- a/elfops.h
+++ b/elfops.h
@@ -16,6 +16,8 @@ struct kernel_symbol64 {
struct elf_file
{
+ char *pathname;
+
/* File operations */
struct module_ops *ops;
@@ -75,4 +77,8 @@ 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(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/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;
}
}