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