xref: /titanic_50/usr/src/cmd/sgs/libelf/common/begin.c (revision 0e42dee69ed771bf604dd1789fca9d77b5bbe302)
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 /*
23  *	Copyright (c) 1988 AT&T
24  *	All Rights Reserved
25  *
26  */
27 
28 /*
29  * Copyright (c) 1998 by Sun Microsystems, Inc.
30  * All rights reserved.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI" 	/* SVr4.0 1.13	*/
34 
35 #pragma weak	elf_begin = _elf_begin
36 #pragma weak	elf_memory = _elf_memory
37 
38 
39 #include "syn.h"
40 #include <ar.h>
41 #include <stdlib.h>
42 #include <memory.h>
43 #include <errno.h>
44 #include <libelf.h>
45 #include <sys/mman.h>
46 #include "decl.h"
47 #include "member.h"
48 #include "msg.h"
49 
50 static const char	armag[] = ARMAG;
51 
52 
53 /*
54  * Initialize archive member
55  */
56 Elf *
57 _elf_member(int fd, Elf * ref, unsigned flags)
58 {
59 	register Elf	*elf;
60 	Member		*mh;
61 	size_t		base;
62 
63 	if (ref->ed_nextoff >= ref->ed_fsz)
64 		return (0);
65 	if (ref->ed_fd == -1)		/* disabled */
66 		fd = -1;
67 	if (flags & EDF_WRITE) {
68 		_elf_seterr(EREQ_ARRDWR, 0);
69 		return (0);
70 	}
71 	if (ref->ed_fd != fd) {
72 		_elf_seterr(EREQ_ARMEMFD, 0);
73 		return (0);
74 	}
75 	if ((_elf_vm(ref, ref->ed_nextoff, sizeof (struct ar_hdr)) !=
76 	    OK_YES) || ((mh = _elf_armem(ref,
77 	    ref->ed_ident + ref->ed_nextoff, ref->ed_fsz)) == 0))
78 		return (0);
79 
80 	base = ref->ed_nextoff + sizeof (struct ar_hdr);
81 	if (ref->ed_fsz - base < mh->m_hdr.ar_size) {
82 		_elf_seterr(EFMT_ARMEMSZ, 0);
83 		return (0);
84 	}
85 	if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) {
86 		_elf_seterr(EMEM_ELF, errno);
87 		return (0);
88 	}
89 	++ref->ed_activ;
90 	elf->ed_parent = ref;
91 	elf->ed_fd = fd;
92 	elf->ed_myflags |= flags;
93 	elf->ed_armem = mh;
94 	elf->ed_fsz = mh->m_hdr.ar_size;
95 	elf->ed_baseoff = ref->ed_baseoff + base;
96 	elf->ed_memoff = base - mh->m_slide;
97 	elf->ed_siboff = base + elf->ed_fsz + (elf->ed_fsz & 1);
98 	ref->ed_nextoff = elf->ed_siboff;
99 	elf->ed_image = ref->ed_image;
100 	elf->ed_imagesz = ref->ed_imagesz;
101 	elf->ed_vm = ref->ed_vm;
102 	elf->ed_vmsz = ref->ed_vmsz;
103 	elf->ed_ident = ref->ed_ident + base - mh->m_slide;
104 
105 	/*
106 	 * If this member is the archive string table,
107 	 * we've already altered the bytes.
108 	 */
109 
110 	if (ref->ed_arstroff == ref->ed_nextoff)
111 		elf->ed_status = ES_COOKED;
112 	return (elf);
113 }
114 
115 
116 Elf *
117 _elf_regular(int fd, unsigned flags)		/* initialize regular file */
118 {
119 	Elf		*elf;
120 
121 	if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) {
122 		_elf_seterr(EMEM_ELF, errno);
123 		return (0);
124 	}
125 
126 	NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf))
127 	elf->ed_fd = fd;
128 	elf->ed_myflags |= flags;
129 	if (_elf_inmap(elf) != OK_YES) {
130 		free(elf);
131 		return (0);
132 	}
133 	NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf))
134 	return (elf);
135 }
136 
137 
138 Elf *
139 _elf_config(Elf * elf)
140 {
141 	char *		base;
142 	unsigned	encode;
143 
144 	ELFRWLOCKINIT(&elf->ed_rwlock);
145 
146 	/*
147 	 * Determine if this is a ELF file.
148 	 */
149 	base = elf->ed_ident;
150 	if ((elf->ed_fsz >= EI_NIDENT) &&
151 	    (_elf_vm(elf, (size_t)0, (size_t)EI_NIDENT) == OK_YES) &&
152 	    (base[EI_MAG0] == ELFMAG0) &&
153 	    (base[EI_MAG1] == ELFMAG1) &&
154 	    (base[EI_MAG2] == ELFMAG2) &&
155 	    (base[EI_MAG3] == ELFMAG3)) {
156 		elf->ed_kind = ELF_K_ELF;
157 		elf->ed_class = base[EI_CLASS];
158 		elf->ed_encode = base[EI_DATA];
159 		if ((elf->ed_version = base[EI_VERSION]) == 0)
160 			elf->ed_version = 1;
161 		elf->ed_identsz = EI_NIDENT;
162 
163 		/*
164 		 * Allow writing only if originally specified read only.
165 		 * This is only necessary if the file must be translating
166 		 * from one encoding to another.
167 		 */
168 		ELFACCESSDATA(encode, _elf_encode)
169 		if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) &&
170 		    (elf->ed_encode != encode)) {
171 			if (mprotect((char *)elf->ed_image, elf->ed_imagesz,
172 			    PROT_READ|PROT_WRITE) == -1) {
173 				_elf_seterr(EIO_VM, errno);
174 				return (0);
175 			}
176 		}
177 		return (elf);
178 	}
179 
180 	/*
181 	 * Determine if this is an Archive
182 	 */
183 	if ((elf->ed_fsz >= SARMAG) &&
184 	    (_elf_vm(elf, (size_t)0, (size_t)SARMAG) == OK_YES) &&
185 	    (memcmp(base, armag, SARMAG) == 0)) {
186 		_elf_arinit(elf);
187 		elf->ed_kind = ELF_K_AR;
188 		elf->ed_identsz = SARMAG;
189 		return (elf);
190 	}
191 
192 	/*
193 	 *	Return a few ident bytes, but not so many that
194 	 *	getident() must read a large file.  512 is arbitrary.
195 	 */
196 
197 	elf->ed_kind = ELF_K_NONE;
198 	if ((elf->ed_identsz = elf->ed_fsz) > 512)
199 		elf->ed_identsz = 512;
200 
201 	return (elf);
202 }
203 
204 Elf *
205 elf_memory(char * image, size_t sz)
206 {
207 	Elf		*elf;
208 	unsigned	work;
209 
210 	/*
211 	 * version() no called yet?
212 	 */
213 	ELFACCESSDATA(work, _elf_work)
214 	if (work == EV_NONE) {
215 		_elf_seterr(ESEQ_VER, 0);
216 		return (0);
217 	}
218 
219 	if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) {
220 		_elf_seterr(EMEM_ELF, errno);
221 		return (0);
222 	}
223 	NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf))
224 	elf->ed_fd = -1;
225 	elf->ed_myflags |= EDF_READ | EDF_MEMORY;
226 	elf->ed_image = elf->ed_ident = image;
227 	elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz;
228 	elf->ed_kind = ELF_K_ELF;
229 	elf->ed_class = image[EI_CLASS];
230 	elf->ed_encode = image[EI_DATA];
231 	if ((elf->ed_version = image[EI_VERSION]) == 0)
232 		elf->ed_version = 1;
233 	elf->ed_identsz = EI_NIDENT;
234 	elf->ed_activ = 1;
235 	elf = _elf_config(elf);
236 	NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf))
237 	return (elf);
238 }
239 
240 /*
241  * The following is a private interface between the linkers (ld & ld.so.1)
242  * and libelf.
243  *
244  * elf_begin(0, ELF_C_IMAGE, ref)
245  *	Return a new elf_descriptor which uses the memory image from
246  *	ref as the base image of the elf file.  Before this elf_begin()
247  *	is called an elf_update(ref, ELF_C_WRIMAGE) must have been
248  *	done to the ref elf descriptor.
249  *	The ELF_C_IMAGE is unique in that modificatino of the Elf structure
250  *	is illegal (no elf_new*()) but you can modify the actual
251  *	data image of the file in question.
252  *
253  *	When you are done processing this file you can then perform a
254  *	elf_end() on it.
255  *
256  *	NOTE: if an elf_update(ref, ELF_C_WRITE) is done on the ref Elf
257  *		descriptor then the memory image that the ELF_C_IMAGE
258  *		is using has been discarded.  The proper calling convention
259  *		for this is as follows:
260  *
261  *	elf1 = elf_begin(fd, ELF_C_WRITE, 0);
262  *	...
263  *	elf_update(elf1, ELF_C_WRIMAGE);	 build memory image
264  *	elf2 = elf_begin(0, ELF_C_IMAGE, elf1);
265  *	...
266  *	elf_end(elf2);
267  *	elf_updage(elf1, ELF_C_WRITE);		flush memory image to disk
268  *	elf_end(elf1);
269  *
270  *
271  * elf_begin(0, ELF_C_IMAGE, 0);
272  *	returns a pointer to an elf descriptor as if it were opened
273  *	with ELF_C_WRITE except that it has no file descriptor and it
274  *	will not create a file.  It's to be used with the command:
275  *
276  *		elf_update(elf, ELF_C_WRIMAGE)
277  *
278  *	which will build a memory image instead of a file image.
279  *	The memory image is allocated via dynamic memory (malloc) and
280  *	can be free with a subsequent call to
281  *
282  *		elf_update(elf, ELF_C_WRITE)
283  *
284  *	NOTE: that if elf_end(elf) is called it will not free the
285  *		memory image if it is still allocated.  It is then
286  *		the callers responsiblity to free it via a call
287  *		to free().
288  *
289  *	Here is a potential calling sequence for this interface:
290  *
291  *	elf1 = elf_begin(0, ELF_C_IMAGE, 0);
292  *	...
293  *	elf_update(elf1, ELF_C_WRIMAGE);	build memory image
294  *	elf2 = elf_begin(0, ELF_C_IMAGE, elf1);
295  *	...
296  *	image_ptr = elf32_getehdr(elf2);	get pointer to image
297  *	elf_end(elf2);
298  *	elf_end(elf1);
299  *	...
300  *	use image
301  *	...
302  *	free(image_ptr);
303  */
304 
305 Elf *
306 elf_begin(int fd, Elf_Cmd cmd, Elf *ref)
307 {
308 	register Elf	*elf;
309 	unsigned	work;
310 	unsigned	flags = 0;
311 
312 	ELFACCESSDATA(work, _elf_work)
313 	if (work == EV_NONE)	/* version() not called yet */
314 	{
315 		_elf_seterr(ESEQ_VER, 0);
316 		return (0);
317 	}
318 	switch (cmd) {
319 	default:
320 		_elf_seterr(EREQ_BEGIN, 0);
321 		return (0);
322 
323 	case ELF_C_NULL:
324 		return (0);
325 
326 	case ELF_C_IMAGE:
327 		if (ref) {
328 			char *	image;
329 			size_t	imagesz;
330 			ELFRLOCK(ref);
331 			if ((image = ref->ed_wrimage) == 0) {
332 				_elf_seterr(EREQ_NOWRIMAGE, 0);
333 				ELFUNLOCK(ref);
334 				return (0);
335 			}
336 			imagesz = ref->ed_wrimagesz;
337 			ELFUNLOCK(ref);
338 			return (elf_memory(image, imagesz));
339 		}
340 		/* FALLTHROUGH */
341 	case ELF_C_WRITE:
342 		if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) {
343 			_elf_seterr(EMEM_ELF, errno);
344 			return (0);
345 		}
346 		NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf))
347 		ELFRWLOCKINIT(&elf->ed_rwlock);
348 		elf->ed_fd = fd;
349 		elf->ed_activ = 1;
350 		elf->ed_myflags |= EDF_WRITE;
351 		if (cmd == ELF_C_IMAGE)
352 			elf->ed_myflags |= EDF_WRALLOC;
353 		NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf))
354 		return (elf);
355 	case ELF_C_RDWR:
356 		flags = EDF_WRITE | EDF_READ;
357 		break;
358 
359 	case ELF_C_READ:
360 		flags = EDF_READ;
361 		break;
362 	}
363 
364 	/*
365 	 *	A null ref asks for a new file
366 	 *	Non-null ref bumps the activation count
367 	 *		or gets next archive member
368 	 */
369 
370 	if (ref == 0) {
371 		if ((elf = _elf_regular(fd, flags)) == 0)
372 			return (0);
373 	} else {
374 		ELFWLOCK(ref);
375 		if ((ref->ed_myflags & flags) != flags) {
376 			_elf_seterr(EREQ_RDWR, 0);
377 			ELFUNLOCK(ref);
378 			return (0);
379 		}
380 		/*
381 		 * new activation ?
382 		 */
383 		if (ref->ed_kind != ELF_K_AR) {
384 			++ref->ed_activ;
385 			ELFUNLOCK(ref);
386 			return (ref);
387 		}
388 		if ((elf = _elf_member(fd, ref, flags)) == 0) {
389 			ELFUNLOCK(ref);
390 			return (0);
391 		}
392 		ELFUNLOCK(ref);
393 	}
394 
395 	NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf))
396 	elf->ed_activ = 1;
397 	elf = _elf_config(elf);
398 	NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf))
399 
400 	return (elf);
401 }
402