xref: /freebsd/contrib/elftoolchain/libelf/elf_update.c (revision d003e0d7fe0d3a9b4b2c5835bb3f0f6faf3ab538)
12de3b87aSKai Wang /*-
22de3b87aSKai Wang  * Copyright (c) 2006-2011 Joseph Koshy
32de3b87aSKai Wang  * All rights reserved.
42de3b87aSKai Wang  *
52de3b87aSKai Wang  * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang  * modification, are permitted provided that the following conditions
72de3b87aSKai Wang  * are met:
82de3b87aSKai Wang  * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang  * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang  *    documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang  *
142de3b87aSKai Wang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152de3b87aSKai Wang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang  * SUCH DAMAGE.
252de3b87aSKai Wang  */
262de3b87aSKai Wang 
272de3b87aSKai Wang #include <sys/param.h>
282de3b87aSKai Wang #include <sys/stat.h>
292de3b87aSKai Wang 
302de3b87aSKai Wang #include <assert.h>
312de3b87aSKai Wang #include <errno.h>
322de3b87aSKai Wang #include <gelf.h>
332de3b87aSKai Wang #include <libelf.h>
342de3b87aSKai Wang #include <stdlib.h>
352de3b87aSKai Wang #include <string.h>
362de3b87aSKai Wang #include <unistd.h>
372de3b87aSKai Wang 
382de3b87aSKai Wang #include "_libelf.h"
392de3b87aSKai Wang 
402de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
412de3b87aSKai Wang #include <sys/mman.h>
422de3b87aSKai Wang #endif
432de3b87aSKai Wang 
44*d003e0d7SEd Maste ELFTC_VCSID("$Id: elf_update.c 3763 2019-06-28 21:43:27Z emaste $");
452de3b87aSKai Wang 
462de3b87aSKai Wang /*
472de3b87aSKai Wang  * Layout strategy:
482de3b87aSKai Wang  *
492de3b87aSKai Wang  * - Case 1: ELF_F_LAYOUT is asserted
502de3b87aSKai Wang  *     In this case the application has full control over where the
512de3b87aSKai Wang  *     section header table, program header table, and section data
522de3b87aSKai Wang  *     will reside.   The library only perform error checks.
532de3b87aSKai Wang  *
542de3b87aSKai Wang  * - Case 2: ELF_F_LAYOUT is not asserted
552de3b87aSKai Wang  *
562de3b87aSKai Wang  *     The library will do the object layout using the following
572de3b87aSKai Wang  *     ordering:
582de3b87aSKai Wang  *     - The executable header is placed first, are required by the
592de3b87aSKai Wang  *     	 ELF specification.
602de3b87aSKai Wang  *     - The program header table is placed immediately following the
612de3b87aSKai Wang  *       executable header.
622de3b87aSKai Wang  *     - Section data, if any, is placed after the program header
632de3b87aSKai Wang  *       table, aligned appropriately.
642de3b87aSKai Wang  *     - The section header table, if needed, is placed last.
652de3b87aSKai Wang  *
662de3b87aSKai Wang  *     There are two sub-cases to be taken care of:
672de3b87aSKai Wang  *
682de3b87aSKai Wang  *     - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR
692de3b87aSKai Wang  *
702de3b87aSKai Wang  *       In this sub-case, the underlying ELF object may already have
712de3b87aSKai Wang  *       content in it, which the application may have modified.  The
722de3b87aSKai Wang  *       library will retrieve content from the existing object as
732de3b87aSKai Wang  *       needed.
742de3b87aSKai Wang  *
752de3b87aSKai Wang  *     - Case 2b: e->e_cmd == ELF_C_WRITE
762de3b87aSKai Wang  *
772de3b87aSKai Wang  *       The ELF object is being created afresh in this sub-case;
782de3b87aSKai Wang  *       there is no pre-existing content in the underlying ELF
792de3b87aSKai Wang  *       object.
802de3b87aSKai Wang  */
812de3b87aSKai Wang 
822de3b87aSKai Wang /*
832de3b87aSKai Wang  * The types of extents in an ELF object.
842de3b87aSKai Wang  */
852de3b87aSKai Wang enum elf_extent {
862de3b87aSKai Wang 	ELF_EXTENT_EHDR,
872de3b87aSKai Wang 	ELF_EXTENT_PHDR,
882de3b87aSKai Wang 	ELF_EXTENT_SECTION,
892de3b87aSKai Wang 	ELF_EXTENT_SHDR
902de3b87aSKai Wang };
912de3b87aSKai Wang 
922de3b87aSKai Wang /*
932de3b87aSKai Wang  * A extent descriptor, used when laying out an ELF object.
942de3b87aSKai Wang  */
952de3b87aSKai Wang struct _Elf_Extent {
962de3b87aSKai Wang 	SLIST_ENTRY(_Elf_Extent) ex_next;
972de3b87aSKai Wang 	uint64_t	ex_start; /* Start of the region. */
982de3b87aSKai Wang 	uint64_t	ex_size;  /* The size of the region. */
992de3b87aSKai Wang 	enum elf_extent	ex_type;  /* Type of region. */
1002de3b87aSKai Wang 	void		*ex_desc; /* Associated descriptor. */
1012de3b87aSKai Wang };
1022de3b87aSKai Wang 
1032de3b87aSKai Wang SLIST_HEAD(_Elf_Extent_List, _Elf_Extent);
1042de3b87aSKai Wang 
1052de3b87aSKai Wang /*
1062de3b87aSKai Wang  * Compute the extents of a section, by looking at the data
1072de3b87aSKai Wang  * descriptors associated with it.  The function returns 1
1082de3b87aSKai Wang  * if successful, or zero if an error was detected.
1092de3b87aSKai Wang  */
1102de3b87aSKai Wang static int
_libelf_compute_section_extents(Elf * e,Elf_Scn * s,off_t rc)1112de3b87aSKai Wang _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
1122de3b87aSKai Wang {
1132de3b87aSKai Wang 	Elf_Data *d;
1142de3b87aSKai Wang 	size_t fsz, msz;
115cf781b2eSEd Maste 	int ec, elftype;
1162de3b87aSKai Wang 	uint32_t sh_type;
1172de3b87aSKai Wang 	uint64_t d_align;
1182de3b87aSKai Wang 	Elf32_Shdr *shdr32;
1192de3b87aSKai Wang 	Elf64_Shdr *shdr64;
1202de3b87aSKai Wang 	struct _Libelf_Data *ld;
1212de3b87aSKai Wang 	uint64_t scn_size, scn_alignment;
1222de3b87aSKai Wang 	uint64_t sh_align, sh_entsize, sh_offset, sh_size;
1232de3b87aSKai Wang 
1242de3b87aSKai Wang 	ec = e->e_class;
1252de3b87aSKai Wang 
1262de3b87aSKai Wang 	shdr32 = &s->s_shdr.s_shdr32;
1272de3b87aSKai Wang 	shdr64 = &s->s_shdr.s_shdr64;
1282de3b87aSKai Wang 	if (ec == ELFCLASS32) {
1292de3b87aSKai Wang 		sh_type    = shdr32->sh_type;
1302de3b87aSKai Wang 		sh_align   = (uint64_t) shdr32->sh_addralign;
1312de3b87aSKai Wang 		sh_entsize = (uint64_t) shdr32->sh_entsize;
1322de3b87aSKai Wang 		sh_offset  = (uint64_t) shdr32->sh_offset;
1332de3b87aSKai Wang 		sh_size    = (uint64_t) shdr32->sh_size;
1342de3b87aSKai Wang 	} else {
1352de3b87aSKai Wang 		sh_type    = shdr64->sh_type;
1362de3b87aSKai Wang 		sh_align   = shdr64->sh_addralign;
1372de3b87aSKai Wang 		sh_entsize = shdr64->sh_entsize;
1382de3b87aSKai Wang 		sh_offset  = shdr64->sh_offset;
1392de3b87aSKai Wang 		sh_size    = shdr64->sh_size;
1402de3b87aSKai Wang 	}
1412de3b87aSKai Wang 
1422de3b87aSKai Wang 	assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS);
1432de3b87aSKai Wang 
1442de3b87aSKai Wang 	elftype = _libelf_xlate_shtype(sh_type);
145*d003e0d7SEd Maste 	if (elftype < ELF_T_FIRST || elftype > ELF_T_LAST) {
1462de3b87aSKai Wang 		LIBELF_SET_ERROR(SECTION, 0);
1472de3b87aSKai Wang 		return (0);
1482de3b87aSKai Wang 	}
1492de3b87aSKai Wang 
1502de3b87aSKai Wang 	if (sh_align == 0)
1512de3b87aSKai Wang 		sh_align = _libelf_falign(elftype, ec);
1522de3b87aSKai Wang 
1532de3b87aSKai Wang 	/*
1542de3b87aSKai Wang 	 * Compute the section's size and alignment using the data
1552de3b87aSKai Wang 	 * descriptors associated with the section.
1562de3b87aSKai Wang 	 */
1572de3b87aSKai Wang 	if (STAILQ_EMPTY(&s->s_data)) {
1582de3b87aSKai Wang 		/*
1592de3b87aSKai Wang 		 * The section's content (if any) has not been read in
1602de3b87aSKai Wang 		 * yet.  If section is not dirty marked dirty, we can
1612de3b87aSKai Wang 		 * reuse the values in the 'sh_size' and 'sh_offset'
1622de3b87aSKai Wang 		 * fields of the section header.
1632de3b87aSKai Wang 		 */
1642de3b87aSKai Wang 		if ((s->s_flags & ELF_F_DIRTY) == 0) {
1652de3b87aSKai Wang 			/*
1662de3b87aSKai Wang 			 * If the library is doing the layout, then we
1672de3b87aSKai Wang 			 * compute the new start offset for the
1682de3b87aSKai Wang 			 * section based on the current offset and the
1692de3b87aSKai Wang 			 * section's alignment needs.
1702de3b87aSKai Wang 			 *
1712de3b87aSKai Wang 			 * If the application is doing the layout, we
1722de3b87aSKai Wang 			 * can use the value in the 'sh_offset' field
1732de3b87aSKai Wang 			 * in the section header directly.
1742de3b87aSKai Wang 			 */
1752de3b87aSKai Wang 			if (e->e_flags & ELF_F_LAYOUT)
1762de3b87aSKai Wang 				goto updatedescriptor;
1772de3b87aSKai Wang 			else
1782de3b87aSKai Wang 				goto computeoffset;
1792de3b87aSKai Wang 		}
1802de3b87aSKai Wang 
1812de3b87aSKai Wang 		/*
1822de3b87aSKai Wang 		 * Otherwise, we need to bring in the section's data
1832de3b87aSKai Wang 		 * from the underlying ELF object.
1842de3b87aSKai Wang 		 */
1852de3b87aSKai Wang 		if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL)
1862de3b87aSKai Wang 			return (0);
1872de3b87aSKai Wang 	}
1882de3b87aSKai Wang 
1892de3b87aSKai Wang 	/*
1902de3b87aSKai Wang 	 * Loop through the section's data descriptors.
1912de3b87aSKai Wang 	 */
1922de3b87aSKai Wang 	scn_size = 0L;
1932de3b87aSKai Wang 	scn_alignment = 0;
1942de3b87aSKai Wang 	STAILQ_FOREACH(ld, &s->s_data, d_next)  {
1952de3b87aSKai Wang 
1962de3b87aSKai Wang 		d = &ld->d_data;
1972de3b87aSKai Wang 
1982de3b87aSKai Wang 		/*
1992de3b87aSKai Wang 		 * The data buffer's type is known.
2002de3b87aSKai Wang 		 */
2012de3b87aSKai Wang 		if (d->d_type >= ELF_T_NUM) {
2022de3b87aSKai Wang 			LIBELF_SET_ERROR(DATA, 0);
2032de3b87aSKai Wang 			return (0);
2042de3b87aSKai Wang 		}
2052de3b87aSKai Wang 
2062de3b87aSKai Wang 		/*
2072de3b87aSKai Wang 		 * The data buffer's version is supported.
2082de3b87aSKai Wang 		 */
2092de3b87aSKai Wang 		if (d->d_version != e->e_version) {
2102de3b87aSKai Wang 			LIBELF_SET_ERROR(VERSION, 0);
2112de3b87aSKai Wang 			return (0);
2122de3b87aSKai Wang 		}
2132de3b87aSKai Wang 
2142de3b87aSKai Wang 		/*
2152de3b87aSKai Wang 		 * The buffer's alignment is non-zero and a power of
2162de3b87aSKai Wang 		 * two.
2172de3b87aSKai Wang 		 */
2182de3b87aSKai Wang 		if ((d_align = d->d_align) == 0 ||
2192de3b87aSKai Wang 		    (d_align & (d_align - 1))) {
2202de3b87aSKai Wang 			LIBELF_SET_ERROR(DATA, 0);
2212de3b87aSKai Wang 			return (0);
2222de3b87aSKai Wang 		}
2232de3b87aSKai Wang 
2242de3b87aSKai Wang 		/*
225*d003e0d7SEd Maste 		 * The data buffer's ELF type, ELF class and ELF version
226*d003e0d7SEd Maste 		 * should be supported.
227*d003e0d7SEd Maste 		 */
228*d003e0d7SEd Maste 		if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0)
229*d003e0d7SEd Maste 			return (0);
230*d003e0d7SEd Maste 
231*d003e0d7SEd Maste 		/*
2322de3b87aSKai Wang 		 * The buffer's size should be a multiple of the
2332de3b87aSKai Wang 		 * memory size of the underlying type.
2342de3b87aSKai Wang 		 */
2352de3b87aSKai Wang 		if (d->d_size % msz) {
2362de3b87aSKai Wang 			LIBELF_SET_ERROR(DATA, 0);
2372de3b87aSKai Wang 			return (0);
2382de3b87aSKai Wang 		}
2392de3b87aSKai Wang 
2402de3b87aSKai Wang 		/*
2412de3b87aSKai Wang 		 * If the application is controlling layout, then the
2422de3b87aSKai Wang 		 * d_offset field should be compatible with the
2432de3b87aSKai Wang 		 * buffer's specified alignment.
2442de3b87aSKai Wang 		 */
2452de3b87aSKai Wang 		if ((e->e_flags & ELF_F_LAYOUT) &&
2462de3b87aSKai Wang 		    (d->d_off & (d_align - 1))) {
2472de3b87aSKai Wang 			LIBELF_SET_ERROR(LAYOUT, 0);
2482de3b87aSKai Wang 			return (0);
2492de3b87aSKai Wang 		}
2502de3b87aSKai Wang 
2512de3b87aSKai Wang 		/*
2522de3b87aSKai Wang 		 * Compute the section's size.
2532de3b87aSKai Wang 		 */
2542de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
2552de3b87aSKai Wang 			if ((uint64_t) d->d_off + d->d_size > scn_size)
2562de3b87aSKai Wang 				scn_size = d->d_off + d->d_size;
2572de3b87aSKai Wang 		} else {
2582de3b87aSKai Wang 			scn_size = roundup2(scn_size, d->d_align);
2592de3b87aSKai Wang 			d->d_off = scn_size;
2602de3b87aSKai Wang 			fsz = _libelf_fsize(d->d_type, ec, d->d_version,
261cf781b2eSEd Maste 			    (size_t) d->d_size / msz);
2622de3b87aSKai Wang 			scn_size += fsz;
2632de3b87aSKai Wang 		}
2642de3b87aSKai Wang 
2652de3b87aSKai Wang 		/*
2662de3b87aSKai Wang 		 * The section's alignment is the maximum alignment
2672de3b87aSKai Wang 		 * needed for its data buffers.
2682de3b87aSKai Wang 		 */
2692de3b87aSKai Wang 		if (d_align > scn_alignment)
2702de3b87aSKai Wang 			scn_alignment = d_align;
2712de3b87aSKai Wang 	}
2722de3b87aSKai Wang 
2732de3b87aSKai Wang 
2742de3b87aSKai Wang 	/*
2752de3b87aSKai Wang 	 * If the application is requesting full control over the
2762de3b87aSKai Wang 	 * layout of the section, check the section's specified size,
2772de3b87aSKai Wang 	 * offsets and alignment for sanity.
2782de3b87aSKai Wang 	 */
2792de3b87aSKai Wang 	if (e->e_flags & ELF_F_LAYOUT) {
280b00fe64fSEd Maste 		if (scn_alignment > sh_align ||
281b00fe64fSEd Maste 		    sh_offset % sh_align ||
282b00fe64fSEd Maste 		    sh_size < scn_size ||
283b00fe64fSEd Maste 		    sh_offset % _libelf_falign(elftype, ec)) {
2842de3b87aSKai Wang 			LIBELF_SET_ERROR(LAYOUT, 0);
2852de3b87aSKai Wang 			return (0);
2862de3b87aSKai Wang 		}
2872de3b87aSKai Wang 		goto updatedescriptor;
2882de3b87aSKai Wang 	}
2892de3b87aSKai Wang 
2902de3b87aSKai Wang 	/*
2912de3b87aSKai Wang 	 * Otherwise, compute the values in the section header.
2922de3b87aSKai Wang 	 *
2932de3b87aSKai Wang 	 * The section alignment is the maximum alignment for any of
2942de3b87aSKai Wang 	 * its contained data descriptors.
2952de3b87aSKai Wang 	 */
2962de3b87aSKai Wang 	if (scn_alignment > sh_align)
2972de3b87aSKai Wang 		sh_align = scn_alignment;
2982de3b87aSKai Wang 
2992de3b87aSKai Wang 	/*
3002de3b87aSKai Wang 	 * If the section entry size is zero, try and fill in an
3012de3b87aSKai Wang 	 * appropriate entry size.  Per the elf(5) manual page
3022de3b87aSKai Wang 	 * sections without fixed-size entries should have their
3032de3b87aSKai Wang 	 * 'sh_entsize' field set to zero.
3042de3b87aSKai Wang 	 */
3052de3b87aSKai Wang 	if (sh_entsize == 0 &&
3062de3b87aSKai Wang 	    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
3072de3b87aSKai Wang 		(size_t) 1)) == 1)
3082de3b87aSKai Wang 		sh_entsize = 0;
3092de3b87aSKai Wang 
3102de3b87aSKai Wang 	sh_size = scn_size;
3112de3b87aSKai Wang 
3122de3b87aSKai Wang computeoffset:
3132de3b87aSKai Wang 	/*
3142de3b87aSKai Wang 	 * Compute the new offset for the section based on
3152de3b87aSKai Wang 	 * the section's alignment needs.
3162de3b87aSKai Wang 	 */
317cf781b2eSEd Maste 	sh_offset = roundup((uint64_t) rc, sh_align);
3182de3b87aSKai Wang 
3192de3b87aSKai Wang 	/*
3202de3b87aSKai Wang 	 * Update the section header.
3212de3b87aSKai Wang 	 */
3222de3b87aSKai Wang 	if (ec == ELFCLASS32) {
3232de3b87aSKai Wang 		shdr32->sh_addralign = (uint32_t) sh_align;
3242de3b87aSKai Wang 		shdr32->sh_entsize   = (uint32_t) sh_entsize;
3252de3b87aSKai Wang 		shdr32->sh_offset    = (uint32_t) sh_offset;
3262de3b87aSKai Wang 		shdr32->sh_size      = (uint32_t) sh_size;
3272de3b87aSKai Wang 	} else {
3282de3b87aSKai Wang 		shdr64->sh_addralign = sh_align;
3292de3b87aSKai Wang 		shdr64->sh_entsize   = sh_entsize;
3302de3b87aSKai Wang 		shdr64->sh_offset    = sh_offset;
3312de3b87aSKai Wang 		shdr64->sh_size      = sh_size;
3322de3b87aSKai Wang 	}
3332de3b87aSKai Wang 
3342de3b87aSKai Wang updatedescriptor:
3352de3b87aSKai Wang 	/*
3362de3b87aSKai Wang 	 * Update the section descriptor.
3372de3b87aSKai Wang 	 */
3382de3b87aSKai Wang 	s->s_size = sh_size;
3392de3b87aSKai Wang 	s->s_offset = sh_offset;
3402de3b87aSKai Wang 
3412de3b87aSKai Wang 	return (1);
3422de3b87aSKai Wang }
3432de3b87aSKai Wang 
3442de3b87aSKai Wang /*
3452de3b87aSKai Wang  * Free a list of extent descriptors.
3462de3b87aSKai Wang  */
3472de3b87aSKai Wang 
3482de3b87aSKai Wang static void
_libelf_release_extents(struct _Elf_Extent_List * extents)3492de3b87aSKai Wang _libelf_release_extents(struct _Elf_Extent_List *extents)
3502de3b87aSKai Wang {
3512de3b87aSKai Wang 	struct _Elf_Extent *ex;
3522de3b87aSKai Wang 
3532de3b87aSKai Wang 	while ((ex = SLIST_FIRST(extents)) != NULL) {
3542de3b87aSKai Wang 		SLIST_REMOVE_HEAD(extents, ex_next);
3552de3b87aSKai Wang 		free(ex);
3562de3b87aSKai Wang 	}
3572de3b87aSKai Wang }
3582de3b87aSKai Wang 
3592de3b87aSKai Wang /*
3602de3b87aSKai Wang  * Check if an extent 's' defined by [start..start+size) is free.
3612de3b87aSKai Wang  * This routine assumes that the given extent list is sorted in order
3622de3b87aSKai Wang  * of ascending extent offsets.
3632de3b87aSKai Wang  */
3642de3b87aSKai Wang 
3652de3b87aSKai Wang static int
_libelf_extent_is_unused(struct _Elf_Extent_List * extents,const uint64_t start,const uint64_t size,struct _Elf_Extent ** prevt)3662de3b87aSKai Wang _libelf_extent_is_unused(struct _Elf_Extent_List *extents,
3672de3b87aSKai Wang     const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt)
3682de3b87aSKai Wang {
3692de3b87aSKai Wang 	uint64_t tmax, tmin;
3702de3b87aSKai Wang 	struct _Elf_Extent *t, *pt;
3712de3b87aSKai Wang 	const uint64_t smax = start + size;
3722de3b87aSKai Wang 
3732de3b87aSKai Wang 	/* First, look for overlaps with existing extents. */
3742de3b87aSKai Wang 	pt = NULL;
3752de3b87aSKai Wang 	SLIST_FOREACH(t, extents, ex_next) {
3762de3b87aSKai Wang 		tmin = t->ex_start;
3772de3b87aSKai Wang 		tmax = tmin + t->ex_size;
3782de3b87aSKai Wang 
3792de3b87aSKai Wang 		if (tmax <= start) {
3802de3b87aSKai Wang 			/*
3812de3b87aSKai Wang 			 * 't' lies entirely before 's': ...| t |...| s |...
3822de3b87aSKai Wang 			 */
3832de3b87aSKai Wang 			pt = t;
3842de3b87aSKai Wang 			continue;
3852de3b87aSKai Wang 		} else if (smax <= tmin) {
3862de3b87aSKai Wang 			/*
3872de3b87aSKai Wang 			 * 's' lies entirely before 't', and after 'pt':
3882de3b87aSKai Wang 			 *      ...| pt |...| s |...| t |...
3892de3b87aSKai Wang 			 */
3902de3b87aSKai Wang 			assert(pt == NULL ||
3912de3b87aSKai Wang 			    pt->ex_start + pt->ex_size <= start);
3922de3b87aSKai Wang 			break;
3932de3b87aSKai Wang 		} else
3942de3b87aSKai Wang 			/* 's' and 't' overlap. */
3952de3b87aSKai Wang 			return (0);
3962de3b87aSKai Wang 	}
3972de3b87aSKai Wang 
3982de3b87aSKai Wang 	if (prevt)
3992de3b87aSKai Wang 		*prevt = pt;
4002de3b87aSKai Wang 	return (1);
4012de3b87aSKai Wang }
4022de3b87aSKai Wang 
4032de3b87aSKai Wang /*
4042de3b87aSKai Wang  * Insert an extent into the list of extents.
4052de3b87aSKai Wang  */
4062de3b87aSKai Wang 
4072de3b87aSKai Wang static int
_libelf_insert_extent(struct _Elf_Extent_List * extents,int type,uint64_t start,uint64_t size,void * desc)4082de3b87aSKai Wang _libelf_insert_extent(struct _Elf_Extent_List *extents, int type,
4092de3b87aSKai Wang     uint64_t start, uint64_t size, void *desc)
4102de3b87aSKai Wang {
4112de3b87aSKai Wang 	struct _Elf_Extent *ex, *prevt;
4122de3b87aSKai Wang 
4132de3b87aSKai Wang 	assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR);
4142de3b87aSKai Wang 
4152de3b87aSKai Wang 	prevt = NULL;
4162de3b87aSKai Wang 
4172de3b87aSKai Wang 	/*
4182de3b87aSKai Wang 	 * If the requested range overlaps with an existing extent,
4192de3b87aSKai Wang 	 * signal an error.
4202de3b87aSKai Wang 	 */
4212de3b87aSKai Wang 	if (!_libelf_extent_is_unused(extents, start, size, &prevt)) {
4222de3b87aSKai Wang 		LIBELF_SET_ERROR(LAYOUT, 0);
4232de3b87aSKai Wang 		return (0);
4242de3b87aSKai Wang 	}
4252de3b87aSKai Wang 
4262de3b87aSKai Wang 	/* Allocate and fill in a new extent descriptor. */
4272de3b87aSKai Wang 	if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL) {
4282de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, errno);
4292de3b87aSKai Wang 		return (0);
4302de3b87aSKai Wang 	}
4312de3b87aSKai Wang 	ex->ex_start = start;
4322de3b87aSKai Wang 	ex->ex_size = size;
4332de3b87aSKai Wang 	ex->ex_desc = desc;
4342de3b87aSKai Wang 	ex->ex_type = type;
4352de3b87aSKai Wang 
4362de3b87aSKai Wang 	/* Insert the region descriptor into the list. */
4372de3b87aSKai Wang 	if (prevt)
4382de3b87aSKai Wang 		SLIST_INSERT_AFTER(prevt, ex, ex_next);
4392de3b87aSKai Wang 	else
4402de3b87aSKai Wang 		SLIST_INSERT_HEAD(extents, ex, ex_next);
4412de3b87aSKai Wang 	return (1);
4422de3b87aSKai Wang }
4432de3b87aSKai Wang 
4442de3b87aSKai Wang /*
4452de3b87aSKai Wang  * Recompute section layout.
4462de3b87aSKai Wang  */
4472de3b87aSKai Wang 
4482de3b87aSKai Wang static off_t
_libelf_resync_sections(Elf * e,off_t rc,struct _Elf_Extent_List * extents)4492de3b87aSKai Wang _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents)
4502de3b87aSKai Wang {
4512de3b87aSKai Wang 	int ec;
4522de3b87aSKai Wang 	Elf_Scn *s;
4532de3b87aSKai Wang 	size_t sh_type;
4542de3b87aSKai Wang 
4552de3b87aSKai Wang 	ec = e->e_class;
4562de3b87aSKai Wang 
4572de3b87aSKai Wang 	/*
4582de3b87aSKai Wang 	 * Make a pass through sections, computing the extent of each
4592de3b87aSKai Wang 	 * section.
4602de3b87aSKai Wang 	 */
4618c953901SMark Johnston 	RB_FOREACH(s, scntree, &e->e_u.e_elf.e_scn) {
4622de3b87aSKai Wang 		if (ec == ELFCLASS32)
4632de3b87aSKai Wang 			sh_type = s->s_shdr.s_shdr32.sh_type;
4642de3b87aSKai Wang 		else
4652de3b87aSKai Wang 			sh_type = s->s_shdr.s_shdr64.sh_type;
4662de3b87aSKai Wang 
4672de3b87aSKai Wang 		if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
4682de3b87aSKai Wang 			continue;
4692de3b87aSKai Wang 
4702de3b87aSKai Wang 		if (_libelf_compute_section_extents(e, s, rc) == 0)
4712de3b87aSKai Wang 			return ((off_t) -1);
4722de3b87aSKai Wang 
4732de3b87aSKai Wang 		if (s->s_size == 0)
4742de3b87aSKai Wang 			continue;
4752de3b87aSKai Wang 
4762de3b87aSKai Wang 		if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION,
4772de3b87aSKai Wang 		    s->s_offset, s->s_size, s))
4782de3b87aSKai Wang 			return ((off_t) -1);
4792de3b87aSKai Wang 
4802de3b87aSKai Wang 		if ((size_t) rc < s->s_offset + s->s_size)
481cf781b2eSEd Maste 			rc = (off_t) (s->s_offset + s->s_size);
4822de3b87aSKai Wang 	}
4832de3b87aSKai Wang 
4842de3b87aSKai Wang 	return (rc);
4852de3b87aSKai Wang }
4862de3b87aSKai Wang 
4872de3b87aSKai Wang /*
4882de3b87aSKai Wang  * Recompute the layout of the ELF object and update the internal data
4892de3b87aSKai Wang  * structures associated with the ELF descriptor.
4902de3b87aSKai Wang  *
4912de3b87aSKai Wang  * Returns the size in bytes the ELF object would occupy in its file
4922de3b87aSKai Wang  * representation.
4932de3b87aSKai Wang  *
4942de3b87aSKai Wang  * After a successful call to this function, the following structures
4952de3b87aSKai Wang  * are updated:
4962de3b87aSKai Wang  *
4972de3b87aSKai Wang  * - The ELF header is updated.
4982de3b87aSKai Wang  * - All extents in the ELF object are sorted in order of ascending
4992de3b87aSKai Wang  *   addresses.  Sections have their section header table entries
5002de3b87aSKai Wang  *   updated.  An error is signalled if an overlap was detected among
5012de3b87aSKai Wang  *   extents.
5022de3b87aSKai Wang  * - Data descriptors associated with sections are checked for valid
5032de3b87aSKai Wang  *   types, offsets and alignment.
5042de3b87aSKai Wang  *
5052de3b87aSKai Wang  * After a resync_elf() successfully returns, the ELF descriptor is
5062de3b87aSKai Wang  * ready for being handed over to _libelf_write_elf().
5072de3b87aSKai Wang  */
5082de3b87aSKai Wang 
5092de3b87aSKai Wang static off_t
_libelf_resync_elf(Elf * e,struct _Elf_Extent_List * extents)5102de3b87aSKai Wang _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents)
5112de3b87aSKai Wang {
5122de3b87aSKai Wang 	int ec, eh_class;
5132de3b87aSKai Wang 	unsigned int eh_byteorder, eh_version;
5142de3b87aSKai Wang 	size_t align, fsz;
5152de3b87aSKai Wang 	size_t phnum, shnum;
5162de3b87aSKai Wang 	off_t rc, phoff, shoff;
5172de3b87aSKai Wang 	void *ehdr, *phdr;
5182de3b87aSKai Wang 	Elf32_Ehdr *eh32;
5192de3b87aSKai Wang 	Elf64_Ehdr *eh64;
5202de3b87aSKai Wang 
5212de3b87aSKai Wang 	rc = 0;
5222de3b87aSKai Wang 
5232de3b87aSKai Wang 	ec = e->e_class;
5242de3b87aSKai Wang 
5252de3b87aSKai Wang 	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
5262de3b87aSKai Wang 
5272de3b87aSKai Wang 	/*
5282de3b87aSKai Wang 	 * Prepare the EHDR.
5292de3b87aSKai Wang 	 */
5302de3b87aSKai Wang 	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
5312de3b87aSKai Wang 		return ((off_t) -1);
5322de3b87aSKai Wang 
5332de3b87aSKai Wang 	eh32 = ehdr;
5342de3b87aSKai Wang 	eh64 = ehdr;
5352de3b87aSKai Wang 
5362de3b87aSKai Wang 	if (ec == ELFCLASS32) {
5372de3b87aSKai Wang 		eh_byteorder = eh32->e_ident[EI_DATA];
5382de3b87aSKai Wang 		eh_class     = eh32->e_ident[EI_CLASS];
539cf781b2eSEd Maste 		phoff        = (off_t) eh32->e_phoff;
540cf781b2eSEd Maste 		shoff        = (off_t) eh32->e_shoff;
5412de3b87aSKai Wang 		eh_version   = eh32->e_version;
5422de3b87aSKai Wang 	} else {
5432de3b87aSKai Wang 		eh_byteorder = eh64->e_ident[EI_DATA];
5442de3b87aSKai Wang 		eh_class     = eh64->e_ident[EI_CLASS];
545cf781b2eSEd Maste 		phoff        = (off_t) eh64->e_phoff;
546cf781b2eSEd Maste 		shoff        = (off_t) eh64->e_shoff;
5472de3b87aSKai Wang 		eh_version   = eh64->e_version;
5482de3b87aSKai Wang 	}
5492de3b87aSKai Wang 
550cf781b2eSEd Maste 	if (phoff < 0 || shoff < 0) {
551cf781b2eSEd Maste 		LIBELF_SET_ERROR(HEADER, 0);
552cf781b2eSEd Maste 		return ((off_t) -1);
553cf781b2eSEd Maste 	}
554cf781b2eSEd Maste 
5552de3b87aSKai Wang 	if (eh_version == EV_NONE)
5562de3b87aSKai Wang 		eh_version = EV_CURRENT;
5572de3b87aSKai Wang 
5582de3b87aSKai Wang 	if (eh_version != e->e_version) {	/* always EV_CURRENT */
5592de3b87aSKai Wang 		LIBELF_SET_ERROR(VERSION, 0);
5602de3b87aSKai Wang 		return ((off_t) -1);
5612de3b87aSKai Wang 	}
5622de3b87aSKai Wang 
5632de3b87aSKai Wang 	if (eh_class != e->e_class) {
5642de3b87aSKai Wang 		LIBELF_SET_ERROR(CLASS, 0);
5652de3b87aSKai Wang 		return ((off_t) -1);
5662de3b87aSKai Wang 	}
5672de3b87aSKai Wang 
5682de3b87aSKai Wang 	if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
5692de3b87aSKai Wang 		LIBELF_SET_ERROR(HEADER, 0);
5702de3b87aSKai Wang 		return ((off_t) -1);
5712de3b87aSKai Wang 	}
5722de3b87aSKai Wang 
5732de3b87aSKai Wang 	shnum = e->e_u.e_elf.e_nscn;
5742de3b87aSKai Wang 	phnum = e->e_u.e_elf.e_nphdr;
5752de3b87aSKai Wang 
5762de3b87aSKai Wang 	e->e_byteorder = eh_byteorder;
5772de3b87aSKai Wang 
5782de3b87aSKai Wang #define	INITIALIZE_EHDR(E,EC,V)	do {					\
579cf781b2eSEd Maste 		unsigned int _version = (unsigned int) (V);		\
5802de3b87aSKai Wang 		(E)->e_ident[EI_MAG0] = ELFMAG0;			\
5812de3b87aSKai Wang 		(E)->e_ident[EI_MAG1] = ELFMAG1;			\
5822de3b87aSKai Wang 		(E)->e_ident[EI_MAG2] = ELFMAG2;			\
5832de3b87aSKai Wang 		(E)->e_ident[EI_MAG3] = ELFMAG3;			\
584cf781b2eSEd Maste 		(E)->e_ident[EI_CLASS] = (unsigned char) (EC);		\
585cf781b2eSEd Maste 		(E)->e_ident[EI_VERSION] = (_version & 0xFFU);		\
586cf781b2eSEd Maste 		(E)->e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR,	\
587cf781b2eSEd Maste 		    (EC), _version, (size_t) 1);			\
588cf781b2eSEd Maste 		(E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 :	\
589cf781b2eSEd Maste 		    _libelf_fsize(ELF_T_PHDR, (EC), _version,		\
590cf781b2eSEd Maste 			(size_t) 1));					\
591cf781b2eSEd Maste 		(E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR,	\
592cf781b2eSEd Maste 		    (EC), _version, (size_t) 1);			\
5932de3b87aSKai Wang 	} while (0)
5942de3b87aSKai Wang 
5952de3b87aSKai Wang 	if (ec == ELFCLASS32)
5962de3b87aSKai Wang 		INITIALIZE_EHDR(eh32, ec, eh_version);
5972de3b87aSKai Wang 	else
5982de3b87aSKai Wang 		INITIALIZE_EHDR(eh64, ec, eh_version);
5992de3b87aSKai Wang 
6002de3b87aSKai Wang 	(void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
6012de3b87aSKai Wang 
602cf781b2eSEd Maste 	rc += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1);
6032de3b87aSKai Wang 
604cf781b2eSEd Maste 	if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, (uint64_t) rc,
605cf781b2eSEd Maste 		ehdr))
6062de3b87aSKai Wang 		return ((off_t) -1);
6072de3b87aSKai Wang 
6082de3b87aSKai Wang 	/*
6092de3b87aSKai Wang 	 * Compute the layout the program header table, if one is
6102de3b87aSKai Wang 	 * present.  The program header table needs to be aligned to a
6112de3b87aSKai Wang 	 * `natural' boundary.
6122de3b87aSKai Wang 	 */
6132de3b87aSKai Wang 	if (phnum) {
6142de3b87aSKai Wang 		fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
6152de3b87aSKai Wang 		align = _libelf_falign(ELF_T_PHDR, ec);
6162de3b87aSKai Wang 
6172de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
6182de3b87aSKai Wang 			/*
6192de3b87aSKai Wang 			 * Check offsets for sanity.
6202de3b87aSKai Wang 			 */
6212de3b87aSKai Wang 			if (rc > phoff) {
6222de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6232de3b87aSKai Wang 				return ((off_t) -1);
6242de3b87aSKai Wang 			}
6252de3b87aSKai Wang 
626cf781b2eSEd Maste 			if (phoff % (off_t) align) {
6272de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6282de3b87aSKai Wang 				return ((off_t) -1);
6292de3b87aSKai Wang 			}
6302de3b87aSKai Wang 
6312de3b87aSKai Wang 		} else
632cf781b2eSEd Maste 			phoff = roundup(rc, (off_t) align);
6332de3b87aSKai Wang 
634cf781b2eSEd Maste 		rc = phoff + (off_t) fsz;
6352de3b87aSKai Wang 
6362de3b87aSKai Wang 		phdr = _libelf_getphdr(e, ec);
6372de3b87aSKai Wang 
638cf781b2eSEd Maste 		if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR,
639cf781b2eSEd Maste 			(uint64_t) phoff, fsz, phdr))
6402de3b87aSKai Wang 			return ((off_t) -1);
6412de3b87aSKai Wang 	} else
6422de3b87aSKai Wang 		phoff = 0;
6432de3b87aSKai Wang 
6442de3b87aSKai Wang 	/*
6452de3b87aSKai Wang 	 * Compute the layout of the sections associated with the
6462de3b87aSKai Wang 	 * file.
6472de3b87aSKai Wang 	 */
6482de3b87aSKai Wang 
6492de3b87aSKai Wang 	if (e->e_cmd != ELF_C_WRITE &&
6502de3b87aSKai Wang 	    (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
6512de3b87aSKai Wang 	    _libelf_load_section_headers(e, ehdr) == 0)
6522de3b87aSKai Wang 		return ((off_t) -1);
6532de3b87aSKai Wang 
6542de3b87aSKai Wang 	if ((rc = _libelf_resync_sections(e, rc, extents)) < 0)
6552de3b87aSKai Wang 		return ((off_t) -1);
6562de3b87aSKai Wang 
6572de3b87aSKai Wang 	/*
6582de3b87aSKai Wang 	 * Compute the space taken up by the section header table, if
6592de3b87aSKai Wang 	 * one is needed.
6602de3b87aSKai Wang 	 *
6612de3b87aSKai Wang 	 * If ELF_F_LAYOUT has been asserted, the application may have
6622de3b87aSKai Wang 	 * placed the section header table in between existing
6632de3b87aSKai Wang 	 * sections, so the net size of the file need not increase due
6642de3b87aSKai Wang 	 * to the presence of the section header table.
6652de3b87aSKai Wang 	 *
6662de3b87aSKai Wang 	 * If the library is responsible for laying out the object,
6672de3b87aSKai Wang 	 * the section header table is placed after section data.
6682de3b87aSKai Wang 	 */
6692de3b87aSKai Wang 	if (shnum) {
6702de3b87aSKai Wang 		fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum);
6712de3b87aSKai Wang 		align = _libelf_falign(ELF_T_SHDR, ec);
6722de3b87aSKai Wang 
6732de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
674cf781b2eSEd Maste 			if (shoff % (off_t) align) {
6752de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6762de3b87aSKai Wang 				return ((off_t) -1);
6772de3b87aSKai Wang 			}
6782de3b87aSKai Wang 		} else
679cf781b2eSEd Maste 			shoff = roundup(rc, (off_t) align);
6802de3b87aSKai Wang 
681cf781b2eSEd Maste 		if (shoff + (off_t) fsz > rc)
682cf781b2eSEd Maste 			rc = shoff + (off_t) fsz;
6832de3b87aSKai Wang 
684cf781b2eSEd Maste 		if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR,
685cf781b2eSEd Maste 			(uint64_t) shoff, fsz, NULL))
6862de3b87aSKai Wang 			return ((off_t) -1);
6872de3b87aSKai Wang 	} else
6882de3b87aSKai Wang 		shoff = 0;
6892de3b87aSKai Wang 
6902de3b87aSKai Wang 	/*
6912de3b87aSKai Wang 	 * Set the fields of the Executable Header that could potentially use
6922de3b87aSKai Wang 	 * extended numbering.
6932de3b87aSKai Wang 	 */
6942de3b87aSKai Wang 	_libelf_setphnum(e, ehdr, ec, phnum);
6952de3b87aSKai Wang 	_libelf_setshnum(e, ehdr, ec, shnum);
6962de3b87aSKai Wang 
6972de3b87aSKai Wang 	/*
6982de3b87aSKai Wang 	 * Update the `e_phoff' and `e_shoff' fields if the library is
6992de3b87aSKai Wang 	 * doing the layout.
7002de3b87aSKai Wang 	 */
7012de3b87aSKai Wang 	if ((e->e_flags & ELF_F_LAYOUT) == 0) {
7022de3b87aSKai Wang 		if (ec == ELFCLASS32) {
7032de3b87aSKai Wang 			eh32->e_phoff = (uint32_t) phoff;
7042de3b87aSKai Wang 			eh32->e_shoff = (uint32_t) shoff;
7052de3b87aSKai Wang 		} else {
7062de3b87aSKai Wang 			eh64->e_phoff = (uint64_t) phoff;
7072de3b87aSKai Wang 			eh64->e_shoff = (uint64_t) shoff;
7082de3b87aSKai Wang 		}
7092de3b87aSKai Wang 	}
7102de3b87aSKai Wang 
7112de3b87aSKai Wang 	return (rc);
7122de3b87aSKai Wang }
7132de3b87aSKai Wang 
7142de3b87aSKai Wang /*
7152de3b87aSKai Wang  * Write out the contents of an ELF section.
7162de3b87aSKai Wang  */
7172de3b87aSKai Wang 
718cf781b2eSEd Maste static off_t
_libelf_write_scn(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)719cf781b2eSEd Maste _libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
7202de3b87aSKai Wang {
721cf781b2eSEd Maste 	off_t rc;
722ae500c1fSEd Maste 	int ec, em;
7232de3b87aSKai Wang 	Elf_Scn *s;
7242de3b87aSKai Wang 	int elftype;
7252de3b87aSKai Wang 	Elf_Data *d, dst;
7262de3b87aSKai Wang 	uint32_t sh_type;
7272de3b87aSKai Wang 	struct _Libelf_Data *ld;
7282de3b87aSKai Wang 	uint64_t sh_off, sh_size;
729cf781b2eSEd Maste 	size_t fsz, msz, nobjects;
7302de3b87aSKai Wang 
7312de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_SECTION);
7322de3b87aSKai Wang 
7332de3b87aSKai Wang 	s = ex->ex_desc;
734cf781b2eSEd Maste 	rc = (off_t) ex->ex_start;
7352de3b87aSKai Wang 
7362de3b87aSKai Wang 	if ((ec = e->e_class) == ELFCLASS32) {
7372de3b87aSKai Wang 		sh_type = s->s_shdr.s_shdr32.sh_type;
7382de3b87aSKai Wang 		sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
7392de3b87aSKai Wang 	} else {
7402de3b87aSKai Wang 		sh_type = s->s_shdr.s_shdr64.sh_type;
7412de3b87aSKai Wang 		sh_size = s->s_shdr.s_shdr64.sh_size;
7422de3b87aSKai Wang 	}
7432de3b87aSKai Wang 
7442de3b87aSKai Wang 	/*
7452de3b87aSKai Wang 	 * Ignore sections that do not allocate space in the file.
7462de3b87aSKai Wang 	 */
7472de3b87aSKai Wang 	if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0)
7482de3b87aSKai Wang 		return (rc);
7492de3b87aSKai Wang 
7502de3b87aSKai Wang 	elftype = _libelf_xlate_shtype(sh_type);
7512de3b87aSKai Wang 	assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
7522de3b87aSKai Wang 
7532de3b87aSKai Wang 	sh_off = s->s_offset;
7542de3b87aSKai Wang 	assert(sh_off % _libelf_falign(elftype, ec) == 0);
7552de3b87aSKai Wang 
756ae500c1fSEd Maste 	em = _libelf_elfmachine(e);
757ae500c1fSEd Maste #if 0
758ae500c1fSEd Maste 	assert(em >= EM_NONE && em < EM__LAST__);
759ae500c1fSEd Maste #endif
760ae500c1fSEd Maste 
7612de3b87aSKai Wang 	/*
7622de3b87aSKai Wang 	 * If the section has a `rawdata' descriptor, and the section
7632de3b87aSKai Wang 	 * contents have not been modified, use its contents directly.
7642de3b87aSKai Wang 	 * The `s_rawoff' member contains the offset into the original
7652de3b87aSKai Wang 	 * file, while `s_offset' contains its new location in the
7662de3b87aSKai Wang 	 * destination.
7672de3b87aSKai Wang 	 */
7682de3b87aSKai Wang 
7692de3b87aSKai Wang 	if (STAILQ_EMPTY(&s->s_data)) {
7702de3b87aSKai Wang 
7712de3b87aSKai Wang 		if ((d = elf_rawdata(s, NULL)) == NULL)
7722de3b87aSKai Wang 			return ((off_t) -1);
7732de3b87aSKai Wang 
7742de3b87aSKai Wang 		STAILQ_FOREACH(ld, &s->s_rawdata, d_next) {
7752de3b87aSKai Wang 
7762de3b87aSKai Wang 			d = &ld->d_data;
7772de3b87aSKai Wang 
7782de3b87aSKai Wang 			if ((uint64_t) rc < sh_off + d->d_off)
7792de3b87aSKai Wang 				(void) memset(nf + rc,
780cf781b2eSEd Maste 				    LIBELF_PRIVATE(fillchar),
781cf781b2eSEd Maste 				    (size_t) (sh_off + d->d_off -
782cf781b2eSEd Maste 					(uint64_t) rc));
783cf781b2eSEd Maste 			rc = (off_t) (sh_off + d->d_off);
7842de3b87aSKai Wang 
7852de3b87aSKai Wang 			assert(d->d_buf != NULL);
7862de3b87aSKai Wang 			assert(d->d_type == ELF_T_BYTE);
7872de3b87aSKai Wang 			assert(d->d_version == e->e_version);
7882de3b87aSKai Wang 
7892de3b87aSKai Wang 			(void) memcpy(nf + rc,
790cf781b2eSEd Maste 			    e->e_rawfile + s->s_rawoff + d->d_off,
791cf781b2eSEd Maste 			    (size_t) d->d_size);
7922de3b87aSKai Wang 
793cf781b2eSEd Maste 			rc += (off_t) d->d_size;
7942de3b87aSKai Wang 		}
7952de3b87aSKai Wang 
7962de3b87aSKai Wang 		return (rc);
7972de3b87aSKai Wang 	}
7982de3b87aSKai Wang 
7992de3b87aSKai Wang 	/*
8002de3b87aSKai Wang 	 * Iterate over the set of data descriptors for this section.
8012de3b87aSKai Wang 	 * The prior call to _libelf_resync_elf() would have setup the
8022de3b87aSKai Wang 	 * descriptors for this step.
8032de3b87aSKai Wang 	 */
8042de3b87aSKai Wang 
8052de3b87aSKai Wang 	dst.d_version = e->e_version;
8062de3b87aSKai Wang 
8072de3b87aSKai Wang 	STAILQ_FOREACH(ld, &s->s_data, d_next) {
8082de3b87aSKai Wang 
8092de3b87aSKai Wang 		d = &ld->d_data;
8102de3b87aSKai Wang 
811*d003e0d7SEd Maste 		if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0)
812*d003e0d7SEd Maste 			return ((off_t) -1);
8132de3b87aSKai Wang 
8142de3b87aSKai Wang 		if ((uint64_t) rc < sh_off + d->d_off)
8152de3b87aSKai Wang 			(void) memset(nf + rc,
816cf781b2eSEd Maste 			    LIBELF_PRIVATE(fillchar),
817cf781b2eSEd Maste 			    (size_t) (sh_off + d->d_off - (uint64_t) rc));
8182de3b87aSKai Wang 
819cf781b2eSEd Maste 		rc = (off_t) (sh_off + d->d_off);
8202de3b87aSKai Wang 
8212de3b87aSKai Wang 		assert(d->d_buf != NULL);
8222de3b87aSKai Wang 		assert(d->d_version == e->e_version);
8232de3b87aSKai Wang 		assert(d->d_size % msz == 0);
824*d003e0d7SEd Maste 		assert(msz != 0);
8252de3b87aSKai Wang 
826cf781b2eSEd Maste 		nobjects = (size_t) (d->d_size / msz);
8272de3b87aSKai Wang 
8282de3b87aSKai Wang 		fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects);
8292de3b87aSKai Wang 
8302de3b87aSKai Wang 		dst.d_buf    = nf + rc;
8312de3b87aSKai Wang 		dst.d_size   = fsz;
8322de3b87aSKai Wang 
833ae500c1fSEd Maste 		if (_libelf_xlate(&dst, d, e->e_byteorder, ec, em, ELF_TOFILE)
834ae500c1fSEd Maste 		    == NULL)
8352de3b87aSKai Wang 			return ((off_t) -1);
8362de3b87aSKai Wang 
837cf781b2eSEd Maste 		rc += (off_t) fsz;
8382de3b87aSKai Wang 	}
8392de3b87aSKai Wang 
840cf781b2eSEd Maste 	return (rc);
8412de3b87aSKai Wang }
8422de3b87aSKai Wang 
8432de3b87aSKai Wang /*
8442de3b87aSKai Wang  * Write out an ELF Executable Header.
8452de3b87aSKai Wang  */
8462de3b87aSKai Wang 
8472de3b87aSKai Wang static off_t
_libelf_write_ehdr(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)848cf781b2eSEd Maste _libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8492de3b87aSKai Wang {
850ae500c1fSEd Maste 	int ec, em;
8512de3b87aSKai Wang 	void *ehdr;
8522de3b87aSKai Wang 	size_t fsz, msz;
8532de3b87aSKai Wang 	Elf_Data dst, src;
8542de3b87aSKai Wang 
8552de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_EHDR);
8562de3b87aSKai Wang 	assert(ex->ex_start == 0); /* Ehdr always comes first. */
8572de3b87aSKai Wang 
8582de3b87aSKai Wang 	ec = e->e_class;
8592de3b87aSKai Wang 
8602de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
8612de3b87aSKai Wang 	assert(ehdr != NULL);
8622de3b87aSKai Wang 
8632de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
864*d003e0d7SEd Maste 	if ((msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version)) == 0)
865*d003e0d7SEd Maste 		return ((off_t) -1);
8662de3b87aSKai Wang 
867ae500c1fSEd Maste 	em = _libelf_elfmachine(e);
868ae500c1fSEd Maste 
8692de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
8702de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
8712de3b87aSKai Wang 
8722de3b87aSKai Wang 	src.d_buf     = ehdr;
8732de3b87aSKai Wang 	src.d_size    = msz;
8742de3b87aSKai Wang 	src.d_type    = ELF_T_EHDR;
8752de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
8762de3b87aSKai Wang 
8772de3b87aSKai Wang 	dst.d_buf     = nf;
8782de3b87aSKai Wang 	dst.d_size    = fsz;
8792de3b87aSKai Wang 
880ae500c1fSEd Maste 	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em, ELF_TOFILE) ==
8812de3b87aSKai Wang 	    NULL)
8822de3b87aSKai Wang 		return ((off_t) -1);
8832de3b87aSKai Wang 
8842de3b87aSKai Wang 	return ((off_t) fsz);
8852de3b87aSKai Wang }
8862de3b87aSKai Wang 
8872de3b87aSKai Wang /*
8882de3b87aSKai Wang  * Write out an ELF program header table.
8892de3b87aSKai Wang  */
8902de3b87aSKai Wang 
8912de3b87aSKai Wang static off_t
_libelf_write_phdr(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)892cf781b2eSEd Maste _libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8932de3b87aSKai Wang {
894ae500c1fSEd Maste 	int ec, em;
8952de3b87aSKai Wang 	void *ehdr;
8962de3b87aSKai Wang 	Elf32_Ehdr *eh32;
8972de3b87aSKai Wang 	Elf64_Ehdr *eh64;
8982de3b87aSKai Wang 	Elf_Data dst, src;
899*d003e0d7SEd Maste 	size_t fsz, msz, phnum;
9002de3b87aSKai Wang 	uint64_t phoff;
9012de3b87aSKai Wang 
9022de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_PHDR);
9032de3b87aSKai Wang 
9042de3b87aSKai Wang 	ec = e->e_class;
9052de3b87aSKai Wang 
906*d003e0d7SEd Maste 	ehdr = _libelf_ehdr(e, ec, 0);
907*d003e0d7SEd Maste 	assert(ehdr != NULL);
908*d003e0d7SEd Maste 
909*d003e0d7SEd Maste 	phnum = e->e_u.e_elf.e_nphdr;
9102de3b87aSKai Wang 	assert(phnum > 0);
9112de3b87aSKai Wang 
9122de3b87aSKai Wang 	if (ec == ELFCLASS32) {
9132de3b87aSKai Wang 		eh32 = (Elf32_Ehdr *) ehdr;
9142de3b87aSKai Wang 		phoff = (uint64_t) eh32->e_phoff;
9152de3b87aSKai Wang 	} else {
9162de3b87aSKai Wang 		eh64 = (Elf64_Ehdr *) ehdr;
9172de3b87aSKai Wang 		phoff = eh64->e_phoff;
9182de3b87aSKai Wang 	}
9192de3b87aSKai Wang 
920ae500c1fSEd Maste 	em = _libelf_elfmachine(e);
921ae500c1fSEd Maste 
9222de3b87aSKai Wang 	assert(phoff > 0);
9232de3b87aSKai Wang 	assert(ex->ex_start == phoff);
9242de3b87aSKai Wang 	assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);
9252de3b87aSKai Wang 
9262de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
9272de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
9282de3b87aSKai Wang 
929*d003e0d7SEd Maste 	if ((msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version)) == 0)
930*d003e0d7SEd Maste 		return ((off_t) -1);
9312de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
9322de3b87aSKai Wang 	assert(fsz > 0);
9332de3b87aSKai Wang 
9342de3b87aSKai Wang 	src.d_buf = _libelf_getphdr(e, ec);
9352de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
9362de3b87aSKai Wang 	src.d_type = ELF_T_PHDR;
937*d003e0d7SEd Maste 	src.d_size = phnum * msz;
9382de3b87aSKai Wang 
9392de3b87aSKai Wang 	dst.d_size = fsz;
9402de3b87aSKai Wang 	dst.d_buf = nf + ex->ex_start;
9412de3b87aSKai Wang 
942ae500c1fSEd Maste 	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em, ELF_TOFILE) ==
9432de3b87aSKai Wang 	    NULL)
9442de3b87aSKai Wang 		return ((off_t) -1);
9452de3b87aSKai Wang 
946cf781b2eSEd Maste 	return ((off_t) (phoff + fsz));
9472de3b87aSKai Wang }
9482de3b87aSKai Wang 
9492de3b87aSKai Wang /*
9502de3b87aSKai Wang  * Write out an ELF section header table.
9512de3b87aSKai Wang  */
9522de3b87aSKai Wang 
9532de3b87aSKai Wang static off_t
_libelf_write_shdr(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)954cf781b2eSEd Maste _libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
9552de3b87aSKai Wang {
956ae500c1fSEd Maste 	int ec, em;
9572de3b87aSKai Wang 	void *ehdr;
9582de3b87aSKai Wang 	Elf_Scn *scn;
9592de3b87aSKai Wang 	uint64_t shoff;
9602de3b87aSKai Wang 	Elf32_Ehdr *eh32;
9612de3b87aSKai Wang 	Elf64_Ehdr *eh64;
962*d003e0d7SEd Maste 	size_t fsz, msz, nscn;
9632de3b87aSKai Wang 	Elf_Data dst, src;
9642de3b87aSKai Wang 
9652de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_SHDR);
9662de3b87aSKai Wang 
9672de3b87aSKai Wang 	ec = e->e_class;
968*d003e0d7SEd Maste 
9692de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
970*d003e0d7SEd Maste 	assert(ehdr != NULL);
971*d003e0d7SEd Maste 
9722de3b87aSKai Wang 	nscn = e->e_u.e_elf.e_nscn;
9732de3b87aSKai Wang 
9742de3b87aSKai Wang 	if (ec == ELFCLASS32) {
9752de3b87aSKai Wang 		eh32 = (Elf32_Ehdr *) ehdr;
9762de3b87aSKai Wang 		shoff = (uint64_t) eh32->e_shoff;
9772de3b87aSKai Wang 	} else {
9782de3b87aSKai Wang 		eh64 = (Elf64_Ehdr *) ehdr;
9792de3b87aSKai Wang 		shoff = eh64->e_shoff;
9802de3b87aSKai Wang 	}
9812de3b87aSKai Wang 
982ae500c1fSEd Maste 	em = _libelf_elfmachine(e);
983ae500c1fSEd Maste 
9842de3b87aSKai Wang 	assert(nscn > 0);
9852de3b87aSKai Wang 	assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0);
9862de3b87aSKai Wang 	assert(ex->ex_start == shoff);
9872de3b87aSKai Wang 
9882de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
9892de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
9902de3b87aSKai Wang 
991*d003e0d7SEd Maste 	if ((msz = _libelf_msize(ELF_T_SHDR, ec, e->e_version)) == 0)
992*d003e0d7SEd Maste 		return ((off_t) -1);
993*d003e0d7SEd Maste 
9942de3b87aSKai Wang 	src.d_type = ELF_T_SHDR;
995*d003e0d7SEd Maste 	src.d_size = msz;
9962de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
9972de3b87aSKai Wang 
9982de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
9992de3b87aSKai Wang 
10008c953901SMark Johnston 	RB_FOREACH(scn, scntree, &e->e_u.e_elf.e_scn) {
10012de3b87aSKai Wang 		if (ec == ELFCLASS32)
10022de3b87aSKai Wang 			src.d_buf = &scn->s_shdr.s_shdr32;
10032de3b87aSKai Wang 		else
10042de3b87aSKai Wang 			src.d_buf = &scn->s_shdr.s_shdr64;
10052de3b87aSKai Wang 
10062de3b87aSKai Wang 		dst.d_size = fsz;
10072de3b87aSKai Wang 		dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz;
10082de3b87aSKai Wang 
1009ae500c1fSEd Maste 		if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em,
10102de3b87aSKai Wang 			ELF_TOFILE) == NULL)
10112de3b87aSKai Wang 			return ((off_t) -1);
10122de3b87aSKai Wang 	}
10132de3b87aSKai Wang 
1014cf781b2eSEd Maste 	return ((off_t) (ex->ex_start + nscn * fsz));
10152de3b87aSKai Wang }
10162de3b87aSKai Wang 
10172de3b87aSKai Wang /*
10182de3b87aSKai Wang  * Write out the file image.
10192de3b87aSKai Wang  *
10202de3b87aSKai Wang  * The original file could have been mapped in with an ELF_C_RDWR
10212de3b87aSKai Wang  * command and the application could have added new content or
10222de3b87aSKai Wang  * re-arranged its sections before calling elf_update().  Consequently
10232de3b87aSKai Wang  * its not safe to work `in place' on the original file.  So we
10242de3b87aSKai Wang  * malloc() the required space for the updated ELF object and build
10252de3b87aSKai Wang  * the object there and write it out to the underlying file at the
10262de3b87aSKai Wang  * end.  Note that the application may have opened the underlying file
10272de3b87aSKai Wang  * in ELF_C_RDWR and only retrieved/modified a few sections.  We take
10282de3b87aSKai Wang  * care to avoid translating file sections unnecessarily.
10292de3b87aSKai Wang  *
10302de3b87aSKai Wang  * Gaps in the coverage of the file by the file's sections will be
10312de3b87aSKai Wang  * filled with the fill character set by elf_fill(3).
10322de3b87aSKai Wang  */
10332de3b87aSKai Wang 
10342de3b87aSKai Wang static off_t
_libelf_write_elf(Elf * e,off_t newsize,struct _Elf_Extent_List * extents)10352de3b87aSKai Wang _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
10362de3b87aSKai Wang {
10372de3b87aSKai Wang 	off_t nrc, rc;
10382de3b87aSKai Wang 	Elf_Scn *scn, *tscn;
10392de3b87aSKai Wang 	struct _Elf_Extent *ex;
1040cf781b2eSEd Maste 	unsigned char *newfile;
10412de3b87aSKai Wang 
10422de3b87aSKai Wang 	assert(e->e_kind == ELF_K_ELF);
10432de3b87aSKai Wang 	assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE);
10442de3b87aSKai Wang 	assert(e->e_fd >= 0);
10452de3b87aSKai Wang 
10462de3b87aSKai Wang 	if ((newfile = malloc((size_t) newsize)) == NULL) {
10472de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, errno);
10482de3b87aSKai Wang 		return ((off_t) -1);
10492de3b87aSKai Wang 	}
10502de3b87aSKai Wang 
10512de3b87aSKai Wang 	nrc = rc = 0;
10522de3b87aSKai Wang 	SLIST_FOREACH(ex, extents, ex_next) {
10532de3b87aSKai Wang 
10542de3b87aSKai Wang 		/* Fill inter-extent gaps. */
10552de3b87aSKai Wang 		if (ex->ex_start > (size_t) rc)
10562de3b87aSKai Wang 			(void) memset(newfile + rc, LIBELF_PRIVATE(fillchar),
1057cf781b2eSEd Maste 			    (size_t) (ex->ex_start - (uint64_t) rc));
10582de3b87aSKai Wang 
10592de3b87aSKai Wang 		switch (ex->ex_type) {
10602de3b87aSKai Wang 		case ELF_EXTENT_EHDR:
10612de3b87aSKai Wang 			if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0)
10622de3b87aSKai Wang 				goto error;
10632de3b87aSKai Wang 			break;
10642de3b87aSKai Wang 
10652de3b87aSKai Wang 		case ELF_EXTENT_PHDR:
10662de3b87aSKai Wang 			if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0)
10672de3b87aSKai Wang 				goto error;
10682de3b87aSKai Wang 			break;
10692de3b87aSKai Wang 
10702de3b87aSKai Wang 		case ELF_EXTENT_SECTION:
10712de3b87aSKai Wang 			if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0)
10722de3b87aSKai Wang 				goto error;
10732de3b87aSKai Wang 			break;
10742de3b87aSKai Wang 
10752de3b87aSKai Wang 		case ELF_EXTENT_SHDR:
10762de3b87aSKai Wang 			if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0)
10772de3b87aSKai Wang 				goto error;
10782de3b87aSKai Wang 			break;
10792de3b87aSKai Wang 
10802de3b87aSKai Wang 		default:
10812de3b87aSKai Wang 			assert(0);
10822de3b87aSKai Wang 			break;
10832de3b87aSKai Wang 		}
10842de3b87aSKai Wang 
10852de3b87aSKai Wang 		assert(ex->ex_start + ex->ex_size == (size_t) nrc);
10862de3b87aSKai Wang 		assert(rc < nrc);
10872de3b87aSKai Wang 
10882de3b87aSKai Wang 		rc = nrc;
10892de3b87aSKai Wang 	}
10902de3b87aSKai Wang 
10912de3b87aSKai Wang 	assert(rc == newsize);
10922de3b87aSKai Wang 
10932de3b87aSKai Wang 	/*
10942de3b87aSKai Wang 	 * For regular files, throw away existing file content and
10952de3b87aSKai Wang 	 * unmap any existing mappings.
10962de3b87aSKai Wang 	 */
10972de3b87aSKai Wang 	if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0) {
10982de3b87aSKai Wang 		if (ftruncate(e->e_fd, (off_t) 0) < 0 ||
10992de3b87aSKai Wang 		    lseek(e->e_fd, (off_t) 0, SEEK_SET)) {
11002de3b87aSKai Wang 			LIBELF_SET_ERROR(IO, errno);
11012de3b87aSKai Wang 			goto error;
11022de3b87aSKai Wang 		}
11032de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
11042de3b87aSKai Wang 		if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
11052de3b87aSKai Wang 			assert(e->e_rawfile != NULL);
11062de3b87aSKai Wang 			assert(e->e_cmd == ELF_C_RDWR);
1107*d003e0d7SEd Maste 			if (munmap(e->e_rawfile, (size_t) e->e_rawsize) < 0) {
11082de3b87aSKai Wang 				LIBELF_SET_ERROR(IO, errno);
11092de3b87aSKai Wang 				goto error;
11102de3b87aSKai Wang 			}
11112de3b87aSKai Wang 		}
11122de3b87aSKai Wang #endif
11132de3b87aSKai Wang 	}
11142de3b87aSKai Wang 
11152de3b87aSKai Wang 	/*
11162de3b87aSKai Wang 	 * Write out the new contents.
11172de3b87aSKai Wang 	 */
11182de3b87aSKai Wang 	if (write(e->e_fd, newfile, (size_t) newsize) != newsize) {
11192de3b87aSKai Wang 		LIBELF_SET_ERROR(IO, errno);
11202de3b87aSKai Wang 		goto error;
11212de3b87aSKai Wang 	}
11222de3b87aSKai Wang 
11232de3b87aSKai Wang 	/*
11242de3b87aSKai Wang 	 * For files opened in ELF_C_RDWR mode, set up the new 'raw'
11252de3b87aSKai Wang 	 * contents.
11262de3b87aSKai Wang 	 */
11272de3b87aSKai Wang 	if (e->e_cmd == ELF_C_RDWR) {
11282de3b87aSKai Wang 		assert(e->e_rawfile != NULL);
11292de3b87aSKai Wang 		assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) ||
11302de3b87aSKai Wang 		    (e->e_flags & LIBELF_F_RAWFILE_MMAP));
11312de3b87aSKai Wang 		if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) {
1132*d003e0d7SEd Maste 			assert((e->e_flags & LIBELF_F_RAWFILE_MMAP) == 0);
11332de3b87aSKai Wang 			free(e->e_rawfile);
11342de3b87aSKai Wang 			e->e_rawfile = newfile;
11352de3b87aSKai Wang 			newfile = NULL;
11362de3b87aSKai Wang 		}
11372de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
11382de3b87aSKai Wang 		else if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
1139*d003e0d7SEd Maste 			assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) == 0);
11402de3b87aSKai Wang 			if ((e->e_rawfile = mmap(NULL, (size_t) newsize,
11412de3b87aSKai Wang 			    PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) ==
11422de3b87aSKai Wang 			    MAP_FAILED) {
11432de3b87aSKai Wang 				LIBELF_SET_ERROR(IO, errno);
11442de3b87aSKai Wang 				goto error;
11452de3b87aSKai Wang 			}
11462de3b87aSKai Wang 		}
11472de3b87aSKai Wang #endif	/* ELFTC_HAVE_MMAP */
11482de3b87aSKai Wang 
11492de3b87aSKai Wang 		/* Record the new size of the file. */
1150*d003e0d7SEd Maste 		e->e_rawsize = newsize;
11512de3b87aSKai Wang 	} else {
11522de3b87aSKai Wang 		/* File opened in ELF_C_WRITE mode. */
11532de3b87aSKai Wang 		assert(e->e_rawfile == NULL);
11542de3b87aSKai Wang 	}
11552de3b87aSKai Wang 
11562de3b87aSKai Wang 	/*
11572de3b87aSKai Wang 	 * Reset flags, remove existing section descriptors and
11582de3b87aSKai Wang 	 * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
11592de3b87aSKai Wang 	 * and elf_getscn() will function correctly.
11602de3b87aSKai Wang 	 */
11612de3b87aSKai Wang 
11622de3b87aSKai Wang 	e->e_flags &= ~ELF_F_DIRTY;
11632de3b87aSKai Wang 
11648c953901SMark Johnston 	RB_FOREACH_SAFE(scn, scntree, &e->e_u.e_elf.e_scn, tscn)
11652de3b87aSKai Wang 		_libelf_release_scn(scn);
11662de3b87aSKai Wang 
11672de3b87aSKai Wang 	if (e->e_class == ELFCLASS32) {
11682de3b87aSKai Wang 		free(e->e_u.e_elf.e_ehdr.e_ehdr32);
11692de3b87aSKai Wang 		if (e->e_u.e_elf.e_phdr.e_phdr32)
11702de3b87aSKai Wang 			free(e->e_u.e_elf.e_phdr.e_phdr32);
11712de3b87aSKai Wang 
11722de3b87aSKai Wang 		e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
11732de3b87aSKai Wang 		e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
11742de3b87aSKai Wang 	} else {
11752de3b87aSKai Wang 		free(e->e_u.e_elf.e_ehdr.e_ehdr64);
11762de3b87aSKai Wang 		if (e->e_u.e_elf.e_phdr.e_phdr64)
11772de3b87aSKai Wang 			free(e->e_u.e_elf.e_phdr.e_phdr64);
11782de3b87aSKai Wang 
11792de3b87aSKai Wang 		e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
11802de3b87aSKai Wang 		e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
11812de3b87aSKai Wang 	}
11822de3b87aSKai Wang 
11832de3b87aSKai Wang 	/* Free the temporary buffer. */
11842de3b87aSKai Wang 	if (newfile)
11852de3b87aSKai Wang 		free(newfile);
11862de3b87aSKai Wang 
11872de3b87aSKai Wang 	return (rc);
11882de3b87aSKai Wang 
11892de3b87aSKai Wang  error:
11902de3b87aSKai Wang 	free(newfile);
11912de3b87aSKai Wang 
11922de3b87aSKai Wang 	return ((off_t) -1);
11932de3b87aSKai Wang }
11942de3b87aSKai Wang 
11952de3b87aSKai Wang /*
11962de3b87aSKai Wang  * Update an ELF object.
11972de3b87aSKai Wang  */
11982de3b87aSKai Wang 
11992de3b87aSKai Wang off_t
elf_update(Elf * e,Elf_Cmd c)12002de3b87aSKai Wang elf_update(Elf *e, Elf_Cmd c)
12012de3b87aSKai Wang {
12022de3b87aSKai Wang 	int ec;
12032de3b87aSKai Wang 	off_t rc;
12042de3b87aSKai Wang 	struct _Elf_Extent_List extents;
12052de3b87aSKai Wang 
12062de3b87aSKai Wang 	rc = (off_t) -1;
12072de3b87aSKai Wang 
12082de3b87aSKai Wang 	if (e == NULL || e->e_kind != ELF_K_ELF ||
12092de3b87aSKai Wang 	    (c != ELF_C_NULL && c != ELF_C_WRITE)) {
12102de3b87aSKai Wang 		LIBELF_SET_ERROR(ARGUMENT, 0);
12112de3b87aSKai Wang 		return (rc);
12122de3b87aSKai Wang 	}
12132de3b87aSKai Wang 
12142de3b87aSKai Wang 	if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
12152de3b87aSKai Wang 		LIBELF_SET_ERROR(CLASS, 0);
12162de3b87aSKai Wang 		return (rc);
12172de3b87aSKai Wang 	}
12182de3b87aSKai Wang 
12192de3b87aSKai Wang 	if (e->e_version == EV_NONE)
12202de3b87aSKai Wang 		e->e_version = EV_CURRENT;
12212de3b87aSKai Wang 
12222de3b87aSKai Wang 	if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
12232de3b87aSKai Wang 		LIBELF_SET_ERROR(MODE, 0);
12242de3b87aSKai Wang 		return (rc);
12252de3b87aSKai Wang 	}
12262de3b87aSKai Wang 
12272de3b87aSKai Wang 	SLIST_INIT(&extents);
12282de3b87aSKai Wang 
12292de3b87aSKai Wang 	if ((rc = _libelf_resync_elf(e, &extents)) < 0)
12302de3b87aSKai Wang 		goto done;
12312de3b87aSKai Wang 
12322de3b87aSKai Wang 	if (c == ELF_C_NULL)
12332de3b87aSKai Wang 		goto done;
12342de3b87aSKai Wang 
12352de3b87aSKai Wang 	if (e->e_fd < 0) {
12362de3b87aSKai Wang 		rc = (off_t) -1;
12372de3b87aSKai Wang 		LIBELF_SET_ERROR(SEQUENCE, 0);
12382de3b87aSKai Wang 		goto done;
12392de3b87aSKai Wang 	}
12402de3b87aSKai Wang 
12412de3b87aSKai Wang 	rc = _libelf_write_elf(e, rc, &extents);
12422de3b87aSKai Wang 
12432de3b87aSKai Wang done:
12442de3b87aSKai Wang 	_libelf_release_extents(&extents);
1245bd6313b6SEd Maste 	e->e_flags &= ~LIBELF_F_SHDRS_LOADED;
12462de3b87aSKai Wang 	return (rc);
12472de3b87aSKai Wang }
1248