1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <memory.h> 33 #include <errno.h> 34 #include <sys/mman.h> 35 #include <sys/param.h> 36 #include <libelf.h> 37 #include "decl.h" 38 #include "msg.h" 39 40 41 /* 42 * File input 43 * These functions read input files. 44 * On SVR4 and newer systems use mmap(2). On older systems (or on 45 * file systems that don't support mmap, this code simulates mmap. 46 * When reading a file, enough memory is allocated to hold the file's 47 * image, and reads are delayed. When another part of the library 48 * wants to use a part of the file, it "fetches" the needed regions. 49 * 50 * An elf descriptor has a bit array to manage this. Each bit 51 * represents one "page" of the file. Pages are grouped into regions. 52 * The page size is tunable. Its value should be at least one disk 53 * block and small enough to avoid superfluous traffic. 54 * 55 * NBITS The number of bits in an unsigned. Each unsigned object 56 * holds a "REGION." A byte must have at least 8 bits; 57 * it may have more, though the extra bits at the top of 58 * the unsigned will be unused. Thus, for 9-bit bytes and 59 * 36-bit words, 4 bits at the top will stay empty. 60 * 61 * This mechanism gives significant performance gains for library 62 * handling (among other things), because programs typically don't 63 * need to look at entire libraries. The fastest I/O is no I/O. 64 */ 65 66 /* 67 * This global is used to hold the value of the PAGESIZE macro. 68 * 69 * This is because the PAGESIZE macro actually calls the 70 * sysconfig(_CONFIG_PAGESIZE) system call and we don't want 71 * to repeatedly call this through out libelf. 72 */ 73 static unsigned long _elf_pagesize = 0; 74 75 #define NBITS (8 * sizeof (unsigned)) 76 #define REGSZ (NBITS * _elf_pagesize) 77 #define PGNUM(off) ((off % REGSZ) / _elf_pagesize) 78 #define REGNUM(off) (off / REGSZ) 79 80 81 82 Okay 83 _elf_vm(Elf * elf, size_t base, size_t sz) 84 { 85 register unsigned *hdreg, hdbit; 86 unsigned *tlreg, tlbit; 87 size_t tail; 88 off_t off; 89 Elf_Void *iop; 90 91 92 /* 93 * always validate region 94 */ 95 96 if ((base + sz) > elf->ed_fsz) { 97 /* 98 * range outside of file bounds. 99 */ 100 _elf_seterr(EFMT_VM, 0); 101 return (OK_NO); 102 } 103 104 /* 105 * If file is mmap()'d and/or the read size is 0 106 * their is nothing else for us to do. 107 */ 108 if (elf->ed_vm == 0 || sz == 0) 109 return (OK_YES); 110 /* 111 * This uses arithmetic instead of masking because 112 * sizeof (unsigned) might not be a power of 2. 113 * 114 * Tail gives one beyond the last offset that must be retrieved, 115 * NOT the last in the region. 116 */ 117 118 if (elf->ed_parent && elf->ed_parent->ed_fd == -1) 119 elf->ed_fd = -1; 120 121 base += elf->ed_baseoff; 122 tail = base + sz + _elf_pagesize - 1; 123 off = base - base % _elf_pagesize; 124 hdbit = 1 << PGNUM(base); 125 tlbit = 1 << PGNUM(tail); 126 hdreg = &elf->ed_vm[REGNUM(base)]; 127 tlreg = &elf->ed_vm[REGNUM(tail)]; 128 sz = 0; 129 130 /* 131 * Scan through the files 'page table' and make sure 132 * that all of the pages in the specified range have been 133 * loaded into memory. As the pages are loaded the appropriate 134 * bit in the 'page table' is set. 135 * 136 * Note: This loop will only read in those pages which havn't 137 * been previously loaded into memory, if the page is 138 * already present it will not be re-loaded. 139 */ 140 while ((hdreg != tlreg) || (hdbit != tlbit)) { 141 if (*hdreg & hdbit) { 142 if (sz != 0) { 143 /* 144 * Read in a 'chunk' of the elf image. 145 */ 146 iop = (Elf_Void *)(elf->ed_image + off); 147 /* 148 * do not read past the end of the file 149 */ 150 if (elf->ed_imagesz - off < sz) 151 sz = elf->ed_imagesz - off; 152 if ((lseek(elf->ed_fd, off, 153 SEEK_SET) != off) || 154 (read(elf->ed_fd, iop, sz) != sz)) { 155 _elf_seterr(EIO_VM, errno); 156 return (OK_NO); 157 } 158 off += sz; 159 sz = 0; 160 } 161 off += _elf_pagesize; 162 } else { 163 if (elf->ed_fd < 0) { 164 _elf_seterr(EREQ_NOFD, 0); 165 return (OK_NO); 166 } 167 sz += _elf_pagesize; 168 *hdreg |= hdbit; 169 } 170 if (hdbit == ((unsigned)1 << (NBITS - 1))) { 171 hdbit = 1; 172 ++hdreg; 173 } else 174 hdbit <<= 1; 175 } 176 177 if (sz != 0) { 178 iop = (Elf_Void *)(elf->ed_image + off); 179 /* 180 * do not read past the end of the file 181 */ 182 if ((elf->ed_imagesz - off) < sz) 183 sz = elf->ed_imagesz - off; 184 if ((lseek(elf->ed_fd, off, SEEK_SET) != off) || 185 (read(elf->ed_fd, iop, sz) != sz)) { 186 _elf_seterr(EIO_VM, errno); 187 return (OK_NO); 188 } 189 } 190 return (OK_YES); 191 } 192 193 194 Okay 195 _elf_inmap(Elf * elf) 196 { 197 int fd = elf->ed_fd; 198 register size_t sz; 199 200 { 201 register off_t off = lseek(fd, (off_t)0, SEEK_END); 202 203 if (off == 0) 204 return (OK_YES); 205 206 if (off == -1) { 207 _elf_seterr(EIO_FSZ, errno); 208 return (OK_NO); 209 } 210 211 if ((sz = (size_t)off) != off) { 212 _elf_seterr(EIO_FBIG, 0); 213 return (OK_NO); 214 } 215 } 216 /* 217 * If the file is mapped, elf->ed_vm will stay null 218 * and elf->ed_image will need to be unmapped someday. 219 * If the file is read, elf->ed_vm and the file image 220 * are allocated together; free() elf->ed_vm. 221 * 222 * If the file can be written, disallow mmap. 223 * Otherwise, the input mapping and the output mapping 224 * can collide. Moreover, elf_update will truncate 225 * the file, possibly invalidating the input mapping. 226 * Disallowing input mmap forces the library to malloc 227 * and read the space, which will make output mmap safe. 228 * Using mmap for output reduces the swap space needed 229 * for the process, so that is given preference. 230 */ 231 232 { 233 register char *p; 234 235 if ((elf->ed_myflags & EDF_WRITE) == 0 && 236 (p = mmap((char *)0, sz, PROT_READ, 237 MAP_PRIVATE, fd, (off_t)0)) != (char *)-1) { 238 elf->ed_image = elf->ed_ident = p; 239 elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz; 240 return (OK_YES); 241 } 242 } 243 244 if (_elf_pagesize == 0) 245 _elf_pagesize = PAGESIZE; 246 247 /* 248 * If mmap fails, try read. Some file systems don't mmap 249 */ 250 { 251 register size_t vmsz = sizeof (unsigned) * (REGNUM(sz) + 1); 252 253 if (vmsz % sizeof (Elf64) != 0) 254 vmsz += sizeof (Elf64) - vmsz % sizeof (Elf64); 255 if ((elf->ed_vm = (unsigned *)malloc(vmsz + sz)) == 0) { 256 _elf_seterr(EMEM_VM, errno); 257 return (OK_NO); 258 } 259 (void) memset(elf->ed_vm, 0, vmsz); 260 elf->ed_vmsz = vmsz / sizeof (unsigned); 261 elf->ed_image = elf->ed_ident = (char *)elf->ed_vm + vmsz; 262 elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz; 263 } 264 return (_elf_vm(elf, (size_t)0, (size_t)1)); 265 } 266 267 268 void 269 _elf_unmap(char *p, size_t sz) 270 { 271 if (p == 0 || sz == 0) 272 return; 273 (void) munmap(p, sz); 274 } 275