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 /*	Copyright (c) 1988 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright (c) 1998 by Sun Microsystems, Inc.
28  * All rights reserved.
29  */
30 
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI" 	/* SVr4.0 1.6	*/
33 
34 #pragma weak	elf_getarsym = _elf_getarsym
35 
36 
37 #include "syn.h"
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <libelf.h>
41 #include "decl.h"
42 #include "msg.h"
43 
44 
45 /*
46  * Convert archive symbol table to memory format
47  *	This takes a pointer to file's archive symbol table,
48  *	alignment unconstrained.  Returns null terminated
49  *	vector of Elf_Arsym structures.
50  *
51  *	Symbol table is the following:
52  *		# offsets	4-byte word
53  *		offset[0...]	4-byte word each
54  *		strings		null-terminated, for offset[x]
55  */
56 
57 
58 #define	get4(p)	((((((p[0]<<8)+p[1])<<8)+p[2])<<8)+p[3])
59 
60 
61 static Elf_Void	*arsym	_((Byte *, size_t, size_t *));
62 
63 
64 Elf_Void *
65 arsym(Byte * off, size_t sz, size_t * e)
66 {
67 	char		*endstr = (char *)off + sz;
68 	register char	*str;
69 	Byte		*endoff;
70 	Elf_Void	*oas;
71 
72 	{
73 		register size_t	n;
74 
75 		if (sz < 4 || (sz - 4) / 4 < (n = get4(off))) {
76 			_elf_seterr(EFMT_ARSYMSZ, 0);
77 			return (0);
78 		}
79 		off += 4;
80 		endoff = off + n * 4;
81 
82 		/*
83 		 * string table must be present, null terminated
84 		 */
85 
86 		if (((str = (char *)endoff) >= endstr) ||
87 		    (*(endstr - 1) != '\0')) {
88 			_elf_seterr(EFMT_ARSYM, 0);
89 			return (0);
90 		}
91 
92 		/*
93 		 * overflow can occur here, but not likely
94 		 */
95 
96 		*e = n + 1;
97 		n = sizeof (Elf_Arsym) * (n + 1);
98 		if ((oas = malloc(n)) == 0) {
99 			_elf_seterr(EMEM_ARSYM, errno);
100 			return (0);
101 		}
102 	}
103 	{
104 		register Elf_Arsym	*as = (Elf_Arsym *)oas;
105 
106 		while (off < endoff) {
107 			if (str >= endstr) {
108 				_elf_seterr(EFMT_ARSYMSTR, 0);
109 				free(oas);
110 				return (0);
111 			}
112 			as->as_off = get4(off);
113 			as->as_name = str;
114 			as->as_hash = elf_hash(str);
115 			++as;
116 			off += 4;
117 			while (*str++ != '\0')
118 				/* LINTED */
119 				;
120 		}
121 		as->as_name = 0;
122 		as->as_off = 0;
123 		as->as_hash = ~(unsigned long)0L;
124 	}
125 	return (oas);
126 }
127 
128 
129 Elf_Arsym *
130 elf_getarsym(Elf * elf, size_t * ptr)
131 {
132 	Byte *		as;
133 	size_t		sz;
134 	Elf_Arsym *	rc;
135 
136 	if (ptr != 0)
137 		*ptr = 0;
138 	if (elf == 0)
139 		return (0);
140 	ELFRLOCK(elf);
141 	if (elf->ed_kind != ELF_K_AR) {
142 		ELFUNLOCK(elf);
143 		_elf_seterr(EREQ_AR, 0);
144 		return (0);
145 	}
146 	if ((as = (Byte *)elf->ed_arsym) == 0) {
147 		ELFUNLOCK(elf);
148 		return (0);
149 	}
150 	if (elf->ed_myflags & EDF_ASALLOC) {
151 		if (ptr != 0)
152 			*ptr = elf->ed_arsymsz;
153 		ELFUNLOCK(elf);
154 		/* LINTED */
155 		return ((Elf_Arsym *)as);
156 	}
157 	/*
158 	 * We're gonna need a write lock.
159 	 */
160 	ELFUNLOCK(elf)
161 	ELFWLOCK(elf)
162 	sz = elf->ed_arsymsz;
163 	if (_elf_vm(elf, (size_t)(as - (Byte *)elf->ed_ident), sz) !=
164 	    OK_YES) {
165 		ELFUNLOCK(elf);
166 		return (0);
167 	}
168 	if ((elf->ed_arsym = arsym(as, sz, &elf->ed_arsymsz)) == 0) {
169 		ELFUNLOCK(elf);
170 		return (0);
171 	}
172 	elf->ed_myflags |= EDF_ASALLOC;
173 	if (ptr != 0)
174 		*ptr = elf->ed_arsymsz;
175 	rc = (Elf_Arsym *)elf->ed_arsym;
176 	ELFUNLOCK(elf);
177 	return (rc);
178 }
179