1 /*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lib/elf.h>
9 #include <assert.h>
10 #include <lk/debug.h>
11 #include <endian.h>
12 #include <lk/err.h>
13 #include <lk/trace.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <arch/ops.h>
17
18 #define LOCAL_TRACE 0
19
20 /* conditionally define a 32 or 64 bit version of the data structures
21 * we care about, based on our bitness.
22 */
23 #if WITH_ELF32
24 typedef struct Elf32_Ehdr elf_ehdr_t;
25 typedef struct Elf32_Phdr elf_phdr_t;
26
27 #define ELF_OFF_PRINT_U "%u"
28 #define ELF_OFF_PRINT_X "%x"
29 #define ELF_ADDR_PRINT_U "%u"
30 #define ELF_ADDR_PRINT_X "%x"
31 #else
32 typedef struct Elf64_Ehdr elf_ehdr_t;
33 typedef struct Elf64_Phdr elf_phdr_t;
34
35 #define ELF_OFF_PRINT_U "%llu"
36 #define ELF_OFF_PRINT_X "%llx"
37 #define ELF_ADDR_PRINT_U "%llu"
38 #define ELF_ADDR_PRINT_X "%llx"
39 #endif
40
41 struct read_hook_memory_args {
42 const uint8_t *ptr;
43 size_t len;
44 };
45
elf_read_hook_memory(struct elf_handle * handle,void * buf,uint64_t offset,size_t len)46 static ssize_t elf_read_hook_memory(struct elf_handle *handle, void *buf, uint64_t offset, size_t len) {
47 LTRACEF("handle %p, buf %p, offset %lld, len %zu\n", handle, buf, offset, len);
48
49 struct read_hook_memory_args *args = handle->read_hook_arg;
50
51 DEBUG_ASSERT(args);
52 DEBUG_ASSERT(buf);
53 DEBUG_ASSERT(handle);
54 DEBUG_ASSERT(handle->open);
55
56 ssize_t toread = len;
57 if (offset >= args->len)
58 toread = 0;
59 if (offset + len >= args->len)
60 toread = args->len - offset;
61
62 memcpy(buf, args->ptr + offset, toread);
63
64 LTRACEF("returning %ld\n", toread);
65
66 return toread;
67 }
68
elf_open_handle(elf_handle_t * handle,elf_read_hook_t read_hook,void * read_hook_arg,bool free_read_hook_arg)69 status_t elf_open_handle(elf_handle_t *handle, elf_read_hook_t read_hook, void *read_hook_arg, bool free_read_hook_arg) {
70 if (!handle)
71 return ERR_INVALID_ARGS;
72 if (!read_hook)
73 return ERR_INVALID_ARGS;
74
75 memset(handle, 0, sizeof(*handle));
76
77 handle->read_hook = read_hook;
78 handle->read_hook_arg = read_hook_arg;
79 handle->free_read_hook_arg = free_read_hook_arg;
80
81 handle->open = true;
82
83 return NO_ERROR;
84 }
85
elf_open_handle_memory(elf_handle_t * handle,const void * ptr,size_t len)86 status_t elf_open_handle_memory(elf_handle_t *handle, const void *ptr, size_t len) {
87 struct read_hook_memory_args *args = malloc(sizeof(struct read_hook_memory_args));
88
89 args->ptr = ptr;
90 args->len = len;
91
92 status_t err = elf_open_handle(handle, elf_read_hook_memory, (void *)args, true);
93 if (err < 0)
94 free(args);
95
96 return err;
97 }
98
elf_close_handle(elf_handle_t * handle)99 void elf_close_handle(elf_handle_t *handle) {
100 if (!handle || !handle->open)
101 return;
102
103 handle->open = false;
104
105 if (handle->free_read_hook_arg)
106 free(handle->read_hook_arg);
107
108 free(handle->pheaders);
109 }
110
verify_eheader(const void * header)111 static int verify_eheader(const void *header) {
112 const elf_ehdr_t *eheader = header;
113
114 if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
115 return ERR_NOT_FOUND;
116
117 #if WITH_ELF32
118 if (eheader->e_ident[EI_CLASS] != ELFCLASS32)
119 return ERR_NOT_FOUND;
120 #else
121 if (eheader->e_ident[EI_CLASS] != ELFCLASS64)
122 return ERR_NOT_FOUND;
123 #endif
124
125 #if BYTE_ORDER == LITTLE_ENDIAN
126 if (eheader->e_ident[EI_DATA] != ELFDATA2LSB)
127 return ERR_NOT_FOUND;
128 #elif BYTE_ORDER == BIG_ENDIAN
129 if (eheader->e_ident[EI_DATA] != ELFDATA2MSB)
130 return ERR_NOT_FOUND;
131 #endif
132
133 if (eheader->e_ident[EI_VERSION] != EV_CURRENT)
134 return ERR_NOT_FOUND;
135
136 if (eheader->e_phoff == 0)
137 return ERR_NOT_FOUND;
138
139 if (eheader->e_phentsize < sizeof(elf_phdr_t))
140 return ERR_NOT_FOUND;
141
142 #if ARCH_ARM
143 if (eheader->e_machine != EM_ARM)
144 return ERR_NOT_FOUND;
145 #elif ARCH_ARM64
146 if (eheader->e_machine != EM_AARCH64)
147 return ERR_NOT_FOUND;
148 #elif ARCH_X86
149 if (eheader->e_machine != EM_386)
150 return ERR_NOT_FOUND;
151 #elif ARCH_X86_64
152 if (eheader->e_machine != EM_X86_64)
153 return ERR_NOT_FOUND;
154 #elif ARCH_MICROBLAZE
155 if (eheader->e_machine != EM_MICROBLAZE)
156 return ERR_NOT_FOUND;
157 #elif ARCH_RISCV
158 if (eheader->e_machine != EM_RISCV)
159 return ERR_NOT_FOUND;
160 #elif ARCH_VPU
161 if (eheader->e_machine != EM_VC4)
162 return ERR_NOT_FOUND;
163 #else
164 #error find proper EM_ define for your machine
165 #endif
166
167 return NO_ERROR;
168 }
169
elf_load(elf_handle_t * handle)170 status_t elf_load(elf_handle_t *handle) {
171 if (!handle)
172 return ERR_INVALID_ARGS;
173 if (!handle->open)
174 return ERR_NOT_READY;
175
176 // validate that this is an ELF file
177 ssize_t readerr = handle->read_hook(handle, &handle->eheader, 0, sizeof(handle->eheader));
178 if (readerr < (ssize_t)sizeof(handle->eheader)) {
179 LTRACEF("couldn't read elf header\n");
180 return ERR_NOT_FOUND;
181 }
182
183 if (verify_eheader(&handle->eheader)) {
184 LTRACEF("header not valid\n");
185 return ERR_NOT_FOUND;
186 }
187
188 // sanity check number of program headers
189 LTRACEF("number of program headers %u, entry size %u\n", handle->eheader.e_phnum, handle->eheader.e_phentsize);
190 if (handle->eheader.e_phnum > 16 ||
191 handle->eheader.e_phentsize != sizeof(elf_phdr_t)) {
192 LTRACEF("too many program headers or bad size\n");
193 return ERR_NO_MEMORY;
194 }
195
196 // allocate and read in the program headers
197 handle->pheaders = calloc(1, handle->eheader.e_phnum * handle->eheader.e_phentsize);
198 if (!handle->pheaders) {
199 LTRACEF("failed to allocate memory for program headers\n");
200 return ERR_NO_MEMORY;
201 }
202
203 readerr = handle->read_hook(handle, handle->pheaders, handle->eheader.e_phoff, handle->eheader.e_phnum * handle->eheader.e_phentsize);
204 if (readerr < (ssize_t)(handle->eheader.e_phnum * handle->eheader.e_phentsize)) {
205 LTRACEF("failed to read program headers\n");
206 return ERR_NO_MEMORY;
207 }
208
209 LTRACEF("program headers:\n");
210 uint load_count = 0;
211 for (uint i = 0; i < handle->eheader.e_phnum; i++) {
212 // parse the program headers
213 elf_phdr_t *pheader = &handle->pheaders[i];
214
215 LTRACEF("%u: type %u offset 0x" ELF_OFF_PRINT_X " vaddr "
216 ELF_ADDR_PRINT_X " paddr " ELF_ADDR_PRINT_X " memsiz "
217 ELF_ADDR_PRINT_U " filesize " ELF_ADDR_PRINT_U "\n",
218 i, pheader->p_type, pheader->p_offset, pheader->p_vaddr,
219 pheader->p_paddr, pheader->p_memsz, pheader->p_filesz);
220
221 // we only care about PT_LOAD segments at the moment
222 if (pheader->p_type == PT_LOAD) {
223 // if the memory allocation hook exists, call it
224 void *ptr = (void *)(uintptr_t)pheader->p_vaddr;
225
226 if (handle->mem_alloc_hook) {
227 status_t err = handle->mem_alloc_hook(handle, &ptr, pheader->p_memsz, load_count, 0);
228 if (err < 0) {
229 LTRACEF("mem hook failed, abort\n");
230 // XXX clean up what we got so far
231 return err;
232 }
233 }
234
235 // read the file portion of the segment into memory at vaddr
236 LTRACEF("reading segment at offset " ELF_OFF_PRINT_U " to address %p\n", pheader->p_offset, ptr);
237 readerr = handle->read_hook(handle, ptr, pheader->p_offset, pheader->p_filesz);
238 if (readerr < (ssize_t)pheader->p_filesz) {
239 LTRACEF("error %ld reading program header %u\n", readerr, i);
240 return (readerr < 0) ? readerr : ERR_IO;
241 }
242
243 // zero out he difference between memsz and filesz
244 size_t tozero = pheader->p_memsz - pheader->p_filesz;
245 if (tozero > 0) {
246 uint8_t *ptr2 = (uint8_t *)ptr + pheader->p_filesz;
247 LTRACEF("zeroing memory at %p, size %zu\n", ptr2, tozero);
248 memset(ptr2, 0, tozero);
249 }
250
251 // make sure the i&d cache are coherent, if they exist
252 arch_sync_cache_range((addr_t)ptr, pheader->p_memsz);
253
254 // track the number of load segments we have seen to pass the mem alloc hook
255 load_count++;
256 }
257 }
258
259 // save the entry point
260 handle->entry = handle->eheader.e_entry;
261
262 return NO_ERROR;
263 }
264
265