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 { \ 13067867308Sbellard unsigned long *pos = (unsigned long *)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 #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) 26709bfb054Sbellard #define get_user(ptr) (typeof(*ptr))(*(ptr)) 268d691f669Sbellard 26909bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) 27009bfb054Sbellard { 27109bfb054Sbellard memcpy(to, from, n); 27209bfb054Sbellard } 27309bfb054Sbellard 27409bfb054Sbellard static inline void memcpy_tofs(void * to, const void * from, unsigned long n) 27509bfb054Sbellard { 27609bfb054Sbellard memcpy(to, from, n); 27709bfb054Sbellard } 27831e31b8aSbellard 27931e31b8aSbellard extern unsigned long x86_stack_size; 28031e31b8aSbellard 28131e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd); 28231e31b8aSbellard 28331e31b8aSbellard #ifdef BSWAP_NEEDED 28431e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr) 28531e31b8aSbellard { 28631e31b8aSbellard bswap16s(&ehdr->e_type); /* Object file type */ 28731e31b8aSbellard bswap16s(&ehdr->e_machine); /* Architecture */ 28831e31b8aSbellard bswap32s(&ehdr->e_version); /* Object file version */ 28931e31b8aSbellard bswap32s(&ehdr->e_entry); /* Entry point virtual address */ 29031e31b8aSbellard bswap32s(&ehdr->e_phoff); /* Program header table file offset */ 29131e31b8aSbellard bswap32s(&ehdr->e_shoff); /* Section header table file offset */ 29231e31b8aSbellard bswap32s(&ehdr->e_flags); /* Processor-specific flags */ 29331e31b8aSbellard bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ 29431e31b8aSbellard bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ 29531e31b8aSbellard bswap16s(&ehdr->e_phnum); /* Program header table entry count */ 29631e31b8aSbellard bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ 29731e31b8aSbellard bswap16s(&ehdr->e_shnum); /* Section header table entry count */ 29831e31b8aSbellard bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ 29931e31b8aSbellard } 30031e31b8aSbellard 30131e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr) 30231e31b8aSbellard { 30331e31b8aSbellard bswap32s(&phdr->p_type); /* Segment type */ 30431e31b8aSbellard bswap32s(&phdr->p_offset); /* Segment file offset */ 30531e31b8aSbellard bswap32s(&phdr->p_vaddr); /* Segment virtual address */ 30631e31b8aSbellard bswap32s(&phdr->p_paddr); /* Segment physical address */ 30731e31b8aSbellard bswap32s(&phdr->p_filesz); /* Segment size in file */ 30831e31b8aSbellard bswap32s(&phdr->p_memsz); /* Segment size in memory */ 30931e31b8aSbellard bswap32s(&phdr->p_flags); /* Segment flags */ 31031e31b8aSbellard bswap32s(&phdr->p_align); /* Segment alignment */ 31131e31b8aSbellard } 312689f936fSbellard 313689f936fSbellard static void bswap_shdr(Elf32_Shdr *shdr) 314689f936fSbellard { 315689f936fSbellard bswap32s(&shdr->sh_name); 316689f936fSbellard bswap32s(&shdr->sh_type); 317689f936fSbellard bswap32s(&shdr->sh_flags); 318689f936fSbellard bswap32s(&shdr->sh_addr); 319689f936fSbellard bswap32s(&shdr->sh_offset); 320689f936fSbellard bswap32s(&shdr->sh_size); 321689f936fSbellard bswap32s(&shdr->sh_link); 322689f936fSbellard bswap32s(&shdr->sh_info); 323689f936fSbellard bswap32s(&shdr->sh_addralign); 324689f936fSbellard bswap32s(&shdr->sh_entsize); 325689f936fSbellard } 326689f936fSbellard 327689f936fSbellard static void bswap_sym(Elf32_Sym *sym) 328689f936fSbellard { 329689f936fSbellard bswap32s(&sym->st_name); 330689f936fSbellard bswap32s(&sym->st_value); 331689f936fSbellard bswap32s(&sym->st_size); 332689f936fSbellard bswap16s(&sym->st_shndx); 333689f936fSbellard } 33431e31b8aSbellard #endif 33531e31b8aSbellard 33631e31b8aSbellard static void * get_free_page(void) 33731e31b8aSbellard { 33831e31b8aSbellard void * retval; 33931e31b8aSbellard 34031e31b8aSbellard /* User-space version of kernel get_free_page. Returns a page-aligned 34131e31b8aSbellard * page-sized chunk of memory. 34231e31b8aSbellard */ 34354936004Sbellard retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE, 34431e31b8aSbellard MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 34531e31b8aSbellard 34631e31b8aSbellard if((long)retval == -1) { 34731e31b8aSbellard perror("get_free_page"); 34831e31b8aSbellard exit(-1); 34931e31b8aSbellard } 35031e31b8aSbellard else { 35131e31b8aSbellard return(retval); 35231e31b8aSbellard } 35331e31b8aSbellard } 35431e31b8aSbellard 35531e31b8aSbellard static void free_page(void * pageaddr) 35631e31b8aSbellard { 35754936004Sbellard target_munmap((unsigned long)pageaddr, host_page_size); 35831e31b8aSbellard } 35931e31b8aSbellard 36031e31b8aSbellard /* 36131e31b8aSbellard * 'copy_string()' copies argument/envelope strings from user 36231e31b8aSbellard * memory to free pages in kernel mem. These are in a format ready 36331e31b8aSbellard * to be put directly into the top of new user memory. 36431e31b8aSbellard * 36531e31b8aSbellard */ 36631e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, 36731e31b8aSbellard unsigned long p) 36831e31b8aSbellard { 36931e31b8aSbellard char *tmp, *tmp1, *pag = NULL; 37031e31b8aSbellard int len, offset = 0; 37131e31b8aSbellard 37231e31b8aSbellard if (!p) { 37331e31b8aSbellard return 0; /* bullet-proofing */ 37431e31b8aSbellard } 37531e31b8aSbellard while (argc-- > 0) { 37631e31b8aSbellard if (!(tmp1 = tmp = get_user(argv+argc))) { 37731e31b8aSbellard fprintf(stderr, "VFS: argc is wrong"); 37831e31b8aSbellard exit(-1); 37931e31b8aSbellard } 38031e31b8aSbellard while (get_user(tmp++)); 38131e31b8aSbellard len = tmp - tmp1; 38231e31b8aSbellard if (p < len) { /* this shouldn't happen - 128kB */ 38331e31b8aSbellard return 0; 38431e31b8aSbellard } 38531e31b8aSbellard while (len) { 38631e31b8aSbellard --p; --tmp; --len; 38731e31b8aSbellard if (--offset < 0) { 38854936004Sbellard offset = p % TARGET_PAGE_SIZE; 38944a91caeSbellard pag = (char *) page[p/TARGET_PAGE_SIZE]; 39044a91caeSbellard if (!pag) { 39144a91caeSbellard pag = (char *)get_free_page(); 39244a91caeSbellard page[p/TARGET_PAGE_SIZE] = (unsigned long)pag; 39344a91caeSbellard if (!pag) 39431e31b8aSbellard return 0; 39531e31b8aSbellard } 39631e31b8aSbellard } 39731e31b8aSbellard if (len == 0 || offset == 0) { 39831e31b8aSbellard *(pag + offset) = get_user(tmp); 39931e31b8aSbellard } 40031e31b8aSbellard else { 40131e31b8aSbellard int bytes_to_copy = (len > offset) ? offset : len; 40231e31b8aSbellard tmp -= bytes_to_copy; 40331e31b8aSbellard p -= bytes_to_copy; 40431e31b8aSbellard offset -= bytes_to_copy; 40531e31b8aSbellard len -= bytes_to_copy; 40631e31b8aSbellard memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); 40731e31b8aSbellard } 40831e31b8aSbellard } 40931e31b8aSbellard } 41031e31b8aSbellard return p; 41131e31b8aSbellard } 41231e31b8aSbellard 41331e31b8aSbellard static int in_group_p(gid_t g) 41431e31b8aSbellard { 41531e31b8aSbellard /* return TRUE if we're in the specified group, FALSE otherwise */ 41631e31b8aSbellard int ngroup; 41731e31b8aSbellard int i; 41831e31b8aSbellard gid_t grouplist[NGROUPS]; 41931e31b8aSbellard 42031e31b8aSbellard ngroup = getgroups(NGROUPS, grouplist); 42131e31b8aSbellard for(i = 0; i < ngroup; i++) { 42231e31b8aSbellard if(grouplist[i] == g) { 42331e31b8aSbellard return 1; 42431e31b8aSbellard } 42531e31b8aSbellard } 42631e31b8aSbellard return 0; 42731e31b8aSbellard } 42831e31b8aSbellard 42931e31b8aSbellard static int count(char ** vec) 43031e31b8aSbellard { 43131e31b8aSbellard int i; 43231e31b8aSbellard 43331e31b8aSbellard for(i = 0; *vec; i++) { 43431e31b8aSbellard vec++; 43531e31b8aSbellard } 43631e31b8aSbellard 43731e31b8aSbellard return(i); 43831e31b8aSbellard } 43931e31b8aSbellard 44031e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm) 44131e31b8aSbellard { 44231e31b8aSbellard struct stat st; 44331e31b8aSbellard int mode; 44431e31b8aSbellard int retval, id_change; 44531e31b8aSbellard 44631e31b8aSbellard if(fstat(bprm->fd, &st) < 0) { 44731e31b8aSbellard return(-errno); 44831e31b8aSbellard } 44931e31b8aSbellard 45031e31b8aSbellard mode = st.st_mode; 45131e31b8aSbellard if(!S_ISREG(mode)) { /* Must be regular file */ 45231e31b8aSbellard return(-EACCES); 45331e31b8aSbellard } 45431e31b8aSbellard if(!(mode & 0111)) { /* Must have at least one execute bit set */ 45531e31b8aSbellard return(-EACCES); 45631e31b8aSbellard } 45731e31b8aSbellard 45831e31b8aSbellard bprm->e_uid = geteuid(); 45931e31b8aSbellard bprm->e_gid = getegid(); 46031e31b8aSbellard id_change = 0; 46131e31b8aSbellard 46231e31b8aSbellard /* Set-uid? */ 46331e31b8aSbellard if(mode & S_ISUID) { 46431e31b8aSbellard bprm->e_uid = st.st_uid; 46531e31b8aSbellard if(bprm->e_uid != geteuid()) { 46631e31b8aSbellard id_change = 1; 46731e31b8aSbellard } 46831e31b8aSbellard } 46931e31b8aSbellard 47031e31b8aSbellard /* Set-gid? */ 47131e31b8aSbellard /* 47231e31b8aSbellard * If setgid is set but no group execute bit then this 47331e31b8aSbellard * is a candidate for mandatory locking, not a setgid 47431e31b8aSbellard * executable. 47531e31b8aSbellard */ 47631e31b8aSbellard if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 47731e31b8aSbellard bprm->e_gid = st.st_gid; 47831e31b8aSbellard if (!in_group_p(bprm->e_gid)) { 47931e31b8aSbellard id_change = 1; 48031e31b8aSbellard } 48131e31b8aSbellard } 48231e31b8aSbellard 48331e31b8aSbellard memset(bprm->buf, 0, sizeof(bprm->buf)); 48431e31b8aSbellard retval = lseek(bprm->fd, 0L, SEEK_SET); 48531e31b8aSbellard if(retval >= 0) { 48631e31b8aSbellard retval = read(bprm->fd, bprm->buf, 128); 48731e31b8aSbellard } 48831e31b8aSbellard if(retval < 0) { 48931e31b8aSbellard perror("prepare_binprm"); 49031e31b8aSbellard exit(-1); 49131e31b8aSbellard /* return(-errno); */ 49231e31b8aSbellard } 49331e31b8aSbellard else { 49431e31b8aSbellard return(retval); 49531e31b8aSbellard } 49631e31b8aSbellard } 49731e31b8aSbellard 49831e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, 49931e31b8aSbellard struct image_info * info) 50031e31b8aSbellard { 50109bfb054Sbellard unsigned long stack_base, size, error; 50231e31b8aSbellard int i; 50331e31b8aSbellard 50431e31b8aSbellard /* Create enough stack to hold everything. If we don't use 50531e31b8aSbellard * it for args, we'll use it for something else... 50631e31b8aSbellard */ 50709bfb054Sbellard size = x86_stack_size; 50854936004Sbellard if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) 50954936004Sbellard size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; 51054936004Sbellard error = target_mmap(0, 51154936004Sbellard size + host_page_size, 51231e31b8aSbellard PROT_READ | PROT_WRITE, 51309bfb054Sbellard MAP_PRIVATE | MAP_ANONYMOUS, 51409bfb054Sbellard -1, 0); 51509bfb054Sbellard if (error == -1) { 51631e31b8aSbellard perror("stk mmap"); 51731e31b8aSbellard exit(-1); 51831e31b8aSbellard } 51909bfb054Sbellard /* we reserve one extra page at the top of the stack as guard */ 52054936004Sbellard target_mprotect(error + size, host_page_size, PROT_NONE); 52131e31b8aSbellard 52254936004Sbellard stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; 52309bfb054Sbellard p += stack_base; 52409bfb054Sbellard 52509bfb054Sbellard if (bprm->loader) { 52609bfb054Sbellard bprm->loader += stack_base; 52709bfb054Sbellard } 52809bfb054Sbellard bprm->exec += stack_base; 52931e31b8aSbellard 53031e31b8aSbellard for (i = 0 ; i < MAX_ARG_PAGES ; i++) { 53131e31b8aSbellard if (bprm->page[i]) { 53231e31b8aSbellard info->rss++; 53331e31b8aSbellard 53454936004Sbellard memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE); 53531e31b8aSbellard free_page((void *)bprm->page[i]); 53631e31b8aSbellard } 53754936004Sbellard stack_base += TARGET_PAGE_SIZE; 53831e31b8aSbellard } 53931e31b8aSbellard return p; 54031e31b8aSbellard } 54131e31b8aSbellard 54231e31b8aSbellard static void set_brk(unsigned long start, unsigned long end) 54331e31b8aSbellard { 54431e31b8aSbellard /* page-align the start and end addresses... */ 54554936004Sbellard start = HOST_PAGE_ALIGN(start); 54654936004Sbellard end = HOST_PAGE_ALIGN(end); 54731e31b8aSbellard if (end <= start) 54831e31b8aSbellard return; 54954936004Sbellard if(target_mmap(start, end - start, 55031e31b8aSbellard PROT_READ | PROT_WRITE | PROT_EXEC, 55131e31b8aSbellard MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { 55231e31b8aSbellard perror("cannot mmap brk"); 55331e31b8aSbellard exit(-1); 55431e31b8aSbellard } 55531e31b8aSbellard } 55631e31b8aSbellard 55731e31b8aSbellard 558853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data 559853d6f7aSbellard section (i.e. bss). This would contain the junk from the file that 560853d6f7aSbellard should not be in memory. */ 56131e31b8aSbellard static void padzero(unsigned long elf_bss) 56231e31b8aSbellard { 56331e31b8aSbellard unsigned long nbyte; 56431e31b8aSbellard char * fpnt; 56531e31b8aSbellard 566853d6f7aSbellard /* XXX: this is really a hack : if the real host page size is 567853d6f7aSbellard smaller than the target page size, some pages after the end 568853d6f7aSbellard of the file may not be mapped. A better fix would be to 569853d6f7aSbellard patch target_mmap(), but it is more complicated as the file 570853d6f7aSbellard size must be known */ 571853d6f7aSbellard if (real_host_page_size < host_page_size) { 572853d6f7aSbellard unsigned long end_addr, end_addr1; 573853d6f7aSbellard end_addr1 = (elf_bss + real_host_page_size - 1) & 574853d6f7aSbellard ~(real_host_page_size - 1); 575853d6f7aSbellard end_addr = HOST_PAGE_ALIGN(elf_bss); 576853d6f7aSbellard if (end_addr1 < end_addr) { 577853d6f7aSbellard mmap((void *)end_addr1, end_addr - end_addr1, 578853d6f7aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 579853d6f7aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 580853d6f7aSbellard } 581853d6f7aSbellard } 582853d6f7aSbellard 583853d6f7aSbellard nbyte = elf_bss & (host_page_size-1); 58431e31b8aSbellard if (nbyte) { 58554936004Sbellard nbyte = host_page_size - nbyte; 58631e31b8aSbellard fpnt = (char *) elf_bss; 58731e31b8aSbellard do { 58831e31b8aSbellard *fpnt++ = 0; 58931e31b8aSbellard } while (--nbyte); 59031e31b8aSbellard } 59131e31b8aSbellard } 59231e31b8aSbellard 59331e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc, 59431e31b8aSbellard struct elfhdr * exec, 59531e31b8aSbellard unsigned long load_addr, 59609bfb054Sbellard unsigned long load_bias, 59731e31b8aSbellard unsigned long interp_load_addr, int ibcs, 59831e31b8aSbellard struct image_info *info) 59931e31b8aSbellard { 600f5155289Sbellard target_ulong *argv, *envp; 601f5155289Sbellard target_ulong *sp, *csp; 60231e31b8aSbellard 60331e31b8aSbellard /* 604f5155289Sbellard * Force 16 byte _final_ alignment here for generality. 60531e31b8aSbellard */ 60631e31b8aSbellard sp = (unsigned int *) (~15UL & (unsigned long) p); 607f5155289Sbellard csp = sp; 608f5155289Sbellard csp -= (DLINFO_ITEMS + 1) * 2; 609f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS 610f5155289Sbellard csp -= DLINFO_ARCH_ITEMS*2; 611f5155289Sbellard #endif 612f5155289Sbellard csp -= envc+1; 613f5155289Sbellard csp -= argc+1; 614f5155289Sbellard csp -= (!ibcs ? 3 : 1); /* argc itself */ 615f5155289Sbellard if ((unsigned long)csp & 15UL) 616f5155289Sbellard sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); 617f5155289Sbellard 618f5155289Sbellard #define NEW_AUX_ENT(nr, id, val) \ 619f5155289Sbellard put_user (tswapl(id), sp + (nr * 2)); \ 620f5155289Sbellard put_user (tswapl(val), sp + (nr * 2 + 1)) 621f5155289Sbellard sp -= 2; 622f5155289Sbellard NEW_AUX_ENT (0, AT_NULL, 0); 623f5155289Sbellard 624a1516e92Sbellard sp -= DLINFO_ITEMS*2; 625f5155289Sbellard NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); 626f5155289Sbellard NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); 627f5155289Sbellard NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum)); 628f5155289Sbellard NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); 629f5155289Sbellard NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr)); 630f5155289Sbellard NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0); 631f5155289Sbellard NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry); 632f5155289Sbellard NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid()); 633f5155289Sbellard NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid()); 634f5155289Sbellard NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid()); 635f5155289Sbellard NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid()); 636f5155289Sbellard #ifdef ARCH_DLINFO 637f5155289Sbellard /* 638f5155289Sbellard * ARCH_DLINFO must come last so platform specific code can enforce 639f5155289Sbellard * special alignment requirements on the AUXV if necessary (eg. PPC). 640f5155289Sbellard */ 641f5155289Sbellard ARCH_DLINFO; 642f5155289Sbellard #endif 643f5155289Sbellard #undef NEW_AUX_ENT 644f5155289Sbellard 64531e31b8aSbellard sp -= envc+1; 64631e31b8aSbellard envp = sp; 64731e31b8aSbellard sp -= argc+1; 64831e31b8aSbellard argv = sp; 64931e31b8aSbellard if (!ibcs) { 650b17780d5Sbellard put_user(tswapl((target_ulong)envp),--sp); 651b17780d5Sbellard put_user(tswapl((target_ulong)argv),--sp); 65231e31b8aSbellard } 653b17780d5Sbellard put_user(tswapl(argc),--sp); 65431e31b8aSbellard info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); 65531e31b8aSbellard while (argc-->0) { 656b17780d5Sbellard put_user(tswapl((target_ulong)p),argv++); 65731e31b8aSbellard while (get_user(p++)) /* nothing */ ; 65831e31b8aSbellard } 65931e31b8aSbellard put_user(0,argv); 66031e31b8aSbellard info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); 66131e31b8aSbellard while (envc-->0) { 662b17780d5Sbellard put_user(tswapl((target_ulong)p),envp++); 66331e31b8aSbellard while (get_user(p++)) /* nothing */ ; 66431e31b8aSbellard } 66531e31b8aSbellard put_user(0,envp); 66631e31b8aSbellard info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); 66731e31b8aSbellard return sp; 66831e31b8aSbellard } 66931e31b8aSbellard 67031e31b8aSbellard 67131e31b8aSbellard 67231e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, 67331e31b8aSbellard int interpreter_fd, 67431e31b8aSbellard unsigned long *interp_load_addr) 67531e31b8aSbellard { 67631e31b8aSbellard struct elf_phdr *elf_phdata = NULL; 67731e31b8aSbellard struct elf_phdr *eppnt; 67809bfb054Sbellard unsigned long load_addr = 0; 67931e31b8aSbellard int load_addr_set = 0; 68031e31b8aSbellard int retval; 68131e31b8aSbellard unsigned long last_bss, elf_bss; 68231e31b8aSbellard unsigned long error; 68331e31b8aSbellard int i; 68431e31b8aSbellard 68531e31b8aSbellard elf_bss = 0; 68631e31b8aSbellard last_bss = 0; 68731e31b8aSbellard error = 0; 68831e31b8aSbellard 689644c433cSbellard #ifdef BSWAP_NEEDED 690644c433cSbellard bswap_ehdr(interp_elf_ex); 691644c433cSbellard #endif 69231e31b8aSbellard /* First of all, some simple consistency checks */ 69331e31b8aSbellard if ((interp_elf_ex->e_type != ET_EXEC && 69431e31b8aSbellard interp_elf_ex->e_type != ET_DYN) || 69531e31b8aSbellard !elf_check_arch(interp_elf_ex->e_machine)) { 69631e31b8aSbellard return ~0UL; 69731e31b8aSbellard } 69831e31b8aSbellard 699644c433cSbellard 70031e31b8aSbellard /* Now read in all of the header information */ 70131e31b8aSbellard 70254936004Sbellard if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) 70331e31b8aSbellard return ~0UL; 70431e31b8aSbellard 70531e31b8aSbellard elf_phdata = (struct elf_phdr *) 70631e31b8aSbellard malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 70731e31b8aSbellard 70831e31b8aSbellard if (!elf_phdata) 70931e31b8aSbellard return ~0UL; 71031e31b8aSbellard 71131e31b8aSbellard /* 71231e31b8aSbellard * If the size of this structure has changed, then punt, since 71331e31b8aSbellard * we will be doing the wrong thing. 71431e31b8aSbellard */ 71509bfb054Sbellard if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { 71631e31b8aSbellard free(elf_phdata); 71731e31b8aSbellard return ~0UL; 71831e31b8aSbellard } 71931e31b8aSbellard 72031e31b8aSbellard retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); 72131e31b8aSbellard if(retval >= 0) { 72231e31b8aSbellard retval = read(interpreter_fd, 72331e31b8aSbellard (char *) elf_phdata, 72431e31b8aSbellard sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); 72531e31b8aSbellard } 72631e31b8aSbellard if (retval < 0) { 72731e31b8aSbellard perror("load_elf_interp"); 72831e31b8aSbellard exit(-1); 72931e31b8aSbellard free (elf_phdata); 73031e31b8aSbellard return retval; 73131e31b8aSbellard } 73231e31b8aSbellard #ifdef BSWAP_NEEDED 73331e31b8aSbellard eppnt = elf_phdata; 73431e31b8aSbellard for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { 73531e31b8aSbellard bswap_phdr(eppnt); 73631e31b8aSbellard } 73731e31b8aSbellard #endif 73809bfb054Sbellard 73909bfb054Sbellard if (interp_elf_ex->e_type == ET_DYN) { 74009bfb054Sbellard /* in order to avoid harcoding the interpreter load 74109bfb054Sbellard address in qemu, we allocate a big enough memory zone */ 74254936004Sbellard error = target_mmap(0, INTERP_MAP_SIZE, 74309bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 74409bfb054Sbellard -1, 0); 74509bfb054Sbellard if (error == -1) { 74609bfb054Sbellard perror("mmap"); 74709bfb054Sbellard exit(-1); 74809bfb054Sbellard } 74909bfb054Sbellard load_addr = error; 75009bfb054Sbellard load_addr_set = 1; 75109bfb054Sbellard } 75209bfb054Sbellard 75331e31b8aSbellard eppnt = elf_phdata; 75431e31b8aSbellard for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) 75531e31b8aSbellard if (eppnt->p_type == PT_LOAD) { 75631e31b8aSbellard int elf_type = MAP_PRIVATE | MAP_DENYWRITE; 75731e31b8aSbellard int elf_prot = 0; 75831e31b8aSbellard unsigned long vaddr = 0; 75931e31b8aSbellard unsigned long k; 76031e31b8aSbellard 76131e31b8aSbellard if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; 76231e31b8aSbellard if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 76331e31b8aSbellard if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 76431e31b8aSbellard if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { 76531e31b8aSbellard elf_type |= MAP_FIXED; 76631e31b8aSbellard vaddr = eppnt->p_vaddr; 76731e31b8aSbellard } 76854936004Sbellard error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), 76954936004Sbellard eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), 77031e31b8aSbellard elf_prot, 77131e31b8aSbellard elf_type, 77231e31b8aSbellard interpreter_fd, 77354936004Sbellard eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); 77431e31b8aSbellard 77531e31b8aSbellard if (error > -1024UL) { 77631e31b8aSbellard /* Real error */ 77731e31b8aSbellard close(interpreter_fd); 77831e31b8aSbellard free(elf_phdata); 77931e31b8aSbellard return ~0UL; 78031e31b8aSbellard } 78131e31b8aSbellard 78231e31b8aSbellard if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { 78331e31b8aSbellard load_addr = error; 78431e31b8aSbellard load_addr_set = 1; 78531e31b8aSbellard } 78631e31b8aSbellard 78731e31b8aSbellard /* 78831e31b8aSbellard * Find the end of the file mapping for this phdr, and keep 78931e31b8aSbellard * track of the largest address we see for this. 79031e31b8aSbellard */ 79131e31b8aSbellard k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; 79231e31b8aSbellard if (k > elf_bss) elf_bss = k; 79331e31b8aSbellard 79431e31b8aSbellard /* 79531e31b8aSbellard * Do the same thing for the memory mapping - between 79631e31b8aSbellard * elf_bss and last_bss is the bss section. 79731e31b8aSbellard */ 79831e31b8aSbellard k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; 79931e31b8aSbellard if (k > last_bss) last_bss = k; 80031e31b8aSbellard } 80131e31b8aSbellard 80231e31b8aSbellard /* Now use mmap to map the library into memory. */ 80331e31b8aSbellard 80431e31b8aSbellard close(interpreter_fd); 80531e31b8aSbellard 80631e31b8aSbellard /* 80731e31b8aSbellard * Now fill out the bss section. First pad the last page up 80831e31b8aSbellard * to the page boundary, and then perform a mmap to make sure 80931e31b8aSbellard * that there are zeromapped pages up to and including the last 81031e31b8aSbellard * bss page. 81131e31b8aSbellard */ 81231e31b8aSbellard padzero(elf_bss); 81354936004Sbellard elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */ 81431e31b8aSbellard 81531e31b8aSbellard /* Map the last of the bss segment */ 81631e31b8aSbellard if (last_bss > elf_bss) { 81754936004Sbellard target_mmap(elf_bss, last_bss-elf_bss, 81831e31b8aSbellard PROT_READ|PROT_WRITE|PROT_EXEC, 81931e31b8aSbellard MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 82031e31b8aSbellard } 82131e31b8aSbellard free(elf_phdata); 82231e31b8aSbellard 82331e31b8aSbellard *interp_load_addr = load_addr; 82431e31b8aSbellard return ((unsigned long) interp_elf_ex->e_entry) + load_addr; 82531e31b8aSbellard } 82631e31b8aSbellard 827689f936fSbellard /* Best attempt to load symbols from this ELF object. */ 828689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd) 829689f936fSbellard { 830689f936fSbellard unsigned int i; 831689f936fSbellard struct elf_shdr sechdr, symtab, strtab; 832689f936fSbellard char *strings; 83331e31b8aSbellard 834689f936fSbellard lseek(fd, hdr->e_shoff, SEEK_SET); 835689f936fSbellard for (i = 0; i < hdr->e_shnum; i++) { 836689f936fSbellard if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) 837689f936fSbellard return; 838689f936fSbellard #ifdef BSWAP_NEEDED 839689f936fSbellard bswap_shdr(&sechdr); 840689f936fSbellard #endif 841689f936fSbellard if (sechdr.sh_type == SHT_SYMTAB) { 842689f936fSbellard symtab = sechdr; 843689f936fSbellard lseek(fd, hdr->e_shoff 844689f936fSbellard + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); 845689f936fSbellard if (read(fd, &strtab, sizeof(strtab)) 846689f936fSbellard != sizeof(strtab)) 847689f936fSbellard return; 848689f936fSbellard #ifdef BSWAP_NEEDED 849689f936fSbellard bswap_shdr(&strtab); 850689f936fSbellard #endif 851689f936fSbellard goto found; 852689f936fSbellard } 853689f936fSbellard } 854689f936fSbellard return; /* Shouldn't happen... */ 855689f936fSbellard 856689f936fSbellard found: 857689f936fSbellard /* Now know where the strtab and symtab are. Snarf them. */ 858689f936fSbellard disas_symtab = malloc(symtab.sh_size); 859689f936fSbellard disas_strtab = strings = malloc(strtab.sh_size); 860689f936fSbellard if (!disas_symtab || !disas_strtab) 861689f936fSbellard return; 862689f936fSbellard 863689f936fSbellard lseek(fd, symtab.sh_offset, SEEK_SET); 864689f936fSbellard if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) 865689f936fSbellard return; 866689f936fSbellard 867689f936fSbellard #ifdef BSWAP_NEEDED 868689f936fSbellard for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) 869689f936fSbellard bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); 870689f936fSbellard #endif 871689f936fSbellard 872689f936fSbellard lseek(fd, strtab.sh_offset, SEEK_SET); 873689f936fSbellard if (read(fd, strings, strtab.sh_size) != strtab.sh_size) 874689f936fSbellard return; 875689f936fSbellard disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); 876689f936fSbellard } 87731e31b8aSbellard 878b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, 87931e31b8aSbellard struct image_info * info) 88031e31b8aSbellard { 88131e31b8aSbellard struct elfhdr elf_ex; 88231e31b8aSbellard struct elfhdr interp_elf_ex; 88331e31b8aSbellard struct exec interp_ex; 88431e31b8aSbellard int interpreter_fd = -1; /* avoid warning */ 88509bfb054Sbellard unsigned long load_addr, load_bias; 88631e31b8aSbellard int load_addr_set = 0; 88731e31b8aSbellard unsigned int interpreter_type = INTERPRETER_NONE; 88831e31b8aSbellard unsigned char ibcs2_interpreter; 88931e31b8aSbellard int i; 89054936004Sbellard unsigned long mapped_addr; 89131e31b8aSbellard struct elf_phdr * elf_ppnt; 89231e31b8aSbellard struct elf_phdr *elf_phdata; 89331e31b8aSbellard unsigned long elf_bss, k, elf_brk; 89431e31b8aSbellard int retval; 89531e31b8aSbellard char * elf_interpreter; 89631e31b8aSbellard unsigned long elf_entry, interp_load_addr = 0; 89731e31b8aSbellard int status; 89831e31b8aSbellard unsigned long start_code, end_code, end_data; 89931e31b8aSbellard unsigned long elf_stack; 90031e31b8aSbellard char passed_fileno[6]; 90131e31b8aSbellard 90231e31b8aSbellard ibcs2_interpreter = 0; 90331e31b8aSbellard status = 0; 90431e31b8aSbellard load_addr = 0; 90509bfb054Sbellard load_bias = 0; 90631e31b8aSbellard elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ 90731e31b8aSbellard #ifdef BSWAP_NEEDED 90831e31b8aSbellard bswap_ehdr(&elf_ex); 90931e31b8aSbellard #endif 91031e31b8aSbellard 91131e31b8aSbellard if (elf_ex.e_ident[0] != 0x7f || 91231e31b8aSbellard strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { 91331e31b8aSbellard return -ENOEXEC; 91431e31b8aSbellard } 91531e31b8aSbellard 91631e31b8aSbellard /* First of all, some simple consistency checks */ 91731e31b8aSbellard if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || 91831e31b8aSbellard (! elf_check_arch(elf_ex.e_machine))) { 91931e31b8aSbellard return -ENOEXEC; 92031e31b8aSbellard } 92131e31b8aSbellard 92231e31b8aSbellard /* Now read in all of the header information */ 92331e31b8aSbellard elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); 92431e31b8aSbellard if (elf_phdata == NULL) { 92531e31b8aSbellard return -ENOMEM; 92631e31b8aSbellard } 92731e31b8aSbellard 92831e31b8aSbellard retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); 92931e31b8aSbellard if(retval > 0) { 93031e31b8aSbellard retval = read(bprm->fd, (char *) elf_phdata, 93131e31b8aSbellard elf_ex.e_phentsize * elf_ex.e_phnum); 93231e31b8aSbellard } 93331e31b8aSbellard 93431e31b8aSbellard if (retval < 0) { 93531e31b8aSbellard perror("load_elf_binary"); 93631e31b8aSbellard exit(-1); 93731e31b8aSbellard free (elf_phdata); 93831e31b8aSbellard return -errno; 93931e31b8aSbellard } 94031e31b8aSbellard 941b17780d5Sbellard #ifdef BSWAP_NEEDED 942b17780d5Sbellard elf_ppnt = elf_phdata; 943b17780d5Sbellard for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { 944b17780d5Sbellard bswap_phdr(elf_ppnt); 945b17780d5Sbellard } 946b17780d5Sbellard #endif 94731e31b8aSbellard elf_ppnt = elf_phdata; 94831e31b8aSbellard 94931e31b8aSbellard elf_bss = 0; 95031e31b8aSbellard elf_brk = 0; 95131e31b8aSbellard 95231e31b8aSbellard 95331e31b8aSbellard elf_stack = ~0UL; 95431e31b8aSbellard elf_interpreter = NULL; 95531e31b8aSbellard start_code = ~0UL; 95631e31b8aSbellard end_code = 0; 95731e31b8aSbellard end_data = 0; 95831e31b8aSbellard 95931e31b8aSbellard for(i=0;i < elf_ex.e_phnum; i++) { 96031e31b8aSbellard if (elf_ppnt->p_type == PT_INTERP) { 96131e31b8aSbellard if ( elf_interpreter != NULL ) 96231e31b8aSbellard { 96331e31b8aSbellard free (elf_phdata); 96431e31b8aSbellard free(elf_interpreter); 96531e31b8aSbellard close(bprm->fd); 96631e31b8aSbellard return -EINVAL; 96731e31b8aSbellard } 96831e31b8aSbellard 96931e31b8aSbellard /* This is the program interpreter used for 97031e31b8aSbellard * shared libraries - for now assume that this 97131e31b8aSbellard * is an a.out format binary 97231e31b8aSbellard */ 97331e31b8aSbellard 97432ce6337Sbellard elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); 97531e31b8aSbellard 97631e31b8aSbellard if (elf_interpreter == NULL) { 97731e31b8aSbellard free (elf_phdata); 97831e31b8aSbellard close(bprm->fd); 97931e31b8aSbellard return -ENOMEM; 98031e31b8aSbellard } 98131e31b8aSbellard 98231e31b8aSbellard retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); 98331e31b8aSbellard if(retval >= 0) { 98432ce6337Sbellard retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); 98531e31b8aSbellard } 98631e31b8aSbellard if(retval < 0) { 98731e31b8aSbellard perror("load_elf_binary2"); 98831e31b8aSbellard exit(-1); 98931e31b8aSbellard } 99031e31b8aSbellard 99131e31b8aSbellard /* If the program interpreter is one of these two, 99231e31b8aSbellard then assume an iBCS2 image. Otherwise assume 99331e31b8aSbellard a native linux image. */ 99431e31b8aSbellard 99531e31b8aSbellard /* JRP - Need to add X86 lib dir stuff here... */ 99631e31b8aSbellard 99731e31b8aSbellard if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || 99831e31b8aSbellard strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { 99931e31b8aSbellard ibcs2_interpreter = 1; 100031e31b8aSbellard } 100131e31b8aSbellard 100231e31b8aSbellard #if 0 100331e31b8aSbellard printf("Using ELF interpreter %s\n", elf_interpreter); 100431e31b8aSbellard #endif 100531e31b8aSbellard if (retval >= 0) { 100632ce6337Sbellard retval = open(path(elf_interpreter), O_RDONLY); 100731e31b8aSbellard if(retval >= 0) { 100831e31b8aSbellard interpreter_fd = retval; 100931e31b8aSbellard } 101031e31b8aSbellard else { 101131e31b8aSbellard perror(elf_interpreter); 101231e31b8aSbellard exit(-1); 101331e31b8aSbellard /* retval = -errno; */ 101431e31b8aSbellard } 101531e31b8aSbellard } 101631e31b8aSbellard 101731e31b8aSbellard if (retval >= 0) { 101831e31b8aSbellard retval = lseek(interpreter_fd, 0, SEEK_SET); 101931e31b8aSbellard if(retval >= 0) { 102031e31b8aSbellard retval = read(interpreter_fd,bprm->buf,128); 102131e31b8aSbellard } 102231e31b8aSbellard } 102331e31b8aSbellard if (retval >= 0) { 102431e31b8aSbellard interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ 102531e31b8aSbellard interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ 102631e31b8aSbellard } 102731e31b8aSbellard if (retval < 0) { 102831e31b8aSbellard perror("load_elf_binary3"); 102931e31b8aSbellard exit(-1); 103031e31b8aSbellard free (elf_phdata); 103131e31b8aSbellard free(elf_interpreter); 103231e31b8aSbellard close(bprm->fd); 103331e31b8aSbellard return retval; 103431e31b8aSbellard } 103531e31b8aSbellard } 103631e31b8aSbellard elf_ppnt++; 103731e31b8aSbellard } 103831e31b8aSbellard 103931e31b8aSbellard /* Some simple consistency checks for the interpreter */ 104031e31b8aSbellard if (elf_interpreter){ 104131e31b8aSbellard interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; 104231e31b8aSbellard 104331e31b8aSbellard /* Now figure out which format our binary is */ 104431e31b8aSbellard if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && 104531e31b8aSbellard (N_MAGIC(interp_ex) != QMAGIC)) { 104631e31b8aSbellard interpreter_type = INTERPRETER_ELF; 104731e31b8aSbellard } 104831e31b8aSbellard 104931e31b8aSbellard if (interp_elf_ex.e_ident[0] != 0x7f || 105031e31b8aSbellard strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { 105131e31b8aSbellard interpreter_type &= ~INTERPRETER_ELF; 105231e31b8aSbellard } 105331e31b8aSbellard 105431e31b8aSbellard if (!interpreter_type) { 105531e31b8aSbellard free(elf_interpreter); 105631e31b8aSbellard free(elf_phdata); 105731e31b8aSbellard close(bprm->fd); 105831e31b8aSbellard return -ELIBBAD; 105931e31b8aSbellard } 106031e31b8aSbellard } 106131e31b8aSbellard 106231e31b8aSbellard /* OK, we are done with that, now set up the arg stuff, 106331e31b8aSbellard and then start this sucker up */ 106431e31b8aSbellard 106531e31b8aSbellard if (!bprm->sh_bang) { 106631e31b8aSbellard char * passed_p; 106731e31b8aSbellard 106831e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) { 106931e31b8aSbellard sprintf(passed_fileno, "%d", bprm->fd); 107031e31b8aSbellard passed_p = passed_fileno; 107131e31b8aSbellard 107231e31b8aSbellard if (elf_interpreter) { 107331e31b8aSbellard bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); 107431e31b8aSbellard bprm->argc++; 107531e31b8aSbellard } 107631e31b8aSbellard } 107731e31b8aSbellard if (!bprm->p) { 107831e31b8aSbellard if (elf_interpreter) { 107931e31b8aSbellard free(elf_interpreter); 108031e31b8aSbellard } 108131e31b8aSbellard free (elf_phdata); 108231e31b8aSbellard close(bprm->fd); 108331e31b8aSbellard return -E2BIG; 108431e31b8aSbellard } 108531e31b8aSbellard } 108631e31b8aSbellard 108731e31b8aSbellard /* OK, This is the point of no return */ 108831e31b8aSbellard info->end_data = 0; 108931e31b8aSbellard info->end_code = 0; 109031e31b8aSbellard info->start_mmap = (unsigned long)ELF_START_MMAP; 109131e31b8aSbellard info->mmap = 0; 109231e31b8aSbellard elf_entry = (unsigned long) elf_ex.e_entry; 109331e31b8aSbellard 109431e31b8aSbellard /* Do this so that we can load the interpreter, if need be. We will 109531e31b8aSbellard change some of these later */ 109631e31b8aSbellard info->rss = 0; 109731e31b8aSbellard bprm->p = setup_arg_pages(bprm->p, bprm, info); 109831e31b8aSbellard info->start_stack = bprm->p; 109931e31b8aSbellard 110031e31b8aSbellard /* Now we do a little grungy work by mmaping the ELF image into 110131e31b8aSbellard * the correct location in memory. At this point, we assume that 110231e31b8aSbellard * the image should be loaded at fixed address, not at a variable 110331e31b8aSbellard * address. 110431e31b8aSbellard */ 110531e31b8aSbellard 110631e31b8aSbellard for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { 110731e31b8aSbellard int elf_prot = 0; 110809bfb054Sbellard int elf_flags = 0; 110909bfb054Sbellard unsigned long error; 111009bfb054Sbellard 111109bfb054Sbellard if (elf_ppnt->p_type != PT_LOAD) 111209bfb054Sbellard continue; 111309bfb054Sbellard 111431e31b8aSbellard if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; 111531e31b8aSbellard if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; 111631e31b8aSbellard if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; 111709bfb054Sbellard elf_flags = MAP_PRIVATE | MAP_DENYWRITE; 111809bfb054Sbellard if (elf_ex.e_type == ET_EXEC || load_addr_set) { 111909bfb054Sbellard elf_flags |= MAP_FIXED; 112009bfb054Sbellard } else if (elf_ex.e_type == ET_DYN) { 112109bfb054Sbellard /* Try and get dynamic programs out of the way of the default mmap 112209bfb054Sbellard base, as well as whatever program they might try to exec. This 112309bfb054Sbellard is because the brk will follow the loader, and is not movable. */ 112409bfb054Sbellard /* NOTE: for qemu, we do a big mmap to get enough space 112509bfb054Sbellard without harcoding any address */ 112654936004Sbellard error = target_mmap(0, ET_DYN_MAP_SIZE, 112709bfb054Sbellard PROT_NONE, MAP_PRIVATE | MAP_ANON, 112809bfb054Sbellard -1, 0); 112909bfb054Sbellard if (error == -1) { 113009bfb054Sbellard perror("mmap"); 113109bfb054Sbellard exit(-1); 113209bfb054Sbellard } 113354936004Sbellard load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); 113409bfb054Sbellard } 113531e31b8aSbellard 113654936004Sbellard error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), 113731e31b8aSbellard (elf_ppnt->p_filesz + 113854936004Sbellard TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), 113931e31b8aSbellard elf_prot, 114031e31b8aSbellard (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), 114131e31b8aSbellard bprm->fd, 114231e31b8aSbellard (elf_ppnt->p_offset - 114354936004Sbellard TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); 114409bfb054Sbellard if (error == -1) { 114531e31b8aSbellard perror("mmap"); 114631e31b8aSbellard exit(-1); 114731e31b8aSbellard } 114831e31b8aSbellard 114931e31b8aSbellard #ifdef LOW_ELF_STACK 115054936004Sbellard if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 115154936004Sbellard elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); 115231e31b8aSbellard #endif 115331e31b8aSbellard 115431e31b8aSbellard if (!load_addr_set) { 115531e31b8aSbellard load_addr_set = 1; 115609bfb054Sbellard load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; 115709bfb054Sbellard if (elf_ex.e_type == ET_DYN) { 115809bfb054Sbellard load_bias += error - 115954936004Sbellard TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); 116009bfb054Sbellard load_addr += load_bias; 116109bfb054Sbellard } 116231e31b8aSbellard } 116331e31b8aSbellard k = elf_ppnt->p_vaddr; 116409bfb054Sbellard if (k < start_code) 116509bfb054Sbellard start_code = k; 116631e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; 116709bfb054Sbellard if (k > elf_bss) 116809bfb054Sbellard elf_bss = k; 116931e31b8aSbellard if ((elf_ppnt->p_flags & PF_X) && end_code < k) 117031e31b8aSbellard end_code = k; 117109bfb054Sbellard if (end_data < k) 117209bfb054Sbellard end_data = k; 117331e31b8aSbellard k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; 117431e31b8aSbellard if (k > elf_brk) elf_brk = k; 117531e31b8aSbellard } 117609bfb054Sbellard 117709bfb054Sbellard elf_entry += load_bias; 117809bfb054Sbellard elf_bss += load_bias; 117909bfb054Sbellard elf_brk += load_bias; 118009bfb054Sbellard start_code += load_bias; 118109bfb054Sbellard end_code += load_bias; 118209bfb054Sbellard // start_data += load_bias; 118309bfb054Sbellard end_data += load_bias; 118431e31b8aSbellard 118531e31b8aSbellard if (elf_interpreter) { 118631e31b8aSbellard if (interpreter_type & 1) { 118731e31b8aSbellard elf_entry = load_aout_interp(&interp_ex, interpreter_fd); 118831e31b8aSbellard } 118931e31b8aSbellard else if (interpreter_type & 2) { 119031e31b8aSbellard elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, 119131e31b8aSbellard &interp_load_addr); 119231e31b8aSbellard } 119331e31b8aSbellard 119431e31b8aSbellard close(interpreter_fd); 119531e31b8aSbellard free(elf_interpreter); 119631e31b8aSbellard 119731e31b8aSbellard if (elf_entry == ~0UL) { 119831e31b8aSbellard printf("Unable to load interpreter\n"); 119931e31b8aSbellard free(elf_phdata); 120031e31b8aSbellard exit(-1); 120131e31b8aSbellard return 0; 120231e31b8aSbellard } 120331e31b8aSbellard } 120431e31b8aSbellard 120531e31b8aSbellard free(elf_phdata); 120631e31b8aSbellard 1207689f936fSbellard if (loglevel) 1208689f936fSbellard load_symbols(&elf_ex, bprm->fd); 1209689f936fSbellard 121031e31b8aSbellard if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); 121131e31b8aSbellard info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); 121231e31b8aSbellard 121331e31b8aSbellard #ifdef LOW_ELF_STACK 121431e31b8aSbellard info->start_stack = bprm->p = elf_stack - 4; 121531e31b8aSbellard #endif 121631e31b8aSbellard bprm->p = (unsigned long) 121731e31b8aSbellard create_elf_tables((char *)bprm->p, 121831e31b8aSbellard bprm->argc, 121931e31b8aSbellard bprm->envc, 1220a1516e92Sbellard &elf_ex, 122109bfb054Sbellard load_addr, load_bias, 122231e31b8aSbellard interp_load_addr, 122331e31b8aSbellard (interpreter_type == INTERPRETER_AOUT ? 0 : 1), 122431e31b8aSbellard info); 122531e31b8aSbellard if (interpreter_type == INTERPRETER_AOUT) 122631e31b8aSbellard info->arg_start += strlen(passed_fileno) + 1; 122731e31b8aSbellard info->start_brk = info->brk = elf_brk; 122831e31b8aSbellard info->end_code = end_code; 122931e31b8aSbellard info->start_code = start_code; 123031e31b8aSbellard info->end_data = end_data; 123131e31b8aSbellard info->start_stack = bprm->p; 123231e31b8aSbellard 123331e31b8aSbellard /* Calling set_brk effectively mmaps the pages that we need for the bss and break 123431e31b8aSbellard sections */ 123531e31b8aSbellard set_brk(elf_bss, elf_brk); 123631e31b8aSbellard 123731e31b8aSbellard padzero(elf_bss); 123831e31b8aSbellard 123931e31b8aSbellard #if 0 124031e31b8aSbellard printf("(start_brk) %x\n" , info->start_brk); 124131e31b8aSbellard printf("(end_code) %x\n" , info->end_code); 124231e31b8aSbellard printf("(start_code) %x\n" , info->start_code); 124331e31b8aSbellard printf("(end_data) %x\n" , info->end_data); 124431e31b8aSbellard printf("(start_stack) %x\n" , info->start_stack); 124531e31b8aSbellard printf("(brk) %x\n" , info->brk); 124631e31b8aSbellard #endif 124731e31b8aSbellard 124831e31b8aSbellard if ( info->personality == PER_SVR4 ) 124931e31b8aSbellard { 125031e31b8aSbellard /* Why this, you ask??? Well SVr4 maps page 0 as read-only, 125131e31b8aSbellard and some applications "depend" upon this behavior. 125231e31b8aSbellard Since we do not have the power to recompile these, we 125331e31b8aSbellard emulate the SVr4 behavior. Sigh. */ 125454936004Sbellard mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC, 125531e31b8aSbellard MAP_FIXED | MAP_PRIVATE, -1, 0); 125631e31b8aSbellard } 125731e31b8aSbellard 125831e31b8aSbellard #ifdef ELF_PLAT_INIT 125931e31b8aSbellard /* 126031e31b8aSbellard * The ABI may specify that certain registers be set up in special 126131e31b8aSbellard * ways (on i386 %edx is the address of a DT_FINI function, for 126231e31b8aSbellard * example. This macro performs whatever initialization to 126331e31b8aSbellard * the regs structure is required. 126431e31b8aSbellard */ 126531e31b8aSbellard ELF_PLAT_INIT(regs); 126631e31b8aSbellard #endif 126731e31b8aSbellard 126831e31b8aSbellard 126931e31b8aSbellard info->entry = elf_entry; 127031e31b8aSbellard 127131e31b8aSbellard return 0; 127231e31b8aSbellard } 127331e31b8aSbellard 127431e31b8aSbellard 127531e31b8aSbellard 127632ce6337Sbellard int elf_exec(const char * filename, char ** argv, char ** envp, 1277b17780d5Sbellard struct target_pt_regs * regs, struct image_info *infop) 127831e31b8aSbellard { 127931e31b8aSbellard struct linux_binprm bprm; 128031e31b8aSbellard int retval; 128131e31b8aSbellard int i; 128231e31b8aSbellard 128354936004Sbellard bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); 128431e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ 128531e31b8aSbellard bprm.page[i] = 0; 128631e31b8aSbellard retval = open(filename, O_RDONLY); 1287*c2735790Sbellard if (retval < 0) 1288*c2735790Sbellard return retval; 128931e31b8aSbellard bprm.fd = retval; 129031e31b8aSbellard bprm.filename = (char *)filename; 129131e31b8aSbellard bprm.sh_bang = 0; 129231e31b8aSbellard bprm.loader = 0; 129331e31b8aSbellard bprm.exec = 0; 129431e31b8aSbellard bprm.dont_iput = 0; 129531e31b8aSbellard bprm.argc = count(argv); 129631e31b8aSbellard bprm.envc = count(envp); 129731e31b8aSbellard 129831e31b8aSbellard retval = prepare_binprm(&bprm); 129931e31b8aSbellard 130031e31b8aSbellard if(retval>=0) { 130131e31b8aSbellard bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p); 130231e31b8aSbellard bprm.exec = bprm.p; 130331e31b8aSbellard bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p); 130431e31b8aSbellard bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p); 130531e31b8aSbellard if (!bprm.p) { 130631e31b8aSbellard retval = -E2BIG; 130731e31b8aSbellard } 130831e31b8aSbellard } 130931e31b8aSbellard 131031e31b8aSbellard if(retval>=0) { 131131e31b8aSbellard retval = load_elf_binary(&bprm,regs,infop); 131231e31b8aSbellard } 131331e31b8aSbellard if(retval>=0) { 131431e31b8aSbellard /* success. Initialize important registers */ 1315b346ff46Sbellard init_thread(regs, infop); 131631e31b8aSbellard return retval; 131731e31b8aSbellard } 131831e31b8aSbellard 131931e31b8aSbellard /* Something went wrong, return the inode and free the argument pages*/ 132031e31b8aSbellard for (i=0 ; i<MAX_ARG_PAGES ; i++) { 132131e31b8aSbellard free_page((void *)bprm.page[i]); 132231e31b8aSbellard } 132331e31b8aSbellard return(retval); 132431e31b8aSbellard } 132531e31b8aSbellard 132631e31b8aSbellard 132731e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd) 132831e31b8aSbellard { 132931e31b8aSbellard printf("a.out interpreter not yet supported\n"); 133031e31b8aSbellard return(0); 133131e31b8aSbellard } 133231e31b8aSbellard 1333