]> git.proxmox.com Git - qemu.git/blobdiff - linux-user/flatload.c
linux-user: Fix pipe syscall return for SPARC
[qemu.git] / linux-user / flatload.c
index 7e3296e5aa341589b8c2dc5f47ba6d85e1b7c3d2..58f679e07282acacde4c9ec20eec6c56d79e2b1b 100644 (file)
@@ -13,8 +13,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  *      Copyright (C) 2006 CodeSourcery.
  *     Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
 
 #include "qemu.h"
 #include "flat.h"
+#define ntohl(x) be32_to_cpu(x)
+#include <target_flat.h>
 
 //#define DEBUG
 
 #ifdef DEBUG
-#define        DBG_FLT(a...)   printf(a)
-#else
-#define        DBG_FLT(a...)
-#endif
-
-#define flat_reloc_valid(reloc, size)             ((reloc) <= (size))
-#define flat_old_ram_flag(flag)                   (flag)
-#ifdef TARGET_WORDS_BIGENDIAN
-#define flat_get_relocate_addr(relval)            (relval)
+#define        DBG_FLT(...)    printf(__VA_ARGS__)
 #else
-#define flat_get_relocate_addr(relval)            bswap32(relval)
+#define        DBG_FLT(...)
 #endif
 
 #define RELOC_FAILED 0xff00ff01                /* Relocation incorrect somewhere */
 #define UNLOADED_LIB 0x7ff000ff                /* Placeholder for unused library */
 
 struct lib_info {
-    target_ulong start_code;   /* Start of text segment */
-    target_ulong start_data;   /* Start of data segment */
-    target_ulong end_data;      /* Start of bss section */
-    target_ulong start_brk;    /* End of data segment */
-    target_ulong text_len;     /* Length of text segment */
-    target_ulong entry;                /* Start address for this module */
-    target_ulong build_date;   /* When this one was compiled */
+    abi_ulong start_code;       /* Start of text segment */
+    abi_ulong start_data;       /* Start of data segment */
+    abi_ulong end_data;         /* Start of bss section */
+    abi_ulong start_brk;        /* End of data segment */
+    abi_ulong text_len;                /* Length of text segment */
+    abi_ulong entry;           /* Start address for this module */
+    abi_ulong build_date;       /* When this one was compiled */
     short loaded;              /* Has this library been loaded? */
 };
 
@@ -79,8 +72,6 @@ static int load_flat_shared_library(int id, struct lib_info *p);
 
 struct linux_binprm;
 
-#define ntohl(x) be32_to_cpu(x)
-
 /****************************************************************************/
 /*
  * create_flat_tables() parses the env- and arg-strings in new user
@@ -89,7 +80,7 @@ struct linux_binprm;
  */
 
 /* Push a block of strings onto the guest stack.  */
-static target_ulong copy_strings(target_ulong p, int n, char **s)
+static abi_ulong copy_strings(abi_ulong p, int n, char **s)
 {
     int len;
 
@@ -102,13 +93,13 @@ static target_ulong copy_strings(target_ulong p, int n, char **s)
     return p;
 }
 
-int target_pread(int fd, target_ulong ptr, target_ulong len,
-                 target_ulong offset)
+static int target_pread(int fd, abi_ulong ptr, abi_ulong len,
+                        abi_ulong offset)
 {
     void *buf;
     int ret;
 
-    buf = lock_user(ptr, len, 0);
+    buf = lock_user(VERIFY_WRITE, ptr, len, 0);
     ret = pread(fd, buf, len, offset);
     unlock_user(buf, ptr, len);
     return ret;
@@ -262,15 +253,15 @@ out:
 
 /****************************************************************************/
 
-static target_ulong
-calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp)
+static abi_ulong
+calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
 {
-    target_ulong addr;
+    abi_ulong addr;
     int id;
-    target_ulong start_brk;
-    target_ulong start_data;
-    target_ulong text_len;
-    target_ulong start_code;
+    abi_ulong start_brk;
+    abi_ulong start_data;
+    abi_ulong text_len;
+    abi_ulong start_code;
 
 #ifdef CONFIG_BINFMT_SHARED_FLAT
 #error needs checking
@@ -336,10 +327,10 @@ failed:
 /****************************************************************************/
 
 /* ??? This does not handle endianness correctly.  */
-void old_reloc(struct lib_info *libinfo, uint32_t rl)
+static void old_reloc(struct lib_info *libinfo, uint32_t rl)
 {
 #ifdef DEBUG
-       char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
+       const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
 #endif
        uint32_t *ptr;
         uint32_t offset;
@@ -349,9 +340,9 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl)
         reloc_type = rl >> 30;
         /* ??? How to handle this?  */
 #if defined(CONFIG_COLDFIRE)
-       ptr = (uint32_t *) (libinfo->start_code + offset);
+       ptr = (uint32_t *) ((unsigned long) libinfo->start_code + offset);
 #else
-       ptr = (uint32_t *) (libinfo->start_data + offset);
+       ptr = (uint32_t *) ((unsigned long) libinfo->start_data + offset);
 #endif
 
 #ifdef DEBUG
@@ -359,7 +350,7 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl)
                "(address %p, currently %x) into segment %s\n",
                offset, ptr, (int)*ptr, segment[reloc_type]);
 #endif
