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