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