1 #include <sys/types.h>
2 #include <sys/mman.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdbool.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <errno.h>
11
12 #include "elf-parse.h"
13
14 struct elf_funcs elf_parser;
15
16 /*
17 * Get the whole file as a programming convenience in order to avoid
18 * malloc+lseek+read+free of many pieces. If successful, then mmap
19 * avoids copying unused pieces; else just read the whole file.
20 * Open for both read and write.
21 */
map_file(char const * fname,size_t * size)22 static void *map_file(char const *fname, size_t *size)
23 {
24 int fd;
25 struct stat sb;
26 void *addr = NULL;
27
28 fd = open(fname, O_RDWR);
29 if (fd < 0) {
30 perror(fname);
31 return NULL;
32 }
33 if (fstat(fd, &sb) < 0) {
34 perror(fname);
35 goto out;
36 }
37 if (!S_ISREG(sb.st_mode)) {
38 fprintf(stderr, "not a regular file: %s\n", fname);
39 goto out;
40 }
41
42 addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
43 if (addr == MAP_FAILED) {
44 fprintf(stderr, "Could not mmap file: %s\n", fname);
45 goto out;
46 }
47
48 *size = sb.st_size;
49
50 out:
51 close(fd);
52 return addr;
53 }
54
elf_parse(const char * fname,void * addr,uint32_t types)55 static int elf_parse(const char *fname, void *addr, uint32_t types)
56 {
57 Elf_Ehdr *ehdr = addr;
58 uint16_t type;
59
60 switch (ehdr->e32.e_ident[EI_DATA]) {
61 case ELFDATA2LSB:
62 elf_parser.r = rle;
63 elf_parser.r2 = r2le;
64 elf_parser.r8 = r8le;
65 elf_parser.w = wle;
66 elf_parser.w8 = w8le;
67 break;
68 case ELFDATA2MSB:
69 elf_parser.r = rbe;
70 elf_parser.r2 = r2be;
71 elf_parser.r8 = r8be;
72 elf_parser.w = wbe;
73 elf_parser.w8 = w8be;
74 break;
75 default:
76 fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
77 ehdr->e32.e_ident[EI_DATA], fname);
78 return -1;
79 }
80
81 if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
82 ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
83 fprintf(stderr, "unrecognized ELF file %s\n", fname);
84 return -1;
85 }
86
87 type = elf_parser.r2(&ehdr->e32.e_type);
88 if (!((1 << type) & types)) {
89 fprintf(stderr, "Invalid ELF type file %s\n", fname);
90 return -1;
91 }
92
93 switch (ehdr->e32.e_ident[EI_CLASS]) {
94 case ELFCLASS32: {
95 elf_parser.ehdr_shoff = ehdr32_shoff;
96 elf_parser.ehdr_shentsize = ehdr32_shentsize;
97 elf_parser.ehdr_shstrndx = ehdr32_shstrndx;
98 elf_parser.ehdr_shnum = ehdr32_shnum;
99 elf_parser.shdr_addr = shdr32_addr;
100 elf_parser.shdr_offset = shdr32_offset;
101 elf_parser.shdr_link = shdr32_link;
102 elf_parser.shdr_size = shdr32_size;
103 elf_parser.shdr_name = shdr32_name;
104 elf_parser.shdr_type = shdr32_type;
105 elf_parser.shdr_entsize = shdr32_entsize;
106 elf_parser.sym_type = sym32_type;
107 elf_parser.sym_name = sym32_name;
108 elf_parser.sym_value = sym32_value;
109 elf_parser.sym_shndx = sym32_shndx;
110 elf_parser.rela_offset = rela32_offset;
111 elf_parser.rela_info = rela32_info;
112 elf_parser.rela_addend = rela32_addend;
113 elf_parser.rela_write_addend = rela32_write_addend;
114
115 if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
116 elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
117 fprintf(stderr,
118 "unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
119 return -1;
120 }
121
122 }
123 break;
124 case ELFCLASS64: {
125 elf_parser.ehdr_shoff = ehdr64_shoff;
126 elf_parser.ehdr_shentsize = ehdr64_shentsize;
127 elf_parser.ehdr_shstrndx = ehdr64_shstrndx;
128 elf_parser.ehdr_shnum = ehdr64_shnum;
129 elf_parser.shdr_addr = shdr64_addr;
130 elf_parser.shdr_offset = shdr64_offset;
131 elf_parser.shdr_link = shdr64_link;
132 elf_parser.shdr_size = shdr64_size;
133 elf_parser.shdr_name = shdr64_name;
134 elf_parser.shdr_type = shdr64_type;
135 elf_parser.shdr_entsize = shdr64_entsize;
136 elf_parser.sym_type = sym64_type;
137 elf_parser.sym_name = sym64_name;
138 elf_parser.sym_value = sym64_value;
139 elf_parser.sym_shndx = sym64_shndx;
140 elf_parser.rela_offset = rela64_offset;
141 elf_parser.rela_info = rela64_info;
142 elf_parser.rela_addend = rela64_addend;
143 elf_parser.rela_write_addend = rela64_write_addend;
144
145 if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
146 elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
147 fprintf(stderr,
148 "unrecognized ET_EXEC/ET_DYN file: %s\n",
149 fname);
150 return -1;
151 }
152
153 }
154 break;
155 default:
156 fprintf(stderr, "unrecognized ELF class %d %s\n",
157 ehdr->e32.e_ident[EI_CLASS], fname);
158 return -1;
159 }
160 return 0;
161 }
162
elf_map_machine(void * addr)163 int elf_map_machine(void *addr)
164 {
165 Elf_Ehdr *ehdr = addr;
166
167 return elf_parser.r2(&ehdr->e32.e_machine);
168 }
169
elf_map_long_size(void * addr)170 int elf_map_long_size(void *addr)
171 {
172 Elf_Ehdr *ehdr = addr;
173
174 return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
175 }
176
elf_map(char const * fname,size_t * size,uint32_t types)177 void *elf_map(char const *fname, size_t *size, uint32_t types)
178 {
179 void *addr;
180 int ret;
181
182 addr = map_file(fname, size);
183 if (!addr)
184 return NULL;
185
186 ret = elf_parse(fname, addr, types);
187 if (ret < 0) {
188 elf_unmap(addr, *size);
189 return NULL;
190 }
191
192 return addr;
193 }
194
elf_unmap(void * addr,size_t size)195 void elf_unmap(void *addr, size_t size)
196 {
197 munmap(addr, size);
198 }
199