This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Commit: Binutils: Improve handling of archives with 64-bit index tables


Hi Guys,

   I am applying the patch below to fix up readelf's handling of
   archives with 64-bit index tables.  There were two problems with
   this.  The first was that the code in elfcomm.c:setup_archive assumed
   that the index tables were always 32-bits wide.  The second was that
   readelf assumed that the symbol tables was always padded to a 16-bit
   boundary, but with 64-bit archives the padding is to a 64-bit
   boundary.

   Tested with a wide variety of different toolchains.  No regressions
   were found.

Cheers
  Nick

binutils/ChangeLog
2012-07-17  Nick Clifton  <nickc@redhat.com>

	* elfcomm.c (setup_archive): Extract index table and symbol table
	scanning code into...
	(process_archive_index_and_symbols): ... this function and add
	support for 64-bit index tables.
	* elfcomm.h (struct archive_info): Change type of index_num and
	index_array to elf_vma.
	Add 'uses_64bit_indicies' field.
	* readelf.c (process_archive): Fix support for 64-bit indicies.

Index: binutils/elfcomm.c
===================================================================
RCS file: /cvs/src/src/binutils/elfcomm.c,v
retrieving revision 1.2
diff -u -3 -p -r1.2 elfcomm.c
--- binutils/elfcomm.c	15 Feb 2012 18:32:30 -0000	1.2
+++ binutils/elfcomm.c	17 Jul 2012 15:50:10 -0000
@@ -29,6 +29,7 @@
 #include "aout/ar.h"
 #include "bucomm.h"
 #include "elfcomm.h"
+#include <assert.h>
 
 void
 error (const char *message, ...)
@@ -303,6 +304,146 @@ adjust_relative_path (const char *file_n
   return member_file_name;
 }
 
