(linenum→info "unix/slp.c:2238")

qemu/0.9.1/linux-user/flatload.c

    1: /****************************************************************************/
    2: /*
    3:  *  QEMU bFLT binary loader.  Based on linux/fs/binfmt_flat.c
    4:  *
    5:  *  This program is free software; you can redistribute it and/or modify
    6:  *  it under the terms of the GNU General Public License as published by
    7:  *  the Free Software Foundation; either version 2 of the License, or
    8:  *  (at your option) any later version.
    9:  *
   10:  *  This program is distributed in the hope that it will be useful,
   11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13:  *  GNU General Public License for more details.
   14:  *
   15:  *  You should have received a copy of the GNU General Public License
   16:  *  along with this program; if not, write to the Free Software
   17:  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18:  *
   19:  *      Copyright (C) 2006 CodeSourcery.
   20:  *      Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
   21:  *      Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
   22:  *      Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
   23:  *      Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
   24:  *  based heavily on:
   25:  *
   26:  *  linux/fs/binfmt_aout.c:
   27:  *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
   28:  *  linux/fs/binfmt_flat.c for 2.0 kernel
   29:  *          Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
   30:  *      JAN/99 -- coded full program relocation (gerg@snapgear.com)
   31:  */
   32: 
   33: /* ??? ZFLAT and shared library support is currently disabled.  */
   34: 
   35: /****************************************************************************/
   36: 
   37: #include <stdio.h>
   38: #include <stdlib.h>
   39: #include <errno.h>
   40: #include <sys/mman.h>
   41: #include <unistd.h>
   42: 
   43: #include "qemu.h"
   44: #include "flat.h"
   45: 
   46: //#define DEBUG
   47: 
   48: #ifdef DEBUG
   49: #define DBG_FLT(a...)   printf(a)
   50: #else
   51: #define DBG_FLT(a...)
   52: #endif
   53: 
   54: #define flat_reloc_valid(reloc, size)             ((reloc) <= (size))
   55: #define flat_old_ram_flag(flag)                   (flag)
   56: #ifdef TARGET_WORDS_BIGENDIAN
   57: #define flat_get_relocate_addr(relval)            (relval)
   58: #else
   59: #define flat_get_relocate_addr(relval)            bswap32(relval)
   60: #endif
   61: 
   62: #define RELOC_FAILED 0xff00ff01         /* Relocation incorrect somewhere */
   63: #define UNLOADED_LIB 0x7ff000ff         /* Placeholder for unused library */
   64: 
   65: struct lib_info {
   66:     abi_ulong start_code;       /* Start of text segment */
   67:     abi_ulong start_data;       /* Start of data segment */
   68:     abi_ulong end_data;         /* Start of bss section */
   69:     abi_ulong start_brk;        /* End of data segment */
   70:     abi_ulong text_len;         /* Length of text segment */
   71:     abi_ulong entry;            /* Start address for this module */
   72:     abi_ulong build_date;       /* When this one was compiled */
   73:     short loaded;               /* Has this library been loaded? */
   74: };
   75: 
   76: #ifdef CONFIG_BINFMT_SHARED_FLAT
   77: static int load_flat_shared_library(int id, struct lib_info *p);
   78: #endif
   79: 
   80: struct linux_binprm;
   81: 
   82: #define ntohl(x) be32_to_cpu(x)
   83: 
   84: /****************************************************************************/
   85: /*
   86:  * create_flat_tables() parses the env- and arg-strings in new user
   87:  * memory and creates the pointer tables from them, and puts their
   88:  * addresses on the "stack", returning the new stack pointer value.
   89:  */
   90: 
   91: /* Push a block of strings onto the guest stack.  */
   92: static abi_ulong copy_strings(abi_ulong p, int n, char **s)
   93: {
   94:     int len;
   95: 
   96:     while (n-- > 0) {
   97:         len = strlen(s[n]) + 1;
   98:         p -= len;
   99:         memcpy_to_target(p, s[n], len);
  100:     }
  101: 
  102:     return p;
  103: }
  104: 
  105: int target_pread(int fd, abi_ulong ptr, abi_ulong len,
  106:                  abi_ulong offset)
  107: {
  108:     void *buf;
  109:     int ret;
  110: 
  111:     buf = lock_user(VERIFY_WRITE, ptr, len, 0);
  112:     ret = pread(fd, buf, len, offset);
  113:     unlock_user(buf, ptr, len);
  114:     return ret;
  115: }
  116: /****************************************************************************/
  117: 
  118: #ifdef CONFIG_BINFMT_ZFLAT
  119: 
  120: #include <linux/zlib.h>
  121: 
  122: #define LBUFSIZE        4000
  123: 
  124: /* gzip flag byte */
  125: #define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
  126: #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
  127: #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
  128: #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
  129: #define COMMENT      0x10 /* bit 4 set: file comment present */
  130: #define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
  131: #define RESERVED     0xC0 /* bit 6,7:   reserved */
  132: 
  133: static int decompress_exec(
  134:         struct linux_binprm *bprm,
  135:         unsigned long offset,
  136:         char *dst,
  137:         long len,
  138:         int fd)
  139: {
  140:         unsigned char *buf;
  141:         z_stream strm;
  142:         loff_t fpos;
  143:         int ret, retval;
  144: 
  145:         DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
  146: 
  147:         memset(&strm, 0, sizeof(strm));
  148:         strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
  149:         if (strm.workspace == NULL) {
  150:                 DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
  151:                 return -ENOMEM;
  152:         }
  153:         buf = kmalloc(LBUFSIZE, GFP_KERNEL);
  154:         if (buf == NULL) {
  155:                 DBG_FLT("binfmt_flat: no memory for read buffer\n");
  156:                 retval = -ENOMEM;
  157:                 goto out_free;
  158:         }
  159: 
  160:         /* Read in first chunk of data and parse gzip header. */
  161:         fpos = offset;
  162:         ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
  163: 
  164:         strm.next_in = buf;
  165:         strm.avail_in = ret;
  166:         strm.total_in = 0;
  167: 
  168:         retval = -ENOEXEC;
  169: 
  170:         /* Check minimum size -- gzip header */
  171:         if (ret < 10) {
  172:                 DBG_FLT("binfmt_flat: file too small?\n");
  173:                 goto out_free_buf;
  174:         }
  175: 
  176:         /* Check gzip magic number */
  177:         if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
  178:                 DBG_FLT("binfmt_flat: unknown compression magic?\n");
  179:                 goto out_free_buf;
  180:         }
  181: 
  182:         /* Check gzip method */
  183:         if (buf[2] != 8) {
  184:                 DBG_FLT("binfmt_flat: unknown compression method?\n");
  185:                 goto out_free_buf;
  186:         }
  187:         /* Check gzip flags */
  188:         if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
  189:             (buf[3] & RESERVED)) {
  190:                 DBG_FLT("binfmt_flat: unknown flags?\n");
  191:                 goto out_free_buf;
  192:         }
  193: 
  194:         ret = 10;
  195:         if (buf[3] & EXTRA_FIELD) {
  196:                 ret += 2 + buf[10] + (buf[11] << 8);
  197:                 if (unlikely(LBUFSIZE == ret)) {
  198:                         DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
  199:                         goto out_free_buf;
  200:                 }
  201:         }
  202:         if (buf[3] & ORIG_NAME) {
  203:                 for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
  204:                         ;
  205:                 if (unlikely(LBUFSIZE == ret)) {
  206:                         DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
  207:                         goto out_free_buf;
  208:                 }
  209:         }
  210:         if (buf[3] & COMMENT) {
  211:                 for (;  ret < LBUFSIZE && (buf[ret] != 0); ret++)
  212:                         ;
  213:                 if (unlikely(LBUFSIZE == ret)) {
  214:                         DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
  215:                         goto out_free_buf;
  216:                 }
  217:         }
  218: 
  219:         strm.next_in += ret;
  220:         strm.avail_in -= ret;
  221: 
  222:         strm.next_out = dst;
  223:         strm.avail_out = len;
  224:         strm.total_out = 0;
  225: 
  226:         if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
  227:                 DBG_FLT("binfmt_flat: zlib init failed?\n");
  228:                 goto out_free_buf;
  229:         }
  230: 
  231:         while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
  232:                 ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
  233:                 if (ret <= 0)
  234:                         break;
  235:                 if (ret >= (unsigned long) -4096)
  236:                         break;
  237:                 len -= ret;
  238: 
  239:                 strm.next_in = buf;
  240:                 strm.avail_in = ret;
  241:                 strm.total_in = 0;
  242:         }
  243: 
  244:         if (ret < 0) {
  245:                 DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
  246:                         ret, strm.msg);
  247:                 goto out_zlib;
  248:         }
  249: 
  250:         retval = 0;
  251: out_zlib:
  252:         zlib_inflateEnd(&strm);
  253: out_free_buf:
  254:         kfree(buf);
  255: out_free:
  256:         kfree(strm.workspace);
  257: out:
  258:         return retval;
  259: }
  260: 
  261: #endif /* CONFIG_BINFMT_ZFLAT */
  262: 
  263: /****************************************************************************/
  264: 
  265: static abi_ulong
  266: calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
  267: {
  268:     abi_ulong addr;
  269:     int id;
  270:     abi_ulong start_brk;
  271:     abi_ulong start_data;
  272:     abi_ulong text_len;
  273:     abi_ulong start_code;
  274: 
  275: #ifdef CONFIG_BINFMT_SHARED_FLAT
  276: #error needs checking
  277:     if (r == 0)
  278:         id = curid;     /* Relocs of 0 are always self referring */
  279:     else {
  280:         id = (r >> 24) & 0xff;  /* Find ID for this reloc */
  281:         r &= 0x00ffffff;        /* Trim ID off here */
  282:     }
  283:     if (id >= MAX_SHARED_LIBS) {
  284:         fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
  285:                 (unsigned) r, id);
  286:         goto failed;
  287:     }
  288:     if (curid != id) {
  289:         if (internalp) {
  290:             fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
  291:                     "in same module (%d != %d)\n",
  292:                     (unsigned) r, curid, id);
  293:             goto failed;
  294:         } else if ( ! p[id].loaded &&
  295:                     load_flat_shared_library(id, p) > (unsigned long) -4096) {
  296:             fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
  297:             goto failed;
  298:         }
  299:         /* Check versioning information (i.e. time stamps) */
  300:         if (p[id].build_date && p[curid].build_date
  301:             && p[curid].build_date < p[id].build_date) {
  302:             fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
  303:                     id, curid);
  304:             goto failed;
  305:         }
  306:     }
  307: #else
  308:     id = 0;
  309: #endif
  310: 
  311:     start_brk = p[id].start_brk;
  312:     start_data = p[id].start_data;
  313:     start_code = p[id].start_code;
  314:     text_len = p[id].text_len;
  315: 
  316:     if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
  317:         fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x "
  318:                 "(0 - 0x%x/0x%x)\n",
  319:                (int) r,(int)(start_brk-start_code),(int)text_len);
  320:         goto failed;
  321:     }
  322: 
  323:     if (r < text_len)                   /* In text segment */
  324:         addr = r + start_code;
  325:     else                                        /* In data segment */
  326:         addr = r - text_len + start_data;
  327: 
  328:     /* Range checked already above so doing the range tests is redundant...*/
  329:     return(addr);
  330: 
  331: failed:
  332:     abort();
  333:     return RELOC_FAILED;
  334: }
  335: 
  336: /****************************************************************************/
  337: 
  338: /* ??? This does not handle endianness correctly.  */
  339: void old_reloc(struct lib_info *libinfo, uint32_t rl)
  340: {
  341: #ifdef DEBUG
  342:         char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
  343: #endif
  344:         uint32_t *ptr;
  345:         uint32_t offset;
  346:         int reloc_type;
  347: 
  348:         offset = rl & 0x3fffffff;
  349:         reloc_type = rl >> 30;
  350:         /* ??? How to handle this?  */
  351: #if defined(CONFIG_COLDFIRE)
  352:         ptr = (uint32_t *) (libinfo->start_code + offset);
  353: #else
  354:         ptr = (uint32_t *) (libinfo->start_data + offset);
  355: #endif
  356: 
  357: #ifdef DEBUG
  358:         fprintf(stderr, "Relocation of variable at DATASEG+%x "
  359:                 "(address %p, currently %x) into segment %s\n",
  360:                 offset, ptr, (int)*ptr, segment[reloc_type]);
  361: #endif
  362: 
  363:         switch (reloc_type) {
  364:         case OLD_FLAT_RELOC_TYPE_TEXT:
  365:                 *ptr += libinfo->start_code;
  366:                 break;
  367:         case OLD_FLAT_RELOC_TYPE_DATA:
  368:                 *ptr += libinfo->start_data;
  369:                 break;
  370:         case OLD_FLAT_RELOC_TYPE_BSS:
  371:                 *ptr += libinfo->end_data;
  372:                 break;
  373:         default:
  374:                 fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n",
  375:                         reloc_type);
  376:                 break;
  377:         }
  378:         DBG_FLT("Relocation became %x\n", (int)*ptr);
  379: }
  380: 
  381: /****************************************************************************/
  382: 
  383: static int load_flat_file(struct linux_binprm * bprm,
  384:                 struct lib_info *libinfo, int id, abi_ulong *extra_stack)
  385: {
  386:     struct flat_hdr * hdr;
  387:     abi_ulong textpos = 0, datapos = 0, result;
  388:     abi_ulong realdatastart = 0;
  389:     abi_ulong text_len, data_len, bss_len, stack_len, flags;
  390:     abi_ulong memp = 0; /* for finding the brk area */
  391:     abi_ulong extra;
  392:     abi_ulong reloc = 0, rp;
  393:     int i, rev, relocs = 0;
  394:     abi_ulong fpos;
  395:     abi_ulong start_code, end_code;
  396:     abi_ulong indx_len;
  397: 
  398:     hdr = ((struct flat_hdr *) bprm->buf);              /* exec-header */
  399: 
  400:     text_len  = ntohl(hdr->data_start);
  401:     data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
  402:     bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
  403:     stack_len = ntohl(hdr->stack_size);
  404:     if (extra_stack) {
  405:         stack_len += *extra_stack;
  406:         *extra_stack = stack_len;
  407:     }
  408:     relocs    = ntohl(hdr->reloc_count);
  409:     flags     = ntohl(hdr->flags);
  410:     rev       = ntohl(hdr->rev);
  411: 
  412:     DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
  413: 
  414:     if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
  415:         fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
  416:                 rev, (int) FLAT_VERSION);
  417:         return -ENOEXEC;
  418:     }
  419: 
  420:     /* Don't allow old format executables to use shared libraries */
  421:     if (rev == OLD_FLAT_VERSION && id != 0) {
  422:         fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
  423:         return -ENOEXEC;
  424:     }
  425: 
  426:     /*
  427:      * fix up the flags for the older format,  there were all kinds
  428:      * of endian hacks,  this only works for the simple cases
  429:      */
  430:     if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
  431:         flags = FLAT_FLAG_RAM;
  432: 
  433: #ifndef CONFIG_BINFMT_ZFLAT
  434:     if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
  435:         fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
  436:         return -ENOEXEC;
  437:     }
  438: #endif
  439: 
  440:     /*
  441:      * calculate the extra space we need to map in
  442:      */
  443:     extra = relocs * sizeof(abi_ulong);
  444:     if (extra < bss_len + stack_len)
  445:         extra = bss_len + stack_len;
  446: 
  447:     /* Add space for library base pointers.  Make sure this does not
  448:        misalign the  doesn't misalign the data segment.  */
  449:     indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong);
  450:     indx_len = (indx_len + 15) & ~(abi_ulong)15;
  451: 
  452:     /*
  453:      * there are a couple of cases here,  the separate code/data
  454:      * case,  and then the fully copied to RAM case which lumps
  455:      * it all together.
  456:      */
  457:     if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
  458:         /*
  459:          * this should give us a ROM ptr,  but if it doesn't we don't
  460:          * really care
  461:          */
  462:         DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
  463: 
  464:         textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
  465:                               MAP_PRIVATE, bprm->fd, 0);
  466:         if (textpos == -1) {
  467:             fprintf(stderr, "Unable to mmap process text\n");
  468:             return -1;
  469:         }
  470: 
  471:         realdatastart = target_mmap(0, data_len + extra + indx_len,
  472:                                     PROT_READ|PROT_WRITE|PROT_EXEC,
  473:                                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  474: 
  475:         if (realdatastart == -1) {
  476:             fprintf(stderr, "Unable to allocate RAM for process data\n");
  477:             return realdatastart;
  478:         }
  479:         datapos = realdatastart + indx_len;
  480: 
  481:         DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
  482:                         (int)(data_len + bss_len + stack_len), (int)datapos);
  483: 
  484:         fpos = ntohl(hdr->data_start);
  485: #ifdef CONFIG_BINFMT_ZFLAT
  486:         if (flags & FLAT_FLAG_GZDATA) {
  487:             result = decompress_exec(bprm, fpos, (char *) datapos,
  488:                                      data_len + (relocs * sizeof(abi_ulong)))
  489:         } else
  490: #endif
  491:         {
  492:             result = target_pread(bprm->fd, datapos,
  493:                                   data_len + (relocs * sizeof(abi_ulong)),
  494:                                   fpos);
  495:         }
  496:         if (result < 0) {
  497:             fprintf(stderr, "Unable to read data+bss\n");
  498:             return result;
  499:         }
  500: 
  501:         reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
  502:         memp = realdatastart;
  503: 
  504:     } else {
  505: 
  506:         textpos = target_mmap(0, text_len + data_len + extra + indx_len,
  507:                               PROT_READ | PROT_EXEC | PROT_WRITE,
  508:                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  509:         if (textpos == -1 ) {
  510:             fprintf(stderr, "Unable to allocate RAM for process text/data\n");
  511:             return -1;
  512:         }
  513: 
  514:         realdatastart = textpos + ntohl(hdr->data_start);
  515:         datapos = realdatastart + indx_len;
  516:         reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
  517:         memp = textpos;
  518: 
  519: #ifdef CONFIG_BINFMT_ZFLAT
  520: #error code needs checking
  521:         /*
  522:          * load it all in and treat it like a RAM load from now on
  523:          */
  524:         if (flags & FLAT_FLAG_GZIP) {
  525:                 result = decompress_exec(bprm, sizeof (struct flat_hdr),
  526:                                  (((char *) textpos) + sizeof (struct flat_hdr)),
  527:                                  (text_len + data_len + (relocs * sizeof(unsigned long))
  528:                                           - sizeof (struct flat_hdr)),
  529:                                  0);
  530:                 memmove((void *) datapos, (void *) realdatastart,
  531:                                 data_len + (relocs * sizeof(unsigned long)));
  532:         } else if (flags & FLAT_FLAG_GZDATA) {
  533:                 fpos = 0;
  534:                 result = bprm->file->f_op->read(bprm->file,
  535:                                 (char *) textpos, text_len, &fpos);
  536:                 if (result < (unsigned long) -4096)
  537:                         result = decompress_exec(bprm, text_len, (char *) datapos,
  538:                                          data_len + (relocs * sizeof(unsigned long)), 0);
  539:         }
  540:         else
  541: