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 "%Z%%M% %I% %E% 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
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 */
75 static unsigned long _elf_pagesize = 0;
76 NOTE(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
86 Okay
_elf_vm(Elf * elf,size_t base,size_t sz)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
199 Okay
_elf_inmap(Elf * elf)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 if ((elf->ed_myflags & EDF_WRITE) == 0 &&
241 (p = mmap((char *)0, sz, PROT_READ,
242 MAP_PRIVATE, fd, (off_t)0)) != (char *)-1) {
243 elf->ed_image = elf->ed_ident = p;
244 elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz;
245 return (OK_YES);
246 }
247 }
248
249 if (_elf_pagesize == 0)
250 _elf_pagesize = PAGESIZE;
251
252 /*
253 * If mmap fails, try read. Some file systems don't mmap
254 */
255 {
256 register size_t vmsz = sizeof (unsigned) * (REGNUM(sz) + 1);
257
258 if (vmsz % sizeof (Elf64) != 0)
259 vmsz += sizeof (Elf64) - vmsz % sizeof (Elf64);
260 if ((elf->ed_vm = (unsigned *)malloc(vmsz + sz)) == 0) {
261 _elf_seterr(EMEM_VM, errno);
262 return (OK_NO);
263 }
264 (void) memset(elf->ed_vm, 0, vmsz);
265 elf->ed_vmsz = vmsz / sizeof (unsigned);
266 elf->ed_image = elf->ed_ident = (char *)elf->ed_vm + vmsz;
267 elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz;
268 }
269 return (_elf_vm(elf, (size_t)0, (size_t)1));
270 }
271
272
273 void
_elf_unmap(char * p,size_t sz)274 _elf_unmap(char *p, size_t sz)
275 {
276 if (p == 0 || sz == 0)
277 return;
278 (void) munmap(p, sz);
279 }
280