blob: 3660961582255a8fb6d28aa4318d063cfb4a1f21 [file] [log] [blame]
Warner Losh310df052021-08-06 12:05:02 -06001/*
2 * ELF loading code
3 *
4 * Copyright (c) 2013 Stacey D. Son
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
blueswir184778502008-10-26 20:33:16 +000019
Peter Maydell22311972016-01-29 17:49:53 +000020#include "qemu/osdep.h"
blueswir184778502008-10-26 20:33:16 +000021
22#include "qemu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +020023#include "disas/disas.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020024#include "qemu/path.h"
blueswir184778502008-10-26 20:33:16 +000025
Warner Losh98b34d32021-08-04 17:13:24 -060026static abi_ulong target_auxents; /* Where the AUX entries are in target */
27static size_t target_auxents_sz; /* Size of AUX entries including AT_NULL */
28
Warner Losh0475f8f2021-08-06 14:20:16 -060029#include "target_arch_reg.h"
Warner Losh98b34d32021-08-04 17:13:24 -060030#include "target_os_elf.h"
31#include "target_os_stack.h"
Warner Losha8fe6d52021-08-03 22:04:20 -060032#include "target_os_thread.h"
Warner Losh0475f8f2021-08-06 14:20:16 -060033#include "target_os_user.h"
blueswir184778502008-10-26 20:33:16 +000034
Warner Losh98b34d32021-08-04 17:13:24 -060035abi_ulong target_stksiz;
36abi_ulong target_stkbas;
blueswir184778502008-10-26 20:33:16 +000037
Warner Losh0475f8f2021-08-06 14:20:16 -060038static int elf_core_dump(int signr, CPUArchState *env);
39
Warner Loshb4bebee2021-04-23 09:05:57 -060040static inline void memcpy_fromfs(void *to, const void *from, unsigned long n)
blueswir184778502008-10-26 20:33:16 +000041{
Warner Loshb62f7902021-08-02 22:59:12 -060042 memcpy(to, from, n);
blueswir184778502008-10-26 20:33:16 +000043}
44
blueswir184778502008-10-26 20:33:16 +000045#ifdef BSWAP_NEEDED
46static void bswap_ehdr(struct elfhdr *ehdr)
47{
Warner Loshb62f7902021-08-02 22:59:12 -060048 bswap16s(&ehdr->e_type); /* Object file type */
blueswir184778502008-10-26 20:33:16 +000049 bswap16s(&ehdr->e_machine); /* Architecture */
50 bswap32s(&ehdr->e_version); /* Object file version */
51 bswaptls(&ehdr->e_entry); /* Entry point virtual address */
52 bswaptls(&ehdr->e_phoff); /* Program header table file offset */
53 bswaptls(&ehdr->e_shoff); /* Section header table file offset */
54 bswap32s(&ehdr->e_flags); /* Processor-specific flags */
55 bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
Warner Loshb62f7902021-08-02 22:59:12 -060056 bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
blueswir184778502008-10-26 20:33:16 +000057 bswap16s(&ehdr->e_phnum); /* Program header table entry count */
Warner Loshb62f7902021-08-02 22:59:12 -060058 bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
blueswir184778502008-10-26 20:33:16 +000059 bswap16s(&ehdr->e_shnum); /* Section header table entry count */
Warner Loshb62f7902021-08-02 22:59:12 -060060 bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
blueswir184778502008-10-26 20:33:16 +000061}
62
Warner Loshb62f7902021-08-02 22:59:12 -060063static void bswap_phdr(struct elf_phdr *phdr, int phnum)
blueswir184778502008-10-26 20:33:16 +000064{
Warner Loshb62f7902021-08-02 22:59:12 -060065 int i;
66
67 for (i = 0; i < phnum; i++, phdr++) {
68 bswap32s(&phdr->p_type); /* Segment type */
69 bswap32s(&phdr->p_flags); /* Segment flags */
70 bswaptls(&phdr->p_offset); /* Segment file offset */
71 bswaptls(&phdr->p_vaddr); /* Segment virtual address */
72 bswaptls(&phdr->p_paddr); /* Segment physical address */
73 bswaptls(&phdr->p_filesz); /* Segment size in file */
74 bswaptls(&phdr->p_memsz); /* Segment size in memory */
75 bswaptls(&phdr->p_align); /* Segment alignment */
76 }
blueswir184778502008-10-26 20:33:16 +000077}
78
Warner Loshb62f7902021-08-02 22:59:12 -060079static void bswap_shdr(struct elf_shdr *shdr, int shnum)
blueswir184778502008-10-26 20:33:16 +000080{
Warner Loshb62f7902021-08-02 22:59:12 -060081 int i;
82
83 for (i = 0; i < shnum; i++, shdr++) {
84 bswap32s(&shdr->sh_name);
85 bswap32s(&shdr->sh_type);
86 bswaptls(&shdr->sh_flags);
87 bswaptls(&shdr->sh_addr);
88 bswaptls(&shdr->sh_offset);
89 bswaptls(&shdr->sh_size);
90 bswap32s(&shdr->sh_link);
91 bswap32s(&shdr->sh_info);
92 bswaptls(&shdr->sh_addralign);
93 bswaptls(&shdr->sh_entsize);
94 }
blueswir184778502008-10-26 20:33:16 +000095}
96
97static void bswap_sym(struct elf_sym *sym)
98{
99 bswap32s(&sym->st_name);
100 bswaptls(&sym->st_value);
101 bswaptls(&sym->st_size);
102 bswap16s(&sym->st_shndx);
103}
Warner Loshb62f7902021-08-02 22:59:12 -0600104
Warner Losh0475f8f2021-08-06 14:20:16 -0600105static void bswap_note(struct elf_note *en)
106{
107 bswap32s(&en->n_namesz);
108 bswap32s(&en->n_descsz);
109 bswap32s(&en->n_type);
110}
111
Warner Loshb62f7902021-08-02 22:59:12 -0600112#else /* ! BSWAP_NEEDED */
113
114static void bswap_ehdr(struct elfhdr *ehdr) { }
115static void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
116static void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
117static void bswap_sym(struct elf_sym *sym) { }
Warner Losh0475f8f2021-08-06 14:20:16 -0600118static void bswap_note(struct elf_note *en) { }
Warner Loshb62f7902021-08-02 22:59:12 -0600119
120#endif /* ! BSWAP_NEEDED */
blueswir184778502008-10-26 20:33:16 +0000121
Warner Losh0475f8f2021-08-06 14:20:16 -0600122#include "elfcore.c"
123
blueswir184778502008-10-26 20:33:16 +0000124/*
125 * 'copy_elf_strings()' copies argument/envelope strings from user
126 * memory to free pages in kernel mem. These are in a format ready
127 * to be put directly into the top of new user memory.
128 *
129 */
Warner Loshb4bebee2021-04-23 09:05:57 -0600130static abi_ulong copy_elf_strings(int argc, char **argv, void **page,
blueswir184778502008-10-26 20:33:16 +0000131 abi_ulong p)
132{
133 char *tmp, *tmp1, *pag = NULL;
134 int len, offset = 0;
135
136 if (!p) {
137 return 0; /* bullet-proofing */
138 }
139 while (argc-- > 0) {
140 tmp = argv[argc];
141 if (!tmp) {
Peter Maydell9bb93182014-06-02 13:24:37 +0100142 fprintf(stderr, "VFS: argc is wrong");
blueswir184778502008-10-26 20:33:16 +0000143 exit(-1);
144 }
145 tmp1 = tmp;
Warner Losh0456a172021-08-06 14:38:48 -0600146 while (*tmp++) {
147 continue;
148 }
blueswir184778502008-10-26 20:33:16 +0000149 len = tmp - tmp1;
150 if (p < len) { /* this shouldn't happen - 128kB */
Warner Losh0456a172021-08-06 14:38:48 -0600151 return 0;
blueswir184778502008-10-26 20:33:16 +0000152 }
153 while (len) {
154 --p; --tmp; --len;
155 if (--offset < 0) {
156 offset = p % TARGET_PAGE_SIZE;
Warner Loshb4bebee2021-04-23 09:05:57 -0600157 pag = (char *)page[p / TARGET_PAGE_SIZE];
blueswir184778502008-10-26 20:33:16 +0000158 if (!pag) {
Stefan Weilc580dee2011-11-21 21:06:22 +0100159 pag = g_try_malloc0(TARGET_PAGE_SIZE);
Warner Loshb4bebee2021-04-23 09:05:57 -0600160 page[p / TARGET_PAGE_SIZE] = pag;
Warner Losh0456a172021-08-06 14:38:48 -0600161 if (!pag) {
blueswir184778502008-10-26 20:33:16 +0000162 return 0;
Warner Losh0456a172021-08-06 14:38:48 -0600163 }
blueswir184778502008-10-26 20:33:16 +0000164 }
165 }
166 if (len == 0 || offset == 0) {
167 *(pag + offset) = *tmp;
Warner Losh0456a172021-08-06 14:38:48 -0600168 } else {
blueswir184778502008-10-26 20:33:16 +0000169 int bytes_to_copy = (len > offset) ? offset : len;
170 tmp -= bytes_to_copy;
171 p -= bytes_to_copy;
172 offset -= bytes_to_copy;
173 len -= bytes_to_copy;
174 memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
175 }
176 }
177 }
178 return p;
179}
180
Warner Losh98b34d32021-08-04 17:13:24 -0600181static void setup_arg_pages(struct bsd_binprm *bprm, struct image_info *info,
182 abi_ulong *stackp, abi_ulong *stringp)
blueswir184778502008-10-26 20:33:16 +0000183{
Warner Losh98b34d32021-08-04 17:13:24 -0600184 abi_ulong stack_base, size;
185 abi_long addr;
blueswir184778502008-10-26 20:33:16 +0000186
Warner Losh0456a172021-08-06 14:38:48 -0600187 /*
188 * Create enough stack to hold everything. If we don't use it for args,
189 * we'll use it for something else...
blueswir184778502008-10-26 20:33:16 +0000190 */
Warner Losh312a0b12021-08-06 18:48:37 -0600191 size = target_dflssiz;
Warner Losh98b34d32021-08-04 17:13:24 -0600192 stack_base = TARGET_USRSTACK - size;
Warner Losh0456a172021-08-06 14:38:48 -0600193 addr = target_mmap(stack_base , size + qemu_host_page_size,
194 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
Warner Losh98b34d32021-08-04 17:13:24 -0600195 if (addr == -1) {
blueswir184778502008-10-26 20:33:16 +0000196 perror("stk mmap");
197 exit(-1);
198 }
199 /* we reserve one extra page at the top of the stack as guard */
Warner Losh98b34d32021-08-04 17:13:24 -0600200 target_mprotect(addr + size, qemu_host_page_size, PROT_NONE);
blueswir184778502008-10-26 20:33:16 +0000201
Warner Losh98b34d32021-08-04 17:13:24 -0600202 target_stksiz = size;
203 target_stkbas = addr;
blueswir184778502008-10-26 20:33:16 +0000204
Warner Losh98b34d32021-08-04 17:13:24 -0600205 if (setup_initial_stack(bprm, stackp, stringp) != 0) {
206 perror("stk setup");
207 exit(-1);
blueswir184778502008-10-26 20:33:16 +0000208 }
blueswir184778502008-10-26 20:33:16 +0000209}
210
211static void set_brk(abi_ulong start, abi_ulong end)
212{
Warner Losh0456a172021-08-06 14:38:48 -0600213 /* page-align the start and end addresses... */
214 start = HOST_PAGE_ALIGN(start);
215 end = HOST_PAGE_ALIGN(end);
216 if (end <= start) {
217 return;
218 }
219 if (target_mmap(start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC,
220 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
221 perror("cannot mmap brk");
222 exit(-1);
223 }
blueswir184778502008-10-26 20:33:16 +0000224}
225
226
Warner Losh0456a172021-08-06 14:38:48 -0600227/*
228 * We need to explicitly zero any fractional pages after the data
229 * section (i.e. bss). This would contain the junk from the file that
230 * should not be in memory.
231 */
blueswir184778502008-10-26 20:33:16 +0000232static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
233{
Warner Losh0456a172021-08-06 14:38:48 -0600234 abi_ulong nbyte;
blueswir184778502008-10-26 20:33:16 +0000235
Warner Losh0456a172021-08-06 14:38:48 -0600236 if (elf_bss >= last_bss) {
237 return;
238 }
blueswir184778502008-10-26 20:33:16 +0000239
Warner Losh0456a172021-08-06 14:38:48 -0600240 /*
241 * XXX: this is really a hack : if the real host page size is
242 * smaller than the target page size, some pages after the end
243 * of the file may not be mapped. A better fix would be to
244 * patch target_mmap(), but it is more complicated as the file
245 * size must be known.
246 */
247 if (qemu_real_host_page_size < qemu_host_page_size) {
248 abi_ulong end_addr, end_addr1;
249 end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss);
250 end_addr = HOST_PAGE_ALIGN(elf_bss);
251 if (end_addr1 < end_addr) {
252 mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1,
253 PROT_READ | PROT_WRITE | PROT_EXEC,
254 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
blueswir184778502008-10-26 20:33:16 +0000255 }
Warner Losh0456a172021-08-06 14:38:48 -0600256 }
blueswir184778502008-10-26 20:33:16 +0000257
Warner Losh0456a172021-08-06 14:38:48 -0600258 nbyte = elf_bss & (qemu_host_page_size - 1);
259 if (nbyte) {
260 nbyte = qemu_host_page_size - nbyte;
261 do {
262 /* FIXME - what to do if put_user() fails? */
263 put_user_u8(0, elf_bss);
264 elf_bss++;
265 } while (--nbyte);
266 }
blueswir184778502008-10-26 20:33:16 +0000267}
268
Warner Loshb4bebee2021-04-23 09:05:57 -0600269static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex,
blueswir184778502008-10-26 20:33:16 +0000270 int interpreter_fd,
271 abi_ulong *interp_load_addr)
272{
Warner Loshb4bebee2021-04-23 09:05:57 -0600273 struct elf_phdr *elf_phdata = NULL;
274 struct elf_phdr *eppnt;
275 abi_ulong load_addr = 0;
276 int load_addr_set = 0;
277 int retval;
278 abi_ulong last_bss, elf_bss;
279 abi_ulong error;
280 int i;
blueswir184778502008-10-26 20:33:16 +0000281
Warner Loshb4bebee2021-04-23 09:05:57 -0600282 elf_bss = 0;
283 last_bss = 0;
284 error = 0;
blueswir184778502008-10-26 20:33:16 +0000285
Warner Loshb4bebee2021-04-23 09:05:57 -0600286 bswap_ehdr(interp_elf_ex);
Warner Loshb4bebee2021-04-23 09:05:57 -0600287 /* First of all, some simple consistency checks */
Warner Losh0456a172021-08-06 14:38:48 -0600288 if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) ||
289 !elf_check_arch(interp_elf_ex->e_machine)) {
Warner Loshb4bebee2021-04-23 09:05:57 -0600290 return ~((abi_ulong)0UL);
291 }
blueswir184778502008-10-26 20:33:16 +0000292
293
Warner Loshb4bebee2021-04-23 09:05:57 -0600294 /* Now read in all of the header information */
Warner Losh0456a172021-08-06 14:38:48 -0600295 if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) {
Warner Loshb4bebee2021-04-23 09:05:57 -0600296 return ~(abi_ulong)0UL;
Warner Losh0456a172021-08-06 14:38:48 -0600297 }
blueswir184778502008-10-26 20:33:16 +0000298
Warner Losh0456a172021-08-06 14:38:48 -0600299 elf_phdata = (struct elf_phdr *) malloc(sizeof(struct elf_phdr) *
300 interp_elf_ex->e_phnum);
blueswir184778502008-10-26 20:33:16 +0000301
Warner Losh0456a172021-08-06 14:38:48 -0600302 if (!elf_phdata) {
Warner Loshb4bebee2021-04-23 09:05:57 -0600303 return ~((abi_ulong)0UL);
Warner Losh0456a172021-08-06 14:38:48 -0600304 }
blueswir184778502008-10-26 20:33:16 +0000305
Warner Loshb4bebee2021-04-23 09:05:57 -0600306 /*
307 * If the size of this structure has changed, then punt, since
308 * we will be doing the wrong thing.
309 */
310 if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
311 free(elf_phdata);
312 return ~((abi_ulong)0UL);
313 }
blueswir184778502008-10-26 20:33:16 +0000314
Warner Loshb4bebee2021-04-23 09:05:57 -0600315 retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
316 if (retval >= 0) {
Warner Losh0456a172021-08-06 14:38:48 -0600317 retval = read(interpreter_fd, (char *) elf_phdata,
318 sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
Warner Loshb4bebee2021-04-23 09:05:57 -0600319 }
320 if (retval < 0) {
321 perror("load_elf_interp");
322 exit(-1);
Warner Loshffa03662021-04-30 08:17:23 -0600323 free(elf_phdata);
Warner Loshb4bebee2021-04-23 09:05:57 -0600324 return retval;
325 }
Warner Loshb62f7902021-08-02 22:59:12 -0600326 bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
blueswir184778502008-10-26 20:33:16 +0000327
Warner Loshb4bebee2021-04-23 09:05:57 -0600328 if (interp_elf_ex->e_type == ET_DYN) {
Warner Losh0456a172021-08-06 14:38:48 -0600329 /*
330 * In order to avoid hardcoding the interpreter load
331 * address in qemu, we allocate a big enough memory zone.
332 */
333 error = target_mmap(0, INTERP_MAP_SIZE, PROT_NONE,
334 MAP_PRIVATE | MAP_ANON, -1, 0);
Warner Loshb4bebee2021-04-23 09:05:57 -0600335 if (error == -1) {
336 perror("mmap");
337 exit(-1);
blueswir184778502008-10-26 20:33:16 +0000338 }
Warner Loshb4bebee2021-04-23 09:05:57 -0600339 load_addr = error;
340 load_addr_set = 1;
341 }
blueswir184778502008-10-26 20:33:16 +0000342
Warner Loshb4bebee2021-04-23 09:05:57 -0600343 eppnt = elf_phdata;
344 for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++)
345 if (eppnt->p_type == PT_LOAD) {
blueswir184778502008-10-26 20:33:16 +0000346 int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
347 int elf_prot = 0;
348 abi_ulong vaddr = 0;
349 abi_ulong k;
350
351 if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
352 if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
353 if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
354 if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
355 elf_type |= MAP_FIXED;
356 vaddr = eppnt->p_vaddr;
357 }
Warner Loshb4bebee2021-04-23 09:05:57 -0600358 error = target_mmap(load_addr + TARGET_ELF_PAGESTART(vaddr),
359 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
360 elf_prot,
361 elf_type,
362 interpreter_fd,
363 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
blueswir184778502008-10-26 20:33:16 +0000364
365 if (error == -1) {
Warner Loshb4bebee2021-04-23 09:05:57 -0600366 /* Real error */
367 close(interpreter_fd);
368 free(elf_phdata);
369 return ~((abi_ulong)0UL);
blueswir184778502008-10-26 20:33:16 +0000370 }
371
372 if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
Warner Loshb4bebee2021-04-23 09:05:57 -0600373 load_addr = error;
374 load_addr_set = 1;
blueswir184778502008-10-26 20:33:16 +0000375 }
376
377 /*
378 * Find the end of the file mapping for this phdr, and keep
379 * track of the largest address we see for this.
380 */
381 k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
382 if (k > elf_bss) elf_bss = k;
383
384 /*
385 * Do the same thing for the memory mapping - between
386 * elf_bss and last_bss is the bss section.
387 */
388 k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
389 if (k > last_bss) last_bss = k;
blueswir184778502008-10-26 20:33:16 +0000390 }
blueswir184778502008-10-26 20:33:16 +0000391
Warner Loshb4bebee2021-04-23 09:05:57 -0600392 /* Now use mmap to map the library into memory. */
393
394 close(interpreter_fd);
395
396 /*
397 * Now fill out the bss section. First pad the last page up
398 * to the page boundary, and then perform a mmap to make sure
399 * that there are zeromapped pages up to and including the last
400 * bss page.
401 */
402 padzero(elf_bss, last_bss);
403 elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
404
405 /* Map the last of the bss segment */
406 if (last_bss > elf_bss) {
407 target_mmap(elf_bss, last_bss - elf_bss,
408 PROT_READ | PROT_WRITE | PROT_EXEC,
409 MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
410 }
411 free(elf_phdata);
412
413 *interp_load_addr = load_addr;
414 return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
blueswir184778502008-10-26 20:33:16 +0000415}
416
417static int symfind(const void *s0, const void *s1)
418{
Stefan Weilc7c530c2012-01-05 15:39:39 +0100419 target_ulong addr = *(target_ulong *)s0;
blueswir184778502008-10-26 20:33:16 +0000420 struct elf_sym *sym = (struct elf_sym *)s1;
421 int result = 0;
Stefan Weilc7c530c2012-01-05 15:39:39 +0100422 if (addr < sym->st_value) {
blueswir184778502008-10-26 20:33:16 +0000423 result = -1;
Stefan Weilc7c530c2012-01-05 15:39:39 +0100424 } else if (addr >= sym->st_value + sym->st_size) {
blueswir184778502008-10-26 20:33:16 +0000425 result = 1;
426 }
427 return result;
428}
429
430static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
431{
432#if ELF_CLASS == ELFCLASS32
433 struct elf_sym *syms = s->disas_symtab.elf32;
434#else
435 struct elf_sym *syms = s->disas_symtab.elf64;
436#endif
437
Warner Losh0456a172021-08-06 14:38:48 -0600438 /* binary search */
blueswir184778502008-10-26 20:33:16 +0000439 struct elf_sym *sym;
440
Stefan Weilc7c530c2012-01-05 15:39:39 +0100441 sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
Blue Swirl7cba04f2009-08-01 10:13:20 +0000442 if (sym != NULL) {
blueswir184778502008-10-26 20:33:16 +0000443 return s->disas_strtab + sym->st_name;
444 }
445
446 return "";
447}
448
449/* FIXME: This should use elf_ops.h */
450static int symcmp(const void *s0, const void *s1)
451{
452 struct elf_sym *sym0 = (struct elf_sym *)s0;
453 struct elf_sym *sym1 = (struct elf_sym *)s1;
Warner Losh0456a172021-08-06 14:38:48 -0600454 return (sym0->st_value < sym1->st_value) ? -1 :
455 ((sym0->st_value > sym1->st_value) ? 1 : 0);
blueswir184778502008-10-26 20:33:16 +0000456}
457
458/* Best attempt to load symbols from this ELF object. */
459static void load_symbols(struct elfhdr *hdr, int fd)
460{
461 unsigned int i, nsyms;
462 struct elf_shdr sechdr, symtab, strtab;
463 char *strings;
464 struct syminfo *s;
Stefan Weil29718712011-01-16 16:28:20 +0100465 struct elf_sym *syms, *new_syms;
blueswir184778502008-10-26 20:33:16 +0000466
467 lseek(fd, hdr->e_shoff, SEEK_SET);
468 for (i = 0; i < hdr->e_shnum; i++) {
Warner Losh0456a172021-08-06 14:38:48 -0600469 if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) {
blueswir184778502008-10-26 20:33:16 +0000470 return;
Warner Losh0456a172021-08-06 14:38:48 -0600471 }
Warner Loshb62f7902021-08-02 22:59:12 -0600472 bswap_shdr(&sechdr, 1);
blueswir184778502008-10-26 20:33:16 +0000473 if (sechdr.sh_type == SHT_SYMTAB) {
474 symtab = sechdr;
Warner Losh0456a172021-08-06 14:38:48 -0600475 lseek(fd, hdr->e_shoff + sizeof(sechdr) * sechdr.sh_link,
476 SEEK_SET);
477 if (read(fd, &strtab, sizeof(strtab)) != sizeof(strtab)) {
blueswir184778502008-10-26 20:33:16 +0000478 return;
Warner Losh0456a172021-08-06 14:38:48 -0600479 }
Warner Loshb62f7902021-08-02 22:59:12 -0600480 bswap_shdr(&strtab, 1);
blueswir184778502008-10-26 20:33:16 +0000481 goto found;
482 }
483 }
484 return; /* Shouldn't happen... */
485
Warner Losh0456a172021-08-06 14:38:48 -0600486found:
blueswir184778502008-10-26 20:33:16 +0000487 /* Now know where the strtab and symtab are. Snarf them. */
488 s = malloc(sizeof(*s));
489 syms = malloc(symtab.sh_size);
Stefan Weil29718712011-01-16 16:28:20 +0100490 if (!syms) {
491 free(s);
blueswir184778502008-10-26 20:33:16 +0000492 return;
Stefan Weil29718712011-01-16 16:28:20 +0100493 }
blueswir184778502008-10-26 20:33:16 +0000494 s->disas_strtab = strings = malloc(strtab.sh_size);
Stefan Weil29718712011-01-16 16:28:20 +0100495 if (!s->disas_strtab) {
496 free(s);
497 free(syms);
blueswir184778502008-10-26 20:33:16 +0000498 return;
Stefan Weil29718712011-01-16 16:28:20 +0100499 }
blueswir184778502008-10-26 20:33:16 +0000500
501 lseek(fd, symtab.sh_offset, SEEK_SET);
Stefan Weil29718712011-01-16 16:28:20 +0100502 if (read(fd, syms, symtab.sh_size) != symtab.sh_size) {
503 free(s);
504 free(syms);
505 free(strings);
blueswir184778502008-10-26 20:33:16 +0000506 return;
Stefan Weil29718712011-01-16 16:28:20 +0100507 }
blueswir184778502008-10-26 20:33:16 +0000508
509 nsyms = symtab.sh_size / sizeof(struct elf_sym);
510
511 i = 0;
512 while (i < nsyms) {
blueswir184778502008-10-26 20:33:16 +0000513 bswap_sym(syms + i);
Warner Losh0456a172021-08-06 14:38:48 -0600514 /* Throw away entries which we do not need. */
blueswir184778502008-10-26 20:33:16 +0000515 if (syms[i].st_shndx == SHN_UNDEF ||
516 syms[i].st_shndx >= SHN_LORESERVE ||
517 ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
518 nsyms--;
519 if (i < nsyms) {
520 syms[i] = syms[nsyms];
521 }
522 continue;
523 }
blueswir184778502008-10-26 20:33:16 +0000524 i++;
525 }
Stefan Weil29718712011-01-16 16:28:20 +0100526
Warner Losh0456a172021-08-06 14:38:48 -0600527 /*
528 * Attempt to free the storage associated with the local symbols
529 * that we threw away. Whether or not this has any effect on the
530 * memory allocation depends on the malloc implementation and how
531 * many symbols we managed to discard.
532 */
Stefan Weil29718712011-01-16 16:28:20 +0100533 new_syms = realloc(syms, nsyms * sizeof(*syms));
534 if (new_syms == NULL) {
535 free(s);
536 free(syms);
537 free(strings);
538 return;
539 }
540 syms = new_syms;
blueswir184778502008-10-26 20:33:16 +0000541
542 qsort(syms, nsyms, sizeof(*syms), symcmp);
543
544 lseek(fd, strtab.sh_offset, SEEK_SET);
Stefan Weil29718712011-01-16 16:28:20 +0100545 if (read(fd, strings, strtab.sh_size) != strtab.sh_size) {
546 free(s);
547 free(syms);
548 free(strings);
blueswir184778502008-10-26 20:33:16 +0000549 return;
Stefan Weil29718712011-01-16 16:28:20 +0100550 }
blueswir184778502008-10-26 20:33:16 +0000551 s->disas_num_syms = nsyms;
552#if ELF_CLASS == ELFCLASS32
553 s->disas_symtab.elf32 = syms;
Blue Swirl032e51d2009-09-27 19:30:56 +0000554 s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
blueswir184778502008-10-26 20:33:16 +0000555#else
556 s->disas_symtab.elf64 = syms;
Blue Swirl032e51d2009-09-27 19:30:56 +0000557 s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
blueswir184778502008-10-26 20:33:16 +0000558#endif
559 s->next = syminfos;
560 syminfos = s;
561}
562
Warner Loshafcbcff2021-04-29 10:04:28 -0600563int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
Warner Loshb4bebee2021-04-23 09:05:57 -0600564 struct image_info *info)
blueswir184778502008-10-26 20:33:16 +0000565{
566 struct elfhdr elf_ex;
567 struct elfhdr interp_elf_ex;
blueswir184778502008-10-26 20:33:16 +0000568 int interpreter_fd = -1; /* avoid warning */
569 abi_ulong load_addr, load_bias;
570 int load_addr_set = 0;
blueswir184778502008-10-26 20:33:16 +0000571 int i;
blueswir184778502008-10-26 20:33:16 +0000572 struct elf_phdr * elf_ppnt;
573 struct elf_phdr *elf_phdata;
574 abi_ulong elf_bss, k, elf_brk;
575 int retval;
576 char * elf_interpreter;
577 abi_ulong elf_entry, interp_load_addr = 0;
blueswir184778502008-10-26 20:33:16 +0000578 abi_ulong start_code, end_code, start_data, end_data;
579 abi_ulong reloc_func_desc = 0;
blueswir184778502008-10-26 20:33:16 +0000580
blueswir184778502008-10-26 20:33:16 +0000581 load_addr = 0;
582 load_bias = 0;
583 elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
blueswir184778502008-10-26 20:33:16 +0000584 bswap_ehdr(&elf_ex);
blueswir184778502008-10-26 20:33:16 +0000585
586 /* First of all, some simple consistency checks */
587 if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
Warner Losh0456a172021-08-06 14:38:48 -0600588 (!elf_check_arch(elf_ex.e_machine))) {
blueswir184778502008-10-26 20:33:16 +0000589 return -ENOEXEC;
590 }
591
592 bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
Warner Losh0456a172021-08-06 14:38:48 -0600593 bprm->p = copy_elf_strings(bprm->envc, bprm->envp, bprm->page, bprm->p);
594 bprm->p = copy_elf_strings(bprm->argc, bprm->argv, bprm->page, bprm->p);
blueswir184778502008-10-26 20:33:16 +0000595 if (!bprm->p) {
596 retval = -E2BIG;
597 }
598
599 /* Now read in all of the header information */
Warner Losh0456a172021-08-06 14:38:48 -0600600 elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize * elf_ex.e_phnum);
blueswir184778502008-10-26 20:33:16 +0000601 if (elf_phdata == NULL) {
602 return -ENOMEM;
603 }
604
605 retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
Warner Loshb4bebee2021-04-23 09:05:57 -0600606 if (retval > 0) {
607 retval = read(bprm->fd, (char *)elf_phdata,
blueswir184778502008-10-26 20:33:16 +0000608 elf_ex.e_phentsize * elf_ex.e_phnum);
609 }
610
611 if (retval < 0) {
612 perror("load_elf_binary");
613 exit(-1);
Warner Loshb4bebee2021-04-23 09:05:57 -0600614 free(elf_phdata);
blueswir184778502008-10-26 20:33:16 +0000615 return -errno;
616 }
617
Warner Loshb62f7902021-08-02 22:59:12 -0600618 bswap_phdr(elf_phdata, elf_ex.e_phnum);
blueswir184778502008-10-26 20:33:16 +0000619 elf_ppnt = elf_phdata;
620
621 elf_bss = 0;
622 elf_brk = 0;
623
624
blueswir184778502008-10-26 20:33:16 +0000625 elf_interpreter = NULL;
626 start_code = ~((abi_ulong)0UL);
627 end_code = 0;
628 start_data = 0;
629 end_data = 0;
blueswir184778502008-10-26 20:33:16 +0000630
Warner Losh0456a172021-08-06 14:38:48 -0600631 for (i = 0; i < elf_ex.e_phnum; i++) {
blueswir184778502008-10-26 20:33:16 +0000632 if (elf_ppnt->p_type == PT_INTERP) {
Warner Losh0456a172021-08-06 14:38:48 -0600633 if (elf_interpreter != NULL) {
Warner Loshb4bebee2021-04-23 09:05:57 -0600634 free(elf_phdata);
blueswir184778502008-10-26 20:33:16 +0000635 free(elf_interpreter);
636 close(bprm->fd);
637 return -EINVAL;
638 }
639
blueswir184778502008-10-26 20:33:16 +0000640 elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
blueswir184778502008-10-26 20:33:16 +0000641 if (elf_interpreter == NULL) {
Warner Loshb4bebee2021-04-23 09:05:57 -0600642 free(elf_phdata);
blueswir184778502008-10-26 20:33:16 +0000643 close(bprm->fd);
644 return -ENOMEM;
645 }
646
647 retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
Warner Loshb4bebee2021-04-23 09:05:57 -0600648 if (retval >= 0) {
blueswir184778502008-10-26 20:33:16 +0000649 retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
650 }
Warner Loshb4bebee2021-04-23 09:05:57 -0600651 if (retval < 0) {
blueswir184778502008-10-26 20:33:16 +0000652 perror("load_elf_binary2");
653 exit(-1);
654 }
655
blueswir184778502008-10-26 20:33:16 +0000656 if (retval >= 0) {
657 retval = open(path(elf_interpreter), O_RDONLY);
Warner Loshb4bebee2021-04-23 09:05:57 -0600658 if (retval >= 0) {
blueswir184778502008-10-26 20:33:16 +0000659 interpreter_fd = retval;
Warner Losh0456a172021-08-06 14:38:48 -0600660 } else {
blueswir184778502008-10-26 20:33:16 +0000661 perror(elf_interpreter);
662 exit(-1);
663 /* retval = -errno; */
664 }
665 }
666
667 if (retval >= 0) {
668 retval = lseek(interpreter_fd, 0, SEEK_SET);
Warner Loshb4bebee2021-04-23 09:05:57 -0600669 if (retval >= 0) {
670 retval = read(interpreter_fd, bprm->buf, 128);
blueswir184778502008-10-26 20:33:16 +0000671 }
672 }
673 if (retval >= 0) {
Warner Losh0456a172021-08-06 14:38:48 -0600674 interp_elf_ex = *((struct elfhdr *) bprm->buf);
blueswir184778502008-10-26 20:33:16 +0000675 }
676 if (retval < 0) {
677 perror("load_elf_binary3");
678 exit(-1);
Warner Loshb4bebee2021-04-23 09:05:57 -0600679 free(elf_phdata);
blueswir184778502008-10-26 20:33:16 +0000680 free(elf_interpreter);
681 close(bprm->fd);
682 return retval;
683 }
684 }
685 elf_ppnt++;
686 }
687
688 /* Some simple consistency checks for the interpreter */
Warner Loshb4bebee2021-04-23 09:05:57 -0600689 if (elf_interpreter) {
blueswir184778502008-10-26 20:33:16 +0000690 if (interp_elf_ex.e_ident[0] != 0x7f ||
Warner Loshffa03662021-04-30 08:17:23 -0600691 strncmp((char *)&interp_elf_ex.e_ident[1], "ELF", 3) != 0) {
blueswir184778502008-10-26 20:33:16 +0000692 free(elf_interpreter);
693 free(elf_phdata);
694 close(bprm->fd);
695 return -ELIBBAD;
696 }
697 }
698
Warner Losh0456a172021-08-06 14:38:48 -0600699 /*
700 * OK, we are done with that, now set up the arg stuff, and then start this
701 * sucker up
702 */
Warner Loshffa03662021-04-30 08:17:23 -0600703 if (!bprm->p) {
704 free(elf_interpreter);
705 free(elf_phdata);
706 close(bprm->fd);
707 return -E2BIG;
blueswir184778502008-10-26 20:33:16 +0000708 }
709
710 /* OK, This is the point of no return */
711 info->end_data = 0;
712 info->end_code = 0;
713 info->start_mmap = (abi_ulong)ELF_START_MMAP;
714 info->mmap = 0;
715 elf_entry = (abi_ulong) elf_ex.e_entry;
716
717 /* Do this so that we can load the interpreter, if need be. We will
718 change some of these later */
719 info->rss = 0;
Warner Losh98b34d32021-08-04 17:13:24 -0600720 setup_arg_pages(bprm, info, &bprm->p, &bprm->stringp);
blueswir184778502008-10-26 20:33:16 +0000721 info->start_stack = bprm->p;
722
723 /* Now we do a little grungy work by mmaping the ELF image into
724 * the correct location in memory. At this point, we assume that
725 * the image should be loaded at fixed address, not at a variable
726 * address.
727 */
728
Warner Loshb4bebee2021-04-23 09:05:57 -0600729 for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
blueswir184778502008-10-26 20:33:16 +0000730 int elf_prot = 0;
731 int elf_flags = 0;
732 abi_ulong error;
733
734 if (elf_ppnt->p_type != PT_LOAD)
735 continue;
736
737 if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
738 if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
739 if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
740 elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
741 if (elf_ex.e_type == ET_EXEC || load_addr_set) {
742 elf_flags |= MAP_FIXED;
743 } else if (elf_ex.e_type == ET_DYN) {
744 /* Try and get dynamic programs out of the way of the default mmap
745 base, as well as whatever program they might try to exec. This
746 is because the brk will follow the loader, and is not movable. */
747 /* NOTE: for qemu, we do a big mmap to get enough space
748 without hardcoding any address */
749 error = target_mmap(0, ET_DYN_MAP_SIZE,
750 PROT_NONE, MAP_PRIVATE | MAP_ANON,
751 -1, 0);
752 if (error == -1) {
753 perror("mmap");
754 exit(-1);
755 }
756 load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
757 }
758
759 error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
760 (elf_ppnt->p_filesz +
761 TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
762 elf_prot,
763 (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
764 bprm->fd,
765 (elf_ppnt->p_offset -
766 TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
767 if (error == -1) {
768 perror("mmap");
769 exit(-1);
770 }
771
blueswir184778502008-10-26 20:33:16 +0000772 if (!load_addr_set) {
773 load_addr_set = 1;
774 load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
775 if (elf_ex.e_type == ET_DYN) {
776 load_bias += error -
777 TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
778 load_addr += load_bias;
779 reloc_func_desc = load_bias;
780 }
781 }
782 k = elf_ppnt->p_vaddr;
783 if (k < start_code)
784 start_code = k;
785 if (start_data < k)
786 start_data = k;
787 k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
788 if (k > elf_bss)
789 elf_bss = k;
790 if ((elf_ppnt->p_flags & PF_X) && end_code < k)
791 end_code = k;
792 if (end_data < k)
793 end_data = k;
794 k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
795 if (k > elf_brk) elf_brk = k;
796 }
797
798 elf_entry += load_bias;
799 elf_bss += load_bias;
800 elf_brk += load_bias;
801 start_code += load_bias;
802 end_code += load_bias;
803 start_data += load_bias;
804 end_data += load_bias;
805
806 if (elf_interpreter) {
Warner Loshffa03662021-04-30 08:17:23 -0600807 elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
808 &interp_load_addr);
blueswir184778502008-10-26 20:33:16 +0000809 reloc_func_desc = interp_load_addr;
810
811 close(interpreter_fd);
812 free(elf_interpreter);
813
814 if (elf_entry == ~((abi_ulong)0UL)) {
815 printf("Unable to load interpreter\n");
816 free(elf_phdata);
817 exit(-1);
818 return 0;
819 }
820 }
821
822 free(elf_phdata);
823
Warner Losh0456a172021-08-06 14:38:48 -0600824 if (qemu_log_enabled()) {
blueswir184778502008-10-26 20:33:16 +0000825 load_symbols(&elf_ex, bprm->fd);
Warner Losh0456a172021-08-06 14:38:48 -0600826 }
blueswir184778502008-10-26 20:33:16 +0000827
Warner Loshffa03662021-04-30 08:17:23 -0600828 close(bprm->fd);
blueswir184778502008-10-26 20:33:16 +0000829
Warner Losh98b34d32021-08-04 17:13:24 -0600830 bprm->p = target_create_elf_tables(bprm->p, bprm->argc, bprm->envc,
831 bprm->stringp, &elf_ex, load_addr,
832 load_bias, interp_load_addr, info);
blueswir184778502008-10-26 20:33:16 +0000833 info->load_addr = reloc_func_desc;
834 info->start_brk = info->brk = elf_brk;
835 info->end_code = end_code;
836 info->start_code = start_code;
837 info->start_data = start_data;
838 info->end_data = end_data;
839 info->start_stack = bprm->p;
840
841 /* Calling set_brk effectively mmaps the pages that we need for the bss and break
842 sections */
843 set_brk(elf_bss, elf_brk);
844
845 padzero(elf_bss, elf_brk);
846
blueswir184778502008-10-26 20:33:16 +0000847 info->entry = elf_entry;
848
Warner Losh0475f8f2021-08-06 14:20:16 -0600849#ifdef USE_ELF_CORE_DUMP
850 bprm->core_dump = &elf_core_dump;
851#else
852 bprm->core_dump = NULL;
853#endif
854
blueswir184778502008-10-26 20:33:16 +0000855 return 0;
856}
857
blueswir184778502008-10-26 20:33:16 +0000858void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
859{
Warner Losha8fe6d52021-08-03 22:04:20 -0600860
861 target_thread_init(regs, infop);
blueswir184778502008-10-26 20:33:16 +0000862}