xref: /qemu/bsd-user/elfload.c (revision 159fb790)
1310df056SWarner Losh /*
2310df056SWarner Losh  *  ELF loading code
3310df056SWarner Losh  *
4310df056SWarner Losh  *  Copyright (c) 2013 Stacey D. Son
5310df056SWarner Losh  *
6310df056SWarner Losh  *  This program is free software; you can redistribute it and/or modify
7310df056SWarner Losh  *  it under the terms of the GNU General Public License as published by
8310df056SWarner Losh  *  the Free Software Foundation; either version 2 of the License, or
9310df056SWarner Losh  *  (at your option) any later version.
10310df056SWarner Losh  *
11310df056SWarner Losh  *  This program is distributed in the hope that it will be useful,
12310df056SWarner Losh  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13310df056SWarner Losh  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14310df056SWarner Losh  *  GNU General Public License for more details.
15310df056SWarner Losh  *
16310df056SWarner Losh  *  You should have received a copy of the GNU General Public License
17310df056SWarner Losh  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18310df056SWarner Losh  */
1984778508Sblueswir1 
202231197cSPeter Maydell #include "qemu/osdep.h"
2184778508Sblueswir1 
2284778508Sblueswir1 #include "qemu.h"
2376cad711SPaolo Bonzini #include "disas/disas.h"
24f348b6d1SVeronia Bahaa #include "qemu/path.h"
2584778508Sblueswir1 
2698b34d35SWarner Losh static abi_ulong target_auxents;   /* Where the AUX entries are in target */
2798b34d35SWarner Losh static size_t target_auxents_sz;   /* Size of AUX entries including AT_NULL */
2898b34d35SWarner Losh 
290475f8faSWarner Losh #include "target_arch_reg.h"
3098b34d35SWarner Losh #include "target_os_elf.h"
3198b34d35SWarner Losh #include "target_os_stack.h"
32a8fe6d5dSWarner Losh #include "target_os_thread.h"
330475f8faSWarner Losh #include "target_os_user.h"
3484778508Sblueswir1 
3598b34d35SWarner Losh abi_ulong target_stksiz;
3698b34d35SWarner Losh abi_ulong target_stkbas;
3784778508Sblueswir1 
380475f8faSWarner Losh static int elf_core_dump(int signr, CPUArchState *env);
39c09f12feSWarner Losh static int load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr,
40c09f12feSWarner Losh     int fd, abi_ulong rbase, abi_ulong *baddrp);
410475f8faSWarner Losh 
memcpy_fromfs(void * to,const void * from,unsigned long n)4284778508Sblueswir1 static inline void memcpy_fromfs(void *to, const void *from, unsigned long n)
4384778508Sblueswir1 {
4484778508Sblueswir1     memcpy(to, from, n);
4584778508Sblueswir1 }
4684778508Sblueswir1 
4784778508Sblueswir1 #ifdef BSWAP_NEEDED
bswap_ehdr(struct elfhdr * ehdr)4884778508Sblueswir1 static void bswap_ehdr(struct elfhdr *ehdr)
4984778508Sblueswir1 {
5084778508Sblueswir1     bswap16s(&ehdr->e_type);            /* Object file type */
5184778508Sblueswir1     bswap16s(&ehdr->e_machine);         /* Architecture */
5284778508Sblueswir1     bswap32s(&ehdr->e_version);         /* Object file version */
5384778508Sblueswir1     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
5484778508Sblueswir1     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
5584778508Sblueswir1     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
5684778508Sblueswir1     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
5784778508Sblueswir1     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
5884778508Sblueswir1     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
5984778508Sblueswir1     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
6084778508Sblueswir1     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
6184778508Sblueswir1     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
6284778508Sblueswir1     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
6384778508Sblueswir1 }
6484778508Sblueswir1 
bswap_phdr(struct elf_phdr * phdr,int phnum)65b62f790cSWarner Losh static void bswap_phdr(struct elf_phdr *phdr, int phnum)
6684778508Sblueswir1 {
67b62f790cSWarner Losh     int i;
68b62f790cSWarner Losh 
69b62f790cSWarner Losh     for (i = 0; i < phnum; i++, phdr++) {
7084778508Sblueswir1         bswap32s(&phdr->p_type);        /* Segment type */
71b62f790cSWarner Losh         bswap32s(&phdr->p_flags);       /* Segment flags */
7284778508Sblueswir1         bswaptls(&phdr->p_offset);      /* Segment file offset */
7384778508Sblueswir1         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
7484778508Sblueswir1         bswaptls(&phdr->p_paddr);       /* Segment physical address */
7584778508Sblueswir1         bswaptls(&phdr->p_filesz);      /* Segment size in file */
7684778508Sblueswir1         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
7784778508Sblueswir1         bswaptls(&phdr->p_align);       /* Segment alignment */
7884778508Sblueswir1     }
79b62f790cSWarner Losh }
8084778508Sblueswir1 
bswap_shdr(struct elf_shdr * shdr,int shnum)81b62f790cSWarner Losh static void bswap_shdr(struct elf_shdr *shdr, int shnum)
8284778508Sblueswir1 {
83b62f790cSWarner Losh     int i;
84b62f790cSWarner Losh 
85b62f790cSWarner Losh     for (i = 0; i < shnum; i++, shdr++) {
8684778508Sblueswir1         bswap32s(&shdr->sh_name);
8784778508Sblueswir1         bswap32s(&shdr->sh_type);
8884778508Sblueswir1         bswaptls(&shdr->sh_flags);
8984778508Sblueswir1         bswaptls(&shdr->sh_addr);
9084778508Sblueswir1         bswaptls(&shdr->sh_offset);
9184778508Sblueswir1         bswaptls(&shdr->sh_size);
9284778508Sblueswir1         bswap32s(&shdr->sh_link);
9384778508Sblueswir1         bswap32s(&shdr->sh_info);
9484778508Sblueswir1         bswaptls(&shdr->sh_addralign);
9584778508Sblueswir1         bswaptls(&shdr->sh_entsize);
9684778508Sblueswir1     }
97b62f790cSWarner Losh }
9884778508Sblueswir1 
bswap_sym(struct elf_sym * sym)9984778508Sblueswir1 static void bswap_sym(struct elf_sym *sym)
10084778508Sblueswir1 {
10184778508Sblueswir1     bswap32s(&sym->st_name);
10284778508Sblueswir1     bswaptls(&sym->st_value);
10384778508Sblueswir1     bswaptls(&sym->st_size);
10484778508Sblueswir1     bswap16s(&sym->st_shndx);
10584778508Sblueswir1 }
106b62f790cSWarner Losh 
bswap_note(struct elf_note * en)1070475f8faSWarner Losh static void bswap_note(struct elf_note *en)
1080475f8faSWarner Losh {
1090475f8faSWarner Losh     bswap32s(&en->n_namesz);
1100475f8faSWarner Losh     bswap32s(&en->n_descsz);
1110475f8faSWarner Losh     bswap32s(&en->n_type);
1120475f8faSWarner Losh }
1130475f8faSWarner Losh 
114b62f790cSWarner Losh #else /* ! BSWAP_NEEDED */
115b62f790cSWarner Losh 
bswap_ehdr(struct elfhdr * ehdr)116b62f790cSWarner Losh static void bswap_ehdr(struct elfhdr *ehdr) { }
bswap_phdr(struct elf_phdr * phdr,int phnum)117b62f790cSWarner Losh static void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
bswap_shdr(struct elf_shdr * shdr,int shnum)118b62f790cSWarner Losh static void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
bswap_sym(struct elf_sym * sym)119b62f790cSWarner Losh static void bswap_sym(struct elf_sym *sym) { }
bswap_note(struct elf_note * en)1200475f8faSWarner Losh static void bswap_note(struct elf_note *en) { }
121b62f790cSWarner Losh 
122b62f790cSWarner Losh #endif /* ! BSWAP_NEEDED */
12384778508Sblueswir1 
1240475f8faSWarner Losh #include "elfcore.c"
1250475f8faSWarner Losh 
12684778508Sblueswir1 /*
12784778508Sblueswir1  * 'copy_elf_strings()' copies argument/envelope strings from user
12884778508Sblueswir1  * memory to free pages in kernel mem. These are in a format ready
12984778508Sblueswir1  * to be put directly into the top of new user memory.
13084778508Sblueswir1  *
13184778508Sblueswir1  */
copy_elf_strings(int argc,char ** argv,void ** page,abi_ulong p)13284778508Sblueswir1 static abi_ulong copy_elf_strings(int argc, char **argv, void **page,
13384778508Sblueswir1                                   abi_ulong p)
13484778508Sblueswir1 {
13584778508Sblueswir1     char *tmp, *tmp1, *pag = NULL;
13684778508Sblueswir1     int len, offset = 0;
13784778508Sblueswir1 
13884778508Sblueswir1     if (!p) {
13984778508Sblueswir1         return 0;       /* bullet-proofing */
14084778508Sblueswir1     }
14184778508Sblueswir1     while (argc-- > 0) {
14284778508Sblueswir1         tmp = argv[argc];
14384778508Sblueswir1         if (!tmp) {
1449bb93180SPeter Maydell             fprintf(stderr, "VFS: argc is wrong");
14584778508Sblueswir1             exit(-1);
14684778508Sblueswir1         }
14784778508Sblueswir1         tmp1 = tmp;
1480456a177SWarner Losh         while (*tmp++) {
1490456a177SWarner Losh             continue;
1500456a177SWarner Losh         }
15184778508Sblueswir1         len = tmp - tmp1;
15284778508Sblueswir1         if (p < len) {  /* this shouldn't happen - 128kB */
15384778508Sblueswir1             return 0;
15484778508Sblueswir1         }
15584778508Sblueswir1         while (len) {
15684778508Sblueswir1             --p; --tmp; --len;
15784778508Sblueswir1             if (--offset < 0) {
15884778508Sblueswir1                 offset = p % TARGET_PAGE_SIZE;
1593d558330SMarkus Armbruster                 pag = page[p / TARGET_PAGE_SIZE];
16084778508Sblueswir1                 if (!pag) {
161c580dee4SStefan Weil                     pag = g_try_malloc0(TARGET_PAGE_SIZE);
16284778508Sblueswir1                     page[p / TARGET_PAGE_SIZE] = pag;
1630456a177SWarner Losh                     if (!pag) {
16484778508Sblueswir1                         return 0;
16584778508Sblueswir1                     }
16684778508Sblueswir1                 }
1670456a177SWarner Losh             }
16884778508Sblueswir1             if (len == 0 || offset == 0) {
16984778508Sblueswir1                 *(pag + offset) = *tmp;
1700456a177SWarner Losh             } else {
17184778508Sblueswir1               int bytes_to_copy = (len > offset) ? offset : len;
17284778508Sblueswir1               tmp -= bytes_to_copy;
17384778508Sblueswir1               p -= bytes_to_copy;
17484778508Sblueswir1               offset -= bytes_to_copy;
17584778508Sblueswir1               len -= bytes_to_copy;
17684778508Sblueswir1               memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
17784778508Sblueswir1             }
17884778508Sblueswir1         }
17984778508Sblueswir1     }
18084778508Sblueswir1     return p;
18184778508Sblueswir1 }
18284778508Sblueswir1 
setup_arg_pages(struct bsd_binprm * bprm,struct image_info * info,abi_ulong * stackp,abi_ulong * stringp)18398b34d35SWarner Losh static void setup_arg_pages(struct bsd_binprm *bprm, struct image_info *info,
18498b34d35SWarner Losh                             abi_ulong *stackp, abi_ulong *stringp)
18584778508Sblueswir1 {
18698b34d35SWarner Losh     abi_ulong stack_base, size;
18798b34d35SWarner Losh     abi_long addr;
18884778508Sblueswir1 
1890456a177SWarner Losh     /*
1900456a177SWarner Losh      * Create enough stack to hold everything.  If we don't use it for args,
1910456a177SWarner Losh      * we'll use it for something else...
19284778508Sblueswir1      */
193312a0b1cSWarner Losh     size = target_dflssiz;
19498b34d35SWarner Losh     stack_base = TARGET_USRSTACK - size;
1950456a177SWarner Losh     addr = target_mmap(stack_base , size + qemu_host_page_size,
1960456a177SWarner Losh             PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
19798b34d35SWarner Losh     if (addr == -1) {
19884778508Sblueswir1         perror("stk mmap");
19984778508Sblueswir1         exit(-1);
20084778508Sblueswir1     }
20184778508Sblueswir1     /* we reserve one extra page at the top of the stack as guard */
20298b34d35SWarner Losh     target_mprotect(addr + size, qemu_host_page_size, PROT_NONE);
20384778508Sblueswir1 
20498b34d35SWarner Losh     target_stksiz = size;
20598b34d35SWarner Losh     target_stkbas = addr;
20684778508Sblueswir1 
20798b34d35SWarner Losh     if (setup_initial_stack(bprm, stackp, stringp) != 0) {
20898b34d35SWarner Losh         perror("stk setup");
20998b34d35SWarner Losh         exit(-1);
21084778508Sblueswir1     }
21184778508Sblueswir1 }
21284778508Sblueswir1 
set_brk(abi_ulong start,abi_ulong end)21384778508Sblueswir1 static void set_brk(abi_ulong start, abi_ulong end)
21484778508Sblueswir1 {
21584778508Sblueswir1     /* page-align the start and end addresses... */
21684778508Sblueswir1     start = HOST_PAGE_ALIGN(start);
21784778508Sblueswir1     end = HOST_PAGE_ALIGN(end);
2180456a177SWarner Losh     if (end <= start) {
21984778508Sblueswir1         return;
2200456a177SWarner Losh     }
2210456a177SWarner Losh     if (target_mmap(start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC,
22284778508Sblueswir1         MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
22384778508Sblueswir1         perror("cannot mmap brk");
22484778508Sblueswir1         exit(-1);
22584778508Sblueswir1     }
22684778508Sblueswir1 }
22784778508Sblueswir1 
22884778508Sblueswir1 
2290456a177SWarner Losh /*
2300456a177SWarner Losh  * We need to explicitly zero any fractional pages after the data
2310456a177SWarner Losh  * section (i.e. bss).  This would contain the junk from the file that
2320456a177SWarner Losh  * should not be in memory.
2330456a177SWarner Losh  */
padzero(abi_ulong elf_bss,abi_ulong last_bss)23484778508Sblueswir1 static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
23584778508Sblueswir1 {
23684778508Sblueswir1     abi_ulong nbyte;
23784778508Sblueswir1 
2380456a177SWarner Losh     if (elf_bss >= last_bss) {
23984778508Sblueswir1         return;
2400456a177SWarner Losh     }
24184778508Sblueswir1 
2420456a177SWarner Losh     /*
2430456a177SWarner Losh      * XXX: this is really a hack : if the real host page size is
2440456a177SWarner Losh      * smaller than the target page size, some pages after the end
2450456a177SWarner Losh      * of the file may not be mapped. A better fix would be to
2460456a177SWarner Losh      * patch target_mmap(), but it is more complicated as the file
2470456a177SWarner Losh      * size must be known.
2480456a177SWarner Losh      */
2498e3b0cbbSMarc-André Lureau     if (qemu_real_host_page_size() < qemu_host_page_size) {
25084778508Sblueswir1         abi_ulong end_addr, end_addr1;
2510c2d70c4SPaolo Bonzini         end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss);
25284778508Sblueswir1         end_addr = HOST_PAGE_ALIGN(elf_bss);
25384778508Sblueswir1         if (end_addr1 < end_addr) {
2543e8f1628SRichard Henderson             mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1,
25584778508Sblueswir1                  PROT_READ | PROT_WRITE | PROT_EXEC,
25684778508Sblueswir1                  MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
25784778508Sblueswir1         }
25884778508Sblueswir1     }
25984778508Sblueswir1 
26084778508Sblueswir1     nbyte = elf_bss & (qemu_host_page_size - 1);
26184778508Sblueswir1     if (nbyte) {
26284778508Sblueswir1         nbyte = qemu_host_page_size - nbyte;
26384778508Sblueswir1         do {
26484778508Sblueswir1             /* FIXME - what to do if put_user() fails? */
26584778508Sblueswir1             put_user_u8(0, elf_bss);
26684778508Sblueswir1             elf_bss++;
26784778508Sblueswir1         } while (--nbyte);
26884778508Sblueswir1     }
26984778508Sblueswir1 }
27084778508Sblueswir1 
load_elf_interp(struct elfhdr * interp_elf_ex,int interpreter_fd,abi_ulong * interp_load_addr)27184778508Sblueswir1 static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex,
27284778508Sblueswir1                                  int interpreter_fd,
27384778508Sblueswir1                                  abi_ulong *interp_load_addr)
27484778508Sblueswir1 {
27584778508Sblueswir1     struct elf_phdr *elf_phdata  =  NULL;
276c09f12feSWarner Losh     abi_ulong rbase;
27784778508Sblueswir1     int retval;
278c09f12feSWarner Losh     abi_ulong baddr, error;
27984778508Sblueswir1 
28084778508Sblueswir1     error = 0;
28184778508Sblueswir1 
28284778508Sblueswir1     bswap_ehdr(interp_elf_ex);
28384778508Sblueswir1     /* First of all, some simple consistency checks */
2840456a177SWarner Losh     if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) ||
28584778508Sblueswir1           !elf_check_arch(interp_elf_ex->e_machine)) {
28684778508Sblueswir1         return ~((abi_ulong)0UL);
28784778508Sblueswir1     }
28884778508Sblueswir1 
28984778508Sblueswir1 
29084778508Sblueswir1     /* Now read in all of the header information */
2910456a177SWarner Losh     if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) {
29284778508Sblueswir1         return ~(abi_ulong)0UL;
2930456a177SWarner Losh     }
29484778508Sblueswir1 
2950456a177SWarner Losh     elf_phdata =  (struct elf_phdr *) malloc(sizeof(struct elf_phdr) *
2960456a177SWarner Losh             interp_elf_ex->e_phnum);
29784778508Sblueswir1 
2980456a177SWarner Losh     if (!elf_phdata) {
29984778508Sblueswir1         return ~((abi_ulong)0UL);
3000456a177SWarner Losh     }
30184778508Sblueswir1 
30284778508Sblueswir1     /*
30384778508Sblueswir1      * If the size of this structure has changed, then punt, since
30484778508Sblueswir1      * we will be doing the wrong thing.
30584778508Sblueswir1      */
30684778508Sblueswir1     if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
30784778508Sblueswir1         free(elf_phdata);
30884778508Sblueswir1         return ~((abi_ulong)0UL);
30984778508Sblueswir1     }
31084778508Sblueswir1 
31184778508Sblueswir1     retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
31284778508Sblueswir1     if (retval >= 0) {
3130456a177SWarner Losh         retval = read(interpreter_fd, (char *) elf_phdata,
31484778508Sblueswir1                 sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
31584778508Sblueswir1     }
31684778508Sblueswir1     if (retval < 0) {
31784778508Sblueswir1         perror("load_elf_interp");
31884778508Sblueswir1         exit(-1);
31984778508Sblueswir1         free(elf_phdata);
32084778508Sblueswir1         return retval;
32184778508Sblueswir1     }
322b62f790cSWarner Losh     bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
32384778508Sblueswir1 
324c09f12feSWarner Losh     rbase = 0;
32584778508Sblueswir1     if (interp_elf_ex->e_type == ET_DYN) {
3260456a177SWarner Losh         /*
3270456a177SWarner Losh          * In order to avoid hardcoding the interpreter load
3280456a177SWarner Losh          * address in qemu, we allocate a big enough memory zone.
3290456a177SWarner Losh          */
330c09f12feSWarner Losh         rbase = target_mmap(0, INTERP_MAP_SIZE, PROT_NONE,
3310456a177SWarner Losh                 MAP_PRIVATE | MAP_ANON, -1, 0);
332c09f12feSWarner Losh         if (rbase == -1) {
33384778508Sblueswir1             perror("mmap");
33484778508Sblueswir1             exit(-1);
33584778508Sblueswir1         }
33684778508Sblueswir1     }
33784778508Sblueswir1 
338c09f12feSWarner Losh     error = load_elf_sections(interp_elf_ex, elf_phdata, interpreter_fd, rbase,
339c09f12feSWarner Losh         &baddr);
340c09f12feSWarner Losh     if (error != 0) {
341c09f12feSWarner Losh         perror("load_elf_sections");
342c09f12feSWarner Losh         exit(-1);
34384778508Sblueswir1     }
34484778508Sblueswir1 
34584778508Sblueswir1     /* Now use mmap to map the library into memory. */
34684778508Sblueswir1     close(interpreter_fd);
34784778508Sblueswir1     free(elf_phdata);
34884778508Sblueswir1 
349c09f12feSWarner Losh     *interp_load_addr = baddr;
350c09f12feSWarner Losh     return ((abi_ulong) interp_elf_ex->e_entry) + rbase;
35184778508Sblueswir1 }
35284778508Sblueswir1 
symfind(const void * s0,const void * s1)35384778508Sblueswir1 static int symfind(const void *s0, const void *s1)
35484778508Sblueswir1 {
35584778508Sblueswir1     struct elf_sym *sym = (struct elf_sym *)s1;
356b6235a75SRichard Henderson     __typeof(sym->st_value) addr = *(uint64_t *)s0;
35784778508Sblueswir1     int result = 0;
358b6235a75SRichard Henderson 
359c7c530cdSStefan Weil     if (addr < sym->st_value) {
36084778508Sblueswir1         result = -1;
361c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
36284778508Sblueswir1         result = 1;
36384778508Sblueswir1     }
36484778508Sblueswir1     return result;
36584778508Sblueswir1 }
36684778508Sblueswir1 
lookup_symbolxx(struct syminfo * s,uint64_t orig_addr)367b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
36884778508Sblueswir1 {
36984778508Sblueswir1 #if ELF_CLASS == ELFCLASS32
37084778508Sblueswir1     struct elf_sym *syms = s->disas_symtab.elf32;
37184778508Sblueswir1 #else
37284778508Sblueswir1     struct elf_sym *syms = s->disas_symtab.elf64;
37384778508Sblueswir1 #endif
37484778508Sblueswir1 
3750456a177SWarner Losh     /* binary search */
37684778508Sblueswir1     struct elf_sym *sym;
37784778508Sblueswir1 
378c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
3797cba04f6SBlue Swirl     if (sym != NULL) {
38084778508Sblueswir1         return s->disas_strtab + sym->st_name;
38184778508Sblueswir1     }
38284778508Sblueswir1 
38384778508Sblueswir1     return "";
38484778508Sblueswir1 }
38584778508Sblueswir1 
386159fb790SPhilippe Mathieu-Daudé /* FIXME: This should use elf_ops.h.inc  */
symcmp(const void * s0,const void * s1)38784778508Sblueswir1 static int symcmp(const void *s0, const void *s1)
38884778508Sblueswir1 {
38984778508Sblueswir1     struct elf_sym *sym0 = (struct elf_sym *)s0;
39084778508Sblueswir1     struct elf_sym *sym1 = (struct elf_sym *)s1;
3910456a177SWarner Losh     return (sym0->st_value < sym1->st_value) ? -1 :
3920456a177SWarner Losh         ((sym0->st_value > sym1->st_value) ? 1 : 0);
39384778508Sblueswir1 }
39484778508Sblueswir1 
39584778508Sblueswir1 /* Best attempt to load symbols from this ELF object. */
load_symbols(struct elfhdr * hdr,int fd)39684778508Sblueswir1 static void load_symbols(struct elfhdr *hdr, int fd)
39784778508Sblueswir1 {
39884778508Sblueswir1     unsigned int i, nsyms;
39984778508Sblueswir1     struct elf_shdr sechdr, symtab, strtab;
40084778508Sblueswir1     char *strings;
40184778508Sblueswir1     struct syminfo *s;
40229718712SStefan Weil     struct elf_sym *syms, *new_syms;
40384778508Sblueswir1 
40484778508Sblueswir1     lseek(fd, hdr->e_shoff, SEEK_SET);
40584778508Sblueswir1     for (i = 0; i < hdr->e_shnum; i++) {
4060456a177SWarner Losh         if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) {
40784778508Sblueswir1             return;
4080456a177SWarner Losh         }
409b62f790cSWarner Losh         bswap_shdr(&sechdr, 1);
41084778508Sblueswir1         if (sechdr.sh_type == SHT_SYMTAB) {
41184778508Sblueswir1             symtab = sechdr;
4120456a177SWarner Losh             lseek(fd, hdr->e_shoff + sizeof(sechdr) * sechdr.sh_link,
4130456a177SWarner Losh                   SEEK_SET);
4140456a177SWarner Losh             if (read(fd, &strtab, sizeof(strtab)) != sizeof(strtab)) {
41584778508Sblueswir1                 return;
4160456a177SWarner Losh             }
417b62f790cSWarner Losh             bswap_shdr(&strtab, 1);
41884778508Sblueswir1             goto found;
41984778508Sblueswir1         }
42084778508Sblueswir1     }
42184778508Sblueswir1     return; /* Shouldn't happen... */
42284778508Sblueswir1 
42384778508Sblueswir1 found:
42484778508Sblueswir1     /* Now know where the strtab and symtab are.  Snarf them. */
42584778508Sblueswir1     s = malloc(sizeof(*s));
42684778508Sblueswir1     syms = malloc(symtab.sh_size);
42729718712SStefan Weil     if (!syms) {
42829718712SStefan Weil         free(s);
42984778508Sblueswir1         return;
43029718712SStefan Weil     }
43184778508Sblueswir1     s->disas_strtab = strings = malloc(strtab.sh_size);
43229718712SStefan Weil     if (!s->disas_strtab) {
43329718712SStefan Weil         free(s);
43429718712SStefan Weil         free(syms);
43584778508Sblueswir1         return;
43629718712SStefan Weil     }
43784778508Sblueswir1 
43884778508Sblueswir1     lseek(fd, symtab.sh_offset, SEEK_SET);
43929718712SStefan Weil     if (read(fd, syms, symtab.sh_size) != symtab.sh_size) {
44029718712SStefan Weil         free(s);
44129718712SStefan Weil         free(syms);
44229718712SStefan Weil         free(strings);
44384778508Sblueswir1         return;
44429718712SStefan Weil     }
44584778508Sblueswir1 
44684778508Sblueswir1     nsyms = symtab.sh_size / sizeof(struct elf_sym);
44784778508Sblueswir1 
44884778508Sblueswir1     i = 0;
44984778508Sblueswir1     while (i < nsyms) {
45084778508Sblueswir1         bswap_sym(syms + i);
4510456a177SWarner Losh         /* Throw away entries which we do not need. */
45284778508Sblueswir1         if (syms[i].st_shndx == SHN_UNDEF ||
45384778508Sblueswir1                 syms[i].st_shndx >= SHN_LORESERVE ||
45484778508Sblueswir1                 ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
45584778508Sblueswir1             nsyms--;
45684778508Sblueswir1             if (i < nsyms) {
45784778508Sblueswir1                 syms[i] = syms[nsyms];
45884778508Sblueswir1             }
45984778508Sblueswir1             continue;
46084778508Sblueswir1         }
461c09f12feSWarner Losh #if defined(TARGET_ARM) || defined(TARGET_MIPS)
462c09f12feSWarner Losh         /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
463c09f12feSWarner Losh         syms[i].st_value &= ~(target_ulong)1;
464c09f12feSWarner Losh #endif
46584778508Sblueswir1         i++;
46684778508Sblueswir1     }
46729718712SStefan Weil 
4680456a177SWarner Losh      /*
4690456a177SWarner Losh       * Attempt to free the storage associated with the local symbols
4700456a177SWarner Losh       * that we threw away.  Whether or not this has any effect on the
4710456a177SWarner Losh       * memory allocation depends on the malloc implementation and how
4720456a177SWarner Losh       * many symbols we managed to discard.
4730456a177SWarner Losh       */
47429718712SStefan Weil     new_syms = realloc(syms, nsyms * sizeof(*syms));
47529718712SStefan Weil     if (new_syms == NULL) {
47629718712SStefan Weil         free(s);
47729718712SStefan Weil         free(syms);
47829718712SStefan Weil         free(strings);
47929718712SStefan Weil         return;
48029718712SStefan Weil     }
48129718712SStefan Weil     syms = new_syms;
48284778508Sblueswir1 
48384778508Sblueswir1     qsort(syms, nsyms, sizeof(*syms), symcmp);
48484778508Sblueswir1 
48584778508Sblueswir1     lseek(fd, strtab.sh_offset, SEEK_SET);
48629718712SStefan Weil     if (read(fd, strings, strtab.sh_size) != strtab.sh_size) {
48729718712SStefan Weil         free(s);
48829718712SStefan Weil         free(syms);
48929718712SStefan Weil         free(strings);
49084778508Sblueswir1         return;
49129718712SStefan Weil     }
49284778508Sblueswir1     s->disas_num_syms = nsyms;
49384778508Sblueswir1 #if ELF_CLASS == ELFCLASS32
49484778508Sblueswir1     s->disas_symtab.elf32 = syms;
495032e51d7SBlue Swirl     s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
49684778508Sblueswir1 #else
49784778508Sblueswir1     s->disas_symtab.elf64 = syms;
498032e51d7SBlue Swirl     s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
49984778508Sblueswir1 #endif
50084778508Sblueswir1     s->next = syminfos;
50184778508Sblueswir1     syminfos = s;
50284778508Sblueswir1 }
50384778508Sblueswir1 
504c09f12feSWarner Losh /* Check the elf header and see if this a target elf binary. */
is_target_elf_binary(int fd)505c09f12feSWarner Losh int is_target_elf_binary(int fd)
506c09f12feSWarner Losh {
507c09f12feSWarner Losh     uint8_t buf[128];
508c09f12feSWarner Losh     struct elfhdr elf_ex;
509c09f12feSWarner Losh 
510c09f12feSWarner Losh     if (lseek(fd, 0L, SEEK_SET) < 0) {
511c09f12feSWarner Losh         return 0;
512c09f12feSWarner Losh     }
513c09f12feSWarner Losh     if (read(fd, buf, sizeof(buf)) < 0) {
514c09f12feSWarner Losh         return 0;
515c09f12feSWarner Losh     }
516c09f12feSWarner Losh 
517c09f12feSWarner Losh     elf_ex = *((struct elfhdr *)buf);
518c09f12feSWarner Losh     bswap_ehdr(&elf_ex);
519c09f12feSWarner Losh 
520c09f12feSWarner Losh     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
521c09f12feSWarner Losh         (!elf_check_arch(elf_ex.e_machine))) {
522c09f12feSWarner Losh         return 0;
523c09f12feSWarner Losh     } else {
524c09f12feSWarner Losh         return 1;
525c09f12feSWarner Losh     }
526c09f12feSWarner Losh }
527c09f12feSWarner Losh 
528c09f12feSWarner Losh static int
load_elf_sections(const struct elfhdr * hdr,struct elf_phdr * phdr,int fd,abi_ulong rbase,abi_ulong * baddrp)529c09f12feSWarner Losh load_elf_sections(const struct elfhdr *hdr, struct elf_phdr *phdr, int fd,
530c09f12feSWarner Losh     abi_ulong rbase, abi_ulong *baddrp)
531c09f12feSWarner Losh {
532c09f12feSWarner Losh     struct elf_phdr *elf_ppnt;
533c09f12feSWarner Losh     abi_ulong baddr;
534c09f12feSWarner Losh     int i;
535c09f12feSWarner Losh     bool first;
536c09f12feSWarner Losh 
537c09f12feSWarner Losh     /*
538c09f12feSWarner Losh      * Now we do a little grungy work by mmaping the ELF image into
539c09f12feSWarner Losh      * the correct location in memory.  At this point, we assume that
540c09f12feSWarner Losh      * the image should be loaded at fixed address, not at a variable
541c09f12feSWarner Losh      * address.
542c09f12feSWarner Losh      */
543c09f12feSWarner Losh     first = true;
544c09f12feSWarner Losh     for (i = 0, elf_ppnt = phdr; i < hdr->e_phnum; i++, elf_ppnt++) {
545c09f12feSWarner Losh         int elf_prot = 0;
546c09f12feSWarner Losh         abi_ulong error;
547c09f12feSWarner Losh 
548c09f12feSWarner Losh         /* XXX Skip memsz == 0. */
549c09f12feSWarner Losh         if (elf_ppnt->p_type != PT_LOAD) {
550c09f12feSWarner Losh             continue;
551c09f12feSWarner Losh         }
552c09f12feSWarner Losh 
553c09f12feSWarner Losh         if (elf_ppnt->p_flags & PF_R) {
554c09f12feSWarner Losh             elf_prot |= PROT_READ;
555c09f12feSWarner Losh         }
556c09f12feSWarner Losh         if (elf_ppnt->p_flags & PF_W) {
557c09f12feSWarner Losh             elf_prot |= PROT_WRITE;
558c09f12feSWarner Losh         }
559c09f12feSWarner Losh         if (elf_ppnt->p_flags & PF_X) {
560c09f12feSWarner Losh             elf_prot |= PROT_EXEC;
561c09f12feSWarner Losh         }
562c09f12feSWarner Losh 
563c09f12feSWarner Losh         error = target_mmap(TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr),
564c09f12feSWarner Losh                             (elf_ppnt->p_filesz +
565c09f12feSWarner Losh                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
566c09f12feSWarner Losh                             elf_prot,
567c09f12feSWarner Losh                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
568c09f12feSWarner Losh                             fd,
569c09f12feSWarner Losh                             (elf_ppnt->p_offset -
570c09f12feSWarner Losh                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
571c09f12feSWarner Losh         if (error == -1) {
572c09f12feSWarner Losh             perror("mmap");
573c09f12feSWarner Losh             exit(-1);
574c09f12feSWarner Losh         } else if (elf_ppnt->p_memsz != elf_ppnt->p_filesz) {
575c09f12feSWarner Losh             abi_ulong start_bss, end_bss;
576c09f12feSWarner Losh 
577c09f12feSWarner Losh             start_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
578c09f12feSWarner Losh             end_bss = rbase + elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
579c09f12feSWarner Losh 
580c09f12feSWarner Losh             /*
581c09f12feSWarner Losh              * Calling set_brk effectively mmaps the pages that we need for the
582c09f12feSWarner Losh              * bss and break sections.
583c09f12feSWarner Losh              */
584c09f12feSWarner Losh             set_brk(start_bss, end_bss);
585c09f12feSWarner Losh             padzero(start_bss, end_bss);
586c09f12feSWarner Losh         }
587c09f12feSWarner Losh 
588c09f12feSWarner Losh         if (first) {
589c09f12feSWarner Losh             baddr = TARGET_ELF_PAGESTART(rbase + elf_ppnt->p_vaddr);
590c09f12feSWarner Losh             first = false;
591c09f12feSWarner Losh         }
592c09f12feSWarner Losh     }
593c09f12feSWarner Losh 
594c09f12feSWarner Losh     if (baddrp != NULL) {
595c09f12feSWarner Losh         *baddrp = baddr;
596c09f12feSWarner Losh     }
597c09f12feSWarner Losh     return 0;
598c09f12feSWarner Losh }
599c09f12feSWarner Losh 
load_elf_binary(struct bsd_binprm * bprm,struct target_pt_regs * regs,struct image_info * info)600afcbcff8SWarner Losh int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
60184778508Sblueswir1                     struct image_info *info)
60284778508Sblueswir1 {
60384778508Sblueswir1     struct elfhdr elf_ex;
60484778508Sblueswir1     struct elfhdr interp_elf_ex;
60584778508Sblueswir1     int interpreter_fd = -1; /* avoid warning */
606c09f12feSWarner Losh     abi_ulong load_addr;
60784778508Sblueswir1     int i;
60884778508Sblueswir1     struct elf_phdr *elf_ppnt;
60984778508Sblueswir1     struct elf_phdr *elf_phdata;
610c09f12feSWarner Losh     abi_ulong elf_brk;
611c09f12feSWarner Losh     int error, retval;
61284778508Sblueswir1     char *elf_interpreter;
613c09f12feSWarner Losh     abi_ulong baddr, elf_entry, et_dyn_addr, interp_load_addr = 0;
61484778508Sblueswir1     abi_ulong reloc_func_desc = 0;
61584778508Sblueswir1 
61684778508Sblueswir1     load_addr = 0;
61784778508Sblueswir1     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
61884778508Sblueswir1     bswap_ehdr(&elf_ex);
61984778508Sblueswir1 
62084778508Sblueswir1     /* First of all, some simple consistency checks */
62184778508Sblueswir1     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
62284778508Sblueswir1         (!elf_check_arch(elf_ex.e_machine))) {
62384778508Sblueswir1             return -ENOEXEC;
62484778508Sblueswir1     }
62584778508Sblueswir1 
62684778508Sblueswir1     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
62784778508Sblueswir1     bprm->p = copy_elf_strings(bprm->envc, bprm->envp, bprm->page, bprm->p);
62884778508Sblueswir1     bprm->p = copy_elf_strings(bprm->argc, bprm->argv, bprm->page, bprm->p);
62984778508Sblueswir1     if (!bprm->p) {
63084778508Sblueswir1         retval = -E2BIG;
63184778508Sblueswir1     }
63284778508Sblueswir1 
63384778508Sblueswir1     /* Now read in all of the header information */
63484778508Sblueswir1     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize * elf_ex.e_phnum);
63584778508Sblueswir1     if (elf_phdata == NULL) {
63684778508Sblueswir1         return -ENOMEM;
63784778508Sblueswir1     }
63884778508Sblueswir1 
63984778508Sblueswir1     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
64084778508Sblueswir1     if (retval > 0) {
64184778508Sblueswir1         retval = read(bprm->fd, (char *)elf_phdata,
64284778508Sblueswir1                                 elf_ex.e_phentsize * elf_ex.e_phnum);
64384778508Sblueswir1     }
64484778508Sblueswir1 
64584778508Sblueswir1     if (retval < 0) {
64684778508Sblueswir1         perror("load_elf_binary");
64784778508Sblueswir1         exit(-1);
64884778508Sblueswir1         free(elf_phdata);
64984778508Sblueswir1         return -errno;
65084778508Sblueswir1     }
65184778508Sblueswir1 
652b62f790cSWarner Losh     bswap_phdr(elf_phdata, elf_ex.e_phnum);
65384778508Sblueswir1     elf_ppnt = elf_phdata;
65484778508Sblueswir1 
65584778508Sblueswir1     elf_brk = 0;
65684778508Sblueswir1 
65784778508Sblueswir1 
65884778508Sblueswir1     elf_interpreter = NULL;
65984778508Sblueswir1     for (i = 0; i < elf_ex.e_phnum; i++) {
66084778508Sblueswir1         if (elf_ppnt->p_type == PT_INTERP) {
6610456a177SWarner Losh             if (elf_interpreter != NULL) {
66284778508Sblueswir1                 free(elf_phdata);
66384778508Sblueswir1                 free(elf_interpreter);
66484778508Sblueswir1                 close(bprm->fd);
66584778508Sblueswir1                 return -EINVAL;
66684778508Sblueswir1             }
66784778508Sblueswir1 
66884778508Sblueswir1             elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
66984778508Sblueswir1             if (elf_interpreter == NULL) {
67084778508Sblueswir1                 free(elf_phdata);
67184778508Sblueswir1                 close(bprm->fd);
67284778508Sblueswir1                 return -ENOMEM;
67384778508Sblueswir1             }
67484778508Sblueswir1 
67584778508Sblueswir1             retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
67684778508Sblueswir1             if (retval >= 0) {
67784778508Sblueswir1                 retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
67884778508Sblueswir1             }
67984778508Sblueswir1             if (retval < 0) {
68084778508Sblueswir1                 perror("load_elf_binary2");
68184778508Sblueswir1                 exit(-1);
68284778508Sblueswir1             }
68384778508Sblueswir1 
68484778508Sblueswir1             if (retval >= 0) {
68584778508Sblueswir1                 retval = open(path(elf_interpreter), O_RDONLY);
68684778508Sblueswir1                 if (retval >= 0) {
68784778508Sblueswir1                     interpreter_fd = retval;
6880456a177SWarner Losh                 } else {
68984778508Sblueswir1                     perror(elf_interpreter);
69084778508Sblueswir1                     exit(-1);
69184778508Sblueswir1                     /* retval = -errno; */
69284778508Sblueswir1                 }
69384778508Sblueswir1             }
69484778508Sblueswir1 
69584778508Sblueswir1             if (retval >= 0) {
69684778508Sblueswir1                 retval = lseek(interpreter_fd, 0, SEEK_SET);
69784778508Sblueswir1                 if (retval >= 0) {
69884778508Sblueswir1                     retval = read(interpreter_fd, bprm->buf, 128);
69984778508Sblueswir1                 }
70084778508Sblueswir1             }
70184778508Sblueswir1             if (retval >= 0) {
7020456a177SWarner Losh                 interp_elf_ex = *((struct elfhdr *) bprm->buf);
70384778508Sblueswir1             }
70484778508Sblueswir1             if (retval < 0) {
70584778508Sblueswir1                 perror("load_elf_binary3");
70684778508Sblueswir1                 exit(-1);
70784778508Sblueswir1                 free(elf_phdata);
70884778508Sblueswir1                 free(elf_interpreter);
70984778508Sblueswir1                 close(bprm->fd);
71084778508Sblueswir1                 return retval;
71184778508Sblueswir1             }
71284778508Sblueswir1         }
71384778508Sblueswir1         elf_ppnt++;
71484778508Sblueswir1     }
71584778508Sblueswir1 
71684778508Sblueswir1     /* Some simple consistency checks for the interpreter */
71784778508Sblueswir1     if (elf_interpreter) {
71884778508Sblueswir1         if (interp_elf_ex.e_ident[0] != 0x7f ||
719fff2a02fSChristoph Egger             strncmp((char *)&interp_elf_ex.e_ident[1], "ELF", 3) != 0) {
72084778508Sblueswir1             free(elf_interpreter);
72184778508Sblueswir1             free(elf_phdata);
72284778508Sblueswir1             close(bprm->fd);
72384778508Sblueswir1             return -ELIBBAD;
72484778508Sblueswir1         }
72584778508Sblueswir1     }
72684778508Sblueswir1 
7270456a177SWarner Losh     /*
7280456a177SWarner Losh      * OK, we are done with that, now set up the arg stuff, and then start this
7290456a177SWarner Losh      * sucker up
7300456a177SWarner Losh      */
73184778508Sblueswir1     if (!bprm->p) {
73284778508Sblueswir1         free(elf_interpreter);
73384778508Sblueswir1         free(elf_phdata);
73484778508Sblueswir1         close(bprm->fd);
73584778508Sblueswir1         return -E2BIG;
73684778508Sblueswir1     }
73784778508Sblueswir1 
73884778508Sblueswir1     /* OK, This is the point of no return */
73984778508Sblueswir1     info->end_data = 0;
74084778508Sblueswir1     info->end_code = 0;
74184778508Sblueswir1     elf_entry = (abi_ulong) elf_ex.e_entry;
74284778508Sblueswir1 
743c09f12feSWarner Losh     /* XXX Join this with PT_INTERP search? */
744c09f12feSWarner Losh     baddr = 0;
745c09f12feSWarner Losh     for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
746c09f12feSWarner Losh         if (elf_ppnt->p_type != PT_LOAD) {
747c09f12feSWarner Losh             continue;
748c09f12feSWarner Losh         }
749c09f12feSWarner Losh         baddr = elf_ppnt->p_vaddr;
750c09f12feSWarner Losh         break;
751c09f12feSWarner Losh     }
752c09f12feSWarner Losh 
753c09f12feSWarner Losh     et_dyn_addr = 0;
754c09f12feSWarner Losh     if (elf_ex.e_type == ET_DYN && baddr == 0) {
755c09f12feSWarner Losh         et_dyn_addr = ELF_ET_DYN_LOAD_ADDR;
756c09f12feSWarner Losh     }
757c09f12feSWarner Losh 
758c09f12feSWarner Losh     /*
759c09f12feSWarner Losh      * Do this so that we can load the interpreter, if need be.  We will
760c09f12feSWarner Losh      * change some of these later
761c09f12feSWarner Losh      */
76284778508Sblueswir1     info->rss = 0;
76398b34d35SWarner Losh     setup_arg_pages(bprm, info, &bprm->p, &bprm->stringp);
76484778508Sblueswir1     info->start_stack = bprm->p;
76584778508Sblueswir1 
766c09f12feSWarner Losh     info->elf_flags = elf_ex.e_flags;
76784778508Sblueswir1 
768c09f12feSWarner Losh     error = load_elf_sections(&elf_ex, elf_phdata, bprm->fd, et_dyn_addr,
769c09f12feSWarner Losh         &load_addr);
77084778508Sblueswir1     for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
771c09f12feSWarner Losh         if (elf_ppnt->p_type != PT_LOAD) {
77284778508Sblueswir1             continue;
773c09f12feSWarner Losh         }
774c09f12feSWarner Losh         if (elf_ppnt->p_memsz > elf_ppnt->p_filesz)
775c09f12feSWarner Losh             elf_brk = MAX(elf_brk, et_dyn_addr + elf_ppnt->p_vaddr +
776c09f12feSWarner Losh                 elf_ppnt->p_memsz);
777c09f12feSWarner Losh     }
778c09f12feSWarner Losh     if (error != 0) {
779c09f12feSWarner Losh         perror("load_elf_sections");
78084778508Sblueswir1         exit(-1);
78184778508Sblueswir1     }
78284778508Sblueswir1 
78384778508Sblueswir1     if (elf_interpreter) {
78484778508Sblueswir1         elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
78584778508Sblueswir1                                     &interp_load_addr);
78684778508Sblueswir1         reloc_func_desc = interp_load_addr;
78784778508Sblueswir1 
78884778508Sblueswir1         close(interpreter_fd);
78984778508Sblueswir1         free(elf_interpreter);
79084778508Sblueswir1 
79184778508Sblueswir1         if (elf_entry == ~((abi_ulong)0UL)) {
79284778508Sblueswir1             printf("Unable to load interpreter\n");
79384778508Sblueswir1             free(elf_phdata);
79484778508Sblueswir1             exit(-1);
79584778508Sblueswir1             return 0;
79684778508Sblueswir1         }
797c09f12feSWarner Losh     } else {
798c09f12feSWarner Losh         interp_load_addr = et_dyn_addr;
799c09f12feSWarner Losh         elf_entry += interp_load_addr;
80084778508Sblueswir1     }
80184778508Sblueswir1 
80284778508Sblueswir1     free(elf_phdata);
80384778508Sblueswir1 
8040456a177SWarner Losh     if (qemu_log_enabled()) {
80584778508Sblueswir1         load_symbols(&elf_ex, bprm->fd);
8060456a177SWarner Losh     }
80784778508Sblueswir1 
808ffa03665SWarner Losh     close(bprm->fd);
80984778508Sblueswir1 
81098b34d35SWarner Losh     bprm->p = target_create_elf_tables(bprm->p, bprm->argc, bprm->envc,
81198b34d35SWarner Losh                                        bprm->stringp, &elf_ex, load_addr,
812c09f12feSWarner Losh                                        et_dyn_addr, interp_load_addr, info);
81384778508Sblueswir1     info->load_addr = reloc_func_desc;
8144436e2ffSRichard Henderson     info->brk = elf_brk;
81584778508Sblueswir1     info->start_stack = bprm->p;
816c09f12feSWarner Losh     info->load_bias = 0;
81784778508Sblueswir1 
81884778508Sblueswir1     info->entry = elf_entry;
81984778508Sblueswir1 
8200475f8faSWarner Losh #ifdef USE_ELF_CORE_DUMP
8210475f8faSWarner Losh     bprm->core_dump = &elf_core_dump;
8220475f8faSWarner Losh #else
8230475f8faSWarner Losh     bprm->core_dump = NULL;
8240475f8faSWarner Losh #endif
8250475f8faSWarner Losh 
82684778508Sblueswir1     return 0;
82784778508Sblueswir1 }
82884778508Sblueswir1 
do_init_thread(struct target_pt_regs * regs,struct image_info * infop)82984778508Sblueswir1 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
83084778508Sblueswir1 {
831a8fe6d5dSWarner Losh 
832a8fe6d5dSWarner Losh     target_thread_init(regs, infop);
83384778508Sblueswir1 }
834