1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #define _GNU_SOURCE
13
14 #include <malloc.h>
15 #include <errno.h>
16 #include <endian.h>
17 #include <stdbool.h>
18 #include "elf.h"
19
20 #define PAGE_SIZE 0x1000
21
is_elf_magic(struct elf_indent * indent)22 static bool is_elf_magic(struct elf_indent *indent)
23 {
24 return (indent->ei_magic[0] == 0x7F && indent->ei_magic[1] == 'E'
25 && indent->ei_magic[2] == 'L' && indent->ei_magic[3] == 'F');
26 }
27
28 #define ELF_ENDIAN_LE(indent) ((indent).ei_data == 1)
29 #define ELF_ENDIAN_BE(indent) ((indent).ei_data == 2)
30
31 #define ELF_BITS_32(indent) ((indent).ei_class == 1)
32 #define ELF_BITS_64(indent) ((indent).ei_class == 2)
33
34 /**
35 * Parse an ELF file header. We use the 64-bit structure `struct elf_header` as
36 * the output structure.
37 *
38 * On error, the negative error code is returned.
39 * On success, 0 is returned, and the header is written in the given parameter.
40 */
parse_elf_header(const char * code,struct elf_header * header)41 static int parse_elf_header(const char *code, struct elf_header *header)
42 {
43 struct elf_header *header_64 = (struct elf_header *)code;
44 struct elf_header_32 *header_32 = (struct elf_header_32 *)code;
45
46 if (!is_elf_magic(&header_64->e_indent)) {
47 return -EINVAL;
48 }
49
50 header->e_indent = *(struct elf_indent *)code;
51
52 if (ELF_ENDIAN_LE(header->e_indent)) {
53 /*
54 * For the first few bytes, both 32-bit and 64-bit ELF headers
55 * have the same field width. So, we simply use header_64 at
56 * first.
57 */
58 header->e_type = le16toh(header_64->e_type);
59 header->e_machine = le16toh(header_64->e_machine);
60 header->e_version = le32toh(header_32->e_version);
61 if (ELF_BITS_32(header->e_indent)) {
62 header->e_entry = le32toh(header_32->e_entry);
63 header->e_phoff = le32toh(header_32->e_phoff);
64 header->e_shoff = le32toh(header_32->e_shoff);
65 header->e_flags = le32toh(header_32->e_flags);
66 header->e_ehsize = le16toh(header_32->e_ehsize);
67 header->e_phentsize = le16toh(header_32->e_phentsize);
68 header->e_phnum = le16toh(header_32->e_phnum);
69 header->e_shentsize = le16toh(header_32->e_shentsize);
70 header->e_shnum = le16toh(header_32->e_shnum);
71 header->e_shstrndx = le16toh(header_32->e_shstrndx);
72 } else if (ELF_BITS_64(header->e_indent)) {
73 header->e_entry = le64toh(header_64->e_entry);
74 header->e_phoff = le64toh(header_64->e_phoff);
75 header->e_shoff = le64toh(header_64->e_shoff);
76 header->e_flags = le32toh(header_64->e_flags);
77 header->e_ehsize = le16toh(header_64->e_ehsize);
78 header->e_phentsize = le16toh(header_64->e_phentsize);
79 header->e_phnum = le16toh(header_64->e_phnum);
80 header->e_shentsize = le16toh(header_64->e_shentsize);
81 header->e_shnum = le16toh(header_64->e_shnum);
82 header->e_shstrndx = le16toh(header_64->e_shstrndx);
83 } else {
84 return -EINVAL;
85 }
86 } else if (ELF_ENDIAN_BE(header->e_indent)) {
87 /*
88 * We use header_64 for the same reason as above.
89 */
90 header->e_type = be16toh(header_64->e_type);
91 header->e_machine = be16toh(header_64->e_machine);
92 header->e_version = be32toh(header_32->e_version);
93 if (ELF_BITS_32(header->e_indent)) {
94 header->e_entry = be32toh(header_32->e_entry);
95 header->e_phoff = be32toh(header_32->e_phoff);
96 header->e_shoff = be32toh(header_32->e_shoff);
97 header->e_flags = be32toh(header_32->e_flags);
98 header->e_ehsize = be16toh(header_32->e_ehsize);
99 header->e_phentsize = be16toh(header_32->e_phentsize);
100 header->e_phnum = be16toh(header_32->e_phnum);
101 header->e_shentsize = be16toh(header_32->e_shentsize);
102 header->e_shnum = be16toh(header_32->e_shnum);
103 header->e_shstrndx = be16toh(header_32->e_shstrndx);
104 } else if (ELF_BITS_64(header->e_indent)) {
105 header->e_entry = be64toh(header_64->e_entry);
106 header->e_phoff = be64toh(header_64->e_phoff);
107 header->e_shoff = be64toh(header_64->e_shoff);
108 header->e_flags = be32toh(header_64->e_flags);
109 header->e_ehsize = be16toh(header_64->e_ehsize);
110 header->e_phentsize = be16toh(header_64->e_phentsize);
111 header->e_phnum = be16toh(header_64->e_phnum);
112 header->e_shentsize = be16toh(header_64->e_shentsize);
113 header->e_shnum = be16toh(header_64->e_shnum);
114 header->e_shstrndx = be16toh(header_64->e_shstrndx);
115 } else {
116 return -EINVAL;
117 }
118 } else {
119 return -EINVAL;
120 }
121 return 0;
122 }
123
124 /**
125 * Parse an ELF program header. We use the 64-bit structure
126 * `struct elf_program_header` as the output structure.
127 *
128 * On error, the negative error code is returned.
129 * On success, 0 is returned, and the header is written in the given parameter.
130 */
parse_elf_program_header(const char * code,const struct elf_header * elf,struct elf_program_header * header)131 static int parse_elf_program_header(const char *code,
132 const struct elf_header *elf,
133 struct elf_program_header *header)
134 {
135 struct elf_program_header *header_64;
136 struct elf_program_header_32 *header_32;
137
138 if (ELF_ENDIAN_LE(elf->e_indent)) {
139 if (ELF_BITS_32(elf->e_indent)) {
140 header_32 = (struct elf_program_header_32 *)code;
141 header->p_type = le32toh(header_32->p_type);
142 header->p_flags = le32toh(header_32->p_flags);
143 header->p_offset = le32toh(header_32->p_offset);
144 header->p_vaddr = le32toh(header_32->p_vaddr);
145 header->p_paddr = le32toh(header_32->p_paddr);
146 header->p_filesz = le32toh(header_32->p_filesz);
147 header->p_memsz = le32toh(header_32->p_memsz);
148 header->p_align = le32toh(header_32->p_align);
149 } else if (ELF_BITS_64(elf->e_indent)) {
150 header_64 = (struct elf_program_header *)code;
151 header->p_type = le32toh(header_64->p_type);
152 header->p_flags = le32toh(header_64->p_flags);
153 header->p_offset = le64toh(header_64->p_offset);
154 header->p_vaddr = le64toh(header_64->p_vaddr);
155 header->p_paddr = le64toh(header_64->p_paddr);
156 header->p_filesz = le64toh(header_64->p_filesz);
157 header->p_memsz = le64toh(header_64->p_memsz);
158 header->p_align = le64toh(header_64->p_align);
159 } else {
160 return -EINVAL;
161 }
162 } else if (ELF_ENDIAN_BE(elf->e_indent)) {
163 if (ELF_BITS_32(elf->e_indent)) {
164 header_32 = (struct elf_program_header_32 *)code;
165 header->p_type = be32toh(header_32->p_type);
166 header->p_flags = be32toh(header_32->p_flags);
167 header->p_offset = be32toh(header_32->p_offset);
168 header->p_vaddr = be32toh(header_32->p_vaddr);
169 header->p_paddr = be32toh(header_32->p_paddr);
170 header->p_filesz = be32toh(header_32->p_filesz);
171 header->p_memsz = be32toh(header_32->p_memsz);
172 header->p_align = be32toh(header_32->p_align);
173 } else if (ELF_BITS_64(elf->e_indent)) {
174 header_64 = (struct elf_program_header *)code;
175 header->p_type = be32toh(header_64->p_type);
176 header->p_flags = be32toh(header_64->p_flags);
177 header->p_offset = be64toh(header_64->p_offset);
178 header->p_vaddr = be64toh(header_64->p_vaddr);
179 header->p_paddr = be64toh(header_64->p_paddr);
180 header->p_filesz = be64toh(header_64->p_filesz);
181 header->p_memsz = be64toh(header_64->p_memsz);
182 header->p_align = be64toh(header_64->p_align);
183 } else {
184 return -EINVAL;
185 }
186 } else {
187 return -EINVAL;
188 }
189 return 0;
190 }
191
192 /**
193 * Parse an ELF section header. We use the 64-bit structure
194 * `struct elf_section_header` as the output structure.
195 *
196 * On error, the negative error code is returned.
197 * On success, 0 is returned, and the header is written in the given parameter.
198 */
parse_elf_section_header(const char * code,const struct elf_header * elf,struct elf_section_header * header)199 static int parse_elf_section_header(const char *code,
200 const struct elf_header *elf,
201 struct elf_section_header *header)
202 {
203 struct elf_section_header *header_64;
204 struct elf_section_header_32 *header_32;
205
206 if (ELF_ENDIAN_LE(elf->e_indent)) {
207 if (ELF_BITS_32(elf->e_indent)) {
208 header_32 = (struct elf_section_header_32 *)code;
209 header->sh_name = le32toh(header_32->sh_name);
210 header->sh_type = le32toh(header_32->sh_type);
211 header->sh_flags = le32toh(header_32->sh_flags);
212 header->sh_addr = le32toh(header_32->sh_addr);
213 header->sh_offset = le32toh(header_32->sh_offset);
214 header->sh_size = le32toh(header_32->sh_size);
215 header->sh_link = le32toh(header_32->sh_link);
216 header->sh_info = le32toh(header_32->sh_info);
217 header->sh_addralign = le32toh(header_32->sh_addralign);
218 header->sh_entsize = le32toh(header_32->sh_entsize);
219 } else if (ELF_BITS_64(elf->e_indent)) {
220 header_64 = (struct elf_section_header *)code;
221 header->sh_name = le32toh(header_64->sh_name);
222 header->sh_type = le32toh(header_64->sh_type);
223 header->sh_flags = le64toh(header_64->sh_flags);
224 header->sh_addr = le64toh(header_64->sh_addr);
225 header->sh_offset = le64toh(header_64->sh_offset);
226 header->sh_size = le64toh(header_64->sh_size);
227 header->sh_link = le32toh(header_64->sh_link);
228 header->sh_info = le32toh(header_64->sh_info);
229 header->sh_addralign = le64toh(header_64->sh_addralign);
230 header->sh_entsize = le64toh(header_64->sh_entsize);
231 } else {
232 return -EINVAL;
233 }
234 } else if (ELF_ENDIAN_BE(elf->e_indent)) {
235 if (ELF_BITS_32(elf->e_indent)) {
236 header_32 = (struct elf_section_header_32 *)code;
237 header->sh_name = be32toh(header_32->sh_name);
238 header->sh_type = be32toh(header_32->sh_type);
239 header->sh_flags = be32toh(header_32->sh_flags);
240 header->sh_addr = be32toh(header_32->sh_addr);
241 header->sh_offset = be32toh(header_32->sh_offset);
242 header->sh_size = be32toh(header_32->sh_size);
243 header->sh_link = be32toh(header_32->sh_link);
244 header->sh_info = be32toh(header_32->sh_info);
245 header->sh_addralign = be32toh(header_32->sh_addralign);
246 header->sh_entsize = be32toh(header_32->sh_entsize);
247 } else if (ELF_BITS_64(elf->e_indent)) {
248 header_64 = (struct elf_section_header *)code;
249 header->sh_name = be32toh(header_64->sh_name);
250 header->sh_type = be32toh(header_64->sh_type);
251 header->sh_flags = be64toh(header_64->sh_flags);
252 header->sh_addr = be64toh(header_64->sh_addr);
253 header->sh_offset = be64toh(header_64->sh_offset);
254 header->sh_size = be64toh(header_64->sh_size);
255 header->sh_link = be32toh(header_64->sh_link);
256 header->sh_info = be32toh(header_64->sh_info);
257 header->sh_addralign = be64toh(header_64->sh_addralign);
258 header->sh_entsize = be64toh(header_64->sh_entsize);
259 } else {
260 return -EINVAL;
261 }
262 } else {
263 return -EINVAL;
264 }
265 return 0;
266 }
267
elf_free(struct elf_file * elf)268 void elf_free(struct elf_file *elf)
269 {
270 if (elf->s_headers)
271 free(elf->s_headers);
272 if (elf->p_headers)
273 free(elf->p_headers);
274 free(elf);
275 }
276
elf_parse_file(const char * code,struct elf_info * info)277 struct elf_file *elf_parse_file(const char *code, struct elf_info*info)
278 {
279 struct elf_file *elf;
280 int err;
281 int i;
282
283 elf = malloc(sizeof(*elf));
284 if (!elf)
285 return NULL;
286
287 err = parse_elf_header(code, &elf->header);
288 if (err)
289 goto out_free_elf;
290
291 /* Allocate memory for program headers and section headers */
292 err = -ENOMEM;
293 elf->p_headers = malloc(sizeof(struct elf_program_header) * elf->header.e_phnum);
294
295 if (!elf->p_headers)
296 goto out_free_elf;
297 elf->s_headers = malloc(sizeof(struct elf_section_header) * elf->header.e_shnum);
298 if (!elf->s_headers)
299 goto out_free_elf_p;
300
301 /* Parse program headers and section headers */
302 for (i = 0; i < elf->header.e_phnum; ++i) {
303 err = parse_elf_program_header(code + elf->header.e_phoff
304 + elf->header.e_phentsize * i,
305 &elf->header,
306 &elf->p_headers[i]);
307 info->phdr[i] = elf->p_headers[i];
308 if (err)
309 goto out_free_all;
310 }
311 for (i = 0; i < elf->header.e_shnum; ++i) {
312 err = parse_elf_section_header(code + elf->header.e_shoff
313 + elf->header.e_shentsize * i,
314 &elf->header,
315 &elf->s_headers[i]);
316 if (err)
317 goto out_free_all;
318 }
319 return elf;
320
321 out_free_all:
322 free(elf->s_headers);
323 out_free_elf_p:
324 free(elf->p_headers);
325 out_free_elf:
326 free(elf);
327 return NULL;
328 }
329