[patch] Add thin archive support to readelf
Cary Coutant
ccoutant@google.com
Fri Feb 27 22:37:00 GMT 2009
I promised a long time ago to provide a patch that adds thin archive
support to readelf. Here it is at long last; sorry for taking so
long.0
-cary
* 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.
-------------- next part --------------
Index: readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.438
diff -u -p -d -r1.438 readelf.c
--- readelf.c 23 Feb 2009 19:01:47 -0000 1.438
+++ readelf.c 27 Feb 2009 22:20:31 -0000
@@ -145,6 +145,7 @@
#include "getopt.h"
#include "libiberty.h"
#include "safe-ctype.h"
+#include "filenames.h"
char *program_name = "readelf";
int do_wide;
@@ -10534,28 +10535,98 @@ process_object (char *file_name, FILE *f
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 +10636,15 @@ process_archive (char *file_name, 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,67 +10667,63 @@ process_archive (char *file_name, 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)),
- 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);
/* 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;
+ 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 +10735,299 @@ process_archive (char *file_name, 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)
- {
- if (got == 0)
- ret = 0;
- else
- {
- error (_("%s: failed to read archive header following long symbol names\n"), file_name);
- ret = 1;
- }
- goto out;
- }
+ return 0;
+}
+
+/* Release the memory used for the archive information. */
+
+static void
+release_archive (struct archive_info *arch)
+{
+ 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)
+ {
+ 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 (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 ((i == 0) || ((i > 0) && (arch.index_array[i] != arch.index_array[i - 1])))
+ {
+ char *member_name = get_archive_member_name_at (&arch, arch.index_array[i], &nested_arch);
+ if (member_name != NULL)
+ {
+ 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);
+ }
}
}
- 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 +11035,10 @@ process_archive (char *file_name, 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 +11047,113 @@ process_archive (char *file_name, FILE *
while (1)
{
char *name;
- char *nameend;
- char *namealc;
+ size_t namelen;
+ char *qualified_name;
- if (arhdr.ar_name[0] == '/')
- {
- unsigned long off;
+ /* Read the next archive header. */
+ if (fseek (file, arch.next_arhdr_offset, SEEK_SET) != 0)
+ {
+ 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)
+ {
+ 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;
+ }
- off = strtoul (arhdr.ar_name + 1, NULL, 10);
- if (off >= longnames_size)
- {
- error (_("%s: invalid archive string table offset %lu\n"), file_name, off);
- ret = 1;
- break;
- }
+ arch.next_arhdr_offset += sizeof arch.arhdr;
- name = longnames + off;
- nameend = memchr (name, '/', longnames_size - off);
- }
- else
- {
- name = arhdr.ar_name;
- nameend = memchr (name, '/', 16);
- }
+ archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10);
+ if (archive_file_size & 01)
+ ++archive_file_size;
- if (nameend == NULL)
+ 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);
- namealc = malloc (file_name_size + (nameend - name) + 3);
- if (namealc == NULL)
+ qualified_name = make_qualified_name (&arch, &nested_arch, name);
+ if (qualified_name == NULL)
{
- error (_("Out of memory\n"));
+ error (_("%s: bad archive file name\n"), file_name);
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';
+ 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)
+ {
+ ret = 1;
+ break;
+ }
- archive_file_offset = ftell (file);
- archive_file_size = strtoul (arhdr.ar_size, NULL, 10);
+ member_file = fopen (member_file_name, "rb");
+ if (member_file == NULL)
+ {
+ error (_("Input file '%s' is not readable.\n"), member_file_name);
+ free (member_file_name);
+ ret = 1;
+ break;
+ }
- ret |= process_object (namealc, file);
+ archive_file_offset = arch.nested_member_origin;
- free (namealc);
+ 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;
- if (fseek (file,
- (archive_file_offset
- + archive_file_size
- + (archive_file_size & 1)),
- SEEK_SET) != 0)
- {
- error (_("%s: failed to seek to next archive header\n"), file_name);
- ret = 1;
- break;
- }
+ /* 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;
+ }
- got = fread (&arhdr, 1, sizeof arhdr, file);
- if (got != sizeof arhdr)
- {
- if (got == 0)
- break;
+ ret |= process_object (qualified_name, nested_arch.file);
+ }
+ else
+ {
+ archive_file_offset = arch.next_arhdr_offset;
+ arch.next_arhdr_offset += archive_file_size;
- error (_("%s: failed to read archive header\n"), file_name);
- ret = 1;
- break;
- }
+ 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 +11197,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)
More information about the Binutils
mailing list