1/*-
2 * Copyright (c) 2006 Joseph Koshy
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27
28#include <sys/mman.h>
29#include <sys/param.h>
30#ifdef __sun
31#include <sys/sysmacros.h>
32#endif
33
34#include <assert.h>
35#include <errno.h>
36#include "gelf.h"
37#include "libelf.h"
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "_libelf.h"
43
44/*
45 * Update the internal data structures associated with an ELF object.
46 * Returns the size in bytes the ELF object would occupy in its file
47 * representation.
48 *
49 * After a successful call to this function, the following structures
50 * are updated:
51 *
52 * - The ELF header is updated.
53 * - All sections are sorted in order of ascending addresses and their
54 *   section header table entries updated.   An error is signalled
55 *   if an overlap was detected among sections.
56 * - All data descriptors associated with a section are sorted in order
57 *   of ascending addresses.  Overlaps, if detected, are signalled as
58 *   errors.  Other sanity checks for alignments, section types etc. are
59 *   made.
60 *
61 * After a resync_elf() successfully returns, the ELF descriptor is
62 * ready for being handed over to _libelf_write_elf().
63 *
64 * File alignments:
65 * PHDR - Addr
66 * SHDR - Addr
67 *
68 * XXX: how do we handle 'flags'.
69 */
70
71/*
72 * Compute the extents of a section, by looking at the.
73 */
74static int
75_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc)
76{
77        int ec;
78        Elf_Data *d, *td;
79        unsigned int elftype;
80        uint32_t sh_type;
81        uint64_t d_align;
82        uint64_t sh_align, sh_entsize, sh_offset, sh_size;
83        uint64_t scn_size, scn_alignment;
84
85        /*
86         * We need to recompute library private data structures if one
87         * or more of the following is true:
88         * - The underlying Shdr structure has been marked `dirty'.  Significant
89         *   fields include: `sh_offset', `sh_type', `sh_size', `sh_addralign'.
90         * - The Elf_Data structures part of this section have been marked
91         *   `dirty'.  Affected members include `d_align', `d_offset', `d_type',
92         *   and `d_size'.
93         * - The section as a whole is `dirty', e.g., it has been allocated
94         *   using elf_newscn(), or if a new Elf_Data structure was added using
95         *   elf_newdata().
96         *
97         * Each of these conditions would result in the ELF_F_DIRTY bit being
98         * set on the section descriptor's `s_flags' field.
99         */
100
101        ec = e->e_class;
102
103        if (ec == ELFCLASS32) {
104                sh_type    = s->s_shdr.s_shdr32.sh_type;
105                sh_align   = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
106                sh_entsize = (uint64_t) s->s_shdr.s_shdr32.sh_entsize;
107                sh_offset  = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
108                sh_size    = (uint64_t) s->s_shdr.s_shdr32.sh_size;
109        } else {
110                sh_type    = s->s_shdr.s_shdr64.sh_type;
111                sh_align   = s->s_shdr.s_shdr64.sh_addralign;
112                sh_entsize = s->s_shdr.s_shdr64.sh_entsize;
113                sh_offset  = s->s_shdr.s_shdr64.sh_offset;
114                sh_size    = s->s_shdr.s_shdr64.sh_size;
115        }
116
117        if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
118                return (1);
119
120        if ((s->s_flags & ELF_F_DIRTY) == 0) {
121                if ((size_t) *rc < sh_offset + sh_size)
122                        *rc = sh_offset + sh_size;
123                return (1);
124        }
125
126        elftype = _libelf_xlate_shtype(sh_type);
127        if (elftype > ELF_T_LAST) {
128                LIBELF_SET_ERROR(SECTION, 0);
129                return (0);
130        }
131
132        /*
133         * Compute the extent of the data descriptors associated with
134         * this section.
135         */
136        scn_alignment = 0;
137        if (sh_align == 0)
138                sh_align = _libelf_falign(elftype, ec);
139
140        /* Compute the section alignment. */
141        STAILQ_FOREACH(d, &s->s_data, d_next)  {
142                if (d->d_type != elftype) {
143                        LIBELF_SET_ERROR(DATA, 0);
144                        return (0);
145                }
146                if (d->d_version != e->e_version) {
147                        LIBELF_SET_ERROR(VERSION, 0);
148                        return (0);
149                }
150                if ((d_align = d->d_align) % sh_align) {
151                        LIBELF_SET_ERROR(LAYOUT, 0);
152                        return (0);
153                }
154                if (d_align == 0 || (d_align & (d_align - 1))) {
155                        LIBELF_SET_ERROR(DATA, 0);
156                        return (0);
157                }
158                if (d_align > scn_alignment)
159                        scn_alignment = d_align;
160        }
161
162        scn_size = 0L;
163
164        STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) {
165                if (e->e_flags & ELF_F_LAYOUT) {
166                        if ((uint64_t) d->d_off + d->d_size > scn_size)
167                                scn_size = d->d_off + d->d_size;
168                } else {
169                        scn_size = roundup(scn_size, scn_alignment);
170                        d->d_off = scn_size;
171                        scn_size += d->d_size;
172                }
173        }
174
175        /*
176         * If the application is requesting full control over the layout
177         * of the section, check its values for sanity.
178         */
179        if (e->e_flags & ELF_F_LAYOUT) {
180                if (scn_alignment > sh_align || sh_offset % sh_align ||
181                    sh_size < scn_size) {
182                        LIBELF_SET_ERROR(LAYOUT, 0);
183                        return (0);
184                }
185        } else {
186                /*
187                 * Otherwise compute the values in the section header.
188                 */
189
190                if (scn_alignment > sh_align)
191                        sh_align = scn_alignment;
192
193                /*
194                 * If the section entry size is zero, try and fill in an
195                 * appropriate entry size.  Per the elf(5) manual page
196                 * sections without fixed-size entries should have their
197                 * 'sh_entsize' field set to zero.
198                 */
199                if (sh_entsize == 0 &&
200                    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
201                    (size_t) 1)) == 1)
202                        sh_entsize = 0;
203
204                sh_size = scn_size;
205                sh_offset = roundup(*rc, sh_align);
206
207                if (ec == ELFCLASS32) {
208                        s->s_shdr.s_shdr32.sh_addralign = (uint32_t) sh_align;
209                        s->s_shdr.s_shdr32.sh_entsize   = (uint32_t) sh_entsize;
210                        s->s_shdr.s_shdr32.sh_offset    = (uint32_t) sh_offset;
211                        s->s_shdr.s_shdr32.sh_size      = (uint32_t) sh_size;
212                } else {
213                        s->s_shdr.s_shdr64.sh_addralign = sh_align;
214                        s->s_shdr.s_shdr64.sh_entsize   = sh_entsize;
215                        s->s_shdr.s_shdr64.sh_offset    = sh_offset;
216                        s->s_shdr.s_shdr64.sh_size      = sh_size;
217                }
218        }
219
220        if ((size_t) *rc < sh_offset + sh_size)
221                *rc = sh_offset + sh_size;
222
223        s->s_size = sh_size;
224        s->s_offset = sh_offset;
225        return (1);
226}
227
228
229/*
230 * Insert a section in ascending order in the list
231 */
232
233static int
234_libelf_insert_section(Elf *e, Elf_Scn *s)
235{
236        Elf_Scn *t, *prevt;
237        uint64_t smax, smin, tmax, tmin;
238
239        smin = s->s_offset;
240        smax = smin + s->s_size;
241
242        prevt = NULL;
243        STAILQ_FOREACH(t, &e->e_u.e_elf.e_scn, s_next) {
244                tmin = t->s_offset;
245                tmax = tmin + t->s_size;
246
247                /* check if there is an overlap */
248                if (tmax < smin) {
249                        prevt = t;
250                        continue;
251                } else if (smax < tmin)
252                        break;
253                else {
254                        LIBELF_SET_ERROR(LAYOUT, 0);
255                        return (0);
256                }
257        }
258
259        if (prevt)
260                STAILQ_INSERT_AFTER(&e->e_u.e_elf.e_scn, prevt, s, s_next);
261        else
262                STAILQ_INSERT_HEAD(&e->e_u.e_elf.e_scn, s, s_next);
263        return (1);
264}
265
266static off_t
267_libelf_resync_sections(Elf *e, off_t rc)
268{
269        int ec;
270        off_t nrc;
271        size_t sh_type;
272        Elf_Scn *s, *ts;
273
274        ec = e->e_class;
275
276        /*
277         * Make a pass through sections, computing the extent of each
278         * section. Order in increasing order of addresses.
279         */
280
281        nrc = rc;
282        STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next)
283                if (_libelf_compute_section_extents(e, s, &nrc) == 0)
284                        return ((off_t) -1);
285
286        STAILQ_FOREACH_SAFE(s, &e->e_u.e_elf.e_scn, s_next, ts) {
287                if (ec == ELFCLASS32)
288                        sh_type = s->s_shdr.s_shdr32.sh_type;
289                else
290                        sh_type = s->s_shdr.s_shdr64.sh_type;
291
292                /* XXX Do we need the 'size' field of an SHT_NOBITS section */
293                if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
294                        continue;
295
296                if (s->s_offset < (uint64_t) rc) {
297                        if (s->s_offset + s->s_size < (uint64_t) rc) {
298                                /*
299                                 * Try insert this section in the
300                                 * correct place in the list,
301                                 * detecting overlaps if any.
302                                 */
303                                STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn,
304                                    s_next);
305                                if (_libelf_insert_section(e, s) == 0)
306                                        return ((off_t) -1);
307                        } else {
308                                LIBELF_SET_ERROR(LAYOUT, 0);
309                                return ((off_t) -1);
310                        }
311                } else
312                        rc = s->s_offset + s->s_size;
313        }
314
315        assert(nrc == rc);
316
317        return (rc);
318}
319
320static off_t
321_libelf_resync_elf(Elf *e)
322{
323        int ec, eh_class, eh_type;
324        unsigned int eh_byteorder, eh_version;
325        size_t align, fsz;
326        size_t phnum, shnum;
327        off_t rc, phoff, shoff;
328        void *ehdr;
329        Elf32_Ehdr *eh32;
330        Elf64_Ehdr *eh64;
331
332        rc = 0;
333
334        ec = e->e_class;
335
336        assert(ec == ELFCLASS32 || ec == ELFCLASS64);
337
338        /*
339         * Prepare the EHDR.
340         */
341        if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
342                return ((off_t) -1);
343
344        eh32 = ehdr;
345        eh64 = ehdr;
346
347        if (ec == ELFCLASS32) {
348                eh_byteorder = eh32->e_ident[EI_DATA];
349                eh_class     = eh32->e_ident[EI_CLASS];
350                phoff        = (uint64_t) eh32->e_phoff;
351                shoff        = (uint64_t) eh32->e_shoff;
352                eh_type      = eh32->e_type;
353                eh_version   = eh32->e_version;
354        } else {
355                eh_byteorder = eh64->e_ident[EI_DATA];
356                eh_class     = eh64->e_ident[EI_CLASS];
357                phoff        = eh64->e_phoff;
358                shoff        = eh64->e_shoff;
359                eh_type      = eh64->e_type;
360                eh_version   = eh64->e_version;
361        }
362
363        if (eh_version == EV_NONE)
364                eh_version = EV_CURRENT;
365
366        if (eh_version != e->e_version) {	/* always EV_CURRENT */
367                LIBELF_SET_ERROR(VERSION, 0);
368                return ((off_t) -1);
369        }
370
371        if (eh_class != e->e_class) {
372                LIBELF_SET_ERROR(CLASS, 0);
373                return ((off_t) -1);
374        }
375
376        if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
377                LIBELF_SET_ERROR(HEADER, 0);
378                return ((off_t) -1);
379        }
380
381        shnum = e->e_u.e_elf.e_nscn;
382        phnum = e->e_u.e_elf.e_nphdr;
383
384        e->e_byteorder = eh_byteorder;
385
386#define	INITIALIZE_EHDR(E,EC,V)	do {					\
387                (E)->e_ident[EI_MAG0] = ELFMAG0;			\
388                (E)->e_ident[EI_MAG1] = ELFMAG1;			\
389                (E)->e_ident[EI_MAG2] = ELFMAG2;			\
390                (E)->e_ident[EI_MAG3] = ELFMAG3;			\
391                (E)->e_ident[EI_CLASS] = (EC);				\
392                (E)->e_ident[EI_VERSION] = (V);				\
393                (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V),	\
394                    (size_t) 1);					\
395                (E)->e_phentsize = _libelf_fsize(ELF_T_PHDR, (EC), (V),	\
396                    (size_t) 1);					\
397                (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V),	\
398                    (size_t) 1);					\
399        } while (0)
400
401        if (ec == ELFCLASS32)
402                INITIALIZE_EHDR(eh32, ec, eh_version);
403        else
404                INITIALIZE_EHDR(eh64, ec, eh_version);
405
406        (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
407
408        rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1);
409
410        /*
411         * Compute the layout the program header table, if one is
412         * present.  The program header table needs to be aligned to a
413         * `natural' boundary.
414         */
415        if (phnum) {
416                fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
417                align = _libelf_falign(ELF_T_PHDR, ec);
418
419                if (e->e_flags & ELF_F_LAYOUT) {
420                        /*
421                         * Check offsets for sanity.
422                         */
423                        if (rc > phoff) {
424                                LIBELF_SET_ERROR(HEADER, 0);
425                                return ((off_t) -1);
426                        }
427
428                        if (phoff % align) {
429                                LIBELF_SET_ERROR(LAYOUT, 0);
430                                return ((off_t) -1);
431                        }
432
433                } else
434                        phoff = roundup(rc, align);
435
436                rc = phoff + fsz;
437        } else
438                phoff = 0;
439
440        /*
441         * Compute the layout of the sections associated with the
442         * file.
443         */
444
445        if ((rc = _libelf_resync_sections(e, rc)) < 0)
446                return ((off_t) -1);
447
448        /*
449         * Compute the space taken up by the section header table, if
450         * one is needed.
451         */
452        if (shnum) {
453                fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, (size_t) 1);
454                align = _libelf_falign(ELF_T_SHDR, ec);
455
456                if (e->e_flags & ELF_F_LAYOUT) {
457                        if (rc > shoff) {
458                                LIBELF_SET_ERROR(HEADER, 0);
459                                return ((off_t) -1);
460                        }
461
462                        if (shoff % align) {
463                                LIBELF_SET_ERROR(LAYOUT, 0);
464                                return ((off_t) -1);
465                        }
466                } else
467                        shoff = roundup(rc, align);
468
469                rc = shoff + fsz * shnum;
470        } else
471                shoff = 0;
472
473        /*
474         * Set the fields of the Executable Header that could potentially use
475         * extended numbering.
476         */
477        _libelf_setphnum(e, ehdr, ec, phnum);
478        _libelf_setshnum(e, ehdr, ec, shnum);
479
480        /*
481         * Update the `e_phoff' and `e_shoff' fields if the library is
482         * doing the layout.
483         */
484        if ((e->e_flags & ELF_F_LAYOUT) == 0) {
485                if (ec == ELFCLASS32) {
486                        eh32->e_phoff = (uint32_t) phoff;
487                        eh32->e_shoff = (uint32_t) shoff;
488                } else {
489                        eh64->e_phoff = (uint64_t) phoff;
490                        eh64->e_shoff = (uint64_t) shoff;
491                }
492        }
493
494        return (rc);
495}
496
497/*
498 * Write out the contents of a section.
499 */
500
501static off_t
502_libelf_write_scn(Elf *e, char *nf, Elf_Scn *s, off_t rc)
503{
504        int ec;
505        size_t fsz, msz, nobjects;
506        uint32_t sh_type;
507        uint64_t sh_off;
508        int elftype;
509        Elf_Data *d, dst;
510
511        if ((ec = e->e_class) == ELFCLASS32)
512                sh_type = s->s_shdr.s_shdr32.sh_type;
513        else
514                sh_type = s->s_shdr.s_shdr64.sh_type;
515
516        /*
517         * Ignore sections that do not allocate space in the file.
518         */
519        if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
520                return (rc);
521
522
523        elftype = _libelf_xlate_shtype(sh_type);
524        assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
525
526        msz = _libelf_msize(elftype, ec, e->e_version);
527
528        sh_off = s->s_offset;
529        assert(sh_off % _libelf_falign(elftype, ec) == 0);
530
531        /*
532         * If the section has a `rawdata' descriptor, and the section
533         * contents have not been modified, use its contents directly.
534         * The `s_rawoff' member contains the offset into the original
535         * file, while `s_offset' contains its new location in the
536         * destination.
537         */
538
539        if (STAILQ_EMPTY(&s->s_data)) {
540
541                if ((d = elf_rawdata(s, NULL)) == NULL)
542                        return ((off_t) -1);
543
544                STAILQ_FOREACH(d, &s->s_rawdata, d_next) {
545                        if ((uint64_t) rc < sh_off + d->d_off)
546                                (void) memset(nf + rc,
547                                    LIBELF_PRIVATE(fillchar), sh_off +
548                                    d->d_off - rc);
549                        rc = sh_off + d->d_off;
550
551                        assert(d->d_buf != NULL);
552                        assert(d->d_type == ELF_T_BYTE);
553                        assert(d->d_version == e->e_version);
554
555                        (void) memcpy(nf + rc,
556                            e->e_rawfile + s->s_rawoff + d->d_off, d->d_size);
557
558                        rc += d->d_size;
559                }
560
561                return (rc);
562        }
563
564        /*
565         * Iterate over the set of data descriptors for this section.
566         * The prior call to _libelf_resync_elf() would have setup the
567         * descriptors for this step.
568         */
569
570        dst.d_version = e->e_version;
571
572        STAILQ_FOREACH(d, &s->s_data, d_next) {
573
574                if ((uint64_t) rc < sh_off + d->d_off)
575                        (void) memset(nf + rc,
576                            LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc);
577
578                rc = sh_off + d->d_off;
579
580                assert(d->d_buf != NULL);
581                assert(d->d_type == (Elf_Type) elftype);
582                assert(d->d_version == e->e_version);
583                assert(d->d_size % msz == 0);
584
585                nobjects = d->d_size / msz;
586
587                fsz = _libelf_fsize(elftype, ec, e->e_version, nobjects);
588
589                dst.d_buf    = nf + rc;
590                dst.d_size   = fsz;
591
592                if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) ==
593                    NULL)
594                        return ((off_t) -1);
595
596                rc += fsz;
597        }
598
599        return ((off_t) rc);
600}
601
602/*
603 * Write out the file image.
604 *
605 * The original file could have been mapped in with an ELF_C_RDWR
606 * command and the application could have added new content or
607 * re-arranged its sections before calling elf_update().  Consequently
608 * its not safe to work `in place' on the original file.  So we
609 * malloc() the required space for the updated ELF object and build
610 * the object there and write it out to the underlying file at the
611 * end.  Note that the application may have opened the underlying file
612 * in ELF_C_RDWR and only retrieved/modified a few sections.  We take
613 * care to avoid translating file sections unnecessarily.
614 *
615 * Gaps in the coverage of the file by the file's sections will be
616 * filled with the fill character set by elf_fill(3).
617 */
618
619static off_t
620_libelf_write_elf(Elf *e, off_t newsize)
621{
622        int ec;
623        off_t rc;
624        size_t fsz, msz, phnum, shnum;
625        uint64_t phoff, shoff;
626        void *ehdr;
627        char *newfile;
628        Elf_Data dst, src;
629        Elf_Scn *scn, *tscn;
630        Elf32_Ehdr *eh32;
631        Elf64_Ehdr *eh64;
632
633        assert(e->e_kind == ELF_K_ELF);
634        assert(e->e_cmd != ELF_C_READ);
635        assert(e->e_fd >= 0);
636
637        if ((newfile = malloc((size_t) newsize)) == NULL) {
638                LIBELF_SET_ERROR(RESOURCE, errno);
639                return ((off_t) -1);
640        }
641
642        ec = e->e_class;
643
644        ehdr = _libelf_ehdr(e, ec, 0);
645        assert(ehdr != NULL);
646
647        phnum = e->e_u.e_elf.e_nphdr;
648
649        if (ec == ELFCLASS32) {
650                eh32 = (Elf32_Ehdr *) ehdr;
651
652                phoff = (uint64_t) eh32->e_phoff;
653                shnum = eh32->e_shnum;
654                shoff = (uint64_t) eh32->e_shoff;
655        } else {
656                eh64 = (Elf64_Ehdr *) ehdr;
657
658                phoff = eh64->e_phoff;
659                shnum = eh64->e_shnum;
660                shoff = eh64->e_shoff;
661        }
662
663        fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
664        msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);
665
666        (void) memset(&dst, 0, sizeof(dst));
667        (void) memset(&src, 0, sizeof(src));
668
669        src.d_buf     = ehdr;
670        src.d_size    = msz;
671        src.d_type    = ELF_T_EHDR;
672        src.d_version = dst.d_version = e->e_version;
673
674        rc = 0;
675
676        dst.d_buf     = newfile + rc;
677        dst.d_size    = fsz;
678
679        if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
680            NULL)
681                goto error;
682
683        rc += fsz;
684
685        /*
686         * Write the program header table if present.
687         */
688
689        if (phnum != 0 && phoff != 0) {
690                assert((unsigned) rc <= phoff);
691
692                fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
693
694                assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);
695                assert(fsz > 0);
696
697                src.d_version = dst.d_version = e->e_version;
698                src.d_type = ELF_T_PHDR;
699
700                if (ec == ELFCLASS32)
701                        src.d_buf = e->e_u.e_elf.e_phdr.e_phdr32;
702                else
703                        src.d_buf = e->e_u.e_elf.e_phdr.e_phdr64;
704
705                src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,
706                    e->e_version);
707
708                dst.d_size = fsz;
709
710                if ((uint64_t) rc < phoff)
711                        (void) memset(newfile + rc,
712                            LIBELF_PRIVATE(fillchar), phoff - rc);
713
714                dst.d_buf = newfile + rc;
715
716                if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
717                    NULL)
718                        goto error;
719
720                rc = phoff + fsz;
721        }
722
723        /*
724         * Write out individual sections.
725         */
726
727        STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next)
728                if ((rc = _libelf_write_scn(e, newfile, scn, rc)) < 0)
729                        goto error;
730
731        /*
732         * Write out the section header table, if required.
733         */
734
735        if (shnum != 0 && shoff != 0) {
736                assert((unsigned) rc <= shoff);
737
738                if ((uint64_t) rc < shoff)
739                        (void) memset(newfile + rc,
740                            LIBELF_PRIVATE(fillchar), shoff - rc);
741
742                rc = shoff;
743
744                assert(rc % _libelf_falign(ELF_T_SHDR, ec) == 0);
745
746                src.d_type = ELF_T_SHDR;
747                src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);
748                src.d_version = dst.d_version = e->e_version;
749
750                fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
751
752                STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) {
753                        if (ec == ELFCLASS32)
754                                src.d_buf = &scn->s_shdr.s_shdr32;
755                        else
756                                src.d_buf = &scn->s_shdr.s_shdr64;
757
758                        dst.d_size = fsz;
759                        dst.d_buf = newfile + rc;
760
761                        if (_libelf_xlate(&dst, &src, e->e_byteorder, ec,
762                                ELF_TOFILE) != &dst)
763                                goto error;
764
765                        rc += fsz;
766                }
767        }
768
769        /*
770         */
771
772        assert(rc == newsize);
773
774        /*
775         * Write out the constructed contents and remap the file in
776         * read-only.
777         */
778
779        if (e->e_rawfile && munmap(e->e_rawfile, e->e_rawsize) < 0) {
780                LIBELF_SET_ERROR(IO, errno);
781                goto error;
782        }
783
784        if (write(e->e_fd, newfile, (size_t) newsize) != newsize ||
785            lseek(e->e_fd, (off_t) 0, SEEK_SET) < 0) {
786                LIBELF_SET_ERROR(IO, errno);
787                goto error;
788        }
789
790        if (e->e_cmd != ELF_C_WRITE) {
791                if ((e->e_rawfile = mmap(NULL, (size_t) newsize, PROT_READ,
792                    MAP_PRIVATE, e->e_fd, (off_t) 0)) == MAP_FAILED) {
793                        LIBELF_SET_ERROR(IO, errno);
794                        goto error;
795                }
796                e->e_rawsize = newsize;
797        }
798
799        /*
800         * Reset flags, remove existing section descriptors and
801         * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
802         * and elf_getscn() will function correctly.
803         */
804
805        e->e_flags &= ~ELF_F_DIRTY;
806
807        STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)
808                _libelf_release_scn(scn);
809
810        if (ec == ELFCLASS32) {
811                free(e->e_u.e_elf.e_ehdr.e_ehdr32);
812                if (e->e_u.e_elf.e_phdr.e_phdr32)
813                        free(e->e_u.e_elf.e_phdr.e_phdr32);
814
815                e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
816                e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
817        } else {
818                free(e->e_u.e_elf.e_ehdr.e_ehdr64);
819                if (e->e_u.e_elf.e_phdr.e_phdr64)
820                        free(e->e_u.e_elf.e_phdr.e_phdr64);
821
822                e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
823                e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
824        }
825
826        return (rc);
827
828 error:
829        if (newfile)
830                free(newfile);
831        return ((off_t) -1);
832}
833
834off_t
835elf_update(Elf *e, Elf_Cmd c)
836{
837        int ec;
838        off_t rc;
839
840        rc = (off_t) -1;
841
842        if (e == NULL || e->e_kind != ELF_K_ELF ||
843            (c != ELF_C_NULL && c != ELF_C_WRITE)) {
844                LIBELF_SET_ERROR(ARGUMENT, 0);
845                return (rc);
846        }
847
848        if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
849                LIBELF_SET_ERROR(CLASS, 0);
850                return (rc);
851        }
852
853        if (e->e_version == EV_NONE)
854                e->e_version = EV_CURRENT;
855
856        if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
857                LIBELF_SET_ERROR(MODE, 0);
858                return (rc);
859        }
860
861        if ((rc = _libelf_resync_elf(e)) < 0)
862                return (rc);
863
864        if (c == ELF_C_NULL)
865                return (rc);
866
867        if (e->e_cmd == ELF_C_READ) {
868                /*
869                 * This descriptor was opened in read-only mode or by
870                 * elf_memory().
871                 */
872                if (e->e_fd)
873                        LIBELF_SET_ERROR(MODE, 0);
874                else
875                        LIBELF_SET_ERROR(ARGUMENT, 0);
876                return ((off_t) -1);
877        }
878
879        if (e->e_fd < 0) {
880                LIBELF_SET_ERROR(SEQUENCE, 0);
881                return ((off_t) -1);
882        }
883
884        return (_libelf_write_elf(e, rc));
885}
886