diff options
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/elfload.c | 1799 | ||||
-rw-r--r-- | linux-user/flatload.c | 3 | ||||
-rw-r--r-- | linux-user/linuxload.c | 17 | ||||
-rw-r--r-- | linux-user/m68k-sim.c | 6 | ||||
-rw-r--r-- | linux-user/main.c | 39 | ||||
-rw-r--r-- | linux-user/mmap.c | 16 | ||||
-rw-r--r-- | linux-user/qemu.h | 9 | ||||
-rw-r--r-- | linux-user/signal.c | 27 | ||||
-rw-r--r-- | linux-user/syscall.c | 20 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 14 |
10 files changed, 854 insertions, 1096 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index accb44d9de..33d776de41 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -35,18 +35,17 @@ * These occupy the top three bytes. */ enum { - ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ - FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors - * (signal handling) - */ - MMAP_PAGE_ZERO = 0x0100000, - ADDR_COMPAT_LAYOUT = 0x0200000, - READ_IMPLIES_EXEC = 0x0400000, - ADDR_LIMIT_32BIT = 0x0800000, - SHORT_INODE = 0x1000000, - WHOLE_SECONDS = 0x2000000, - STICKY_TIMEOUTS = 0x4000000, - ADDR_LIMIT_3GB = 0x8000000, + ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ + FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to + descriptors (signal handling) */ + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000, }; /* @@ -56,36 +55,35 @@ enum { * conflict with error returns. */ enum { - PER_LINUX = 0x0000, - PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, - PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, - PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, - PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, - PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | - WHOLE_SECONDS | SHORT_INODE, - PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, - PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, - PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, - PER_BSD = 0x0006, - PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, - PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, - PER_LINUX32 = 0x0008, - PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, - PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ - PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ - PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ - PER_RISCOS = 0x000c, - PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, - PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, - PER_OSF4 = 0x000f, /* OSF/1 v4 */ - PER_HPUX = 0x0010, - PER_MASK = 0x00ff, + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, /* OSF/1 v4 */ + PER_HPUX = 0x0010, + PER_MASK = 0x00ff, }; /* * Return the base personality without flags. */ -#define personality(pers) (pers & PER_MASK) +#define personality(pers) (pers & PER_MASK) /* this flag is uneffective under linux too, should be deleted */ #ifndef MAP_DENYWRITE @@ -97,15 +95,21 @@ enum { #define ELIBBAD 80 #endif -typedef target_ulong target_elf_greg_t; +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif + +typedef target_ulong target_elf_greg_t; #ifdef USE_UID16 -typedef uint16_t target_uid_t; -typedef uint16_t target_gid_t; +typedef uint16_t target_uid_t; +typedef uint16_t target_gid_t; #else -typedef uint32_t target_uid_t; -typedef uint32_t target_gid_t; +typedef uint32_t target_uid_t; +typedef uint32_t target_gid_t; #endif -typedef int32_t target_pid_t; +typedef int32_t target_pid_t; #ifdef TARGET_I386 @@ -126,7 +130,7 @@ static const char *get_elf_platform(void) static uint32_t get_elf_hwcap(void) { - return thread_env->cpuid_features; + return thread_env->cpuid_features; } #ifdef TARGET_X86_64 @@ -134,7 +138,6 @@ static uint32_t get_elf_hwcap(void) #define elf_check_arch(x) ( ((x) == ELF_ARCH) ) #define ELF_CLASS ELFCLASS64 -#define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_X86_64 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) @@ -197,11 +200,11 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) /* * These are used to set parameters in the core dumps. */ -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB -#define ELF_ARCH EM_386 +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_386 -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { regs->esp = infop->start_stack; regs->eip = infop->entry; @@ -249,7 +252,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) #endif #define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 +#define ELF_EXEC_PAGESIZE 4096 #endif @@ -259,21 +262,17 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) #define elf_check_arch(x) ( (x) == EM_ARM ) -#define ELF_CLASS ELFCLASS32 -#ifdef TARGET_WORDS_BIGENDIAN -#define ELF_DATA ELFDATA2MSB -#else -#define ELF_DATA ELFDATA2LSB -#endif -#define ELF_ARCH EM_ARM +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_ARM -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; if (infop->entry & 1) - regs->ARM_cpsr |= CPSR_T; + regs->ARM_cpsr |= CPSR_T; regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; /* FIXME - what to for failure of get_user()? */ @@ -313,30 +312,30 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) } #define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 +#define ELF_EXEC_PAGESIZE 4096 enum { - ARM_HWCAP_ARM_SWP = 1 << 0, - ARM_HWCAP_ARM_HALF = 1 << 1, - ARM_HWCAP_ARM_THUMB = 1 << 2, - ARM_HWCAP_ARM_26BIT = 1 << 3, - ARM_HWCAP_ARM_FAST_MULT = 1 << 4, - ARM_HWCAP_ARM_FPA = 1 << 5, - ARM_HWCAP_ARM_VFP = 1 << 6, - ARM_HWCAP_ARM_EDSP = 1 << 7, - ARM_HWCAP_ARM_JAVA = 1 << 8, - ARM_HWCAP_ARM_IWMMXT = 1 << 9, - ARM_HWCAP_ARM_THUMBEE = 1 << 10, - ARM_HWCAP_ARM_NEON = 1 << 11, - ARM_HWCAP_ARM_VFPv3 = 1 << 12, - ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, + ARM_HWCAP_ARM_SWP = 1 << 0, + ARM_HWCAP_ARM_HALF = 1 << 1, + ARM_HWCAP_ARM_THUMB = 1 << 2, + ARM_HWCAP_ARM_26BIT = 1 << 3, + ARM_HWCAP_ARM_FAST_MULT = 1 << 4, + ARM_HWCAP_ARM_FPA = 1 << 5, + ARM_HWCAP_ARM_VFP = 1 << 6, + ARM_HWCAP_ARM_EDSP = 1 << 7, + ARM_HWCAP_ARM_JAVA = 1 << 8, + ARM_HWCAP_ARM_IWMMXT = 1 << 9, + ARM_HWCAP_ARM_THUMBEE = 1 << 10, + ARM_HWCAP_ARM_NEON = 1 << 11, + ARM_HWCAP_ARM_VFPv3 = 1 << 12, + ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, }; -#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ - | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ - | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP \ - | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 ) +#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ + | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ + | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP \ + | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 ) #endif @@ -352,12 +351,12 @@ enum #endif #define ELF_CLASS ELFCLASS64 -#define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARCV9 -#define STACK_BIAS 2047 +#define STACK_BIAS 2047 -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { #ifndef TARGET_ABI32 regs->tstate = 0; @@ -381,10 +380,10 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define elf_check_arch(x) ( (x) == EM_SPARC ) #define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARC -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { regs->psr = 0; regs->pc = infop->entry; @@ -404,22 +403,17 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define elf_check_arch(x) ( (x) == EM_PPC64 ) -#define ELF_CLASS ELFCLASS64 +#define ELF_CLASS ELFCLASS64 #else #define elf_check_arch(x) ( (x) == EM_PPC ) -#define ELF_CLASS ELFCLASS32 +#define ELF_CLASS ELFCLASS32 #endif -#ifdef TARGET_WORDS_BIGENDIAN -#define ELF_DATA ELFDATA2MSB -#else -#define ELF_DATA ELFDATA2LSB -#endif -#define ELF_ARCH EM_PPC +#define ELF_ARCH EM_PPC /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP). See arch/powerpc/include/asm/cputable.h. */ @@ -464,7 +458,7 @@ static uint32_t get_elf_hwcap(void) /* We don't have to be terribly complete here; the high points are Altivec/FP/SPE support. Anything else is just a bonus. */ -#define GET_FEATURE(flag, feature) \ +#define GET_FEATURE(flag, feature) \ do {if (e->insns_flags & flag) features |= feature; } while(0) GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64); GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU); @@ -480,15 +474,6 @@ static uint32_t get_elf_hwcap(void) } /* - * We need to put in some extra aux table entries to tell glibc what - * the cache block size is, so it can use the dcbz instruction safely. - */ -#define AT_DCACHEBSIZE 19 -#define AT_ICACHEBSIZE 20 -#define AT_UCACHEBSIZE 21 -/* A special ignored type value for PPC, for glibc compatibility. */ -#define AT_IGNOREPPC 22 -/* * The requirements here are: * - keep the final alignment of sp (sp & 0xf) * - make sure the 32-bit value at the first 16 byte aligned position of @@ -498,17 +483,17 @@ static uint32_t get_elf_hwcap(void) * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. */ #define DLINFO_ARCH_ITEMS 5 -#define ARCH_DLINFO \ -do { \ - NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ - NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ - NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ - /* \ - * Now handle glibc compatibility. \ - */ \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - } while (0) +#define ARCH_DLINFO \ + do { \ + NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ + /* \ + * Now handle glibc compatibility. \ + */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + } while (0) static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) { @@ -546,7 +531,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) } #define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 +#define ELF_EXEC_PAGESIZE 4096 #endif @@ -561,14 +546,10 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) #else #define ELF_CLASS ELFCLASS32 #endif -#ifdef TARGET_WORDS_BIGENDIAN -#define ELF_DATA ELFDATA2MSB -#else -#define ELF_DATA ELFDATA2LSB -#endif #define ELF_ARCH EM_MIPS -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { regs->cp0_status = 2 << CP0St_KSU; regs->cp0_epc = infop->entry; @@ -632,10 +613,10 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD) #define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_MICROBLAZE -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { regs->pc = infop->entry; regs->r1 = infop->start_stack; @@ -671,14 +652,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) #define elf_check_arch(x) ( (x) == EM_SH ) #define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_SH -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { - /* Check other registers XXXXX */ - regs->pc = infop->entry; - regs->regs[15] = infop->start_stack; + /* Check other registers XXXXX */ + regs->pc = infop->entry; + regs->regs[15] = infop->start_stack; } /* See linux kernel: arch/sh/include/asm/elf.h. */ @@ -696,7 +677,8 @@ enum { TARGET_REG_SYSCALL = 22 }; -static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) +static inline void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPUState *env) { int i; @@ -725,12 +707,12 @@ static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState #define elf_check_arch(x) ( (x) == EM_CRIS ) #define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_CRIS -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { - regs->erp = infop->entry; + regs->erp = infop->entry; } #define ELF_EXEC_PAGESIZE 8192 @@ -743,14 +725,14 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define elf_check_arch(x) ( (x) == EM_68K ) -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB -#define ELF_ARCH EM_68K +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_68K /* ??? Does this need to do anything? -#define ELF_PLAT_INIT(_r) */ + #define ELF_PLAT_INIT(_r) */ -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { regs->usp = infop->start_stack; regs->sr = 0; @@ -786,7 +768,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) } #define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 8192 +#define ELF_EXEC_PAGESIZE 8192 #endif @@ -797,10 +779,10 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) #define elf_check_arch(x) ( (x) == ELF_ARCH ) #define ELF_CLASS ELFCLASS64 -#define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_ALPHA -static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) { regs->pc = infop->entry; regs->ps = 8; @@ -830,14 +812,14 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i struct exec { - unsigned int a_info; /* Use macros N_MAGIC, etc for access */ - unsigned int a_text; /* length of text, in bytes */ - unsigned int a_data; /* length of data, in bytes */ - unsigned int a_bss; /* length of uninitialized data area, in bytes */ - unsigned int a_syms; /* length of symbol table data in file, in bytes */ - unsigned int a_entry; /* start address */ - unsigned int a_trsize; /* length of relocation info for text, in bytes */ - unsigned int a_drsize; /* length of relocation info for data, in bytes */ + unsigned int a_info; /* Use macros N_MAGIC, etc for access */ + unsigned int a_text; /* length of text, in bytes */ + unsigned int a_data; /* length of data, in bytes */ + unsigned int a_bss; /* length of uninitialized data area, in bytes */ + unsigned int a_syms; /* length of symbol table data in file, in bytes */ + unsigned int a_entry; /* start address */ + unsigned int a_trsize; /* length of relocation info for text, in bytes */ + unsigned int a_drsize; /* length of relocation info for data, in bytes */ }; @@ -847,72 +829,66 @@ struct exec #define ZMAGIC 0413 #define QMAGIC 0314 -/* max code+data+bss space allocated to elf interpreter */ -#define INTERP_MAP_SIZE (32 * 1024 * 1024) - -/* max code+data+bss+brk space allocated to ET_DYN executables */ -#define ET_DYN_MAP_SIZE (128 * 1024 * 1024) - /* Necessary parameters */ #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) -#define INTERPRETER_NONE 0 -#define INTERPRETER_AOUT 1 -#define INTERPRETER_ELF 2 - #define DLINFO_ITEMS 12 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { - memcpy(to, from, n); + memcpy(to, from, n); } -static int load_aout_interp(void * exptr, int interp_fd); - #ifdef BSWAP_NEEDED static void bswap_ehdr(struct elfhdr *ehdr) { - bswap16s(&ehdr->e_type); /* Object file type */ - bswap16s(&ehdr->e_machine); /* Architecture */ - bswap32s(&ehdr->e_version); /* Object file version */ - bswaptls(&ehdr->e_entry); /* Entry point virtual address */ - bswaptls(&ehdr->e_phoff); /* Program header table file offset */ - bswaptls(&ehdr->e_shoff); /* Section header table file offset */ - bswap32s(&ehdr->e_flags); /* Processor-specific flags */ - bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ - bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ - bswap16s(&ehdr->e_phnum); /* Program header table entry count */ - bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ - bswap16s(&ehdr->e_shnum); /* Section header table entry count */ - bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ -} - -static void bswap_phdr(struct elf_phdr *phdr) -{ - bswap32s(&phdr->p_type); /* Segment type */ - bswaptls(&phdr->p_offset); /* Segment file offset */ - bswaptls(&phdr->p_vaddr); /* Segment virtual address */ - bswaptls(&phdr->p_paddr); /* Segment physical address */ - bswaptls(&phdr->p_filesz); /* Segment size in file */ - bswaptls(&phdr->p_memsz); /* Segment size in memory */ - bswap32s(&phdr->p_flags); /* Segment flags */ - bswaptls(&phdr->p_align); /* Segment alignment */ -} - -static void bswap_shdr(struct elf_shdr *shdr) -{ - bswap32s(&shdr->sh_name); - bswap32s(&shdr->sh_type); - bswaptls(&shdr->sh_flags); - bswaptls(&shdr->sh_addr); - bswaptls(&shdr->sh_offset); - bswaptls(&shdr->sh_size); - bswap32s(&shdr->sh_link); - bswap32s(&shdr->sh_info); - bswaptls(&shdr->sh_addralign); - bswaptls(&shdr->sh_entsize); + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswaptls(&ehdr->e_entry); /* Entry point virtual address */ + bswaptls(&ehdr->e_phoff); /* Program header table file offset */ + bswaptls(&ehdr->e_shoff); /* Section header table file offset */ + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void bswap_phdr(struct elf_phdr *phdr, int phnum) +{ + int i; + for (i = 0; i < phnum; ++i, ++phdr) { + bswap32s(&phdr->p_type); /* Segment type */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswaptls(&phdr->p_offset); /* Segment file offset */ + bswaptls(&phdr->p_vaddr); /* Segment virtual address */ + bswaptls(&phdr->p_paddr); /* Segment physical address */ + bswaptls(&phdr->p_filesz); /* Segment size in file */ + bswaptls(&phdr->p_memsz); /* Segment size in memory */ + bswaptls(&phdr->p_align); /* Segment alignment */ + } +} + +static void bswap_shdr(struct elf_shdr *shdr, int shnum) +{ + int i; + for (i = 0; i < shnum; ++i, ++shdr) { + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswaptls(&shdr->sh_flags); + bswaptls(&shdr->sh_addr); + bswaptls(&shdr->sh_offset); + bswaptls(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswaptls(&shdr->sh_addralign); + bswaptls(&shdr->sh_entsize); + } } static void bswap_sym(struct elf_sym *sym) @@ -922,21 +898,41 @@ static void bswap_sym(struct elf_sym *sym) bswaptls(&sym->st_size); bswap16s(&sym->st_shndx); } +#else +static inline void bswap_ehdr(struct elfhdr *ehdr) { } +static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { } +static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { } +static inline void bswap_sym(struct elf_sym *sym) { } #endif #ifdef USE_ELF_CORE_DUMP static int elf_core_dump(int, const CPUState *); +#endif /* USE_ELF_CORE_DUMP */ +static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias); -#ifdef BSWAP_NEEDED -static void bswap_note(struct elf_note *en) +/* Verify the portions of EHDR within E_IDENT for the target. + This can be performed before bswapping the entire header. */ +static bool elf_check_ident(struct elfhdr *ehdr) { - bswap32s(&en->n_namesz); - bswap32s(&en->n_descsz); - bswap32s(&en->n_type); + return (ehdr->e_ident[EI_MAG0] == ELFMAG0 + && ehdr->e_ident[EI_MAG1] == ELFMAG1 + && ehdr->e_ident[EI_MAG2] == ELFMAG2 + && ehdr->e_ident[EI_MAG3] == ELFMAG3 + && ehdr->e_ident[EI_CLASS] == ELF_CLASS + && ehdr->e_ident[EI_DATA] == ELF_DATA + && ehdr->e_ident[EI_VERSION] == EV_CURRENT); } -#endif /* BSWAP_NEEDED */ -#endif /* USE_ELF_CORE_DUMP */ +/* Verify the portions of EHDR outside of E_IDENT for the target. + This has to wait until after bswapping the header. */ +static bool elf_check_ehdr(struct elfhdr *ehdr) +{ + return (elf_check_arch(ehdr->e_machine) + && ehdr->e_ehsize == sizeof(struct elfhdr) + && ehdr->e_phentsize == sizeof(struct elf_phdr) + && ehdr->e_shentsize == sizeof(struct elf_shdr) + && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)); +} /* * 'copy_elf_strings()' copies argument/envelope strings from user @@ -951,24 +947,24 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, int len, offset = 0; if (!p) { - return 0; /* bullet-proofing */ + return 0; /* bullet-proofing */ } while (argc-- > 0) { tmp = argv[argc]; if (!tmp) { - fprintf(stderr, "VFS: argc is wrong"); - exit(-1); - } + fprintf(stderr, "VFS: argc is wrong"); + exit(-1); + } tmp1 = tmp; - while (*tmp++); - len = tmp - tmp1; - if (p < len) { /* this shouldn't happen - 128kB */ - return 0; - } - while (len) { - --p; --tmp; --len; - if (--offset < 0) { - offset = p % TARGET_PAGE_SIZE; + while (*tmp++); + len = tmp - tmp1; + if (p < len) { /* this shouldn't happen - 128kB */ + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % TARGET_PAGE_SIZE; pag = (char *)page[p/TARGET_PAGE_SIZE]; if (!pag) { pag = (char *)malloc(TARGET_PAGE_SIZE); @@ -976,20 +972,20 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, page[p/TARGET_PAGE_SIZE] = pag; if (!pag) return 0; - } - } - if (len == 0 || offset == 0) { - *(pag + offset) = *tmp; - } - else { - int bytes_to_copy = (len > offset) ? offset : len; - tmp -= bytes_to_copy; - p -= bytes_to_copy; - offset -= bytes_to_copy; - len -= bytes_to_copy; - memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); - } - } + } + } + if (len == 0 || offset == 0) { + *(pag + offset) = *tmp; + } + else { + int bytes_to_copy = (len > offset) ? offset : len; + tmp -= bytes_to_copy; + p -= bytes_to_copy; + offset -= bytes_to_copy; + len -= bytes_to_copy; + memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); + } + } } return p; } @@ -997,332 +993,440 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, struct image_info *info) { - abi_ulong stack_base, size, error; + abi_ulong stack_base, size, error, guard; int i; /* Create enough stack to hold everything. If we don't use - * it for args, we'll use it for something else... - */ + it for args, we'll use it for something else. */ size = guest_stack_size; - if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) { size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; - error = target_mmap(0, - size + qemu_host_page_size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); + } + guard = TARGET_PAGE_SIZE; + if (guard < qemu_real_host_page_size) { + guard = qemu_real_host_page_size; + } + + error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (error == -1) { - perror("stk mmap"); + perror("mmap stack"); exit(-1); } - /* we reserve one extra page at the top of the stack as guard */ - target_mprotect(error + size, qemu_host_page_size, PROT_NONE); - info->stack_limit = error; - stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; + /* We reserve one extra page at the top of the stack as guard. */ + target_mprotect(error, guard, PROT_NONE); + + info->stack_limit = error + guard; + stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; p += stack_base; for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - if (bprm->page[i]) { - info->rss++; + if (bprm->page[i]) { + info->rss++; /* FIXME - check return value of memcpy_to_target() for failure */ - memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); - free(bprm->page[i]); - } + memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); + free(bprm->page[i]); + } stack_base += TARGET_PAGE_SIZE; } return p; } -static void set_brk(abi_ulong start, abi_ulong end) -{ - /* page-align the start and end addresses... */ - start = HOST_PAGE_ALIGN(start); - end = HOST_PAGE_ALIGN(end); - if (end <= start) - return; - if(target_mmap(start, end - start, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { - perror("cannot mmap brk"); - exit(-1); - } -} - - -/* We need to explicitly zero any fractional pages after the data - section (i.e. bss). This would contain the junk from the file that - should not be in memory. */ -static void padzero(abi_ulong elf_bss, abi_ulong last_bss) -{ - abi_ulong nbyte; - - if (elf_bss >= last_bss) - return; - - /* XXX: this is really a hack : if the real host page size is - smaller than the target page size, some pages after the end - of the file may not be mapped. A better fix would be to - patch target_mmap(), but it is more complicated as the file - size must be known */ - if (qemu_real_host_page_size < qemu_host_page_size) { - abi_ulong end_addr, end_addr1; - end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & - ~(qemu_real_host_page_size - 1); - end_addr = HOST_PAGE_ALIGN(elf_bss); - if (end_addr1 < end_addr) { - mmap((void *)g2h(end_addr1), end_addr - end_addr1, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - } - } +/* Map and zero the bss. We need to explicitly zero any fractional pages + after the data section (i.e. bss). */ +static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot) +{ + uintptr_t host_start, host_map_start, host_end; - nbyte = elf_bss & (qemu_host_page_size-1); - if (nbyte) { - nbyte = qemu_host_page_size - nbyte; - do { - /* FIXME - what to do if put_user() fails? */ - put_user_u8(0, elf_bss); - elf_bss++; - } while (--nbyte); + last_bss = TARGET_PAGE_ALIGN(last_bss); + + /* ??? There is confusion between qemu_real_host_page_size and + qemu_host_page_size here and elsewhere in target_mmap, which + may lead to the end of the data section mapping from the file + not being mapped. At least there was an explicit test and + comment for that here, suggesting that "the file size must + be known". The comment probably pre-dates the introduction + of the fstat system call in target_mmap which does in fact + find out the size. What isn't clear is if the workaround + here is still actually needed. For now, continue with it, + but merge it with the "normal" mmap that would allocate the bss. */ + + host_start = (uintptr_t) g2h(elf_bss); + host_end = (uintptr_t) g2h(last_bss); + host_map_start = (host_start + qemu_real_host_page_size - 1); + host_map_start &= -qemu_real_host_page_size; + + if (host_map_start < host_end) { + void *p = mmap((void *)host_map_start, host_end - host_map_start, + prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) { + perror("cannot mmap brk"); + exit(-1); } -} + /* Since we didn't use target_mmap, make sure to record + the validity of the pages with qemu. */ + page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID); + } + + if (host_start < host_map_start) { + memset((void *)host_start, 0, host_map_start - host_start); + } +} static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, - struct elfhdr * exec, - abi_ulong load_addr, - abi_ulong load_bias, - abi_ulong interp_load_addr, int ibcs, - struct image_info *info) -{ - abi_ulong sp; - int size; - abi_ulong u_platform; - const char *k_platform; - const int n = sizeof(elf_addr_t); - - sp = p; - u_platform = 0; - k_platform = ELF_PLATFORM; - if (k_platform) { - size_t len = strlen(k_platform) + 1; - sp -= (len + n - 1) & ~(n - 1); - u_platform = sp; - /* FIXME - check return value of memcpy_to_target() for failure */ - memcpy_to_target(sp, k_platform, len); - } - /* - * Force 16 byte _final_ alignment here for generality. - */ - sp = sp &~ (abi_ulong)15; - size = (DLINFO_ITEMS + 1) * 2; - if (k_platform) - size += 2; + struct elfhdr *exec, + struct image_info *info, + struct image_info *interp_info) +{ + abi_ulong sp; + int size; + abi_ulong u_platform; + const char *k_platform; + const int n = sizeof(elf_addr_t); + + sp = p; + u_platform = 0; + k_platform = ELF_PLATFORM; + if (k_platform) { + size_t len = strlen(k_platform) + 1; + sp -= (len + n - 1) & ~(n - 1); + u_platform = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_platform, len); + } + /* + * Force 16 byte _final_ alignment here for generality. + */ + sp = sp &~ (abi_ulong)15; + size = (DLINFO_ITEMS + 1) * 2; + if (k_platform) + size += 2; #ifdef DLINFO_ARCH_ITEMS - size += DLINFO_ARCH_ITEMS * 2; + size += DLINFO_ARCH_ITEMS * 2; #endif - size += envc + argc + 2; - size += (!ibcs ? 3 : 1); /* argc itself */ - size *= n; - if (size & 15) - sp -= 16 - (size & 15); - - /* This is correct because Linux defines - * elf_addr_t as Elf32_Off / Elf64_Off - */ -#define NEW_AUX_ENT(id, val) do { \ - sp -= n; put_user_ual(val, sp); \ - sp -= n; put_user_ual(id, sp); \ - } while(0) - - NEW_AUX_ENT (AT_NULL, 0); - - /* There must be exactly DLINFO_ITEMS entries here. */ - NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); - NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); - NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); - NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); - NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); - NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); - NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); - NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); - NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); - NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); - NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); - if (k_platform) - NEW_AUX_ENT(AT_PLATFORM, u_platform); + size += envc + argc + 2; + size += 1; /* argc itself */ + size *= n; + if (size & 15) + sp -= 16 - (size & 15); + + /* This is correct because Linux defines + * elf_addr_t as Elf32_Off / Elf64_Off + */ +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; put_user_ual(val, sp); \ + sp -= n; put_user_ual(id, sp); \ + } while(0) + + NEW_AUX_ENT (AT_NULL, 0); + + /* There must be exactly DLINFO_ITEMS entries here. */ + NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff)); + NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); + NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0)); + NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); + NEW_AUX_ENT(AT_ENTRY, info->entry); + NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); + NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); + NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); + NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); + NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); + NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); + if (k_platform) + NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO - /* - * ARCH_DLINFO must come last so platform specific code can enforce - * special alignment requirements on the AUXV if necessary (eg. PPC). - */ - ARCH_DLINFO; + /* + * ARCH_DLINFO must come last so platform specific code can enforce + * special alignment requirements on the AUXV if necessary (eg. PPC). + */ + ARCH_DLINFO; #endif #undef NEW_AUX_ENT - info->saved_auxv = sp; + info->saved_auxv = sp; - sp = loader_build_argptr(envc, argc, sp, p, !ibcs); - return sp; + sp = loader_build_argptr(envc, argc, sp, p, 0); + return sp; } +/* Load an ELF image into the address space. -static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, - int interpreter_fd, - abi_ulong *interp_load_addr) + IMAGE_NAME is the filename of the image, to use in error messages. + IMAGE_FD is the open file descriptor for the image. + + BPRM_BUF is a copy of the beginning of the file; this of course + contains the elf file header at offset 0. It is assumed that this + buffer is sufficiently aligned to present no problems to the host + in accessing data at aligned offsets within the buffer. + + On return: INFO values will be filled in, as necessary or available. */ + +static void load_elf_image(const char *image_name, int image_fd, + struct image_info *info, char **pinterp_name, + char bprm_buf[BPRM_BUF_SIZE]) { - struct elf_phdr *elf_phdata = NULL; - struct elf_phdr *eppnt; - abi_ulong load_addr = 0; - int load_addr_set = 0; - int retval; - abi_ulong last_bss, elf_bss; - abi_ulong error; - int i; + struct elfhdr *ehdr = (struct elfhdr *)bprm_buf; + struct elf_phdr *phdr; + abi_ulong load_addr, load_bias, loaddr, hiaddr, error; + int i, retval; + const char *errmsg; - elf_bss = 0; - last_bss = 0; - error = 0; + /* First of all, some simple consistency checks */ + errmsg = "Invalid ELF image for this architecture"; + if (!elf_check_ident(ehdr)) { + goto exit_errmsg; + } + bswap_ehdr(ehdr); + if (!elf_check_ehdr(ehdr)) { + goto exit_errmsg; + } -#ifdef BSWAP_NEEDED - bswap_ehdr(interp_elf_ex); + i = ehdr->e_phnum * sizeof(struct elf_phdr); + if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) { + phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff); + } else { + phdr = (struct elf_phdr *) alloca(i); + retval = pread(image_fd, phdr, i, ehdr->e_phoff); + if (retval != i) { + goto exit_read; + } + } + bswap_phdr(phdr, ehdr->e_phnum); + + /* Find the maximum size of the image and allocate an appropriate + amount of memory to handle that. */ + loaddr = -1, hiaddr = 0; + for (i = 0; i < ehdr->e_phnum; ++i) { + if (phdr[i].p_type == PT_LOAD) { + abi_ulong a = phdr[i].p_vaddr; + if (a < loaddr) { + loaddr = a; + } + a += phdr[i].p_memsz; + if (a > hiaddr) { + hiaddr = a; + } + } + } + + load_addr = loaddr; + if (ehdr->e_type == ET_DYN) { + /* The image indicates that it can be loaded anywhere. Find a + location that can hold the memory space required. If the + image is pre-linked, LOADDR will be non-zero. Since we do + not supply MAP_FIXED here we'll use that address if and + only if it remains available. */ + load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE, + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, + -1, 0); + if (load_addr == -1) { + goto exit_perror; + } + } else if (pinterp_name != NULL) { + /* This is the main executable. Make sure that the low + address does not conflict with MMAP_MIN_ADDR or the + QEMU application itself. */ +#if defined(CONFIG_USE_GUEST_BASE) + /* + * In case where user has not explicitly set the guest_base, we + * probe here that should we set it automatically. + */ + if (!have_guest_base && !reserved_va) { + unsigned long host_start, real_start, host_size; + + /* Round addresses to page boundaries. */ + loaddr &= qemu_host_page_mask; + hiaddr = HOST_PAGE_ALIGN(hiaddr); + + if (loaddr < mmap_min_addr) { + host_start = HOST_PAGE_ALIGN(mmap_min_addr); + } else { + host_start = loaddr; + if (host_start != loaddr) { + errmsg = "Address overflow loading ELF binary"; + goto exit_errmsg; + } + } + host_size = hiaddr - loaddr; + while (1) { + /* Do not use mmap_find_vma here because that is limited to the + guest address space. We are going to make the + guest address space fit whatever we're given. */ + real_start = (unsigned long) + mmap((void *)host_start, host_size, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); + if (real_start == (unsigned long)-1) { + goto exit_perror; + } + if (real_start == host_start) { + break; + } + /* That address didn't work. Unmap and try a different one. + The address the host picked because is typically right at + the top of the host address space and leaves the guest with + no usable address space. Resort to a linear search. We + already compensated for mmap_min_addr, so this should not + happen often. Probably means we got unlucky and host + address space randomization put a shared library somewhere + inconvenient. */ + munmap((void *)real_start, host_size); + host_start += qemu_host_page_size; + if (host_start == loaddr) { + /* Theoretically possible if host doesn't have any suitably + aligned areas. Normally the first mmap will fail. */ + errmsg = "Unable to find space for application"; + goto exit_errmsg; + } + } + qemu_log("Relocating guest address space from 0x" + TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start); + guest_base = real_start - loaddr; + } #endif - /* First of all, some simple consistency checks */ - if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || - !elf_check_arch(interp_elf_ex->e_machine)) { - return ~((abi_ulong)0UL); - } + } + load_bias = load_addr - loaddr; + info->load_bias = load_bias; + info->load_addr = load_addr; + info->entry = ehdr->e_entry + load_bias; + info->start_code = -1; + info->end_code = 0; + info->start_data = -1; + info->end_data = 0; + info->brk = 0; - /* Now read in all of the header information */ + for (i = 0; i < ehdr->e_phnum; i++) { + struct elf_phdr *eppnt = phdr + i; + if (eppnt->p_type == PT_LOAD) { + abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em; + int elf_prot = 0; - if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) - return ~(abi_ulong)0UL; + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - elf_phdata = (struct elf_phdr *) - malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + vaddr = load_bias + eppnt->p_vaddr; + vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr); + vaddr_ps = TARGET_ELF_PAGESTART(vaddr); - if (!elf_phdata) - return ~((abi_ulong)0UL); + error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po, + elf_prot, MAP_PRIVATE | MAP_FIXED, + image_fd, eppnt->p_offset - vaddr_po); + if (error == -1) { + goto exit_perror; + } - /* - * If the size of this structure has changed, then punt, since - * we will be doing the wrong thing. - */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { - free(elf_phdata); - return ~((abi_ulong)0UL); - } + vaddr_ef = vaddr + eppnt->p_filesz; + vaddr_em = vaddr + eppnt->p_memsz; - retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd, - (char *) elf_phdata, - sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); - } - if (retval < 0) { - perror("load_elf_interp"); - exit(-1); - free (elf_phdata); - return retval; - } -#ifdef BSWAP_NEEDED - eppnt = elf_phdata; - for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { - bswap_phdr(eppnt); - } -#endif + /* If the load segment requests extra zeros (e.g. bss), map it. */ + if (vaddr_ef < vaddr_em) { + zero_bss(vaddr_ef, vaddr_em, elf_prot); + } - if (interp_elf_ex->e_type == ET_DYN) { - /* in order to avoid hardcoding the interpreter load - address in qemu, we allocate a big enough memory zone */ - error = target_mmap(0, INTERP_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, - -1, 0); - if (error == -1) { - perror("mmap"); - exit(-1); + /* Find the full program boundaries. */ + if (elf_prot & PROT_EXEC) { + if (vaddr < info->start_code) { + info->start_code = vaddr; + } + if (vaddr_ef > info->end_code) { + info->end_code = vaddr_ef; + } + } + if (elf_prot & PROT_WRITE) { + if (vaddr < info->start_data) { + info->start_data = vaddr; + } + if (vaddr_ef > info->end_data) { + info->end_data = vaddr_ef; + } + if (vaddr_em > info->brk) { + info->brk = vaddr_em; + } + } + } else if (eppnt->p_type == PT_INTERP && pinterp_name) { + char *interp_name; + + if (*pinterp_name) { + errmsg = "Multiple PT_INTERP entries"; + goto exit_errmsg; + } + interp_name = malloc(eppnt->p_filesz); + if (!interp_name) { + goto exit_perror; } - load_addr = error; - load_addr_set = 1; + + if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) { + memcpy(interp_name, bprm_buf + eppnt->p_offset, + eppnt->p_filesz); + } else { + retval = pread(image_fd, interp_name, eppnt->p_filesz, + eppnt->p_offset); + if (retval != eppnt->p_filesz) { + goto exit_perror; + } + } + if (interp_name[eppnt->p_filesz - 1] != 0) { + errmsg = "Invalid PT_INTERP entry"; + goto exit_errmsg; + } + *pinterp_name = interp_name; } + } + + if (info->end_data == 0) { + info->start_data = info->end_code; + info->end_data = info->end_code; + info->brk = info->end_code; + } + + if (qemu_log_enabled()) { + load_symbols(ehdr, image_fd, load_bias); + } + + close(image_fd); + return; - eppnt = elf_phdata; - for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) - if (eppnt->p_type == PT_LOAD) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - abi_ulong vaddr = 0; - abi_ulong k; - - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { - elf_type |= MAP_FIXED; - vaddr = eppnt->p_vaddr; - } - error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), - eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), - elf_prot, - elf_type, - interpreter_fd, - eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - - if (error == -1) { - /* Real error */ - close(interpreter_fd); - free(elf_phdata); - return ~((abi_ulong)0UL); - } - - if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - load_addr_set = 1; - } - - /* - * Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; - if (k > elf_bss) elf_bss = k; - - /* - * Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; - if (k > last_bss) last_bss = k; - } - - /* Now use mmap to map the library into memory. */ - - close(interpreter_fd); - - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zeromapped pages up to and including the last - * bss page. - */ - padzero(elf_bss, last_bss); - elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ - - /* Map the last of the bss segment */ - if (last_bss > elf_bss) { - target_mmap(elf_bss, last_bss-elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - } - free(elf_phdata); - - *interp_load_addr = load_addr; - return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; + exit_read: + if (retval >= 0) { + errmsg = "Incomplete read of file header"; + goto exit_errmsg; + } + exit_perror: + errmsg = strerror(errno); + exit_errmsg: + fprintf(stderr, "%s: %s\n", image_name, errmsg); + exit(-1); +} + +static void load_elf_interp(const char *filename, struct image_info *info, + char bprm_buf[BPRM_BUF_SIZE]) +{ + int fd, retval; + + fd = open(path(filename), O_RDONLY); + if (fd < 0) { + goto exit_perror; + } + + retval = read(fd, bprm_buf, BPRM_BUF_SIZE); + if (retval < 0) { + goto exit_perror; + } + if (retval < BPRM_BUF_SIZE) { + memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval); + } + + load_elf_image(filename, fd, info, NULL, bprm_buf); + return; + + exit_perror: + fprintf(stderr, "%s: %s\n", filename, strerror(errno)); + exit(-1); } static int symfind(const void *s0, const void *s1) @@ -1371,88 +1475,97 @@ static int symcmp(const void *s0, const void *s1) } /* Best attempt to load symbols from this ELF object. */ -static void load_symbols(struct elfhdr *hdr, int fd) +static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) { - unsigned int i, nsyms; - struct elf_shdr sechdr, symtab, strtab; + int i, shnum, nsyms, sym_idx = 0, str_idx = 0; + struct elf_shdr *shdr; char *strings; struct syminfo *s; struct elf_sym *syms; - lseek(fd, hdr->e_shoff, SEEK_SET); - for (i = 0; i < hdr->e_shnum; i++) { - if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) - return; -#ifdef BSWAP_NEEDED - bswap_shdr(&sechdr); -#endif - if (sechdr.sh_type == SHT_SYMTAB) { - symtab = sechdr; - lseek(fd, hdr->e_shoff - + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); - if (read(fd, &strtab, sizeof(strtab)) - != sizeof(strtab)) - return; -#ifdef BSWAP_NEEDED - bswap_shdr(&strtab); -#endif + shnum = hdr->e_shnum; + i = shnum * sizeof(struct elf_shdr); + shdr = (struct elf_shdr *)alloca(i); + if (pread(fd, shdr, i, hdr->e_shoff) != i) { + return; + } + + bswap_shdr(shdr, shnum); + for (i = 0; i < shnum; ++i) { + if (shdr[i].sh_type == SHT_SYMTAB) { + sym_idx = i; + str_idx = shdr[i].sh_link; goto found; } } - return; /* Shouldn't happen... */ + + /* There will be no symbol table if the file was stripped. */ + return; found: - /* Now know where the strtab and symtab are. Snarf them. */ + /* Now know where the strtab and symtab are. Snarf them. */ s = malloc(sizeof(*s)); - syms = malloc(symtab.sh_size); - if (!syms) - return; - s->disas_strtab = strings = malloc(strtab.sh_size); - if (!s->disas_strtab) + if (!s) { return; + } - lseek(fd, symtab.sh_offset, SEEK_SET); - if (read(fd, syms, symtab.sh_size) != symtab.sh_size) + i = shdr[str_idx].sh_size; + s->disas_strtab = strings = malloc(i); + if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) { + free(s); + free(strings); return; + } - nsyms = symtab.sh_size / sizeof(struct elf_sym); + i = shdr[sym_idx].sh_size; + syms = malloc(i); + if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) { + free(s); + free(strings); + free(syms); + return; + } - i = 0; - while (i < nsyms) { -#ifdef BSWAP_NEEDED + nsyms = i / sizeof(struct elf_sym); + for (i = 0; i < nsyms; ) { bswap_sym(syms + i); -#endif - // Throw away entries which we do not need. - if (syms[i].st_shndx == SHN_UNDEF || - syms[i].st_shndx >= SHN_LORESERVE || - ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { - nsyms--; - if (i < nsyms) { + /* Throw away entries which we do not need. */ + if (syms[i].st_shndx == SHN_UNDEF + || syms[i].st_shndx >= SHN_LORESERVE + || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { + if (i < --nsyms) { syms[i] = syms[nsyms]; } - continue; - } + } else { #if defined(TARGET_ARM) || defined (TARGET_MIPS) - /* The bottom address bit marks a Thumb or MIPS16 symbol. */ - syms[i].st_value &= ~(target_ulong)1; + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ + syms[i].st_value &= ~(target_ulong)1; #endif - i++; + syms[i].st_value += load_bias; + i++; + } } + + /* Attempt to free the storage associated with the local symbols + that we threw away. Whether or not this has any effect on the + memory allocation depends on the malloc implementation and how + many symbols we managed to discard. */ syms = realloc(syms, nsyms * sizeof(*syms)); + if (syms == NULL) { + free(s); + free(strings); + return; + } qsort(syms, nsyms, sizeof(*syms), symcmp); - lseek(fd, strtab.sh_offset, SEEK_SET); - if (read(fd, strings, strtab.sh_size) != strtab.sh_size) - return; s->disas_num_syms = nsyms; #if ELF_CLASS == ELFCLASS32 s->disas_symtab.elf32 = syms; - s->lookup_symbol = lookup_symbolxx; #else s->disas_symtab.elf64 = syms; - s->lookup_symbol = lookup_symbolxx; #endif + s->lookup_symbol = lookup_symbolxx; s->next = syminfos; syminfos = s; } @@ -1460,477 +1573,67 @@ static void load_symbols(struct elfhdr *hdr, int fd) int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info) { + struct image_info interp_info; struct elfhdr elf_ex; - struct elfhdr interp_elf_ex; - struct exec interp_ex; - int interpreter_fd = -1; /* avoid warning */ - abi_ulong load_addr, load_bias; - int load_addr_set = 0; - unsigned int interpreter_type = INTERPRETER_NONE; - unsigned char ibcs2_interpreter; - int i; - abi_ulong mapped_addr; - struct elf_phdr * elf_ppnt; - struct elf_phdr *elf_phdata; - abi_ulong elf_bss, k, elf_brk; - int retval; - char * elf_interpreter; - abi_ulong elf_entry, interp_load_addr = 0; - int status; - abi_ulong start_code, end_code, start_data, end_data; - abi_ulong reloc_func_desc = 0; - abi_ulong elf_stack; - char passed_fileno[6]; - - ibcs2_interpreter = 0; - status = 0; - load_addr = 0; - load_bias = 0; - elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ -#ifdef BSWAP_NEEDED - bswap_ehdr(&elf_ex); -#endif - - /* First of all, some simple consistency checks */ - if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || - (! elf_check_arch(elf_ex.e_machine))) { - return -ENOEXEC; - } - - bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); - bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); - bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); - if (!bprm->p) { - retval = -E2BIG; - } - - /* Now read in all of the header information */ - elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); - if (elf_phdata == NULL) { - return -ENOMEM; - } - - retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); - if(retval > 0) { - retval = read(bprm->fd, (char *) elf_phdata, - elf_ex.e_phentsize * elf_ex.e_phnum); - } - - if (retval < 0) { - perror("load_elf_binary"); - exit(-1); - free (elf_phdata); - return -errno; - } - -#ifdef BSWAP_NEEDED - elf_ppnt = elf_phdata; - for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { - bswap_phdr(elf_ppnt); - } -#endif - elf_ppnt = elf_phdata; - - elf_bss = 0; - elf_brk = 0; - - - elf_stack = ~((abi_ulong)0UL); - elf_interpreter = NULL; - start_code = ~((abi_ulong)0UL); - end_code = 0; - start_data = 0; - end_data = 0; - interp_ex.a_info = 0; - - for(i=0;i < elf_ex.e_phnum; i++) { - if (elf_ppnt->p_type == PT_INTERP) { - if ( elf_interpreter != NULL ) - { - free (elf_phdata); - free(elf_interpreter); - close(bprm->fd); - return -EINVAL; - } - - /* This is the program interpreter used for - * shared libraries - for now assume that this - * is an a.out format binary - */ - - elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); - - if (elf_interpreter == NULL) { - free (elf_phdata); - close(bprm->fd); - return -ENOMEM; - } - - retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); - if(retval >= 0) { - retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); - } - if(retval < 0) { - perror("load_elf_binary2"); - exit(-1); - } - - /* If the program interpreter is one of these two, - then assume an iBCS2 image. Otherwise assume - a native linux image. */ - - /* JRP - Need to add X86 lib dir stuff here... */ - - if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || - strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { - ibcs2_interpreter = 1; - } + char *elf_interpreter = NULL; -#if 0 - printf("Using ELF interpreter %s\n", path(elf_interpreter)); -#endif - if (retval >= 0) { - retval = open(path(elf_interpreter), O_RDONLY); - if(retval >= 0) { - interpreter_fd = retval; - } - else { - perror(elf_interpreter); - exit(-1); - /* retval = -errno; */ - } - } - - if (retval >= 0) { - retval = lseek(interpreter_fd, 0, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd,bprm->buf,128); - } - } - if (retval >= 0) { - interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ - interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */ - } - if (retval < 0) { - perror("load_elf_binary3"); - exit(-1); - free (elf_phdata); - free(elf_interpreter); - close(bprm->fd); - return retval; - } - } - elf_ppnt++; - } - - /* Some simple consistency checks for the interpreter */ - if (elf_interpreter){ - interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; - - /* Now figure out which format our binary is */ - if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && - (N_MAGIC(interp_ex) != QMAGIC)) { - interpreter_type = INTERPRETER_ELF; - } - - if (interp_elf_ex.e_ident[0] != 0x7f || - strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) { - interpreter_type &= ~INTERPRETER_ELF; - } - - if (!interpreter_type) { - free(elf_interpreter); - free(elf_phdata); - close(bprm->fd); - return -ELIBBAD; - } - } - - /* OK, we are done with that, now set up the arg stuff, - and then start this sucker up */ - - { - char * passed_p; - - if (interpreter_type == INTERPRETER_AOUT) { - snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); - passed_p = passed_fileno; - - if (elf_interpreter) { - bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); - bprm->argc++; - } - } - if (!bprm->p) { - if (elf_interpreter) { - free(elf_interpreter); - } - free (elf_phdata); - close(bprm->fd); - return -E2BIG; - } - } - - /* OK, This is the point of no return */ - info->end_data = 0; - info->end_code = 0; info->start_mmap = (abi_ulong)ELF_START_MMAP; info->mmap = 0; - elf_entry = (abi_ulong) elf_ex.e_entry; + info->rss = 0; -#if defined(CONFIG_USE_GUEST_BASE) - /* - * In case where user has not explicitly set the guest_base, we - * probe here that should we set it automatically. - */ - if (!(have_guest_base || reserved_va)) { - /* - * Go through ELF program header table and find the address - * range used by loadable segments. Check that this is available on - * the host, and if not find a suitable value for guest_base. */ - abi_ulong app_start = ~0; - abi_ulong app_end = 0; - abi_ulong addr; - unsigned long host_start; - unsigned long real_start; - unsigned long host_size; - for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; - i++, elf_ppnt++) { - if (elf_ppnt->p_type != PT_LOAD) - continue; - addr = elf_ppnt->p_vaddr; - if (addr < app_start) { - app_start = addr; - } - addr += elf_ppnt->p_memsz; - if (addr > app_end) { - app_end = addr; - } - } + load_elf_image(bprm->filename, bprm->fd, info, + &elf_interpreter, bprm->buf); - /* If we don't have any loadable segments then something - is very wrong. */ - assert(app_start < app_end); + /* ??? We need a copy of the elf header for passing to create_elf_tables. + If we do nothing, we'll have overwritten this when we re-use bprm->buf + when we load the interpreter. */ + elf_ex = *(struct elfhdr *)bprm->buf; - /* Round addresses to page boundaries. */ - app_start = app_start & qemu_host_page_mask; - app_end = HOST_PAGE_ALIGN(app_end); - if (app_start < mmap_min_addr) { - host_start = HOST_PAGE_ALIGN(mmap_min_addr); - } else { - host_start = app_start; - if (host_start != app_start) { - fprintf(stderr, "qemu: Address overflow loading ELF binary\n"); - abort(); - } - } - host_size = app_end - app_start; - while (1) { - /* Do not use mmap_find_vma here because that is limited to the - guest address space. We are going to make the - guest address space fit whatever we're given. */ - real_start = (unsigned long)mmap((void *)host_start, host_size, - PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); - if (real_start == (unsigned long)-1) { - fprintf(stderr, "qemu: Virtual memory exausted\n"); - abort(); - } - if (real_start == host_start) { - break; - } - /* That address didn't work. Unmap and try a different one. - The address the host picked because is typically - right at the top of the host address space and leaves the - guest with no usable address space. Resort to a linear search. - We already compensated for mmap_min_addr, so this should not - happen often. Probably means we got unlucky and host address - space randomization put a shared library somewhere - inconvenient. */ - munmap((void *)real_start, host_size); - host_start += qemu_host_page_size; - if (host_start == app_start) { - /* Theoretically possible if host doesn't have any - suitably aligned areas. Normally the first mmap will - fail. */ - fprintf(stderr, "qemu: Unable to find space for application\n"); - abort(); - } - } - qemu_log("Relocating guest address space from 0x" TARGET_ABI_FMT_lx - " to 0x%lx\n", app_start, real_start); - guest_base = real_start - app_start; + bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); + bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + if (!bprm->p) { + fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG)); + exit(-1); } -#endif /* CONFIG_USE_GUEST_BASE */ /* Do this so that we can load the interpreter, if need be. We will change some of these later */ - info->rss = 0; bprm->p = setup_arg_pages(bprm->p, bprm, info); - info->start_stack = bprm->p; - /* Now we do a little grungy work by mmaping the ELF image into - * the correct location in memory. At this point, we assume that - * the image should be loaded at fixed address, not at a variable - * address. - */ + if (elf_interpreter) { + load_elf_interp(elf_interpreter, &interp_info, bprm->buf); - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { - int elf_prot = 0; - int elf_flags = 0; - abi_ulong error; + /* If the program interpreter is one of these two, then assume + an iBCS2 image. Otherwise assume a native linux image. */ - if (elf_ppnt->p_type != PT_LOAD) - continue; + if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 + || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) { + info->personality = PER_SVR4; - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - elf_flags = MAP_PRIVATE | MAP_DENYWRITE; - if (elf_ex.e_type == ET_EXEC || load_addr_set) { - elf_flags |= MAP_FIXED; - } else if (elf_ex.e_type == ET_DYN) { - /* Try and get dynamic programs out of the way of the default mmap - base, as well as whatever program they might try to exec. This - is because the brk will follow the loader, and is not movable. */ - /* NOTE: for qemu, we do a big mmap to get enough space - without hardcoding any address */ - error = target_mmap(0, ET_DYN_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, - -1, 0); - if (error == -1) { - perror("mmap"); - exit(-1); - } - load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. Since + we do not have the power to recompile these, we emulate + the SVr4 behavior. Sigh. */ + target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, -1, 0); } - - error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), - (elf_ppnt->p_filesz + - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), - bprm->fd, - (elf_ppnt->p_offset - - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - if (error == -1) { - perror("mmap"); - exit(-1); - } - -#ifdef LOW_ELF_STACK - if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) - elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); -#endif - - if (!load_addr_set) { - load_addr_set = 1; - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; - if (elf_ex.e_type == ET_DYN) { - load_bias += error - - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); - load_addr += load_bias; - reloc_func_desc = load_bias; - } - } - k = elf_ppnt->p_vaddr; - if (k < start_code) - start_code = k; - if (start_data < k) - start_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) - elf_bss = k; - if ((elf_ppnt->p_flags & PF_X) && end_code < k) - end_code = k; - if (end_data < k) - end_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) elf_brk = k; - } - - elf_entry += load_bias; - elf_bss += load_bias; - elf_brk += load_bias; - start_code += load_bias; - end_code += load_bias; - start_data += load_bias; - end_data += load_bias; - - if (elf_interpreter) { - if (interpreter_type & 1) { - elf_entry = load_aout_interp(&interp_ex, interpreter_fd); - } - else if (interpreter_type & 2) { - elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, - &interp_load_addr); - } - reloc_func_desc = interp_load_addr; - - close(interpreter_fd); - free(elf_interpreter); - - if (elf_entry == ~((abi_ulong)0UL)) { - printf("Unable to load interpreter\n"); - free(elf_phdata); - exit(-1); - return 0; - } } - free(elf_phdata); - - if (qemu_log_enabled()) - load_symbols(&elf_ex, bprm->fd); - - if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); - info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); - -#ifdef LOW_ELF_STACK - info->start_stack = bprm->p = elf_stack - 4; -#endif - bprm->p = create_elf_tables(bprm->p, - bprm->argc, - bprm->envc, - &elf_ex, - load_addr, load_bias, - interp_load_addr, - (interpreter_type == INTERPRETER_AOUT ? 0 : 1), - info); - info->load_addr = reloc_func_desc; - info->start_brk = info->brk = elf_brk; - info->end_code = end_code; - info->start_code = start_code; - info->start_data = start_data; - info->end_data = end_data; + bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex, + info, (elf_interpreter ? &interp_info : NULL)); info->start_stack = bprm->p; - /* Calling set_brk effectively mmaps the pages that we need for the bss and break - sections */ - set_brk(elf_bss, elf_brk); - - padzero(elf_bss, elf_brk); - -#if 0 - printf("(start_brk) %x\n" , info->start_brk); - printf("(end_code) %x\n" , info->end_code); - printf("(start_code) %x\n" , info->start_code); - printf("(end_data) %x\n" , info->end_data); - printf("(start_stack) %x\n" , info->start_stack); - printf("(brk) %x\n" , info->brk); -#endif - - if ( info->personality == PER_SVR4 ) - { - /* Why this, you ask??? Well SVr4 maps page 0 as read-only, - and some applications "depend" upon this behavior. - Since we do not have the power to recompile these, we - emulate the SVr4 behavior. Sigh. */ - mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, -1, 0); + /* If we have an interpreter, set that as the program's entry point. + Copy the load_addr as well, to help PPC64 interpret the entry + point as a function descriptor. Do this after creating elf tables + so that we copy the original program entry point into the AUXV. */ + if (elf_interpreter) { + info->load_addr = interp_info.load_addr; + info->entry = interp_info.entry; + free(elf_interpreter); } - info->entry = elf_entry; - #ifdef USE_ELF_CORE_DUMP bprm->core_dump = &elf_core_dump; #endif @@ -1939,7 +1642,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } #ifdef USE_ELF_CORE_DUMP - /* * Definitions to generate Intel SVR4-like core files. * These mostly have the same names as the SVR4 types with "target_elf_" @@ -2076,17 +1778,17 @@ struct mm_struct { static struct mm_struct *vma_init(void); static void vma_delete(struct mm_struct *); static int vma_add_mapping(struct mm_struct *, abi_ulong, - abi_ulong, abi_ulong); + abi_ulong, abi_ulong); static int vma_get_mapping_count(const struct mm_struct *); static struct vm_area_struct *vma_first(const struct mm_struct *); static struct vm_area_struct *vma_next(struct vm_area_struct *); static abi_ulong vma_dump_size(const struct vm_area_struct *); static int vma_walker(void *priv, abi_ulong start, abi_ulong end, - unsigned long flags); + unsigned long flags); static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t); static void fill_note(struct memelfnote *, const char *, int, - unsigned int, void *); + unsigned int, void *); static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int); static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *); static void fill_auxv_note(struct memelfnote *, const TaskState *); @@ -2102,9 +1804,6 @@ static int write_note(struct memelfnote *, int); static int write_note_info(struct elf_note_info *, int); #ifdef BSWAP_NEEDED -static void bswap_prstatus(struct target_elf_prstatus *); -static void bswap_psinfo(struct target_elf_prpsinfo *); - static void bswap_prstatus(struct target_elf_prstatus *prstatus) { prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo); @@ -2132,6 +1831,17 @@ static void bswap_psinfo(struct target_elf_prpsinfo *psinfo) psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp); psinfo->pr_sid = tswap32(psinfo->pr_sid); } + +static void bswap_note(struct elf_note *en) +{ + bswap32s(&en->n_namesz); + bswap32s(&en->n_descsz); + bswap32s(&en->n_type); +} +#else +static inline void bswap_prstatus(struct target_elf_prstatus *p) { } +static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {} +static inline void bswap_note(struct elf_note *en) { } #endif /* BSWAP_NEEDED */ /* @@ -2166,7 +1876,7 @@ static void vma_delete(struct mm_struct *mm) } static int vma_add_mapping(struct mm_struct *mm, abi_ulong start, - abi_ulong end, abi_ulong flags) + abi_ulong end, abi_ulong flags) { struct vm_area_struct *vma; @@ -2235,7 +1945,7 @@ static abi_ulong vma_dump_size(const struct vm_area_struct *vma) } static int vma_walker(void *priv, abi_ulong start, abi_ulong end, - unsigned long flags) + unsigned long flags) { struct mm_struct *mm = (struct mm_struct *)priv; @@ -2244,7 +1954,7 @@ static int vma_walker(void *priv, abi_ulong start, abi_ulong end, } static void fill_note(struct memelfnote *note, const char *name, int type, - unsigned int sz, void *data) + unsigned int sz, void *data) { unsigned int namesz; @@ -2265,7 +1975,7 @@ static void fill_note(struct memelfnote *note, const char *name, int type, } static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine, - uint32_t flags) + uint32_t flags) { (void) memset(elf, 0, sizeof(*elf)); @@ -2284,9 +1994,7 @@ static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine, elf->e_phentsize = sizeof(struct elf_phdr); elf->e_phnum = segs; -#ifdef BSWAP_NEEDED bswap_ehdr(elf); -#endif } static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset) @@ -2300,9 +2008,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset) phdr->p_flags = 0; phdr->p_align = 0; -#ifdef BSWAP_NEEDED - bswap_phdr(phdr); -#endif + bswap_phdr(phdr, 1); } static size_t note_size(const struct memelfnote *note) @@ -2311,7 +2017,7 @@ static size_t note_size(const struct memelfnote *note) } static void fill_prstatus(struct target_elf_prstatus *prstatus, - const TaskState *ts, int signr) + const TaskState *ts, int signr) { (void) memset(prstatus, 0, sizeof (*prstatus)); prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; @@ -2320,9 +2026,7 @@ static void fill_prstatus(struct target_elf_prstatus *prstatus, prstatus->pr_pgrp = getpgrp(); prstatus->pr_sid = getsid(0); -#ifdef BSWAP_NEEDED bswap_prstatus(prstatus); -#endif } static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts) @@ -2352,13 +2056,11 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts) filename = strdup(ts->bprm->filename); base_filename = strdup(basename(filename)); (void) strncpy(psinfo->pr_fname, base_filename, - sizeof(psinfo->pr_fname)); + sizeof(psinfo->pr_fname)); free(base_filename); free(filename); -#ifdef BSWAP_NEEDED bswap_psinfo(psinfo); -#endif return (0); } @@ -2401,7 +2103,7 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts) * Returns 0 in case of success, -1 otherwise (errno is set). */ static int core_dump_filename(const TaskState *ts, char *buf, - size_t bufsize) + size_t bufsize) { char timestamp[64]; char *filename = NULL; @@ -2413,16 +2115,16 @@ static int core_dump_filename(const TaskState *ts, char *buf, if (gettimeofday(&tv, NULL) < 0) { (void) fprintf(stderr, "unable to get current timestamp: %s", - strerror(errno)); + strerror(errno)); return (-1); } filename = strdup(ts->bprm->filename); base_filename = strdup(basename(filename)); (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S", - localtime_r(&tv.tv_sec, &tm)); + localtime_r(&tv.tv_sec, &tm)); (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core", - base_filename, timestamp, (int)getpid()); + base_filename, timestamp, (int)getpid()); free(base_filename); free(filename); @@ -2483,9 +2185,7 @@ static int write_note(struct memelfnote *men, int fd) en.n_type = men->type; en.n_descsz = men->datasz; -#ifdef BSWAP_NEEDED bswap_note(&en); -#endif if (dump_write(fd, &en, sizeof(en)) != 0) return (-1); @@ -2507,7 +2207,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env) fill_prstatus(&ets->prstatus, ts, 0); elf_core_copy_regs(&ets->prstatus.pr_reg, env); fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus), - &ets->prstatus); + &ets->prstatus); QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link); @@ -2515,7 +2215,7 @@ static void fill_thread_info(struct elf_note_info *info, const CPUState *env) } static int fill_note_info(struct elf_note_info *info, - long signr, const CPUState *env) + long signr, const CPUState *env) { #define NUMNOTES 3 CPUState *cpu = NULL; @@ -2543,10 +2243,10 @@ static int fill_note_info(struct elf_note_info *info, fill_prstatus(info->prstatus, ts, signr); elf_core_copy_regs(&info->prstatus->pr_reg, env); fill_note(&info->notes[0], "CORE", NT_PRSTATUS, - sizeof (*info->prstatus), info->prstatus); + sizeof (*info->prstatus), info->prstatus); fill_psinfo(info->psinfo, ts); fill_note(&info->notes[1], "CORE", NT_PRPSINFO, - sizeof (*info->psinfo), info->psinfo); + sizeof (*info->psinfo), info->psinfo); fill_auxv_note(&info->notes[2], ts); info->numnote = 3; @@ -2593,7 +2293,7 @@ static int write_note_info(struct elf_note_info *info, int fd) /* write prstatus for each thread */ for (ets = info->thread_list.tqh_first; ets != NULL; - ets = ets->ets_link.tqe_next) { + ets = ets->ets_link.tqe_next) { if ((error = write_note(&ets->notes[0], fd)) != 0) return (error); } @@ -2661,13 +2361,13 @@ static int elf_core_dump(int signr, const CPUState *env) errno = 0; getrlimit(RLIMIT_CORE, &dumpsize); if (dumpsize.rlim_cur == 0) - return 0; + return 0; if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0) return (-errno); if ((fd = open(corefile, O_WRONLY | O_CREAT, - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) return (-errno); /* @@ -2756,7 +2456,7 @@ static int elf_core_dump(int signr, const CPUState *env) end = vma->vma_start + vma_dump_size(vma); for (addr = vma->vma_start; addr < end; - addr += TARGET_PAGE_SIZE) { + addr += TARGET_PAGE_SIZE) { char page[TARGET_PAGE_SIZE]; int error; @@ -2767,7 +2467,7 @@ static int elf_core_dump(int signr, const CPUState *env) error = copy_from_user(page, addr, sizeof (page)); if (error != 0) { (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n", - addr); + addr); errno = -error; goto out; } @@ -2776,7 +2476,7 @@ static int elf_core_dump(int signr, const CPUState *env) } } -out: + out: free_note_info(&info); if (mm != NULL) vma_delete(mm); @@ -2786,15 +2486,8 @@ out: return (-errno); return (0); } - #endif /* USE_ELF_CORE_DUMP */ -static int load_aout_interp(void * exptr, int interp_fd) -{ - printf("a.out interpreter not yet supported\n"); - return(0); -} - void do_init_thread(struct target_pt_regs *regs, struct image_info *infop) { init_thread(regs, infop); diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 8ad130a2bd..8f9f4a5fcc 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -383,7 +383,8 @@ static int load_flat_file(struct linux_binprm * bprm, struct lib_info *libinfo, int id, abi_ulong *extra_stack) { struct flat_hdr * hdr; - abi_ulong textpos = 0, datapos = 0, result; + abi_ulong textpos = 0, datapos = 0; + abi_long result; abi_ulong realdatastart = 0; abi_ulong text_len, data_len, bss_len, stack_len, flags; abi_ulong memp = 0; /* for finding the brk area */ diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 13ad9aaebe..9ee27c3558 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -96,18 +96,16 @@ static int prepare_binprm(struct linux_binprm *bprm) } } - retval = lseek(bprm->fd, 0L, SEEK_SET); - if(retval >= 0) { - retval = read(bprm->fd, bprm->buf, 128); - } - if(retval < 0) { + retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE); + if (retval < 0) { perror("prepare_binprm"); exit(-1); - /* return(-errno); */ } - else { - return(retval); + if (retval < BPRM_BUF_SIZE) { + /* Make sure the rest of the loader won't read garbage. */ + memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval); } + return retval; } /* Construct the envp and argv tables on the target stack. */ @@ -163,8 +161,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, int i; bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); - for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ - bprm->page[i] = NULL; + memset(bprm->page, 0, sizeof(bprm->page)); retval = open(filename, O_RDONLY); if (retval < 0) return retval; diff --git a/linux-user/m68k-sim.c b/linux-user/m68k-sim.c index 64d3b23d68..d5926eec4b 100644 --- a/linux-user/m68k-sim.c +++ b/linux-user/m68k-sim.c @@ -38,7 +38,7 @@ #define SYS_ISATTY 29 #define SYS_LSEEK 199 -struct m86k_sim_stat { +struct m68k_sim_stat { uint16_t sim_st_dev; uint16_t sim_st_ino; uint32_t sim_st_mode; @@ -138,10 +138,10 @@ void do_m68k_simcall(CPUM68KState *env, int nr) { struct stat s; int rc; - struct m86k_sim_stat *p; + struct m68k_sim_stat *p; rc = check_err(env, fstat(ARG(0), &s)); if (rc == 0) { - p = (struct m86k_sim_stat *)(unsigned long)ARG(1); + p = (struct m68k_sim_stat *)(unsigned long)ARG(1); p->sim_st_dev = tswap16(s.st_dev); p->sim_st_ino = tswap16(s.st_ino); p->sim_st_mode = tswap32(s.st_mode); diff --git a/linux-user/main.c b/linux-user/main.c index 403c8d3b96..dbba8befe7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2233,6 +2233,37 @@ void cpu_loop (CPUState *env) env->regs[3] = ret; env->sregs[SR_PC] = env->regs[14]; break; + case EXCP_HW_EXCP: + env->regs[17] = env->sregs[SR_PC] + 4; + if (env->iflags & D_FLAG) { + env->sregs[SR_ESR] |= 1 << 12; + env->sregs[SR_PC] -= 4; + /* FIXME: if branch was immed, replay the imm aswell. */ + } + + env->iflags &= ~(IMM_FLAG | D_FLAG); + + switch (env->sregs[SR_ESR] & 31) { + case ESR_EC_FPU: + info.si_signo = SIGFPE; + info.si_errno = 0; + if (env->sregs[SR_FSR] & FSR_IO) { + info.si_code = TARGET_FPE_FLTINV; + } + if (env->sregs[SR_FSR] & FSR_DZ) { + info.si_code = TARGET_FPE_FLTDIV; + } + info._sifields._sigfault._addr = 0; + queue_signal(env, info.si_signo, &info); + break; + default: + printf ("Unhandled hw-exception: 0x%x\n", + env->sregs[SR_ESR] & 5); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + break; + } + break; case EXCP_DEBUG: { int sig; @@ -2759,6 +2790,12 @@ int main(int argc, char **argv, char **envp) r = argv[optind++]; if (envlist_setenv(envlist, r) != 0) usage(); + } else if (!strcmp(r, "ignore-environment")) { + envlist_free(envlist); + if ((envlist = envlist_create()) == NULL) { + (void) fprintf(stderr, "Unable to allocate envlist\n"); + exit(1); + } } else if (!strcmp(r, "U")) { r = argv[optind++]; if (envlist_unsetenv(envlist, r) != 0) @@ -2800,6 +2837,8 @@ int main(int argc, char **argv, char **envp) /* XXX: implement xxx_cpu_list for targets that still miss it */ #if defined(cpu_list_id) cpu_list_id(stdout, &fprintf, ""); +#elif defined(cpu_list) + cpu_list(stdout, &fprintf); /* deprecated */ #endif exit(1); } diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 39da6dfb40..035dfbd076 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -225,13 +225,13 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size) int prot; int looped = 0; - if (size > reserved_va) { + if (size > RESERVED_VA) { return (abi_ulong)-1; } last_addr = start; for (addr = start; last_addr + size != addr; addr += qemu_host_page_size) { - if (last_addr + size >= reserved_va + if (last_addr + size >= RESERVED_VA || (abi_ulong)(last_addr + size) < last_addr) { if (looped) { return (abi_ulong)-1; @@ -271,7 +271,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) size = HOST_PAGE_ALIGN(size); - if (reserved_va) { + if (RESERVED_VA) { return mmap_find_vma_reserved(start, size); } @@ -342,7 +342,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) munmap(ptr, size); /* ENOMEM if we checked the whole of the target address space. */ - if (addr == -1ul) { + if (addr == (abi_ulong)-1) { return (abi_ulong)-1; } else if (addr == 0) { if (wrapped) { @@ -651,7 +651,7 @@ int target_munmap(abi_ulong start, abi_ulong len) ret = 0; /* unmap what we can */ if (real_start < real_end) { - if (reserved_va) { + if (RESERVED_VA) { mmap_reserve(real_start, real_end - real_start); } else { ret = munmap(g2h(real_start), real_end - real_start); @@ -679,7 +679,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, flags, g2h(new_addr)); - if (reserved_va && host_addr != MAP_FAILED) { + if (RESERVED_VA && host_addr != MAP_FAILED) { /* If new and old addresses overlap then the above mremap will already have failed with EINVAL. */ mmap_reserve(old_addr, old_size); @@ -701,7 +701,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, } } else { int prot = 0; - if (reserved_va && old_size < new_size) { + if (RESERVED_VA && old_size < new_size) { abi_ulong addr; for (addr = old_addr + old_size; addr < old_addr + new_size; @@ -711,7 +711,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, } if (prot == 0) { host_addr = mremap(g2h(old_addr), old_size, new_size, flags); - if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) { + if (host_addr != MAP_FAILED && RESERVED_VA && old_size > new_size) { mmap_reserve(old_addr + old_size, new_size - old_size); } } else { diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 1878d5a61e..708021e006 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -31,6 +31,7 @@ * task_struct fields in the kernel */ struct image_info { + abi_ulong load_bias; abi_ulong load_addr; abi_ulong start_code; abi_ulong end_code; @@ -144,12 +145,16 @@ extern unsigned long mmap_min_addr; */ #define MAX_ARG_PAGES 33 +/* Read a good amount of data initially, to hopefully get all the + program headers loaded. */ +#define BPRM_BUF_SIZE 1024 + /* * This structure is used to hold the arguments that are * used when loading binaries. */ struct linux_binprm { - char buf[128]; + char buf[BPRM_BUF_SIZE] __attribute__((aligned)); void *page[MAX_ARG_PAGES]; abi_ulong p; int fd; @@ -181,7 +186,7 @@ void syscall_init(void); abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); -void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2); extern THREAD CPUState *thread_env; void cpu_loop(CPUState *env); char *target_strerror(int err); diff --git a/linux-user/signal.c b/linux-user/signal.c index e5a187e106..77683f7534 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -3064,9 +3064,23 @@ struct target_sigcontext { uint32_t oldmask; }; +struct target_stack_t { + abi_ulong ss_sp; + int ss_flags; + unsigned int ss_size; +}; + +struct target_ucontext { + abi_ulong uc_flags; + abi_ulong uc_link; + struct target_stack_t uc_stack; + struct target_sigcontext sc; + uint32_t extramask[TARGET_NSIG_WORDS - 1]; +}; + /* Signal frames. */ struct target_signal_frame { - struct target_sigcontext sc; + struct target_ucontext uc; uint32_t extramask[TARGET_NSIG_WORDS - 1]; uint32_t tramp[2]; }; @@ -3175,7 +3189,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, goto badframe; /* Save the mask. */ - err |= __put_user(set->sig[0], &frame->sc.oldmask); + err |= __put_user(set->sig[0], &frame->uc.sc.oldmask); if (err) goto badframe; @@ -3184,7 +3198,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, goto badframe; } - setup_sigcontext(&frame->sc, env); + setup_sigcontext(&frame->uc.sc, env); /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -3213,7 +3227,8 @@ static void setup_frame(int sig, struct target_sigaction *ka, env->regs[1] = (unsigned long) frame; /* Signal handler args: */ env->regs[5] = sig; /* Arg 0: signum */ - env->regs[6] = (unsigned long) &frame->sc; /* arg 1: sigcontext */ + env->regs[6] = 0; + env->regs[7] = (unsigned long) &frame->uc; /* arg 1: sigcontext */ /* Offset of 4 to handle microblaze rtid r14, 0 */ env->sregs[SR_PC] = (unsigned long)ka->_sa_handler; @@ -3246,7 +3261,7 @@ long do_sigreturn(CPUState *env) goto badframe; /* Restore blocked signals */ - if (__get_user(target_set.sig[0], &frame->sc.oldmask)) + if (__get_user(target_set.sig[0], &frame->uc.sc.oldmask)) goto badframe; for(i = 1; i < TARGET_NSIG_WORDS; i++) { if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) @@ -3255,7 +3270,7 @@ long do_sigreturn(CPUState *env) target_to_host_sigset_internal(&set, &target_set); sigprocmask(SIG_SETMASK, &set, NULL); - restore_sigcontext(&frame->sc, env); + restore_sigcontext(&frame->uc.sc, env); /* We got here through a sigreturn syscall, our path back is via an rtb insn so setup r14 for that. */ env->regs[14] = env->sregs[SR_PC]; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0ebe7e1c26..d44f512ed3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1551,8 +1551,9 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr, void *addr; abi_long ret; - if (addrlen < 0) + if ((int)addrlen < 0) { return -TARGET_EINVAL; + } addr = alloca(addrlen+1); @@ -1570,8 +1571,9 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr, void *addr; abi_long ret; - if (addrlen < 0) + if ((int)addrlen < 0) { return -TARGET_EINVAL; + } addr = alloca(addrlen); @@ -1656,8 +1658,9 @@ static abi_long do_accept(int fd, abi_ulong target_addr, if (get_user_u32(addrlen, target_addrlen_addr)) return -TARGET_EINVAL; - if (addrlen < 0) + if ((int)addrlen < 0) { return -TARGET_EINVAL; + } if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) return -TARGET_EINVAL; @@ -1684,8 +1687,9 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr, if (get_user_u32(addrlen, target_addrlen_addr)) return -TARGET_EFAULT; - if (addrlen < 0) + if ((int)addrlen < 0) { return -TARGET_EINVAL; + } if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) return -TARGET_EFAULT; @@ -1712,8 +1716,9 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr, if (get_user_u32(addrlen, target_addrlen_addr)) return -TARGET_EFAULT; - if (addrlen < 0) + if ((int)addrlen < 0) { return -TARGET_EINVAL; + } if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) return -TARGET_EFAULT; @@ -1753,8 +1758,9 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, void *host_msg; abi_long ret; - if (addrlen < 0) + if ((int)addrlen < 0) { return -TARGET_EINVAL; + } host_msg = lock_user(VERIFY_READ, msg, len, 1); if (!host_msg) @@ -1792,7 +1798,7 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, ret = -TARGET_EFAULT; goto fail; } - if (addrlen < 0) { + if ((int)addrlen < 0) { ret = -TARGET_EINVAL; goto fail; } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 46cb05ea9f..6c57e2481a 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1282,7 +1282,10 @@ struct target_stat { /* FIXME: Microblaze no-mmu user-space has a difference stat64 layout... */ struct __attribute__((__packed__)) target_stat64 { uint64_t st_dev; - uint64_t st_ino; +#define TARGET_STAT64_HAS_BROKEN_ST_INO 1 + uint32_t pad0; + uint32_t __st_ino; + uint32_t st_mode; uint32_t st_nlink; uint32_t st_uid; @@ -1296,13 +1299,12 @@ struct __attribute__((__packed__)) target_stat64 { int64_t st_blocks; /* Number 512-byte blocks allocated. */ int target_st_atime; - unsigned int target_st_atime_nsec; + unsigned int target_st_atime_nsec; int target_st_mtime; - unsigned int target_st_mtime_nsec; + unsigned int target_st_mtime_nsec; int target_st_ctime; - unsigned int target_st_ctime_nsec; - uint32_t __unused4; - uint32_t __unused5; + unsigned int target_st_ctime_nsec; + uint64_t st_ino; }; #elif defined(TARGET_M68K) |