qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c
@ 2010-07-27 17:25 Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
                   ` (13 more replies)
  0 siblings, 14 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

A re-based and re-tested version of a patch series I
posted back in April and May.  These cleanups prepare
elfload.c for loading the VDSO for x86_64.


r~


Richard Henderson (12):
  linux-user: Handle filesz < memsz for any PT_LOAD segment.
  Add more DT_* and AT_* constants to qemu's copy of elf.h.
  linux-user: Reindent elfload.c.
  linux-user: Reduce lseek+reads while loading elf files.
  linux-user: Define ELF_DATA generically.
  linux-user: Clean up byte-swapping in elfload.c.
  linux-user: Load symbols from the interpreter.
  linux-user: Improve consistency checking in elf headers.
  linux-user: Put the stack guard page at the top.
  linux-user: Remove partial support for a.out interpreters.
  linux-user: Extract load_elf_image from load_elf_interp.
  linux-user: Re-use load_elf_image for the main binary.

 elf.h                  |   44 ++
 linux-user/elfload.c   | 1791 ++++++++++++++++++++----------------------------
 linux-user/linuxload.c |   17 +-
 linux-user/qemu.h      |    7 +-
 4 files changed, 794 insertions(+), 1065 deletions(-)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 02/12] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

I caught padzero not properly initializing the .bss segment
on a statically linked Alpha program.  Rather than a minimal
patch, replace the gross code with a single mmap+memset.

Share more code between load_elf_interp and load_elf_binary.

Legally, an ELF program need not have just a single .bss;
and PT_LOAD segment can have memsz > filesz.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |  150 ++++++++++++++++++--------------------------------
 1 files changed, 54 insertions(+), 96 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index accb44d..5a0d3d4 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1034,60 +1034,47 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
     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;
+
+    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);
         }
 
-        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);
-        }
-}
+        /* 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,
@@ -1179,12 +1166,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
 	abi_ulong load_addr = 0;
 	int load_addr_set = 0;
 	int retval;
-	abi_ulong last_bss, elf_bss;
 	abi_ulong error;
 	int i;
 
-	elf_bss = 0;
-	last_bss = 0;
 	error = 0;
 
 #ifdef BSWAP_NEEDED
@@ -1257,7 +1241,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
 	    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;
@@ -1285,40 +1268,17 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
 	      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;
+            /* If the load segment requests extra zeros (e.g. bss), map it.  */
+            if (eppnt->p_filesz < eppnt->p_memsz) {
+                abi_ulong base = load_addr + eppnt->p_vaddr;
+                zero_bss(base + eppnt->p_filesz,
+                         base + eppnt->p_memsz, elf_prot);
+            }
 	  }
 
 	/* 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;
@@ -1472,7 +1432,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     abi_ulong mapped_addr;
     struct elf_phdr * elf_ppnt;
     struct elf_phdr *elf_phdata;
-    abi_ulong elf_bss, k, elf_brk;
+    abi_ulong k, elf_brk;
     int retval;
     char * elf_interpreter;
     abi_ulong elf_entry, interp_load_addr = 0;
@@ -1531,10 +1491,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 #endif
     elf_ppnt = elf_phdata;
 
-    elf_bss = 0;
     elf_brk = 0;
 
-
     elf_stack = ~((abi_ulong)0UL);
     elf_interpreter = NULL;
     start_code = ~((abi_ulong)0UL);
@@ -1838,18 +1796,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
         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;
+        if (k > elf_brk) {
+            elf_brk = TARGET_PAGE_ALIGN(k);
+        }
+
+        /* If the load segment requests extra zeros (e.g. bss), map it.  */
+        if (elf_ppnt->p_filesz < elf_ppnt->p_memsz) {
+            abi_ulong base = load_bias + elf_ppnt->p_vaddr;
+            zero_bss(base + elf_ppnt->p_filesz,
+                     base + elf_ppnt->p_memsz, elf_prot);
+        }
     }
 
     elf_entry += load_bias;
-    elf_bss += load_bias;
     elf_brk += load_bias;
     start_code += load_bias;
     end_code += load_bias;
@@ -1904,12 +1868,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     info->end_data = end_data;
     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);
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 02/12] Add more DT_* and AT_* constants to qemu's copy of elf.h.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 03/12] linux-user: Reindent elfload.c Richard Henderson
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

Moving some PPC AT_* constants from elfload.c at the same time.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 elf.h                |   44 ++++++++++++++++++++++++++++++++++++++++++++
 linux-user/elfload.c |    9 ---------
 2 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/elf.h b/elf.h
index eb9e3be..7067c90 100644
--- a/elf.h
+++ b/elf.h
@@ -147,8 +147,37 @@ typedef int64_t  Elf64_Sxword;
 #define DT_DEBUG	21
 #define DT_TEXTREL	22
 #define DT_JMPREL	23
+#define DT_BINDNOW	24
+#define DT_INIT_ARRAY	25
+#define DT_FINI_ARRAY	26
+#define DT_INIT_ARRAYSZ	27
+#define DT_FINI_ARRAYSZ	28
+#define DT_RUNPATH	29
+#define DT_FLAGS	30
+#define DT_LOOS		0x6000000d
+#define DT_HIOS		0x6ffff000
 #define DT_LOPROC	0x70000000
 #define DT_HIPROC	0x7fffffff
+
+/* DT_ entries which fall between DT_VALRNGLO and DT_VALRNDHI use
+   the d_val field of the Elf*_Dyn structure.  I.e. they contain scalars.  */
+#define DT_VALRNGLO	0x6ffffd00
+#define DT_VALRNGHI	0x6ffffdff
+
+/* DT_ entries which fall between DT_ADDRRNGLO and DT_ADDRRNGHI use
+   the d_ptr field of the Elf*_Dyn structure.  I.e. they contain pointers.  */
+#define DT_ADDRRNGLO	0x6ffffe00
+#define DT_ADDRRNGHI	0x6ffffeff
+
+#define	DT_VERSYM	0x6ffffff0
+#define DT_RELACOUNT	0x6ffffff9
+#define DT_RELCOUNT	0x6ffffffa
+#define DT_FLAGS_1	0x6ffffffb
+#define DT_VERDEF	0x6ffffffc
+#define DT_VERDEFNUM	0x6ffffffd
+#define DT_VERNEED	0x6ffffffe
+#define DT_VERNEEDNUM	0x6fffffff
+
 #define DT_MIPS_RLD_VERSION	0x70000001
 #define DT_MIPS_TIME_STAMP	0x70000002
 #define DT_MIPS_ICHECKSUM	0x70000003
@@ -207,6 +236,21 @@ typedef int64_t  Elf64_Sxword;
 #define AT_PLATFORM 15  /* string identifying CPU for optimizations */
 #define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
 #define AT_CLKTCK 17	/* frequency at which times() increments */
+#define AT_FPUCW  18	/* info about fpu initialization by kernel */
+#define AT_DCACHEBSIZE	19	/* data cache block size */
+#define AT_ICACHEBSIZE	20	/* instruction cache block size */
+#define AT_UCACHEBSIZE	21	/* unified cache block size */
+#define AT_IGNOREPPC	22	/* ppc only; entry should be ignored */
+#define AT_SECURE	23	/* boolean, was exec suid-like? */
+#define AT_BASE_PLATFORM 24	/* string identifying real platforms */
+#define AT_RANDOM	25	/* address of 16 random bytes */
+#define AT_EXECFN	31	/* filename of the executable */
+#define AT_SYSINFO	32	/* address of kernel entry point */
+#define AT_SYSINFO_EHDR	33	/* address of kernel vdso */
+#define AT_L1I_CACHESHAPE 34	/* shapes of the caches: */
+#define AT_L1D_CACHESHAPE 35	/*   bits 0-3: cache associativity.  */
+#define AT_L2_CACHESHAPE  36	/*   bits 4-7: log2 of line size.  */
+#define AT_L3_CACHESHAPE  37	/*   val&~255: cache size.  */
 
 typedef struct dynamic{
   Elf32_Sword d_tag;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5a0d3d4..2727222 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -480,15 +480,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
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 03/12] linux-user: Reindent elfload.c.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 02/12] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 04/12] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c | 1028 +++++++++++++++++++++++++-------------------------
 1 files changed, 518 insertions(+), 510 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 2727222..6ea1e8d 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,15 @@ enum {
 #define ELIBBAD 80
 #endif
 
-typedef target_ulong	target_elf_greg_t;
+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 +124,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
@@ -197,11 +195,12 @@ 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_DATA        ELFDATA2LSB
+#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 +248,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 +258,22 @@ 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
+#define ELF_CLASS       ELFCLASS32
 #ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA	ELFDATA2MSB
+#define ELF_DATA        ELFDATA2MSB
 #else
-#define ELF_DATA	ELFDATA2LSB
+#define ELF_DATA        ELFDATA2LSB
 #endif
-#define ELF_ARCH	EM_ARM
+#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 +313,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
 
@@ -355,9 +355,10 @@ enum
 #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;
@@ -384,7 +385,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
 #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 +406,22 @@ 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
+#define ELF_DATA        ELFDATA2MSB
 #else
-#define ELF_DATA	ELFDATA2LSB
+#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 +466,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);
@@ -489,17 +491,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)
 {
@@ -537,7 +539,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
 
@@ -553,13 +555,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
 #define ELF_CLASS   ELFCLASS32
 #endif
 #ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA	ELFDATA2MSB
+#define ELF_DATA        ELFDATA2MSB
 #else
-#define ELF_DATA	ELFDATA2LSB
+#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;
@@ -623,10 +626,11 @@ 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_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;
@@ -665,11 +669,12 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
 #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.  */
@@ -687,7 +692,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;
 
@@ -719,9 +725,10 @@ static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState
 #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
@@ -734,14 +741,15 @@ 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_DATA        ELFDATA2MSB
+#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;
@@ -777,7 +785,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
 
@@ -791,7 +799,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
 #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;
@@ -821,14 +830,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 */
 };
 
 
@@ -857,7 +866,7 @@ struct exec
 
 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);
@@ -865,31 +874,31 @@ 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 */
+    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 */
+    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)
@@ -942,24 +951,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);
@@ -967,20 +976,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;
 }
@@ -1014,12 +1023,12 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
     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;
@@ -1074,77 +1083,77 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
                                    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;
+    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 += (!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);
 #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, !ibcs);
+    return sp;
 }
 
 
@@ -1152,112 +1161,112 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                  int interpreter_fd,
                                  abi_ulong *interp_load_addr)
 {
-	struct elf_phdr *elf_phdata  =  NULL;
-	struct elf_phdr *eppnt;
-	abi_ulong load_addr = 0;
-	int load_addr_set = 0;
-	int retval;
-	abi_ulong error;
-	int i;
+    struct elf_phdr *elf_phdata  =  NULL;
+    struct elf_phdr *eppnt;
+    abi_ulong load_addr = 0;
+    int load_addr_set = 0;
+    int retval;
+    abi_ulong error;
+    int i;
 
-	error = 0;
+    error = 0;
 
 #ifdef BSWAP_NEEDED
-        bswap_ehdr(interp_elf_ex);
+    bswap_ehdr(interp_elf_ex);
 #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);
-	}
+    /* 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);
+    }
 
 
-	/* Now read in all of the header information */
+    /* Now read in all of the header information */
 
-	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
-	    return ~(abi_ulong)0UL;
+    if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
+        return ~(abi_ulong)0UL;
 
-	elf_phdata =  (struct elf_phdr *)
-		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+    elf_phdata =  (struct elf_phdr *)
+        malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
 
-	if (!elf_phdata)
-	  return ~((abi_ulong)0UL);
+    if (!elf_phdata)
+        return ~((abi_ulong)0UL);
 
-	/*
-	 * 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);
-        }
+    /*
+     * 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);
+    }
 
-	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;
- 	}
+    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);
-        }
+    eppnt = elf_phdata;
+    for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
+        bswap_phdr(eppnt);
+    }
 #endif
 
-        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 (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);
+        }
+        load_addr = error;
+        load_addr_set = 1;
+    }
+
+    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;
+
+            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) {
-                perror("mmap");
-                exit(-1);
+                /* Real error */
+                close(interpreter_fd);
+                free(elf_phdata);
+                return ~((abi_ulong)0UL);
             }
-            load_addr = error;
-            load_addr_set = 1;
-        }
 
-	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;
-
-	    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;
-	    }
+            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+                load_addr = error;
+                load_addr_set = 1;
+            }
 
             /* If the load segment requests extra zeros (e.g. bss), map it.  */
             if (eppnt->p_filesz < eppnt->p_memsz) {
@@ -1265,15 +1274,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                 zero_bss(base + eppnt->p_filesz,
                          base + eppnt->p_memsz, elf_prot);
             }
-	  }
+        }
 
-	/* Now use mmap to map the library into memory. */
+    /* Now use mmap to map the library into memory. */
 
-	close(interpreter_fd);
-	free(elf_phdata);
+    close(interpreter_fd);
+    free(elf_phdata);
 
-	*interp_load_addr = load_addr;
-	return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+    *interp_load_addr = load_addr;
+    return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
 }
 
 static int symfind(const void *s0, const void *s1)
@@ -1375,8 +1384,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
 #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) {
+            syms[i].st_shndx >= SHN_LORESERVE ||
+            ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
             nsyms--;
             if (i < nsyms) {
                 syms[i] = syms[nsyms];
@@ -1444,8 +1453,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 
     /* 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;
+        (! elf_check_arch(elf_ex.e_machine))) {
+        return -ENOEXEC;
     }
 
     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
@@ -1458,20 +1467,20 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     /* 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;
+        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);
+        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;
+        perror("load_elf_binary");
+        exit(-1);
+        free (elf_phdata);
+        return -errno;
     }
 
 #ifdef BSWAP_NEEDED
@@ -1493,131 +1502,131 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     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;
-	    }
+        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;
+            }
 
 #if 0
-	    printf("Using ELF interpreter %s\n", path(elf_interpreter));
+            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++;
+            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;
+        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;
-	}
+        /* 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 ||
+        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;
-	}
+            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;
-	}
+        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 */
@@ -1644,7 +1653,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
         unsigned long real_start;
         unsigned long host_size;
         for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
-            i++, elf_ppnt++) {
+             i++, elf_ppnt++) {
             if (elf_ppnt->p_type != PT_LOAD)
                 continue;
             addr = elf_ppnt->p_vaddr;
@@ -1728,7 +1737,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
         int elf_flags = 0;
         abi_ulong error;
 
-	if (elf_ppnt->p_type != PT_LOAD)
+        if (elf_ppnt->p_type != PT_LOAD)
             continue;
 
         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
@@ -1812,30 +1821,30 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     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);
-	}
+        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);
+        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;
-	}
+        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);
+        load_symbols(&elf_ex, bprm->fd);
 
     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
@@ -1844,13 +1853,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     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);
+                                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;
@@ -1870,12 +1879,12 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 
     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);
+        /* 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);
     }
 
     info->entry = elf_entry;
@@ -1888,7 +1897,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_"
@@ -2025,17 +2033,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 *);
@@ -2115,7 +2123,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;
 
@@ -2184,7 +2192,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;
 
@@ -2193,7 +2201,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;
 
@@ -2214,7 +2222,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));
 
@@ -2260,7 +2268,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;
@@ -2301,7 +2309,7 @@ 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);
 
@@ -2350,7 +2358,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;
@@ -2362,16 +2370,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);
 
@@ -2456,7 +2464,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);
 
@@ -2464,7 +2472,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;
@@ -2492,10 +2500,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;
 
@@ -2542,7 +2550,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);
     }
@@ -2610,13 +2618,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);
 
     /*
@@ -2705,7 +2713,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;
 
@@ -2716,7 +2724,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;
             }
@@ -2725,7 +2733,7 @@ static int elf_core_dump(int signr, const CPUState *env)
         }
     }
 
-out:
+ out:
     free_note_info(&info);
     if (mm != NULL)
         vma_delete(mm);
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 04/12] linux-user: Reduce lseek+reads while loading elf files.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (2 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 03/12] linux-user: Reindent elfload.c Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 05/12] linux-user: Define ELF_DATA generically Richard Henderson
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

Define BPRM_BUF_SIZE to 1k and read that amount initially.  If the
data we want from the binary is in this buffer, use it instead of
reading from the file again.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c   |  104 ++++++++++++++++++++---------------------------
 linux-user/linuxload.c |   17 +++-----
 linux-user/qemu.h      |    7 +++-
 3 files changed, 57 insertions(+), 71 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 6ea1e8d..4a48c85 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1159,7 +1159,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
 
 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                  int interpreter_fd,
-                                 abi_ulong *interp_load_addr)
+                                 abi_ulong *interp_load_addr,
+                                 char bprm_buf[BPRM_BUF_SIZE])
 {
     struct elf_phdr *elf_phdata  =  NULL;
     struct elf_phdr *eppnt;
@@ -1202,17 +1203,15 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         return ~((abi_ulong)0UL);
     }
 
-    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;
+    i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
+    if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
+        memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+    } else {
+        retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+        if (retval != i) {
+            perror("load_elf_interp");
+            exit(-1);
+        }
     }
 #ifdef BSWAP_NEEDED
     eppnt = elf_phdata;
@@ -1470,17 +1469,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
         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;
+    i = elf_ex.e_phnum * sizeof(struct elf_phdr);
+    if (elf_ex.e_phoff + i <= BPRM_BUF_SIZE) {
+        memcpy(elf_phdata, bprm->buf + elf_ex.e_phoff, i);
+    } else {
+        retval = pread(bprm->fd, (char *) elf_phdata, i, elf_ex.e_phoff);
+        if (retval != i) {
+            perror("load_elf_binary");
+            exit(-1);
+        }
     }
 
 #ifdef BSWAP_NEEDED
@@ -1524,13 +1521,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                 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 (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
+                memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
+                       elf_ppnt->p_filesz);
+            } else {
+                retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
+                               elf_ppnt->p_offset);
+                if (retval != elf_ppnt->p_filesz) {
+                    perror("load_elf_binary2");
+                    exit(-1);
+                }
             }
 
             /* If the program interpreter is one of these two,
@@ -1544,39 +1544,24 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                 ibcs2_interpreter = 1;
             }
 
-#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; */
-                }
+            retval = open(path(elf_interpreter), O_RDONLY);
+            if (retval < 0) {
+                perror(elf_interpreter);
+                exit(-1);
             }
+            interpreter_fd = retval;
 
-            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 */
-            }
+            retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
             if (retval < 0) {
                 perror("load_elf_binary3");
                 exit(-1);
-                free (elf_phdata);
-                free(elf_interpreter);
-                close(bprm->fd);
-                return retval;
             }
+            if (retval < BPRM_BUF_SIZE) {
+                memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
+            }
+
+            interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
+            interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
         }
         elf_ppnt++;
     }
@@ -1823,10 +1808,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     if (elf_interpreter) {
         if (interpreter_type & 1) {
             elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
-        }
-        else if (interpreter_type & 2) {
+        } else if (interpreter_type & 2) {
             elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
-                                        &interp_load_addr);
+                                        &interp_load_addr, bprm->buf);
         }
         reloc_func_desc = interp_load_addr;
 
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 13ad9aa..9ee27c3 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/qemu.h b/linux-user/qemu.h
index 1878d5a..0a61274 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;
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 05/12] linux-user: Define ELF_DATA generically.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (3 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 04/12] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 06/12] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

The only consideration on this value is the target endianness.
The existing defines were incorrect for alpha and sh4eb.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |   30 ++++++------------------------
 1 files changed, 6 insertions(+), 24 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 4a48c85..a757dc9 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -95,6 +95,12 @@ enum {
 #define ELIBBAD 80
 #endif
 
+#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;
@@ -132,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)
@@ -196,7 +201,6 @@ 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
 
 static inline void init_thread(struct target_pt_regs *regs,
@@ -259,11 +263,6 @@ 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
 
 static inline void init_thread(struct target_pt_regs *regs,
@@ -352,7 +351,6 @@ enum
 #endif
 
 #define ELF_CLASS   ELFCLASS64
-#define ELF_DATA    ELFDATA2MSB
 #define ELF_ARCH    EM_SPARCV9
 
 #define STACK_BIAS              2047
@@ -382,7 +380,6 @@ static inline void init_thread(struct target_pt_regs *regs,
 #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,
@@ -416,11 +413,6 @@ static inline void init_thread(struct target_pt_regs *regs,
 
 #endif
 
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA        ELFDATA2MSB
-#else
-#define ELF_DATA        ELFDATA2LSB
-#endif
 #define ELF_ARCH        EM_PPC
 
 /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
@@ -554,11 +546,6 @@ 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,
@@ -626,7 +613,6 @@ 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,
@@ -666,7 +652,6 @@ 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,
@@ -722,7 +707,6 @@ static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
 #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,
@@ -742,7 +726,6 @@ static inline void init_thread(struct target_pt_regs *regs,
 #define elf_check_arch(x) ( (x) == EM_68K )
 
 #define ELF_CLASS       ELFCLASS32
-#define ELF_DATA        ELFDATA2MSB
 #define ELF_ARCH        EM_68K
 
 /* ??? Does this need to do anything?
@@ -796,7 +779,6 @@ 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,
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 06/12] linux-user: Clean up byte-swapping in elfload.c.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (4 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 05/12] linux-user: Define ELF_DATA generically Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter Richard Henderson
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

Remove ifdefs from code by defining empty inline functions
when byte swapping isn't needed.  Push loops over swapping
arrays of structures into the swapping functions.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |  119 ++++++++++++++++++++------------------------------
 1 files changed, 48 insertions(+), 71 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index a757dc9..3cbb1f4 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -871,30 +871,36 @@ static void bswap_ehdr(struct elfhdr *ehdr)
     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
 }
 
-static void bswap_phdr(struct elf_phdr *phdr)
+static void bswap_phdr(struct elf_phdr *phdr, int phnum)
 {
-    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 */
+    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)
+static void bswap_shdr(struct elf_shdr *shdr, int shnum)
 {
-    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);
+    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)
@@ -904,20 +910,15 @@ 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 *);
-
-#ifdef BSWAP_NEEDED
-static void bswap_note(struct elf_note *en)
-{
-    bswap32s(&en->n_namesz);
-    bswap32s(&en->n_descsz);
-    bswap32s(&en->n_type);
-}
-#endif /* BSWAP_NEEDED */
-
 #endif /* USE_ELF_CORE_DUMP */
 
 /*
@@ -1154,9 +1155,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
 
     error = 0;
 
-#ifdef BSWAP_NEEDED
     bswap_ehdr(interp_elf_ex);
-#endif
     /* First of all, some simple consistency checks */
     if ((interp_elf_ex->e_type != ET_EXEC &&
          interp_elf_ex->e_type != ET_DYN) ||
@@ -1195,12 +1194,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
             exit(-1);
         }
     }
-#ifdef BSWAP_NEEDED
-    eppnt = elf_phdata;
-    for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
-        bswap_phdr(eppnt);
-    }
-#endif
+    bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
 
     if (interp_elf_ex->e_type == ET_DYN) {
         /* in order to avoid hardcoding the interpreter load
@@ -1324,9 +1318,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     for (i = 0; i < hdr->e_shnum; i++) {
         if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
             return;
-#ifdef BSWAP_NEEDED
-        bswap_shdr(&sechdr);
-#endif
+        bswap_shdr(&sechdr, 1);
         if (sechdr.sh_type == SHT_SYMTAB) {
             symtab = sechdr;
             lseek(fd, hdr->e_shoff
@@ -1334,9 +1326,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
             if (read(fd, &strtab, sizeof(strtab))
                 != sizeof(strtab))
                 return;
-#ifdef BSWAP_NEEDED
-            bswap_shdr(&strtab);
-#endif
+            bswap_shdr(&strtab, 1);
             goto found;
         }
     }
@@ -1360,9 +1350,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
 
     i = 0;
     while (i < nsyms) {
-#ifdef BSWAP_NEEDED
         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 ||
@@ -1428,9 +1416,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     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) ||
@@ -1461,17 +1447,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
             exit(-1);
         }
     }
-
-#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;
+    bswap_phdr(elf_phdata, elf_ex.e_phnum);
 
     elf_brk = 0;
-
     elf_stack = ~((abi_ulong)0UL);
     elf_interpreter = NULL;
     start_code = ~((abi_ulong)0UL);
@@ -1480,6 +1458,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     end_data = 0;
     interp_ex.a_info = 0;
 
+    elf_ppnt = elf_phdata;
     for(i=0;i < elf_ex.e_phnum; i++) {
         if (elf_ppnt->p_type == PT_INTERP) {
             if ( elf_interpreter != NULL )
@@ -2025,9 +2004,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);
@@ -2055,6 +2031,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 */
 
 /*
@@ -2207,9 +2194,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)
@@ -2223,9 +2208,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)
@@ -2243,9 +2226,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)
@@ -2279,9 +2260,7 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
     free(base_filename);
     free(filename);
 
-#ifdef BSWAP_NEEDED
     bswap_psinfo(psinfo);
-#endif
     return (0);
 }
 
@@ -2406,9 +2385,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);
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (5 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 06/12] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 18:45   ` malc
  2010-07-28 22:16   ` Edgar E. Iglesias
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 08/12] linux-user: Improve consistency checking in elf headers Richard Henderson
                   ` (6 subsequent siblings)
  13 siblings, 2 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