-       
+
        switch (reloc_type) {
        case OLD_FLAT_RELOC_TYPE_TEXT:
                *ptr += libinfo->start_code;
@@ -376,23 +367,24 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl)
                break;
        }
        DBG_FLT("Relocation became %x\n", (int)*ptr);
-}              
+}
 
 /****************************************************************************/
 
 static int load_flat_file(struct linux_binprm * bprm,
-               struct lib_info *libinfo, int id, target_ulong *extra_stack)
+               struct lib_info *libinfo, int id, abi_ulong *extra_stack)
 {
     struct flat_hdr * hdr;
-    target_ulong textpos = 0, datapos = 0, result;
-    target_ulong realdatastart = 0;
-    target_ulong text_len, data_len, bss_len, stack_len, flags;
-    target_ulong memp = 0; /* for finding the brk area */
-    target_ulong extra;
-    target_ulong reloc = 0, rp;
+    abi_ulong textpos = 0, datapos = 0;
+    abi_long result;
+    abi_ulong realdatastart = 0;
+    abi_ulong text_len, data_len, bss_len, stack_len, flags;
+    abi_ulong extra;
+    abi_ulong reloc = 0, rp;
     int i, rev, relocs = 0;
-    target_ulong fpos;
-    target_ulong start_code, end_code;
+    abi_ulong fpos;
+    abi_ulong start_code;
+    abi_ulong indx_len;
 
     hdr = ((struct flat_hdr *) bprm->buf);             /* exec-header */
 
@@ -415,7 +407,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                 rev, (int) FLAT_VERSION);
         return -ENOEXEC;
     }
