xref: /onnv-gate/usr/src/cmd/sgs/libelf/common/clscook.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*6812Sraf  * Common Development and Distribution License (the "License").
6*6812Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*6812Sraf 
22*6812Sraf /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*6812Sraf  * Use is subject to license terms.
25*6812Sraf  */
26*6812Sraf 
270Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate  * This stuff used to live in cook.c, but was moved out to
340Sstevel@tonic-gate  * facilitate dual (Elf32 and Elf64) compilation.  See block
350Sstevel@tonic-gate  * comment in cook.c for more info.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <string.h>
390Sstevel@tonic-gate #include <ar.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <errno.h>
420Sstevel@tonic-gate #include "decl.h"
430Sstevel@tonic-gate #include "member.h"
440Sstevel@tonic-gate #include "msg.h"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * This module is compiled twice, the second time having
480Sstevel@tonic-gate  * -D_ELF64 defined.  The following set of macros, along
490Sstevel@tonic-gate  * with machelf.h, represent the differences between the
500Sstevel@tonic-gate  * two compilations.  Be careful *not* to add any class-
510Sstevel@tonic-gate  * dependent code (anything that has elf32 or elf64 in the
520Sstevel@tonic-gate  * name) to this code without hiding it behind a switch-
530Sstevel@tonic-gate  * able macro like these.
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate #if	defined(_ELF64)
560Sstevel@tonic-gate #define	Snode		Snode64
570Sstevel@tonic-gate #define	ELFCLASS	ELFCLASS64
580Sstevel@tonic-gate #define	ElfField	Elf64
590Sstevel@tonic-gate #define	_elf_snode_init	_elf64_snode_init
600Sstevel@tonic-gate #define	_elf_prepscan	_elf64_prepscan
610Sstevel@tonic-gate #define	_elf_cookscn	_elf64_cookscn
620Sstevel@tonic-gate #define	_elf_mtype	_elf64_mtype
630Sstevel@tonic-gate #define	_elf_msize	_elf64_msize
640Sstevel@tonic-gate #define	elf_fsize	elf64_fsize
650Sstevel@tonic-gate #define	_elf_snode	_elf64_snode
660Sstevel@tonic-gate #define	_elf_ehdr	_elf64_ehdr
670Sstevel@tonic-gate #define	elf_xlatetom	elf64_xlatetom
680Sstevel@tonic-gate #define	_elf_phdr	_elf64_phdr
690Sstevel@tonic-gate #define	_elf_shdr	_elf64_shdr
700Sstevel@tonic-gate #define	_elf_prepscn	_elf64_prepscn
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #else  /* Elf32 */
730Sstevel@tonic-gate #define	Snode		Snode32
740Sstevel@tonic-gate #define	ELFCLASS	ELFCLASS32
750Sstevel@tonic-gate #define	ElfField	Elf32
760Sstevel@tonic-gate #define	_elf_snode_init	_elf32_snode_init
770Sstevel@tonic-gate #define	_elf_prepscan	_elf32_prepscan
780Sstevel@tonic-gate #define	_elf_cookscn	_elf32_cookscn
790Sstevel@tonic-gate #define	_elf_mtype	_elf32_mtype
800Sstevel@tonic-gate #define	_elf_msize	_elf32_msize
810Sstevel@tonic-gate #define	elf_fsize	elf32_fsize
820Sstevel@tonic-gate #define	_elf_snode	_elf32_snode
830Sstevel@tonic-gate #define	_elf_ehdr	_elf32_ehdr
840Sstevel@tonic-gate #define	elf_xlatetom	elf32_xlatetom
850Sstevel@tonic-gate #define	_elf_phdr	_elf32_phdr
860Sstevel@tonic-gate #define	_elf_shdr	_elf32_shdr
870Sstevel@tonic-gate #define	_elf_prepscn	_elf32_prepscn
880Sstevel@tonic-gate 
890Sstevel@tonic-gate #endif /* _ELF64 */
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static Okay
_elf_prepscn(Elf * elf,size_t cnt)930Sstevel@tonic-gate _elf_prepscn(Elf *elf, size_t cnt)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*elf))
960Sstevel@tonic-gate 	Elf_Scn *	s;
970Sstevel@tonic-gate 	Elf_Scn *	end;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	if (cnt == 0)
1000Sstevel@tonic-gate 		return (OK_YES);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	if ((s = malloc(cnt * sizeof (Elf_Scn))) == 0) {
1030Sstevel@tonic-gate 		_elf_seterr(EMEM_SCN, errno);
1040Sstevel@tonic-gate 		return (OK_NO);
1050Sstevel@tonic-gate 	}
1060Sstevel@tonic-gate 	NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*s))
1070Sstevel@tonic-gate 	elf->ed_scntabsz = cnt;
1080Sstevel@tonic-gate 	end = s + cnt;
1090Sstevel@tonic-gate 	elf->ed_hdscn = s;
1100Sstevel@tonic-gate 	do {
1110Sstevel@tonic-gate 		*s = _elf_snode_init.sb_scn;
1120Sstevel@tonic-gate 		s->s_elf = elf;
1130Sstevel@tonic-gate 		s->s_next = s + 1;
1140Sstevel@tonic-gate 		s->s_index = s - elf->ed_hdscn;
1150Sstevel@tonic-gate 		s->s_shdr = (Shdr*)s->s_elf->ed_shdr + s->s_index;
1160Sstevel@tonic-gate 		ELFMUTEXINIT(&s->s_mutex);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 		/*
1190Sstevel@tonic-gate 		 * Section has not yet been cooked!
1200Sstevel@tonic-gate 		 *
1210Sstevel@tonic-gate 		 * We don't cook a section until it's data is actually
1220Sstevel@tonic-gate 		 * referenced.
1230Sstevel@tonic-gate 		 */
1240Sstevel@tonic-gate 		s->s_myflags = 0;
1250Sstevel@tonic-gate 	} while (++s < end);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	elf->ed_tlscn = --s;
1280Sstevel@tonic-gate 	s->s_next = 0;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/*
1310Sstevel@tonic-gate 	 * Section index SHN_UNDEF (0) does not and cannot
1320Sstevel@tonic-gate 	 * have a data buffer.  Fix it here.  Also mark the
1330Sstevel@tonic-gate 	 * initial section as being allocated for the block
1340Sstevel@tonic-gate 	 */
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	s = elf->ed_hdscn;
1370Sstevel@tonic-gate 	s->s_myflags = SF_ALLOC;
1380Sstevel@tonic-gate 	s->s_hdnode = 0;
1390Sstevel@tonic-gate 	s->s_tlnode = 0;
1400Sstevel@tonic-gate 	NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*s))
1410Sstevel@tonic-gate 	return (OK_YES);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate Okay
_elf_cookscn(Elf_Scn * s)1460Sstevel@tonic-gate _elf_cookscn(Elf_Scn * s)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*s, *(s->s_elf)))
1490Sstevel@tonic-gate 	Elf *			elf;
1500Sstevel@tonic-gate 	Shdr *			sh;
1510Sstevel@tonic-gate 	register Dnode *	d = &s->s_dnode;
1520Sstevel@tonic-gate 	size_t			fsz, msz;
1530Sstevel@tonic-gate 	unsigned		work;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d))
1560Sstevel@tonic-gate 	s->s_hdnode = s->s_tlnode = d;
1570Sstevel@tonic-gate 	s->s_err = 0;
1580Sstevel@tonic-gate 	s->s_shflags = 0;
1590Sstevel@tonic-gate 	s->s_uflags = 0;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/*
1630Sstevel@tonic-gate 	 * Prepare d_data for inspection, but don't actually
1640Sstevel@tonic-gate 	 * translate data until needed.  Leave the READY
1650Sstevel@tonic-gate 	 * flag off.  NOBITS sections see zero size.
1660Sstevel@tonic-gate 	 */
1670Sstevel@tonic-gate 	elf = s->s_elf;
1680Sstevel@tonic-gate 	sh = s->s_shdr;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	d->db_scn = s;
1710Sstevel@tonic-gate 	d->db_off = sh->sh_offset;
1720Sstevel@tonic-gate 	d->db_data.d_align = sh->sh_addralign;
1730Sstevel@tonic-gate 	d->db_data.d_version = elf->ed_version;
1740Sstevel@tonic-gate 	ELFACCESSDATA(work, _elf_work)
1750Sstevel@tonic-gate 	d->db_data.d_type = _elf_mtype(elf, sh->sh_type, work);
1760Sstevel@tonic-gate 	d->db_data.d_buf = 0;
1770Sstevel@tonic-gate 	d->db_data.d_off = 0;
1780Sstevel@tonic-gate 	fsz = elf_fsize(d->db_data.d_type, 1, elf->ed_version);
1790Sstevel@tonic-gate 	msz = _elf_msize(d->db_data.d_type, elf->ed_version);
1800Sstevel@tonic-gate 	d->db_data.d_size = (sh->sh_size / fsz) * msz;
1810Sstevel@tonic-gate 	d->db_shsz = sh->sh_size;
1820Sstevel@tonic-gate 	d->db_raw = 0;
1830Sstevel@tonic-gate 	d->db_buf = 0;
1840Sstevel@tonic-gate 	d->db_uflags = 0;
1850Sstevel@tonic-gate 	d->db_myflags = 0;
1860Sstevel@tonic-gate 	d->db_next = 0;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	if (sh->sh_type != SHT_NOBITS)
1890Sstevel@tonic-gate 		d->db_fsz = sh->sh_size;
1900Sstevel@tonic-gate 	else
1910Sstevel@tonic-gate 		d->db_fsz = 0;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	s->s_myflags |= SF_READY;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d))
1960Sstevel@tonic-gate 	return (OK_YES);
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate Snode *
_elf_snode()2020Sstevel@tonic-gate _elf_snode()
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate 	register Snode	*s;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	if ((s = malloc(sizeof (Snode))) == 0) {
2070Sstevel@tonic-gate 		_elf_seterr(EMEM_SNODE, errno);
2080Sstevel@tonic-gate 		return (0);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	*s = _elf_snode_init;
2110Sstevel@tonic-gate 	ELFMUTEXINIT(&s->sb_scn.s_mutex);
2120Sstevel@tonic-gate 	s->sb_scn.s_myflags = SF_ALLOC | SF_READY;
2130Sstevel@tonic-gate 	s->sb_scn.s_shdr = &s->sb_shdr;
2140Sstevel@tonic-gate 	return (s);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate int
_elf_ehdr(Elf * elf,int inplace)2200Sstevel@tonic-gate _elf_ehdr(Elf * elf, int inplace)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*elf))
2230Sstevel@tonic-gate 	register size_t	fsz;		/* field size */
2240Sstevel@tonic-gate 	Elf_Data	dst, src;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	fsz = elf_fsize(ELF_T_EHDR, 1, elf->ed_version);
2270Sstevel@tonic-gate 	if (fsz > elf->ed_fsz) {
2280Sstevel@tonic-gate 		_elf_seterr(EFMT_EHDRSZ, 0);
2290Sstevel@tonic-gate 		return (-1);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 	if (inplace && (fsz >= sizeof (Ehdr))) {
2320Sstevel@tonic-gate 		/*
2330Sstevel@tonic-gate 		 * The translated Ehdr will fit over the original Ehdr.
2340Sstevel@tonic-gate 		 */
2350Sstevel@tonic-gate 		/* LINTED */
2360Sstevel@tonic-gate 		elf->ed_ehdr = (Ehdr *)elf->ed_ident;
2370Sstevel@tonic-gate 		elf->ed_status = ES_COOKED;
2380Sstevel@tonic-gate 	} else {
2390Sstevel@tonic-gate 		elf->ed_ehdr = malloc(sizeof (Ehdr));
2400Sstevel@tonic-gate 		if (elf->ed_ehdr == 0) {
2410Sstevel@tonic-gate 			_elf_seterr(EMEM_EHDR, errno);
2420Sstevel@tonic-gate 			return (-1);
2430Sstevel@tonic-gate 		}
2440Sstevel@tonic-gate 		elf->ed_myflags |= EDF_EHALLOC;
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * Memory size >= fsz, because otherwise the memory version
2490Sstevel@tonic-gate 	 * loses information and cannot accurately implement the
2500Sstevel@tonic-gate 	 * file.
2510Sstevel@tonic-gate 	 */
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	src.d_buf = (Elf_Void *)elf->ed_ident;
2540Sstevel@tonic-gate 	src.d_type = ELF_T_EHDR;
2550Sstevel@tonic-gate 	src.d_size = fsz;
2560Sstevel@tonic-gate 	src.d_version = elf->ed_version;
2570Sstevel@tonic-gate 	dst.d_buf = (Elf_Void *)elf->ed_ehdr;
2580Sstevel@tonic-gate 	dst.d_size = sizeof (Ehdr);
2590Sstevel@tonic-gate 	dst.d_version = EV_CURRENT;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if ((_elf_vm(elf, (size_t)0, fsz) != OK_YES) ||
2620Sstevel@tonic-gate 	    (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
2630Sstevel@tonic-gate 		if (elf->ed_myflags & EDF_EHALLOC) {
2640Sstevel@tonic-gate 			elf->ed_myflags &= ~EDF_EHALLOC;
2650Sstevel@tonic-gate 			free(elf->ed_ehdr);
2660Sstevel@tonic-gate 		}
2670Sstevel@tonic-gate 		elf->ed_ehdr = 0;
2680Sstevel@tonic-gate 		return (-1);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	if (((Ehdr*)elf->ed_ehdr)->e_ident[EI_CLASS] != ELFCLASS) {
2720Sstevel@tonic-gate 		_elf_seterr(EREQ_CLASS, 0);
2730Sstevel@tonic-gate 		if (elf->ed_myflags & EDF_EHALLOC) {
2740Sstevel@tonic-gate 			elf->ed_myflags &= ~EDF_EHALLOC;
2750Sstevel@tonic-gate 			free(elf->ed_ehdr);
2760Sstevel@tonic-gate 		}
2770Sstevel@tonic-gate 		elf->ed_ehdr = 0;
2780Sstevel@tonic-gate 		return (-1);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if (((Ehdr*)elf->ed_ehdr)->e_version != elf->ed_version) {
2820Sstevel@tonic-gate 		_elf_seterr(EFMT_VER2, 0);
2830Sstevel@tonic-gate 		if (elf->ed_myflags & EDF_EHALLOC) {
2840Sstevel@tonic-gate 			elf->ed_myflags &= ~EDF_EHALLOC;
2850Sstevel@tonic-gate 			free(elf->ed_ehdr);
2860Sstevel@tonic-gate 		}
2870Sstevel@tonic-gate 		elf->ed_ehdr = 0;
2880Sstevel@tonic-gate 		return (-1);
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	return (0);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate int
_elf_phdr(Elf * elf,int inplace)2970Sstevel@tonic-gate _elf_phdr(Elf * elf, int inplace)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*elf))
3000Sstevel@tonic-gate 	register size_t		fsz, msz;
3010Sstevel@tonic-gate 	Elf_Data		dst, src;
3020Sstevel@tonic-gate 	Ehdr *			eh = elf->ed_ehdr;	/* must be present */
3030Sstevel@tonic-gate 	unsigned		work;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	if (eh->e_phnum == 0)
3060Sstevel@tonic-gate 		return (0);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	fsz = elf_fsize(ELF_T_PHDR, 1, elf->ed_version);
3090Sstevel@tonic-gate 	if (eh->e_phentsize != fsz) {
3100Sstevel@tonic-gate 		_elf_seterr(EFMT_PHDRSZ, 0);
3110Sstevel@tonic-gate 		return (-1);
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	fsz *= eh->e_phnum;
3150Sstevel@tonic-gate 	ELFACCESSDATA(work, _elf_work)
3160Sstevel@tonic-gate 	msz = _elf_msize(ELF_T_PHDR, work) * eh->e_phnum;
3170Sstevel@tonic-gate 	if ((eh->e_phoff == 0) ||
3180Sstevel@tonic-gate 	    ((fsz + eh->e_phoff) > elf->ed_fsz)) {
3190Sstevel@tonic-gate 		_elf_seterr(EFMT_PHTAB, 0);
3200Sstevel@tonic-gate 		return (-1);
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	if (inplace && fsz >= msz && eh->e_phoff % sizeof (ElfField) == 0) {
3240Sstevel@tonic-gate 		elf->ed_phdr = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
3250Sstevel@tonic-gate 		elf->ed_status = ES_COOKED;
3260Sstevel@tonic-gate 	} else {
3270Sstevel@tonic-gate 		if ((elf->ed_phdr = malloc(msz)) == 0) {
3280Sstevel@tonic-gate 			_elf_seterr(EMEM_PHDR, errno);
3290Sstevel@tonic-gate 			return (-1);
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 		elf->ed_myflags |= EDF_PHALLOC;
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 	src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
3340Sstevel@tonic-gate 	src.d_type = ELF_T_PHDR;
3350Sstevel@tonic-gate 	src.d_size = fsz;
3360Sstevel@tonic-gate 	src.d_version = elf->ed_version;
3370Sstevel@tonic-gate 	dst.d_buf = elf->ed_phdr;
3380Sstevel@tonic-gate 	dst.d_size = msz;
3390Sstevel@tonic-gate 	dst.d_version = work;
3400Sstevel@tonic-gate 	if ((_elf_vm(elf, (size_t)eh->e_phoff, fsz) != OK_YES) ||
3410Sstevel@tonic-gate 	    (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
3420Sstevel@tonic-gate 		if (elf->ed_myflags & EDF_PHALLOC) {
3430Sstevel@tonic-gate 			elf->ed_myflags &= ~EDF_PHALLOC;
3440Sstevel@tonic-gate 			free(elf->ed_phdr);
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 		elf->ed_phdr = 0;
3470Sstevel@tonic-gate 		return (-1);
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate 	elf->ed_phdrsz = msz;
3500Sstevel@tonic-gate 	return (0);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate int
_elf_shdr(Elf * elf,int inplace)3560Sstevel@tonic-gate _elf_shdr(Elf * elf, int inplace)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*elf))
3590Sstevel@tonic-gate 	register size_t		fsz, msz;
3600Sstevel@tonic-gate 	size_t			scncnt;
3610Sstevel@tonic-gate 	Elf_Data		dst, src;
3620Sstevel@tonic-gate 	register Ehdr		*eh = elf->ed_ehdr;	/* must be present */
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	if ((eh->e_shnum == 0) && (eh->e_shoff == 0))
3650Sstevel@tonic-gate 		return (0);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	fsz = elf_fsize(ELF_T_SHDR, 1, elf->ed_version);
3680Sstevel@tonic-gate 	if (eh->e_shentsize != fsz) {
3690Sstevel@tonic-gate 		_elf_seterr(EFMT_SHDRSZ, 0);
3700Sstevel@tonic-gate 		return (-1);
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 	/*
3730Sstevel@tonic-gate 	 * If we are dealing with a file with 'extended section
3740Sstevel@tonic-gate 	 * indexes' - then we need to load the first section
3750Sstevel@tonic-gate 	 * header.  The actual section count is stored in
3760Sstevel@tonic-gate 	 * Shdr[0].sh_size.
3770Sstevel@tonic-gate 	 */
3780Sstevel@tonic-gate 	if ((scncnt = eh->e_shnum) == 0) {
3790Sstevel@tonic-gate 		Shdr	sh;
3800Sstevel@tonic-gate 		if ((eh->e_shoff == 0) ||
3810Sstevel@tonic-gate 		    (elf->ed_fsz <= eh->e_shoff) ||
3820Sstevel@tonic-gate 		    (elf->ed_fsz - eh->e_shoff < fsz)) {
3830Sstevel@tonic-gate 			_elf_seterr(EFMT_SHTAB, 0);
3840Sstevel@tonic-gate 			return (-1);
3850Sstevel@tonic-gate 		}
3860Sstevel@tonic-gate 		src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
3870Sstevel@tonic-gate 		src.d_type = ELF_T_SHDR;
3880Sstevel@tonic-gate 		src.d_size = fsz;
3890Sstevel@tonic-gate 		src.d_version = elf->ed_version;
3900Sstevel@tonic-gate 		dst.d_buf = (Elf_Void *)&sh;
3910Sstevel@tonic-gate 		dst.d_size = sizeof (Shdr);
3920Sstevel@tonic-gate 		dst.d_version = EV_CURRENT;
3930Sstevel@tonic-gate 		if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
3940Sstevel@tonic-gate 		    (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
3950Sstevel@tonic-gate 			return (-1);
3960Sstevel@tonic-gate 		}
3970Sstevel@tonic-gate 		scncnt = sh.sh_size;
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	fsz *= scncnt;
4010Sstevel@tonic-gate 	msz = scncnt * sizeof (Shdr);
4020Sstevel@tonic-gate 	if ((eh->e_shoff == 0) ||
4030Sstevel@tonic-gate 	    (elf->ed_fsz <= eh->e_shoff) ||
4040Sstevel@tonic-gate 	    (elf->ed_fsz - eh->e_shoff < fsz)) {
4050Sstevel@tonic-gate 		_elf_seterr(EFMT_SHTAB, 0);
4060Sstevel@tonic-gate 		return (-1);
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	if (inplace && (fsz >= msz) &&
4100Sstevel@tonic-gate 	    ((eh->e_shoff % sizeof (ElfField)) == 0)) {
4110Sstevel@tonic-gate 		/* LINTED */
4120Sstevel@tonic-gate 		elf->ed_shdr = (Shdr *)(elf->ed_ident + eh->e_shoff);
4130Sstevel@tonic-gate 		elf->ed_status = ES_COOKED;
4140Sstevel@tonic-gate 	} else {
4150Sstevel@tonic-gate 		if ((elf->ed_shdr = malloc(msz)) == 0) {
4160Sstevel@tonic-gate 			_elf_seterr(EMEM_SHDR, errno);
4170Sstevel@tonic-gate 			return (-1);
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 		elf->ed_myflags |= EDF_SHALLOC;
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 	src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
4220Sstevel@tonic-gate 	src.d_type = ELF_T_SHDR;
4230Sstevel@tonic-gate 	src.d_size = fsz;
4240Sstevel@tonic-gate 	src.d_version = elf->ed_version;
4250Sstevel@tonic-gate 	dst.d_buf = (Elf_Void *)elf->ed_shdr;
4260Sstevel@tonic-gate 	dst.d_size = msz;
4270Sstevel@tonic-gate 	dst.d_version = EV_CURRENT;
4280Sstevel@tonic-gate 	if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
4290Sstevel@tonic-gate 	    (elf_xlatetom(&dst, &src, elf->ed_encode) == 0) ||
4300Sstevel@tonic-gate 	    (_elf_prepscn(elf, scncnt) != OK_YES)) {
4310Sstevel@tonic-gate 		if (elf->ed_myflags & EDF_SHALLOC) {
4320Sstevel@tonic-gate 			elf->ed_myflags &= ~EDF_SHALLOC;
4330Sstevel@tonic-gate 			free(elf->ed_shdr);
4340Sstevel@tonic-gate 		}
4350Sstevel@tonic-gate 		elf->ed_shdr = 0;
4360Sstevel@tonic-gate 		return (-1);
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 	return (0);
4390Sstevel@tonic-gate }
440