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
_elf_vm(Elf * elf,size_t base,size_t sz)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
_elf_inmap(Elf * elf)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
_elf_unmap(char * p,size_t sz)269 _elf_unmap(char *p, size_t sz)
270 {
271 if (p == 0 || sz == 0)
272 return;
273 (void) munmap(p, sz);
274 }
275