summaryrefslogtreecommitdiffstats
path: root/libelf/elf32_updatenull.c
diff options
context:
space:
mode:
Diffstat (limited to 'libelf/elf32_updatenull.c')
-rw-r--r--libelf/elf32_updatenull.c153
1 files changed, 108 insertions, 45 deletions
diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c
index 6811ad1f..a18d0bea 100644
--- a/libelf/elf32_updatenull.c
+++ b/libelf/elf32_updatenull.c
@@ -1,26 +1,59 @@
/* Update data structures for changes.
- Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, version 2.
-
- This program 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 a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat 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 a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
-//#include <endian.h>
+#include <endian.h>
#include <libelf.h>
#include <stdbool.h>
#include <string.h>
@@ -99,26 +132,33 @@ ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
off_t
-internal_function_def
-__elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
+internal_function
+__elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
{
- ElfW2(LIBELFBITS,Ehdr) *ehdr = INTUSE(elfw2(LIBELFBITS,getehdr)) (elf);
+ ElfW2(LIBELFBITS,Ehdr) *ehdr;
int changed = 0;
int ehdr_flags = 0;
- off_t size;
+
+ ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
/* Set the default values. */
if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
return -1;
/* At least the ELF header is there. */
- size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
+ off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
/* Set the program header position. */
+ if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL
+ && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN
+ || ehdr->e_type == ET_CORE))
+ (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
{
- /* Only executables or shared objects have a program header. */
- if (ehdr->e_type != ET_EXEC && unlikely (ehdr->e_type != ET_DYN))
+ /* Only executables, shared objects, and core files have a program
+ header. */
+ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
+ && unlikely (ehdr->e_type != ET_CORE))
{
__libelf_seterrno (ELF_E_INVALID_PHDR);
return -1;
@@ -154,31 +194,31 @@ __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
{
/* We have to fill in the number of sections in the header
of the zeroth section. */
- elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr.ELFW(e,LIBELFBITS)->sh_size
- = shnum;
- elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr_flags
- |= ELF_F_DIRTY;
- }
+ Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
+ update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
+ shnum, scn0->shdr_flags);
+ }
/* Go over all sections and find out how large they are. */
list = &elf->state.ELFW(elf,LIBELFBITS).scns;
+ /* Load the section headers if necessary. This loads the
+ headers for all sections. */
+ if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL)
+ (void) __elfw2(LIBELFBITS,getshdr_wrlock) (&list->data[1]);
+
do
{
- size_t cnt;
-
- for (cnt = first == true; cnt < list->cnt; ++cnt)
+ for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
{
Elf_Scn *scn = &list->data[cnt];
ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
off_t offset = 0;
- ElfW2(LIBELFBITS,Word) sh_entsize;
- ElfW2(LIBELFBITS,Word) sh_align;
assert (shdr != NULL);
- sh_entsize = shdr->sh_entsize;
- sh_align = shdr->sh_addralign ?: 1;
+ ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize;
+ ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1;
/* Set the sh_entsize value if we can reliably detect it. */
switch (shdr->sh_type)
@@ -227,6 +267,11 @@ __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
update_if_changed (shdr->sh_entsize, sh_entsize,
scn->shdr_flags);
+ if (scn->data_read == 0
+ && __libelf_set_rawdata_wrlock (scn) != 0)
+ /* Something went wrong. The error value is already set. */
+ return -1;
+
/* Iterate over all data blocks. */
if (list->data[cnt].data_list_rear != NULL)
{
@@ -234,28 +279,33 @@ __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
while (dl != NULL)
{
- if (unlikely (dl->data.d.d_version == EV_NONE)
- || unlikely (dl->data.d.d_version >= EV_NUM))
+ Elf_Data *data = &dl->data.d;
+ if (dl == &scn->data_list && data->d_buf == NULL
+ && scn->rawdata.d.d_buf != NULL)
+ data = &scn->rawdata.d;
+
+ if (unlikely (data->d_version == EV_NONE)
+ || unlikely (data->d_version >= EV_NUM))
{
__libelf_seterrno (ELF_E_UNKNOWN_VERSION);
return -1;
}
- if (unlikely (! powerof2 (dl->data.d.d_align)))
+ if (unlikely (! powerof2 (data->d_align)))
{
__libelf_seterrno (ELF_E_INVALID_ALIGN);
return -1;
}
- sh_align = MAX (sh_align, dl->data.d.d_align);
+ sh_align = MAX (sh_align, data->d_align);
if (elf->flags & ELF_F_LAYOUT)
{
/* The user specified the offset and the size.
All we have to do is check whether this block
fits in the size specified for the section. */
- if (unlikely ((GElf_Word) (dl->data.d.d_off
- + dl->data.d.d_size)
+ if (unlikely ((GElf_Word) (data->d_off
+ + data->d_size)
> shdr->sh_size))
{
__libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
@@ -265,19 +315,22 @@ __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
else
{
/* Determine the padding. */
- offset = ((offset + dl->data.d.d_align - 1)
- & ~(dl->data.d.d_align - 1));
+ offset = ((offset + data->d_align - 1)
+ & ~(data->d_align - 1));
- update_if_changed (dl->data.d.d_off, offset,
- changed);
+ update_if_changed (data->d_off, offset, changed);
- offset += dl->data.d.d_size;
+ offset += data->d_size;
}
/* Next data block. */
dl = dl->next;
}
}
+ else
+ /* Get the size of the section from the raw data. If
+ none is available the value is zero. */
+ offset += scn->rawdata.d.d_size;
if (elf->flags & ELF_F_LAYOUT)
{
@@ -305,8 +358,18 @@ __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
scn->shdr_flags);
size = (size + sh_align - 1) & ~(sh_align - 1);
+ int offset_changed = 0;
update_if_changed (shdr->sh_offset, (GElf_Word) size,
- changed);
+ offset_changed);
+ changed |= offset_changed;
+
+ if (offset_changed && scn->data_list_rear == NULL)
+ {
+ /* The position of the section in the file
+ changed. Create the section data list. */
+ if (__elf_getdata_rdlock (scn, NULL) == NULL)
+ return -1;
+ }
/* See whether the section size is correct. */
update_if_changed (shdr->sh_size, (GElf_Word) offset,