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