First, adjust load_symbols to accept a load_bias parameter.  At the same
time, read the entire section header table in one go, use pread instead
f lseek+read for the symbol and string tables, and properly free
allocated structures on error exit paths.

Second, adjust load_elf_interp to compute load_bias.  This requires
finding out the built-in load addresses.  Which allows us to honor a
pre-linked interpreter image when possible, and eliminate the hard-coded
INTERP_MAP_SIZE value.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |  189 +++++++++++++++++++++++++++-----------------------
 1 files changed, 101 insertions(+), 88 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 3cbb1f4..6b57a91 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -829,9 +829,6 @@ 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)
 
@@ -920,6 +917,7 @@ static inline void bswap_sym(struct elf_sym *sym) { }
 #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);
 
 /*
  * 'copy_elf_strings()' copies argument/envelope strings from user
@@ -1146,15 +1144,11 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                  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;
+    abi_ulong load_addr, load_bias, loaddr, hiaddr;
     int retval;
     abi_ulong error;
     int i;
 
-    error = 0;
-
     bswap_ehdr(interp_elf_ex);
     /* First of all, some simple consistency checks */
     if ((interp_elf_ex->e_type != ET_EXEC &&
@@ -1163,7 +1157,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
         return ~((abi_ulong)0UL);
     }
 
-
     /* Now read in all of the header information */
 
     if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
@@ -1196,41 +1189,56 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
     }
     bswap_phdr(elf_phdata, interp_elf_ex->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 < interp_elf_ex->e_phnum; ++i) {
+        if (elf_phdata[i].p_type == PT_LOAD) {
+            abi_ulong a = elf_phdata[i].p_vaddr;
+            if (a < loaddr) {
+                loaddr = a;
+            }
+            a += elf_phdata[i].p_memsz;
+            if (a > hiaddr) {
+                hiaddr = a;
+            }
+        }
+    }
+
+    load_addr = loaddr;
     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) {
+        /* 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) {
             perror("mmap");
             exit(-1);
         }
-        load_addr = error;
-        load_addr_set = 1;
     }
+    load_bias = load_addr - loaddr;
 
-    eppnt = elf_phdata;
-    for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+    for (i = 0; i < interp_elf_ex->e_phnum; i++) {
+        struct elf_phdr *eppnt = elf_phdata + i;
         if (eppnt->p_type == PT_LOAD) {
-            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+            abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
             int elf_prot = 0;
-            abi_ulong vaddr = 0;
 
             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));
 
+            vaddr = load_bias + eppnt->p_vaddr;
+            vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
+            vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
+
+            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
+                                elf_prot, MAP_PRIVATE | MAP_FIXED,
+                                interpreter_fd, eppnt->p_offset - vaddr_po);
             if (error == -1) {
                 /* Real error */
                 close(interpreter_fd);
@@ -1238,26 +1246,25 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                 return ~((abi_ulong)0UL);
             }
 
