* 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:
parent
83cf10fd4a
commit
2cf0635d9d
2 changed files with 854 additions and 557 deletions
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue