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#pragma ident "@(#)input.c 1.19 08/05/31 SMI" 31 32#include <unistd.h> 33#include <stdlib.h> 34#include <memory.h> 35#include <errno.h> 36#include <sys/mman.h> 37#include <sys/param.h> 38#include <libelf.h> 39#include "decl.h" 40#include "msg.h" 41#include <string.h> 42 43/* 44 * File input 45 * These functions read input files. 46 * On SVR4 and newer systems use mmap(2). On older systems (or on 47 * file systems that don't support mmap, this code simulates mmap. 48 * When reading a file, enough memory is allocated to hold the file's 49 * image, and reads are delayed. When another part of the library 50 * wants to use a part of the file, it "fetches" the needed regions. 51 * 52 * An elf descriptor has a bit array to manage this. Each bit 53 * represents one "page" of the file. Pages are grouped into regions. 54 * The page size is tunable. Its value should be at least one disk 55 * block and small enough to avoid superfluous traffic. 56 * 57 * NBITS The number of bits in an unsigned. Each unsigned object 58 * holds a "REGION." A byte must have at least 8 bits; 59 * it may have more, though the extra bits at the top of 60 * the unsigned will be unused. Thus, for 9-bit bytes and 61 * 36-bit words, 4 bits at the top will stay empty. 62 * 63 * This mechanism gives significant performance gains for library 64 * handling (among other things), because programs typically don't 65 * need to look at entire libraries. The fastest I/O is no I/O. 66 */ 67 68/* 69 * This global is used to hold the value of the PAGESIZE macro. 70 * 71 * This is because the PAGESIZE macro actually calls the 72 * sysconfig(_CONFIG_PAGESIZE) system call and we don't want 73 * to repeatedly call this through out libelf. 74 */ 75static unsigned long _elf_pagesize = 0; 76NOTE(SCHEME_PROTECTS_DATA("read only data", _elf_pagesize)) 77 78 79#define NBITS (8 * sizeof (unsigned)) 80#define REGSZ (NBITS * _elf_pagesize) 81#define PGNUM(off) ((off % REGSZ) / _elf_pagesize) 82#define REGNUM(off) (off / REGSZ) 83 84 85 86Okay 87_elf_vm(Elf * elf, size_t base, size_t sz) 88{ 89 NOTE(ASSUMING_PROTECTED(*elf)) 90 register unsigned *hdreg, hdbit; 91 unsigned *tlreg, tlbit; 92 size_t tail; 93 off_t off; 94 Elf_Void *iop; 95 96 97 /* 98 * always validate region 99 */ 100 101 if ((base + sz) > elf->ed_fsz) { 102 /* 103 * range outside of file bounds. 104 */ 105 _elf_seterr(EFMT_VM, 0); 106 return (OK_NO); 107 } 108 109 /* 110 * If file is mmap()'d and/or the read size is 0 111 * their is nothing else for us to do. 112 */ 113 if (elf->ed_vm == 0 || sz == 0) 114 return (OK_YES); 115 /* 116 * This uses arithmetic instead of masking because 117 * sizeof (unsigned) might not be a power of 2. 118 * 119 * Tail gives one beyond the last offset that must be retrieved, 120 * NOT the last in the region. 121 */ 122 123 if (elf->ed_parent && elf->ed_parent->ed_fd == -1) 124 elf->ed_fd = -1; 125 126 base += elf->ed_baseoff; 127 tail = base + sz + _elf_pagesize - 1; 128 off = base - base % _elf_pagesize; 129 hdbit = 1 << PGNUM(base); 130 tlbit = 1 << PGNUM(tail); 131 hdreg = &elf->ed_vm[REGNUM(base)]; 132 tlreg = &elf->ed_vm[REGNUM(tail)]; 133 sz = 0; 134 135 /* 136 * Scan through the files 'page table' and make sure 137 * that all of the pages in the specified range have been 138 * loaded into memory. As the pages are loaded the appropriate 139 * bit in the 'page table' is set. 140 * 141 * Note: This loop will only read in those pages which havn't 142 * been previously loaded into memory, if the page is 143 * already present it will not be re-loaded. 144 */ 145 while ((hdreg != tlreg) || (hdbit != tlbit)) { 146 if (*hdreg & hdbit) { 147 if (sz != 0) { 148 /* 149 * Read in a 'chunk' of the elf image. 150 */ 151 iop = (Elf_Void *)(elf->ed_image + off); 152 /* 153 * do not read past the end of the file 154 */ 155 if (elf->ed_imagesz - off < sz) 156 sz = elf->ed_imagesz - off; 157 if ((lseek(elf->ed_fd, off, 158 SEEK_SET) != off) || 159 (read(elf->ed_fd, iop, sz) != sz)) { 160 _elf_seterr(EIO_VM, errno); 161 return (OK_NO); 162 } 163 off += sz; 164 sz = 0; 165 } 166 off += _elf_pagesize; 167 } else { 168 if (elf->ed_fd < 0) { 169 _elf_seterr(EREQ_NOFD, 0); 170 return (OK_NO); 171 } 172 sz += _elf_pagesize; 173 *hdreg |= hdbit; 174 } 175 if (hdbit == ((unsigned)1 << (NBITS - 1))) { 176 hdbit = 1; 177 ++hdreg; 178 } else 179 hdbit <<= 1; 180 } 181 182 if (sz != 0) { 183 iop = (Elf_Void *)(elf->ed_image + off); 184 /* 185 * do not read past the end of the file 186 */ 187 if ((elf->ed_imagesz - off) < sz) 188 sz = elf->ed_imagesz - off; 189 if ((lseek(elf->ed_fd, off, SEEK_SET) != off) || 190 (read(elf->ed_fd, iop, sz) != sz)) { 191 _elf_seterr(EIO_VM, errno); 192 return (OK_NO); 193 } 194 } 195 return (OK_YES); 196} 197 198 199Okay 200_elf_inmap(Elf * elf) 201{ 202 int fd = elf->ed_fd; 203 register size_t sz; 204 205 { 206 register off_t off = lseek(fd, (off_t)0, SEEK_END); 207 208 if (off == 0) 209 return (OK_YES); 210 211 if (off == -1) { 212 _elf_seterr(EIO_FSZ, errno); 213 return (OK_NO); 214 } 215 216 if ((sz = (size_t)off) != off) { 217 _elf_seterr(EIO_FBIG, 0); 218 return (OK_NO); 219 } 220 } 221 /* 222 * If the file is mapped, elf->ed_vm will stay null 223 * and elf->ed_image will need to be unmapped someday. 224 * If the file is read, elf->ed_vm and the file image 225 * are allocated together; free() elf->ed_vm. 226 * 227 * If the file can be written, disallow mmap. 228 * Otherwise, the input mapping and the output mapping 229 * can collide. Moreover, elf_update will truncate 230 * the file, possibly invalidating the input mapping. 231 * Disallowing input mmap forces the library to malloc 232 * and read the space, which will make output mmap safe. 233 * Using mmap for output reduces the swap space needed 234 * for the process, so that is given preference. 235 */ 236 237 { 238 register char *p; 239 240 /* The embedded build won't let us reprotect this memory with write 241 * permissions later unless we give it write permissions now 242 */ 243 if ((elf->ed_myflags & EDF_WRITE) == 0 && 244 (p = mmap((char *)0, sz, PROT_READ|PROT_WRITE, 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 276void 277_elf_unmap(char * p, size_t sz) 278{ 279 if (p == 0 || sz == 0) 280 return; 281 (void) munmap(p, sz); 282} 283