-            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-                load_addr = error;
-                load_addr_set = 1;
-            }
+            vaddr_ef = vaddr + eppnt->p_filesz;
+            vaddr_em = vaddr + eppnt->p_memsz;
 
             /* If the load segment requests extra zeros (e.g. bss), map it.  */
-            if (eppnt->p_filesz < eppnt->p_memsz) {
-                abi_ulong base = load_addr + eppnt->p_vaddr;
-                zero_bss(base + eppnt->p_filesz,
-                         base + eppnt->p_memsz, elf_prot);
+            if (vaddr_ef < vaddr_em) {
+                zero_bss(vaddr_ef, vaddr_em, elf_prot);
             }
         }
+    }
 
-    /* Now use mmap to map the library into memory. */
+    if (qemu_log_enabled()) {
+        load_symbols(interp_elf_ex, interpreter_fd, load_bias);
+    }
 
     close(interpreter_fd);
     free(elf_phdata);
 
     *interp_load_addr = load_addr;
-    return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
+    return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
 }
 
 static int symfind(const void *s0, const void *s1)
@@ -1306,82 +1313,87 @@ 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;
-        bswap_shdr(&sechdr, 1);
-        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;
-            bswap_shdr(&strtab, 1);
+    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) {
+    nsyms = i / sizeof(struct elf_sym);
+    for (i = 0; i < nsyms; ) {
         bswap_sym(syms + i);
-        // 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++;
+        }
     }