+/* Processes the archive index table and symbol table in ARCH.
+   Entries in the index table are SIZEOF_AR_INDEX bytes long.
+   Fills in ARCH->next_arhdr_offset and ARCH->arhdr.
+   If READ_SYMBOLS is true then fills in ARCH->index_num, ARCH->index_array,
+    ARCH->sym_size and ARCH->sym_table.
+   It is the caller's responsibility to free ARCH->index_array and
+    ARCH->sym_table.
+   Returns TRUE upon success, FALSE otherwise.
+   If failure occurs an error message is printed.  */
+
+static bfd_boolean
+process_archive_index_and_symbols (struct archive_info *  arch,
+				   unsigned int           sizeof_ar_index,
+				   bfd_boolean            read_symbols)
+{
+  size_t got;
+  unsigned long size;
+
+  size = strtoul (arch->arhdr.ar_size, NULL, 10);
+  size = size + (size & 1);
+
+  arch->next_arhdr_offset += sizeof arch->arhdr + size;
+
+  if (! read_symbols)
+    {
+      if (fseek (arch->file, size, SEEK_CUR) != 0)
+	{
+	  error (_("%s: failed to skip archive symbol table\n"),
+		 arch->file_name);
+	  return FALSE;
+	}
+    }
+  else
+    {
+      unsigned long i;
+      /* A buffer used to hold numbers read in from an archive index.
+	 These are always SIZEOF_AR_INDEX bytes long and stored in
+	 big-endian format.  */
+      unsigned char integer_buffer[sizeof arch->index_num];
+      unsigned char * index_buffer;
+
+      assert (sizeof_ar_index <= sizeof integer_buffer);
+  
+      /* Check the size of the archive index.  */
+      if (size < sizeof_ar_index)
+	{
+	  error (_("%s: the archive index is empty\n"), arch->file_name);
+	  return FALSE;
+	}
+
+      /* Read the number of entries in the archive index.  */
+      got = fread (integer_buffer, 1, sizeof_ar_index, arch->file);
+      if (got != sizeof_ar_index)
+	{
+	  error (_("%s: failed to read archive index\n"), arch->file_name);
+	  return FALSE;
+	}
+
+      arch->index_num = byte_get_big_endian (integer_buffer, sizeof_ar_index);
+      size -= sizeof_ar_index;
+
+      if (size < arch->index_num * sizeof_ar_index)
+	{
+	  error (_("%s: the archive index is supposed to have %ld entries of %d bytes, but the size is only %ld\n"),
+		 arch->file_name, (long) arch->index_num, sizeof_ar_index, size);
+	  return FALSE;
+	}
+
+      /* Read in the archive index.  */
+      index_buffer = (unsigned char *)
+	malloc (arch->index_num * sizeof_ar_index);
+      if (index_buffer == NULL)
+	{
+	  error (_("Out of memory whilst trying to read archive symbol index\n"));
+	  return FALSE;
+	}
+
+      got = fread (index_buffer, sizeof_ar_index, arch->index_num, arch->file);
+      if (got != arch->index_num)
+	{
+	  free (index_buffer);
+	  error (_("%s: failed to read archive index\n"), arch->file_name);
+	  return FALSE;
+	}
+
+      size -= arch->index_num * sizeof_ar_index;
+
+      /* Convert the index numbers into the host's numeric format.  */
+      arch->index_array = (elf_vma *)
+	malloc (arch->index_num * sizeof (* arch->index_array));
+      if (arch->index_array == NULL)
+	{
+	  free (index_buffer);
+	  error (_("Out of memory whilst trying to convert the archive symbol index\n"));
+	  return FALSE;
+	}
+
+      for (i = 0; i < arch->index_num; i++)
+	arch->index_array[i] =
+	  byte_get_big_endian ((unsigned char *) (index_buffer + (i * sizeof_ar_index)),
+			       sizeof_ar_index);
+      free (index_buffer);
+
+      /* The remaining space in the header is taken up by the symbol table.  */
+      if (size < 1)
+	{
+	  error (_("%s: the archive has an index but no symbols\n"),
+		 arch->file_name);
+	  return FALSE;
+	}
+
+      arch->sym_table = (char *) malloc (size);
+      if (arch->sym_table == NULL)
+	{
+	  error (_("Out of memory whilst trying to read archive index symbol table\n"));
+	  return FALSE;
+	}
+
+      arch->sym_size = size;
+      got = fread (arch->sym_table, 1, size, arch->file);
+      if (got != size)
+	{
+	  error (_("%s: failed to read archive index symbol table\n"),
+		 arch->file_name);
+	  return FALSE;
+	}
+    }
+
+  /* Read the next archive header.  */
+  got = fread (&arch->arhdr, 1, sizeof arch->arhdr, arch->file);
+  if (got != sizeof arch->arhdr && got != 0)
+    {
+      error (_("%s: failed to read archive header following archive index\n"),
+	     arch->file_name);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* Read the symbol table and long-name table from an archive.  */
 
 int
@@ -311,7 +452,6 @@ setup_archive (struct archive_info *arch
 	       bfd_boolean read_symbols)
 {
   size_t got;
-  unsigned long size;
 
   arch->file_name = strdup (file_name);
   arch->file = file;
@@ -323,6 +463,7 @@ setup_archive (struct archive_info *arch
   arch->longnames_size = 0;
   arch->nested_member_origin = 0;
   arch->is_thin_archive = is_thin_archive;
+  arch->uses_64bit_indicies = FALSE;
   arch->next_arhdr_offset = SARMAG;
 
   /* Read the first archive member header.  */
@@ -342,124 +483,16 @@ setup_archive (struct archive_info *arch
     }
 
   /* See if this is the archive symbol table.  */
-  if (const_strneq (arch->arhdr.ar_name, "/               ")
-      || const_strneq (arch->arhdr.ar_name, "/SYM64/         "))
+  if (const_strneq (arch->arhdr.ar_name, "/               "))
     {
-      size = strtoul (arch->arhdr.ar_size, NULL, 10);
-      size = size + (size & 1);
-
-      arch->next_arhdr_offset += sizeof arch->arhdr + size;
-
-      if (read_symbols)
-	{
-	  unsigned long i;
-	  /* A buffer used to hold numbers read in from an archive index.
-	     These are always 4 bytes long and stored in big-endian
-	     format.  */
-#define SIZEOF_AR_INDEX_NUMBERS 4
-	  unsigned char integer_buffer[SIZEOF_AR_INDEX_NUMBERS];
-	  unsigned char * index_buffer;
-
-	  /* Check the size of the archive index.  */
-	  if (size < SIZEOF_AR_INDEX_NUMBERS)
-	    {
-	      error (_("%s: the archive index is empty\n"), file_name);
-	      return 1;
-	    }
-
-	  /* Read the numer of entries in the archive index.  */
-	  got = fread (integer_buffer, 1, sizeof integer_buffer, file);
-	  if (got != sizeof (integer_buffer))
-	    {
-	      error (_("%s: failed to read archive index\n"), file_name);
-	      return 1;
-	    }
-	  arch->index_num = byte_get_big_endian (integer_buffer,
-						 sizeof integer_buffer);
-	  size -= SIZEOF_AR_INDEX_NUMBERS;
-
-	  /* Read in the archive index.  */
-	  if (size < arch->index_num * SIZEOF_AR_INDEX_NUMBERS)
-	    {
-	      error (_("%s: the archive index is supposed to have %ld entries, but the size in the header is too small\n"),
-		     file_name, arch->index_num);
-	      return 1;
-	    }
-	  index_buffer = (unsigned char *)
-              malloc (arch->index_num * SIZEOF_AR_INDEX_NUMBERS);
-	  if (index_buffer == NULL)
-	    {
-	      error (_("Out of memory whilst trying to read archive symbol index\n"));
-	      return 1;
-	    }
-	  got = fread (index_buffer, SIZEOF_AR_INDEX_NUMBERS,
-		       arch->index_num, file);
-	  if (got != arch->index_num)
-	    {
-	      free (index_buffer);
-	      error (_("%s: failed to read archive index\n"), file_name);
-	      return 1;
-	    }
-	  size -= arch->index_num * SIZEOF_AR_INDEX_NUMBERS;
-
-	  /* Convert the index numbers into the host's numeric format.  */
-	  arch->index_array = (long unsigned int *)
-              malloc (arch->index_num * sizeof (* arch->index_array));
-	  if (arch->index_array == NULL)
-	    {
-	      free (index_buffer);
-	      error (_("Out of memory whilst trying to convert the archive symbol index\n"));
-	      return 1;
-	    }
-
-	  for (i = 0; i < arch->index_num; i++)
-	    arch->index_array[i] = byte_get_big_endian ((unsigned char *) (index_buffer + (i * SIZEOF_AR_INDEX_NUMBERS)),
-						        SIZEOF_AR_INDEX_NUMBERS);
-	  free (index_buffer);
-
-	  /* The remaining space in the header is taken up by the symbol
-	     table.  */
-	  if (size < 1)
-	    {
-	      error (_("%s: the archive has an index but no symbols\n"),
-		     file_name);
-	      return 1;
-	    }
-	  arch->sym_table = (char *) malloc (size);
-	  arch->sym_size = size;
-	  if (arch->sym_table == NULL)
-	    {
-	      error (_("Out of memory whilst trying to read archive index symbol table\n"));
-	      return 1;
-	    }
-	  got = fread (arch->sym_table, 1, size, file);
-	  if (got != size)
-	    {
-	      error (_("%s: failed to read archive index symbol table\n"),
-		     file_name);
-	      return 1;
-	    }
-  	}
-      else
-	{
-	  if (fseek (file, size, SEEK_CUR) != 0)
-	    {
-	      error (_("%s: failed to skip archive symbol table\n"),
-		     file_name);
-	      return 1;
-	    }
-	}
-
-      /* Read the next archive header.  */
-      got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
-      if (got != sizeof arch->arhdr)
-	{
-	  if (got == 0)
-            return 0;
-	  error (_("%s: failed to read archive header following archive index\n"),
-		 file_name);
-	  return 1;
-	}
+      if (! process_archive_index_and_symbols (arch, 4, read_symbols))
+	return 1;
+    }
+  else if (const_strneq (arch->arhdr.ar_name, "/SYM64/         "))
+    {
+      arch->uses_64bit_indicies = TRUE;
+      if (! process_archive_index_and_symbols (arch, 8, read_symbols))
+	return 1;
     }
   else if (read_symbols)
     printf (_("%s has no archive index\n"), file_name);
Index: binutils/elfcomm.h
===================================================================
RCS file: /cvs/src/src/binutils/elfcomm.h,v
retrieving revision 1.2
diff -u -3 -p -r1.2 elfcomm.h
--- binutils/elfcomm.h	15 Feb 2012 18:32:30 -0000	1.2
+++ binutils/elfcomm.h	17 Jul 2012 15:50:10 -0000
@@ -64,8 +64,8 @@ struct archive_info
 {
   char * file_name;                     /* Archive file name.  */
   FILE * file;                          /* Open file descriptor.  */
-  unsigned long index_num;              /* Number of symbols in table.  */
-  unsigned long * index_array;          /* The array of member offsets.  */
+  elf_vma index_num;                    /* Number of symbols in table.  */
+  elf_vma * index_array;                /* The array of member offsets.  */
   char * sym_table;                     /* The symbol table.  */
   unsigned long sym_size;               /* Size of the symbol table.  */
   char * longnames;                     /* The long file names table.  */
@@ -73,6 +73,7 @@ struct archive_info
   unsigned long nested_member_origin;   /* Origin in the nested archive of the current member.  */
   unsigned long next_arhdr_offset;      /* Offset of the next archive header.  */
   bfd_boolean is_thin_archive;          /* TRUE if this is a thin archive.  */
+  bfd_boolean uses_64bit_indicies;      /* TRUE if the index table uses 64bit entries.  */
   struct ar_hdr arhdr;                  /* Current archive header.  */
 };
 
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.577
diff -u -3 -p -r1.577 readelf.c
--- binutils/readelf.c	3 Jul 2012 16:25:17 -0000	1.577
+++ binutils/readelf.c	17 Jul 2012 15:50:11 -0000
@@ -13442,7 +13442,7 @@ process_archive (char * file_name, FILE 
 	  unsigned long current_pos;
 
 	  printf (_("Index of archive %s: (%ld entries, 0x%lx bytes in the symbol table)\n"),
-		  file_name, arch.index_num, arch.sym_size);
+		  file_name, (long) arch.index_num, arch.sym_size);
 	  current_pos = ftell (file);
 
 	  for (i = l = 0; i < arch.index_num; i++)
@@ -13459,8 +13459,9 @@ process_archive (char * file_name, FILE 
 
                       if (qualified_name != NULL)
                         {
-		          printf (_("Binary %s at offset 0x%lx contains:\n"),
-				  qualified_name, arch.index_array[i]);
+		          printf (_("Contents of binary %s at offset "), qualified_name);
+			  (void) print_vma (arch.index_array[i], PREFIX_HEX);
+			  putchar ('\n');
 		          free (qualified_name);
 		        }
 		    }
@@ -13476,11 +13477,14 @@ process_archive (char * file_name, FILE 
 	      l += strlen (arch.sym_table + l) + 1;
 	    }
 
-          if (l & 01)
-            ++l;
+	  if (arch.uses_64bit_indicies)
+	    l = (l + 7) & ~ 7;
+	  else
+	    l += l & 1;
+
 	  if (l < arch.sym_size)
-	    error (_("%s: symbols remain in the index symbol table, but without corresponding entries in the index table\n"),
-		   file_name);
+	    error (_("%s: %ld bytes remain in the symbol table, but without corresponding entries in the index table\n"),
+		   file_name, arch.sym_size - l);
 
 	  if (fseek (file, current_pos, SEEK_SET) != 0)
 	    {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]