summaryrefslogtreecommitdiffstats
path: root/src/libelf/elf32_updatefile.c
diff options
context:
space:
mode:
authorChih-hung Hsieh <chh@google.com>2015-09-25 14:51:48 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-09-25 14:51:48 +0000
commitb0121c5547604527aaeea297b54047cd14b234df (patch)
tree7d9031ee3d5796de4a1825892fc6e04ba6e36ae2 /src/libelf/elf32_updatefile.c
parentd03895cf5f8b77c6a85abcd84ea0d80ff56be846 (diff)
parent5eafdf0f9bfd9a3c5f93414ac16bb399b6da0b7f (diff)
downloadandroid_external_elfutils-b0121c5547604527aaeea297b54047cd14b234df.tar.gz
android_external_elfutils-b0121c5547604527aaeea297b54047cd14b234df.tar.bz2
android_external_elfutils-b0121c5547604527aaeea297b54047cd14b234df.zip
Merge "Move files up to match upstream source structure."
Diffstat (limited to 'src/libelf/elf32_updatefile.c')
-rw-r--r--src/libelf/elf32_updatefile.c808
1 files changed, 0 insertions, 808 deletions
diff --git a/src/libelf/elf32_updatefile.c b/src/libelf/elf32_updatefile.c
deleted file mode 100644
index 153e377f..00000000
--- a/src/libelf/elf32_updatefile.c
+++ /dev/null
@@ -1,808 +0,0 @@
-/* Write changed data structures.
- Copyright (C) 2000-2010, 2014 Red Hat, Inc.
- This file is part of elfutils.
- Written by Ulrich Drepper <drepper@redhat.com>, 2000.
-
- This file is free software; you can redistribute it and/or modify
- it under the terms of either
-
- * the GNU Lesser General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at
- your option) any later version
-
- or
-
- * the GNU General Public License as published by the Free
- Software Foundation; either version 2 of the License, or (at
- your option) any later version
-
- or both in parallel, as here.
-
- elfutils is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received copies of the GNU General Public License and
- the GNU Lesser General Public License along with this program. If
- not, see <http://www.gnu.org/licenses/>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <assert.h>
-#include <errno.h>
-#include <libelf.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-
-#include <system.h>
-#include "libelfP.h"
-
-
-#ifndef LIBELFBITS
-# define LIBELFBITS 32
-#endif
-
-
-static int
-compare_sections (const void *a, const void *b)
-{
- const Elf_Scn **scna = (const Elf_Scn **) a;
- const Elf_Scn **scnb = (const Elf_Scn **) b;
-
- if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
- < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
- return -1;
-
- if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
- > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
- return 1;
-
- if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
- < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
- return -1;
-
- if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
- > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
- return 1;
-
- if ((*scna)->index < (*scnb)->index)
- return -1;
-
- if ((*scna)->index > (*scnb)->index)
- return 1;
-
- return 0;
-}
-
-
-/* Insert the sections in the list into the provided array and sort
- them according to their start offsets. For sections with equal
- start offsets, the size is used; for sections with equal start
- offsets and sizes, the section index is used. Sorting by size
- ensures that zero-length sections are processed first, which
- is what we want since they do not advance our file writing position. */
-static void
-sort_sections (Elf_Scn **scns, Elf_ScnList *list)
-{
- Elf_Scn **scnp = scns;
- do
- for (size_t cnt = 0; cnt < list->cnt; ++cnt)
- *scnp++ = &list->data[cnt];
- while ((list = list->next) != NULL);
-
- qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
-}
-
-
-int
-internal_function
-__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
-{
- bool previous_scn_changed = false;
-
- /* We need the ELF header several times. */
- ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
-
- /* Write out the ELF header. */
- if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
- {
- /* If the type sizes should be different at some time we have to
- rewrite this code. */
- assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
- == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
-
- if (unlikely (change_bo))
- {
- /* Today there is only one version of the ELF header. */
-#if EV_NUM != 2
- xfct_t fctp;
- fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
-#else
-# undef fctp
-# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
-#endif
-
- /* Do the real work. */
- (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
- sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
- }
- else if (elf->map_address + elf->start_offset != ehdr)
- memcpy (elf->map_address + elf->start_offset, ehdr,
- sizeof (ElfW2(LIBELFBITS,Ehdr)));
-
- elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
-
- /* We start writing sections after the ELF header only if there is
- no program header. */
- previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
- }
-
- size_t phnum;
- if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
- return -1;
-
- /* Write out the program header table. */
- if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
- && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
- & ELF_F_DIRTY))
- {
- /* If the type sizes should be different at some time we have to
- rewrite this code. */
- assert (sizeof (ElfW2(LIBELFBITS,Phdr))
- == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
-
- /* Maybe the user wants a gap between the ELF header and the program
- header. */
- if (ehdr->e_phoff > ehdr->e_ehsize)
- memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
- __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
-
- if (unlikely (change_bo))
- {
- /* Today there is only one version of the ELF header. */
-#if EV_NUM != 2
- xfct_t fctp;
- fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
-#else
-# undef fctp
-# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
-#endif
-
- /* Do the real work. */
- (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
- elf->state.ELFW(elf,LIBELFBITS).phdr,
- sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
- }
- else
- memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
- elf->state.ELFW(elf,LIBELFBITS).phdr,
- sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
-
- elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
-
- /* We modified the program header. Maybe this created a gap so
- we have to write fill bytes, if necessary. */
- previous_scn_changed = true;
- }
-
- /* From now on we have to keep track of the last position to eventually
- fill the gaps with the prescribed fill byte. */
- char *last_position = ((char *) elf->map_address + elf->start_offset
- + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
- ehdr->e_phoff)
- + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
-
- /* Write all the sections. Well, only those which are modified. */
- if (shnum > 0)
- {
- if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
- return 1;
-
- Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
- Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
- char *const shdr_start = ((char *) elf->map_address + elf->start_offset
- + ehdr->e_shoff);
- char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
-
-#if EV_NUM != 2
- xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
-#else
-# undef shdr_fctp
-# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
-#endif
-#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
-
- /* Get all sections into the array and sort them. */
- sort_sections (scns, list);
-
- /* We possibly have to copy the section header data because moving
- the sections might overwrite the data. */
- for (size_t cnt = 0; cnt < shnum; ++cnt)
- {
- Elf_Scn *scn = scns[cnt];
-
- if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
- && (scn->shdr_flags & ELF_F_MALLOCED) == 0
- && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
- {
- assert ((char *) elf->map_address + elf->start_offset
- < (char *) scn->shdr.ELFW(e,LIBELFBITS));
- assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
- < ((char *) elf->map_address + elf->start_offset
- + elf->maximum_size));
-
- void *p = alloca (sizeof (ElfW2(LIBELFBITS,Shdr)));
- scn->shdr.ELFW(e,LIBELFBITS)
- = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
- sizeof (ElfW2(LIBELFBITS,Shdr)));
- }
-
- /* If the file is mmaped and the original position of the
- section in the file is lower than the new position we
- need to save the section content since otherwise it is
- overwritten before it can be copied. If there are
- multiple data segments in the list only the first can be
- from the file. */
- if (((char *) elf->map_address + elf->start_offset
- <= (char *) scn->data_list.data.d.d_buf)
- && ((char *) scn->data_list.data.d.d_buf
- < ((char *) elf->map_address + elf->start_offset
- + elf->maximum_size))
- && (((char *) elf->map_address + elf->start_offset
- + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
- > (char *) scn->data_list.data.d.d_buf))
- {
- void *p = malloc (scn->data_list.data.d.d_size);
- if (p == NULL)
- {
- __libelf_seterrno (ELF_E_NOMEM);
- return -1;
- }
- scn->data_list.data.d.d_buf = scn->data_base
- = memcpy (p, scn->data_list.data.d.d_buf,
- scn->data_list.data.d.d_size);
- }
- }
-
- /* Iterate over all the section in the order in which they
- appear in the output file. */
- for (size_t cnt = 0; cnt < shnum; ++cnt)
- {
- Elf_Scn *scn = scns[cnt];
- if (scn->index == 0)
- {
- /* The dummy section header entry. It should not be
- possible to mark this "section" as dirty. */
- assert ((scn->flags & ELF_F_DIRTY) == 0);
- continue;
- }
-
- ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
- if (shdr->sh_type == SHT_NOBITS)
- goto next;
-
- char *scn_start = ((char *) elf->map_address
- + elf->start_offset + shdr->sh_offset);
- Elf_Data_List *dl = &scn->data_list;
- bool scn_changed = false;
-
- void fill_mmap (size_t offset)
- {
- size_t written = 0;
-
- if (last_position < shdr_start)
- {
- written = MIN (scn_start + offset - last_position,
- shdr_start - last_position);
-
- memset (last_position, __libelf_fill_byte, written);
- }
-
- if (last_position + written != scn_start + offset
- && shdr_end < scn_start + offset)
- {
- char *fill_start = MAX (shdr_end, scn_start);
- memset (fill_start, __libelf_fill_byte,
- scn_start + offset - fill_start);
- }
- }
-
- if (scn->data_list_rear != NULL)
- do
- {
- assert (dl->data.d.d_off >= 0);
- assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
- assert (dl->data.d.d_size <= (shdr->sh_size
- - (GElf_Off) dl->data.d.d_off));
-
- /* If there is a gap, fill it. */
- if (scn_start + dl->data.d.d_off > last_position
- && (dl->data.d.d_off == 0
- || ((scn->flags | dl->flags | elf->flags)
- & ELF_F_DIRTY) != 0))
- {
- fill_mmap (dl->data.d.d_off);
- last_position = scn_start + dl->data.d.d_off;
- }
-
- if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
- {
- /* Let it go backward if the sections use a bogus
- layout with overlaps. We'll overwrite the stupid
- user's section data with the latest one, rather than
- crashing. */
-
- last_position = scn_start + dl->data.d.d_off;
-
- if (unlikely (change_bo))
- {
-#if EV_NUM != 2
- xfct_t fctp;
- fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
-#else
-# undef fctp
-# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
-#endif
-
- /* Do the real work. */
- (*fctp) (last_position, dl->data.d.d_buf,
- dl->data.d.d_size, 1);
-
- last_position += dl->data.d.d_size;
- }
- else
- last_position = mempcpy (last_position,
- dl->data.d.d_buf,
- dl->data.d.d_size);
-
- scn_changed = true;
- }
- else
- last_position += dl->data.d.d_size;
-
- assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
- == last_position);
-
- dl->flags &= ~ELF_F_DIRTY;
-
- dl = dl->next;
- }
- while (dl != NULL);
- else
- {
- /* If the previous section (or the ELF/program
- header) changed we might have to fill the gap. */
- if (scn_start > last_position && previous_scn_changed)
- fill_mmap (0);
-
- /* We have to trust the existing section header information. */
- last_position = scn_start + shdr->sh_size;
- }
-
-
- previous_scn_changed = scn_changed;
- next:
- scn->flags &= ~ELF_F_DIRTY;
- }
-
- /* Fill the gap between last section and section header table if
- necessary. */
- if ((elf->flags & ELF_F_DIRTY)
- && last_position < ((char *) elf->map_address + elf->start_offset
- + ehdr->e_shoff))
- memset (last_position, __libelf_fill_byte,
- (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
- - last_position);
-
- /* Write the section header table entry if necessary. */
- for (size_t cnt = 0; cnt < shnum; ++cnt)
- {
- Elf_Scn *scn = scns[cnt];
-
- if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
- {
- if (unlikely (change_bo))
- (*shdr_fctp) (&shdr_dest[scn->index],
- scn->shdr.ELFW(e,LIBELFBITS),
- sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
- else
- memcpy (&shdr_dest[scn->index],
- scn->shdr.ELFW(e,LIBELFBITS),
- sizeof (ElfW2(LIBELFBITS,Shdr)));
-
- /* If we previously made a copy of the section header
- entry we now have to adjust the pointer again so
- point to new place in the mapping. */
- if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
- && (scn->shdr_flags & ELF_F_MALLOCED) == 0)
- scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
-
- scn->shdr_flags &= ~ELF_F_DIRTY;
- }
- }
- }
-
- /* That was the last part. Clear the overall flag. */
- elf->flags &= ~ELF_F_DIRTY;
-
- /* Make sure the content hits the disk. */
- char *msync_start = ((char *) elf->map_address
- + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
- char *msync_end = ((char *) elf->map_address
- + elf->start_offset + ehdr->e_shoff
- + ehdr->e_shentsize * shnum);
- (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
-
- return 0;
-}
-
-
-/* Size of the buffer we use to generate the blocks of fill bytes. */
-#define FILLBUFSIZE 4096
-
-/* If we have to convert the section buffer contents we have to use
- temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
- on the stack. */
-#define MAX_TMPBUF 32768
-
-
-/* Helper function to write out fill bytes. */
-static int
-fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
-{
- size_t filled = *filledp;
- size_t fill_len = MIN (len, FILLBUFSIZE);
-
- if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
- {
- /* Initialize a few more bytes. */
- memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
- *filledp = filled = fill_len;
- }
-
- do
- {
- /* This many bytes we want to write in this round. */
- size_t n = MIN (filled, len);
-
- if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
- {
- __libelf_seterrno (ELF_E_WRITE_ERROR);
- return 1;
- }
-
- pos += n;
- len -= n;
- }
- while (len > 0);
-
- return 0;
-}
-
-
-int
-internal_function
-__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
-{
- char fillbuf[FILLBUFSIZE];
- size_t filled = 0;
- bool previous_scn_changed = false;
-
- /* We need the ELF header several times. */
- ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
-
- /* Write out the ELF header. */
- if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
- {
- ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
- ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
-
- /* If the type sizes should be different at some time we have to
- rewrite this code. */
- assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
- == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
-
- if (unlikely (change_bo))
- {
- /* Today there is only one version of the ELF header. */
-#if EV_NUM != 2
- xfct_t fctp;
- fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
-#else
-# undef fctp
-# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
-#endif
-
- /* Write the converted ELF header in a temporary buffer. */
- (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
-
- /* This is the buffer we want to write. */
- out_ehdr = &tmp_ehdr;
- }
-
- /* Write out the ELF header. */
- if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
- sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
- != sizeof (ElfW2(LIBELFBITS,Ehdr))))
- {
- __libelf_seterrno (ELF_E_WRITE_ERROR);
- return 1;
- }
-
- elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
-
- /* We start writing sections after the ELF header only if there is
- no program header. */
- previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
- }
-
- /* If the type sizes should be different at some time we have to
- rewrite this code. */
- assert (sizeof (ElfW2(LIBELFBITS,Phdr))
- == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
-
- size_t phnum;
- if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
- return -1;
-
- /* Write out the program header table. */
- if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
- && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
- & ELF_F_DIRTY))
- {
- ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
- ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
-
- /* Maybe the user wants a gap between the ELF header and the program
- header. */
- if (ehdr->e_phoff > ehdr->e_ehsize
- && unlikely (fill (elf->fildes, ehdr->e_ehsize,
- ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
- != 0))
- return 1;
-
- if (unlikely (change_bo))
- {
- /* Today there is only one version of the ELF header. */
-#if EV_NUM != 2
- xfct_t fctp;
- fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
-#else
-# undef fctp
-# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
-#endif
-
- /* Allocate sufficient memory. */
- tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
- malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
- if (tmp_phdr == NULL)
- {
- __libelf_seterrno (ELF_E_NOMEM);
- return 1;
- }
-
- /* Write the converted ELF header in a temporary buffer. */
- (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
- sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
-
- /* This is the buffer we want to write. */
- out_phdr = tmp_phdr;
- }
-
- /* Write out the ELF header. */
- size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
- if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
- phdr_size, ehdr->e_phoff)
- != phdr_size))
- {
- __libelf_seterrno (ELF_E_WRITE_ERROR);
- return 1;
- }
-
- /* This is a no-op we we have not allocated any memory. */
- free (tmp_phdr);
-
- elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
-
- /* We modified the program header. Maybe this created a gap so
- we have to write fill bytes, if necessary. */
- previous_scn_changed = true;
- }
-
- /* From now on we have to keep track of the last position to eventually
- fill the gaps with the prescribed fill byte. */
- off_t last_offset;
- if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
- last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
- else
- last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
-
- /* Write all the sections. Well, only those which are modified. */
- if (shnum > 0)
- {
- if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
- + sizeof (ElfW2(LIBELFBITS,Shdr)))))
- return 1;
-
- off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
-#if EV_NUM != 2
- xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
-#else
-# undef shdr_fctp
-# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
-#endif
-
- ElfW2(LIBELFBITS,Shdr) *shdr_data;
- if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
- || (elf->flags & ELF_F_DIRTY))
- shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
- alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
- else
- shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
- int shdr_flags = elf->flags;
-
- /* Get all sections into the array and sort them. */
- Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
- Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
- sort_sections (scns, list);
-
- for (size_t cnt = 0; cnt < shnum; ++cnt)
- {
- Elf_Scn *scn = scns[cnt];
- if (scn->index == 0)
- {
- /* The dummy section header entry. It should not be
- possible to mark this "section" as dirty. */
- assert ((scn->flags & ELF_F_DIRTY) == 0);
- goto next;
- }
-
- ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
- if (shdr->sh_type == SHT_NOBITS)
- goto next;
-
- off_t scn_start = elf->start_offset + shdr->sh_offset;
- Elf_Data_List *dl = &scn->data_list;
- bool scn_changed = false;
-
- if (scn->data_list_rear != NULL)
- do
- {
- /* If there is a gap, fill it. */
- if (scn_start + dl->data.d.d_off > last_offset
- && ((previous_scn_changed && dl->data.d.d_off == 0)
- || ((scn->flags | dl->flags | elf->flags)
- & ELF_F_DIRTY) != 0))
- {
- if (unlikely (fill (elf->fildes, last_offset,
- (scn_start + dl->data.d.d_off)
- - last_offset, fillbuf,
- &filled) != 0))
- return 1;
- }
-
- if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
- {
- char tmpbuf[MAX_TMPBUF];
- void *buf = dl->data.d.d_buf;
-
- /* Let it go backward if the sections use a bogus
- layout with overlaps. We'll overwrite the stupid
- user's section data with the latest one, rather than
- crashing. */
-
- last_offset = scn_start + dl->data.d.d_off;
-
- if (unlikely (change_bo))
- {
-#if EV_NUM != 2
- xfct_t fctp;
- fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
-#else
-# undef fctp
-# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
-#endif
-
- buf = tmpbuf;
- if (dl->data.d.d_size > MAX_TMPBUF)
- {
- buf = malloc (dl->data.d.d_size);
- if (buf == NULL)
- {
- __libelf_seterrno (ELF_E_NOMEM);
- return 1;
- }
- }
-
- /* Do the real work. */
- (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
- }
-
- ssize_t n = pwrite_retry (elf->fildes, buf,
- dl->data.d.d_size,
- last_offset);
- if (unlikely ((size_t) n != dl->data.d.d_size))
- {
- if (buf != dl->data.d.d_buf && buf != tmpbuf)
- free (buf);
-
- __libelf_seterrno (ELF_E_WRITE_ERROR);
- return 1;
- }
-
- if (buf != dl->data.d.d_buf && buf != tmpbuf)
- free (buf);
-
- scn_changed = true;
- }
-
- last_offset += dl->data.d.d_size;
-
- dl->flags &= ~ELF_F_DIRTY;
-
- dl = dl->next;
- }
- while (dl != NULL);
- else
- {
- /* If the previous section (or the ELF/program
- header) changed we might have to fill the gap. */
- if (scn_start > last_offset && previous_scn_changed)
- {
- if (unlikely (fill (elf->fildes, last_offset,
- scn_start - last_offset, fillbuf,
- &filled) != 0))
- return 1;
- }
-
- last_offset = scn_start + shdr->sh_size;
- }
-
- previous_scn_changed = scn_changed;
- next:
- /* Collect the section header table information. */
- if (unlikely (change_bo))
- (*shdr_fctp) (&shdr_data[scn->index],
- scn->shdr.ELFW(e,LIBELFBITS),
- sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
- else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
- || (elf->flags & ELF_F_DIRTY))
- memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
- sizeof (ElfW2(LIBELFBITS,Shdr)));
-
- shdr_flags |= scn->shdr_flags;
- scn->shdr_flags &= ~ELF_F_DIRTY;
- }
-
- /* Fill the gap between last section and section header table if
- necessary. */
- if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
- && unlikely (fill (elf->fildes, last_offset,
- shdr_offset - last_offset,
- fillbuf, &filled) != 0))
- return 1;
-
- /* Write out the section header table. */
- if (shdr_flags & ELF_F_DIRTY
- && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
- sizeof (ElfW2(LIBELFBITS,Shdr))
- * shnum, shdr_offset)
- != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
- {
- __libelf_seterrno (ELF_E_WRITE_ERROR);
- return 1;
- }
- }
-
- /* That was the last part. Clear the overall flag. */
- elf->flags &= ~ELF_F_DIRTY;
-
- return 0;
-}