* readelf.c (do_archive_index): New.
authorNick Clifton <nickc@redhat.com>
Mon, 17 Sep 2007 16:09:24 +0000 (16:09 +0000)
committerNick Clifton <nickc@redhat.com>
Mon, 17 Sep 2007 16:09:24 +0000 (16:09 +0000)
  (options): Add -c and --archive-index option.
  (usage): Add -c option.
  (parse_args): Add c option parsing.
  (process_archive): Dump archive index.
* NEWS: Mention the new feature.
* doc/binutils.texi: Document the new feature.

binutils/ChangeLog
binutils/NEWS
binutils/doc/binutils.texi
binutils/readelf.c

index 368aeaa..de6b750 100644 (file)
@@ -1,3 +1,13 @@
+2007-09-17  Shen Feng  <shen@cn.fujitsu.com>
+
+       * readelf.c (do_archive_index): New.
+       (options): Add -c and --archive-index option.
+       (usage): Add -c option.
+       (parse_args): Add c option parsing.
+       (process_archive): Dump archive index.
+       * NEWS: Mention the new feature.
+       * doc/binutils.texi: Document the new feature.
+
 2007-09-17  Nick Clifton  <nickc@redhat.com>
 
        * po/es.po: Updated Spanish translation.
index 00148db..5171e55 100644 (file)
@@ -1,4 +1,6 @@
 -*- text -*-
+* Added -c switch to readelf to allow string dumps of archive symbol index.
+
 * Support for SSE5 has been added to the i386 port.
 
 * Added -p switch to readelf to allow string dumps of sections.
index aec1c6d..6e3c1dd 100644 (file)
@@ -3688,6 +3688,7 @@ readelf [@option{-a}|@option{--all}]
         [@option{-D}|@option{--use-dynamic}]
         [@option{-x} <number or name>|@option{--hex-dump=}<number or name>]
         [@option{-p} <number or name>|@option{--string-dump=}<number or name>]
+        [@option{-c}|@option{--archive-index}]
         [@option{-w[liaprmfFsoR]}|
          @option{--debug-dump}[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]]
         [@option{-I}|@option{-histogram}]
@@ -3819,6 +3820,13 @@ Displays the contents of the indicated section as printable strings.
 A number identifies a particular section by index in the section table;
 any other string identifies all sections with that name in the object file.
 
+@item -c
+@itemx --archive-index
+@cindex Archive file symbol index information
+Displays the file symbol index infomation contained in the header part
+of binary archives.  Performs the same function as the @option{t}
+command to @command{ar}, but without using the BFD library.  @xref{ar}.
+
 @item -w[liaprmfFsoR]
 @itemx --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]
 Displays the contents of the debug sections in the file, if any are
index 8bf65c7..e51e8b0 100644 (file)
@@ -202,6 +202,7 @@ static int do_histogram;
 static int do_debugging;
 static int do_arch;
 static int do_notes;
+static int do_archive_index;
 static int is_32bit_elf;
 
 struct group_list
@@ -2755,6 +2756,7 @@ static struct option options[] =
   {"version-info",     no_argument, 0, 'V'},
   {"use-dynamic",      no_argument, 0, 'D'},
   {"unwind",          no_argument, 0, 'u'},
+  {"archive-index",    no_argument, 0, 'c'},
   {"hex-dump",        required_argument, 0, 'x'},
   {"debug-dump",       optional_argument, 0, OPTION_DEBUG_DUMP},
   {"string-dump",      required_argument, 0, 'p'},
@@ -2791,6 +2793,7 @@ usage (FILE *stream)
   -d --dynamic           Display the dynamic section (if present)\n\
   -V --version-info      Display the version sections (if present)\n\
   -A --arch-specific     Display architecture specific information (if any).\n\
+  -c --archive-index     Display the symbol/file index in an archive\n\
   -D --use-dynamic       Use the dynamic section info when displaying symbols\n\
   -x --hex-dump=<number|name>\n\
                          Dump the contents of section <number|name> as bytes\n\
@@ -2881,7 +2884,7 @@ parse_args (int argc, char **argv)
     usage (stderr);
 
   while ((c = getopt_long
-         (argc, argv, "ersuahnldSDAINtgw::x:i:vVWHp:", options, NULL)) != EOF)
+         (argc, argv, "ADHINSVWacdeghi:lnp:rstuvw::x:", options, NULL)) != EOF)
     {
       char *cp;
       int section;
@@ -2955,6 +2958,9 @@ parse_args (int argc, char **argv)
        case 'n':
          do_notes++;
          break;
+       case 'c':
+         do_archive_index++;
+         break;
        case 'x':
          do_dump++;
          section = strtoul (optarg, & cp, 0);
@@ -3143,7 +3149,7 @@ parse_args (int argc, char **argv)
   if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections
       && !do_segments && !do_header && !do_dump && !do_version
       && !do_histogram && !do_debugging && !do_arch && !do_notes
-      && !do_section_groups)
+      && !do_section_groups && !do_archive_index)
     usage (stderr);
   else if (argc < 3)
     {
@@ -9796,8 +9802,8 @@ process_object (char *file_name, FILE *file)
   return 0;
 }
 
