10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*6812Sraf * Common Development and Distribution License (the "License").
6*6812Sraf * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*6812Sraf
22*6812Sraf /*
23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24*6812Sraf * Use is subject to license terms.
25*6812Sraf */
26*6812Sraf
270Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate
30*6812Sraf #pragma ident "%Z%%M% %I% %E% SMI"
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <memory.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <sys/mman.h>
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include <libelf.h>
390Sstevel@tonic-gate #include "decl.h"
400Sstevel@tonic-gate #include "msg.h"
410Sstevel@tonic-gate
420Sstevel@tonic-gate
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate * File input
450Sstevel@tonic-gate * These functions read input files.
460Sstevel@tonic-gate * On SVR4 and newer systems use mmap(2). On older systems (or on
470Sstevel@tonic-gate * file systems that don't support mmap, this code simulates mmap.
480Sstevel@tonic-gate * When reading a file, enough memory is allocated to hold the file's
490Sstevel@tonic-gate * image, and reads are delayed. When another part of the library
500Sstevel@tonic-gate * wants to use a part of the file, it "fetches" the needed regions.
510Sstevel@tonic-gate *
520Sstevel@tonic-gate * An elf descriptor has a bit array to manage this. Each bit
530Sstevel@tonic-gate * represents one "page" of the file. Pages are grouped into regions.
540Sstevel@tonic-gate * The page size is tunable. Its value should be at least one disk
550Sstevel@tonic-gate * block and small enough to avoid superfluous traffic.
560Sstevel@tonic-gate *
570Sstevel@tonic-gate * NBITS The number of bits in an unsigned. Each unsigned object
580Sstevel@tonic-gate * holds a "REGION." A byte must have at least 8 bits;
590Sstevel@tonic-gate * it may have more, though the extra bits at the top of
600Sstevel@tonic-gate * the unsigned will be unused. Thus, for 9-bit bytes and
610Sstevel@tonic-gate * 36-bit words, 4 bits at the top will stay empty.
620Sstevel@tonic-gate *
630Sstevel@tonic-gate * This mechanism gives significant performance gains for library
640Sstevel@tonic-gate * handling (among other things), because programs typically don't
650Sstevel@tonic-gate * need to look at entire libraries. The fastest I/O is no I/O.
660Sstevel@tonic-gate */
670Sstevel@tonic-gate
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate * This global is used to hold the value of the PAGESIZE macro.
700Sstevel@tonic-gate *
710Sstevel@tonic-gate * This is because the PAGESIZE macro actually calls the
720Sstevel@tonic-gate * sysconfig(_CONFIG_PAGESIZE) system call and we don't want
730Sstevel@tonic-gate * to repeatedly call this through out libelf.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate static unsigned long _elf_pagesize = 0;
760Sstevel@tonic-gate NOTE(SCHEME_PROTECTS_DATA("read only data", _elf_pagesize))
770Sstevel@tonic-gate
780Sstevel@tonic-gate
790Sstevel@tonic-gate #define NBITS (8 * sizeof (unsigned))
800Sstevel@tonic-gate #define REGSZ (NBITS * _elf_pagesize)
810Sstevel@tonic-gate #define PGNUM(off) ((off % REGSZ) / _elf_pagesize)
820Sstevel@tonic-gate #define REGNUM(off) (off / REGSZ)
830Sstevel@tonic-gate
840Sstevel@tonic-gate
850Sstevel@tonic-gate
860Sstevel@tonic-gate Okay
_elf_vm(Elf * elf,size_t base,size_t sz)870Sstevel@tonic-gate _elf_vm(Elf * elf, size_t base, size_t sz)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf))
900Sstevel@tonic-gate register unsigned *hdreg, hdbit;
910Sstevel@tonic-gate unsigned *tlreg, tlbit;
920Sstevel@tonic-gate size_t tail;
930Sstevel@tonic-gate off_t off;
940Sstevel@tonic-gate Elf_Void *iop;
950Sstevel@tonic-gate
960Sstevel@tonic-gate
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate * always validate region
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate if ((base + sz) > elf->ed_fsz) {
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate * range outside of file bounds.
1040Sstevel@tonic-gate */
1050Sstevel@tonic-gate _elf_seterr(EFMT_VM, 0);
1060Sstevel@tonic-gate return (OK_NO);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /*
1100Sstevel@tonic-gate * If file is mmap()'d and/or the read size is 0
1110Sstevel@tonic-gate * their is nothing else for us to do.
1120Sstevel@tonic-gate */
1130Sstevel@tonic-gate if (elf->ed_vm == 0 || sz == 0)
1140Sstevel@tonic-gate return (OK_YES);
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate * This uses arithmetic instead of masking because
1170Sstevel@tonic-gate * sizeof (unsigned) might not be a power of 2.
1180Sstevel@tonic-gate *
1190Sstevel@tonic-gate * Tail gives one beyond the last offset that must be retrieved,
1200Sstevel@tonic-gate * NOT the last in the region.
1210Sstevel@tonic-gate */
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate if (elf->ed_parent && elf->ed_parent->ed_fd == -1)
1240Sstevel@tonic-gate elf->ed_fd = -1;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate base += elf->ed_baseoff;
1270Sstevel@tonic-gate tail = base + sz + _elf_pagesize - 1;
1280Sstevel@tonic-gate off = base - base % _elf_pagesize;
1290Sstevel@tonic-gate hdbit = 1 << PGNUM(base);
1300Sstevel@tonic-gate tlbit = 1 << PGNUM(tail);
1310Sstevel@tonic-gate hdreg = &elf->ed_vm[REGNUM(base)];
1320Sstevel@tonic-gate tlreg = &elf->ed_vm[REGNUM(tail)];
1330Sstevel@tonic-gate sz = 0;
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate * Scan through the files 'page table' and make sure
1370Sstevel@tonic-gate * that all of the pages in the specified range have been
1380Sstevel@tonic-gate * loaded into memory. As the pages are loaded the appropriate
1390Sstevel@tonic-gate * bit in the 'page table' is set.
1400Sstevel@tonic-gate *
1410Sstevel@tonic-gate * Note: This loop will only read in those pages which havn't
1420Sstevel@tonic-gate * been previously loaded into memory, if the page is
1430Sstevel@tonic-gate * already present it will not be re-loaded.
1440Sstevel@tonic-gate */
1450Sstevel@tonic-gate while ((hdreg != tlreg) || (hdbit != tlbit)) {
1460Sstevel@tonic-gate if (*hdreg & hdbit) {
1470Sstevel@tonic-gate if (sz != 0) {
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate * Read in a 'chunk' of the elf image.
1500Sstevel@tonic-gate */
1510Sstevel@tonic-gate iop = (Elf_Void *)(elf->ed_image + off);
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate * do not read past the end of the file
1540Sstevel@tonic-gate */
1550Sstevel@tonic-gate if (elf->ed_imagesz - off < sz)
1560Sstevel@tonic-gate sz = elf->ed_imagesz - off;
1570Sstevel@tonic-gate if ((lseek(elf->ed_fd, off,
1580Sstevel@tonic-gate SEEK_SET) != off) ||
1590Sstevel@tonic-gate (read(elf->ed_fd, iop, sz) != sz)) {
1600Sstevel@tonic-gate _elf_seterr(EIO_VM, errno);
1610Sstevel@tonic-gate return (OK_NO);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate off += sz;
1640Sstevel@tonic-gate sz = 0;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate off += _elf_pagesize;
1670Sstevel@tonic-gate } else {
1680Sstevel@tonic-gate if (elf->ed_fd < 0) {
1690Sstevel@tonic-gate _elf_seterr(EREQ_NOFD, 0);
1700Sstevel@tonic-gate return (OK_NO);
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate sz += _elf_pagesize;
1730Sstevel@tonic-gate *hdreg |= hdbit;
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate if (hdbit == ((unsigned)1 << (NBITS - 1))) {
1760Sstevel@tonic-gate hdbit = 1;
1770Sstevel@tonic-gate ++hdreg;
1780Sstevel@tonic-gate } else
1790Sstevel@tonic-gate hdbit <<= 1;
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate if (sz != 0) {
1830Sstevel@tonic-gate iop = (Elf_Void *)(elf->ed_image + off);
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate * do not read past the end of the file
1860Sstevel@tonic-gate */
1870Sstevel@tonic-gate if ((elf->ed_imagesz - off) < sz)
1880Sstevel@tonic-gate sz = elf->ed_imagesz - off;
1890Sstevel@tonic-gate if ((lseek(elf->ed_fd, off, SEEK_SET) != off) ||
1900Sstevel@tonic-gate (read(elf->ed_fd, iop, sz) != sz)) {
1910Sstevel@tonic-gate _elf_seterr(EIO_VM, errno);
1920Sstevel@tonic-gate return (OK_NO);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate return (OK_YES);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate Okay
_elf_inmap(Elf * elf)2000Sstevel@tonic-gate _elf_inmap(Elf * elf)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate int fd = elf->ed_fd;
2030Sstevel@tonic-gate register size_t sz;
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate register off_t off = lseek(fd, (off_t)0, SEEK_END);
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate if (off == 0)
2090Sstevel@tonic-gate return (OK_YES);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate if (off == -1) {
2120Sstevel@tonic-gate _elf_seterr(EIO_FSZ, errno);
2130Sstevel@tonic-gate return (OK_NO);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate if ((sz = (size_t)off) != off) {
2170Sstevel@tonic-gate _elf_seterr(EIO_FBIG, 0);
2180Sstevel@tonic-gate return (OK_NO);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate * If the file is mapped, elf->ed_vm will stay null
2230Sstevel@tonic-gate * and elf->ed_image will need to be unmapped someday.
2240Sstevel@tonic-gate * If the file is read, elf->ed_vm and the file image
2250Sstevel@tonic-gate * are allocated together; free() elf->ed_vm.
2260Sstevel@tonic-gate *
2270Sstevel@tonic-gate * If the file can be written, disallow mmap.
2280Sstevel@tonic-gate * Otherwise, the input mapping and the output mapping
2290Sstevel@tonic-gate * can collide. Moreover, elf_update will truncate
2300Sstevel@tonic-gate * the file, possibly invalidating the input mapping.
2310Sstevel@tonic-gate * Disallowing input mmap forces the library to malloc
2320Sstevel@tonic-gate * and read the space, which will make output mmap safe.
2330Sstevel@tonic-gate * Using mmap for output reduces the swap space needed
2340Sstevel@tonic-gate * for the process, so that is given preference.
2350Sstevel@tonic-gate */
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate register char *p;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate if ((elf->ed_myflags & EDF_WRITE) == 0 &&
2410Sstevel@tonic-gate (p = mmap((char *)0, sz, PROT_READ,
2420Sstevel@tonic-gate MAP_PRIVATE, fd, (off_t)0)) != (char *)-1) {
2430Sstevel@tonic-gate elf->ed_image = elf->ed_ident = p;
2440Sstevel@tonic-gate elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz;
2450Sstevel@tonic-gate return (OK_YES);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate if (_elf_pagesize == 0)
2500Sstevel@tonic-gate _elf_pagesize = PAGESIZE;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate * If mmap fails, try read. Some file systems don't mmap
2540Sstevel@tonic-gate */
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate register size_t vmsz = sizeof (unsigned) * (REGNUM(sz) + 1);
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate if (vmsz % sizeof (Elf64) != 0)
2590Sstevel@tonic-gate vmsz += sizeof (Elf64) - vmsz % sizeof (Elf64);
2600Sstevel@tonic-gate if ((elf->ed_vm = (unsigned *)malloc(vmsz + sz)) == 0) {
2610Sstevel@tonic-gate _elf_seterr(EMEM_VM, errno);
2620Sstevel@tonic-gate return (OK_NO);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate (void) memset(elf->ed_vm, 0, vmsz);
2650Sstevel@tonic-gate elf->ed_vmsz = vmsz / sizeof (unsigned);
2660Sstevel@tonic-gate elf->ed_image = elf->ed_ident = (char *)elf->ed_vm + vmsz;
2670Sstevel@tonic-gate elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz;
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate return (_elf_vm(elf, (size_t)0, (size_t)1));
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate void
_elf_unmap(char * p,size_t sz)274*6812Sraf _elf_unmap(char *p, size_t sz)
2750Sstevel@tonic-gate {
2760Sstevel@tonic-gate if (p == 0 || sz == 0)
2770Sstevel@tonic-gate return;
2780Sstevel@tonic-gate (void) munmap(p, sz);
2790Sstevel@tonic-gate }
280