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