-/* Process an ELF archive.  The file is positioned just after the
-   ARMAG string.  */
+/* Process an ELF archive.
+   On entry the file is positioned just after the ARMAG string.  */
 
 static int
 process_archive (char *file_name, FILE *file)
@@ -9805,6 +9811,10 @@ process_archive (char *file_name, FILE *file)
   struct ar_hdr arhdr;
   size_t got;
   unsigned long size;
+  unsigned long index_num = 0;
+  unsigned long *index_array = NULL;
+  char *sym_table = NULL;
+  unsigned long sym_size = 0;
   char *longnames = NULL;
   unsigned long longnames_size = 0;
   size_t file_name_size;
@@ -9822,28 +9832,124 @@ process_archive (char *file_name, FILE *file)
       return 1;
     }
 
+  /* See if this is the archive symbol table.  */
   if (const_strneq (arhdr.ar_name, "/               ")
       || const_strneq (arhdr.ar_name, "/SYM64/         "))
     {
-      /* This is the archive symbol table.  Skip it.
-        FIXME: We should have an option to dump it.  */
       size = strtoul (arhdr.ar_size, NULL, 10);
-      if (fseek (file, size + (size & 1), SEEK_CUR) != 0)
+      size = size + (size & 1);
+
+      if (do_archive_index)
        {
-         error (_("%s: failed to skip archive symbol table\n"), file_name);
-         return 1;
+         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;
+           }
+         index_num = byte_get_big_endian (integer_buffer, sizeof integer_buffer);
+         size -= SIZEOF_AR_INDEX_NUMBERS;
+
+         /* Read in the archive index.  */
+         if (size < 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, index_num);
+             return 1;
+           }
+         index_buffer = malloc (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, index_num, file);
+         if (got != index_num)
+           {
+             free (index_buffer);
+             error (_("%s: failed to read archive index\n"), file_name);
+             ret = 1;
+             goto out;
+           }
+         size -= index_num * SIZEOF_AR_INDEX_NUMBERS;
+
+         /* Convert the index numbers into the host's numeric format.  */
+         index_array = malloc (index_num * sizeof (* index_array));      
+         if (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 < index_num; i++)
+           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);
+             ret = 1;
+             goto out;
+           }
+         sym_table = malloc (size);
+         sym_size = size;
+         if (sym_table == NULL)
+           {
+             error (_("Out of memory whilst trying to read archive index symbol table\n"));
+             ret = 1;
+             goto out;
+           }
+         got = fread (sym_table, 1, size, file);
+         if (got != size)
+           {
+             error (_("%s: failed to read archive index symbol table\n"), file_name);
+             ret = 1;
+             goto out;
+           }     
+       }
+      else
+       {
+         if (fseek (file, size, SEEK_CUR) != 0)
+           {
+             error (_("%s: failed to skip archive symbol table\n"), file_name);
+             return 1;
+           }
        }
 
-      got = fread (&arhdr, 1, sizeof arhdr, file);
+      got = fread (& arhdr, 1, sizeof arhdr, file);
       if (got != sizeof arhdr)
        {
          if (got == 0)
-           return 0;
+           {
+             ret = 0;
+             goto out;
+           }
 
-         error (_("%s: failed to read archive header\n"), file_name);
-         return 1;
+         error (_("%s: failed to read archive header following archive index\n"), file_name);
+         ret = 1;
+         goto out;
        }
     }
