14484Sbinkertn@umich.edu/*- 24484Sbinkertn@umich.edu * Copyright (c) 2006 Joseph Koshy 34484Sbinkertn@umich.edu * All rights reserved. 44484Sbinkertn@umich.edu * 54484Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without 64484Sbinkertn@umich.edu * modification, are permitted provided that the following conditions 74484Sbinkertn@umich.edu * are met: 84484Sbinkertn@umich.edu * 1. Redistributions of source code must retain the above copyright 94484Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer. 104484Sbinkertn@umich.edu * 2. Redistributions in binary form must reproduce the above copyright 114484Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the 124484Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution. 134484Sbinkertn@umich.edu * 144484Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154484Sbinkertn@umich.edu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164484Sbinkertn@umich.edu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174484Sbinkertn@umich.edu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184484Sbinkertn@umich.edu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194484Sbinkertn@umich.edu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204484Sbinkertn@umich.edu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214484Sbinkertn@umich.edu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224484Sbinkertn@umich.edu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234484Sbinkertn@umich.edu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244484Sbinkertn@umich.edu * SUCH DAMAGE. 254484Sbinkertn@umich.edu */ 264484Sbinkertn@umich.edu 274484Sbinkertn@umich.edu 284484Sbinkertn@umich.edu#include <sys/mman.h> 294484Sbinkertn@umich.edu#include <sys/param.h> 304494Ssaidi@eecs.umich.edu#ifdef __sun 314494Ssaidi@eecs.umich.edu#include <sys/sysmacros.h> 324494Ssaidi@eecs.umich.edu#endif 334484Sbinkertn@umich.edu 344484Sbinkertn@umich.edu#include <assert.h> 354484Sbinkertn@umich.edu#include <errno.h> 364484Sbinkertn@umich.edu#include "gelf.h" 374484Sbinkertn@umich.edu#include "libelf.h" 384484Sbinkertn@umich.edu#include <stdlib.h> 394484Sbinkertn@umich.edu#include <string.h> 404484Sbinkertn@umich.edu#include <unistd.h> 414484Sbinkertn@umich.edu 424484Sbinkertn@umich.edu#include "_libelf.h" 434484Sbinkertn@umich.edu 444484Sbinkertn@umich.edu/* 454484Sbinkertn@umich.edu * Update the internal data structures associated with an ELF object. 464484Sbinkertn@umich.edu * Returns the size in bytes the ELF object would occupy in its file 474484Sbinkertn@umich.edu * representation. 484484Sbinkertn@umich.edu * 494484Sbinkertn@umich.edu * After a successful call to this function, the following structures 504484Sbinkertn@umich.edu * are updated: 514484Sbinkertn@umich.edu * 524484Sbinkertn@umich.edu * - The ELF header is updated. 534484Sbinkertn@umich.edu * - All sections are sorted in order of ascending addresses and their 544484Sbinkertn@umich.edu * section header table entries updated. An error is signalled 554484Sbinkertn@umich.edu * if an overlap was detected among sections. 564484Sbinkertn@umich.edu * - All data descriptors associated with a section are sorted in order 574484Sbinkertn@umich.edu * of ascending addresses. Overlaps, if detected, are signalled as 584484Sbinkertn@umich.edu * errors. Other sanity checks for alignments, section types etc. are 594484Sbinkertn@umich.edu * made. 604484Sbinkertn@umich.edu * 614484Sbinkertn@umich.edu * After a resync_elf() successfully returns, the ELF descriptor is 624484Sbinkertn@umich.edu * ready for being handed over to _libelf_write_elf(). 634484Sbinkertn@umich.edu * 644484Sbinkertn@umich.edu * File alignments: 654484Sbinkertn@umich.edu * PHDR - Addr 664484Sbinkertn@umich.edu * SHDR - Addr 674484Sbinkertn@umich.edu * 684484Sbinkertn@umich.edu * XXX: how do we handle 'flags'. 694484Sbinkertn@umich.edu */ 704484Sbinkertn@umich.edu 714484Sbinkertn@umich.edu/* 724484Sbinkertn@umich.edu * Compute the extents of a section, by looking at the. 734484Sbinkertn@umich.edu */ 744484Sbinkertn@umich.edustatic int 754484Sbinkertn@umich.edu_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc) 764484Sbinkertn@umich.edu{ 774484Sbinkertn@umich.edu int ec; 784484Sbinkertn@umich.edu Elf_Data *d, *td; 794484Sbinkertn@umich.edu unsigned int elftype; 804484Sbinkertn@umich.edu uint32_t sh_type; 814484Sbinkertn@umich.edu uint64_t d_align; 824484Sbinkertn@umich.edu uint64_t sh_align, sh_entsize, sh_offset, sh_size; 834484Sbinkertn@umich.edu uint64_t scn_size, scn_alignment; 844484Sbinkertn@umich.edu 854484Sbinkertn@umich.edu /* 864484Sbinkertn@umich.edu * We need to recompute library private data structures if one 874484Sbinkertn@umich.edu * or more of the following is true: 884484Sbinkertn@umich.edu * - The underlying Shdr structure has been marked `dirty'. Significant 894484Sbinkertn@umich.edu * fields include: `sh_offset', `sh_type', `sh_size', `sh_addralign'. 904484Sbinkertn@umich.edu * - The Elf_Data structures part of this section have been marked 914484Sbinkertn@umich.edu * `dirty'. Affected members include `d_align', `d_offset', `d_type', 924484Sbinkertn@umich.edu * and `d_size'. 934484Sbinkertn@umich.edu * - The section as a whole is `dirty', e.g., it has been allocated 944484Sbinkertn@umich.edu * using elf_newscn(), or if a new Elf_Data structure was added using 954484Sbinkertn@umich.edu * elf_newdata(). 964484Sbinkertn@umich.edu * 974484Sbinkertn@umich.edu * Each of these conditions would result in the ELF_F_DIRTY bit being 984484Sbinkertn@umich.edu * set on the section descriptor's `s_flags' field. 994484Sbinkertn@umich.edu */ 1004484Sbinkertn@umich.edu 1014484Sbinkertn@umich.edu ec = e->e_class; 1024484Sbinkertn@umich.edu 1034484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 1044484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr32.sh_type; 1054484Sbinkertn@umich.edu sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 1064484Sbinkertn@umich.edu sh_entsize = (uint64_t) s->s_shdr.s_shdr32.sh_entsize; 1074484Sbinkertn@umich.edu sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 1084484Sbinkertn@umich.edu sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 1094484Sbinkertn@umich.edu } else { 1104484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr64.sh_type; 1114484Sbinkertn@umich.edu sh_align = s->s_shdr.s_shdr64.sh_addralign; 1124484Sbinkertn@umich.edu sh_entsize = s->s_shdr.s_shdr64.sh_entsize; 1134484Sbinkertn@umich.edu sh_offset = s->s_shdr.s_shdr64.sh_offset; 1144484Sbinkertn@umich.edu sh_size = s->s_shdr.s_shdr64.sh_size; 1154484Sbinkertn@umich.edu } 1164484Sbinkertn@umich.edu 1174484Sbinkertn@umich.edu if (sh_type == SHT_NULL || sh_type == SHT_NOBITS) 1184484Sbinkertn@umich.edu return (1); 1194484Sbinkertn@umich.edu 1204484Sbinkertn@umich.edu if ((s->s_flags & ELF_F_DIRTY) == 0) { 1214484Sbinkertn@umich.edu if ((size_t) *rc < sh_offset + sh_size) 1224484Sbinkertn@umich.edu *rc = sh_offset + sh_size; 1234484Sbinkertn@umich.edu return (1); 1244484Sbinkertn@umich.edu } 1254484Sbinkertn@umich.edu 1264484Sbinkertn@umich.edu elftype = _libelf_xlate_shtype(sh_type); 1274484Sbinkertn@umich.edu if (elftype > ELF_T_LAST) { 1284484Sbinkertn@umich.edu LIBELF_SET_ERROR(SECTION, 0); 1294484Sbinkertn@umich.edu return (0); 1304484Sbinkertn@umich.edu } 1314484Sbinkertn@umich.edu 1324484Sbinkertn@umich.edu /* 1334484Sbinkertn@umich.edu * Compute the extent of the data descriptors associated with 1344484Sbinkertn@umich.edu * this section. 1354484Sbinkertn@umich.edu */ 1364484Sbinkertn@umich.edu scn_alignment = 0; 1374484Sbinkertn@umich.edu if (sh_align == 0) 1384484Sbinkertn@umich.edu sh_align = _libelf_falign(elftype, ec); 1394484Sbinkertn@umich.edu 1404484Sbinkertn@umich.edu /* Compute the section alignment. */ 1414484Sbinkertn@umich.edu STAILQ_FOREACH(d, &s->s_data, d_next) { 1424484Sbinkertn@umich.edu if (d->d_type != elftype) { 1434484Sbinkertn@umich.edu LIBELF_SET_ERROR(DATA, 0); 1444484Sbinkertn@umich.edu return (0); 1454484Sbinkertn@umich.edu } 1464484Sbinkertn@umich.edu if (d->d_version != e->e_version) { 1474484Sbinkertn@umich.edu LIBELF_SET_ERROR(VERSION, 0); 1484484Sbinkertn@umich.edu return (0); 1494484Sbinkertn@umich.edu } 1504484Sbinkertn@umich.edu if ((d_align = d->d_align) % sh_align) { 1514484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 1524484Sbinkertn@umich.edu return (0); 1534484Sbinkertn@umich.edu } 1544484Sbinkertn@umich.edu if (d_align == 0 || (d_align & (d_align - 1))) { 1554484Sbinkertn@umich.edu LIBELF_SET_ERROR(DATA, 0); 1564484Sbinkertn@umich.edu return (0); 1574484Sbinkertn@umich.edu } 1584484Sbinkertn@umich.edu if (d_align > scn_alignment) 1594484Sbinkertn@umich.edu scn_alignment = d_align; 1604484Sbinkertn@umich.edu } 1614484Sbinkertn@umich.edu 1624484Sbinkertn@umich.edu scn_size = 0L; 1634484Sbinkertn@umich.edu 1644484Sbinkertn@umich.edu STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) { 1654484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 1664484Sbinkertn@umich.edu if ((uint64_t) d->d_off + d->d_size > scn_size) 1674484Sbinkertn@umich.edu scn_size = d->d_off + d->d_size; 1684484Sbinkertn@umich.edu } else { 1694484Sbinkertn@umich.edu scn_size = roundup(scn_size, scn_alignment); 1704484Sbinkertn@umich.edu d->d_off = scn_size; 1714484Sbinkertn@umich.edu scn_size += d->d_size; 1724484Sbinkertn@umich.edu } 1734484Sbinkertn@umich.edu } 1744484Sbinkertn@umich.edu 1754484Sbinkertn@umich.edu /* 1764484Sbinkertn@umich.edu * If the application is requesting full control over the layout 1774484Sbinkertn@umich.edu * of the section, check its values for sanity. 1784484Sbinkertn@umich.edu */ 1794484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 1804484Sbinkertn@umich.edu if (scn_alignment > sh_align || sh_offset % sh_align || 1814484Sbinkertn@umich.edu sh_size < scn_size) { 1824484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 1834484Sbinkertn@umich.edu return (0); 1844484Sbinkertn@umich.edu } 1854484Sbinkertn@umich.edu } else { 1864484Sbinkertn@umich.edu /* 1874484Sbinkertn@umich.edu * Otherwise compute the values in the section header. 1884484Sbinkertn@umich.edu */ 1894484Sbinkertn@umich.edu 1904484Sbinkertn@umich.edu if (scn_alignment > sh_align) 1914484Sbinkertn@umich.edu sh_align = scn_alignment; 1924484Sbinkertn@umich.edu 1934484Sbinkertn@umich.edu /* 1944484Sbinkertn@umich.edu * If the section entry size is zero, try and fill in an 1954484Sbinkertn@umich.edu * appropriate entry size. Per the elf(5) manual page 1964484Sbinkertn@umich.edu * sections without fixed-size entries should have their 1974484Sbinkertn@umich.edu * 'sh_entsize' field set to zero. 1984484Sbinkertn@umich.edu */ 1994484Sbinkertn@umich.edu if (sh_entsize == 0 && 2004484Sbinkertn@umich.edu (sh_entsize = _libelf_fsize(elftype, ec, e->e_version, 2014484Sbinkertn@umich.edu (size_t) 1)) == 1) 2024484Sbinkertn@umich.edu sh_entsize = 0; 2034484Sbinkertn@umich.edu 2044484Sbinkertn@umich.edu sh_size = scn_size; 2054484Sbinkertn@umich.edu sh_offset = roundup(*rc, sh_align); 2064484Sbinkertn@umich.edu 2074484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 2084484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_addralign = (uint32_t) sh_align; 2094484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_entsize = (uint32_t) sh_entsize; 2104484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_offset = (uint32_t) sh_offset; 2114484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_size = (uint32_t) sh_size; 2124484Sbinkertn@umich.edu } else { 2134484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_addralign = sh_align; 2144484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_entsize = sh_entsize; 2154484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_offset = sh_offset; 2164484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_size = sh_size; 2174484Sbinkertn@umich.edu } 2184484Sbinkertn@umich.edu } 2194484Sbinkertn@umich.edu 2204484Sbinkertn@umich.edu if ((size_t) *rc < sh_offset + sh_size) 2214484Sbinkertn@umich.edu *rc = sh_offset + sh_size; 2224484Sbinkertn@umich.edu 2234484Sbinkertn@umich.edu s->s_size = sh_size; 2244484Sbinkertn@umich.edu s->s_offset = sh_offset; 2254484Sbinkertn@umich.edu return (1); 2264484Sbinkertn@umich.edu} 2274484Sbinkertn@umich.edu 2284484Sbinkertn@umich.edu 2294484Sbinkertn@umich.edu/* 2304484Sbinkertn@umich.edu * Insert a section in ascending order in the list 2314484Sbinkertn@umich.edu */ 2324484Sbinkertn@umich.edu 2334484Sbinkertn@umich.edustatic int 2344484Sbinkertn@umich.edu_libelf_insert_section(Elf *e, Elf_Scn *s) 2354484Sbinkertn@umich.edu{ 2364484Sbinkertn@umich.edu Elf_Scn *t, *prevt; 2374484Sbinkertn@umich.edu uint64_t smax, smin, tmax, tmin; 2384484Sbinkertn@umich.edu 2394484Sbinkertn@umich.edu smin = s->s_offset; 2404484Sbinkertn@umich.edu smax = smin + s->s_size; 2414484Sbinkertn@umich.edu 2424484Sbinkertn@umich.edu prevt = NULL; 2434484Sbinkertn@umich.edu STAILQ_FOREACH(t, &e->e_u.e_elf.e_scn, s_next) { 2444484Sbinkertn@umich.edu tmin = t->s_offset; 2454484Sbinkertn@umich.edu tmax = tmin + t->s_size; 2464484Sbinkertn@umich.edu 2474484Sbinkertn@umich.edu /* check if there is an overlap */ 2484484Sbinkertn@umich.edu if (tmax < smin) { 2494484Sbinkertn@umich.edu prevt = t; 2504484Sbinkertn@umich.edu continue; 2514484Sbinkertn@umich.edu } else if (smax < tmin) 2524484Sbinkertn@umich.edu break; 2534484Sbinkertn@umich.edu else { 2544484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 2554484Sbinkertn@umich.edu return (0); 2564484Sbinkertn@umich.edu } 2574484Sbinkertn@umich.edu } 2584484Sbinkertn@umich.edu 2594484Sbinkertn@umich.edu if (prevt) 2604484Sbinkertn@umich.edu STAILQ_INSERT_AFTER(&e->e_u.e_elf.e_scn, prevt, s, s_next); 2614484Sbinkertn@umich.edu else 2624484Sbinkertn@umich.edu STAILQ_INSERT_HEAD(&e->e_u.e_elf.e_scn, s, s_next); 2634484Sbinkertn@umich.edu return (1); 2644484Sbinkertn@umich.edu} 2654484Sbinkertn@umich.edu 2664484Sbinkertn@umich.edustatic off_t 2674484Sbinkertn@umich.edu_libelf_resync_sections(Elf *e, off_t rc) 2684484Sbinkertn@umich.edu{ 2694484Sbinkertn@umich.edu int ec; 2704484Sbinkertn@umich.edu off_t nrc; 2714484Sbinkertn@umich.edu size_t sh_type; 2724484Sbinkertn@umich.edu Elf_Scn *s, *ts; 2734484Sbinkertn@umich.edu 2744484Sbinkertn@umich.edu ec = e->e_class; 2754484Sbinkertn@umich.edu 2764484Sbinkertn@umich.edu /* 2774484Sbinkertn@umich.edu * Make a pass through sections, computing the extent of each 2784484Sbinkertn@umich.edu * section. Order in increasing order of addresses. 2794484Sbinkertn@umich.edu */ 2804484Sbinkertn@umich.edu 2814484Sbinkertn@umich.edu nrc = rc; 2824484Sbinkertn@umich.edu STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) 2834484Sbinkertn@umich.edu if (_libelf_compute_section_extents(e, s, &nrc) == 0) 2844484Sbinkertn@umich.edu return ((off_t) -1); 2854484Sbinkertn@umich.edu 2864484Sbinkertn@umich.edu STAILQ_FOREACH_SAFE(s, &e->e_u.e_elf.e_scn, s_next, ts) { 2874484Sbinkertn@umich.edu if (ec == ELFCLASS32) 2884484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr32.sh_type; 2894484Sbinkertn@umich.edu else 2904484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr64.sh_type; 2914484Sbinkertn@umich.edu 2924484Sbinkertn@umich.edu /* XXX Do we need the 'size' field of an SHT_NOBITS section */ 2934484Sbinkertn@umich.edu if (sh_type == SHT_NOBITS || sh_type == SHT_NULL) 2944484Sbinkertn@umich.edu continue; 2954484Sbinkertn@umich.edu 2964484Sbinkertn@umich.edu if (s->s_offset < (uint64_t) rc) { 2974484Sbinkertn@umich.edu if (s->s_offset + s->s_size < (uint64_t) rc) { 2984484Sbinkertn@umich.edu /* 2994484Sbinkertn@umich.edu * Try insert this section in the 3004484Sbinkertn@umich.edu * correct place in the list, 3014484Sbinkertn@umich.edu * detecting overlaps if any. 3024484Sbinkertn@umich.edu */ 3034484Sbinkertn@umich.edu STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn, 3044484Sbinkertn@umich.edu s_next); 3054484Sbinkertn@umich.edu if (_libelf_insert_section(e, s) == 0) 3064484Sbinkertn@umich.edu return ((off_t) -1); 3074484Sbinkertn@umich.edu } else { 3084484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 3094484Sbinkertn@umich.edu return ((off_t) -1); 3104484Sbinkertn@umich.edu } 3114484Sbinkertn@umich.edu } else 3124484Sbinkertn@umich.edu rc = s->s_offset + s->s_size; 3134484Sbinkertn@umich.edu } 3144484Sbinkertn@umich.edu 3154484Sbinkertn@umich.edu assert(nrc == rc); 3164484Sbinkertn@umich.edu 3174484Sbinkertn@umich.edu return (rc); 3184484Sbinkertn@umich.edu} 3194484Sbinkertn@umich.edu 3204484Sbinkertn@umich.edustatic off_t 3214484Sbinkertn@umich.edu_libelf_resync_elf(Elf *e) 3224484Sbinkertn@umich.edu{ 3234484Sbinkertn@umich.edu int ec, eh_class, eh_type; 3244484Sbinkertn@umich.edu unsigned int eh_byteorder, eh_version; 3254484Sbinkertn@umich.edu size_t align, fsz; 3264484Sbinkertn@umich.edu size_t phnum, shnum; 3274484Sbinkertn@umich.edu off_t rc, phoff, shoff; 3284484Sbinkertn@umich.edu void *ehdr; 3294484Sbinkertn@umich.edu Elf32_Ehdr *eh32; 3304484Sbinkertn@umich.edu Elf64_Ehdr *eh64; 3314484Sbinkertn@umich.edu 3324484Sbinkertn@umich.edu rc = 0; 3334484Sbinkertn@umich.edu 3344484Sbinkertn@umich.edu ec = e->e_class; 3354484Sbinkertn@umich.edu 3364484Sbinkertn@umich.edu assert(ec == ELFCLASS32 || ec == ELFCLASS64); 3374484Sbinkertn@umich.edu 3384484Sbinkertn@umich.edu /* 3394484Sbinkertn@umich.edu * Prepare the EHDR. 3404484Sbinkertn@umich.edu */ 3414484Sbinkertn@umich.edu if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) 3424484Sbinkertn@umich.edu return ((off_t) -1); 3434484Sbinkertn@umich.edu 3444484Sbinkertn@umich.edu eh32 = ehdr; 3454484Sbinkertn@umich.edu eh64 = ehdr; 3464484Sbinkertn@umich.edu 3474484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 3484484Sbinkertn@umich.edu eh_byteorder = eh32->e_ident[EI_DATA]; 3494484Sbinkertn@umich.edu eh_class = eh32->e_ident[EI_CLASS]; 3504484Sbinkertn@umich.edu phoff = (uint64_t) eh32->e_phoff; 3514484Sbinkertn@umich.edu shoff = (uint64_t) eh32->e_shoff; 3524484Sbinkertn@umich.edu eh_type = eh32->e_type; 3534484Sbinkertn@umich.edu eh_version = eh32->e_version; 3544484Sbinkertn@umich.edu } else { 3554484Sbinkertn@umich.edu eh_byteorder = eh64->e_ident[EI_DATA]; 3564484Sbinkertn@umich.edu eh_class = eh64->e_ident[EI_CLASS]; 3574484Sbinkertn@umich.edu phoff = eh64->e_phoff; 3584484Sbinkertn@umich.edu shoff = eh64->e_shoff; 3594484Sbinkertn@umich.edu eh_type = eh64->e_type; 3604484Sbinkertn@umich.edu eh_version = eh64->e_version; 3614484Sbinkertn@umich.edu } 3624484Sbinkertn@umich.edu 3634484Sbinkertn@umich.edu if (eh_version == EV_NONE) 3644484Sbinkertn@umich.edu eh_version = EV_CURRENT; 3654484Sbinkertn@umich.edu 3664484Sbinkertn@umich.edu if (eh_version != e->e_version) { /* always EV_CURRENT */ 3674484Sbinkertn@umich.edu LIBELF_SET_ERROR(VERSION, 0); 3684484Sbinkertn@umich.edu return ((off_t) -1); 3694484Sbinkertn@umich.edu } 3704484Sbinkertn@umich.edu 3714484Sbinkertn@umich.edu if (eh_class != e->e_class) { 3724484Sbinkertn@umich.edu LIBELF_SET_ERROR(CLASS, 0); 3734484Sbinkertn@umich.edu return ((off_t) -1); 3744484Sbinkertn@umich.edu } 3754484Sbinkertn@umich.edu 3764484Sbinkertn@umich.edu if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) { 3774484Sbinkertn@umich.edu LIBELF_SET_ERROR(HEADER, 0); 3784484Sbinkertn@umich.edu return ((off_t) -1); 3794484Sbinkertn@umich.edu } 3804484Sbinkertn@umich.edu 3814484Sbinkertn@umich.edu shnum = e->e_u.e_elf.e_nscn; 3824484Sbinkertn@umich.edu phnum = e->e_u.e_elf.e_nphdr; 3834484Sbinkertn@umich.edu 3844484Sbinkertn@umich.edu e->e_byteorder = eh_byteorder; 3854484Sbinkertn@umich.edu 3864484Sbinkertn@umich.edu#define INITIALIZE_EHDR(E,EC,V) do { \ 3874484Sbinkertn@umich.edu (E)->e_ident[EI_MAG0] = ELFMAG0; \ 3884484Sbinkertn@umich.edu (E)->e_ident[EI_MAG1] = ELFMAG1; \ 3894484Sbinkertn@umich.edu (E)->e_ident[EI_MAG2] = ELFMAG2; \ 3904484Sbinkertn@umich.edu (E)->e_ident[EI_MAG3] = ELFMAG3; \ 3914484Sbinkertn@umich.edu (E)->e_ident[EI_CLASS] = (EC); \ 3924484Sbinkertn@umich.edu (E)->e_ident[EI_VERSION] = (V); \ 3934484Sbinkertn@umich.edu (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), \ 3944484Sbinkertn@umich.edu (size_t) 1); \ 3954484Sbinkertn@umich.edu (E)->e_phentsize = _libelf_fsize(ELF_T_PHDR, (EC), (V), \ 3964484Sbinkertn@umich.edu (size_t) 1); \ 3974484Sbinkertn@umich.edu (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V), \ 3984484Sbinkertn@umich.edu (size_t) 1); \ 3994484Sbinkertn@umich.edu } while (0) 4004484Sbinkertn@umich.edu 4014484Sbinkertn@umich.edu if (ec == ELFCLASS32) 4024484Sbinkertn@umich.edu INITIALIZE_EHDR(eh32, ec, eh_version); 4034484Sbinkertn@umich.edu else 4044484Sbinkertn@umich.edu INITIALIZE_EHDR(eh64, ec, eh_version); 4054484Sbinkertn@umich.edu 4064484Sbinkertn@umich.edu (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); 4074484Sbinkertn@umich.edu 4084484Sbinkertn@umich.edu rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); 4094484Sbinkertn@umich.edu 4104484Sbinkertn@umich.edu /* 4114484Sbinkertn@umich.edu * Compute the layout the program header table, if one is 4124484Sbinkertn@umich.edu * present. The program header table needs to be aligned to a 4134484Sbinkertn@umich.edu * `natural' boundary. 4144484Sbinkertn@umich.edu */ 4154484Sbinkertn@umich.edu if (phnum) { 4164484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum); 4174484Sbinkertn@umich.edu align = _libelf_falign(ELF_T_PHDR, ec); 4184484Sbinkertn@umich.edu 4194484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 4204484Sbinkertn@umich.edu /* 4214484Sbinkertn@umich.edu * Check offsets for sanity. 4224484Sbinkertn@umich.edu */ 4234484Sbinkertn@umich.edu if (rc > phoff) { 4244484Sbinkertn@umich.edu LIBELF_SET_ERROR(HEADER, 0); 4254484Sbinkertn@umich.edu return ((off_t) -1); 4264484Sbinkertn@umich.edu } 4274484Sbinkertn@umich.edu 4284484Sbinkertn@umich.edu if (phoff % align) { 4294484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 4304484Sbinkertn@umich.edu return ((off_t) -1); 4314484Sbinkertn@umich.edu } 4324484Sbinkertn@umich.edu 4334484Sbinkertn@umich.edu } else 4344484Sbinkertn@umich.edu phoff = roundup(rc, align); 4354484Sbinkertn@umich.edu 4364484Sbinkertn@umich.edu rc = phoff + fsz; 4374484Sbinkertn@umich.edu } else 4384484Sbinkertn@umich.edu phoff = 0; 4394484Sbinkertn@umich.edu 4404484Sbinkertn@umich.edu /* 4414484Sbinkertn@umich.edu * Compute the layout of the sections associated with the 4424484Sbinkertn@umich.edu * file. 4434484Sbinkertn@umich.edu */ 4444484Sbinkertn@umich.edu 4454484Sbinkertn@umich.edu if ((rc = _libelf_resync_sections(e, rc)) < 0) 4464484Sbinkertn@umich.edu return ((off_t) -1); 4474484Sbinkertn@umich.edu 4484484Sbinkertn@umich.edu /* 4494484Sbinkertn@umich.edu * Compute the space taken up by the section header table, if 4504484Sbinkertn@umich.edu * one is needed. 4514484Sbinkertn@umich.edu */ 4524484Sbinkertn@umich.edu if (shnum) { 4534484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, (size_t) 1); 4544484Sbinkertn@umich.edu align = _libelf_falign(ELF_T_SHDR, ec); 4554484Sbinkertn@umich.edu 4564484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 4574484Sbinkertn@umich.edu if (rc > shoff) { 4584484Sbinkertn@umich.edu LIBELF_SET_ERROR(HEADER, 0); 4594484Sbinkertn@umich.edu return ((off_t) -1); 4604484Sbinkertn@umich.edu } 4614484Sbinkertn@umich.edu 4624484Sbinkertn@umich.edu if (shoff % align) { 4634484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 4644484Sbinkertn@umich.edu return ((off_t) -1); 4654484Sbinkertn@umich.edu } 4664484Sbinkertn@umich.edu } else 4674484Sbinkertn@umich.edu shoff = roundup(rc, align); 4684484Sbinkertn@umich.edu 4694484Sbinkertn@umich.edu rc = shoff + fsz * shnum; 4704484Sbinkertn@umich.edu } else 4714484Sbinkertn@umich.edu shoff = 0; 4724484Sbinkertn@umich.edu 4734484Sbinkertn@umich.edu /* 4744484Sbinkertn@umich.edu * Set the fields of the Executable Header that could potentially use 4754484Sbinkertn@umich.edu * extended numbering. 4764484Sbinkertn@umich.edu */ 4774484Sbinkertn@umich.edu _libelf_setphnum(e, ehdr, ec, phnum); 4784484Sbinkertn@umich.edu _libelf_setshnum(e, ehdr, ec, shnum); 4794484Sbinkertn@umich.edu 4804484Sbinkertn@umich.edu /* 4814484Sbinkertn@umich.edu * Update the `e_phoff' and `e_shoff' fields if the library is 4824484Sbinkertn@umich.edu * doing the layout. 4834484Sbinkertn@umich.edu */ 4844484Sbinkertn@umich.edu if ((e->e_flags & ELF_F_LAYOUT) == 0) { 4854484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 4864484Sbinkertn@umich.edu eh32->e_phoff = (uint32_t) phoff; 4874484Sbinkertn@umich.edu eh32->e_shoff = (uint32_t) shoff; 4884484Sbinkertn@umich.edu } else { 4894484Sbinkertn@umich.edu eh64->e_phoff = (uint64_t) phoff; 4904484Sbinkertn@umich.edu eh64->e_shoff = (uint64_t) shoff; 4914484Sbinkertn@umich.edu } 4924484Sbinkertn@umich.edu } 4934484Sbinkertn@umich.edu 4944484Sbinkertn@umich.edu return (rc); 4954484Sbinkertn@umich.edu} 4964484Sbinkertn@umich.edu 4974484Sbinkertn@umich.edu/* 4984484Sbinkertn@umich.edu * Write out the contents of a section. 4994484Sbinkertn@umich.edu */ 5004484Sbinkertn@umich.edu 5014484Sbinkertn@umich.edustatic off_t 5024484Sbinkertn@umich.edu_libelf_write_scn(Elf *e, char *nf, Elf_Scn *s, off_t rc) 5034484Sbinkertn@umich.edu{ 5044484Sbinkertn@umich.edu int ec; 5054484Sbinkertn@umich.edu size_t fsz, msz, nobjects; 5064484Sbinkertn@umich.edu uint32_t sh_type; 5074484Sbinkertn@umich.edu uint64_t sh_off; 5084484Sbinkertn@umich.edu int elftype; 5094484Sbinkertn@umich.edu Elf_Data *d, dst; 5104484Sbinkertn@umich.edu 5114484Sbinkertn@umich.edu if ((ec = e->e_class) == ELFCLASS32) 5124484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr32.sh_type; 5134484Sbinkertn@umich.edu else 5144484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr64.sh_type; 5154484Sbinkertn@umich.edu 5164484Sbinkertn@umich.edu /* 5174484Sbinkertn@umich.edu * Ignore sections that do not allocate space in the file. 5184484Sbinkertn@umich.edu */ 5194484Sbinkertn@umich.edu if (sh_type == SHT_NOBITS || sh_type == SHT_NULL) 5204484Sbinkertn@umich.edu return (rc); 5214484Sbinkertn@umich.edu 5224484Sbinkertn@umich.edu 5234484Sbinkertn@umich.edu elftype = _libelf_xlate_shtype(sh_type); 5244484Sbinkertn@umich.edu assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST); 5254484Sbinkertn@umich.edu 5264484Sbinkertn@umich.edu msz = _libelf_msize(elftype, ec, e->e_version); 5274484Sbinkertn@umich.edu 5284484Sbinkertn@umich.edu sh_off = s->s_offset; 5294484Sbinkertn@umich.edu assert(sh_off % _libelf_falign(elftype, ec) == 0); 5304484Sbinkertn@umich.edu 5314484Sbinkertn@umich.edu /* 5324484Sbinkertn@umich.edu * If the section has a `rawdata' descriptor, and the section 5334484Sbinkertn@umich.edu * contents have not been modified, use its contents directly. 5344484Sbinkertn@umich.edu * The `s_rawoff' member contains the offset into the original 5354484Sbinkertn@umich.edu * file, while `s_offset' contains its new location in the 5364484Sbinkertn@umich.edu * destination. 5374484Sbinkertn@umich.edu */ 5384484Sbinkertn@umich.edu 5394484Sbinkertn@umich.edu if (STAILQ_EMPTY(&s->s_data)) { 5404484Sbinkertn@umich.edu 5414484Sbinkertn@umich.edu if ((d = elf_rawdata(s, NULL)) == NULL) 5424484Sbinkertn@umich.edu return ((off_t) -1); 5434484Sbinkertn@umich.edu 5444484Sbinkertn@umich.edu STAILQ_FOREACH(d, &s->s_rawdata, d_next) { 5454484Sbinkertn@umich.edu if ((uint64_t) rc < sh_off + d->d_off) 5464484Sbinkertn@umich.edu (void) memset(nf + rc, 5474484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), sh_off + 5484484Sbinkertn@umich.edu d->d_off - rc); 5494484Sbinkertn@umich.edu rc = sh_off + d->d_off; 5504484Sbinkertn@umich.edu 5514484Sbinkertn@umich.edu assert(d->d_buf != NULL); 5524484Sbinkertn@umich.edu assert(d->d_type == ELF_T_BYTE); 5534484Sbinkertn@umich.edu assert(d->d_version == e->e_version); 5544484Sbinkertn@umich.edu 5554484Sbinkertn@umich.edu (void) memcpy(nf + rc, 5564484Sbinkertn@umich.edu e->e_rawfile + s->s_rawoff + d->d_off, d->d_size); 5574484Sbinkertn@umich.edu 5584484Sbinkertn@umich.edu rc += d->d_size; 5594484Sbinkertn@umich.edu } 5604484Sbinkertn@umich.edu 5614484Sbinkertn@umich.edu return (rc); 5624484Sbinkertn@umich.edu } 5634484Sbinkertn@umich.edu 5644484Sbinkertn@umich.edu /* 5654484Sbinkertn@umich.edu * Iterate over the set of data descriptors for this section. 5664484Sbinkertn@umich.edu * The prior call to _libelf_resync_elf() would have setup the 5674484Sbinkertn@umich.edu * descriptors for this step. 5684484Sbinkertn@umich.edu */ 5694484Sbinkertn@umich.edu 5704484Sbinkertn@umich.edu dst.d_version = e->e_version; 5714484Sbinkertn@umich.edu 5724484Sbinkertn@umich.edu STAILQ_FOREACH(d, &s->s_data, d_next) { 5734484Sbinkertn@umich.edu 5744484Sbinkertn@umich.edu if ((uint64_t) rc < sh_off + d->d_off) 5754484Sbinkertn@umich.edu (void) memset(nf + rc, 5764484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc); 5774484Sbinkertn@umich.edu 5784484Sbinkertn@umich.edu rc = sh_off + d->d_off; 5794484Sbinkertn@umich.edu 5804484Sbinkertn@umich.edu assert(d->d_buf != NULL); 5814484Sbinkertn@umich.edu assert(d->d_type == (Elf_Type) elftype); 5824484Sbinkertn@umich.edu assert(d->d_version == e->e_version); 5834484Sbinkertn@umich.edu assert(d->d_size % msz == 0); 5844484Sbinkertn@umich.edu 5854484Sbinkertn@umich.edu nobjects = d->d_size / msz; 5864484Sbinkertn@umich.edu 5874484Sbinkertn@umich.edu fsz = _libelf_fsize(elftype, ec, e->e_version, nobjects); 5884484Sbinkertn@umich.edu 5894484Sbinkertn@umich.edu dst.d_buf = nf + rc; 5904484Sbinkertn@umich.edu dst.d_size = fsz; 5914484Sbinkertn@umich.edu 5924484Sbinkertn@umich.edu if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) == 5934484Sbinkertn@umich.edu NULL) 5944484Sbinkertn@umich.edu return ((off_t) -1); 5954484Sbinkertn@umich.edu 5964484Sbinkertn@umich.edu rc += fsz; 5974484Sbinkertn@umich.edu } 5984484Sbinkertn@umich.edu 5994484Sbinkertn@umich.edu return ((off_t) rc); 6004484Sbinkertn@umich.edu} 6014484Sbinkertn@umich.edu 6024484Sbinkertn@umich.edu/* 6034484Sbinkertn@umich.edu * Write out the file image. 6044484Sbinkertn@umich.edu * 6054484Sbinkertn@umich.edu * The original file could have been mapped in with an ELF_C_RDWR 6064484Sbinkertn@umich.edu * command and the application could have added new content or 6074484Sbinkertn@umich.edu * re-arranged its sections before calling elf_update(). Consequently 6084484Sbinkertn@umich.edu * its not safe to work `in place' on the original file. So we 6094484Sbinkertn@umich.edu * malloc() the required space for the updated ELF object and build 6104484Sbinkertn@umich.edu * the object there and write it out to the underlying file at the 6114484Sbinkertn@umich.edu * end. Note that the application may have opened the underlying file 6124484Sbinkertn@umich.edu * in ELF_C_RDWR and only retrieved/modified a few sections. We take 6134484Sbinkertn@umich.edu * care to avoid translating file sections unnecessarily. 6144484Sbinkertn@umich.edu * 6154484Sbinkertn@umich.edu * Gaps in the coverage of the file by the file's sections will be 6164484Sbinkertn@umich.edu * filled with the fill character set by elf_fill(3). 6174484Sbinkertn@umich.edu */ 6184484Sbinkertn@umich.edu 6194484Sbinkertn@umich.edustatic off_t 6204484Sbinkertn@umich.edu_libelf_write_elf(Elf *e, off_t newsize) 6214484Sbinkertn@umich.edu{ 6224484Sbinkertn@umich.edu int ec; 6234484Sbinkertn@umich.edu off_t rc; 6244484Sbinkertn@umich.edu size_t fsz, msz, phnum, shnum; 6254484Sbinkertn@umich.edu uint64_t phoff, shoff; 6264484Sbinkertn@umich.edu void *ehdr; 6274484Sbinkertn@umich.edu char *newfile; 6284484Sbinkertn@umich.edu Elf_Data dst, src; 6294484Sbinkertn@umich.edu Elf_Scn *scn, *tscn; 6304484Sbinkertn@umich.edu Elf32_Ehdr *eh32; 6314484Sbinkertn@umich.edu Elf64_Ehdr *eh64; 6324484Sbinkertn@umich.edu 6334484Sbinkertn@umich.edu assert(e->e_kind == ELF_K_ELF); 6344484Sbinkertn@umich.edu assert(e->e_cmd != ELF_C_READ); 6354484Sbinkertn@umich.edu assert(e->e_fd >= 0); 6364484Sbinkertn@umich.edu 6374484Sbinkertn@umich.edu if ((newfile = malloc((size_t) newsize)) == NULL) { 6384484Sbinkertn@umich.edu LIBELF_SET_ERROR(RESOURCE, errno); 6394484Sbinkertn@umich.edu return ((off_t) -1); 6404484Sbinkertn@umich.edu } 6414484Sbinkertn@umich.edu 6424484Sbinkertn@umich.edu ec = e->e_class; 6434484Sbinkertn@umich.edu 6444484Sbinkertn@umich.edu ehdr = _libelf_ehdr(e, ec, 0); 6454484Sbinkertn@umich.edu assert(ehdr != NULL); 6464484Sbinkertn@umich.edu 6474484Sbinkertn@umich.edu phnum = e->e_u.e_elf.e_nphdr; 6484484Sbinkertn@umich.edu 6494484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 6504484Sbinkertn@umich.edu eh32 = (Elf32_Ehdr *) ehdr; 6514484Sbinkertn@umich.edu 6524484Sbinkertn@umich.edu phoff = (uint64_t) eh32->e_phoff; 6534484Sbinkertn@umich.edu shnum = eh32->e_shnum; 6544484Sbinkertn@umich.edu shoff = (uint64_t) eh32->e_shoff; 6554484Sbinkertn@umich.edu } else { 6564484Sbinkertn@umich.edu eh64 = (Elf64_Ehdr *) ehdr; 6574484Sbinkertn@umich.edu 6584484Sbinkertn@umich.edu phoff = eh64->e_phoff; 6594484Sbinkertn@umich.edu shnum = eh64->e_shnum; 6604484Sbinkertn@umich.edu shoff = eh64->e_shoff; 6614484Sbinkertn@umich.edu } 6624484Sbinkertn@umich.edu 6634484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); 6644484Sbinkertn@umich.edu msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version); 6654484Sbinkertn@umich.edu 6664484Sbinkertn@umich.edu (void) memset(&dst, 0, sizeof(dst)); 6674484Sbinkertn@umich.edu (void) memset(&src, 0, sizeof(src)); 6684484Sbinkertn@umich.edu 6694484Sbinkertn@umich.edu src.d_buf = ehdr; 6704484Sbinkertn@umich.edu src.d_size = msz; 6714484Sbinkertn@umich.edu src.d_type = ELF_T_EHDR; 6724484Sbinkertn@umich.edu src.d_version = dst.d_version = e->e_version; 6734484Sbinkertn@umich.edu 6744484Sbinkertn@umich.edu rc = 0; 6754484Sbinkertn@umich.edu 6764484Sbinkertn@umich.edu dst.d_buf = newfile + rc; 6774484Sbinkertn@umich.edu dst.d_size = fsz; 6784484Sbinkertn@umich.edu 6794484Sbinkertn@umich.edu if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == 6804484Sbinkertn@umich.edu NULL) 6814484Sbinkertn@umich.edu goto error; 6824484Sbinkertn@umich.edu 6834484Sbinkertn@umich.edu rc += fsz; 6844484Sbinkertn@umich.edu 6854484Sbinkertn@umich.edu /* 6864484Sbinkertn@umich.edu * Write the program header table if present. 6874484Sbinkertn@umich.edu */ 6884484Sbinkertn@umich.edu 6894484Sbinkertn@umich.edu if (phnum != 0 && phoff != 0) { 6904484Sbinkertn@umich.edu assert((unsigned) rc <= phoff); 6914484Sbinkertn@umich.edu 6924484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum); 6934484Sbinkertn@umich.edu 6944484Sbinkertn@umich.edu assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0); 6954484Sbinkertn@umich.edu assert(fsz > 0); 6964484Sbinkertn@umich.edu 6974484Sbinkertn@umich.edu src.d_version = dst.d_version = e->e_version; 6984484Sbinkertn@umich.edu src.d_type = ELF_T_PHDR; 6994484Sbinkertn@umich.edu 7004484Sbinkertn@umich.edu if (ec == ELFCLASS32) 7014484Sbinkertn@umich.edu src.d_buf = e->e_u.e_elf.e_phdr.e_phdr32; 7024484Sbinkertn@umich.edu else 7034484Sbinkertn@umich.edu src.d_buf = e->e_u.e_elf.e_phdr.e_phdr64; 7044484Sbinkertn@umich.edu 7054484Sbinkertn@umich.edu src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec, 7064484Sbinkertn@umich.edu e->e_version); 7074484Sbinkertn@umich.edu 7084484Sbinkertn@umich.edu dst.d_size = fsz; 7094484Sbinkertn@umich.edu 7104484Sbinkertn@umich.edu if ((uint64_t) rc < phoff) 7114484Sbinkertn@umich.edu (void) memset(newfile + rc, 7124484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), phoff - rc); 7134484Sbinkertn@umich.edu 7144484Sbinkertn@umich.edu dst.d_buf = newfile + rc; 7154484Sbinkertn@umich.edu 7164484Sbinkertn@umich.edu if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == 7174484Sbinkertn@umich.edu NULL) 7184484Sbinkertn@umich.edu goto error; 7194484Sbinkertn@umich.edu 7204484Sbinkertn@umich.edu rc = phoff + fsz; 7214484Sbinkertn@umich.edu } 7224484Sbinkertn@umich.edu 7234484Sbinkertn@umich.edu /* 7244484Sbinkertn@umich.edu * Write out individual sections. 7254484Sbinkertn@umich.edu */ 7264484Sbinkertn@umich.edu 7274484Sbinkertn@umich.edu STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) 7284484Sbinkertn@umich.edu if ((rc = _libelf_write_scn(e, newfile, scn, rc)) < 0) 7294484Sbinkertn@umich.edu goto error; 7304484Sbinkertn@umich.edu 7314484Sbinkertn@umich.edu /* 7324484Sbinkertn@umich.edu * Write out the section header table, if required. 7334484Sbinkertn@umich.edu */ 7344484Sbinkertn@umich.edu 7354484Sbinkertn@umich.edu if (shnum != 0 && shoff != 0) { 7364484Sbinkertn@umich.edu assert((unsigned) rc <= shoff); 7374484Sbinkertn@umich.edu 7384484Sbinkertn@umich.edu if ((uint64_t) rc < shoff) 7394484Sbinkertn@umich.edu (void) memset(newfile + rc, 7404484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), shoff - rc); 7414484Sbinkertn@umich.edu 7424484Sbinkertn@umich.edu rc = shoff; 7434484Sbinkertn@umich.edu 7444484Sbinkertn@umich.edu assert(rc % _libelf_falign(ELF_T_SHDR, ec) == 0); 7454484Sbinkertn@umich.edu 7464484Sbinkertn@umich.edu src.d_type = ELF_T_SHDR; 7474484Sbinkertn@umich.edu src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version); 7484484Sbinkertn@umich.edu src.d_version = dst.d_version = e->e_version; 7494484Sbinkertn@umich.edu 7504484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); 7514484Sbinkertn@umich.edu 7524484Sbinkertn@umich.edu STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) { 7534484Sbinkertn@umich.edu if (ec == ELFCLASS32) 7544484Sbinkertn@umich.edu src.d_buf = &scn->s_shdr.s_shdr32; 7554484Sbinkertn@umich.edu else 7564484Sbinkertn@umich.edu src.d_buf = &scn->s_shdr.s_shdr64; 7574484Sbinkertn@umich.edu 7584484Sbinkertn@umich.edu dst.d_size = fsz; 7594484Sbinkertn@umich.edu dst.d_buf = newfile + rc; 7604484Sbinkertn@umich.edu 7614484Sbinkertn@umich.edu if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, 7624484Sbinkertn@umich.edu ELF_TOFILE) != &dst) 7634484Sbinkertn@umich.edu goto error; 7644484Sbinkertn@umich.edu 7654484Sbinkertn@umich.edu rc += fsz; 7664484Sbinkertn@umich.edu } 7674484Sbinkertn@umich.edu } 7684484Sbinkertn@umich.edu 7694484Sbinkertn@umich.edu /* 7704484Sbinkertn@umich.edu */ 7714484Sbinkertn@umich.edu 7724484Sbinkertn@umich.edu assert(rc == newsize); 7734484Sbinkertn@umich.edu 7744484Sbinkertn@umich.edu /* 7754484Sbinkertn@umich.edu * Write out the constructed contents and remap the file in 7764484Sbinkertn@umich.edu * read-only. 7774484Sbinkertn@umich.edu */ 7784484Sbinkertn@umich.edu 7794484Sbinkertn@umich.edu if (e->e_rawfile && munmap(e->e_rawfile, e->e_rawsize) < 0) { 7804484Sbinkertn@umich.edu LIBELF_SET_ERROR(IO, errno); 7814484Sbinkertn@umich.edu goto error; 7824484Sbinkertn@umich.edu } 7834484Sbinkertn@umich.edu 7844484Sbinkertn@umich.edu if (write(e->e_fd, newfile, (size_t) newsize) != newsize || 7854484Sbinkertn@umich.edu lseek(e->e_fd, (off_t) 0, SEEK_SET) < 0) { 7864484Sbinkertn@umich.edu LIBELF_SET_ERROR(IO, errno); 7874484Sbinkertn@umich.edu goto error; 7884484Sbinkertn@umich.edu } 7894484Sbinkertn@umich.edu 7904484Sbinkertn@umich.edu if (e->e_cmd != ELF_C_WRITE) { 7914484Sbinkertn@umich.edu if ((e->e_rawfile = mmap(NULL, (size_t) newsize, PROT_READ, 7924484Sbinkertn@umich.edu MAP_PRIVATE, e->e_fd, (off_t) 0)) == MAP_FAILED) { 7934484Sbinkertn@umich.edu LIBELF_SET_ERROR(IO, errno); 7944484Sbinkertn@umich.edu goto error; 7954484Sbinkertn@umich.edu } 7964484Sbinkertn@umich.edu e->e_rawsize = newsize; 7974484Sbinkertn@umich.edu } 7984484Sbinkertn@umich.edu 7994484Sbinkertn@umich.edu /* 8004484Sbinkertn@umich.edu * Reset flags, remove existing section descriptors and 8014484Sbinkertn@umich.edu * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr() 8024484Sbinkertn@umich.edu * and elf_getscn() will function correctly. 8034484Sbinkertn@umich.edu */ 8044484Sbinkertn@umich.edu 8054484Sbinkertn@umich.edu e->e_flags &= ~ELF_F_DIRTY; 8064484Sbinkertn@umich.edu 8074484Sbinkertn@umich.edu STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn) 8084484Sbinkertn@umich.edu _libelf_release_scn(scn); 8094484Sbinkertn@umich.edu 8104484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 8114484Sbinkertn@umich.edu free(e->e_u.e_elf.e_ehdr.e_ehdr32); 8124484Sbinkertn@umich.edu if (e->e_u.e_elf.e_phdr.e_phdr32) 8134484Sbinkertn@umich.edu free(e->e_u.e_elf.e_phdr.e_phdr32); 8144484Sbinkertn@umich.edu 8154484Sbinkertn@umich.edu e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL; 8164484Sbinkertn@umich.edu e->e_u.e_elf.e_phdr.e_phdr32 = NULL; 8174484Sbinkertn@umich.edu } else { 8184484Sbinkertn@umich.edu free(e->e_u.e_elf.e_ehdr.e_ehdr64); 8194484Sbinkertn@umich.edu if (e->e_u.e_elf.e_phdr.e_phdr64) 8204484Sbinkertn@umich.edu free(e->e_u.e_elf.e_phdr.e_phdr64); 8214484Sbinkertn@umich.edu 8224484Sbinkertn@umich.edu e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL; 8234484Sbinkertn@umich.edu e->e_u.e_elf.e_phdr.e_phdr64 = NULL; 8244484Sbinkertn@umich.edu } 8254484Sbinkertn@umich.edu 8264484Sbinkertn@umich.edu return (rc); 8274484Sbinkertn@umich.edu 8284484Sbinkertn@umich.edu error: 8294484Sbinkertn@umich.edu if (newfile) 8304484Sbinkertn@umich.edu free(newfile); 8314484Sbinkertn@umich.edu return ((off_t) -1); 8324484Sbinkertn@umich.edu} 8334484Sbinkertn@umich.edu 8344484Sbinkertn@umich.eduoff_t 8354484Sbinkertn@umich.eduelf_update(Elf *e, Elf_Cmd c) 8364484Sbinkertn@umich.edu{ 8374484Sbinkertn@umich.edu int ec; 8384484Sbinkertn@umich.edu off_t rc; 8394484Sbinkertn@umich.edu 8404484Sbinkertn@umich.edu rc = (off_t) -1; 8414484Sbinkertn@umich.edu 8424484Sbinkertn@umich.edu if (e == NULL || e->e_kind != ELF_K_ELF || 8434484Sbinkertn@umich.edu (c != ELF_C_NULL && c != ELF_C_WRITE)) { 8444484Sbinkertn@umich.edu LIBELF_SET_ERROR(ARGUMENT, 0); 8454484Sbinkertn@umich.edu return (rc); 8464484Sbinkertn@umich.edu } 8474484Sbinkertn@umich.edu 8484484Sbinkertn@umich.edu if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { 8494484Sbinkertn@umich.edu LIBELF_SET_ERROR(CLASS, 0); 8504484Sbinkertn@umich.edu return (rc); 8514484Sbinkertn@umich.edu } 8524484Sbinkertn@umich.edu 8534484Sbinkertn@umich.edu if (e->e_version == EV_NONE) 8544484Sbinkertn@umich.edu e->e_version = EV_CURRENT; 8554484Sbinkertn@umich.edu 8564484Sbinkertn@umich.edu if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) { 8574484Sbinkertn@umich.edu LIBELF_SET_ERROR(MODE, 0); 8584484Sbinkertn@umich.edu return (rc); 8594484Sbinkertn@umich.edu } 8604484Sbinkertn@umich.edu 8614484Sbinkertn@umich.edu if ((rc = _libelf_resync_elf(e)) < 0) 8624484Sbinkertn@umich.edu return (rc); 8634484Sbinkertn@umich.edu 8644484Sbinkertn@umich.edu if (c == ELF_C_NULL) 8654484Sbinkertn@umich.edu return (rc); 8664484Sbinkertn@umich.edu 8674484Sbinkertn@umich.edu if (e->e_cmd == ELF_C_READ) { 8684484Sbinkertn@umich.edu /* 8694484Sbinkertn@umich.edu * This descriptor was opened in read-only mode or by 8704484Sbinkertn@umich.edu * elf_memory(). 8714484Sbinkertn@umich.edu */ 8724484Sbinkertn@umich.edu if (e->e_fd) 8734484Sbinkertn@umich.edu LIBELF_SET_ERROR(MODE, 0); 8744484Sbinkertn@umich.edu else 8754484Sbinkertn@umich.edu LIBELF_SET_ERROR(ARGUMENT, 0); 8764484Sbinkertn@umich.edu return ((off_t) -1); 8774484Sbinkertn@umich.edu } 8784484Sbinkertn@umich.edu 8794484Sbinkertn@umich.edu if (e->e_fd < 0) { 8804484Sbinkertn@umich.edu LIBELF_SET_ERROR(SEQUENCE, 0); 8814484Sbinkertn@umich.edu return ((off_t) -1); 8824484Sbinkertn@umich.edu } 8834484Sbinkertn@umich.edu 8844484Sbinkertn@umich.edu return (_libelf_write_elf(e, rc)); 8854484Sbinkertn@umich.edu} 886