* 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.
This commit is contained in:
Nick Clifton 2012-07-17 16:29:36 +00:00
parent 2e84b6bfc2
commit c2a7d3f57d
4 changed files with 176 additions and 127 deletions

View file

@ -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_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);