+  else if (do_archive_index)
+    printf (_("%s has no archive index\n"), file_name);
 
   if (const_strneq (arhdr.ar_name, "//              "))
     {
@@ -9851,35 +9957,120 @@ process_archive (char *file_name, FILE *file)
         names.  */
 
       longnames_size = strtoul (arhdr.ar_size, NULL, 10);
-
       longnames = malloc (longnames_size);
       if (longnames == NULL)
        {
-         error (_("Out of memory\n"));
-         return 1;
+         error (_("Out of memory reading long symbol names in archive\n"));
+         ret = 1;
+         goto out;
        }
 
       if (fread (longnames, longnames_size, 1, file) != 1)
        {
          free (longnames);
-         error (_("%s: failed to read string table\n"), file_name);
-         return 1;
+         error (_("%s: failed to read long symbol name string table\n"), file_name);
+         ret = 1;
+         goto out;
        }
 
       if ((longnames_size & 1) != 0)
        getc (file);
 
-      got = fread (&arhdr, 1, sizeof arhdr, file);
+      got = fread (& arhdr, 1, sizeof arhdr, file);
       if (got != sizeof arhdr)
        {
-         free (longnames);
-
          if (got == 0)
-           return 0;
+           ret = 0;
+         else
+           {
+             error (_("%s: failed to read archive header following long symbol names\n"), file_name);
+             ret = 1;
+           }
+         goto out;
+       }
+    }
 
-         error (_("%s: failed to read archive header\n"), file_name);
-         return 1;
+  if (do_archive_index)
+    {
+      if (sym_table == NULL)
+       error (_("%s: unable to dump the index as none was found\n"), file_name);
+      else
+       {
+         unsigned int i, j, k, l;
+         char elf_name[16];
+         unsigned long current_pos;
+
+         printf (_("Index of archive %s: (%ld entries, 0x%lx bytes in the symbol table)\n"),
+                 file_name, index_num, sym_size);
+         current_pos = ftell (file);
+
+         for (i = l = 0; i < index_num; i++)
+           {
+             if ((i == 0) || ((i > 0) && (index_array[i] != index_array[i - 1])))
+               {
+                 if (fseek (file, index_array[i], SEEK_SET) != 0)
+                   {
+                     error (_("%s: failed to seek to next file name\n"), file_name);
+                     ret = 1;
+                     goto out;
+                   }
+                 got = fread (elf_name, 1, 16, file);
+                 if (got != 16)
+                   {
+                     error (_("%s: failed to read file name\n"), file_name);
+                     ret = 1;
+                     goto out;
+                   }
+
+                 if (elf_name[0] == '/')
+                   {
+                     /* We have a long name.  */
+                     k = j = strtoul (elf_name + 1, NULL, 10);
+                     while ((j < longnames_size) && (longnames[j] != '/'))
+                       j++;
+                     longnames[j] = '\0';
+                     printf (_("Binary %s contains:\n"), longnames + k);
+                     longnames[j] = '/';
+                   }
+                 else
+                   {
+                     j = 0;
+                     while ((elf_name[j] != '/') && (j < 16))
+                       j++;
+                     elf_name[j] = '\0';
+                     printf(_("Binary %s contains:\n"), elf_name);
+                   }
+               }
+             if (l >= sym_size)
+               {
+                 error (_("%s: end of the symbol table reached before the end of the index\n"),
+                        file_name);
+                 break;                         
+               }
+             printf ("\t%s\n", sym_table + l);
+             l += strlen (sym_table + l) + 1;
+           }
+
+         if (l < sym_size)
+           error (_("%s: symbols remain in the index symbol table, but without corresponding entries in the index table\n"),
+                  file_name);
+
+         free (index_array);
+         index_array = NULL;
+         free (sym_table);
+         sym_table = NULL;
+         if (fseek (file, current_pos, SEEK_SET) != 0)
+           {
+             error (_("%s: failed to seek back to start of object files in the archive\n"), file_name);
+             return 1;
+           }
        }
+
+      if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections
+         && !do_segments && !do_header && !do_dump && !do_version
+         && !do_histogram && !do_debugging && !do_arch && !do_notes
+         && !do_section_groups)
+       return 0; /* Archive index only.  */
     }
 
   file_name_size = strlen (file_name);
@@ -9963,7 +10154,12 @@ process_archive (char *file_name, FILE *file)
        }
     }
 
-  if (longnames != 0)
+ out:
+  if (index_array != NULL)
+    free (index_array);
+  if (sym_table != NULL)
+    free (sym_table);
+  if (longnames != NULL)
     free (longnames);
 
   return ret;
@@ -10002,7 +10198,7 @@ process_file (char *file_name)
 
   if (fread (armag, SARMAG, 1, file) != 1)
     {
-      error (_("%s: Failed to read file header\n"), file_name);
+      error (_("%s: Failed to read file's magic number\n"), file_name);
       fclose (file);
       return 1;
     }
@@ -10011,6 +10207,10 @@ process_file (char *file_name)
     ret = process_archive (file_name, file);
   else
     {
+      if (do_archive_index)
+       error (_("File %s is not an archive so its index cannot be displayed.\n"),
+              file_name);
+
       rewind (file);
       archive_file_size = archive_file_offset = 0;
       ret = process_object (file_name, file);