From: Roland McGrath Date: Fri, 8 Jan 2010 03:41:04 +0000 (-0800) Subject: Add elf_getphdrnum, support >65536 phdrs. X-Git-Tag: elfutils-0.144~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6fd3cd104adf4107aa64e1c1e84028b4ea0b3296;p=platform%2Fupstream%2Felfutils.git Add elf_getphdrnum, support >65536 phdrs. --- diff --git a/NEWS b/NEWS index 24aa18b..4a8163f 100644 --- a/NEWS +++ b/NEWS @@ -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 58b8fe9..c71c563 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,23 @@ +2010-01-07 Roland McGrath + + * 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 * elf32_updatefile.c (fill_mmap): When starting past shdr_end, start diff --git a/libelf/Makefile.am b/libelf/Makefile.am index 2899043..b277e94 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 ce6de07..1bc8ef3 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 c32c282..0a617a6 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 , 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 d1b1608..03ff100 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 , 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 8be1994..898cf1a 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 , 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 5ce8bbc..ca9a870 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 , 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 04670a4..896d86b 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 , 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 0000000..edf073e --- /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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#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 66cd143..7b04b39 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 , 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 e8b7f78..d6d5f5a 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 , 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 16c7a7a..b0b3a8d 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 e0f40eb..de6d912 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 ca754a0..2b8391b 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 , 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)