Add elf_getphdrnum, support >65536 phdrs.
authorRoland McGrath <roland@redhat.com>
Fri, 8 Jan 2010 03:41:04 +0000 (19:41 -0800)
committerRoland McGrath <roland@redhat.com>
Fri, 8 Jan 2010 03:43:42 +0000 (19:43 -0800)
15 files changed:
NEWS
libelf/ChangeLog
libelf/Makefile.am
libelf/elf.h
libelf/elf32_getphdr.c
libelf/elf32_newphdr.c
libelf/elf32_updatefile.c
libelf/elf32_updatenull.c
libelf/elf_begin.c
libelf/elf_getphdrnum.c [new file with mode: 0644]
libelf/gelf_getphdr.c
libelf/gelf_update_phdr.c
libelf/libelf.h
libelf/libelf.map
libelf/libelfP.h

diff --git a/NEWS b/NEWS
index 24aa18b..4a8163f 100644 (file)
--- 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.
 
index 58b8fe9..c71c563 100644 (file)
@@ -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
index 2899043..b277e94 100644 (file)
@@ -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 \
index ce6de07..1bc8ef3 100644 (file)
@@ -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)
index c32c282..0a617a6 100644 (file)
@@ -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);
index d1b1608..03ff100 100644 (file)
@@ -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:
index 8be1994..898cf1a 100644 (file)
@@ -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)
index 5ce8bbc..ca9a870 100644 (file)
@@ -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);
        }
     }
 
index 04670a4..896d86b 100644 (file)
@@ -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 (file)
index 0000000..edf073e
--- /dev/null
@@ -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;
+}
index 66cd143..7b04b39 100644 (file)
@@ -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;
index e8b7f78..d6d5f5a 100644 (file)
@@ -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;
index 16c7a7a..b0b3a8d 100644 (file)
@@ -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.  */
index e0f40eb..de6d912 100644 (file)
@@ -133,3 +133,8 @@ ELFUTILS_1.5 {
   global:
     elf_getshdrnum; elf_getshdrstrndx;
 } ELFUTILS_1.4;
+
+ELFUTILS_1.6 {
+  global:
+    elf_getphdrnum;
+} ELFUTILS_1.5;
index ca754a0..2b8391b 100644 (file)
@@ -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)