diff options
author | Roland McGrath <roland@redhat.com> | 2010-01-07 19:41:04 -0800 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2010-01-07 19:43:42 -0800 |
commit | 6fd3cd104adf4107aa64e1c1e84028b4ea0b3296 (patch) | |
tree | 6d42f1017e802ccf94abbe5af598eec8b2600166 | |
parent | 7452e1953a4a4e70af3fb472e609e89776031e53 (diff) | |
download | android_external_elfutils-6fd3cd104adf4107aa64e1c1e84028b4ea0b3296.tar.gz android_external_elfutils-6fd3cd104adf4107aa64e1c1e84028b4ea0b3296.tar.bz2 android_external_elfutils-6fd3cd104adf4107aa64e1c1e84028b4ea0b3296.zip |
Add elf_getphdrnum, support >65536 phdrs.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | libelf/ChangeLog | 20 | ||||
-rw-r--r-- | libelf/Makefile.am | 4 | ||||
-rw-r--r-- | libelf/elf.h | 31 | ||||
-rw-r--r-- | libelf/elf32_getphdr.c | 6 | ||||
-rw-r--r-- | libelf/elf32_newphdr.c | 32 | ||||
-rw-r--r-- | libelf/elf32_updatefile.c | 26 | ||||
-rw-r--r-- | libelf/elf32_updatenull.c | 10 | ||||
-rw-r--r-- | libelf/elf_begin.c | 21 | ||||
-rw-r--r-- | libelf/elf_getphdrnum.c | 116 | ||||
-rw-r--r-- | libelf/gelf_getphdr.c | 14 | ||||
-rw-r--r-- | libelf/gelf_update_phdr.c | 14 | ||||
-rw-r--r-- | libelf/libelf.h | 8 | ||||
-rw-r--r-- | libelf/libelf.map | 5 | ||||
-rw-r--r-- | libelf/libelfP.h | 4 |
15 files changed, 267 insertions, 47 deletions
@@ -1,5 +1,8 @@ Version 0.144: +libelf: New function elf_getphdrnum. + Now support using more than 65536 program headers in a file. + libdw: New function dwarf_aggregate_size for computing (constant) type sizes, including array_type cases with nontrivial calculation. diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 58b8fe9a..c71c5638 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,23 @@ +2010-01-07 Roland McGrath <roland@redhat.com> + + * elf32_getphdr.c: Use __elf_getphdrnum_rdlock. + * gelf_getphdr.c: Likewise. + * gelf_update_phdr.c: Likewise. + * elf32_updatefile.c (__elf32_updatemmap, __elf32_updatefile): Likewise. + * elf32_updatenull.c (__elf32_updatenull_wrlock): Likewise. + * elf32_newphdr.c: Clear section 0's sh_info when resetting e_phnum. + If COUNT is too large, use store PN_XNUM instead and set sh_info. + * elf_begin.c (file_read_elf): Always allocate space we can use later + for section 0 if doing RDWR. + + * elf_getphdrnum.c: New file. + * Makefile.am (libelf_a_SOURCES): Add it. + * libelf.h: Declare elf_getphdrnum. + * libelfP.h: Declare __elf_getphdrnum_rdlock. + * libelf.map (ELFUTILS_1.6): New set, add elf_getphdrnum. + + * elf.h: Update from glibc. + 2009-10-23 Lubomir Rintel <lkundrak@v3.sk> * elf32_updatefile.c (fill_mmap): When starting past shdr_end, start diff --git a/libelf/Makefile.am b/libelf/Makefile.am index 2899043d..b277e944 100644 --- a/libelf/Makefile.am +++ b/libelf/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 1996-2006, 2007, 2008, 2009 Red Hat, Inc. +## Copyright (C) 1996-2010 Red Hat, Inc. ## This file is part of Red Hat elfutils. ## ## Red Hat elfutils is free software; you can redistribute it and/or modify @@ -91,7 +91,7 @@ libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \ gelf_update_versym.c gelf_update_verneed.c \ gelf_update_vernaux.c gelf_update_verdef.c \ gelf_update_verdaux.c \ - elf_getshdrnum.c elf_getshdrstrndx.c \ + elf_getphdrnum.c elf_getshdrnum.c elf_getshdrstrndx.c \ gelf_checksum.c elf32_checksum.c elf64_checksum.c \ libelf_crc32.c libelf_next_prime.c \ elf_clone.c \ diff --git a/libelf/elf.h b/libelf/elf.h index ce6de07e..1bc8ef34 100644 --- a/libelf/elf.h +++ b/libelf/elf.h @@ -1,5 +1,5 @@ /* This file defines standard ELF types, structures, and macros. - Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009 + Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -558,6 +558,12 @@ typedef struct Elf64_Xword p_align; /* Segment alignment */ } Elf64_Phdr; +/* Special value for e_phnum. This indicates that the real number of + program headers is too large to fit into e_phnum. Instead the real + value is in the field sh_info of section 0. */ + +#define PN_XNUM 0xffff + /* Legal values for p_type (segment type). */ #define PT_NULL 0 /* Program header table entry unused */ @@ -2041,9 +2047,6 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ #define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ -/* Keep this the last entry. */ -#define R_PPC_NUM 95 - /* The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 @@ -2071,11 +2074,14 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ #define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ +/* GNU extension to support local ifunc. */ +#define R_PPC_IRELATIVE 248 + /* GNU relocs used in PIC code sequences. */ -#define R_PPC_REL16 249 /* word32 (sym-.) */ -#define R_PPC_REL16_LO 250 /* half16 (sym-.)@l */ -#define R_PPC_REL16_HI 251 /* half16 (sym-.)@h */ -#define R_PPC_REL16_HA 252 /* half16 (sym-.)@ha */ +#define R_PPC_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ /* This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. */ @@ -2197,8 +2203,13 @@ typedef Elf32_Addr Elf32_Conflict; #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ -/* Keep this the last entry. */ -#define R_PPC64_NUM 107 +/* GNU extension to support local ifunc. */ +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ /* PowerPC64 specific values for the Dyn d_tag field. */ #define DT_PPC64_GLINK (DT_LOPROC + 0) diff --git a/libelf/elf32_getphdr.c b/libelf/elf32_getphdr.c index c32c2827..0a617a67 100644 --- a/libelf/elf32_getphdr.c +++ b/libelf/elf32_getphdr.c @@ -1,5 +1,5 @@ /* Get ELF program header table. - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006 Red Hat, Inc. + Copyright (C) 1998-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -94,7 +94,9 @@ __elfw2(LIBELFBITS,getphdr_wrlock) (elf) ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; /* If no program header exists return NULL. */ - size_t phnum = ehdr->e_phnum; + size_t phnum; + if (__elf_getphdrnum_rdlock (elf, &phnum) != 0) + goto out; if (phnum == 0) { __libelf_seterrno (ELF_E_NO_PHDR); diff --git a/libelf/elf32_newphdr.c b/libelf/elf32_newphdr.c index d1b16088..03ff100a 100644 --- a/libelf/elf32_newphdr.c +++ b/libelf/elf32_newphdr.c @@ -1,5 +1,5 @@ /* Create new ELF program header table. - Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + Copyright (C) 1999-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -79,6 +79,12 @@ elfw2(LIBELFBITS,newphdr) (elf, count) return NULL; } + if (unlikely ((ElfW2(LIBELFBITS,Word)) count != count)) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + rwlock_wrlock (elf->lock); if (elf->class == 0) @@ -110,6 +116,10 @@ elfw2(LIBELFBITS,newphdr) (elf, count) elf->state.ELFW(elf,LIBELFBITS).phdr = NULL; /* Set the `e_phnum' member to the new value. */ elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = 0; + /* Also clear any old PN_XNUM extended value. */ + if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0) + elf->state.ELFW(elf,LIBELFBITS).scns.data[0] + .shdr.ELFW(e,LIBELFBITS)->sh_info = 0; /* Also set the size. */ elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = sizeof (ElfW2(LIBELFBITS,Phdr)); @@ -122,6 +132,7 @@ elfw2(LIBELFBITS,newphdr) (elf, count) result = NULL; } else if (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum != count + || count == PN_XNUM || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) { /* Allocate a new program header with the appropriate number of @@ -135,10 +146,24 @@ elfw2(LIBELFBITS,newphdr) (elf, count) { /* Now set the result. */ elf->state.ELFW(elf,LIBELFBITS).phdr = result; + if (count >= PN_XNUM) + { + /* We have to write COUNT into the zeroth section's sh_info. */ + Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0]; + if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt == 0) + { + assert (elf->state.ELFW(elf,LIBELFBITS).scns.max > 0); + elf->state.ELFW(elf,LIBELFBITS).scns.cnt = 1; + } + scn0->shdr.ELFW(e,LIBELFBITS)->sh_info = count; + scn0->shdr_flags |= ELF_F_DIRTY; + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = PN_XNUM; + } + else + /* Set the `e_phnum' member to the new value. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count; /* Clear the whole memory. */ memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr))); - /* Set the `e_phnum' member to the new value. */ - elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count; /* Also set the size. */ elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = elf_typesize (LIBELFBITS, ELF_T_PHDR, 1); @@ -161,6 +186,7 @@ elfw2(LIBELFBITS,newphdr) (elf, count) elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY; result = elf->state.ELFW(elf,LIBELFBITS).phdr; + memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr))); } out: diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index 8be19948..898cf1ab 100644 --- a/libelf/elf32_updatefile.c +++ b/libelf/elf32_updatefile.c @@ -1,5 +1,5 @@ /* Write changed data structures. - Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. + Copyright (C) 2000-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2000. @@ -165,6 +165,10 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) 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) @@ -195,12 +199,12 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) /* Do the real work. */ (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff, elf->state.ELFW(elf,LIBELFBITS).phdr, - sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1); + 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)) * ehdr->e_phnum); + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; @@ -214,8 +218,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) 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, - ehdr->e_phnum)); + + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum)); /* Write all the sections. Well, only those which are modified. */ if (shnum > 0) @@ -563,6 +566,10 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) 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) @@ -592,7 +599,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) /* Allocate sufficient memory. */ tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *) - malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum); + malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); if (tmp_phdr == NULL) { __libelf_seterrno (ELF_E_NOMEM); @@ -601,14 +608,14 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) /* Write the converted ELF header in a temporary buffer. */ (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr, - sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1); + 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)) * ehdr->e_phnum; + 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)) @@ -633,8 +640,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) 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)) * ehdr->e_phnum); + last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); /* Write all the sections. Well, only those which are modified. */ if (shnum > 0) diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c index 5ce8bbc9..ca9a8708 100644 --- a/libelf/elf32_updatenull.c +++ b/libelf/elf32_updatenull.c @@ -1,5 +1,5 @@ /* Update data structures for changes. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 Red Hat, Inc. + Copyright (C) 2000-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2000. @@ -164,13 +164,17 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum) return -1; } + size_t phnum; + if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0)) + return -1; + if (elf->flags & ELF_F_LAYOUT) { /* The user is supposed to fill out e_phoff. Use it and e_phnum to determine the maximum extend. */ size = MAX ((size_t) size, ehdr->e_phoff - + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum)); + + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum)); } else { @@ -179,7 +183,7 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum) ehdr_flags); /* We need no alignment here. */ - size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum); + size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum); } } diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index 04670a45..896d86b6 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -1,5 +1,5 @@ /* Create descriptor for processing file. - Copyright (C) 1998-2005, 2006, 2007, 2008 Red Hat, Inc. + Copyright (C) 1998-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -285,13 +285,22 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, /* Could not determine the number of sections. */ return NULL; - /* We can now allocate the memory. */ + /* We can now allocate the memory. Even if there are no section headers, + we allocate space for a zeroth section in case we need it later. */ + const size_t scnmax = (scncnt ?: (cmd == ELF_C_RDWR || cmd == ELF_C_RDWR_MMAP) + ? 1 : 0); Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, - ELF_K_ELF, scncnt * sizeof (Elf_Scn)); + ELF_K_ELF, scnmax * sizeof (Elf_Scn)); if (elf == NULL) /* Not enough memory. */ return NULL; + assert ((unsigned int) scncnt == scncnt); + assert (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)); + elf->state.elf32.scns.cnt = scncnt; + elf->state.elf32.scns.max = scnmax; + /* Some more or less arbitrary value. */ elf->state.elf.scnincr = 10; @@ -304,9 +313,6 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, not sufficient for the architecture. */ Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset); - assert ((unsigned int) scncnt == scncnt); - elf->state.elf32.scns.cnt = elf->state.elf32.scns.max = scncnt; - /* This is a 32-bit binary. */ if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA && (ALLOW_UNALIGNED @@ -392,9 +398,6 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, not sufficient for the architecture. */ Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset); - assert ((unsigned int) scncnt == scncnt); - elf->state.elf64.scns.cnt = elf->state.elf64.scns.max = scncnt; - /* This is a 64-bit binary. */ if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA && (ALLOW_UNALIGNED diff --git a/libelf/elf_getphdrnum.c b/libelf/elf_getphdrnum.c new file mode 100644 index 00000000..edf073ec --- /dev/null +++ b/libelf/elf_getphdrnum.c @@ -0,0 +1,116 @@ +/* Return number of program headers in the ELF file. + Copyright (C) 2010 Red Hat, Inc. + This file is part of Red Hat elfutils. + + 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 <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +int +__elf_getphdrnum_rdlock (elf, dst) + Elf *elf; + size_t *dst; +{ + if (unlikely (elf->state.elf64.ehdr == NULL)) + { + /* Maybe no ELF header was created yet. */ + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + return -1; + } + + *dst = (elf->class == ELFCLASS32 + ? elf->state.elf32.ehdr->e_phnum + : elf->state.elf64.ehdr->e_phnum); + + if (*dst == PN_XNUM) + { + const Elf_ScnList *const scns = (elf->class == ELFCLASS32 + ? &elf->state.elf32.scns + : &elf->state.elf64.scns); + + /* If there are no section headers, perhaps this is really just 65536 + written without PN_XNUM support. Either that or it's bad data. */ + + if (likely (scns->cnt > 0)) + *dst = (elf->class == ELFCLASS32 + ? scns->data[0].shdr.e32->sh_info + : scns->data[0].shdr.e64->sh_info); + } + + return 0; +} + +int +elf_getphdrnum (elf, dst) + Elf *elf; + size_t *dst; +{ + int result; + + if (elf == NULL) + return -1; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_rdlock (elf->lock); + result = __elf_getphdrnum_rdlock (elf, dst); + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/gelf_getphdr.c b/libelf/gelf_getphdr.c index 66cd143d..7b04b399 100644 --- a/libelf/gelf_getphdr.c +++ b/libelf/gelf_getphdr.c @@ -1,5 +1,5 @@ /* Return program header table entry. - Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Copyright (C) 1998-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -100,7 +100,11 @@ gelf_getphdr (elf, ndx, dst) } /* Test whether the index is ok. */ - if (ndx >= elf->state.elf32.ehdr->e_phnum) + size_t phnum; + if (ndx >= elf->state.elf32.ehdr->e_phnum + && (elf->state.elf32.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) { __libelf_seterrno (ELF_E_INVALID_INDEX); goto out; @@ -138,7 +142,11 @@ gelf_getphdr (elf, ndx, dst) } /* Test whether the index is ok. */ - if (ndx >= elf->state.elf64.ehdr->e_phnum) + size_t phnum; + if (ndx >= elf->state.elf64.ehdr->e_phnum + && (elf->state.elf64.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) { __libelf_seterrno (ELF_E_INVALID_INDEX); goto out; diff --git a/libelf/gelf_update_phdr.c b/libelf/gelf_update_phdr.c index e8b7f788..d6d5f5ae 100644 --- a/libelf/gelf_update_phdr.c +++ b/libelf/gelf_update_phdr.c @@ -1,5 +1,5 @@ /* Update program header program header table entry. - Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + Copyright (C) 2000-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2000. @@ -101,7 +101,11 @@ gelf_update_phdr (Elf *elf, int ndx, GElf_Phdr *src) } /* Test whether the index is ok. */ - if (unlikely (ndx >= elf->state.elf32.ehdr->e_phnum)) + size_t phnum; + if (ndx >= elf->state.elf32.ehdr->e_phnum + && (elf->state.elf32.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) { __libelf_seterrno (ELF_E_INVALID_INDEX); goto out; @@ -134,7 +138,11 @@ gelf_update_phdr (Elf *elf, int ndx, GElf_Phdr *src) } /* Test whether the index is ok. */ - if (unlikely (ndx >= elf->state.elf64.ehdr->e_phnum)) + size_t phnum; + if (ndx >= elf->state.elf64.ehdr->e_phnum + && (elf->state.elf64.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) { __libelf_seterrno (ELF_E_INVALID_INDEX); goto out; diff --git a/libelf/libelf.h b/libelf/libelf.h index 16c7a7a2..b0b3a8d7 100644 --- a/libelf/libelf.h +++ b/libelf/libelf.h @@ -1,5 +1,5 @@ /* Interface for libelf. - Copyright (C) 1998-2000, 2002, 2004-2007, 2009 Red Hat, Inc. + Copyright (C) 1998-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -220,6 +220,12 @@ extern Elf32_Ehdr *elf32_newehdr (Elf *__elf); /* Similar but this time the binary calls is ELFCLASS64. */ extern Elf64_Ehdr *elf64_newehdr (Elf *__elf); +/* Get the number of program headers in the ELF file. If the file uses + more headers than can be represented in the e_phnum field of the ELF + header the information from the sh_info field in the zeroth section + header is used. */ +extern int elf_getphdrnum (Elf *__elf, size_t *__dst); + /* Retrieve class-dependent program header table. */ extern Elf32_Phdr *elf32_getphdr (Elf *__elf); /* Similar but this time the binary calls is ELFCLASS64. */ diff --git a/libelf/libelf.map b/libelf/libelf.map index e0f40eb8..de6d912a 100644 --- a/libelf/libelf.map +++ b/libelf/libelf.map @@ -133,3 +133,8 @@ ELFUTILS_1.5 { global: elf_getshdrnum; elf_getshdrstrndx; } ELFUTILS_1.4; + +ELFUTILS_1.6 { + global: + elf_getphdrnum; +} ELFUTILS_1.5; diff --git a/libelf/libelfP.h b/libelf/libelfP.h index ca754a01..2b8391bd 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -1,5 +1,5 @@ /* Internal interfaces for libelf. - Copyright (C) 1998-2003, 2005, 2006, 2007, 2009 Red Hat, Inc. + Copyright (C) 1998-2010 Red Hat, Inc. This file is part of Red Hat elfutils. Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. @@ -530,6 +530,8 @@ extern Elf_Scn *__elf32_offscn_internal (Elf *__elf, Elf32_Off __offset) attribute_hidden; extern Elf_Scn *__elf64_offscn_internal (Elf *__elf, Elf64_Off __offset) attribute_hidden; +extern int __elf_getphdrnum_rdlock (Elf *__elf, size_t *__dst) + internal_function; extern int __elf_getshdrnum_rdlock (Elf *__elf, size_t *__dst) internal_function; extern int __elf_getshdrstrndx_internal (Elf *__elf, size_t *__dst) |