-    syms = realloc(syms, nsyms * sizeof(*syms));
 
+    syms = realloc(syms, nsyms * sizeof(*syms));
     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;
 }
@@ -1788,8 +1800,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 
     free(elf_phdata);
 
-    if (qemu_log_enabled())
-        load_symbols(&elf_ex, bprm->fd);
+    if (qemu_log_enabled()) {
+        load_symbols(&elf_ex, bprm->fd, load_bias);
+    }
 
     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 08/12] linux-user: Improve consistency checking in elf headers.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (6 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 09/12] linux-user: Put the stack guard page at the top Richard Henderson
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

Validate more fields of the elf header.  Extract those checks
into two common functions to be used in both load_elf_interp
and load_elf_binary.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |   57 +++++++++++++++++++++++++++++---------------------
 1 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 6b57a91..86872b2 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -919,6 +919,30 @@ 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);
 
+/* 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)
+{
+    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);
+}
+
+/* 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
  * memory to free pages in kernel mem. These are in a format ready
@@ -1150,33 +1174,16 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
     int i;
 
     bswap_ehdr(interp_elf_ex);
-    /* 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)) {
+    if (!elf_check_ehdr(interp_elf_ex)) {
         return ~((abi_ulong)0UL);
     }
 
     /* Now read in all of the header information */
-
-    if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
-        return ~(abi_ulong)0UL;
-
     elf_phdata =  (struct elf_phdr *)
         malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-
     if (!elf_phdata)
         return ~((abi_ulong)0UL);
 
-    /*
-     * 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);
-    }
-
     i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
     if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
         memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
@@ -1428,11 +1435,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     load_addr = 0;
     load_bias = 0;
     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
-    bswap_ehdr(&elf_ex);
 
     /* 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))) {
+    if (!elf_check_ident(&elf_ex)) {
+        return -ENOEXEC;
+    }
+    bswap_ehdr(&elf_ex);
+    if (!elf_check_ehdr(&elf_ex)) {
         return -ENOEXEC;
     }
 
@@ -1444,7 +1453,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     }
 
     /* Now read in all of the header information */
-    elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
+    elf_phdata = (struct elf_phdr *)
+        malloc(elf_ex.e_phnum * sizeof(struct elf_phdr));
     if (elf_phdata == NULL) {
         return -ENOMEM;
     }
@@ -1549,8 +1559,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
             interpreter_type = INTERPRETER_ELF;
         }
 
-        if (interp_elf_ex.e_ident[0] != 0x7f ||
-            strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
+        if (!elf_check_ident(&interp_elf_ex)) {
             interpreter_type &= ~INTERPRETER_ELF;
         }
 
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 09/12] linux-user: Put the stack guard page at the top.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (7 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 08/12] linux-user: Improve consistency checking in elf headers Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 10/12] linux-user: Remove partial support for a.out interpreters Richard Henderson
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

There are no supported stack-grows-up targets.  We were putting
the guard page at the highest address, i.e. the bottom of the stack.
Use the maximum of host and guest page size for the guard size.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |   31 +++++++++++++++++--------------
 1 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 86872b2..01020c5 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1002,29 +1002,32 @@ 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++) {
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 10/12] linux-user: Remove partial support for a.out interpreters.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (8 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 09/12] linux-user: Put the stack guard page at the top Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

At the bottom of the a.out support was the unimplemented load_aout_interp
function.  There were other portions of the support that didn't look
right; when I went to look in the Linux kernel for clarification, I found
that the support for such interpreters has been removed from binfmt_elf.
There doesn't seem to be any reason to keep this broken support in qemu.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |   79 ++++++--------------------------------------------
 1 files changed, 9 insertions(+), 70 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 01020c5..61167cd 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -837,10 +837,6 @@ struct exec
 #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)
@@ -848,8 +844,6 @@ static inline void memcpy_fromfs(void * to, const void * from, unsigned long 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)
 {
@@ -1088,7 +1082,7 @@ 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,
+                                   abi_ulong interp_load_addr,
                                    struct image_info *info)
 {
     abi_ulong sp;
@@ -1118,7 +1112,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     size += DLINFO_ARCH_ITEMS * 2;
 #endif
     size += envc + argc + 2;
-    size += (!ibcs ? 3 : 1);    /* argc itself */
+    size += 1;  /* argc itself */
     size *= n;
     if (size & 15)
         sp -= 16 - (size & 15);
@@ -1160,7 +1154,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
 
     info->saved_auxv = sp;
 
-    sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
+    sp = loader_build_argptr(envc, argc, sp, p, 0);
     return sp;
 }
 
@@ -1413,11 +1407,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 {
     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;
@@ -1431,7 +1423,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     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;
@@ -1481,7 +1472,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     end_code = 0;
     start_data = 0;
     end_data = 0;
-    interp_ex.a_info = 0;
 
     elf_ppnt = elf_phdata;
     for(i=0;i < elf_ex.e_phnum; i++) {
@@ -1546,59 +1536,22 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                 memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
             }
 
-            interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
-            interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
+            interp_elf_ex = *((struct elfhdr *) bprm->buf);
         }
         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 (elf_interpreter) {
         if (!elf_check_ident(&interp_elf_ex)) {
-            interpreter_type &= ~INTERPRETER_ELF;
-        }
-
-        if (!interpreter_type) {
             free(elf_interpreter);
             free(elf_phdata);
             close(bprm->fd);
+            close(interpreter_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;
@@ -1791,15 +1744,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     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, bprm->buf);
-        }
+        elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
+                                    &interp_load_addr, bprm->buf);
         reloc_func_desc = interp_load_addr;
-
-        close(interpreter_fd);
         free(elf_interpreter);
 
         if (elf_entry == ~((abi_ulong)0UL)) {
@@ -1816,7 +1763,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
         load_symbols(&elf_ex, bprm->fd, load_bias);
     }
 
-    if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
+    close(bprm->fd);
     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
 
 #ifdef LOW_ELF_STACK
