From c2a7d3f57d9b69909262d5c36fd500b94c84542f Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 17 Jul 2012 16:29:36 +0000 Subject: [PATCH] * 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. --- binutils/ChangeLog | 11 ++ binutils/elfcomm.c | 269 +++++++++++++++++++++++++-------------------- binutils/elfcomm.h | 5 +- binutils/readelf.c | 18 +-- 4 files changed, 176 insertions(+), 127 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 7c3018f432..3068937616 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,14 @@ +2012-07-17 Nick Clifton + + * 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. + 2012-07-03 Nick Clifton * readelf.c (process_archive): Display member indicies when diff --git a/binutils/elfcomm.c b/binutils/elfcomm.c index 4224f8235e..a50b1ece38 100644 --- a/binutils/elfcomm.c +++ b/binutils/elfcomm.c @@ -29,6 +29,7 @@ #include "aout/ar.h" #include "bucomm.h" #include "elfcomm.h" +#include void error (const char *message, ...) @@ -303,6 +304,146 @@ adjust_relative_path (const char *file_name, const char *name, 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, const char *file_name, 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, const char *file_name, 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, const char *file_name, } /* 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); diff --git a/binutils/elfcomm.h b/binutils/elfcomm.h index 2a3c9133bd..a8c3aa309d 100644 --- a/binutils/elfcomm.h +++ b/binutils/elfcomm.h @@ -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. */ }; diff --git a/binutils/readelf.c b/binutils/readelf.c index 2fcd5827d6..e6f2be6b0d 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -13442,7 +13442,7 @@ process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive) 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 * file, bfd_boolean is_thin_archive) 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 * file, bfd_boolean is_thin_archive) 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) { -- 2.34.1