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 /*
33 * This stuff used to live in cook.c, but was moved out to
34 * facilitate dual (Elf32 and Elf64) compilation. See block
35 * comment in cook.c for more info.
36 */
37
38 #include <string.h>
39 #include <ar.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include "decl.h"
43 #include "member.h"
44 #include "msg.h"
45
46 /*
47 * This module is compiled twice, the second time having
48 * -D_ELF64 defined. The following set of macros, along
49 * with machelf.h, represent the differences between the
50 * two compilations. Be careful *not* to add any class-
51 * dependent code (anything that has elf32 or elf64 in the
52 * name) to this code without hiding it behind a switch-
53 * able macro like these.
54 */
55 #if defined(_ELF64)
56 #define Snode Snode64
57 #define ELFCLASS ELFCLASS64
58 #define ElfField Elf64
59 #define _elf_snode_init _elf64_snode_init
60 #define _elf_prepscan _elf64_prepscan
61 #define _elf_cookscn _elf64_cookscn
62 #define _elf_mtype _elf64_mtype
63 #define _elf_msize _elf64_msize
64 #define elf_fsize elf64_fsize
65 #define _elf_snode _elf64_snode
66 #define _elf_ehdr _elf64_ehdr
67 #define elf_xlatetom elf64_xlatetom
68 #define _elf_phdr _elf64_phdr
69 #define _elf_shdr _elf64_shdr
70 #define _elf_prepscn _elf64_prepscn
71
72 #else /* Elf32 */
73 #define Snode Snode32
74 #define ELFCLASS ELFCLASS32
75 #define ElfField Elf32
76 #define _elf_snode_init _elf32_snode_init
77 #define _elf_prepscan _elf32_prepscan
78 #define _elf_cookscn _elf32_cookscn
79 #define _elf_mtype _elf32_mtype
80 #define _elf_msize _elf32_msize
81 #define elf_fsize elf32_fsize
82 #define _elf_snode _elf32_snode
83 #define _elf_ehdr _elf32_ehdr
84 #define elf_xlatetom elf32_xlatetom
85 #define _elf_phdr _elf32_phdr
86 #define _elf_shdr _elf32_shdr
87 #define _elf_prepscn _elf32_prepscn
88
89 #endif /* _ELF64 */
90
91
92 static Okay
_elf_prepscn(Elf * elf,size_t cnt)93 _elf_prepscn(Elf *elf, size_t cnt)
94 {
95 NOTE(ASSUMING_PROTECTED(*elf))
96 Elf_Scn * s;
97 Elf_Scn * end;
98
99 if (cnt == 0)
100 return (OK_YES);
101
102 if ((s = malloc(cnt * sizeof (Elf_Scn))) == 0) {
103 _elf_seterr(EMEM_SCN, errno);
104 return (OK_NO);
105 }
106 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*s))
107 elf->ed_scntabsz = cnt;
108 end = s + cnt;
109 elf->ed_hdscn = s;
110 do {
111 *s = _elf_snode_init.sb_scn;
112 s->s_elf = elf;
113 s->s_next = s + 1;
114 s->s_index = s - elf->ed_hdscn;
115 s->s_shdr = (Shdr*)s->s_elf->ed_shdr + s->s_index;
116 ELFMUTEXINIT(&s->s_mutex);
117
118 /*
119 * Section has not yet been cooked!
120 *
121 * We don't cook a section until it's data is actually
122 * referenced.
123 */
124 s->s_myflags = 0;
125 } while (++s < end);
126
127 elf->ed_tlscn = --s;
128 s->s_next = 0;
129
130 /*
131 * Section index SHN_UNDEF (0) does not and cannot
132 * have a data buffer. Fix it here. Also mark the
133 * initial section as being allocated for the block
134 */
135
136 s = elf->ed_hdscn;
137 s->s_myflags = SF_ALLOC;
138 s->s_hdnode = 0;
139 s->s_tlnode = 0;
140 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*s))
141 return (OK_YES);
142 }
143
144
145 Okay
_elf_cookscn(Elf_Scn * s)146 _elf_cookscn(Elf_Scn * s)
147 {
148 NOTE(ASSUMING_PROTECTED(*s, *(s->s_elf)))
149 Elf * elf;
150 Shdr * sh;
151 register Dnode * d = &s->s_dnode;
152 size_t fsz, msz;
153 unsigned work;
154
155 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d))
156 s->s_hdnode = s->s_tlnode = d;
157 s->s_err = 0;
158 s->s_shflags = 0;
159 s->s_uflags = 0;
160
161
162 /*
163 * Prepare d_data for inspection, but don't actually
164 * translate data until needed. Leave the READY
165 * flag off. NOBITS sections see zero size.
166 */
167 elf = s->s_elf;
168 sh = s->s_shdr;
169
170 d->db_scn = s;
171 d->db_off = sh->sh_offset;
172 d->db_data.d_align = sh->sh_addralign;
173 d->db_data.d_version = elf->ed_version;
174 ELFACCESSDATA(work, _elf_work)
175 d->db_data.d_type = _elf_mtype(elf, sh->sh_type, work);
176 d->db_data.d_buf = 0;
177 d->db_data.d_off = 0;
178 fsz = elf_fsize(d->db_data.d_type, 1, elf->ed_version);
179 msz = _elf_msize(d->db_data.d_type, elf->ed_version);
180 d->db_data.d_size = (sh->sh_size / fsz) * msz;
181 d->db_shsz = sh->sh_size;
182 d->db_raw = 0;
183 d->db_buf = 0;
184 d->db_uflags = 0;
185 d->db_myflags = 0;
186 d->db_next = 0;
187
188 if (sh->sh_type != SHT_NOBITS)
189 d->db_fsz = sh->sh_size;
190 else
191 d->db_fsz = 0;
192
193 s->s_myflags |= SF_READY;
194
195 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d))
196 return (OK_YES);
197 }
198
199
200
201 Snode *
_elf_snode()202 _elf_snode()
203 {
204 register Snode *s;
205
206 if ((s = malloc(sizeof (Snode))) == 0) {
207 _elf_seterr(EMEM_SNODE, errno);
208 return (0);
209 }
210 *s = _elf_snode_init;
211 ELFMUTEXINIT(&s->sb_scn.s_mutex);
212 s->sb_scn.s_myflags = SF_ALLOC | SF_READY;
213 s->sb_scn.s_shdr = &s->sb_shdr;
214 return (s);
215 }
216
217
218
219 int
_elf_ehdr(Elf * elf,int inplace)220 _elf_ehdr(Elf * elf, int inplace)
221 {
222 NOTE(ASSUMING_PROTECTED(*elf))
223 register size_t fsz; /* field size */
224 Elf_Data dst, src;
225
226 fsz = elf_fsize(ELF_T_EHDR, 1, elf->ed_version);
227 if (fsz > elf->ed_fsz) {
228 _elf_seterr(EFMT_EHDRSZ, 0);
229 return (-1);
230 }
231 if (inplace && (fsz >= sizeof (Ehdr))) {
232 /*
233 * The translated Ehdr will fit over the original Ehdr.
234 */
235 /* LINTED */
236 elf->ed_ehdr = (Ehdr *)elf->ed_ident;
237 elf->ed_status = ES_COOKED;
238 } else {
239 elf->ed_ehdr = malloc(sizeof (Ehdr));
240 if (elf->ed_ehdr == 0) {
241 _elf_seterr(EMEM_EHDR, errno);
242 return (-1);
243 }
244 elf->ed_myflags |= EDF_EHALLOC;
245 }
246
247 /*
248 * Memory size >= fsz, because otherwise the memory version
249 * loses information and cannot accurately implement the
250 * file.
251 */
252
253 src.d_buf = (Elf_Void *)elf->ed_ident;
254 src.d_type = ELF_T_EHDR;
255 src.d_size = fsz;
256 src.d_version = elf->ed_version;
257 dst.d_buf = (Elf_Void *)elf->ed_ehdr;
258 dst.d_size = sizeof (Ehdr);
259 dst.d_version = EV_CURRENT;
260
261 if ((_elf_vm(elf, (size_t)0, fsz) != OK_YES) ||
262 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
263 if (elf->ed_myflags & EDF_EHALLOC) {
264 elf->ed_myflags &= ~EDF_EHALLOC;
265 free(elf->ed_ehdr);
266 }
267 elf->ed_ehdr = 0;
268 return (-1);
269 }
270
271 if (((Ehdr*)elf->ed_ehdr)->e_ident[EI_CLASS] != ELFCLASS) {
272 _elf_seterr(EREQ_CLASS, 0);
273 if (elf->ed_myflags & EDF_EHALLOC) {
274 elf->ed_myflags &= ~EDF_EHALLOC;
275 free(elf->ed_ehdr);
276 }
277 elf->ed_ehdr = 0;
278 return (-1);
279 }
280
281 if (((Ehdr*)elf->ed_ehdr)->e_version != elf->ed_version) {
282 _elf_seterr(EFMT_VER2, 0);
283 if (elf->ed_myflags & EDF_EHALLOC) {
284 elf->ed_myflags &= ~EDF_EHALLOC;
285 free(elf->ed_ehdr);
286 }
287 elf->ed_ehdr = 0;
288 return (-1);
289 }
290
291 return (0);
292 }
293
294
295
296 int
_elf_phdr(Elf * elf,int inplace)297 _elf_phdr(Elf * elf, int inplace)
298 {
299 NOTE(ASSUMING_PROTECTED(*elf))
300 register size_t fsz, msz;
301 Elf_Data dst, src;
302 Ehdr * eh = elf->ed_ehdr; /* must be present */
303 unsigned work;
304
305 if (eh->e_phnum == 0)
306 return (0);
307
308 fsz = elf_fsize(ELF_T_PHDR, 1, elf->ed_version);
309 if (eh->e_phentsize != fsz) {
310 _elf_seterr(EFMT_PHDRSZ, 0);
311 return (-1);
312 }
313
314 fsz *= eh->e_phnum;
315 ELFACCESSDATA(work, _elf_work)
316 msz = _elf_msize(ELF_T_PHDR, work) * eh->e_phnum;
317 if ((eh->e_phoff == 0) ||
318 ((fsz + eh->e_phoff) > elf->ed_fsz)) {
319 _elf_seterr(EFMT_PHTAB, 0);
320 return (-1);
321 }
322
323 if (inplace && fsz >= msz && eh->e_phoff % sizeof (ElfField) == 0) {
324 elf->ed_phdr = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
325 elf->ed_status = ES_COOKED;
326 } else {
327 if ((elf->ed_phdr = malloc(msz)) == 0) {
328 _elf_seterr(EMEM_PHDR, errno);
329 return (-1);
330 }
331 elf->ed_myflags |= EDF_PHALLOC;
332 }
333 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
334 src.d_type = ELF_T_PHDR;
335 src.d_size = fsz;
336 src.d_version = elf->ed_version;
337 dst.d_buf = elf->ed_phdr;
338 dst.d_size = msz;
339 dst.d_version = work;
340 if ((_elf_vm(elf, (size_t)eh->e_phoff, fsz) != OK_YES) ||
341 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
342 if (elf->ed_myflags & EDF_PHALLOC) {
343 elf->ed_myflags &= ~EDF_PHALLOC;
344 free(elf->ed_phdr);
345 }
346 elf->ed_phdr = 0;
347 return (-1);
348 }
349 elf->ed_phdrsz = msz;
350 return (0);
351 }
352
353
354
355 int
_elf_shdr(Elf * elf,int inplace)356 _elf_shdr(Elf * elf, int inplace)
357 {
358 NOTE(ASSUMING_PROTECTED(*elf))
359 register size_t fsz, msz;
360 size_t scncnt;
361 Elf_Data dst, src;
362 register Ehdr *eh = elf->ed_ehdr; /* must be present */
363
364 if ((eh->e_shnum == 0) && (eh->e_shoff == 0))
365 return (0);
366
367 fsz = elf_fsize(ELF_T_SHDR, 1, elf->ed_version);
368 if (eh->e_shentsize != fsz) {
369 _elf_seterr(EFMT_SHDRSZ, 0);
370 return (-1);
371 }
372 /*
373 * If we are dealing with a file with 'extended section
374 * indexes' - then we need to load the first section
375 * header. The actual section count is stored in
376 * Shdr[0].sh_size.
377 */
378 if ((scncnt = eh->e_shnum) == 0) {
379 Shdr sh;
380 if ((eh->e_shoff == 0) ||
381 (elf->ed_fsz <= eh->e_shoff) ||
382 (elf->ed_fsz - eh->e_shoff < fsz)) {
383 _elf_seterr(EFMT_SHTAB, 0);
384 return (-1);
385 }
386 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
387 src.d_type = ELF_T_SHDR;
388 src.d_size = fsz;
389 src.d_version = elf->ed_version;
390 dst.d_buf = (Elf_Void *)&sh;
391 dst.d_size = sizeof (Shdr);
392 dst.d_version = EV_CURRENT;
393 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
394 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
395 return (-1);
396 }
397 scncnt = sh.sh_size;
398 }
399
400 fsz *= scncnt;
401 msz = scncnt * sizeof (Shdr);
402 if ((eh->e_shoff == 0) ||
403 (elf->ed_fsz <= eh->e_shoff) ||
404 (elf->ed_fsz - eh->e_shoff < fsz)) {
405 _elf_seterr(EFMT_SHTAB, 0);
406 return (-1);
407 }
408
409 if (inplace && (fsz >= msz) &&
410 ((eh->e_shoff % sizeof (ElfField)) == 0)) {
411 /* LINTED */
412 elf->ed_shdr = (Shdr *)(elf->ed_ident + eh->e_shoff);
413 elf->ed_status = ES_COOKED;
414 } else {
415 if ((elf->ed_shdr = malloc(msz)) == 0) {
416 _elf_seterr(EMEM_SHDR, errno);
417 return (-1);
418 }
419 elf->ed_myflags |= EDF_SHALLOC;
420 }
421 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
422 src.d_type = ELF_T_SHDR;
423 src.d_size = fsz;
424 src.d_version = elf->ed_version;
425 dst.d_buf = (Elf_Void *)elf->ed_shdr;
426 dst.d_size = msz;
427 dst.d_version = EV_CURRENT;
428 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
429 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0) ||
430 (_elf_prepscn(elf, scncnt) != OK_YES)) {
431 if (elf->ed_myflags & EDF_SHALLOC) {
432 elf->ed_myflags &= ~EDF_SHALLOC;
433 free(elf->ed_shdr);
434 }
435 elf->ed_shdr = 0;
436 return (-1);
437 }
438 return (0);
439 }
440