@@ -1828,7 +1775,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                                 &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;
@@ -2711,15 +2657,8 @@ static int elf_core_dump(int signr, const CPUState *env)
         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);
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (9 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 10/12] linux-user: Remove partial support for a.out interpreters Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-28 22:00   ` Edgar E. Iglesias
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 12/12] linux-user: Re-use load_elf_image for the main binary Richard Henderson
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

Moving toward a single copy of the elf binary loading code.
Fill in the details of the loaded image into a struct image_info.

Adjust create_elf_tables to read from such structures instead
of from a collection of passed arguments.  Don't return error
values from load_elf_interp; always exit(-1) with a message to
stderr.  Collect elf_interpreter handling in load_elf_binary
to a common spot.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |  341 ++++++++++++++++++++++++-------------------------
 1 files changed, 167 insertions(+), 174 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 61167cd..8ff9b6a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1079,11 +1079,9 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
 }
 
 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,
-                                   struct image_info *info)
+                                   struct elfhdr *exec,
+                                   struct image_info *info,
+                                   struct image_info *interp_info)
 {
     abi_ulong sp;
     int size;
@@ -1128,13 +1126,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     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_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_load_addr));
+    NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
-    NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+    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());
@@ -1158,51 +1156,60 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     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,
-                                 char bprm_buf[BPRM_BUF_SIZE])
+   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 bprm_buf[BPRM_BUF_SIZE])
 {
-    struct elf_phdr *elf_phdata  =  NULL;
-    abi_ulong load_addr, load_bias, loaddr, hiaddr;
-    int retval;
-    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;
 
-    bswap_ehdr(interp_elf_ex);
-    if (!elf_check_ehdr(interp_elf_ex)) {
-        return ~((abi_ulong)0UL);
+    /* 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;
     }
 
-    /* Now read in all of the header information */
-    elf_phdata =  (struct elf_phdr *)
-        malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-    if (!elf_phdata)
-        return ~((abi_ulong)0UL);
-
-    i = interp_elf_ex->e_phnum * sizeof(struct elf_phdr);
-    if (interp_elf_ex->e_phoff + i <= BPRM_BUF_SIZE) {
-        memcpy(elf_phdata, bprm_buf + interp_elf_ex->e_phoff, i);
+    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 {
-        retval = pread(interpreter_fd, elf_phdata, i, interp_elf_ex->e_phoff);
+        phdr = (struct elf_phdr *) alloca(i);
+        retval = pread(image_fd, phdr, i, ehdr->e_phoff);
         if (retval != i) {
-            perror("load_elf_interp");
-            exit(-1);
+            goto exit_read;
         }
     }
-    bswap_phdr(elf_phdata, interp_elf_ex->e_phnum);
+    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 < interp_elf_ex->e_phnum; ++i) {
-        if (elf_phdata[i].p_type == PT_LOAD) {
-            abi_ulong a = elf_phdata[i].p_vaddr;
+    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 += elf_phdata[i].p_memsz;
+            a += phdr[i].p_memsz;
             if (a > hiaddr) {
                 hiaddr = a;
             }
@@ -1210,7 +1217,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
     }
 
     load_addr = loaddr;
-    if (interp_elf_ex->e_type == ET_DYN) {
+    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
@@ -1220,14 +1227,22 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
                                 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
                                 -1, 0);
         if (load_addr == -1) {
-            perror("mmap");
-            exit(-1);
+            goto exit_perror;
         }
     }
     load_bias = load_addr - loaddr;
 
-    for (i = 0; i < interp_elf_ex->e_phnum; i++) {
-        struct elf_phdr *eppnt = elf_phdata + i;
+    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;
+
+    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;
@@ -1242,12 +1257,9 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
 
             error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
                                 elf_prot, MAP_PRIVATE | MAP_FIXED,
-                                interpreter_fd, eppnt->p_offset - vaddr_po);
+                                image_fd, eppnt->p_offset - vaddr_po);
             if (error == -1) {
-                /* Real error */
-                close(interpreter_fd);
-                free(elf_phdata);
-                return ~((abi_ulong)0UL);
+                goto exit_perror;
             }
 
             vaddr_ef = vaddr + eppnt->p_filesz;
@@ -1257,18 +1269,79 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
             if (vaddr_ef < vaddr_em) {
                 zero_bss(vaddr_ef, vaddr_em, elf_prot);
             }
+
+            /* 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;
+                }
+            }
         }
     }
 
+    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(interp_elf_ex, interpreter_fd, load_bias);
+        load_symbols(ehdr, image_fd, load_bias);
     }
 
-    close(interpreter_fd);
-    free(elf_phdata);
+    close(image_fd);
+    return;
+
+ 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, bprm_buf);
+    return;
 
-    *interp_load_addr = load_addr;
-    return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
+ exit_perror:
+    fprintf(stderr, "%s: %s\n", filename, strerror(errno));
+    exit(-1);
 }
 
 static int symfind(const void *s0, const void *s1)
@@ -1405,26 +1478,21 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
 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;
-    int interpreter_fd = -1; /* avoid warning */
     abi_ulong load_addr, load_bias;
     int load_addr_set = 0;
-    unsigned char ibcs2_interpreter;
     int i;
-    abi_ulong mapped_addr;
     struct elf_phdr * elf_ppnt;
     struct elf_phdr *elf_phdata;
     abi_ulong k, elf_brk;
     int retval;
-    char * elf_interpreter;
-    abi_ulong elf_entry, interp_load_addr = 0;
+    char *elf_interpreter = NULL;
+    abi_ulong elf_entry;
     int status;
     abi_ulong start_code, end_code, start_data, end_data;
-    abi_ulong reloc_func_desc = 0;
     abi_ulong elf_stack;
 
-    ibcs2_interpreter = 0;
     status = 0;
     load_addr = 0;
     load_bias = 0;
@@ -1467,7 +1535,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 
     elf_brk = 0;
     elf_stack = ~((abi_ulong)0UL);
-    elf_interpreter = NULL;
     start_code = ~((abi_ulong)0UL);
     end_code = 0;
     start_data = 0;
@@ -1476,82 +1543,21 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     elf_ppnt = elf_phdata;
     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;
-            }
-
             if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
-                memcpy(elf_interpreter, bprm->buf + elf_ppnt->p_offset,
-                       elf_ppnt->p_filesz);
+                elf_interpreter = bprm->buf + elf_ppnt->p_offset;
             } else {
+                elf_interpreter = alloca(elf_ppnt->p_filesz);
                 retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
                                elf_ppnt->p_offset);
                 if (retval != elf_ppnt->p_filesz) {
-                    perror("load_elf_binary2");
+                    perror("load_elf_binary");
                     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;
-            }
-
-            retval = open(path(elf_interpreter), O_RDONLY);
-            if (retval < 0) {
-                perror(elf_interpreter);
-                exit(-1);
-            }
-            interpreter_fd = retval;
-
-            retval = read(interpreter_fd, bprm->buf, BPRM_BUF_SIZE);
-            if (retval < 0) {
-                perror("load_elf_binary3");
-                exit(-1);
-            }
-            if (retval < BPRM_BUF_SIZE) {
-                memset(bprm->buf, 0, BPRM_BUF_SIZE - retval);
-            }
-
-            interp_elf_ex = *((struct elfhdr *) bprm->buf);
         }
         elf_ppnt++;
     }
 
-    /* Some simple consistency checks for the interpreter */
-    if (elf_interpreter) {
-        if (!elf_check_ident(&interp_elf_ex)) {
-            free(elf_interpreter);
-            free(elf_phdata);
-            close(bprm->fd);
-            close(interpreter_fd);
-            return -ELIBBAD;
-        }
-    }
-
     /* OK, This is the point of no return */
     info->end_data = 0;
     info->end_code = 0;
@@ -1710,7 +1716,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                 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;
@@ -1743,19 +1748,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     start_data += load_bias;
     end_data += load_bias;
 
-    if (elf_interpreter) {
-        elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
-                                    &interp_load_addr, bprm->buf);
-        reloc_func_desc = interp_load_addr;
-        free(elf_interpreter);
-
-        if (elf_entry == ~((abi_ulong)0UL)) {
-            printf("Unable to load interpreter\n");
-            free(elf_phdata);
-            exit(-1);
-            return 0;
-        }
-    }
+    info->load_bias = load_bias;
+    info->load_addr = load_addr;
+    info->entry = elf_entry;
+    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;
+    info->personality = PER_LINUX;
 
     free(elf_phdata);
 
@@ -1764,46 +1765,38 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     }
 
     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,
-                                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;
-    info->start_stack = bprm->p;
+    if (elf_interpreter) {
+        load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
 
-#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 the program interpreter is one of these two, then assume
+           an iBCS2 image.  Otherwise assume a native linux image.  */
+
+        if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
+            || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
+            info->personality = PER_SVR4;
 
-    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);
+            /* 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);
+        }
     }
 
-    info->entry = elf_entry;
+    bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
+                                info, (elf_interpreter ? &interp_info : NULL));
+    info->start_stack = bprm->p;
+
+    /* 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;
+    }
 
 #ifdef USE_ELF_CORE_DUMP
     bprm->core_dump = &elf_core_dump;
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 12/12] linux-user: Re-use load_elf_image for the main binary.
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (10 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
@ 2010-07-27 17:25 ` Richard Henderson
  2010-07-29  7:09 ` [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Edgar E. Iglesias
  2010-08-09 16:52 ` Jan-Simon Möller
  13 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 17:25 UTC (permalink / raw)
  To: qemu-devel

This requires moving the PT_INTERP extraction and GUEST_BASE
handling into load_elf_image.  Key this off a non-null pointer
argument to receive the interpreter name.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |  380 ++++++++++++++------------------------------------
 1 files changed, 103 insertions(+), 277 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 8ff9b6a..b4cf671 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -829,9 +829,6 @@ struct exec
 #define ZMAGIC 0413
 #define QMAGIC 0314
 
