131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */ 231e31b8aSbellard 331e31b8aSbellard #include <stdio.h> 431e31b8aSbellard #include <sys/types.h> 531e31b8aSbellard #include <fcntl.h> 631e31b8aSbellard #include <sys/stat.h> 731e31b8aSbellard #include <errno.h> 831e31b8aSbellard #include <unistd.h> 931e31b8aSbellard #include <sys/mman.h> 1031e31b8aSbellard #include <stdlib.h> 1131e31b8aSbellard #include <string.h> 1231e31b8aSbellard 133ef693a0Sbellard #include "qemu.h" 14689f936fSbellard #include "disas.h" 1531e31b8aSbellard 1630ac07d4Sbellard #ifdef TARGET_I386 1730ac07d4Sbellard 1830ac07d4Sbellard #define ELF_START_MMAP 0x80000000 1930ac07d4Sbellard 2030ac07d4Sbellard /* 2130ac07d4Sbellard * This is used to ensure we don't load something for the wrong architecture. 2230ac07d4Sbellard */ 2330ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) 2430ac07d4Sbellard 2530ac07d4Sbellard /* 2630ac07d4Sbellard * These are used to set parameters in the core dumps. 2730ac07d4Sbellard */ 2830ac07d4Sbellard #define ELF_CLASS ELFCLASS32 2930ac07d4Sbellard #define ELF_DATA ELFDATA2LSB 3030ac07d4Sbellard #define ELF_ARCH EM_386 3130ac07d4Sbellard 3230ac07d4Sbellard /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program 3330ac07d4Sbellard starts %edx contains a pointer to a function which might be 3430ac07d4Sbellard registered using `atexit'. This provides a mean for the 3530ac07d4Sbellard dynamic linker to call DT_FINI functions for shared libraries 3630ac07d4Sbellard that have been loaded before the code runs. 3730ac07d4Sbellard 3830ac07d4Sbellard A value of 0 tells we have no such handler. */ 3930ac07d4Sbellard #define ELF_PLAT_INIT(_r) _r->edx = 0 4030ac07d4Sbellard 41b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 42b346ff46Sbellard { 43b346ff46Sbellard regs->esp = infop->start_stack; 44b346ff46Sbellard regs->eip = infop->entry; 45b346ff46Sbellard } 46b346ff46Sbellard 47b346ff46Sbellard #define USE_ELF_CORE_DUMP 48b346ff46Sbellard #define ELF_EXEC_PAGESIZE 4096 49b346ff46Sbellard 50b346ff46Sbellard #endif 51b346ff46Sbellard 52b346ff46Sbellard #ifdef TARGET_ARM 53b346ff46Sbellard 54b346ff46Sbellard #define ELF_START_MMAP 0x80000000 55b346ff46Sbellard 56b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM ) 57b346ff46Sbellard 58b346ff46Sbellard #define ELF_CLASS ELFCLASS32 59b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN 60b346ff46Sbellard #define ELF_DATA ELFDATA2MSB 61b346ff46Sbellard #else 62b346ff46Sbellard #define ELF_DATA ELFDATA2LSB 63b346ff46Sbellard #endif 64b346ff46Sbellard #define ELF_ARCH EM_ARM 65b346ff46Sbellard 66b346ff46Sbellard #define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0 67b346ff46Sbellard 68b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 69b346ff46Sbellard { 70b346ff46Sbellard target_long *stack = (void *)infop->start_stack; 71b346ff46Sbellard memset(regs, 0, sizeof(*regs)); 72b346ff46Sbellard regs->ARM_cpsr = 0x10; 73b346ff46Sbellard regs->ARM_pc = infop->entry; 74b346ff46Sbellard regs->ARM_sp = infop->start_stack; 75b346ff46Sbellard regs->ARM_r2 = tswapl(stack[2]); /* envp */ 76b346ff46Sbellard regs->ARM_r1 = tswapl(stack[1]); /* argv */ 77a1516e92Sbellard /* XXX: it seems that r0 is zeroed after ! */ 78a1516e92Sbellard // regs->ARM_r0 = tswapl(stack[0]); /* argc */ 79b346ff46Sbellard } 80b346ff46Sbellard 8130ac07d4Sbellard #define USE_ELF_CORE_DUMP 8230ac07d4Sbellard #define ELF_EXEC_PAGESIZE 4096 8330ac07d4Sbellard 8430ac07d4Sbellard #endif 8530ac07d4Sbellard 86853d6f7aSbellard #ifdef TARGET_SPARC 87853d6f7aSbellard 88853d6f7aSbellard #define ELF_START_MMAP 0x80000000 89853d6f7aSbellard 90853d6f7aSbellard #define elf_check_arch(x) ( (x) == EM_SPARC ) 91853d6f7aSbellard 92853d6f7aSbellard #define ELF_CLASS ELFCLASS32 93853d6f7aSbellard #define ELF_DATA ELFDATA2MSB 94853d6f7aSbellard #define ELF_ARCH EM_SPARC 95853d6f7aSbellard 96853d6f7aSbellard /*XXX*/ 97853d6f7aSbellard #define ELF_PLAT_INIT(_r) 98853d6f7aSbellard 99853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) 100853d6f7aSbellard { 101f5155289Sbellard regs->psr = 0; 102f5155289Sbellard regs->pc = infop->entry; 103f5155289Sbellard regs->npc = regs->pc + 4; 104f5155289Sbellard regs->y = 0; 105f5155289Sbellard regs->u_regs[14] = infop->start_stack - 16 * 4; 106853d6f7aSbellard } 107853d6f7aSbellard 108853d6f7aSbellard #endif 109853d6f7aSbellard 11067867308Sbellard #ifdef TARGET_PPC 11167867308Sbellard 11267867308Sbellard #define ELF_START_MMAP 0x80000000 11367867308Sbellard 11467867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC ) 11567867308Sbellard 11667867308Sbellard #define ELF_CLASS ELFCLASS32 11767867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN 11867867308Sbellard #define ELF_DATA ELFDATA2MSB 11967867308Sbellard #else 12067867308Sbellard #define ELF_DATA ELFDATA2LSB 12167867308Sbellard #endif 12267867308Sbellard #define ELF_ARCH EM_PPC 12367867308Sbellard 12467867308Sbellard /* Note that isn't exactly what regular kernel does 12567867308Sbellard * but this is what the ABI wants and is needed to allow 12667867308Sbellard * execution of PPC BSD programs. 12767867308Sbellard */ 12867867308Sbellard #define ELF_PLAT_INIT(_r) \ 12967867308Sbellard do { \ 130274da6b2Sbellard target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \ 13167867308Sbellard _r->gpr[3] = bprm->argc; \ 13267867308Sbellard _r->gpr[4] = (unsigned long)++pos; \ 13367867308Sbellard for (; tmp != 0; pos++) \ 13467867308Sbellard tmp = *pos; \ 13567867308Sbellard _r->gpr[5] = (unsigned long)pos; \ 13667867308Sbellard } while (0) 13767867308Sbellard 138f5155289Sbellard /* 139f5155289Sbellard * We need to put in some extra aux table entries to tell glibc what 140f5155289Sbellard * the cache block size is, so it can use the dcbz instruction safely. 141f5155289Sbellard */ 142f5155289Sbellard #define AT_DCACHEBSIZE 19 143f5155289Sbellard #define AT_ICACHEBSIZE 20 144f5155289Sbellard #define AT_UCACHEBSIZE 21 145f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility. */ 146f5155289Sbellard #define AT_IGNOREPPC 22 147f5155289Sbellard /* 148f5155289Sbellard * The requirements here are: 149f5155289Sbellard * - keep the final alignment of sp (sp & 0xf) 150f5155289Sbellard * - make sure the 32-bit value at the first 16 byte aligned position of 151f5155289Sbellard * AUXV is greater than 16 for glibc compatibility. 152f5155289Sbellard * AT_IGNOREPPC is used for that. 153f5155289Sbellard * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, 154f5155289Sbellard * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. 155f5155289Sbellard */ 156f5155289Sbellard #define DLINFO_ARCH_ITEMS 3 157f5155289Sbellard #define ARCH_DLINFO \ 158f5155289Sbellard do { \ 159f5155289Sbellard sp -= DLINFO_ARCH_ITEMS * 2; \ 160f5155289Sbellard NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \ 161f5155289Sbellard NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \ 162f5155289Sbellard NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \ 163f5155289Sbellard /* \ 164f5155289Sbellard * Now handle glibc compatibility. \ 165f5155289Sbellard */ \ 166f5155289Sbellard sp -= 2*2; \ 167f5155289Sbellard NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ 168f5155289Sbellard NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ 169f5155289Sbellard } while (0) 170f5155289Sbellard 17167867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) 17267867308Sbellard { 17367867308Sbellard _regs->msr = 1 << MSR_PR; /* Set user mode */ 17467867308Sbellard _regs->gpr[1] = infop->start_stack; 17567867308Sbellard _regs->nip = infop->entry; 17667867308Sbellard } 17767867308Sbellard 17867867308Sbellard #define USE_ELF_CORE_DUMP 17967867308Sbellard #define ELF_EXEC_PAGESIZE 4096 18067867308Sbellard 18167867308Sbellard #endif 18267867308Sbellard 18331e31b8aSbellard #include "elf.h" 18409bfb054Sbellard 18509bfb054Sbellard /* 18609bfb054Sbellard * MAX_ARG_PAGES defines the number of pages allocated for arguments 18709bfb054Sbellard * and envelope for the new program. 32 should suffice, this gives 18809bfb054Sbellard * a maximum env+arg of 128kB w/4KB pages! 18909bfb054Sbellard */ 19009bfb054Sbellard #define MAX_ARG_PAGES 32 19109bfb054Sbellard 19209bfb054Sbellard /* 19309bfb054Sbellard * This structure is used to hold the arguments that are 19409bfb054Sbellard * used when loading binaries. 19509bfb054Sbellard */ 19609bfb054Sbellard struct linux_binprm { 19709bfb054Sbellard char buf[128]; 19809bfb054Sbellard unsigned long page[MAX_ARG_PAGES]; 19909bfb054Sbellard unsigned long p; 20009bfb054Sbellard int sh_bang; 20109bfb054Sbellard int fd; 20209bfb054Sbellard int e_uid, e_gid; 20309bfb054Sbellard int argc, envc; 20409bfb054Sbellard char * filename; /* Name of binary */ 20509bfb054Sbellard unsigned long loader, exec; 20609bfb054Sbellard int dont_iput; /* binfmt handler has put inode */ 20709bfb054Sbellard }; 20809bfb054Sbellard 20909bfb054Sbellard struct exec 21009bfb054Sbellard { 21109bfb054Sbellard unsigned int a_info; /* Use macros N_MAGIC, etc for access */ 21209bfb054Sbellard unsigned int a_text; /* length of text, in bytes */ 21309bfb054Sbellard unsigned int a_data; /* length of data, in bytes */ 21409bfb054Sbellard unsigned int a_bss; /* length of uninitialized data area, in bytes */ 21509bfb054Sbellard unsigned int a_syms; /* length of symbol table data in file, in bytes */ 21609bfb054Sbellard unsigned int a_entry; /* start address */ 21709bfb054Sbellard unsigned int a_trsize; /* length of relocation info for text, in bytes */ 21809bfb054Sbellard unsigned int a_drsize; /* length of relocation info for data, in bytes */ 21909bfb054Sbellard }; 22009bfb054Sbellard 22109bfb054Sbellard 22209bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff) 22309bfb054Sbellard #define OMAGIC 0407 22409bfb054Sbellard #define NMAGIC 0410 22509bfb054Sbellard #define ZMAGIC 0413 22609bfb054Sbellard #define QMAGIC 0314 22709bfb054Sbellard 22809bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */ 22909bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024) 23009bfb054Sbellard 23109bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */ 23209bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024) 23309bfb054Sbellard 23409bfb054Sbellard /* from personality.h */ 23509bfb054Sbellard 23609bfb054Sbellard /* Flags for bug emulation. These occupy the top three bytes. */ 23709bfb054Sbellard #define STICKY_TIMEOUTS 0x4000000 23809bfb054Sbellard #define WHOLE_SECONDS 0x2000000 23909bfb054Sbellard 24009bfb054Sbellard /* Personality types. These go in the low byte. Avoid using the top bit, 24109bfb054Sbellard * it will conflict with error returns. 24209bfb054Sbellard */ 24309bfb054Sbellard #define PER_MASK (0x00ff) 24409bfb054Sbellard #define PER_LINUX (0x0000) 24509bfb054Sbellard #define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) 24609bfb054Sbellard #define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) 24709bfb054Sbellard #define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) 24809bfb054Sbellard #define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) 24909bfb054Sbellard #define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) 25009bfb054Sbellard #define PER_BSD (0x0006) 25109bfb054Sbellard #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) 25231e31b8aSbellard 25331e31b8aSbellard /* Necessary parameters */ 25431e31b8aSbellard #define NGROUPS 32 25531e31b8aSbellard 25654936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE 25754936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) 25854936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) 25931e31b8aSbellard 26031e31b8aSbellard #define INTERPRETER_NONE 0 26131e31b8aSbellard #define INTERPRETER_AOUT 1 26231e31b8aSbellard #define INTERPRETER_ELF 2 26331e31b8aSbellard 264f5155289Sbellard #define DLINFO_ITEMS 11 26531e31b8aSbellard 26609bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) 26709bfb054Sbellard { 26809bfb054Sbellard memcpy(to, from, n); 26909bfb054Sbellard } 27009bfb054Sbellard 27131e31b8aSbellard extern unsigned long x86_stack_size; 27231e31b8aSbellard 27331e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd); 27431e31b8aSbellard 27531e31b8aSbellard #ifdef BSWAP_NEEDED 27631e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr) 27731e31b8aSbellard { 27831e31b8aSbellard bswap16s(&ehdr->e_type); /* Object file type */ 27931e31b8aSbellard bswap16s(&ehdr->e_machine); /* Architecture */ 28031e31b8aSbellard bswap32s(&ehdr->e_version); /* Object file version */ 28131e31b8aSbellard bswap32s(&ehdr->e_entry); /* Entry point virtual address */ 28231e31b8aSbellard bswap32s(&ehdr->e_phoff); /* Program header table file offset */ 28331e31b8aSbellard bswap32s(&ehdr->e_shoff); /* Section header table file offset */ 28431e31b8aSbellard bswap32s(&ehdr->e_flags); /* Processor-specific flags */ 28531e31b8aSbellard bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ 28631e31b8aSbellard bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ 28731e31b8aSbellard bswap16s(&ehdr->e_phnum); /* Program header table entry count */ 28831e31b8aSbellard bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ 28931e31b8aSbellard bswap16s(&ehdr->e_shnum); /* Section header table entry count */ 29031e31b8aSbellard bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ 29131e31b8aSbellard } 29231e31b8aSbellard 29331e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr) 29431e31b8aSbellard { 29531e31b8aSbellard bswap32s(&phdr->p_type); /* Segment type */ 29631e31b8aSbellard bswap32s(&phdr->p_offset); /* Segment file offset */ 29731e31b8aSbellard bswap32s(&phdr->p_vaddr); /* Segment virtual address */ 29831e31b8aSbellard bswap32s(&phdr->p_paddr); /* Segment physical address */ 29931e31b8aSbellard bswap32s(&phdr->p_filesz); /* Segment size in file */ 30031e31b8aSbellard bswap32s(&phdr->p_memsz); /* Segment size in memory */ 30131e31b8aSbellard bswap32s(&phdr->p_flags); /* Segment flags */ 30231e31b8aSbellard bswap32s(&phdr->p_align); /* Segment alignment */ 30331e31b8aSbellard } 304689f936fSbellard 305689f936fSbellard static void bswap_shdr(Elf32_Shdr *shdr) 306689f936fSbellard { 307689f936fSbellard bswap32s(&shdr->sh_name); 308689f936fSbellard bswap32s(&shdr->sh_type); 309689f936fSbellard bswap32s(&shdr->sh_flags); 310689f936fSbellard bswap32s(&shdr->sh_addr); 311689f936fSbellard bswap32s(&shdr->sh_offset); 312689f936fSbellard bswap32s(&shdr->sh_size); 313689f936fSbellard bswap32s(&shdr->sh_link); 314689f936fSbellard bswap32s(&shdr->sh_info); 315689f936fSbellard bswap32s(&shdr->sh_addralign); 316689f936fSbellard bswap32s(&shdr->sh_entsize); 317689f936fSbellard } 318689f936fSbellard 319689f936fSbellard static void bswap_sym(Elf32_Sym *sym) 320689f936fSbellard { 321689f936fSbellard bswap32s(&sym->st_name); 322689f936fSbellard bswap32s(&sym->st_value); 323689f936fSbellard bswap32s(&sym->st_size); 324689f936fSbellard bswap16s(&sym->st_shndx); 325689f936fSbellard } 32631e31b8aSbellard #endif 32731e31b8aSbellard 32831e31b8aSbellard static void * get_free_page(void) 32931e31b8aSbellard { 33031e31b8aSbellard void * retval; 33131e31b8aSbellard 33231e31b8aSbellard /* User-space version of kernel get_free_page. Returns a page-aligned 33331e31b8aSbellard * page-sized chunk of memory. 33431e31b8aSbellard */ 33554936004Sbellard retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE, 33631e31b8aSbellard MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 33731e31b8aSbellard 33831e31b8aSbellard if((long)retval == -1) { 33931e31b8aSbellard perror("get_free_page"); 34031e31b8aSbellard exit(-1); 34131e31b8aSbellard } 34231e31b8aSbellard else { 34331e31b8aSbellard return(retval); 34431e31b8aSbellard } 34531e31b8aSbellard } 34631e31b8aSbellard 34731e31b8aSbellard static void free_page(void * pageaddr) 34831e31b8aSbellard { 34954936004Sbellard target_munmap((unsigned long)pageaddr, host_page_size); 35031e31b8aSbellard } 35131e31b8aSbellard 35231e31b8aSbellard /* 35331e31b8aSbellard * 'copy_string()' copies argument/envelope strings from user 35431e31b8aSbellard * memory to free pages in kernel mem. These are in a format ready 35531e31b8aSbellard * to be put directly into the top of new user memory. 35631e31b8aSbellard * 35731e31b8aSbellard */ 35831e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, 35931e31b8aSbellard unsigned long p) 36031e31b8aSbellard { 36131e31b8aSbellard char *tmp, *tmp1, *pag = NULL; 36231e31b8aSbellard int len, offset = 0; 36331e31b8aSbellard 36431e31b8aSbellard if (!p) { 36531e31b8aSbellard return 0; /* bullet-proofing */ 36631e31b8aSbellard } 36731e31b8aSbellard while (argc-- > 0) { 368edf779ffSbellard tmp = argv[argc]; 369edf779ffSbellard if (!tmp) { 37031e31b8aSbellard fprintf(stderr, "VFS: argc is wrong"); 37131e31b8aSbellard exit(-1); 37231e31b8aSbellard } 373edf779ffSbellard tmp1 = tmp; 374edf779ffSbellard while (*tmp++); 37531e31b8aSbellard len = tmp - tmp1; 37631e31b8aSbellard if (p < len) { /* this shouldn't happen - 128kB */ 37731e31b8aSbellard return 0; 37831e31b8aSbellard } 37931e31b8aSbellard while (len) { 38031e31b8aSbellard --p; --tmp; --len; 38131e31b8aSbellard if (--offset < 0) { 38254936004Sbellard offset = p % TARGET_PAGE_SIZE; 38344a91caeSbellard pag = (char *) page[p/TARGET_PAGE_SIZE]; 38444a91caeSbellard if (!pag) { 38544a91caeSbellard pag = (char *)get_free_page(); 38644a91caeSbellard page[p/TARGET_PAGE_SIZE] = (unsigned long)pag; 38744a91caeSbellard if (!pag) 38831e31b8aSbellard return 0; 38931e31b8aSbellard } 39031e31b8aSbellard } 39131e31b8aSbellard if (len == 0 || offset == 0) { 392edf779ffSbellard *(pag + offset) = *tmp; 39331e31b8aSbellard } 39431e31b8aSbellard else { 39531e31b8aSbellard int bytes_to_copy = (len > offset) ? offset : len; 39631e31b8aSbellard tmp -= bytes_to_copy; 39731e31b8aSbellard p -= bytes_to_copy; 39831e31b8aSbellard offset -= bytes_to_copy; 39931e31b8aSbellard len -= bytes_to_copy; 40031e31b8aSbellard memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); 40131e31b8aSbellard } 40231e31b8aSbellard } 40331e31b8aSbellard } 40431e31b8aSbellard return p; 40531e31b8aSbellard } 40631e31b8aSbellard 40731e31b8aSbellard static int in_group_p(gid_t g) 40831e31b8aSbellard { 40931e31b8aSbellard /* return TRUE if we're in the specified group, FALSE otherwise */ 41031e31b8aSbellard int ngroup; 41131e31b8aSbellard int i; 41231e31b8aSbellard gid_t grouplist[NGROUPS]; 41331e31b8aSbellard 41431e31b8aSbellard ngroup = getgroups(NGROUPS, grouplist); 41531e31b8aSbellard for(i = 0; i < ngroup; i++) { 41631e31b8aSbellard if(grouplist[i] == g) { 41731e31b8aSbellard return 1; 41831e31b8aSbellard } 41931e31b8aSbellard } 42031e31b8aSbellard return 0; 42131e31b8aSbellard } 42231e31b8aSbellard 42331e31b8aSbellard static int count(char ** vec) 42431e31b8aSbellard { 42531e31b8aSbellard int i; 42631e31b8aSbellard 42731e31b8aSbellard for(i = 0; *vec; i++) { 42831e31b8aSbellard vec++; 42931e31b8aSbellard } 43031e31b8aSbellard 43131e31b8aSbellard return(i); 43231e31b8aSbellard } 43331e31b8aSbellard 43431e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm) 43531e31b8aSbellard { 43631e31b8aSbellard struct stat st; 43731e31b8aSbellard int mode; 43831e31b8aSbellard int retval, id_change; 43931e31b8aSbellard 44031e31b8aSbellard if(fstat(bprm->fd, &st) < 0) { 44131e31b8aSbellard return(-errno); 44231e31b8aSbellard } 44331e31b8aSbellard 44431e31b8aSbellard mode = st.st_mode; 44531e31b8aSbellard if(!S_ISREG(mode)) { /* Must be regular file */ 44631e31b8aSbellard return(-EACCES); 44731e31b8aSbellard } 44831e31b8aSbellard if(!(mode & 0111)) { /* Must have at least one execute bit set */ 44931e31b8aSbellard return(-EACCES); 45031e31b8aSbellard } 45131e31b8aSbellard 45231e31b8aSbellard bprm->e_uid = geteuid(); 45331e31b8aSbellard bprm->e_gid = getegid(); 45431e31b8aSbellard id_change = 0; 45531e31b8aSbellard 45631e31b8aSbellard /* Set-uid? */ 45731e31b8aSbellard if(mode & S_ISUID) { 45831e31b8aSbellard bprm->e_uid = st.st_uid; 45931e31b8aSbellard if(bprm->e_uid != geteuid()) { 46031e31b8aSbellard id_change = 1; 46131e31b8aSbellard } 46231e31b8aSbellard } 46331e31b8aSbellard 46431e31b8aSbellard /* Set-gid? */ 46531e31b8aSbellard /* 46631e31b8aSbellard * If setgid is set but no group execute bit then this 46731e31b8aSbellard * is a candidate for mandatory locking, not a setgid 46831e31b8aSbellard * executable. 46931e31b8aSbellard */ 47031e31b8aSbellard if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 47131e31b8aSbellard bprm->e_gid = st.st_gid; 47231e31b8aSbellard if (!in_group_p(bprm->e_gid)) { 47331e31b8aSbellard id_change = 1; 47431e31b8aSbellard } 47531e31b8aSbellard } 47631e31b8aSbellard 47731e31b8aSbellard memset(bprm->buf, 0, sizeof(bprm->buf)); 47831e31b8aSbellard retval = lseek(bprm->fd, 0L, SEEK_SET); 47931e31b8aSbellard if(retval >= 0) { 48031e31b8aSbellard retval = read(bprm->fd, bprm->buf, 128); 48131e31b8aSbellard } 48231e31b8aSbellard if(retval < 0) { 48331e31b8aSbellard perror("prepare_binprm"); 48431e31b8aSbellard exit(-1); 48531e31b8aSbellard /* return(-errno); */ 48631e31b8aSbellard } 48731e31b8aSbellard else { 48831e31b8aSbellard return(retval); 48931e31b8aSbellard } 49031e31b8aSbellard } 49131e31b8aSbellard 49231e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, 49331e31b8aSbellard struct image_info * info) 49431e31b8aSbellard { 49509bfb054Sbellard unsigned long stack_base, size, error; 49631e31b8aSbellard int i; 49731e31b8aSbellard 49831e31b8aSbellard /* Create enough stack to hold everything. If we don't use 49931e31b8aSbellard * it for args, we'll use it for something else... 50031e31b8aSbellard */ 50109bfb054Sbellard size = x86_stack_size; 50254936004Sbellard if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) 50354936004Sbellard size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; 50454936004Sbellard error = target_mmap(0, 50554936004Sbellard size + host_page_size, 50631e31b8aSbellard PROT_READ | PROT_WRITE, 50709bfb054Sbellard MAP_PRIVATE | MAP_ANONYMOUS, 50809bfb054Sbellard -1, 0); 50909bfb054Sbellard if (error == -1) { 51031e31b8aSbellard perror("stk mmap"); 51131e31b8aSbellard exit(-1); 51231e31b8aSbellard } 51309bfb054Sbellard /* we reserve one extra page at the top of the stack as guard */ 51454936004Sbellard target_mprotect(error + size, host_page_size, PROT_NONE); 51531e31b8aSbellard 51654936004Sbellard stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; 51709bfb054Sbellard p += stack_base; 51809bfb054Sbellard 51909bfb054Sbellard if (bprm->loader) { 52009bfb054Sbellard bprm->loader += stack_base; 52109bfb054Sbellard } 52209bfb054Sbellard bprm->exec += stack_base; 52331e31b8aSbellard 52431e31b8aSbellard for (i = 0 ; i < MAX_ARG_PAGES ; i++) { 52531e31b8aSbellard if (bprm->page[i]) { 52631e31b8aSbellard info->rss++; 52731e31b8aSbellard 52854936004Sbellard memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE); 52931e31b8aSbellard free_page((void *)bprm->page[i]); 53031e31b8aSbellard } 53154936004Sbellard stack_base += TARGET_PAGE_SIZE; 53231e31b8aSbellard } 53331e31b8aSbellard return p; 53431e31b8aSbellard } 53531e31b8aSbellard 53631e31b8aSbellard static void set_brk(unsigned long start, unsigned long end) 53731e31b8aSbellard { 53831e31b8aSbellard /* page-align the start and end addresses... */ 53954936004Sbellard start = HOST_PAGE_ALIGN(start); 54054936004Sbellard end = HOST_PAGE_ALIGN(end); 54131e31b8aSbellard if (end <= start) 54231e31b8aSbellard return; 54354936004Sbellard if(target_mmap(start, end - start, 54431e31b8aSbellard PROT_READ | PROT_WRITE | PROT_EXEC, 54531e31b8aSbellard MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { 54631e31b8aSbellard perror("cannot mmap brk"); 54731e31b8aSbellard exit(-1); 54831e31b8aSbellard } 54931e31b8aSbellard } 55031e31b8aSbellard 55131e31b8aSbellard 552853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data 553853d6f7aSbellard section (i.e. bss). This would contain the junk from the file that 554853d6f7aSbellard should not be in memory. */ 55531e31b8aSbellard static void padzero(unsigned long elf_bss) 55631e31b8aSbellard { 55731e31b8aSbellard unsigned long nbyte; 55831e31b8aSbellard char * fpnt; 55931e31b8aSbellard 560853d6f7aSbellard /* XXX: this is really a hack : if the real host page size is 561853d6f7aSbellard smaller than the target page size, some pages after the end 562853d6f7aSbellard of the file may not be mapped. A better fix would be to 563853d6f7aSbellard patch target_mmap(), but it is more complicated as the file 564853d6f7aSbellard size must be known */ 565853d6f7aSbellard if (real_host_page_size < host_page_size) { 566853d6f7aSbellard unsigned long end_addr, end_addr1; 567853d6f7aSbellard end_addr1 = (elf_bss + real_host_page_size - 1) & 568853d6f7aSbellard ~(real_host_page_size - 1); 569853d6f7aSbellard end_addr = HOST_PAGE_ALIGN(elf_bss); 570853d6f7aSbellard if (end_addr1 < end_addr) { 571853d6f7aSbellard mmap((void *)end_addr1, end_addr - end_addr1, 572853d6f7aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 573853d6f7aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 574853d6f7aSbellard } 575853d6f7aSbellard } 576853d6f7aSbellard 577853d6f7aSbellard nbyte = elf_bss & (host_page_size-1); 57831e31b8aSbellard if (nbyte) { 57954936004Sbellard nbyte = host_page_size - nbyte; 58031e31b8aSbellard fpnt = (char *) elf_bss; 58131e31b8aSbellard do { 58231e31b8aSbellard *fpnt++ = 0; 58331e31b8aSbellard } while (--nbyte); 58431e31b8aSbellard } 58531e31b8aSbellard } 58631e31b8aSbellard 58731e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc, 58831e31b8aSbellard struct elfhdr * exec, 58931e31b8aSbellard unsigned long load_addr, 59009bfb054Sbellard unsigned long load_bias, 59131e31b8aSbellard unsigned long interp_load_addr, int ibcs, 59231e31b8aSbellard struct image_info *info) 59331e31b8aSbellard { 594f5155289Sbellard target_ulong *argv, *envp; 595f5155289Sbellard target_ulong *sp, *csp; 596edf779ffSbellard int v; 59731e31b8aSbellard 59831e31b8aSbellard /* 599f5155289Sbellard * Force 16 byte _final_ alignment here for generality. 60031e31b8aSbellard */ 60131e31b8aSbellard sp = (unsigned int *) (~15UL & (unsigned long) p); 602f5155289Sbellard csp = sp; 603f5155289Sbellard csp -= (DLINFO_ITEMS + 1) * 2; 604f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS 605f5155289Sbellard csp -= DLINFO_ARCH_ITEMS*2; 606f5155289Sbellard #endif 607f5155289Sbellard csp -= envc+1; 608f5155289Sbellard csp -= argc+1; 609f5155289Sbellard csp -= (!ibcs ? 3 : 1); /* argc itself */ 610f5155289Sbellard if ((unsigned long)csp & 15UL) 611f5155289Sbellard sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); 612f5155289Sbellard 613f5155289Sbellard #define NEW_AUX_ENT(nr, id, val) \ 614edf779ffSbellard put_user (id, sp + (nr * 2)); \ 615edf779ffSbellard put_user (val, sp + (nr * 2 + 1)) 616f5155289Sbellard sp -= 2; 617f5155289Sbellard NEW_AUX_ENT (0, AT_NULL, 0); 618f5155289Sbellard 619a1516e92Sbellard sp -= DLINFO_ITEMS*2; 620f5155289Sbellard NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); 621f5155289Sbellard NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); 622f5155289Sbellard NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum)); 623f5155289Sbellard NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); 624f5155289Sbellard NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr)); 625f5155289Sbellard NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0); 626f5155289Sbellard NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry); 627f5155289Sbellard NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid()); 628f5155289Sbellard NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid()); 629f5155289Sbellard NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid()); 630f5155289Sbellard NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid()); 631f5155289Sbellard #ifdef ARCH_DLINFO 632f5155289Sbellard /* 633f5155289Sbellard * ARCH_DLINFO must come last so platform specific code can enforce 634f5155289Sbellard * special alignment requirements on the AUXV if necessary (eg. PPC). 635f5155289Sbellard */ 636f5155289Sbellard ARCH_DLINFO; 637f5155289Sbellard #endif 638f5155289Sbellard #undef NEW_AUX_ENT 639f5155289Sbellard 64031e31b8aSbellard sp -= envc+1; 64131e31b8aSbellard envp = sp; 64231e31b8aSbellard sp -= argc+1; 64331e31b8aSbellard argv = sp; 64431e31b8aSbellard if (!ibcs) { 645edf779ffSbellard put_user((target_ulong)envp,--sp); 646edf779ffSbellard put_user((target_ulong)argv,--sp); 64731e31b8aSbellard } 648edf779ffSbellard put_user(argc,--sp); 64931e31b8aSbellard info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); 65031e31b8aSbellard while (argc-->0) { 651edf779ffSbellard put_user((target_ulong)p,argv++); 652edf779ffSbellard do { 653edf779ffSbellard get_user(v, p); 654edf779ffSbellard p++; 655edf779ffSbellard } while (v != 0); 65631e31b8aSbellard } 65731e31b8aSbellard put_user(0,argv); 65831e31b8aSbellard info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); 65931e31b8aSbellard while (envc-->0) { 660edf779ffSbellard put_user((target_ulong)p,envp++); 661edf779ffSbellard do { 662edf779ffSbellard get_user(v, p); 663edf779ffSbellard p++; 664edf779ffSbellard } while (v != 0); 66531e31b8aSbellard } 66631e31b8aSbellard put_user(0,envp); 66731e31b8aSbellard info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); 66831e31b8aSbellard return sp; 66931e31b8aSbellard } 67031e31b8aSbellard 67131e31b8aSbellard 67231e31b8aSbellard 67331e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, 67431e31b8aSbellard int interpreter_fd, 67531e31b8aSbellard unsigned long *interp_load_addr) 67631e31b8aSbellard { 67731e31b8aSbellard struct elf_phdr *elf_phdata = NULL; 67831e31b8aSbellard struct elf_phdr *eppnt; 67909bfb054Sbellard unsigned long load_addr = 0; 68031e31b8aSbellard int load_addr_set = 0; 68131e31b8aSbellard int retval; 68231e31b8aSbellard unsigned long last_bss, elf_bss; 68331e31b8aSbellard unsigned long error; 68431e31b8aSbellard int i; 68531e31b8aSbellard 68631e31b8aSbellard elf_bss = 0; 68731e31b8aSbellard last_bss = 0; 68831e31b8aSbellard error = 0; 68931e31b8aSbellard 690644c433cSbellard #ifdef BSWAP_NEEDED 691644c433cSbellard bswap_ehdr(interp_elf_ex); 692644c433cSbellard #endif 69331e31b8aSbellard /* First of all, some simple consistency checks */ 69431e31b8aSbellard if ((interp_elf_ex->e_type != ET_EXEC && 69531e31b8aSbellard interp_elf_ex->e_type != ET_DYN) || 69631e31b8aSbellard !elf_check_arch(interp_elf_ex->e_machine)) { 69731e31b8aSbellard return ~0UL; 69831e31b8aSbellard } 69931e31b8aSbellard 700644c433cSbellard 70131e31b8aSbellard /* Now read in all of the header information */ 70231e31b8aSbellard 70354936004Sbellard if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) 70431e31b8aSbellard return ~0UL; 70531e31b8aSbellard 70631e31b8aSbellard elf_phdata = (struct elf_phdr *) 70731e31b8aSbellard malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 70831e31b8aSbellard 70931e31b8aSbellard if (!elf_phdata) 71031e31b8aSbellard return ~0UL; 71131e31b8aSbellard 71231e31b8aSbellard /* 71331e31b8aSbellard * If the size of this structure has changed, then punt, since 71431e31b8aSbellard * we will be doing the wrong thing. 71531e31b8aSbellard */ 71609bfb054Sbellard if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { 71731e31b8aSbellard free(elf_phdata); 71831e31b8aSbellard return ~0UL; 71931e31b8aSbellard } 72031e31b8aSbellard 72131e31b8aSbellard retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); 72231e31b8aSbellard if(retval >= 0) { 72331e31b8aSbellard retval = read(interpreter_fd, 72431e31b8aSbellard (char *) elf_phdata, 72531e31b8aSbellard sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 72631e31b8aSbellard } 72731e31b8aSbellard if (retval < 0) { 72831e31b8aSbellard perror("load_elf_interp"); 72931e31b8aSbellard exit(-1); 73031e31b8aSbellard free (elf_phdata); 73131e31b8aSbellard return retval; 73231e31b8aSbellard } 73331e31b8aSbellard #ifdef BSWAP_NEEDED 73431e31b8aSbellard eppnt = elf_phdata; 73531e31b8aSbellard for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { 73631e31b8aSbellard bswap_phdr(eppnt); 73731e31b8aSbellard } 73831e31b8aSbellard #endif 73909bfb054Sbellard 74009bfb054Sbellard if (interp_elf_ex->e_type == ET_DYN) { 74109bfb054Sbellard /* in order to avoid harcoding the interpreter load 74209bfb054Sbellard address in qemu, we allocate a big enough memory zone */ 74354936004Sbellard error = target_mmap(0, INTERP_MAP_SIZE, 74409bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 74509bfb054Sbellard -1, 0); 74609bfb054Sbellard if (error == -1) { 74709bfb054Sbellard perror("mmap"); 74809bfb054Sbellard exit(-1); 74909bfb054Sbellard } 75009bfb054Sbellard load_addr = error; 75109bfb054Sbellard load_addr_set = 1; 75209bfb054Sbellard } 75309bfb054Sbellard 75431e31b8aSbellard eppnt = elf_phdata; 75531e31b8aSbellard for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) 75631e31b8aSbellard if (eppnt->p_type == PT_LOAD) { 75731e31b8aSbellard int elf_type = MAP_PRIVATE | MAP_DENYWRITE; 75831e31b8aSbellard int elf_prot = 0; 75931e31b8aSbellard unsigned long vaddr = 0; 76031e31b8aSbellard unsigned long k; 76131e31b8aSbellard 76231e31b8aSbellard if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; 76331e31b8aSbellard if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 76431e31b8aSbellard if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 76531e31b8aSbellard if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { 76631e31b8aSbellard elf_type |= MAP_FIXED; 76731e31b8aSbellard vaddr = eppnt->p_vaddr; 76831e31b8aSbellard } 76954936004Sbellard error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), 77054936004Sbellard eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), 77131e31b8aSbellard elf_prot, 77231e31b8aSbellard elf_type, 77331e31b8aSbellard interpreter_fd, 77454936004Sbellard eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); 77531e31b8aSbellard 77631e31b8aSbellard if (error > -1024UL) { 77731e31b8aSbellard /* Real error */ 77831e31b8aSbellard close(interpreter_fd); 77931e31b8aSbellard free(elf_phdata); 78031e31b8aSbellard return ~0UL; 78131e31b8aSbellard } 78231e31b8aSbellard 78331e31b8aSbellard if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { 78431e31b8aSbellard load_addr = error; 78531e31b8aSbellard load_addr_set = 1; 78631e31b8aSbellard } 78731e31b8aSbellard 78831e31b8aSbellard /* 78931e31b8aSbellard * Find the end of the file mapping for this phdr, and keep 79031e31b8aSbellard * track of the largest address we see for this. 79131e31b8aSbellard */ 79231e31b8aSbellard k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 79331e31b8aSbellard if (k > elf_bss) elf_bss = k; 79431e31b8aSbellard 79531e31b8aSbellard /* 79631e31b8aSbellard * Do the same thing for the memory mapping - between 79731e31b8aSbellard * elf_bss and last_bss is the bss section. 79831e31b8aSbellard */ 79931e31b8aSbellard k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; 80031e31b8aSbellard if (k > last_bss) last_bss = k; 80131e31b8aSbellard } 80231e31b8aSbellard 80331e31b8aSbellard /* Now use mmap to map the library into memory. */ 80431e31b8aSbellard 80531e31b8aSbellard close(interpreter_fd); 80631e31b8aSbellard 80731e31b8aSbellard /* 80831e31b8aSbellard * Now fill out the bss section. First pad the last page up 80931e31b8aSbellard * to the page boundary, and then perform a mmap to make sure 81031e31b8aSbellard * that there are zeromapped pages up to and including the last 81131e31b8aSbellard * bss page. 81231e31b8aSbellard */ 81331e31b8aSbellard padzero(elf_bss); 81454936004Sbellard elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */ 81531e31b8aSbellard 81631e31b8aSbellard /* Map the last of the bss segment */ 81731e31b8aSbellard if (last_bss > elf_bss) { 81854936004Sbellard target_mmap(elf_bss, last_bss-elf_bss, 81931e31b8aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 82031e31b8aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 82131e31b8aSbellard } 82231e31b8aSbellard free(elf_phdata); 82331e31b8aSbellard 82431e31b8aSbellard *interp_load_addr = load_addr; 82531e31b8aSbellard return ((unsigned long) interp_elf_ex->e_entry) + load_addr; 82631e31b8aSbellard } 82731e31b8aSbellard 828689f936fSbellard /* Best attempt to load symbols from this ELF object. */ 829689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd) 830689f936fSbellard { 831689f936fSbellard unsigned int i; 832689f936fSbellard struct elf_shdr sechdr, symtab, strtab; 833689f936fSbellard char *strings; 83431e31b8aSbellard 835689f936fSbellard lseek(fd, hdr->e_shoff, SEEK_SET); 836689f936fSbellard for (i = 0; i < hdr->e_shnum; i++) { 837689f936fSbellard if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) 838689f936fSbellard return; 839689f936fSbellard #ifdef BSWAP_NEEDED 840689f936fSbellard bswap_shdr(&sechdr); 841689f936fSbellard #endif 842689f936fSbellard if (sechdr.sh_type == SHT_SYMTAB) { 843689f936fSbellard symtab = sechdr; 844689f936fSbellard lseek(fd, hdr->e_shoff 845689f936fSbellard + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); 846689f936fSbellard if (read(fd, &strtab, sizeof(strtab)) 847689f936fSbellard != sizeof(strtab)) 848689f936fSbellard return; 849689f936fSbellard #ifdef BSWAP_NEEDED 850689f936fSbellard bswap_shdr(&strtab); 851689f936fSbellard #endif 852689f936fSbellard goto found; 853689f936fSbellard } 854689f936fSbellard } 855689f936fSbellard return; /* Shouldn't happen... */ 856689f936fSbellard 857689f936fSbellard found: 858689f936fSbellard /* Now know where the strtab and symtab are. Snarf them. */ 859689f936fSbellard disas_symtab = malloc(symtab.sh_size); 860689f936fSbellard disas_strtab = strings = malloc(strtab.sh_size); 861689f936fSbellard if (!disas_symtab || !disas_strtab) 862689f936fSbellard return; 863689f936fSbellard 864689f936fSbellard lseek(fd, symtab.sh_offset, SEEK_SET); 865689f936fSbellard if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) 866689f936fSbellard return; 867689f936fSbellard 868689f936fSbellard #ifdef BSWAP_NEEDED 869689f936fSbellard for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) 870689f936fSbellard bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); 871689f936fSbellard #endif 872689f936fSbellard 873689f936fSbellard lseek(fd, strtab.sh_offset, SEEK_SET); 874689f936fSbellard if (read(fd, strings, strtab.sh_size) != strtab.sh_size) 875689f936fSbellard return; 876689f936fSbellard disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); 877689f936fSbellard } 87831e31b8aSbellard 879b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 88031e31b8aSbellard struct image_info * info) 88131e31b8aSbellard { 88231e31b8aSbellard struct elfhdr elf_ex; 88331e31b8aSbellard struct elfhdr interp_elf_ex; 88431e31b8aSbellard struct exec interp_ex; 88531e31b8aSbellard int interpreter_fd = -1; /* avoid warning */ 88609bfb054Sbellard unsigned long load_addr, load_bias; 88731e31b8aSbellard int load_addr_set = 0; 88831e31b8aSbellard unsigned int interpreter_type = INTERPRETER_NONE; 88931e31b8aSbellard unsigned char ibcs2_interpreter; 89031e31b8aSbellard int i; 89154936004Sbellard unsigned long mapped_addr; 89231e31b8aSbellard struct elf_phdr * elf_ppnt; 89331e31b8aSbellard struct elf_phdr *elf_phdata; 89431e31b8aSbellard unsigned long elf_bss, k, elf_brk; 89531e31b8aSbellard int retval; 89631e31b8aSbellard char * elf_interpreter; 89731e31b8aSbellard unsigned long elf_entry, interp_load_addr = 0; 89831e31b8aSbellard int status; 89931e31b8aSbellard unsigned long start_code, end_code, end_data; 90031e31b8aSbellard unsigned long elf_stack; 90131e31b8aSbellard char passed_fileno[6]; 90231e31b8aSbellard 90331e31b8aSbellard ibcs2_interpreter = 0; 90431e31b8aSbellard status = 0; 90531e31b8aSbellard load_addr = 0; 90609bfb054Sbellard load_bias = 0; 90731e31b8aSbellard elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ 90831e31b8aSbellard #ifdef BSWAP_NEEDED 90931e31b8aSbellard bswap_ehdr(&elf_ex); 91031e31b8aSbellard #endif 91131e31b8aSbellard 91231e31b8aSbellard if (elf_ex.e_ident[0] != 0x7f || 91331e31b8aSbellard strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { 91431e31b8aSbellard return -ENOEXEC; 91531e31b8aSbellard } 91631e31b8aSbellard 91731e31b8aSbellard /* First of all, some simple consistency checks */ 91831e31b8aSbellard if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || 91931e31b8aSbellard (! elf_check_arch(elf_ex.e_machine))) { 92031e31b8aSbellard return -ENOEXEC; 92131e31b8aSbellard } 92231e31b8aSbellard 92331e31b8aSbellard /* Now read in all of the header information */ 92431e31b8aSbellard elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); 92531e31b8aSbellard if (elf_phdata == NULL) { 92631e31b8aSbellard return -ENOMEM; 92731e31b8aSbellard } 92831e31b8aSbellard 92931e31b8aSbellard retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); 93031e31b8aSbellard if(retval > 0) { 93131e31b8aSbellard retval = read(bprm->fd, (char *) elf_phdata, 93231e31b8aSbellard elf_ex.e_phentsize * elf_ex.e_phnum); 93331e31b8aSbellard } 93431e31b8aSbellard 93531e31b8aSbellard if (retval < 0) { 93631e31b8aSbellard perror("load_elf_binary"); 93731e31b8aSbellard exit(-1); 93831e31b8aSbellard free (elf_phdata); 93931e31b8aSbellard return -errno; 94031e31b8aSbellard } 94131e31b8aSbellard 942b17780d5Sbellard #ifdef BSWAP_NEEDED 943b17780d5Sbellard elf_ppnt = elf_phdata; 944b17780d5Sbellard for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { 945b17780d5Sbellard bswap_phdr(elf_ppnt); 946b17780d5Sbellard } 947b17780d5Sbellard #endif 94831e31b8aSbellard elf_ppnt = elf_phdata; 94931e31b8aSbellard 95031e31b8aSbellard elf_bss = 0; 95131e31b8aSbellard elf_brk = 0; 95231e31b8aSbellard 95331e31b8aSbellard 95431e31b8aSbellard elf_stack = ~0UL; 95531e31b8aSbellard elf_interpreter = NULL; 95631e31b8aSbellard start_code = ~0UL; 95731e31b8aSbellard end_code = 0; 95831e31b8aSbellard end_data = 0; 95931e31b8aSbellard 96031e31b8aSbellard for(i=0;i < elf_ex.e_phnum; i++) { 96131e31b8aSbellard if (elf_ppnt->p_type == PT_INTERP) { 96231e31b8aSbellard if ( elf_interpreter != NULL ) 96331e31b8aSbellard { 96431e31b8aSbellard free (elf_phdata); 96531e31b8aSbellard free(elf_interpreter); 96631e31b8aSbellard close(bprm->fd); 96731e31b8aSbellard return -EINVAL; 96831e31b8aSbellard } 96931e31b8aSbellard 97031e31b8aSbellard /* This is the program interpreter used for 97131e31b8aSbellard * shared libraries - for now assume that this 97231e31b8aSbellard * is an a.out format binary 97331e31b8aSbellard */ 97431e31b8aSbellard 97532ce6337Sbellard elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); 97631e31b8aSbellard 97731e31b8aSbellard if (elf_interpreter == NULL) { 97831e31b8aSbellard free (elf_phdata); 97931e31b8aSbellard close(bprm->fd); 98031e31b8aSbellard return -ENOMEM; 98131e31b8aSbellard } 98231e31b8aSbellard 98331e31b8aSbellard retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); 98431e31b8aSbellard if(retval >= 0) { 98532ce6337Sbellard retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); 98631e31b8aSbellard } 98731e31b8aSbellard if(retval < 0) { 98831e31b8aSbellard perror("load_elf_binary2"); 98931e31b8aSbellard exit(-1); 99031e31b8aSbellard } 99131e31b8aSbellard 99231e31b8aSbellard /* If the program interpreter is one of these two, 99331e31b8aSbellard then assume an iBCS2 image. Otherwise assume 99431e31b8aSbellard a native linux image. */ 99531e31b8aSbellard 99631e31b8aSbellard /* JRP - Need to add X86 lib dir stuff here... */ 99731e31b8aSbellard 99831e31b8aSbellard if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || 99931e31b8aSbellard strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { 100031e31b8aSbellard ibcs2_interpreter = 1; 100131e31b8aSbellard } 100231e31b8aSbellard 100331e31b8aSbellard #if 0 100431e31b8aSbellard printf("Using ELF interpreter %s\n", elf_interpreter); 100531e31b8aSbellard #endif 100631e31b8aSbellard if (retval >= 0) { 100732ce6337Sbellard retval = open(path(elf_interpreter), O_RDONLY); 100831e31b8aSbellard if(retval >= 0) { 100931e31b8aSbellard interpreter_fd = retval; 101031e31b8aSbellard } 101131e31b8aSbellard else { 101231e31b8aSbellard perror(elf_interpreter); 101331e31b8aSbellard exit(-1); 101431e31b8aSbellard /* retval = -errno; */ 101531e31b8aSbellard } 101631e31b8aSbellard } 101731e31b8aSbellard 101831e31b8aSbellard if (retval >= 0) { 101931e31b8aSbellard retval = lseek(interpreter_fd, 0, SEEK_SET); 102031e31b8aSbellard if(retval >= 0) { 102131e31b8aSbellard retval = read(interpreter_fd,bprm->buf,128); 102231e31b8aSbellard } 102331e31b8aSbellard } 102431e31b8aSbellard if (retval >= 0) { 102531e31b8aSbellard interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ 102631e31b8aSbellard interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ 102731e31b8aSbellard } 102831e31b8aSbellard if (retval < 0) { 102931e31b8aSbellard perror("load_elf_binary3"); 103031e31b8aSbellard exit(-1); 103131e31b8aSbellard free (elf_phdata); 103231e31b8aSbellard free(elf_interpreter); 103331e31b8aSbellard close(bprm->fd); 103431e31b8aSbellard return retval; 103531e31b8aSbellard } 103631e31b8aSbellard } 103731e31b8aSbellard elf_ppnt++; 103831e31b8aSbellard } 103931e31b8aSbellard 104031e31b8aSbellard /* Some simple consistency checks for the interpreter */ 104131e31b8aSbellard if (elf_interpreter){ 104231e31b8aSbellard interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; 104331e31b8aSbellard 104431e31b8aSbellard /* Now figure out which format our binary is */ 104531e31b8aSbellard if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && 104631e31b8aSbellard (N_MAGIC(interp_ex) != QMAGIC)) { 104731e31b8aSbellard interpreter_type = INTERPRETER_ELF; 104831e31b8aSbellard } 104931e31b8aSbellard 105031e31b8aSbellard if (interp_elf_ex.e_ident[0] != 0x7f || 105131e31b8aSbellard strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { 105231e31b8aSbellard interpreter_type &= ~INTERPRETER_ELF; 105331e31b8aSbellard } 105431e31b8aSbellard 105531e31b8aSbellard if (!interpreter_type) { 105631e31b8aSbellard free(elf_interpreter); 105731e31b8aSbellard free(elf_phdata); 105831e31b8aSbellard close(bprm->fd); 105931e31b8aSbellard return -ELIBBAD; 106031e31b8aSbellard } 106131e31b8aSbellard } 106231e31b8aSbellard 106331e31b8aSbellard /* OK, we are done with that, now set up the arg stuff, 106431e31b8aSbellard and then start this sucker up */ 106531e31b8aSbellard 106631e31b8aSbellard if (!bprm->sh_bang) { 106731e31b8aSbellard char * passed_p; 106831e31b8aSbellard 106931e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) { 1070*eba2af63Sbellard snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); 107131e31b8aSbellard passed_p = passed_fileno; 107231e31b8aSbellard 107331e31b8aSbellard if (elf_interpreter) { 107431e31b8aSbellard bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); 107531e31b8aSbellard bprm->argc++; 107631e31b8aSbellard } 107731e31b8aSbellard } 107831e31b8aSbellard if (!bprm->p) { 107931e31b8aSbellard if (elf_interpreter) { 108031e31b8aSbellard free(elf_interpreter); 108131e31b8aSbellard } 108231e31b8aSbellard free (elf_phdata); 108331e31b8aSbellard close(bprm->fd); 108431e31b8aSbellard return -E2BIG; 108531e31b8aSbellard } 108631e31b8aSbellard } 108731e31b8aSbellard 108831e31b8aSbellard /* OK, This is the point of no return */ 108931e31b8aSbellard info->end_data = 0; 109031e31b8aSbellard info->end_code = 0; 109131e31b8aSbellard info->start_mmap = (unsigned long)ELF_START_MMAP; 109231e31b8aSbellard info->mmap = 0; 109331e31b8aSbellard elf_entry = (unsigned long) elf_ex.e_entry; 109431e31b8aSbellard 109531e31b8aSbellard /* Do this so that we can load the interpreter, if need be. We will 109631e31b8aSbellard change some of these later */ 109731e31b8aSbellard info->rss = 0; 109831e31b8aSbellard bprm->p = setup_arg_pages(bprm->p, bprm, info); 109931e31b8aSbellard info->start_stack = bprm->p; 110031e31b8aSbellard 110131e31b8aSbellard /* Now we do a little grungy work by mmaping the ELF image into 110231e31b8aSbellard * the correct location in memory. At this point, we assume that 110331e31b8aSbellard * the image should be loaded at fixed address, not at a variable 110431e31b8aSbellard * address. 110531e31b8aSbellard */ 110631e31b8aSbellard 110731e31b8aSbellard for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { 110831e31b8aSbellard int elf_prot = 0; 110909bfb054Sbellard int elf_flags = 0; 111009bfb054Sbellard unsigned long error; 111109bfb054Sbellard 111209bfb054Sbellard if (elf_ppnt->p_type != PT_LOAD) 111309bfb054Sbellard continue; 111409bfb054Sbellard 111531e31b8aSbellard if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; 111631e31b8aSbellard if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 111731e31b8aSbellard if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 111809bfb054Sbellard elf_flags = MAP_PRIVATE | MAP_DENYWRITE; 111909bfb054Sbellard if (elf_ex.e_type == ET_EXEC || load_addr_set) { 112009bfb054Sbellard elf_flags |= MAP_FIXED; 112109bfb054Sbellard } else if (elf_ex.e_type == ET_DYN) { 112209bfb054Sbellard /* Try and get dynamic programs out of the way of the default mmap 112309bfb054Sbellard base, as well as whatever program they might try to exec. This 112409bfb054Sbellard is because the brk will follow the loader, and is not movable. */ 112509bfb054Sbellard /* NOTE: for qemu, we do a big mmap to get enough space 112609bfb054Sbellard without harcoding any address */ 112754936004Sbellard error = target_mmap(0, ET_DYN_MAP_SIZE, 112809bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 112909bfb054Sbellard -1, 0); 113009bfb054Sbellard if (error == -1) { 113109bfb054Sbellard perror("mmap"); 113209bfb054Sbellard exit(-1); 113309bfb054Sbellard } 113454936004Sbellard load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); 113509bfb054Sbellard } 113631e31b8aSbellard 113754936004Sbellard error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), 113831e31b8aSbellard (elf_ppnt->p_filesz + 113954936004Sbellard TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), 114031e31b8aSbellard elf_prot, 114131e31b8aSbellard (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), 114231e31b8aSbellard bprm->fd, 114331e31b8aSbellard (elf_ppnt->p_offset - 114454936004Sbellard TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); 114509bfb054Sbellard if (error == -1) { 114631e31b8aSbellard perror("mmap"); 114731e31b8aSbellard exit(-1); 114831e31b8aSbellard } 114931e31b8aSbellard 115031e31b8aSbellard #ifdef LOW_ELF_STACK 115154936004Sbellard if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 115254936004Sbellard elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); 115331e31b8aSbellard #endif 115431e31b8aSbellard 115531e31b8aSbellard if (!load_addr_set) { 115631e31b8aSbellard load_addr_set = 1; 115709bfb054Sbellard load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; 115809bfb054Sbellard if (elf_ex.e_type == ET_DYN) { 115909bfb054Sbellard load_bias += error - 116054936004Sbellard TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); 116109bfb054Sbellard load_addr += load_bias; 116209bfb054Sbellard } 116331e31b8aSbellard } 116431e31b8aSbellard k = elf_ppnt->p_vaddr; 116509bfb054Sbellard if (k < start_code) 116609bfb054Sbellard start_code = k; 116731e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 116809bfb054Sbellard if (k > elf_bss) 116909bfb054Sbellard elf_bss = k; 117031e31b8aSbellard if ((elf_ppnt->p_flags & PF_X) && end_code < k) 117131e31b8aSbellard end_code = k; 117209bfb054Sbellard if (end_data < k) 117309bfb054Sbellard end_data = k; 117431e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 117531e31b8aSbellard if (k > elf_brk) elf_brk = k; 117631e31b8aSbellard } 117709bfb054Sbellard 117809bfb054Sbellard elf_entry += load_bias; 117909bfb054Sbellard elf_bss += load_bias; 118009bfb054Sbellard elf_brk += load_bias; 118109bfb054Sbellard start_code += load_bias; 118209bfb054Sbellard end_code += load_bias; 118309bfb054Sbellard // start_data += load_bias; 118409bfb054Sbellard end_data += load_bias; 118531e31b8aSbellard 118631e31b8aSbellard if (elf_interpreter) { 118731e31b8aSbellard if (interpreter_type & 1) { 118831e31b8aSbellard elf_entry = load_aout_interp(&interp_ex, interpreter_fd); 118931e31b8aSbellard } 119031e31b8aSbellard else if (interpreter_type & 2) { 119131e31b8aSbellard elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, 119231e31b8aSbellard &interp_load_addr); 119331e31b8aSbellard } 119431e31b8aSbellard 119531e31b8aSbellard close(interpreter_fd); 119631e31b8aSbellard free(elf_interpreter); 119731e31b8aSbellard 119831e31b8aSbellard if (elf_entry == ~0UL) { 119931e31b8aSbellard printf("Unable to load interpreter\n"); 120031e31b8aSbellard free(elf_phdata); 120131e31b8aSbellard exit(-1); 120231e31b8aSbellard return 0; 120331e31b8aSbellard } 120431e31b8aSbellard } 120531e31b8aSbellard 120631e31b8aSbellard free(elf_phdata); 120731e31b8aSbellard 1208689f936fSbellard if (loglevel) 1209689f936fSbellard load_symbols(&elf_ex, bprm->fd); 1210689f936fSbellard 121131e31b8aSbellard if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); 121231e31b8aSbellard info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); 121331e31b8aSbellard 121431e31b8aSbellard #ifdef LOW_ELF_STACK 121531e31b8aSbellard info->start_stack = bprm->p = elf_stack - 4; 121631e31b8aSbellard #endif 121731e31b8aSbellard bprm->p = (unsigned long) 121831e31b8aSbellard create_elf_tables((char *)bprm->p, 121931e31b8aSbellard bprm->argc, 122031e31b8aSbellard bprm->envc, 1221a1516e92Sbellard &elf_ex, 122209bfb054Sbellard load_addr, load_bias, 122331e31b8aSbellard interp_load_addr, 122431e31b8aSbellard (interpreter_type == INTERPRETER_AOUT ? 0 : 1), 122531e31b8aSbellard info); 122631e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) 122731e31b8aSbellard info->arg_start += strlen(passed_fileno) + 1; 122831e31b8aSbellard info->start_brk = info->brk = elf_brk; 122931e31b8aSbellard info->end_code = end_code; 123031e31b8aSbellard info->start_code = start_code; 123131e31b8aSbellard info->end_data = end_data; 123231e31b8aSbellard info->start_stack = bprm->p; 123331e31b8aSbellard 123431e31b8aSbellard /* Calling set_brk effectively mmaps the pages that we need for the bss and break 123531e31b8aSbellard sections */ 123631e31b8aSbellard set_brk(elf_bss, elf_brk); 123731e31b8aSbellard 123831e31b8aSbellard padzero(elf_bss); 123931e31b8aSbellard 124031e31b8aSbellard #if 0 124131e31b8aSbellard printf("(start_brk) %x\n" , info->start_brk); 124231e31b8aSbellard printf("(end_code) %x\n" , info->end_code); 124331e31b8aSbellard printf("(start_code) %x\n" , info->start_code); 124431e31b8aSbellard printf("(end_data) %x\n" , info->end_data); 124531e31b8aSbellard printf("(start_stack) %x\n" , info->start_stack); 124631e31b8aSbellard printf("(brk) %x\n" , info->brk); 124731e31b8aSbellard #endif 124831e31b8aSbellard 124931e31b8aSbellard if ( info->personality == PER_SVR4 ) 125031e31b8aSbellard { 125131e31b8aSbellard /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 125231e31b8aSbellard and some applications "depend" upon this behavior. 125331e31b8aSbellard Since we do not have the power to recompile these, we 125431e31b8aSbellard emulate the SVr4 behavior. Sigh. */ 125554936004Sbellard mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC, 125631e31b8aSbellard MAP_FIXED | MAP_PRIVATE, -1, 0); 125731e31b8aSbellard } 125831e31b8aSbellard 125931e31b8aSbellard #ifdef ELF_PLAT_INIT 126031e31b8aSbellard /* 126131e31b8aSbellard * The ABI may specify that certain registers be set up in special 126231e31b8aSbellard * ways (on i386 %edx is the address of a DT_FINI function, for 126331e31b8aSbellard * example. This macro performs whatever initialization to 126431e31b8aSbellard * the regs structure is required. 126531e31b8aSbellard */ 126631e31b8aSbellard ELF_PLAT_INIT(regs); 126731e31b8aSbellard #endif 126831e31b8aSbellard 126931e31b8aSbellard 127031e31b8aSbellard info->entry = elf_entry; 127131e31b8aSbellard 127231e31b8aSbellard return 0; 127331e31b8aSbellard } 127431e31b8aSbellard 127531e31b8aSbellard 127631e31b8aSbellard 127732ce6337Sbellard int elf_exec(const char * filename, char ** argv, char ** envp, 1278b17780d5Sbellard struct target_pt_regs * regs, struct image_info *infop) 127931e31b8aSbellard { 128031e31b8aSbellard struct linux_binprm bprm; 128131e31b8aSbellard int retval; 128231e31b8aSbellard int i; 128331e31b8aSbellard 128454936004Sbellard bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); 128531e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ 128631e31b8aSbellard bprm.page[i] = 0; 128731e31b8aSbellard retval = open(filename, O_RDONLY); 1288c2735790Sbellard if (retval < 0) 1289c2735790Sbellard return retval; 129031e31b8aSbellard bprm.fd = retval; 129131e31b8aSbellard bprm.filename = (char *)filename; 129231e31b8aSbellard bprm.sh_bang = 0; 129331e31b8aSbellard bprm.loader = 0; 129431e31b8aSbellard bprm.exec = 0; 129531e31b8aSbellard bprm.dont_iput = 0; 129631e31b8aSbellard bprm.argc = count(argv); 129731e31b8aSbellard bprm.envc = count(envp); 129831e31b8aSbellard 129931e31b8aSbellard retval = prepare_binprm(&bprm); 130031e31b8aSbellard 130131e31b8aSbellard if(retval>=0) { 130231e31b8aSbellard bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p); 130331e31b8aSbellard bprm.exec = bprm.p; 130431e31b8aSbellard bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p); 130531e31b8aSbellard bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p); 130631e31b8aSbellard if (!bprm.p) { 130731e31b8aSbellard retval = -E2BIG; 130831e31b8aSbellard } 130931e31b8aSbellard } 131031e31b8aSbellard 131131e31b8aSbellard if(retval>=0) { 131231e31b8aSbellard retval = load_elf_binary(&bprm,regs,infop); 131331e31b8aSbellard } 131431e31b8aSbellard if(retval>=0) { 131531e31b8aSbellard /* success. Initialize important registers */ 1316b346ff46Sbellard init_thread(regs, infop); 131731e31b8aSbellard return retval; 131831e31b8aSbellard } 131931e31b8aSbellard 132031e31b8aSbellard /* Something went wrong, return the inode and free the argument pages*/ 132131e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) { 132231e31b8aSbellard free_page((void *)bprm.page[i]); 132331e31b8aSbellard } 132431e31b8aSbellard return(retval); 132531e31b8aSbellard } 132631e31b8aSbellard 132731e31b8aSbellard 132831e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd) 132931e31b8aSbellard { 133031e31b8aSbellard printf("a.out interpreter not yet supported\n"); 133131e31b8aSbellard return(0); 133231e31b8aSbellard } 133331e31b8aSbellard 1334