1164190Sjkoshy/*-
2176758Sjkoshy * Copyright (c) 2006-2008 Joseph Koshy
3164190Sjkoshy * All rights reserved.
4164190Sjkoshy *
5164190Sjkoshy * Redistribution and use in source and binary forms, with or without
6164190Sjkoshy * modification, are permitted provided that the following conditions
7164190Sjkoshy * are met:
8164190Sjkoshy * 1. Redistributions of source code must retain the above copyright
9164190Sjkoshy *    notice, this list of conditions and the following disclaimer.
10164190Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright
11164190Sjkoshy *    notice, this list of conditions and the following disclaimer in the
12164190Sjkoshy *    documentation and/or other materials provided with the distribution.
13164190Sjkoshy *
14164190Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15164190Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16164190Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17164190Sjkoshy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18164190Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19164190Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20164190Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21164190Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22164190Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23164190Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24164190Sjkoshy * SUCH DAMAGE.
25164190Sjkoshy */
26164190Sjkoshy
27164190Sjkoshy#include <sys/cdefs.h>
28164190Sjkoshy__FBSDID("$FreeBSD$");
29164190Sjkoshy
30164190Sjkoshy#include <sys/mman.h>
31164190Sjkoshy#include <sys/param.h>
32164190Sjkoshy
33164190Sjkoshy#include <assert.h>
34164190Sjkoshy#include <errno.h>
35164190Sjkoshy#include <gelf.h>
36164190Sjkoshy#include <libelf.h>
37164190Sjkoshy#include <stdlib.h>
38164190Sjkoshy#include <string.h>
39164190Sjkoshy#include <unistd.h>
40164190Sjkoshy
41164190Sjkoshy#include "_libelf.h"
42164190Sjkoshy
43164190Sjkoshy/*
44247221Smarkj * Layout strategy:
45164190Sjkoshy *
46247221Smarkj * - Case 1: ELF_F_LAYOUT is asserted
47247221Smarkj *     In this case the application has full control over where the
48247221Smarkj *     section header table, program header table, and section data
49247221Smarkj *     will reside.   The library only perform error checks.
50164190Sjkoshy *
51247221Smarkj * - Case 2: ELF_F_LAYOUT is not asserted
52164190Sjkoshy *
53247221Smarkj *     The library will do the object layout using the following
54247221Smarkj *     ordering:
55247221Smarkj *     - The executable header is placed first, are required by the
56247221Smarkj *     	 ELF specification.
57247221Smarkj *     - The program header table is placed immediately following the
58247221Smarkj *       executable header.
59247221Smarkj *     - Section data, if any, is placed after the program header
60247221Smarkj *       table, aligned appropriately.
61247221Smarkj *     - The section header table, if needed, is placed last.
62164190Sjkoshy *
63247221Smarkj *     There are two sub-cases to be taken care of:
64164190Sjkoshy *
65247221Smarkj *     - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR
66247221Smarkj *
67247221Smarkj *       In this sub-case, the underlying ELF object may already have
68247221Smarkj *       content in it, which the application may have modified.  The
69247221Smarkj *       library will retrieve content from the existing object as
70247221Smarkj *       needed.
71247221Smarkj *
72247221Smarkj *     - Case 2b: e->e_cmd == ELF_C_WRITE
73247221Smarkj *
74247221Smarkj *       The ELF object is being created afresh in this sub-case;
75247221Smarkj *       there is no pre-existing content in the underlying ELF
76247221Smarkj *       object.
77164190Sjkoshy */
78164190Sjkoshy
79164190Sjkoshy/*
80172088Sjkoshy * Compute the extents of a section, by looking at the data
81247221Smarkj * descriptors associated with it.  The function returns 1 if
82247221Smarkj * successful, or zero if an error was detected.
83164190Sjkoshy */
84164190Sjkoshystatic int
85247221Smarkj_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
86164190Sjkoshy{
87164190Sjkoshy	int ec;
88247221Smarkj	size_t fsz, msz;
89247221Smarkj	Elf_Data *d;
90247221Smarkj	Elf32_Shdr *shdr32;
91247221Smarkj	Elf64_Shdr *shdr64;
92164190Sjkoshy	unsigned int elftype;
93164190Sjkoshy	uint32_t sh_type;
94164190Sjkoshy	uint64_t d_align;
95164190Sjkoshy	uint64_t sh_align, sh_entsize, sh_offset, sh_size;
96164190Sjkoshy	uint64_t scn_size, scn_alignment;
97164190Sjkoshy
98164190Sjkoshy	ec = e->e_class;
99164190Sjkoshy
100247221Smarkj	shdr32 = &s->s_shdr.s_shdr32;
101247221Smarkj	shdr64 = &s->s_shdr.s_shdr64;
102164190Sjkoshy	if (ec == ELFCLASS32) {
103247221Smarkj		sh_type    = shdr32->sh_type;
104247221Smarkj		sh_align   = (uint64_t) shdr32->sh_addralign;
105247221Smarkj		sh_entsize = (uint64_t) shdr32->sh_entsize;
106247221Smarkj		sh_offset  = (uint64_t) shdr32->sh_offset;
107247221Smarkj		sh_size    = (uint64_t) shdr32->sh_size;
108164190Sjkoshy	} else {
109247221Smarkj		sh_type    = shdr64->sh_type;
110247221Smarkj		sh_align   = shdr64->sh_addralign;
111247221Smarkj		sh_entsize = shdr64->sh_entsize;
112247221Smarkj		sh_offset  = shdr64->sh_offset;
113247221Smarkj		sh_size    = shdr64->sh_size;
114164190Sjkoshy	}
115164190Sjkoshy
116247221Smarkj	assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS);
117164190Sjkoshy
118164190Sjkoshy	elftype = _libelf_xlate_shtype(sh_type);
119164190Sjkoshy	if (elftype > ELF_T_LAST) {
120164190Sjkoshy		LIBELF_SET_ERROR(SECTION, 0);
121164190Sjkoshy		return (0);
122164190Sjkoshy	}
123164190Sjkoshy
124164190Sjkoshy	if (sh_align == 0)
125164190Sjkoshy		sh_align = _libelf_falign(elftype, ec);
126164190Sjkoshy
127247221Smarkj	/*
128247221Smarkj	 * Check the section's data buffers for sanity and compute the
129247221Smarkj	 * section's alignment.
130247221Smarkj	 * Compute the section's size and alignment using the data
131247221Smarkj	 * descriptors associated with the section.
132247221Smarkj	 */
133247221Smarkj	if (STAILQ_EMPTY(&s->s_data)) {
134247221Smarkj		/*
135247221Smarkj		 * The section's content (if any) has not been read in
136247221Smarkj		 * yet.  If section is not dirty marked dirty, we can
137247221Smarkj		 * reuse the values in the 'sh_size' and 'sh_offset'
138247221Smarkj		 * fields of the section header.
139247221Smarkj		 */
140247221Smarkj		if ((s->s_flags & ELF_F_DIRTY) == 0) {
141247221Smarkj			/*
142247221Smarkj			 * If the library is doing the layout, then we
143247221Smarkj			 * compute the new start offset for the
144247221Smarkj			 * section based on the current offset and the
145247221Smarkj			 * section's alignment needs.
146247221Smarkj			 *
147247221Smarkj			 * If the application is doing the layout, we
148247221Smarkj			 * can use the value in the 'sh_offset' field
149247221Smarkj			 * in the section header directly.
150247221Smarkj			 */
151247221Smarkj			if (e->e_flags & ELF_F_LAYOUT)
152247221Smarkj				goto updatedescriptor;
153247221Smarkj			else
154247221Smarkj				goto computeoffset;
155247221Smarkj		}
156247221Smarkj
157247221Smarkj		/*
158247221Smarkj		 * Otherwise, we need to bring in the section's data
159247221Smarkj		 * from the underlying ELF object.
160247221Smarkj		 */
161247221Smarkj		if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL)
162247221Smarkj			return (0);
163247221Smarkj	}
164247221Smarkj
165247221Smarkj	/*
166247221Smarkj	 * Loop through the section's data descriptors.
167247221Smarkj	 */
168247221Smarkj	scn_size = 0L;
169247221Smarkj	scn_alignment = 0L;
170164190Sjkoshy	STAILQ_FOREACH(d, &s->s_data, d_next)  {
171212373Skaiw		if (d->d_type > ELF_T_LAST) {
172164190Sjkoshy			LIBELF_SET_ERROR(DATA, 0);
173164190Sjkoshy			return (0);
174164190Sjkoshy		}
175164190Sjkoshy		if (d->d_version != e->e_version) {
176164190Sjkoshy			LIBELF_SET_ERROR(VERSION, 0);
177164190Sjkoshy			return (0);
178164190Sjkoshy		}
179212373Skaiw		if ((d_align = d->d_align) == 0 || (d_align & (d_align - 1))) {
180164190Sjkoshy			LIBELF_SET_ERROR(DATA, 0);
181164190Sjkoshy			return (0);
182164190Sjkoshy		}
183164190Sjkoshy
184247221Smarkj		/*
185247221Smarkj		 * The buffer's size should be a multiple of the
186247221Smarkj		 * memory size of the underlying type.
187247221Smarkj		 */
188247221Smarkj		msz = _libelf_msize(d->d_type, ec, e->e_version);
189247221Smarkj		if (d->d_size % msz) {
190247221Smarkj			LIBELF_SET_ERROR(DATA, 0);
191247221Smarkj			return (0);
192247221Smarkj		}
193164190Sjkoshy
194247221Smarkj		/*
195247221Smarkj		 * Compute the section's size.
196247221Smarkj		 */
197164190Sjkoshy		if (e->e_flags & ELF_F_LAYOUT) {
198164190Sjkoshy			if ((uint64_t) d->d_off + d->d_size > scn_size)
199164190Sjkoshy				scn_size = d->d_off + d->d_size;
200164190Sjkoshy		} else {
201212373Skaiw			scn_size = roundup2(scn_size, d->d_align);
202164190Sjkoshy			d->d_off = scn_size;
203247221Smarkj			fsz = _libelf_fsize(d->d_type, ec, d->d_version,
204247221Smarkj			    d->d_size / msz);
205247221Smarkj			scn_size += fsz;
206164190Sjkoshy		}
207247221Smarkj
208247221Smarkj		/*
209247221Smarkj		 * The section's alignment is the maximum alignment
210247221Smarkj		 * needed for its data buffers.
211247221Smarkj		 */
212247221Smarkj		if (d_align > scn_alignment)
213247221Smarkj			scn_alignment = d_align;
214164190Sjkoshy	}
215164190Sjkoshy
216247221Smarkj
217164190Sjkoshy	/*
218164190Sjkoshy	 * If the application is requesting full control over the layout
219164190Sjkoshy	 * of the section, check its values for sanity.
220164190Sjkoshy	 */
221164190Sjkoshy	if (e->e_flags & ELF_F_LAYOUT) {
222164190Sjkoshy		if (scn_alignment > sh_align || sh_offset % sh_align ||
223164190Sjkoshy		    sh_size < scn_size) {
224164190Sjkoshy			LIBELF_SET_ERROR(LAYOUT, 0);
225164190Sjkoshy			return (0);
226164190Sjkoshy		}
227247221Smarkj		goto updatedescriptor;
228247221Smarkj	}
229164190Sjkoshy
230247221Smarkj	/*
231247221Smarkj	 * Otherwise compute the values in the section header.
232247221Smarkj	 *
233247221Smarkj	 * The section alignment is the maximum alignment for any of
234247221Smarkj	 * its contained data descriptors.
235247221Smarkj	 */
236247221Smarkj	if (scn_alignment > sh_align)
237247221Smarkj		sh_align = scn_alignment;
238164190Sjkoshy
239247221Smarkj	/*
240247221Smarkj	 * If the section entry size is zero, try and fill in an
241247221Smarkj	 * appropriate entry size.  Per the elf(5) manual page
242247221Smarkj	 * sections without fixed-size entries should have their
243247221Smarkj	 * 'sh_entsize' field set to zero.
244247221Smarkj	 */
245247221Smarkj	if (sh_entsize == 0 &&
246247221Smarkj	    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
247247221Smarkj	    (size_t) 1)) == 1)
248247221Smarkj		sh_entsize = 0;
249164190Sjkoshy
250247221Smarkj	sh_size = scn_size;
251164190Sjkoshy
252247221Smarkjcomputeoffset:
253247221Smarkj	/*
254247221Smarkj	 * Compute the new offset for the section based on
255247221Smarkj	 * the section's alignment needs.
256247221Smarkj	 */
257247221Smarkj	sh_offset = roundup(rc, sh_align);
258247221Smarkj
259247221Smarkj	/*
260247221Smarkj	 * Update the section header.
261247221Smarkj	 */
262247221Smarkj	if (ec == ELFCLASS32) {
263247221Smarkj		shdr32->sh_addralign = (uint32_t) sh_align;
264247221Smarkj		shdr32->sh_entsize   = (uint32_t) sh_entsize;
265247221Smarkj		shdr32->sh_offset    = (uint32_t) sh_offset;
266247221Smarkj		shdr32->sh_size      = (uint32_t) sh_size;
267247221Smarkj	} else {
268247221Smarkj		shdr64->sh_addralign = sh_align;
269247221Smarkj		shdr64->sh_entsize   = sh_entsize;
270247221Smarkj		shdr64->sh_offset    = sh_offset;
271247221Smarkj		shdr64->sh_size      = sh_size;
272164190Sjkoshy	}
273164190Sjkoshy
274247221Smarkjupdatedescriptor:
275247221Smarkj	/*
276247221Smarkj	 * Update the section descriptor.
277247221Smarkj	 */
278164190Sjkoshy	s->s_size = sh_size;
279164190Sjkoshy	s->s_offset = sh_offset;
280247221Smarkj
281164190Sjkoshy	return (1);
282164190Sjkoshy}
283164190Sjkoshy
284164190Sjkoshy
285164190Sjkoshy/*
286164190Sjkoshy * Insert a section in ascending order in the list
287164190Sjkoshy */
288164190Sjkoshy
289164190Sjkoshystatic int
290164190Sjkoshy_libelf_insert_section(Elf *e, Elf_Scn *s)
291164190Sjkoshy{
292164190Sjkoshy	Elf_Scn *t, *prevt;
293164190Sjkoshy	uint64_t smax, smin, tmax, tmin;
294164190Sjkoshy
295164190Sjkoshy	smin = s->s_offset;
296164190Sjkoshy	smax = smin + s->s_size;
297164190Sjkoshy
298164190Sjkoshy	prevt = NULL;
299164190Sjkoshy	STAILQ_FOREACH(t, &e->e_u.e_elf.e_scn, s_next) {
300164190Sjkoshy		tmin = t->s_offset;
301164190Sjkoshy		tmax = tmin + t->s_size;
302164190Sjkoshy
303176758Sjkoshy		if (tmax <= smin) {
304176758Sjkoshy			/*
305176758Sjkoshy			 * 't' lies entirely before 's': ...| t |...| s |...
306176758Sjkoshy			 */
307164190Sjkoshy			prevt = t;
308164190Sjkoshy			continue;
309176758Sjkoshy		} else if (smax <= tmin)
310176758Sjkoshy			/*
311176758Sjkoshy			 * 's' lies entirely before 't', and after 'prevt':
312176758Sjkoshy			 *      ...| prevt |...| s |...| t |...
313176758Sjkoshy			 */
314164190Sjkoshy			break;
315176758Sjkoshy		else {	/* 's' and 't' overlap. */
316164190Sjkoshy			LIBELF_SET_ERROR(LAYOUT, 0);
317164190Sjkoshy			return (0);
318164190Sjkoshy		}
319164190Sjkoshy	}
320164190Sjkoshy
321164190Sjkoshy	if (prevt)
322164190Sjkoshy		STAILQ_INSERT_AFTER(&e->e_u.e_elf.e_scn, prevt, s, s_next);
323164190Sjkoshy	else
324164190Sjkoshy		STAILQ_INSERT_HEAD(&e->e_u.e_elf.e_scn, s, s_next);
325164190Sjkoshy	return (1);
326164190Sjkoshy}
327164190Sjkoshy
328247221Smarkj/*
329247221Smarkj * Recompute section layout.
330247221Smarkj */
331247221Smarkj
332164190Sjkoshystatic off_t
333164190Sjkoshy_libelf_resync_sections(Elf *e, off_t rc)
334164190Sjkoshy{
335164190Sjkoshy	int ec;
336247221Smarkj	Elf_Scn *s;
337172088Sjkoshy	size_t sh_type, shdr_start, shdr_end;
338164190Sjkoshy
339164190Sjkoshy	ec = e->e_class;
340164190Sjkoshy
341164190Sjkoshy	/*
342164190Sjkoshy	 * Make a pass through sections, computing the extent of each
343164190Sjkoshy	 * section. Order in increasing order of addresses.
344164190Sjkoshy	 */
345247221Smarkj	STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) {
346164190Sjkoshy		if (ec == ELFCLASS32)
347164190Sjkoshy			sh_type = s->s_shdr.s_shdr32.sh_type;
348164190Sjkoshy		else
349164190Sjkoshy			sh_type = s->s_shdr.s_shdr64.sh_type;
350164190Sjkoshy
351164190Sjkoshy		if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
352164190Sjkoshy			continue;
353164190Sjkoshy
354247221Smarkj		if (_libelf_compute_section_extents(e, s, rc) == 0)
355247221Smarkj			return ((off_t) -1);
356247221Smarkj
357247221Smarkj		if (s->s_size == 0)
358247221Smarkj			continue;
359247221Smarkj
360247221Smarkj		if (s->s_offset + s->s_size < (size_t) rc) {
361247221Smarkj			/*
362247221Smarkj			 * Try insert this section in the
363247221Smarkj			 * correct place in the list,
364247221Smarkj			 * detecting overlaps if any.
365247221Smarkj			 */
366247221Smarkj			STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn,
367247221Smarkj			    s_next);
368247221Smarkj			if (_libelf_insert_section(e, s) == 0)
369164190Sjkoshy				return ((off_t) -1);
370164190Sjkoshy		} else
371164190Sjkoshy			rc = s->s_offset + s->s_size;
372164190Sjkoshy	}
373164190Sjkoshy
374172088Sjkoshy	/*
375172088Sjkoshy	 * If the application is controlling file layout, check for an
376172088Sjkoshy	 * overlap between this section's extents and the SHDR table.
377172088Sjkoshy	 */
378172088Sjkoshy	if (e->e_flags & ELF_F_LAYOUT) {
379172088Sjkoshy
380172088Sjkoshy		if (e->e_class == ELFCLASS32)
381172088Sjkoshy			shdr_start = e->e_u.e_elf.e_ehdr.e_ehdr32->e_shoff;
382172088Sjkoshy		else
383172088Sjkoshy			shdr_start = e->e_u.e_elf.e_ehdr.e_ehdr64->e_shoff;
384172088Sjkoshy
385172088Sjkoshy		shdr_end = shdr_start + _libelf_fsize(ELF_T_SHDR, e->e_class,
386172088Sjkoshy		    e->e_version, e->e_u.e_elf.e_nscn);
387172088Sjkoshy
388172088Sjkoshy		STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) {
389172088Sjkoshy			if (s->s_offset >= shdr_end ||
390172088Sjkoshy			    s->s_offset + s->s_size <= shdr_start)
391172088Sjkoshy				continue;
392172088Sjkoshy			LIBELF_SET_ERROR(LAYOUT, 0);
393172088Sjkoshy			return ((off_t) -1);
394172088Sjkoshy		}
395172088Sjkoshy	}
396172088Sjkoshy
397164190Sjkoshy	return (rc);
398164190Sjkoshy}
399164190Sjkoshy
400164190Sjkoshystatic off_t
401164190Sjkoshy_libelf_resync_elf(Elf *e)
402164190Sjkoshy{
403164190Sjkoshy	int ec, eh_class, eh_type;
404164190Sjkoshy	unsigned int eh_byteorder, eh_version;
405164190Sjkoshy	size_t align, fsz;
406164190Sjkoshy	size_t phnum, shnum;
407164190Sjkoshy	off_t rc, phoff, shoff;
408164190Sjkoshy	void *ehdr;
409164190Sjkoshy	Elf32_Ehdr *eh32;
410164190Sjkoshy	Elf64_Ehdr *eh64;
411164190Sjkoshy
412164190Sjkoshy	rc = 0;
413164190Sjkoshy
414164190Sjkoshy	ec = e->e_class;
415164190Sjkoshy
416164190Sjkoshy	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
417164190Sjkoshy
418164190Sjkoshy	/*
419164190Sjkoshy	 * Prepare the EHDR.
420164190Sjkoshy	 */
421164190Sjkoshy	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
422164190Sjkoshy		return ((off_t) -1);
423164190Sjkoshy
424164190Sjkoshy	eh32 = ehdr;
425164190Sjkoshy	eh64 = ehdr;
426164190Sjkoshy
427164190Sjkoshy	if (ec == ELFCLASS32) {
428164190Sjkoshy		eh_byteorder = eh32->e_ident[EI_DATA];
429164190Sjkoshy		eh_class     = eh32->e_ident[EI_CLASS];
430164190Sjkoshy		phoff        = (uint64_t) eh32->e_phoff;
431164190Sjkoshy		shoff        = (uint64_t) eh32->e_shoff;
432164190Sjkoshy		eh_type      = eh32->e_type;
433164190Sjkoshy		eh_version   = eh32->e_version;
434164190Sjkoshy	} else {
435164190Sjkoshy		eh_byteorder = eh64->e_ident[EI_DATA];
436164190Sjkoshy		eh_class     = eh64->e_ident[EI_CLASS];
437164190Sjkoshy		phoff        = eh64->e_phoff;
438164190Sjkoshy		shoff        = eh64->e_shoff;
439164190Sjkoshy		eh_type      = eh64->e_type;
440164190Sjkoshy		eh_version   = eh64->e_version;
441164190Sjkoshy	}
442164190Sjkoshy
443164190Sjkoshy	if (eh_version == EV_NONE)
444164190Sjkoshy		eh_version = EV_CURRENT;
445164190Sjkoshy
446164190Sjkoshy	if (eh_version != e->e_version) {	/* always EV_CURRENT */
447164190Sjkoshy		LIBELF_SET_ERROR(VERSION, 0);
448164190Sjkoshy		return ((off_t) -1);
449164190Sjkoshy	}
450164190Sjkoshy
451164190Sjkoshy	if (eh_class != e->e_class) {
452164190Sjkoshy		LIBELF_SET_ERROR(CLASS, 0);
453164190Sjkoshy		return ((off_t) -1);
454164190Sjkoshy	}
455164190Sjkoshy
456164190Sjkoshy	if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
457164190Sjkoshy		LIBELF_SET_ERROR(HEADER, 0);
458164190Sjkoshy		return ((off_t) -1);
459164190Sjkoshy	}
460164190Sjkoshy
461165535Sjkoshy	shnum = e->e_u.e_elf.e_nscn;
462165535Sjkoshy	phnum = e->e_u.e_elf.e_nphdr;
463164190Sjkoshy
464164190Sjkoshy	e->e_byteorder = eh_byteorder;
465164190Sjkoshy
466164190Sjkoshy#define	INITIALIZE_EHDR(E,EC,V)	do {					\
467164190Sjkoshy		(E)->e_ident[EI_MAG0] = ELFMAG0;			\
468164190Sjkoshy		(E)->e_ident[EI_MAG1] = ELFMAG1;			\
469164190Sjkoshy		(E)->e_ident[EI_MAG2] = ELFMAG2;			\
470164190Sjkoshy		(E)->e_ident[EI_MAG3] = ELFMAG3;			\
471164190Sjkoshy		(E)->e_ident[EI_CLASS] = (EC);				\
472164190Sjkoshy		(E)->e_ident[EI_VERSION] = (V);				\
473164190Sjkoshy		(E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V),	\
474164190Sjkoshy		    (size_t) 1);					\
475210326Skaiw		(E)->e_phentsize = (phnum == 0) ? 0 : _libelf_fsize(	\
476210326Skaiw		    ELF_T_PHDR, (EC), (V), (size_t) 1);			\
477164190Sjkoshy		(E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V),	\
478164190Sjkoshy		    (size_t) 1);					\
479164190Sjkoshy	} while (0)
480164190Sjkoshy
481164190Sjkoshy	if (ec == ELFCLASS32)
482164190Sjkoshy		INITIALIZE_EHDR(eh32, ec, eh_version);
483164190Sjkoshy	else
484164190Sjkoshy		INITIALIZE_EHDR(eh64, ec, eh_version);
485164190Sjkoshy
486164190Sjkoshy	(void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
487164190Sjkoshy
488164190Sjkoshy	rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1);
489164190Sjkoshy
490164190Sjkoshy	/*
491164190Sjkoshy	 * Compute the layout the program header table, if one is
492164190Sjkoshy	 * present.  The program header table needs to be aligned to a
493164190Sjkoshy	 * `natural' boundary.
494164190Sjkoshy	 */
495164190Sjkoshy	if (phnum) {
496164190Sjkoshy		fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
497164190Sjkoshy		align = _libelf_falign(ELF_T_PHDR, ec);
498164190Sjkoshy
499164190Sjkoshy		if (e->e_flags & ELF_F_LAYOUT) {
500164190Sjkoshy			/*
501164190Sjkoshy			 * Check offsets for sanity.
502164190Sjkoshy			 */
503164190Sjkoshy			if (rc > phoff) {
504164190Sjkoshy				LIBELF_SET_ERROR(HEADER, 0);
505164190Sjkoshy				return ((off_t) -1);
506164190Sjkoshy			}
507164190Sjkoshy
508164190Sjkoshy			if (phoff % align) {
509164190Sjkoshy				LIBELF_SET_ERROR(LAYOUT, 0);
510164190Sjkoshy				return ((off_t) -1);
511164190Sjkoshy			}
512164190Sjkoshy
513164190Sjkoshy		} else
514164190Sjkoshy			phoff = roundup(rc, align);
515164190Sjkoshy
516164190Sjkoshy		rc = phoff + fsz;
517164190Sjkoshy	} else
518164190Sjkoshy		phoff = 0;
519164190Sjkoshy
520164190Sjkoshy	/*
521164190Sjkoshy	 * Compute the layout of the sections associated with the
522164190Sjkoshy	 * file.
523164190Sjkoshy	 */
524164190Sjkoshy
525210330Skaiw	if (e->e_cmd != ELF_C_WRITE &&
526210330Skaiw	    (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
527210330Skaiw	    _libelf_load_scn(e, ehdr) == 0)
528210330Skaiw		return ((off_t) -1);
529210330Skaiw
530164190Sjkoshy	if ((rc = _libelf_resync_sections(e, rc)) < 0)
531164190Sjkoshy		return ((off_t) -1);
532164190Sjkoshy
533164190Sjkoshy	/*
534164190Sjkoshy	 * Compute the space taken up by the section header table, if
535172088Sjkoshy	 * one is needed.  If ELF_F_LAYOUT is asserted, the
536172088Sjkoshy	 * application may have placed the section header table in
537172088Sjkoshy	 * between existing sections, so the net size of the file need
538172088Sjkoshy	 * not increase due to the presence of the section header
539172088Sjkoshy	 * table.
540164190Sjkoshy	 */
541164190Sjkoshy	if (shnum) {
542164190Sjkoshy		fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, (size_t) 1);
543164190Sjkoshy		align = _libelf_falign(ELF_T_SHDR, ec);
544164190Sjkoshy
545164190Sjkoshy		if (e->e_flags & ELF_F_LAYOUT) {
546164190Sjkoshy			if (shoff % align) {
547164190Sjkoshy				LIBELF_SET_ERROR(LAYOUT, 0);
548164190Sjkoshy				return ((off_t) -1);
549164190Sjkoshy			}
550164190Sjkoshy		} else
551164190Sjkoshy			shoff = roundup(rc, align);
552164190Sjkoshy
553172088Sjkoshy		if (shoff + fsz * shnum > (size_t) rc)
554172088Sjkoshy			rc = shoff + fsz * shnum;
555164190Sjkoshy	} else
556164190Sjkoshy		shoff = 0;
557164190Sjkoshy
558164190Sjkoshy	/*
559165535Sjkoshy	 * Set the fields of the Executable Header that could potentially use
560165535Sjkoshy	 * extended numbering.
561165535Sjkoshy	 */
562165535Sjkoshy	_libelf_setphnum(e, ehdr, ec, phnum);
563165535Sjkoshy	_libelf_setshnum(e, ehdr, ec, shnum);
564165535Sjkoshy
565165535Sjkoshy	/*
566164190Sjkoshy	 * Update the `e_phoff' and `e_shoff' fields if the library is
567164190Sjkoshy	 * doing the layout.
568164190Sjkoshy	 */
569164190Sjkoshy	if ((e->e_flags & ELF_F_LAYOUT) == 0) {
570164190Sjkoshy		if (ec == ELFCLASS32) {
571164190Sjkoshy			eh32->e_phoff = (uint32_t) phoff;
572164190Sjkoshy			eh32->e_shoff = (uint32_t) shoff;
573164190Sjkoshy		} else {
574164190Sjkoshy			eh64->e_phoff = (uint64_t) phoff;
575164190Sjkoshy			eh64->e_shoff = (uint64_t) shoff;
576164190Sjkoshy		}
577164190Sjkoshy	}
578164190Sjkoshy
579164190Sjkoshy	return (rc);
580164190Sjkoshy}
581164190Sjkoshy
582164190Sjkoshy/*
583164190Sjkoshy * Write out the contents of a section.
584164190Sjkoshy */
585164190Sjkoshy
586164190Sjkoshystatic off_t
587164190Sjkoshy_libelf_write_scn(Elf *e, char *nf, Elf_Scn *s, off_t rc)
588164190Sjkoshy{
589164190Sjkoshy	int ec;
590164190Sjkoshy	size_t fsz, msz, nobjects;
591164190Sjkoshy	uint32_t sh_type;
592210328Skaiw	uint64_t sh_off, sh_size;
593164190Sjkoshy	int elftype;
594164190Sjkoshy	Elf_Data *d, dst;
595164190Sjkoshy
596210328Skaiw	if ((ec = e->e_class) == ELFCLASS32) {
597164190Sjkoshy		sh_type = s->s_shdr.s_shdr32.sh_type;
598210328Skaiw		sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
599210328Skaiw	} else {
600164190Sjkoshy		sh_type = s->s_shdr.s_shdr64.sh_type;
601210328Skaiw		sh_size = s->s_shdr.s_shdr64.sh_size;
602210328Skaiw	}
603164190Sjkoshy
604164190Sjkoshy	/*
605164190Sjkoshy	 * Ignore sections that do not allocate space in the file.
606164190Sjkoshy	 */
607210328Skaiw	if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0)
608164190Sjkoshy		return (rc);
609164190Sjkoshy
610164190Sjkoshy	elftype = _libelf_xlate_shtype(sh_type);
611164190Sjkoshy	assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
612164190Sjkoshy
613164190Sjkoshy	sh_off = s->s_offset;
614164190Sjkoshy	assert(sh_off % _libelf_falign(elftype, ec) == 0);
615164190Sjkoshy
616164190Sjkoshy	/*
617164190Sjkoshy	 * If the section has a `rawdata' descriptor, and the section
618164190Sjkoshy	 * contents have not been modified, use its contents directly.
619164190Sjkoshy	 * The `s_rawoff' member contains the offset into the original
620164190Sjkoshy	 * file, while `s_offset' contains its new location in the
621164190Sjkoshy	 * destination.
622164190Sjkoshy	 */
623164190Sjkoshy
624164190Sjkoshy	if (STAILQ_EMPTY(&s->s_data)) {
625164190Sjkoshy
626164190Sjkoshy		if ((d = elf_rawdata(s, NULL)) == NULL)
627164190Sjkoshy			return ((off_t) -1);
628164190Sjkoshy
629164190Sjkoshy		STAILQ_FOREACH(d, &s->s_rawdata, d_next) {
630164190Sjkoshy			if ((uint64_t) rc < sh_off + d->d_off)
631164190Sjkoshy				(void) memset(nf + rc,
632164190Sjkoshy				    LIBELF_PRIVATE(fillchar), sh_off +
633164190Sjkoshy				    d->d_off - rc);
634164190Sjkoshy			rc = sh_off + d->d_off;
635164190Sjkoshy
636164190Sjkoshy			assert(d->d_buf != NULL);
637164190Sjkoshy			assert(d->d_type == ELF_T_BYTE);
638164190Sjkoshy			assert(d->d_version == e->e_version);
639164190Sjkoshy
640164190Sjkoshy			(void) memcpy(nf + rc,
641164190Sjkoshy			    e->e_rawfile + s->s_rawoff + d->d_off, d->d_size);
642164190Sjkoshy
643164190Sjkoshy			rc += d->d_size;
644164190Sjkoshy		}
645164190Sjkoshy
646164190Sjkoshy		return (rc);
647164190Sjkoshy	}
648164190Sjkoshy
649164190Sjkoshy	/*
650164190Sjkoshy	 * Iterate over the set of data descriptors for this section.
651164190Sjkoshy	 * The prior call to _libelf_resync_elf() would have setup the
652164190Sjkoshy	 * descriptors for this step.
653164190Sjkoshy	 */
654164190Sjkoshy
655164190Sjkoshy	dst.d_version = e->e_version;
656164190Sjkoshy
657164190Sjkoshy	STAILQ_FOREACH(d, &s->s_data, d_next) {
658164190Sjkoshy
659212373Skaiw		msz = _libelf_msize(d->d_type, ec, e->e_version);
660212373Skaiw
661164190Sjkoshy		if ((uint64_t) rc < sh_off + d->d_off)
662164190Sjkoshy			(void) memset(nf + rc,
663164190Sjkoshy			    LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc);
664164190Sjkoshy
665164190Sjkoshy		rc = sh_off + d->d_off;
666164190Sjkoshy
667164190Sjkoshy		assert(d->d_buf != NULL);
668164190Sjkoshy		assert(d->d_version == e->e_version);
669164190Sjkoshy		assert(d->d_size % msz == 0);
670164190Sjkoshy
671164190Sjkoshy		nobjects = d->d_size / msz;
672164190Sjkoshy
673212373Skaiw		fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects);
674164190Sjkoshy
675164190Sjkoshy		dst.d_buf    = nf + rc;
676164190Sjkoshy		dst.d_size   = fsz;
677164190Sjkoshy
678164190Sjkoshy		if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) ==
679164190Sjkoshy		    NULL)
680164190Sjkoshy			return ((off_t) -1);
681164190Sjkoshy
682164190Sjkoshy		rc += fsz;
683164190Sjkoshy	}
684164190Sjkoshy
685164190Sjkoshy	return ((off_t) rc);
686164190Sjkoshy}
687164190Sjkoshy
688164190Sjkoshy/*
689164190Sjkoshy * Write out the file image.
690164190Sjkoshy *
691164190Sjkoshy * The original file could have been mapped in with an ELF_C_RDWR
692164190Sjkoshy * command and the application could have added new content or
693164190Sjkoshy * re-arranged its sections before calling elf_update().  Consequently
694164190Sjkoshy * its not safe to work `in place' on the original file.  So we
695164190Sjkoshy * malloc() the required space for the updated ELF object and build
696164190Sjkoshy * the object there and write it out to the underlying file at the
697164190Sjkoshy * end.  Note that the application may have opened the underlying file
698164190Sjkoshy * in ELF_C_RDWR and only retrieved/modified a few sections.  We take
699164190Sjkoshy * care to avoid translating file sections unnecessarily.
700164190Sjkoshy *
701164190Sjkoshy * Gaps in the coverage of the file by the file's sections will be
702164190Sjkoshy * filled with the fill character set by elf_fill(3).
703164190Sjkoshy */
704164190Sjkoshy
705164190Sjkoshystatic off_t
706164190Sjkoshy_libelf_write_elf(Elf *e, off_t newsize)
707164190Sjkoshy{
708164190Sjkoshy	int ec;
709172088Sjkoshy	off_t maxrc, rc;
710164190Sjkoshy	size_t fsz, msz, phnum, shnum;
711164190Sjkoshy	uint64_t phoff, shoff;
712164190Sjkoshy	void *ehdr;
713164190Sjkoshy	char *newfile;
714164190Sjkoshy	Elf_Data dst, src;
715164190Sjkoshy	Elf_Scn *scn, *tscn;
716164190Sjkoshy	Elf32_Ehdr *eh32;
717164190Sjkoshy	Elf64_Ehdr *eh64;
718164190Sjkoshy
719164190Sjkoshy	assert(e->e_kind == ELF_K_ELF);
720164190Sjkoshy	assert(e->e_cmd != ELF_C_READ);
721164190Sjkoshy	assert(e->e_fd >= 0);
722164190Sjkoshy
723164190Sjkoshy	if ((newfile = malloc((size_t) newsize)) == NULL) {
724164190Sjkoshy		LIBELF_SET_ERROR(RESOURCE, errno);
725164190Sjkoshy		return ((off_t) -1);
726164190Sjkoshy	}
727164190Sjkoshy
728164190Sjkoshy	ec = e->e_class;
729164190Sjkoshy
730164190Sjkoshy	ehdr = _libelf_ehdr(e, ec, 0);
731164190Sjkoshy	assert(ehdr != NULL);
732164190Sjkoshy
733165535Sjkoshy	phnum = e->e_u.e_elf.e_nphdr;
734165535Sjkoshy
735164190Sjkoshy	if (ec == ELFCLASS32) {
736164190Sjkoshy		eh32 = (Elf32_Ehdr *) ehdr;
737164190Sjkoshy
738164190Sjkoshy		phoff = (uint64_t) eh32->e_phoff;
739164190Sjkoshy		shnum = eh32->e_shnum;
740164190Sjkoshy		shoff = (uint64_t) eh32->e_shoff;
741164190Sjkoshy	} else {
742164190Sjkoshy		eh64 = (Elf64_Ehdr *) ehdr;
743164190Sjkoshy
744164190Sjkoshy		phoff = eh64->e_phoff;
745164190Sjkoshy		shnum = eh64->e_shnum;
746164190Sjkoshy		shoff = eh64->e_shoff;
747164190Sjkoshy	}
748164190Sjkoshy
749164190Sjkoshy	fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
750164190Sjkoshy	msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);
751164190Sjkoshy
752164190Sjkoshy	(void) memset(&dst, 0, sizeof(dst));
753164190Sjkoshy	(void) memset(&src, 0, sizeof(src));
754164190Sjkoshy
755164190Sjkoshy	src.d_buf     = ehdr;
756164190Sjkoshy	src.d_size    = msz;
757164190Sjkoshy	src.d_type    = ELF_T_EHDR;
758164190Sjkoshy	src.d_version = dst.d_version = e->e_version;
759164190Sjkoshy
760164190Sjkoshy	rc = 0;
761164190Sjkoshy
762164190Sjkoshy	dst.d_buf     = newfile + rc;
763164190Sjkoshy	dst.d_size    = fsz;
764164190Sjkoshy
765164190Sjkoshy	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
766164190Sjkoshy	    NULL)
767164190Sjkoshy		goto error;
768164190Sjkoshy
769164190Sjkoshy	rc += fsz;
770164190Sjkoshy
771164190Sjkoshy	/*
772164190Sjkoshy	 * Write the program header table if present.
773164190Sjkoshy	 */
774164190Sjkoshy
775164190Sjkoshy	if (phnum != 0 && phoff != 0) {
776164190Sjkoshy		assert((unsigned) rc <= phoff);
777164190Sjkoshy
778164190Sjkoshy		fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
779164190Sjkoshy
780164190Sjkoshy		assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);
781164190Sjkoshy		assert(fsz > 0);
782164190Sjkoshy
783210330Skaiw		src.d_buf = _libelf_getphdr(e, ec);
784164190Sjkoshy		src.d_version = dst.d_version = e->e_version;
785164190Sjkoshy		src.d_type = ELF_T_PHDR;
786164190Sjkoshy		src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,
787164190Sjkoshy		    e->e_version);
788164190Sjkoshy
789164190Sjkoshy		dst.d_size = fsz;
790164190Sjkoshy
791164190Sjkoshy		if ((uint64_t) rc < phoff)
792164190Sjkoshy			(void) memset(newfile + rc,
793164190Sjkoshy			    LIBELF_PRIVATE(fillchar), phoff - rc);
794164190Sjkoshy
795164190Sjkoshy		dst.d_buf = newfile + rc;
796164190Sjkoshy
797164190Sjkoshy		if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
798164190Sjkoshy		    NULL)
799164190Sjkoshy			goto error;
800164190Sjkoshy
801164190Sjkoshy		rc = phoff + fsz;
802164190Sjkoshy	}
803164190Sjkoshy
804164190Sjkoshy	/*
805164190Sjkoshy	 * Write out individual sections.
806164190Sjkoshy	 */
807164190Sjkoshy
808164190Sjkoshy	STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next)
809164190Sjkoshy 		if ((rc = _libelf_write_scn(e, newfile, scn, rc)) < 0)
810164190Sjkoshy			goto error;
811164190Sjkoshy
812164190Sjkoshy	/*
813172088Sjkoshy	 * Write out the section header table, if required.  Note that
814172088Sjkoshy	 * if flag ELF_F_LAYOUT has been set the section header table
815172088Sjkoshy	 * could reside in between byte ranges mapped by section
816172088Sjkoshy	 * descriptors.
817164190Sjkoshy	 */
818164190Sjkoshy	if (shnum != 0 && shoff != 0) {
819164190Sjkoshy		if ((uint64_t) rc < shoff)
820164190Sjkoshy			(void) memset(newfile + rc,
821164190Sjkoshy			    LIBELF_PRIVATE(fillchar), shoff - rc);
822164190Sjkoshy
823172088Sjkoshy		maxrc = rc;
824164190Sjkoshy		rc = shoff;
825164190Sjkoshy
826164190Sjkoshy		assert(rc % _libelf_falign(ELF_T_SHDR, ec) == 0);
827164190Sjkoshy
828164190Sjkoshy		src.d_type = ELF_T_SHDR;
829164190Sjkoshy		src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);
830164190Sjkoshy		src.d_version = dst.d_version = e->e_version;
831164190Sjkoshy
832164190Sjkoshy		fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
833164190Sjkoshy
834164190Sjkoshy		STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) {
835164190Sjkoshy			if (ec == ELFCLASS32)
836164190Sjkoshy				src.d_buf = &scn->s_shdr.s_shdr32;
837164190Sjkoshy			else
838164190Sjkoshy				src.d_buf = &scn->s_shdr.s_shdr64;
839164190Sjkoshy
840164190Sjkoshy			dst.d_size = fsz;
841177367Sjkoshy			dst.d_buf = newfile + rc + scn->s_ndx * fsz;
842164190Sjkoshy
843164190Sjkoshy			if (_libelf_xlate(&dst, &src, e->e_byteorder, ec,
844164190Sjkoshy				ELF_TOFILE) != &dst)
845164190Sjkoshy				goto error;
846164190Sjkoshy		}
847172088Sjkoshy
848177367Sjkoshy		rc += e->e_u.e_elf.e_nscn * fsz;
849172088Sjkoshy		if (maxrc > rc)
850172088Sjkoshy			rc = maxrc;
851164190Sjkoshy	}
852164190Sjkoshy
853164190Sjkoshy	assert(rc == newsize);
854164190Sjkoshy
855164190Sjkoshy	/*
856164190Sjkoshy	 * Write out the constructed contents and remap the file in
857164190Sjkoshy	 * read-only.
858164190Sjkoshy	 */
859164190Sjkoshy
860164190Sjkoshy	if (e->e_rawfile && munmap(e->e_rawfile, e->e_rawsize) < 0) {
861164190Sjkoshy		LIBELF_SET_ERROR(IO, errno);
862164190Sjkoshy		goto error;
863164190Sjkoshy	}
864164190Sjkoshy
865164190Sjkoshy	if (write(e->e_fd, newfile, (size_t) newsize) != newsize ||
866164190Sjkoshy	    lseek(e->e_fd, (off_t) 0, SEEK_SET) < 0) {
867164190Sjkoshy		LIBELF_SET_ERROR(IO, errno);
868164190Sjkoshy		goto error;
869164190Sjkoshy	}
870164190Sjkoshy
871164190Sjkoshy	if (e->e_cmd != ELF_C_WRITE) {
872164190Sjkoshy		if ((e->e_rawfile = mmap(NULL, (size_t) newsize, PROT_READ,
873164190Sjkoshy		    MAP_PRIVATE, e->e_fd, (off_t) 0)) == MAP_FAILED) {
874164190Sjkoshy			LIBELF_SET_ERROR(IO, errno);
875164190Sjkoshy			goto error;
876164190Sjkoshy		}
877164190Sjkoshy		e->e_rawsize = newsize;
878164190Sjkoshy	}
879164190Sjkoshy
880164190Sjkoshy	/*
881164190Sjkoshy	 * Reset flags, remove existing section descriptors and
882164190Sjkoshy	 * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
883164190Sjkoshy	 * and elf_getscn() will function correctly.
884164190Sjkoshy	 */
885164190Sjkoshy
886164190Sjkoshy	e->e_flags &= ~ELF_F_DIRTY;
887164190Sjkoshy
888164190Sjkoshy	STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)
889164190Sjkoshy		_libelf_release_scn(scn);
890164190Sjkoshy
891164190Sjkoshy	if (ec == ELFCLASS32) {
892164190Sjkoshy		free(e->e_u.e_elf.e_ehdr.e_ehdr32);
893164190Sjkoshy		if (e->e_u.e_elf.e_phdr.e_phdr32)
894164190Sjkoshy			free(e->e_u.e_elf.e_phdr.e_phdr32);
895164190Sjkoshy
896164190Sjkoshy		e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
897164190Sjkoshy		e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
898164190Sjkoshy	} else {
899164190Sjkoshy		free(e->e_u.e_elf.e_ehdr.e_ehdr64);
900164190Sjkoshy		if (e->e_u.e_elf.e_phdr.e_phdr64)
901164190Sjkoshy			free(e->e_u.e_elf.e_phdr.e_phdr64);
902164190Sjkoshy
903164190Sjkoshy		e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
904164190Sjkoshy		e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
905164190Sjkoshy	}
906164190Sjkoshy
907210347Skaiw	free(newfile);
908210347Skaiw
909164190Sjkoshy	return (rc);
910164190Sjkoshy
911164190Sjkoshy error:
912210347Skaiw	free(newfile);
913210347Skaiw
914164190Sjkoshy	return ((off_t) -1);
915164190Sjkoshy}
916164190Sjkoshy
917164190Sjkoshyoff_t
918164190Sjkoshyelf_update(Elf *e, Elf_Cmd c)
919164190Sjkoshy{
920164190Sjkoshy	int ec;
921164190Sjkoshy	off_t rc;
922164190Sjkoshy
923164190Sjkoshy	rc = (off_t) -1;
924164190Sjkoshy
925164190Sjkoshy	if (e == NULL || e->e_kind != ELF_K_ELF ||
926164190Sjkoshy	    (c != ELF_C_NULL && c != ELF_C_WRITE)) {
927164190Sjkoshy		LIBELF_SET_ERROR(ARGUMENT, 0);
928164190Sjkoshy		return (rc);
929164190Sjkoshy	}
930164190Sjkoshy
931164190Sjkoshy	if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
932164190Sjkoshy		LIBELF_SET_ERROR(CLASS, 0);
933164190Sjkoshy		return (rc);
934164190Sjkoshy	}
935164190Sjkoshy
936164190Sjkoshy	if (e->e_version == EV_NONE)
937164190Sjkoshy		e->e_version = EV_CURRENT;
938164190Sjkoshy
939164190Sjkoshy	if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
940164190Sjkoshy		LIBELF_SET_ERROR(MODE, 0);
941164190Sjkoshy		return (rc);
942164190Sjkoshy	}
943164190Sjkoshy
944164190Sjkoshy	if ((rc = _libelf_resync_elf(e)) < 0)
945164190Sjkoshy		return (rc);
946164190Sjkoshy
947164190Sjkoshy	if (c == ELF_C_NULL)
948164190Sjkoshy		return (rc);
949164190Sjkoshy
950164190Sjkoshy	if (e->e_cmd == ELF_C_READ) {
951164190Sjkoshy		/*
952164190Sjkoshy		 * This descriptor was opened in read-only mode or by
953164190Sjkoshy		 * elf_memory().
954164190Sjkoshy		 */
955164190Sjkoshy		if (e->e_fd)
956164190Sjkoshy			LIBELF_SET_ERROR(MODE, 0);
957164190Sjkoshy		else
958164190Sjkoshy			LIBELF_SET_ERROR(ARGUMENT, 0);
959164190Sjkoshy		return ((off_t) -1);
960164190Sjkoshy	}
961164190Sjkoshy
962164190Sjkoshy	if (e->e_fd < 0) {
963164190Sjkoshy		LIBELF_SET_ERROR(SEQUENCE, 0);
964164190Sjkoshy		return ((off_t) -1);
965164190Sjkoshy	}
966164190Sjkoshy
967164190Sjkoshy	return (_libelf_write_elf(e, rc));
968164190Sjkoshy}
969