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