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