* elfcode.h (elf_swap_ehdr_out): Handle e_phnum > 0xffff.
authorAlan Modra <amodra@gmail.com>
Tue, 19 Jan 2010 13:50:55 +0000 (13:50 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 19 Jan 2010 13:50:55 +0000 (13:50 +0000)
(elf_object_p): Read e_phnum extension.
(elf_write_shdrs_and_ehdr): Write e_phnum extension.
        * elfcore.h (elf_core_file_p): Read e_phnum extension.  Sanity check
that we can read last program header.

bfd/ChangeLog
bfd/elfcode.h
bfd/elfcore.h

index 1801912..3f68528 100644 (file)
@@ -1,3 +1,12 @@
+2010-01-19  Daisuke Hatayama  <d.hatayama@jp.fujitsu.com>
+           Alan Modra <amodra@gmail.com>
+
+        * elfcode.h (elf_swap_ehdr_out): Handle e_phnum > 0xffff.
+       (elf_object_p): Read e_phnum extension.
+       (elf_write_shdrs_and_ehdr): Write e_phnum extension.
+        * elfcore.h (elf_core_file_p): Read e_phnum extension.  Sanity check
+       that we can read last program header.
+
 2010-01-19  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>
 
        * elf32-arm.c (elf32_arm_howto_table_1): Correct bitsize of
index ecdc2de..07ad3c9 100644 (file)
@@ -1,6 +1,6 @@
 /* ELF executable support for BFD.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
    Written by Fred Fish @ Cygnus Support, from information published
@@ -279,7 +279,10 @@ elf_swap_ehdr_out (bfd *abfd,
   H_PUT_32 (abfd, src->e_flags, dst->e_flags);
   H_PUT_16 (abfd, src->e_ehsize, dst->e_ehsize);
   H_PUT_16 (abfd, src->e_phentsize, dst->e_phentsize);
-  H_PUT_16 (abfd, src->e_phnum, dst->e_phnum);
+  tmp = src->e_phnum;
+  if (tmp > PN_XNUM)
+    tmp = PN_XNUM;
+  H_PUT_16 (abfd, tmp, dst->e_phnum);
   H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize);
   tmp = src->e_shnum;
   if (tmp >= (SHN_LORESERVE & 0xffff))
@@ -701,6 +704,14 @@ elf_object_p (bfd *abfd)
            goto got_wrong_format_error;
        }
 
+      /* And program headers.  */
+      if (i_ehdrp->e_phnum == PN_XNUM && i_shdr.sh_info != 0)
+       {
+         i_ehdrp->e_phnum = i_shdr.sh_info;
+         if (i_ehdrp->e_phnum != i_shdr.sh_info)
+           goto got_wrong_format_error;
+       }
+
       /* Sanity check that we can read all of the section headers.
         It ought to be good enough to just read the last one.  */
       if (i_ehdrp->e_shnum != 1)
@@ -1072,6 +1083,8 @@ elf_write_shdrs_and_ehdr (bfd *abfd)
 
   /* Some fields in the first section header handle overflow of ehdr
      fields.  */
+  if (i_ehdrp->e_phnum >= PN_XNUM)
+    i_shdrp[0]->sh_info = i_ehdrp->e_phnum;
   if (i_ehdrp->e_shnum >= (SHN_LORESERVE & 0xffff))
     i_shdrp[0]->sh_size = i_ehdrp->e_shnum;
   if (i_ehdrp->e_shstrndx >= (SHN_LORESERVE & 0xffff))
index c51c575..168c81a 100644 (file)
@@ -1,6 +1,6 @@
 /* ELF core file support for BFD.
    Copyright 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2007,
-   2008 Free Software Foundation, Inc.
+   2008, 2010 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -184,6 +184,61 @@ elf_core_file_p (bfd *abfd)
   if (i_ehdrp->e_phentsize != sizeof (Elf_External_Phdr))
     goto wrong;
 
+  /* If the program header count is PN_XNUM(0xffff), the actual
+     count is in the first section header.  */
+  if (i_ehdrp->e_shoff != 0 && i_ehdrp->e_phnum == PN_XNUM)
+    {
+      Elf_External_Shdr x_shdr;
+      Elf_Internal_Shdr i_shdr;
+      bfd_signed_vma where = i_ehdrp->e_shoff;
+
+      if (where != (file_ptr) where)
+       goto wrong;
+
+      /* Seek to the section header table in the file.  */
+      if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0)
+       goto fail;
+
+      /* Read the first section header at index 0, and convert to internal
+        form.  */
+      if (bfd_bread (&x_shdr, sizeof (x_shdr), abfd) != sizeof (x_shdr))
+       goto fail;
+      elf_swap_shdr_in (abfd, &x_shdr, &i_shdr);
+
+      if (i_shdr.sh_info != 0)
+       {
+         i_ehdrp->e_phnum = i_shdr.sh_info;
+         if (i_ehdrp->e_phnum != i_shdr.sh_info)
+           goto wrong;
+       }
+    }
+
+  /* Sanity check that we can read all of the program headers.
+     It ought to be good enough to just read the last one.  */
+  if (i_ehdrp->e_phnum > 1)
+    {
+      Elf_External_Phdr x_phdr;
+      Elf_Internal_Phdr i_phdr;
+      bfd_signed_vma where;
+
+      /* Check that we don't have a totally silly number of
+        program headers.  */
+      if (i_ehdrp->e_phnum > (unsigned int) -1 / sizeof (x_phdr)
+         || i_ehdrp->e_phnum > (unsigned int) -1 / sizeof (i_phdr))
+       goto wrong;
+
+      where = i_ehdrp->e_phoff + (i_ehdrp->e_phnum - 1) * sizeof (x_phdr);
+      if (where != (file_ptr) where)
+       goto wrong;
+      if ((bfd_size_type) where <= i_ehdrp->e_phoff)
+       goto wrong;
+
+      if (bfd_seek (abfd, (file_ptr) where, SEEK_SET) != 0)
+       goto fail;
+      if (bfd_bread (&x_phdr, sizeof (x_phdr), abfd) != sizeof (x_phdr))
+       goto fail;
+    }
+
   /* Move to the start of the program headers.  */
   if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0)
     goto wrong;