blob: 10e80ea487d430f65b9aa81318277b34011d59fe [file] [log] [blame]
/* The nasty work of reading 32 and 64-bit modules is in here. */
#include <elf.h>
#include <sys/types.h>
#include <unistd.h>
#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
#define ELF64BIT
#include "elfops_core.c"
#undef ELF64BIT
/*
* Check ELF file header.
*/
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;
if (fsize < EI_CLASS || memcmp(file, ELFMAG, SELFMAG) != 0)
return -ENOEXEC; /* Not an ELF object */
if (ident[EI_DATA] == 0 || ident[EI_DATA] > 2)
return -EINVAL; /* Unknown endianness */
if (conv != NULL)
*conv = native_endianness() != ident[EI_DATA];
return ident[EI_CLASS];
}
/*
* 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)
{
struct elf_file *file;
file = malloc(sizeof(*file));
if (!file) {
errno = ENOMEM;
goto fail;
}
file->pathname = strdup(pathname);
if (!file->pathname) {
errno = ENOMEM;
goto fail_free_file;
}
file->data = grab_file(pathname, &file->len);
if (!file->data)
goto fail_free_pathname;
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_free_pathname:
free(file->pathname);
fail_free_file:
free(file);
fail:
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;
}