-    
+
     /* Don't allow old format executables to use shared libraries */
     if (rev == OLD_FLAT_VERSION && id != 0) {
         fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
@@ -439,10 +431,15 @@ static int load_flat_file(struct linux_binprm * bprm,
     /*
      * calculate the extra space we need to map in
      */
-    extra = relocs * sizeof(target_ulong);
+    extra = relocs * sizeof(abi_ulong);
     if (extra < bss_len + stack_len)
         extra = bss_len + stack_len;
 
+    /* Add space for library base pointers.  Make sure this does not
+       misalign the  doesn't misalign the data segment.  */
+    indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong);
+    indx_len = (indx_len + 15) & ~(abi_ulong)15;
+
     /*
      * there are a couple of cases here,  the separate code/data
      * case,  and then the fully copied to RAM case which lumps
@@ -457,13 +454,12 @@ static int load_flat_file(struct linux_binprm * bprm,
 
         textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
                               MAP_PRIVATE, bprm->fd, 0);
-        if (textpos == -1) { 
+        if (textpos == -1) {
             fprintf(stderr, "Unable to mmap process text\n");
             return -1;
         }
 
-        realdatastart = target_mmap(0, data_len + extra +
-                                    MAX_SHARED_LIBS * sizeof(target_ulong),
+        realdatastart = target_mmap(0, data_len + extra + indx_len,
                                     PROT_READ|PROT_WRITE|PROT_EXEC,
                                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 
@@ -471,7 +467,7 @@ static int load_flat_file(struct linux_binprm * bprm,
             fprintf(stderr, "Unable to allocate RAM for process data\n");
             return realdatastart;
         }
-        datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
+        datapos = realdatastart + indx_len;
 
         DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
                         (int)(data_len + bss_len + stack_len), (int)datapos);
@@ -479,13 +475,13 @@ static int load_flat_file(struct linux_binprm * bprm,
         fpos = ntohl(hdr->data_start);
 #ifdef CONFIG_BINFMT_ZFLAT
         if (flags & FLAT_FLAG_GZDATA) {
-            result = decompress_exec(bprm, fpos, (char *) datapos, 
-                                     data_len + (relocs * sizeof(target_ulong)))
+            result = decompress_exec(bprm, fpos, (char *) datapos,
+                                     data_len + (relocs * sizeof(abi_ulong)))
         } else
 #endif
         {
             result = target_pread(bprm->fd, datapos,
-                                  data_len + (relocs * sizeof(target_ulong)),
+                                  data_len + (relocs * sizeof(abi_ulong)),
                                   fpos);
         }
         if (result < 0) {
@@ -494,12 +490,10 @@ static int load_flat_file(struct linux_binprm * bprm,
         }
 
         reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
-        memp = realdatastart;
 
     } else {
 
-        textpos = target_mmap(0, text_len + data_len + extra +
-                              MAX_SHARED_LIBS * sizeof(target_ulong),
+        textpos = target_mmap(0, text_len + data_len + extra + indx_len,
                               PROT_READ | PROT_EXEC | PROT_WRITE,
                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
         if (textpos == -1 ) {
@@ -508,10 +502,8 @@ static int load_flat_file(struct linux_binprm * bprm,
         }
 
         realdatastart = textpos + ntohl(hdr->data_start);
-        datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
-        reloc = (textpos + ntohl(hdr->reloc_start) +
-                 MAX_SHARED_LIBS * sizeof(target_ulong));
-        memp = textpos;
+        datapos = realdatastart + indx_len;
+        reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
 
 #ifdef CONFIG_BINFMT_ZFLAT
 #error code needs checking
@@ -541,7 +533,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                                   text_len, 0);
             if (result >= 0) {
                 result = target_pread(bprm->fd, datapos,
-                    data_len + (relocs * sizeof(target_ulong)),
+                    data_len + (relocs * sizeof(abi_ulong)),
                     ntohl(hdr->data_start));
             }
         }
@@ -557,11 +549,10 @@ static int load_flat_file(struct linux_binprm * bprm,
 
     /* The main program needs a little extra setup in the task structure */
     start_code = textpos + sizeof (struct flat_hdr);
-    end_code = textpos + text_len;
 
     DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
             id ? "Lib" : "Load", bprm->filename,
-            (int) start_code, (int) end_code,
+            (int) start_code, (int) (textpos + text_len),
             (int) datapos,
             (int) (datapos + data_len),
             (int) (datapos + data_len),
@@ -578,13 +569,13 @@ static int load_flat_file(struct linux_binprm * bprm,
     libinfo[id].loaded = 1;
     libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
     libinfo[id].build_date = ntohl(hdr->build_date);
-    
+
     /*
      * We just load the allocations into some temporary memory to
      * help simplify all this mumbo jumbo
      *
      * We've got two different sections of relocation entries.
-     * The first is the GOT which resides at the begining of the data segment
+     * The first is the GOT which resides at the beginning of the data segment
      * and is terminated with a -1.  This one can be relocated in place.
      * The second is the extra relocation entries tacked after the image's
      * data segment. These require a little more processing as the entry is
@@ -594,17 +585,19 @@ static int load_flat_file(struct linux_binprm * bprm,
     if (flags & FLAT_FLAG_GOTPIC) {
         rp = datapos;
         while (1) {
-            target_ulong addr;
-            addr = tgetl(rp);
+            abi_ulong addr;
+            if (get_user_ual(addr, rp))
+                return -EFAULT;
             if (addr == -1)
                 break;
             if (addr) {
                 addr = calc_reloc(addr, libinfo, id, 0);
                 if (addr == RELOC_FAILED)
                     return -ENOEXEC;
-                tputl(rp, addr);
+                if (put_user_ual(addr, rp))
+                    return -EFAULT;
             }
-            rp += sizeof(target_ulong);
+            rp += sizeof(abi_ulong);
         }
     }
 
@@ -620,48 +613,54 @@ static int load_flat_file(struct linux_binprm * bprm,
      * __start to address 4 so that is okay).
      */
     if (rev > OLD_FLAT_VERSION) {
+        abi_ulong persistent = 0;
         for (i = 0; i < relocs; i++) {
-            target_ulong addr, relval;
+            abi_ulong addr, relval;
 
             /* Get the address of the pointer to be
                relocated (of course, the address has to be
                relocated first).  */
-            relval = tgetl(reloc + i * sizeof (target_ulong));
+            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+                return -EFAULT;
+            relval = ntohl(relval);
+            if (flat_set_persistent(relval, &persistent))
+                continue;
             addr = flat_get_relocate_addr(relval);
             rp = calc_reloc(addr, libinfo, id, 1);
             if (rp == RELOC_FAILED)
                 return -ENOEXEC;
 
             /* Get the pointer's value.  */
-            addr = tgetl(rp);
+            if (get_user_ual(addr, rp))
+                return -EFAULT;
+            addr = flat_get_addr_from_rp(rp, relval, flags, &persistent);
             if (addr != 0) {
                 /*
                  * Do the relocation.  PIC relocs in the data section are
                  * already in target order
                  */
-
-#ifndef TARGET_WORDS_BIGENDIAN
                 if ((flags & FLAT_FLAG_GOTPIC) == 0)
-                    addr = bswap32(addr);
-#endif
+                    addr = ntohl(addr);
                 addr = calc_reloc(addr, libinfo, id, 0);
                 if (addr == RELOC_FAILED)
                     return -ENOEXEC;
 
                 /* Write back the relocated pointer.  */
-                tputl(rp, addr);
+                if (flat_put_addr_at_rp(rp, addr, relval))
+                    return -EFAULT;
             }
         }
     } else {
         for (i = 0; i < relocs; i++) {
-            target_ulong relval;
-            relval = tgetl(reloc + i * sizeof (target_ulong));
+            abi_ulong relval;
+            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+                return -EFAULT;
             old_reloc(&libinfo[0], relval);
         }
     }
-    
+
     /* zero the BSS.  */
-    memset((void*)(datapos + data_len), 0, bss_len);
+    memset(g2h(datapos + data_len), 0, bss_len);
 
     return 0;
 }
@@ -709,10 +708,10 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                     struct image_info * info)
 {
     struct lib_info libinfo[MAX_SHARED_LIBS];
-    target_ulong p = bprm->p;
-    target_ulong stack_len;
-    target_ulong start_addr;
-    target_ulong sp;
+    abi_ulong p = bprm->p;
+    abi_ulong stack_len;
+    abi_ulong start_addr;
+    abi_ulong sp;
     int res;
     int i, j;
 
@@ -724,26 +723,36 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
      * pedantic and include space for the argv/envp array as it may have
      * a lot of entries.
      */
-#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
-    stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
+    stack_len = 0;
+    for (i = 0; i < bprm->argc; ++i) {
+        /* the argv strings */
+        stack_len += strlen(bprm->argv[i]);
+    }
+    for (i = 0; i < bprm->envc; ++i) {
+        /* the envp strings */
+        stack_len += strlen(bprm->envp[i]);
+    }
     stack_len += (bprm->argc + 1) * 4; /* the argv array */
     stack_len += (bprm->envc + 1) * 4; /* the envp array */
 
-    
+
     res = load_flat_file(bprm, libinfo, 0, &stack_len);
     if (res > (unsigned long)-4096)
             return res;
-    
+
     /* Update data segment pointers for all libraries */
     for (i=0; i<MAX_SHARED_LIBS; i++) {
         if (libinfo[i].loaded) {
-            target_ulong p;
+            abi_ulong p;
             p = libinfo[i].start_data;
             for (j=0; j<MAX_SHARED_LIBS; j++) {
                 p -= 4;
-                tput32(p, libinfo[j].loaded
-                          ? libinfo[j].start_data
-                          : UNLOADED_LIB);
+                /* FIXME - handle put_user() failures */
+                if (put_user_ual(libinfo[j].loaded
+                                 ? libinfo[j].start_data
+                                 : UNLOADED_LIB,
+                                 p))
+                    return -EFAULT;
             }
         }
     }
@@ -755,9 +764,17 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     p = copy_strings(p, bprm->envc, bprm->envp);
     p = copy_strings(p, bprm->argc, bprm->argv);
     /* Align stack.  */
-    sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
-    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
-    
+    sp = p & ~(abi_ulong)(sizeof(abi_ulong) - 1);
+    /* Enforce final stack alignment of 16 bytes.  This is sufficient
+       for all current targets, and excess alignment is harmless.  */
+    stack_len = bprm->envc + bprm->argc + 2;
+    stack_len += 3;    /* argc, arvg, argp */
+    stack_len *= sizeof(abi_ulong);
+    if ((sp + stack_len) & 15)
+        sp -= 16 - ((sp + stack_len) & 15);
+    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p,
+                             flat_argvp_envp_on_stack());
+
     /* Fake some return addresses to ensure the call chain will
      * initialise library in order for us.  We are required to call
      * lib 1 first, then 2, ... and finally the main program (id 0).
@@ -769,12 +786,14 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     for (i = MAX_SHARED_LIBS-1; i>0; i--) {
             if (libinfo[i].loaded) {
                     /* Push previos first to call address */
-                    --sp;      put_user(start_addr, sp);
+                    --sp;
+                    if (put_user_ual(start_addr, sp))
+                        return -EFAULT;
                     start_addr = libinfo[i].entry;
             }
     }
 #endif
-    
+
     /* Stash our initial stack pointer into the mm structure */
     info->start_code = libinfo[0].start_code;
     info->end_code = libinfo[0].start_code = libinfo[0].text_len;
@@ -782,12 +801,13 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     info->end_data = libinfo[0].end_data;
     info->start_brk = libinfo[0].start_brk;
     info->start_stack = sp;
+    info->stack_limit = libinfo[0].start_brk;
     info->entry = start_addr;
     info->code_offset = info->start_code;
     info->data_offset = info->start_data - libinfo[0].text_len;
 
     DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
             (int)info->entry, (int)info->start_stack);
-    
+
     return 0;
 }