* readelf.c (adjust_relative_path): New function.

(struct archive_info): New type.
        (setup_archive): New function.
        (release_archive): New function.
        (setup_nested_archive): New function.
        (get_archive_member_name): New function.
        (get_archive_member_name_at): New function.
        (make_qualified_name): New function.
        (process_archive): Factor out code for reading archive index and
        long filename table to setup_archive.  Add support for thin archives.
This commit is contained in:
Nick Clifton 2009-03-02 16:06:50 +00:00
parent 83cf10fd4a
commit 2cf0635d9d
2 changed files with 854 additions and 557 deletions

View file

@ -1,3 +1,16 @@
2009-03-02 Cary Coutant <ccoutant@google.com>
* readelf.c (adjust_relative_path): New function.
(struct archive_info): New type.
(setup_archive): New function.
(release_archive): New function.
(setup_nested_archive): New function.
(get_archive_member_name): New function.
(get_archive_member_name_at): New function.
(make_qualified_name): New function.
(process_archive): Factor out code for reading archive index and
long filename table to setup_archive. Add support for thin archives.
2009-03-02 Nick Clifton <nickc@redhat.com>
* po/sk.po: Updated Slovak translation.

View file

@ -1,6 +1,6 @@
/* readelf.c -- display contents of an ELF format file
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
2008 Free Software Foundation, Inc.
2008, 2009 Free Software Foundation, Inc.
Originally developed by Eric Youngdale <eric@andante.jic.com>
Modifications by Nick Clifton <nickc@redhat.com>
@ -145,6 +145,7 @@
#include "getopt.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "filenames.h"
char * program_name = "readelf";
int do_wide;
@ -870,7 +871,6 @@ dump_relocations (FILE *file,
unsigned int i;
Elf_Internal_Rela * rels;
if (is_rela == UNKNOWN)
is_rela = guess_is_rela (elf_header.e_machine);
@ -4411,7 +4411,8 @@ process_section_groups (FILE *file)
Elf_Internal_Shdr * section;
unsigned int i;
struct group * group;
Elf_Internal_Shdr *symtab_sec, *strtab_sec;
Elf_Internal_Shdr * symtab_sec;
Elf_Internal_Shdr * strtab_sec;
Elf_Internal_Sym * symtab;
char * strtab;
size_t strtab_size;
@ -4480,7 +4481,8 @@ process_section_groups (FILE *file)
{
char * name = SECTION_NAME (section);
char * group_name;
unsigned char *start, *indices;
unsigned char * start;
unsigned char * indices;
unsigned int entry, j, size;
Elf_Internal_Shdr * sec;
Elf_Internal_Sym * sym;
@ -4839,7 +4841,8 @@ find_symbol_for_address (Elf_Internal_Sym *symtab,
bfd_vma * offset)
{
bfd_vma dist = 0x100000;
Elf_Internal_Sym *sym, *best = NULL;
Elf_Internal_Sym * sym;
Elf_Internal_Sym * best = NULL;
unsigned long i;
for (i = 0, sym = symtab; i < nsyms; ++i, ++sym)
@ -4932,8 +4935,10 @@ slurp_ia64_unwind_table (FILE *file,
Elf_Internal_Phdr * seg;
struct ia64_unw_table_entry * tep;
Elf_Internal_Shdr * relsec;
Elf_Internal_Rela *rela, *rp;
unsigned char *table, *tp;
Elf_Internal_Rela * rela;
Elf_Internal_Rela * rp;
unsigned char * table;
unsigned char * tp;
Elf_Internal_Sym * sym;
const char * relname;
@ -5048,7 +5053,9 @@ slurp_ia64_unwind_table (FILE *file,
static int
ia64_process_unwind (FILE * file)
{
Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec;
Elf_Internal_Shdr * sec;
Elf_Internal_Shdr * unwsec = NULL;
Elf_Internal_Shdr * strsec;
unsigned long i, unwcount = 0, unwstart = 0;
struct ia64_unw_aux_info aux;
@ -5304,8 +5311,10 @@ slurp_hppa_unwind_table (FILE *file,
Elf_Internal_Phdr * seg;
struct hppa_unw_table_entry * tep;
Elf_Internal_Shdr * relsec;
Elf_Internal_Rela *rela, *rp;
unsigned char *table, *tp;
Elf_Internal_Rela * rela;
Elf_Internal_Rela * rp;
unsigned char * table;
unsigned char * tp;
Elf_Internal_Sym * sym;
const char * relname;
@ -5512,10 +5521,12 @@ hppa_process_unwind (FILE *file)
static int
process_unwind (FILE * file)
{
struct unwind_handler {
struct unwind_handler
{
int machtype;
int (*handler)(FILE *file);
} handlers[] = {
int (* handler)(FILE *);
} handlers[] =
{
{ EM_IA_64, ia64_process_unwind },
{ EM_PARISC, hppa_process_unwind },
{ 0, 0 }
@ -5690,7 +5701,8 @@ dynamic_section_ia64_val (Elf_Internal_Dyn *entry)
static int
get_32bit_dynamic_section (FILE * file)
{
Elf32_External_Dyn *edyn, *ext;
Elf32_External_Dyn * edyn;
Elf32_External_Dyn * ext;
Elf_Internal_Dyn * entry;
edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
@ -5734,7 +5746,8 @@ get_32bit_dynamic_section (FILE *file)
static int
get_64bit_dynamic_section (FILE * file)
{
Elf64_External_Dyn *edyn, *ext;
Elf64_External_Dyn * edyn;
Elf64_External_Dyn * ext;
Elf_Internal_Dyn * entry;
edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
@ -5943,7 +5956,8 @@ process_dynamic_section (FILE *file)
if (dynamic_syminfo_offset != 0 && syminsz != 0)
{
Elf_External_Syminfo *extsyminfo, *extsym;
Elf_External_Syminfo * extsyminfo;
Elf_External_Syminfo * extsym;
Elf_Internal_Syminfo * syminfo;
/* There is a syminfo section. Read the data. */
@ -7302,7 +7316,6 @@ process_symbol_table (FILE *file)
Elf_Internal_Sym * symtab;
Elf_Internal_Sym * psym;
if ( section->sh_type != SHT_SYMTAB
&& section->sh_type != SHT_DYNSYM)
continue;
@ -8300,7 +8313,8 @@ debug_apply_relocations (void *file,
{
bfd_boolean is_rela;
unsigned long num_relocs;
Elf_Internal_Rela *relocs, *rp;
Elf_Internal_Rela * relocs;
Elf_Internal_Rela * rp;
Elf_Internal_Shdr * symsec;
Elf_Internal_Sym * symtab;
Elf_Internal_Sym * sym;
@ -8731,6 +8745,7 @@ static arm_attr_public_tag arm_attr_public_tags[] =
/* Read an unsigned LEB128 encoded value from p. Set *PLEN to the number of
bytes read. */
static unsigned int
read_uleb128 (unsigned char * p, unsigned int * plen)
{
@ -9864,7 +9879,8 @@ process_mips_specific (FILE *file)
static int
process_gnu_liblist (FILE * file)
{
Elf_Internal_Shdr *section, *string_sec;
Elf_Internal_Shdr * section;
Elf_Internal_Shdr * string_sec;
Elf32_External_Lib * elib;
char * strtab;
size_t strtab_size;
@ -10514,7 +10530,8 @@ process_object (char *file_name, FILE *file)
if (section_groups)
{
struct group_list *g, *next;
struct group_list * g;
struct group_list * next;
for (i = 0; i < group_count; i++)
{
@ -10534,28 +10551,98 @@ process_object (char *file_name, FILE *file)
return 0;
}
/* Process an ELF archive.
On entry the file is positioned just after the ARMAG string. */
/* Return the path name for a proxy entry in a thin archive, adjusted relative
to the path name of the thin archive itself if necessary. Always returns
a pointer to malloc'ed memory. */
static char *
adjust_relative_path (char * file_name, char * name, int name_len)
{
char * member_file_name;
const char * base_name = lbasename (file_name);
/* This is a proxy entry for a thin archive member.
If the extended name table contains an absolute path
name, or if the archive is in the current directory,
use the path name as given. Otherwise, we need to
find the member relative to the directory where the
archive is located. */
if (IS_ABSOLUTE_PATH (name) || base_name == file_name)
{
member_file_name = malloc (name_len + 1);
if (member_file_name == NULL)
{
error (_("Out of memory\n"));
return NULL;
}
memcpy (member_file_name, name, name_len);
member_file_name[name_len] = '\0';
}
else
{
/* Concatenate the path components of the archive file name
to the relative path name from the extended name table. */
size_t prefix_len = base_name - file_name;
member_file_name = malloc (prefix_len + name_len + 1);
if (member_file_name == NULL)
{
error (_("Out of memory\n"));
return NULL;
}
memcpy (member_file_name, file_name, prefix_len);
memcpy (member_file_name + prefix_len, name, name_len);
member_file_name[prefix_len + name_len] = '\0';
}
return member_file_name;
}
/* Structure to hold information about an archive file. */
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. */
char * sym_table; /* The symbol table. */
unsigned long sym_size; /* Size of the symbol table. */
char * longnames; /* The long file names table. */
unsigned long longnames_size; /* Size of the long file names table. */
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. */
struct ar_hdr arhdr; /* Current archive header. */
};
/* Read the symbol table and long-name table from an archive. */
static int
process_archive (char *file_name, FILE *file)
setup_archive (struct archive_info * arch, char * file_name, FILE * file,
bfd_boolean is_thin_archive, bfd_boolean read_symbols)
{
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;
int ret;
show_name = 1;
arch->file_name = strdup (file_name);
arch->file = file;
arch->index_num = 0;
arch->index_array = NULL;
arch->sym_table = NULL;
arch->sym_size = 0;
arch->longnames = NULL;
arch->longnames_size = 0;
arch->nested_member_origin = 0;
arch->is_thin_archive = is_thin_archive;
arch->next_arhdr_offset = SARMAG;
got = fread (&arhdr, 1, sizeof arhdr, file);
if (got != sizeof arhdr)
/* Read the first archive member header. */
if (fseek (file, SARMAG, SEEK_SET) != 0)
{
error (_("%s: failed to seek to first archive header\n"), file_name);
return 1;
}
got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
if (got != sizeof arch->arhdr)
{
if (got == 0)
return 0;
@ -10565,13 +10652,15 @@ process_archive (char *file_name, FILE *file)
}
/* See if this is the archive symbol table. */
if (const_strneq (arhdr.ar_name, "/ ")
|| const_strneq (arhdr.ar_name, "/SYM64/ "))
if (const_strneq (arch->arhdr.ar_name, "/ ")
|| const_strneq (arch->arhdr.ar_name, "/SYM64/ "))
{
size = strtoul (arhdr.ar_size, NULL, 10);
size = strtoul (arch->arhdr.ar_size, NULL, 10);
size = size + (size & 1);
if (do_archive_index)
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.
@ -10594,43 +10683,42 @@ process_archive (char *file_name, FILE *file)
error (_("%s: failed to read archive index\n"), file_name);
return 1;
}
index_num = byte_get_big_endian (integer_buffer, sizeof integer_buffer);
arch->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)
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, index_num);
file_name, arch->index_num);
return 1;
}
index_buffer = malloc (index_num * SIZEOF_AR_INDEX_NUMBERS);
index_buffer = 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, index_num, file);
if (got != index_num)
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);
ret = 1;
goto out;
return 1;
}
size -= index_num * SIZEOF_AR_INDEX_NUMBERS;
size -= arch->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)
arch->index_array = 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 < index_num; i++)
index_array[i] = byte_get_big_endian ((unsigned char *)(index_buffer + (i * SIZEOF_AR_INDEX_NUMBERS)),
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);
@ -10638,23 +10726,20 @@ process_archive (char *file_name, FILE *file)
if (size < 1)
{
error (_("%s: the archive has an index but no symbols\n"), file_name);
ret = 1;
goto out;
return 1;
}
sym_table = malloc (size);
sym_size = size;
if (sym_table == NULL)
arch->sym_table = malloc (size);
arch->sym_size = size;
if (arch->sym_table == NULL)
{
error (_("Out of memory whilst trying to read archive index symbol table\n"));
ret = 1;
goto out;
return 1;
}
got = fread (sym_table, 1, size, file);
got = fread (arch->sym_table, 1, size, file);
if (got != size)
{
error (_("%s: failed to read archive index symbol table\n"), file_name);
ret = 1;
goto out;
return 1;
}
}
else
@ -10666,135 +10751,304 @@ process_archive (char *file_name, FILE *file)
}
}
got = fread (& arhdr, 1, sizeof arhdr, file);
if (got != sizeof arhdr)
/* Read the next archive header. */
got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
if (got != sizeof arch->arhdr)
{
if (got == 0)
{
ret = 0;
goto out;
}
return 0;
error (_("%s: failed to read archive header following archive index\n"), file_name);
ret = 1;
goto out;
return 1;
}
}
else if (do_archive_index)
else if (read_symbols)
printf (_("%s has no archive index\n"), file_name);
if (const_strneq (arhdr.ar_name, "// "))
if (const_strneq (arch->arhdr.ar_name, "// "))
{
/* This is the archive string table holding long member
names. */
/* This is the archive string table holding long member names. */
arch->longnames_size = strtoul (arch->arhdr.ar_size, NULL, 10);
arch->next_arhdr_offset += sizeof arch->arhdr + arch->longnames_size;
longnames_size = strtoul (arhdr.ar_size, NULL, 10);
longnames = malloc (longnames_size);
if (longnames == NULL)
arch->longnames = malloc (arch->longnames_size);
if (arch->longnames == NULL)
{
error (_("Out of memory reading long symbol names in archive\n"));
ret = 1;
goto out;
return 1;
}
if (fread (longnames, longnames_size, 1, file) != 1)
if (fread (arch->longnames, arch->longnames_size, 1, file) != 1)
{
free (longnames);
free (arch->longnames);
arch->longnames = NULL;
error (_("%s: failed to read long symbol name string table\n"), file_name);
ret = 1;
goto out;
return 1;
}
if ((longnames_size & 1) != 0)
if ((arch->longnames_size & 1) != 0)
getc (file);
}
got = fread (& arhdr, 1, sizeof arhdr, file);
if (got != sizeof arhdr)
return 0;
}
/* Release the memory used for the archive information. */
static void
release_archive (struct archive_info * arch)
{
if (got == 0)
ret = 0;
if (arch->file_name != NULL)
free (arch->file_name);
if (arch->index_array != NULL)
free (arch->index_array);
if (arch->sym_table != NULL)
free (arch->sym_table);
if (arch->longnames != NULL)
free (arch->longnames);
}
/* Open and setup a nested archive, if not already open. */
static int
setup_nested_archive (struct archive_info * nested_arch, char * member_file_name)
{
FILE * member_file;
/* Have we already setup this archive? */
if (nested_arch->file_name != NULL
&& streq (nested_arch->file_name, member_file_name))
return 0;
/* Close previous file and discard cached information. */
if (nested_arch->file != NULL)
fclose (nested_arch->file);
release_archive (nested_arch);
member_file = fopen (member_file_name, "rb");
if (member_file == NULL)
return 1;
return setup_archive (nested_arch, member_file_name, member_file, FALSE, FALSE);
}
static char *
get_archive_member_name_at (struct archive_info * arch,
unsigned long offset,
struct archive_info * nested_arch);
/* Get the name of an archive member from the current archive header.
For simple names, this will modify the ar_name field of the current
archive header. For long names, it will return a pointer to the
longnames table. For nested archives, it will open the nested archive
and get the name recursively. NESTED_ARCH is a single-entry cache so
we don't keep rereading the same information from a nested archive. */
static char *
get_archive_member_name (struct archive_info * arch,
struct archive_info * nested_arch)
{
unsigned long j, k;
if (arch->arhdr.ar_name[0] == '/')
{
/* We have a long name. */
char * endp;
char * member_file_name;
char * member_name;
arch->nested_member_origin = 0;
k = j = strtoul (arch->arhdr.ar_name + 1, &endp, 10);
if (arch->is_thin_archive && endp != NULL && * endp == ':')
arch->nested_member_origin = strtoul (endp + 1, NULL, 10);
while ((j < arch->longnames_size)
&& (arch->longnames[j] != '\n')
&& (arch->longnames[j] != '\0'))
j++;
if (arch->longnames[j-1] == '/')
j--;
arch->longnames[j] = '\0';
if (!arch->is_thin_archive || arch->nested_member_origin == 0)
return arch->longnames + k;
/* This is a proxy for a member of a nested archive.
Find the name of the member in that archive. */
member_file_name = adjust_relative_path (arch->file_name, arch->longnames + k, j - k);
if (member_file_name != NULL
&& setup_nested_archive (nested_arch, member_file_name) == 0
&& (member_name = get_archive_member_name_at (nested_arch, arch->nested_member_origin, NULL)) != NULL)
{
free (member_file_name);
return member_name;
}
free (member_file_name);
/* Last resort: just return the name of the nested archive. */
return arch->longnames + k;
}
/* We have a normal (short) name. */
j = 0;
while ((arch->arhdr.ar_name[j] != '/') && (j < 16))
j++;
arch->arhdr.ar_name[j] = '\0';
return arch->arhdr.ar_name;
}
/* Get the name of an archive member at a given OFFSET within an archive ARCH. */
static char *
get_archive_member_name_at (struct archive_info * arch,
unsigned long offset,
struct archive_info * nested_arch)
{
size_t got;
if (fseek (arch->file, offset, SEEK_SET) != 0)
{
error (_("%s: failed to seek to next file name\n"), arch->file_name);
return NULL;
}
got = fread (&arch->arhdr, 1, sizeof arch->arhdr, arch->file);
if (got != sizeof arch->arhdr)
{
error (_("%s: failed to read archive header\n"), arch->file_name);
return NULL;
}
if (memcmp (arch->arhdr.ar_fmag, ARFMAG, 2) != 0)
{
error (_("%s: did not find a valid archive header\n"), arch->file_name);
return NULL;
}
return get_archive_member_name (arch, nested_arch);
}
/* Construct a string showing the name of the archive member, qualified
with the name of the containing archive file. For thin archives, we
use square brackets to denote the indirection. For nested archives,
we show the qualified name of the external member inside the square
brackets (e.g., "thin.a[normal.a(foo.o)]"). */
static char *
make_qualified_name (struct archive_info * arch,
struct archive_info * nested_arch,
char * member_name)
{
size_t len;
char * name;
len = strlen (arch->file_name) + strlen (member_name) + 3;
if (arch->is_thin_archive && arch->nested_member_origin != 0)
len += strlen (nested_arch->file_name) + 2;
name = malloc (len);
if (name == NULL)
{
error (_("Out of memory\n"));
return NULL;
}
if (arch->is_thin_archive && arch->nested_member_origin != 0)
snprintf (name, len, "%s[%s(%s)]", arch->file_name, nested_arch->file_name, member_name);
else if (arch->is_thin_archive)
snprintf (name, len, "%s[%s]", arch->file_name, member_name);
else
snprintf (name, len, "%s(%s)", arch->file_name, member_name);
return name;
}
/* Process an ELF archive.
On entry the file is positioned just after the ARMAG string. */
static int
process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive)
{
struct archive_info arch;
struct archive_info nested_arch;
size_t got;
size_t file_name_size;
int ret;
show_name = 1;
/* The ARCH structure is used to hold information about this archive. */
arch.file_name = NULL;
arch.file = NULL;
arch.index_array = NULL;
arch.sym_table = NULL;
arch.longnames = NULL;
/* The NESTED_ARCH structure is used as a single-item cache of information
about a nested archive (when members of a thin archive reside within
another regular archive file). */
nested_arch.file_name = NULL;
nested_arch.file = NULL;
nested_arch.index_array = NULL;
nested_arch.sym_table = NULL;
nested_arch.longnames = NULL;
if (setup_archive (&arch, file_name, file, is_thin_archive, do_archive_index) != 0)
{
error (_("%s: failed to read archive header following long symbol names\n"), file_name);
ret = 1;
}
goto out;
}
}
if (do_archive_index)
{
if (sym_table == NULL)
if (arch.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 int i, l;
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);
file_name, arch.index_num, arch.sym_size);
current_pos = ftell (file);
for (i = l = 0; i < index_num; i++)
for (i = l = 0; i < arch.index_num; i++)
{
if ((i == 0) || ((i > 0) && (index_array[i] != index_array[i - 1])))
if ((i == 0) || ((i > 0) && (arch.index_array[i] != arch.index_array[i - 1])))
{
if (fseek (file, index_array[i], SEEK_SET) != 0)
char * member_name;
member_name = get_archive_member_name_at (&arch, arch.index_array[i], &nested_arch);
if (member_name != NULL)
{
error (_("%s: failed to seek to next file name\n"), file_name);
ret = 1;
goto out;
char * qualified_name = make_qualified_name (&arch, &nested_arch, member_name);
if (qualified_name != NULL)
{
printf (_("Binary %s contains:\n"), qualified_name);
free (qualified_name);
}
}
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)
if (l >= arch.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;
printf ("\t%s\n", arch.sym_table + l);
l += strlen (arch.sym_table + l) + 1;
}
if (l < sym_size)
if (l & 01)
++l;
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);
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;
ret = 1;
goto out;
}
}
@ -10802,7 +11056,10 @@ process_archive (char *file_name, FILE *file)
&& !do_segments && !do_header && !do_dump && !do_version
&& !do_histogram && !do_debugging && !do_arch && !do_notes
&& !do_section_groups)
return 0; /* Archive index only. */
{
ret = 0; /* Archive index only. */
goto out;
}
}
file_name_size = strlen (file_name);
@ -10811,88 +11068,113 @@ process_archive (char *file_name, FILE *file)
while (1)
{
char * name;
char *nameend;
char *namealc;
size_t namelen;
char * qualified_name;
if (arhdr.ar_name[0] == '/')
/* Read the next archive header. */
if (fseek (file, arch.next_arhdr_offset, SEEK_SET) != 0)
{
unsigned long off;
off = strtoul (arhdr.ar_name + 1, NULL, 10);
if (off >= longnames_size)
error (_("%s: failed to seek to next archive header\n"), file_name);
return 1;
}
got = fread (&arch.arhdr, 1, sizeof arch.arhdr, file);
if (got != sizeof arch.arhdr)
{
error (_("%s: invalid archive string table offset %lu\n"), file_name, off);
if (got == 0)
break;
error (_("%s: failed to read archive header\n"), file_name);
ret = 1;
break;
}
if (memcmp (arch.arhdr.ar_fmag, ARFMAG, 2) != 0)
{
error (_("%s: did not find a valid archive header\n"), arch.file_name);
ret = 1;
break;
}
name = longnames + off;
nameend = memchr (name, '/', longnames_size - off);
}
else
{
name = arhdr.ar_name;
nameend = memchr (name, '/', 16);
}
arch.next_arhdr_offset += sizeof arch.arhdr;
if (nameend == NULL)
archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10);
if (archive_file_size & 01)
++archive_file_size;
name = get_archive_member_name (&arch, &nested_arch);
if (name == NULL)
{
error (_("%s: bad archive file name\n"), file_name);
ret = 1;
break;
}
namelen = strlen (name);
qualified_name = make_qualified_name (&arch, &nested_arch, name);
if (qualified_name == NULL)
{
error (_("%s: bad archive file name\n"), file_name);
ret = 1;
break;
}
namealc = malloc (file_name_size + (nameend - name) + 3);
if (namealc == NULL)
if (is_thin_archive && arch.nested_member_origin == 0)
{
/* This is a proxy for an external member of a thin archive. */
FILE * member_file;
char * member_file_name = adjust_relative_path (file_name, name, namelen);
if (member_file_name == NULL)
{
error (_("Out of memory\n"));
ret = 1;
break;
}
memcpy (namealc, file_name, file_name_size);
namealc[file_name_size] = '(';
memcpy (namealc + file_name_size + 1, name, nameend - name);
namealc[file_name_size + 1 + (nameend - name)] = ')';
namealc[file_name_size + 2 + (nameend - name)] = '\0';
archive_file_offset = ftell (file);
archive_file_size = strtoul (arhdr.ar_size, NULL, 10);
ret |= process_object (namealc, file);
free (namealc);
if (fseek (file,
(archive_file_offset
+ archive_file_size
+ (archive_file_size & 1)),
SEEK_SET) != 0)
member_file = fopen (member_file_name, "rb");
if (member_file == NULL)
{
error (_("%s: failed to seek to next archive header\n"), file_name);
error (_("Input file '%s' is not readable.\n"), member_file_name);
free (member_file_name);
ret = 1;
break;
}
got = fread (&arhdr, 1, sizeof arhdr, file);
if (got != sizeof arhdr)
{
if (got == 0)
break;
archive_file_offset = arch.nested_member_origin;
error (_("%s: failed to read archive header\n"), file_name);
ret |= process_object (qualified_name, member_file);
fclose (member_file);
free (member_file_name);
}
else if (is_thin_archive)
{
/* This is a proxy for a member of a nested archive. */
archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr;
/* The nested archive file will have been opened and setup by
get_archive_member_name. */
if (fseek (nested_arch.file, archive_file_offset, SEEK_SET) != 0)
{
error (_("%s: failed to seek to archive member.\n"), nested_arch.file_name);
ret = 1;
break;
}
ret |= process_object (qualified_name, nested_arch.file);
}
else
{
archive_file_offset = arch.next_arhdr_offset;
arch.next_arhdr_offset += archive_file_size;
ret |= process_object (qualified_name, file);
}
free (qualified_name);
}
out:
if (index_array != NULL)
free (index_array);
if (sym_table != NULL)
free (sym_table);
if (longnames != NULL)
free (longnames);
if (nested_arch.file != NULL)
fclose (nested_arch.file);
release_archive (&nested_arch);
release_archive (&arch);
return ret;
}
@ -10936,7 +11218,9 @@ process_file (char *file_name)
}
if (memcmp (armag, ARMAG, SARMAG) == 0)
ret = process_archive (file_name, file);
ret = process_archive (file_name, file, FALSE);
else if (memcmp (armag, ARMAGT, SARMAG) == 0)
ret = process_archive (file_name, file, TRUE);
else
{
if (do_archive_index)