-/* 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))
@@ -1169,7 +1166,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
    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,
+                           struct image_info *info, char **pinterp_name,
                            char bprm_buf[BPRM_BUF_SIZE])
 {
     struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
@@ -1229,6 +1226,67 @@ static void load_elf_image(const char *image_name, int image_fd,
         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
     }
     load_bias = load_addr - loaddr;
 
@@ -1290,6 +1348,33 @@ static void load_elf_image(const char *image_name, int image_fd,
                     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;
+            }
+
+            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;
         }
     }
 
@@ -1336,7 +1421,7 @@ static void load_elf_interp(const char *filename, struct image_info *info,
         memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
     }
 
-    load_elf_image(filename, fd, info, bprm_buf);
+    load_elf_image(filename, fd, info, NULL, bprm_buf);
     return;
 
  exit_perror:
@@ -1480,291 +1565,31 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 {
     struct image_info interp_info;
     struct elfhdr elf_ex;
-    abi_ulong load_addr, load_bias;
-    int load_addr_set = 0;
-    int i;
-    struct elf_phdr * elf_ppnt;
-    struct elf_phdr *elf_phdata;
-    abi_ulong k, elf_brk;
-    int retval;
     char *elf_interpreter = NULL;
-    abi_ulong elf_entry;
-    int status;
-    abi_ulong start_code, end_code, start_data, end_data;
-    abi_ulong elf_stack;
 
-    status = 0;
-    load_addr = 0;
-    load_bias = 0;
-    elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
+    info->start_mmap = (abi_ulong)ELF_START_MMAP;
+    info->mmap = 0;
+    info->rss = 0;
 
-    /* First of all, some simple consistency checks */
-    if (!elf_check_ident(&elf_ex)) {
-        return -ENOEXEC;
-    }
-    bswap_ehdr(&elf_ex);
-    if (!elf_check_ehdr(&elf_ex)) {
-        return -ENOEXEC;
-    }
+    load_elf_image(bprm->filename, bprm->fd, info,
+                   &elf_interpreter, bprm->buf);
+
+    /* ??? 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;
 
     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_phnum * sizeof(struct elf_phdr));
-    if (elf_phdata == NULL) {
-        return -ENOMEM;
-    }
-
-    i = elf_ex.e_phnum * sizeof(struct elf_phdr);
-    if (elf_ex.e_phoff + i <= BPRM_BUF_SIZE) {
-        memcpy(elf_phdata, bprm->buf + elf_ex.e_phoff, i);
-    } else {
-        retval = pread(bprm->fd, (char *) elf_phdata, i, elf_ex.e_phoff);
-        if (retval != i) {
-            perror("load_elf_binary");
-            exit(-1);
-        }
-    }
-    bswap_phdr(elf_phdata, elf_ex.e_phnum);
-
-    elf_brk = 0;
-    elf_stack = ~((abi_ulong)0UL);
-    start_code = ~((abi_ulong)0UL);
-    end_code = 0;
-    start_data = 0;
-    end_data = 0;
-
-    elf_ppnt = elf_phdata;
-    for(i=0;i < elf_ex.e_phnum; i++) {
-        if (elf_ppnt->p_type == PT_INTERP) {
-            if (elf_ppnt->p_offset + elf_ppnt->p_filesz <= BPRM_BUF_SIZE) {
-                elf_interpreter = bprm->buf + elf_ppnt->p_offset;
-            } else {
-                elf_interpreter = alloca(elf_ppnt->p_filesz);
-                retval = pread(bprm->fd, elf_interpreter, elf_ppnt->p_filesz,
-                               elf_ppnt->p_offset);
-                if (retval != elf_ppnt->p_filesz) {
-                    perror("load_elf_binary");
-                    exit(-1);
-                }
-            }
-        }
-        elf_ppnt++;
-    }
-
-    /* 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;
-
-#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;
-            }
-        }
-
-        /* If we don't have any loadable segments then something
-           is very wrong.  */
-        assert(app_start < app_end);
-
-        /* 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;
+        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.
-     */
-
-    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 (elf_ppnt->p_type != PT_LOAD)
-            continue;
-
-        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);
-        }
-
-        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;
-            }
-        }
-        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 ((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 = TARGET_PAGE_ALIGN(k);
-        }
-
-        /* If the load segment requests extra zeros (e.g. bss), map it.  */
-        if (elf_ppnt->p_filesz < elf_ppnt->p_memsz) {
-            abi_ulong base = load_bias + elf_ppnt->p_vaddr;
-            zero_bss(base + elf_ppnt->p_filesz,
-                     base + elf_ppnt->p_memsz, elf_prot);
-        }
-    }
-
-    elf_entry += load_bias;
-    elf_brk += load_bias;
-    start_code += load_bias;
-    end_code += load_bias;
-    start_data += load_bias;
-    end_data += load_bias;
-
-    info->load_bias = load_bias;
-    info->load_addr = load_addr;
-    info->entry = elf_entry;
-    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;
-    info->personality = PER_LINUX;
-
-    free(elf_phdata);
-
-    if (qemu_log_enabled()) {
-        load_symbols(&elf_ex, bprm->fd, load_bias);
-    }
-
-    close(bprm->fd);
 
     if (elf_interpreter) {
         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
@@ -1796,6 +1621,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     if (elf_interpreter) {
         info->load_addr = interp_info.load_addr;
         info->entry = interp_info.entry;
+        free(elf_interpreter);
     }
 
 #ifdef USE_ELF_CORE_DUMP
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter.
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter Richard Henderson
@ 2010-07-27 18:45   ` malc
  2010-07-27 19:59     ` Richard Henderson
  2010-07-28 22:16   ` Edgar E. Iglesias
  1 sibling, 1 reply; 23+ messages in thread
From: malc @ 2010-07-27 18:45 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 27 Jul 2010, Richard Henderson wrote:

> First, adjust load_symbols to accept a load_bias parameter.  At the same
> time, read the entire section header table in one go, use pread instead
> f lseek+read for the symbol and string tables, and properly free
> allocated structures on error exit paths.
> 
> Second, adjust load_elf_interp to compute load_bias.  This requires
> finding out the built-in load addresses.  Which allows us to honor a
> pre-linked interpreter image when possible, and eliminate the hard-coded
> INTERP_MAP_SIZE value.
> 
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  linux-user/elfload.c |  189 +++++++++++++++++++++++++++-----------------------
>  1 files changed, 101 insertions(+), 88 deletions(-)
> 
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 3cbb1f4..6b57a91 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -829,9 +829,6 @@ 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)
>  
> @@ -920,6 +917,7 @@ static inline void bswap_sym(struct elf_sym *sym) { }
>  #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);
>  
>  /*
>   * 'copy_elf_strings()' copies argument/envelope strings from user
> @@ -1146,15 +1144,11 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>                                   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;
> +    abi_ulong load_addr, load_bias, loaddr, hiaddr;
>      int retval;
>      abi_ulong error;
>      int i;
>  
> -    error = 0;
> -
>      bswap_ehdr(interp_elf_ex);
>      /* First of all, some simple consistency checks */
>      if ((interp_elf_ex->e_type != ET_EXEC &&
> @@ -1163,7 +1157,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>          return ~((abi_ulong)0UL);
>      }
>  
> -
>      /* Now read in all of the header information */
>  
>      if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
> @@ -1196,41 +1189,56 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>      }
>      bswap_phdr(elf_phdata, interp_elf_ex->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 < interp_elf_ex->e_phnum; ++i) {
> +        if (elf_phdata[i].p_type == PT_LOAD) {
> +            abi_ulong a = elf_phdata[i].p_vaddr;
> +            if (a < loaddr) {
> +                loaddr = a;
> +            }
> +            a += elf_phdata[i].p_memsz;
> +            if (a > hiaddr) {
> +                hiaddr = a;
> +            }
> +        }
> +    }
> +
> +    load_addr = loaddr;
>      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) {
> +        /* 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) {
>              perror("mmap");
>              exit(-1);
>          }
> -        load_addr = error;
> -        load_addr_set = 1;
>      }
> +    load_bias = load_addr - loaddr;
>  
> -    eppnt = elf_phdata;
> -    for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
> +    for (i = 0; i < interp_elf_ex->e_phnum; i++) {
> +        struct elf_phdr *eppnt = elf_phdata + i;
>          if (eppnt->p_type == PT_LOAD) {
> -            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
> +            abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
>              int elf_prot = 0;
> -            abi_ulong vaddr = 0;
>  
>              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));
>  
> +            vaddr = load_bias + eppnt->p_vaddr;
> +            vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
> +            vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
> +
> +            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
> +                                elf_prot, MAP_PRIVATE | MAP_FIXED,
> +                                interpreter_fd, eppnt->p_offset - vaddr_po);
>              if (error == -1) {
>                  /* Real error */
>                  close(interpreter_fd);
> @@ -1238,26 +1246,25 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>                  return ~((abi_ulong)0UL);
>              }
>  
> -            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
> -                load_addr = error;
> -                load_addr_set = 1;
> -            }
> +            vaddr_ef = vaddr + eppnt->p_filesz;
> +            vaddr_em = vaddr + eppnt->p_memsz;
>  
>              /* If the load segment requests extra zeros (e.g. bss), map it.  */
> -            if (eppnt->p_filesz < eppnt->p_memsz) {
> -                abi_ulong base = load_addr + eppnt->p_vaddr;
> -                zero_bss(base + eppnt->p_filesz,
> -                         base + eppnt->p_memsz, elf_prot);
> +            if (vaddr_ef < vaddr_em) {
> +                zero_bss(vaddr_ef, vaddr_em, elf_prot);
>              }
>          }
> +    }
>  
> -    /* Now use mmap to map the library into memory. */
> +    if (qemu_log_enabled()) {
> +        load_symbols(interp_elf_ex, interpreter_fd, load_bias);
> +    }
>  
>      close(interpreter_fd);
>      free(elf_phdata);
>  
>      *interp_load_addr = load_addr;
> -    return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
> +    return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
>  }
>  
>  static int symfind(const void *s0, const void *s1)
> @@ -1306,82 +1313,87 @@ 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;
> -        bswap_shdr(&sechdr, 1);
> -        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;
> -            bswap_shdr(&strtab, 1);
> +    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) {
> +    nsyms = i / sizeof(struct elf_sym);
> +    for (i = 0; i < nsyms; ) {
>          bswap_sym(syms + i);
> -        // 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++;
> +        }
>      }
> -    syms = realloc(syms, nsyms * sizeof(*syms));
>  
> +    syms = realloc(syms, nsyms * sizeof(*syms));

Realloc can fail here.

>      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;
>  }
> @@ -1788,8 +1800,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
>  
>      free(elf_phdata);
>  
> -    if (qemu_log_enabled())
> -        load_symbols(&elf_ex, bprm->fd);
> +    if (qemu_log_enabled()) {
> +        load_symbols(&elf_ex, bprm->fd, load_bias);
> +    }
>  
>      if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
>      info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
> 

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter.
  2010-07-27 18:45   ` malc
@ 2010-07-27 19:59     ` Richard Henderson
  2010-07-27 20:39       ` malc
  0 siblings, 1 reply; 23+ messages in thread
From: Richard Henderson @ 2010-07-27 19:59 UTC (permalink / raw)
  To: malc; +Cc: qemu-devel

On 07/27/2010 11:45 AM, malc wrote:
>> +    syms = realloc(syms, nsyms * sizeof(*syms));
> 
> Realloc can fail here.

I don't believe it can.  This (pre-existing) statement *reduces*
the existing allocation of syms.  I'd be surprised if any malloc
implementation fails on a size reduction.

That said, I'd be happy enough to eliminate the call entirely.


r~

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter.
  2010-07-27 19:59     ` Richard Henderson
@ 2010-07-27 20:39       ` malc
  2010-07-27 20:44         ` malc
  0 siblings, 1 reply; 23+ messages in thread
From: malc @ 2010-07-27 20:39 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 27 Jul 2010, Richard Henderson wrote:

> On 07/27/2010 11:45 AM, malc wrote:
> >> +    syms = realloc(syms, nsyms * sizeof(*syms));
> > 
> > Realloc can fail here.
> 
> I don't believe it can.  This (pre-existing) statement *reduces*
> the existing allocation of syms.  I'd be surprised if any malloc
> implementation fails on a size reduction.

Life is full of surprises.

realloc$ cat tr.c 
#include <stdio.h>
#include <stdlib.h>

int main (void)
{
    void *ptr;

    for (;;) {
        ptr = malloc (2);
        if (!ptr) break;
    }
    printf ("result = %p\n", realloc (ptr, 1));
    return 0;
}
realloc$ \time -v ./a.out 
result = (nil)
        Command being timed: "./a.out"
        User time (seconds): 5.62
        [..snip..]

> That said, I'd be happy enough to eliminate the call entirely.

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter.
  2010-07-27 20:39       ` malc
@ 2010-07-27 20:44         ` malc
  0 siblings, 0 replies; 23+ messages in thread
From: malc @ 2010-07-27 20:44 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Wed, 28 Jul 2010, malc wrote:

> On Tue, 27 Jul 2010, Richard Henderson wrote:
> 
> > On 07/27/2010 11:45 AM, malc wrote:
> > >> +    syms = realloc(syms, nsyms * sizeof(*syms));
> > > 
> > > Realloc can fail here.
> > 
> > I don't believe it can.  This (pre-existing) statement *reduces*
> > the existing allocation of syms.  I'd be surprised if any malloc
> > implementation fails on a size reduction.
> 
> Life is full of surprises.
> 
> realloc$ cat tr.c 
> #include <stdio.h>
> #include <stdlib.h>
> 
> int main (void)
> {
>     void *ptr;
> 
>     for (;;) {
>         ptr = malloc (2);
>         if (!ptr) break;
>     }
>     printf ("result = %p\n", realloc (ptr, 1));
>     return 0;
> }

Uh, appologies, this doesn't quite do what i thought it should,
final realloc allocates without freeing. Guess i have to spend
more time trying to prove that i'm the smartest kid on the block.

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp.
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
@ 2010-07-28 22:00   ` Edgar E. Iglesias
  2010-07-28 23:18     ` Richard Henderson
  0 siblings, 1 reply; 23+ messages in thread
From: Edgar E. Iglesias @ 2010-07-28 22:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, Jul 27, 2010 at 10:25:37AM -0700, Richard Henderson wrote:
> Moving toward a single copy of the elf binary loading code.
> Fill in the details of the loaded image into a struct image_info.
> 
> Adjust create_elf_tables to read from such structures instead
> of from a collection of passed arguments.  Don't return error
> values from load_elf_interp; always exit(-1) with a message to
> stderr.  Collect elf_interpreter handling in load_elf_binary
> to a common spot.
> 
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  linux-user/elfload.c |  341 ++++++++++++++++++++++++-------------------------
>  1 files changed, 167 insertions(+), 174 deletions(-)
> 
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 61167cd..8ff9b6a 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -1079,11 +1079,9 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
>  }
>  
>  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,
> -                                   struct image_info *info)
> +                                   struct elfhdr *exec,
> +                                   struct image_info *info,
> +                                   struct image_info *interp_info)
>  {
>      abi_ulong sp;
>      int size;
> @@ -1128,13 +1126,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
>      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_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_load_addr));
> +    NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));


Hi Richard,

I think this part breaks loading of statically linked ELFs (no
interpreter). I beleive Linux sets AT_BASE to zero in those cases.

Cheers

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter.
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter Richard Henderson
  2010-07-27 18:45   ` malc
@ 2010-07-28 22:16   ` Edgar E. Iglesias
  1 sibling, 0 replies; 23+ messages in thread
From: Edgar E. Iglesias @ 2010-07-28 22:16 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, Jul 27, 2010 at 10:25:33AM -0700, Richard Henderson wrote:
> First, adjust load_symbols to accept a load_bias parameter.  At the same
> time, read the entire section header table in one go, use pread instead
> f lseek+read for the symbol and string tables, and properly free
> allocated structures on error exit paths.
> 
> Second, adjust load_elf_interp to compute load_bias.  This requires
> finding out the built-in load addresses.  Which allows us to honor a
> pre-linked interpreter image when possible, and eliminate the hard-coded
> INTERP_MAP_SIZE value.


This was neat, I wish we've had this feature before :)

Cheers



> 
> Signed-off-by: Richard Henderson <rth@twiddle.net>
> ---
>  linux-user/elfload.c |  189 +++++++++++++++++++++++++++-----------------------
>  1 files changed, 101 insertions(+), 88 deletions(-)
> 
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 3cbb1f4..6b57a91 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -829,9 +829,6 @@ 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)
>  
> @@ -920,6 +917,7 @@ static inline void bswap_sym(struct elf_sym *sym) { }
>  #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);
>  
>  /*
>   * 'copy_elf_strings()' copies argument/envelope strings from user
> @@ -1146,15 +1144,11 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>                                   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;
> +    abi_ulong load_addr, load_bias, loaddr, hiaddr;
>      int retval;
>      abi_ulong error;
>      int i;
>  
> -    error = 0;
> -
>      bswap_ehdr(interp_elf_ex);
>      /* First of all, some simple consistency checks */
>      if ((interp_elf_ex->e_type != ET_EXEC &&
> @@ -1163,7 +1157,6 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>          return ~((abi_ulong)0UL);
>      }
>  
> -
>      /* Now read in all of the header information */
>  
>      if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
> @@ -1196,41 +1189,56 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>      }
>      bswap_phdr(elf_phdata, interp_elf_ex->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 < interp_elf_ex->e_phnum; ++i) {
> +        if (elf_phdata[i].p_type == PT_LOAD) {
> +            abi_ulong a = elf_phdata[i].p_vaddr;
> +            if (a < loaddr) {
> +                loaddr = a;
> +            }
> +            a += elf_phdata[i].p_memsz;
> +            if (a > hiaddr) {
> +                hiaddr = a;
> +            }
> +        }
> +    }
> +
> +    load_addr = loaddr;
>      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) {
> +        /* 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) {
>              perror("mmap");
>              exit(-1);
>          }
> -        load_addr = error;
> -        load_addr_set = 1;
>      }
> +    load_bias = load_addr - loaddr;
>  
> -    eppnt = elf_phdata;
> -    for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
> +    for (i = 0; i < interp_elf_ex->e_phnum; i++) {
> +        struct elf_phdr *eppnt = elf_phdata + i;
>          if (eppnt->p_type == PT_LOAD) {
> -            int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
> +            abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
>              int elf_prot = 0;
> -            abi_ulong vaddr = 0;
>  
>              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));
>  
> +            vaddr = load_bias + eppnt->p_vaddr;
> +            vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
> +            vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
> +
> +            error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
> +                                elf_prot, MAP_PRIVATE | MAP_FIXED,
> +                                interpreter_fd, eppnt->p_offset - vaddr_po);
>              if (error == -1) {
>                  /* Real error */
>                  close(interpreter_fd);
> @@ -1238,26 +1246,25 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
>                  return ~((abi_ulong)0UL);
>              }
>  
> -            if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
> -                load_addr = error;
> -                load_addr_set = 1;
> -            }
> +            vaddr_ef = vaddr + eppnt->p_filesz;
> +            vaddr_em = vaddr + eppnt->p_memsz;
>  
>              /* If the load segment requests extra zeros (e.g. bss), map it.  */
> -            if (eppnt->p_filesz < eppnt->p_memsz) {
> -                abi_ulong base = load_addr + eppnt->p_vaddr;
> -                zero_bss(base + eppnt->p_filesz,
> -                         base + eppnt->p_memsz, elf_prot);
> +            if (vaddr_ef < vaddr_em) {
> +                zero_bss(vaddr_ef, vaddr_em, elf_prot);
>              }
>          }
> +    }
>  
> -    /* Now use mmap to map the library into memory. */
> +    if (qemu_log_enabled()) {
> +        load_symbols(interp_elf_ex, interpreter_fd, load_bias);
> +    }
>  
>      close(interpreter_fd);
>      free(elf_phdata);
>  
>      *interp_load_addr = load_addr;
> -    return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
> +    return ((abi_ulong) interp_elf_ex->e_entry) + load_bias;
>  }
>  
>  static int symfind(const void *s0, const void *s1)
> @@ -1306,82 +1313,87 @@ 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;
> -        bswap_shdr(&sechdr, 1);
> -        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;
> -            bswap_shdr(&strtab, 1);
> +    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) {
> +    nsyms = i / sizeof(struct elf_sym);
> +    for (i = 0; i < nsyms; ) {
>          bswap_sym(syms + i);
> -        // 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++;
> +        }
>      }
> -    syms = realloc(syms, nsyms * sizeof(*syms));
>  
> +    syms = realloc(syms, nsyms * sizeof(*syms));
>      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;
>  }
> @@ -1788,8 +1800,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
>  
>      free(elf_phdata);
>  
> -    if (qemu_log_enabled())
> -        load_symbols(&elf_ex, bprm->fd);
> +    if (qemu_log_enabled()) {
> +        load_symbols(&elf_ex, bprm->fd, load_bias);
> +    }
>  
>      if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
>      info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
> -- 
> 1.7.1.1
> 
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp.
  2010-07-28 22:00   ` Edgar E. Iglesias
@ 2010-07-28 23:18     ` Richard Henderson
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-07-28 23:18 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel

On 07/28/2010 03:00 PM, Edgar E. Iglesias wrote:
>> -    NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
>> +    NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info->load_addr));
> 
> 
> Hi Richard,
> 
> I think this part breaks loading of statically linked ELFs (no
> interpreter). I beleive Linux sets AT_BASE to zero in those cases.

You're right.  This should be 

  interp_info ? interp_info->load_addr : 0


r~

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (11 preceding siblings ...)
  2010-07-27 17:25 ` [Qemu-devel] [PATCH 12/12] linux-user: Re-use load_elf_image for the main binary Richard Henderson
@ 2010-07-29  7:09 ` Edgar E. Iglesias
  2010-08-09 16:52 ` Jan-Simon Möller
  13 siblings, 0 replies; 23+ messages in thread
From: Edgar E. Iglesias @ 2010-07-29  7:09 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, Jul 27, 2010 at 10:25:26AM -0700, Richard Henderson wrote:
> A re-based and re-tested version of a patch series I
> posted back in April and May.  These cleanups prepare
> elfload.c for loading the VDSO for x86_64.

I got a whitespace warning when applying the patches:
Applying: linux-user: Reduce lseek+reads while loading elf files.
/home/edgar/src/c/qemu/git/qemu/.git/rebase-apply/patch:219: trailing whitespace.
/* Read a good amount of data initially, to hopefully get all the 
warning: 1 line adds whitespace errors.


I removed the trailing whitespace and fixed the interpreter less
ELF loading on my side and applied the series.

If there are more issues with the pre-existing realloc malc
commented on, I think those can be handled with follow up patches.

Thanks,
Edgar



> 
> 
> r~
> 
> 
> Richard Henderson (12):
>   linux-user: Handle filesz < memsz for any PT_LOAD segment.
>   Add more DT_* and AT_* constants to qemu's copy of elf.h.
>   linux-user: Reindent elfload.c.
>   linux-user: Reduce lseek+reads while loading elf files.
>   linux-user: Define ELF_DATA generically.
>   linux-user: Clean up byte-swapping in elfload.c.
>   linux-user: Load symbols from the interpreter.
>   linux-user: Improve consistency checking in elf headers.
>   linux-user: Put the stack guard page at the top.
>   linux-user: Remove partial support for a.out interpreters.
>   linux-user: Extract load_elf_image from load_elf_interp.
>   linux-user: Re-use load_elf_image for the main binary.
> 
>  elf.h                  |   44 ++
>  linux-user/elfload.c   | 1791 ++++++++++++++++++++----------------------------
>  linux-user/linuxload.c |   17 +-
>  linux-user/qemu.h      |    7 +-
>  4 files changed, 794 insertions(+), 1065 deletions(-)
> 
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c
  2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
                   ` (12 preceding siblings ...)
  2010-07-29  7:09 ` [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Edgar E. Iglesias
@ 2010-08-09 16:52 ` Jan-Simon Möller
  2010-08-10 16:21   ` Richard Henderson
  13 siblings, 1 reply; 23+ messages in thread
From: Jan-Simon Möller @ 2010-08-09 16:52 UTC (permalink / raw)
  To: qemu-devel

Am Dienstag, 27. Juli 2010, 19:25:26 schrieb Richard Henderson:
> A re-based and re-tested version of a patch series I
> posted back in April and May.  These cleanups prepare
> elfload.c for loading the VDSO for x86_64.
> 
> 

Do you have a repo where i could pull these from ?

Best,
Jan-Simon

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c
  2010-08-09 16:52 ` Jan-Simon Möller
@ 2010-08-10 16:21   ` Richard Henderson
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Henderson @ 2010-08-10 16:21 UTC (permalink / raw)
  To: Jan-Simon Möller; +Cc: qemu-devel

On 08/09/2010 09:52 AM, Jan-Simon Möller wrote:
>> A re-based and re-tested version of a patch series I
>> posted back in April and May.  These cleanups prepare
>> elfload.c for loading the VDSO for x86_64.
> 
> Do you have a repo where i could pull these from ?

Which, the vdso loading bits?

  git://repo.or.cz/qemu/rth.git elfload-vdso

I still haven't worked out how to fix the makefile, and
there's still the question of how to load the vdso from
the build tree (as opposed to the install tree).


r~

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2010-08-10 17:20 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-27 17:25 [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 01/12] linux-user: Handle filesz < memsz for any PT_LOAD segment Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 02/12] Add more DT_* and AT_* constants to qemu's copy of elf.h Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 03/12] linux-user: Reindent elfload.c Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 04/12] linux-user: Reduce lseek+reads while loading elf files Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 05/12] linux-user: Define ELF_DATA generically Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 06/12] linux-user: Clean up byte-swapping in elfload.c Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 07/12] linux-user: Load symbols from the interpreter Richard Henderson
2010-07-27 18:45   ` malc
2010-07-27 19:59     ` Richard Henderson
2010-07-27 20:39       ` malc
2010-07-27 20:44         ` malc
2010-07-28 22:16   ` Edgar E. Iglesias
2010-07-27 17:25 ` [Qemu-devel] [PATCH 08/12] linux-user: Improve consistency checking in elf headers Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 09/12] linux-user: Put the stack guard page at the top Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 10/12] linux-user: Remove partial support for a.out interpreters Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 11/12] linux-user: Extract load_elf_image from load_elf_interp Richard Henderson
2010-07-28 22:00   ` Edgar E. Iglesias
2010-07-28 23:18     ` Richard Henderson
2010-07-27 17:25 ` [Qemu-devel] [PATCH 12/12] linux-user: Re-use load_elf_image for the main binary Richard Henderson
2010-07-29  7:09 ` [Qemu-devel] [PATCH 00/12 v4] Clean up linux-user/elfload.c Edgar E. Iglesias
2010-08-09 16:52 ` Jan-Simon Möller
2010-08-10 16:21   ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).