aboutsummaryrefslogtreecommitdiffstats
path: root/elfops.c
blob: 10e80ea487d430f65b9aa81318277b34011d59fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* 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;
}