xref: /titanic_41/usr/src/cmd/sgs/libelf/common/getdata.c (revision 88f8b78a88cbdc6d8c1af5c3e54bc49d25095c98)
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 2004 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI" 	/* SVr4.0 1.16	*/
33 
34 
35 #pragma weak	elf_getdata = _elf_getdata
36 
37 
38 #include "syn.h"
39 #include <stdlib.h>
40 #include <assert.h>
41 #include <errno.h>
42 #include <libelf.h>
43 #include "decl.h"
44 #include "msg.h"
45 
46 
47 /*
48  * Convert data from file format to memory format.
49  */
50 
51 
52 static const size_t	align32[ELF_T_NUM] =
53 {
54 	1,			/* ELF_T_BYTE */
55 	sizeof (Elf32),		/* ELF_T_ADDR */
56 	sizeof (Elf32),		/* ELF_T_DYN */
57 	sizeof (Elf32),		/* ELF_T_EHDR */
58 	sizeof (Elf32_Half),	/* ELF_T_HALF */
59 	sizeof (Elf32),		/* ELF_T_OFF */
60 	sizeof (Elf32),		/* ELF_T_PHDR */
61 	sizeof (Elf32),		/* ELF_T_RELA */
62 	sizeof (Elf32),		/* ELF_T_REL */
63 	sizeof (Elf32),		/* ELF_T_SHDR */
64 	sizeof (Elf32),		/* ELF_T_SWORD */
65 	sizeof (Elf32),		/* ELF_T_SYM */
66 	sizeof (Elf32),		/* ELF_T_WORD */
67 	sizeof (Elf32),		/* ELF_T_VERDEF */
68 	sizeof (Elf32),		/* ELF_T_VERNEED */
69 	sizeof (Elf64_Sxword),	/* ELF_T_SXWORD */
70 	sizeof (Elf64),		/* ELF_T_XWORD */
71 	sizeof (Elf32_Half), 	/* ELF_T_SYMINFO */
72 	sizeof (Elf32),		/* ELF_T_NOTE */
73 	sizeof (Elf32_Lword),	/* ELF_T_MOVE */
74 	sizeof (Elf32_Lword),	/* ELF_T_MOVEP */
75 	sizeof (Elf32_Word)	/* ELF_T_CAP */
76 
77 };
78 
79 #define	Nalign32	(sizeof (align32)/sizeof (align32[0]))
80 
81 static const size_t	align64[ELF_T_NUM] =
82 {
83 	1,			/* ELF_T_BYTE */
84 	sizeof (Elf64),		/* ELF_T_ADDR */
85 	sizeof (Elf64),		/* ELF_T_DYN */
86 	sizeof (Elf64),		/* ELF_T_EHDR */
87 	sizeof (Elf64_Half),	/* ELF_T_HALF */
88 	sizeof (Elf64),		/* ELF_T_OFF */
89 	sizeof (Elf64),		/* ELF_T_PHDR */
90 	sizeof (Elf64),		/* ELF_T_RELA */
91 	sizeof (Elf64),		/* ELF_T_REL */
92 	sizeof (Elf64),		/* ELF_T_SHDR */
93 	sizeof (Elf64_Word),	/* ELF_T_SWORD */
94 	sizeof (Elf64),		/* ELF_T_SYM */
95 	sizeof (Elf64_Word),	/* ELF_T_WORD */
96 	sizeof (Elf64),		/* ELF_T_VDEF */
97 	sizeof (Elf64),		/* ELF_T_VNEED */
98 	sizeof (Elf64),		/* ELF_T_SXWORD */
99 	sizeof (Elf64),		/* ELF_T_XWORD */
100 	sizeof (Elf32_Half), 	/* ELF_T_SYMINFO */
101 	sizeof (Elf32),		/* ELF_T_NOTE */
102 	sizeof (Elf64),		/* ELF_T_MOVE */
103 	sizeof (Elf64),		/* ELF_T_MOVEP */
104 	sizeof (Elf64_Word)	/* ELF_T_CAP */
105 };
106 
107 #define	Nalign64	(sizeof (align64)/sizeof (align64[0]))
108 
109 
110 /*
111  * Could use an array indexed by ELFCLASS*, but I'd rather
112  * avoid .data over something this infrequently used.  The
113  * next choice would be to add extra conditionals.
114  */
115 #define	NALIGN(elf)	((elf->ed_class == ELFCLASS32) ? Nalign32 : Nalign64)
116 #define	ALIGN(elf)	((elf->ed_class == ELFCLASS32) ? align32 : align64)
117 
118 
119 Elf_Data *
120 _elf_locked_getdata(Elf_Scn * scn, Elf_Data * data)
121 {
122 	Dnode *		d = (Dnode *)data;
123 	Elf *		elf;
124 	Elf_Data	src;
125 	unsigned	work;
126 
127 	assert(!elf_threaded || RW_LOCK_HELD(&(scn->s_elf->ed_rwlock)));
128 	assert(!elf_threaded || MUTEX_HELD(&(scn->s_mutex)));
129 	elf = scn->s_elf;
130 
131 	if ((scn->s_myflags & SF_READY) == 0) {
132 		UPGRADELOCKS(elf, scn)
133 		/*
134 		 * make sure someone else didn't come along and cook
135 		 * this stuff.
136 		 */
137 		if ((scn->s_myflags & SF_READY) == 0)
138 			(void) _elf_cookscn(scn);
139 		DOWNGRADELOCKS(elf, scn)
140 	}
141 
142 	if (d == 0)
143 		d = scn->s_hdnode;
144 	else
145 		d = d->db_next;
146 
147 	if (scn->s_err != 0) {
148 		/*LINTED*/
149 		_elf_seterr((Msg)scn->s_err, 0);
150 		return (0);
151 	}
152 
153 	if (d == 0) {
154 		return (0);
155 	}
156 
157 	if (d->db_scn != scn) {
158 		_elf_seterr(EREQ_DATA, 0);
159 		return (0);
160 	}
161 
162 	if (d->db_myflags & DBF_READY) {
163 		return (&d->db_data);
164 	}
165 	elf = scn->s_elf;
166 
167 	/*
168 	 * Prepare return buffer.  The data comes from the memory
169 	 * image of the file.  "Empty" regions get an empty buffer.
170 	 *
171 	 * Only sections of an ELF_C_READ file can be not READY here.
172 	 * Furthermore, the input file must have been cooked or
173 	 * frozen by now.  Translate cooked files in place if possible.
174 	 */
175 
176 	ELFACCESSDATA(work, _elf_work)
177 	d->db_data.d_version = work;
178 	if ((d->db_off == 0) || (d->db_fsz == 0)) {
179 		d->db_myflags |= DBF_READY;
180 		return (&d->db_data);
181 	}
182 
183 	if (elf->ed_class == ELFCLASS32) {
184 		Elf32_Shdr	*sh = scn->s_shdr;
185 		size_t		sz = sh->sh_entsize;
186 		Elf_Type	t = d->db_data.d_type;
187 
188 		if ((t != ELF_T_BYTE) &&
189 		    (sz > 1) && (sz != elf32_fsize(t, 1, elf->ed_version))) {
190 			_elf_seterr(EFMT_ENTSZ, 0);
191 			return (0);
192 		}
193 	} else if (elf->ed_class == ELFCLASS64) {
194 		Elf64_Shdr	*sh = scn->s_shdr;
195 		Elf64_Xword	sz = sh->sh_entsize;
196 		Elf_Type	t = d->db_data.d_type;
197 
198 		if (t != ELF_T_BYTE && sz > 1 &&
199 		    sz != elf64_fsize(t, 1, elf->ed_version)) {
200 			_elf_seterr(EFMT_ENTSZ, 0);
201 			return (0);
202 		}
203 	} else {
204 		_elf_seterr(EREQ_CLASS, 0);
205 		return (0);
206 	}
207 
208 
209 	/*
210 	 * validate the region
211 	 */
212 
213 	if ((d->db_off < 0) || (d->db_off >= elf->ed_fsz) ||
214 	    (elf->ed_fsz - d->db_off < d->db_fsz)) {
215 		_elf_seterr(EFMT_DATA, 0);
216 		return (0);
217 	}
218 
219 	/*
220 	 * set up translation buffers and validate
221 	 */
222 
223 	src.d_buf = (Elf_Void *)(elf->ed_ident + d->db_off);
224 	src.d_size = d->db_fsz;
225 	src.d_type = d->db_data.d_type;
226 	src.d_version = elf->ed_version;
227 	if (elf->ed_vm) {
228 		UPGRADELOCKS(elf, scn)
229 		if (_elf_vm(elf, (size_t)d->db_off, d->db_fsz) != OK_YES) {
230 			DOWNGRADELOCKS(elf, scn)
231 			return (0);
232 		}
233 		DOWNGRADELOCKS(elf, scn)
234 	}
235 
236 	/*
237 	 * decide where to put destination
238 	 */
239 
240 	switch (elf->ed_status) {
241 	case ES_COOKED:
242 		if ((size_t)d->db_data.d_type >= NALIGN(elf)) {
243 			_elf_seterr(EBUG_COOKTYPE, 0);
244 			return (0);
245 		}
246 
247 		/*
248 		 * If the destination size (memory) is at least as
249 		 * big as the source size (file), reuse the space.
250 		 */
251 
252 		if ((d->db_data.d_size <= src.d_size) &&
253 		    (d->db_off % ALIGN(elf)[d->db_data.d_type] == 0)) {
254 			d->db_data.d_buf = (Elf_Void *)(elf->ed_ident +
255 				d->db_off);
256 			break;
257 		}
258 
259 		/*FALLTHRU*/
260 	case ES_FROZEN:
261 		if ((d->db_buf = malloc(d->db_data.d_size)) == 0) {
262 			_elf_seterr(EMEM_DATA, errno);
263 			return (0);
264 		}
265 		d->db_data.d_buf = d->db_buf;
266 		break;
267 
268 	default:
269 		_elf_seterr(EBUG_COOKSTAT, 0);
270 		return (0);
271 	}
272 
273 	if (elf->ed_class == ELFCLASS32) {
274 		if (elf32_xlatetom(&d->db_data, &src, elf->ed_encode) == 0)
275 			return (0);
276 	} else {	/* ELFCLASS64 */
277 		if (elf64_xlatetom(&d->db_data, &src, elf->ed_encode) == 0)
278 			return (0);
279 	}
280 	d->db_myflags |= DBF_READY;
281 
282 	return (&d->db_data);
283 }
284 
285 Elf_Data *
286 elf_getdata(Elf_Scn * scn, Elf_Data * data)
287 {
288 	Elf_Data *	rc;
289 	Elf *	elf;
290 
291 	/*
292 	 * trap null args, end of list, previous buffer.
293 	 * SHT_NULL sections have no buffer list, so they
294 	 * fall out here too.
295 	 */
296 	if (scn == 0)
297 		return (0);
298 
299 	elf = scn->s_elf;
300 	READLOCKS(elf, scn);
301 	rc = _elf_locked_getdata(scn, data);
302 	READUNLOCKS(elf, scn);
303 	return (rc);
304 }
305