mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-18 14:04:24 +08:00
Add ability for readelf to parse archives
This commit is contained in:
parent
e561512e36
commit
fb52b2f459
@ -1,3 +1,25 @@
|
||||
2003-08-11 Ian Lance Taylor <ian@airs.com>
|
||||
|
||||
* readelf.c: Add ability to read archives.
|
||||
(archive_file_offset): New variable.
|
||||
(archive_file_size): New variable.
|
||||
(get_data): Include archive_file_offset in file offset
|
||||
calculation when fseeking.
|
||||
(process_program_headers): Likewise.
|
||||
(process_symbol_table): Likewise.
|
||||
(process_dynamic_segment): Handle computation of end of file
|
||||
position when the file is in an archive.
|
||||
(process_object): New function. Contains the body of
|
||||
process_file().
|
||||
(process_archive): New function. Call process_object on each
|
||||
member of an archive.
|
||||
(process_file): Detect archives and handle appropriately.
|
||||
* Makefile.am: Add dependency on aout/ar.h for readelf.c
|
||||
* Makefile.in: Regenerate.
|
||||
* NEWS: Document readelf's new ability.
|
||||
* doc/binutils: Alter text to say that readelf supports archives
|
||||
and 64-bit ELF files.
|
||||
|
||||
2003-08-08 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* po/fr.po: Updated French translation.
|
||||
|
@ -477,7 +477,7 @@ readelf.o: readelf.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
|
||||
$(INCDIR)/elf/sparc.h $(INCDIR)/elf/v850.h $(INCDIR)/elf/vax.h \
|
||||
$(INCDIR)/elf/x86-64.h $(INCDIR)/elf/xstormy16.h $(INCDIR)/elf/iq2000.h \
|
||||
bucomm.h config.h $(INCDIR)/bin-bugs.h $(INCDIR)/fopen-same.h \
|
||||
unwind-ia64.h
|
||||
unwind-ia64.h $(INCDIR)/aout/ar.h
|
||||
rename.o: rename.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
|
||||
$(INCDIR)/symcat.h bucomm.h config.h $(INCDIR)/bin-bugs.h \
|
||||
$(INCDIR)/fopen-same.h
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
|
||||
# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
|
||||
|
||||
# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
@ -442,7 +442,7 @@ configure.in deflex.c defparse.c nlmheader.c rclex.c rcparse.c
|
||||
|
||||
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
|
||||
|
||||
TAR = tar
|
||||
TAR = gtar
|
||||
GZIP_ENV = --best
|
||||
SOURCES = $(nlmconv_SOURCES) $(srconv_SOURCES) $(sysdump_SOURCES) $(coffdump_SOURCES) $(dlltool_SOURCES) $(windres_SOURCES) $(dllwrap_SOURCES) $(size_SOURCES) $(objdump_SOURCES) $(ar_SOURCES) $(strings_SOURCES) $(ranlib_SOURCES) $(objcopy_SOURCES) $(addr2line_SOURCES) $(readelf_SOURCES) $(nm_new_SOURCES) $(strip_new_SOURCES) $(cxxfilt_SOURCES)
|
||||
OBJECTS = $(nlmconv_OBJECTS) $(srconv_OBJECTS) $(sysdump_OBJECTS) $(coffdump_OBJECTS) $(dlltool_OBJECTS) $(windres_OBJECTS) $(dllwrap_OBJECTS) $(size_OBJECTS) $(objdump_OBJECTS) $(ar_OBJECTS) $(strings_OBJECTS) $(ranlib_OBJECTS) $(objcopy_OBJECTS) $(addr2line_OBJECTS) $(readelf_OBJECTS) $(nm_new_OBJECTS) $(strip_new_OBJECTS) $(cxxfilt_OBJECTS)
|
||||
@ -870,7 +870,7 @@ distclean-generic:
|
||||
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
-test -z "arlex.cdeflex.crclex.carparse.harparse.cdefparse.hdefparse.cnlmheader.hnlmheader.crcparse.hrcparse.c" || rm -f arlex.c deflex.c rclex.c arparse.h arparse.c defparse.h defparse.c nlmheader.h nlmheader.c rcparse.h rcparse.c
|
||||
-test -z "arlexldeflexlrclexlarparseharparsecdefparsehdefparsecnlmheaderhnlmheadercrcparsehrcparsec" || rm -f arlexl deflexl rclexl arparseh arparsec defparseh defparsec nlmheaderh nlmheaderc rcparseh rcparsec
|
||||
mostlyclean-am: mostlyclean-hdr mostlyclean-binPROGRAMS \
|
||||
mostlyclean-noinstPROGRAMS mostlyclean-compile \
|
||||
mostlyclean-libtool mostlyclean-tags \
|
||||
@ -1205,7 +1205,7 @@ readelf.o: readelf.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
|
||||
$(INCDIR)/elf/sparc.h $(INCDIR)/elf/v850.h $(INCDIR)/elf/vax.h \
|
||||
$(INCDIR)/elf/x86-64.h $(INCDIR)/elf/xstormy16.h $(INCDIR)/elf/iq2000.h \
|
||||
bucomm.h config.h $(INCDIR)/bin-bugs.h $(INCDIR)/fopen-same.h \
|
||||
unwind-ia64.h
|
||||
unwind-ia64.h $(INCDIR)/aout/ar.h
|
||||
rename.o: rename.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
|
||||
$(INCDIR)/symcat.h bucomm.h config.h $(INCDIR)/bin-bugs.h \
|
||||
$(INCDIR)/fopen-same.h
|
||||
|
@ -1,5 +1,7 @@
|
||||
-*- text -*-
|
||||
|
||||
* readelf can now parse archives.
|
||||
|
||||
* objdump now accepts --debugging-tags to print the debug information in a
|
||||
format compatible with ctags tool.
|
||||
|
||||
|
@ -3078,9 +3078,8 @@ readelf [@option{-a}|@option{--all}]
|
||||
@command{readelf} displays information about one or more ELF format object
|
||||
files. The options control what particular information to display.
|
||||
|
||||
@var{elffile}@dots{} are the object files to be examined. At the
|
||||
moment, @command{readelf} does not support examining archives, nor does it
|
||||
support examining 64 bit ELF files.
|
||||
@var{elffile}@dots{} are the object files to be examined. 32-bit and
|
||||
64-bit ELF files are supported, as are archives containing ELF files.
|
||||
|
||||
@c man end
|
||||
|
||||
|
@ -90,11 +90,15 @@
|
||||
#include "elf/iq2000.h"
|
||||
#include "elf/xtensa.h"
|
||||
|
||||
#include "aout/ar.h"
|
||||
|
||||
#include "bucomm.h"
|
||||
#include "getopt.h"
|
||||
#include "libiberty.h"
|
||||
|
||||
char *program_name = "readelf";
|
||||
long archive_file_offset;
|
||||
unsigned long archive_file_size;
|
||||
unsigned long dynamic_addr;
|
||||
bfd_size_type dynamic_size;
|
||||
char *dynamic_strings;
|
||||
@ -244,9 +248,10 @@ get_data (void *var, FILE *file, long offset, size_t size, const char *reason)
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
if (fseek (file, offset, SEEK_SET))
|
||||
if (fseek (file, archive_file_offset + offset, SEEK_SET))
|
||||
{
|
||||
error (_("Unable to seek to 0x%x for %s\n"), offset, reason);
|
||||
error (_("Unable to seek to 0x%x for %s\n"),
|
||||
archive_file_offset + offset, reason);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3064,7 +3069,8 @@ process_program_headers (FILE *file)
|
||||
break;
|
||||
|
||||
case PT_INTERP:
|
||||
if (fseek (file, (long) segment->p_offset, SEEK_SET))
|
||||
if (fseek (file, archive_file_offset + (long) segment->p_offset,
|
||||
SEEK_SET))
|
||||
error (_("Unable to find program interpreter name\n"));
|
||||
else
|
||||
{
|
||||
@ -4503,10 +4509,16 @@ process_dynamic_segment (FILE *file)
|
||||
should work. */
|
||||
section.sh_offset = offset_from_vma (file, entry->d_un.d_val, 0);
|
||||
|
||||
if (fseek (file, 0, SEEK_END))
|
||||
error (_("Unable to seek to end of file!"));
|
||||
if (archive_file_offset != 0)
|
||||
section.sh_size = archive_file_size - section.sh_offset;
|
||||
else
|
||||
{
|
||||
if (fseek (file, 0, SEEK_END))
|
||||
error (_("Unable to seek to end of file!"));
|
||||
|
||||
section.sh_size = ftell (file) - section.sh_offset;
|
||||
}
|
||||
|
||||
section.sh_size = ftell (file) - section.sh_offset;
|
||||
if (is_32bit_elf)
|
||||
section.sh_entsize = sizeof (Elf32_External_Sym);
|
||||
else
|
||||
@ -4544,9 +4556,15 @@ process_dynamic_segment (FILE *file)
|
||||
should work. */
|
||||
|
||||
offset = offset_from_vma (file, entry->d_un.d_val, 0);
|
||||
if (fseek (file, 0, SEEK_END))
|
||||
error (_("Unable to seek to end of file\n"));
|
||||
str_tab_len = ftell (file) - offset;
|
||||
|
||||
if (archive_file_offset != 0)
|
||||
str_tab_len = archive_file_size - offset;
|
||||
else
|
||||
{
|
||||
if (fseek (file, 0, SEEK_END))
|
||||
error (_("Unable to seek to end of file\n"));
|
||||
str_tab_len = ftell (file) - offset;
|
||||
}
|
||||
|
||||
if (str_tab_len < 1)
|
||||
{
|
||||
@ -5598,8 +5616,10 @@ process_symbol_table (FILE *file)
|
||||
if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL)
|
||||
|| do_histogram))
|
||||
{
|
||||
if (fseek (file, offset_from_vma (file, dynamic_info[DT_HASH],
|
||||
sizeof nb + sizeof nc),
|
||||
if (fseek (file,
|
||||
(archive_file_offset
|
||||
+ offset_from_vma (file, dynamic_info[DT_HASH],
|
||||
sizeof nb + sizeof nc)),
|
||||
SEEK_SET))
|
||||
{
|
||||
error (_("Unable to seek to start of dynamic information"));
|
||||
@ -10142,30 +10162,18 @@ get_file_header (FILE *file)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Process one ELF object file according to the command line options.
|
||||
This file may actually be stored in an archive. The file is
|
||||
positioned at the start of the ELF object. */
|
||||
|
||||
static int
|
||||
process_file (char *file_name)
|
||||
process_object (char *file_name, FILE *file)
|
||||
{
|
||||
FILE *file;
|
||||
struct stat statbuf;
|
||||
unsigned int i;
|
||||
|
||||
if (stat (file_name, & statbuf) < 0)
|
||||
{
|
||||
error (_("Cannot stat input file %s.\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = fopen (file_name, "rb");
|
||||
if (file == NULL)
|
||||
{
|
||||
error (_("Input file %s not found.\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (! get_file_header (file))
|
||||
{
|
||||
error (_("%s: Failed to read file header\n"), file_name);
|
||||
fclose (file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -10181,10 +10189,7 @@ process_file (char *file_name)
|
||||
printf (_("\nFile: %s\n"), file_name);
|
||||
|
||||
if (! process_file_header ())
|
||||
{
|
||||
fclose (file);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
if (! process_section_headers (file))
|
||||
{
|
||||
@ -10217,8 +10222,6 @@ process_file (char *file_name)
|
||||
|
||||
process_arch_specific (file);
|
||||
|
||||
fclose (file);
|
||||
|
||||
if (program_headers)
|
||||
{
|
||||
free (program_headers);
|
||||
@ -10260,6 +10263,210 @@ process_file (char *file_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process an ELF archive. The file is positioned just after the
|
||||
ARMAG string. */
|
||||
|
||||
static int
|
||||
process_archive (char *file_name, FILE *file)
|
||||
{
|
||||
struct ar_hdr arhdr;
|
||||
size_t got;
|
||||
unsigned long size;
|
||||
char *longnames = NULL;
|
||||
unsigned long longnames_size = 0;
|
||||
size_t file_name_size;
|
||||
|
||||
show_name = 1;
|
||||
|
||||
got = fread (&arhdr, 1, sizeof arhdr, file);
|
||||
if (got != sizeof arhdr)
|
||||
{
|
||||
if (got == 0)
|
||||
return 0;
|
||||
|
||||
error (_("%s: failed to read archive header\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp (arhdr.ar_name, "/ ", 16) == 0)
|
||||
{
|
||||
/* This is the archive symbol table. Skip it.
|
||||
FIXME: We should have an option to dump it. */
|
||||
size = strtoul (arhdr.ar_size, NULL, 10);
|
||||
if (fseek (file, size + (size & 1), SEEK_CUR) != 0)
|
||||
{
|
||||
error (_("%s: failed to skip archive symbol table\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
got = fread (&arhdr, 1, sizeof arhdr, file);
|
||||
if (got != sizeof arhdr)
|
||||
{
|
||||
if (got == 0)
|
||||
return 0;
|
||||
|
||||
error (_("%s: failed to read archive header\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp (arhdr.ar_name, "// ", 16) == 0)
|
||||
{
|
||||
/* This is the archive string table holding long member
|
||||
names. */
|
||||
|
||||
longnames_size = strtoul (arhdr.ar_size, NULL, 10);
|
||||
|
||||
longnames = malloc (longnames_size);
|
||||
if (longnames == NULL)
|
||||
{
|
||||
error (_("Out of memory\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fread (longnames, longnames_size, 1, file) != 1)
|
||||
{
|
||||
error(_("%s: failed to read string table\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((longnames_size & 1) != 0)
|
||||
getc (file);
|
||||
|
||||
got = fread (&arhdr, 1, sizeof arhdr, file);
|
||||
if (got != sizeof arhdr)
|
||||
{
|
||||
if (got == 0)
|
||||
return 0;
|
||||
|
||||
error (_("%s: failed to read archive header\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
file_name_size = strlen (file_name);
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *name;
|
||||
char *nameend;
|
||||
char *namealc;
|
||||
|
||||
if (arhdr.ar_name[0] == '/')
|
||||
{
|
||||
unsigned long off;
|
||||
|
||||
off = strtoul (arhdr.ar_name + 1, NULL, 10);
|
||||
if (off >= longnames_size)
|
||||
{
|
||||
error (_("%s: invalid archive string table offset %lu\n"), off);
|
||||
return 1;
|
||||
}
|
||||
|
||||
name = longnames + off;
|
||||
nameend = memchr (name, '/', longnames_size - off);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = arhdr.ar_name;
|
||||
nameend = memchr (name, '/', 16);
|
||||
}
|
||||
|
||||
if (nameend == NULL)
|
||||
{
|
||||
error (_("%s: bad archive file name\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
namealc = malloc (file_name_size + (nameend - name) + 3);
|
||||
if (namealc == NULL)
|
||||
{
|
||||
error (_("Out of memory\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
process_object (namealc, file);
|
||||
|
||||
free (namealc);
|
||||
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
got = fread (&arhdr, 1, sizeof arhdr, file);
|
||||
if (got != sizeof arhdr)
|
||||
{
|
||||
if (got == 0)
|
||||
return 0;
|
||||
|
||||
error (_("%s: failed to read archive header\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (longnames != 0)
|
||||
free (longnames);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
process_file (char *file_name)
|
||||
{
|
||||
FILE *file;
|
||||
struct stat statbuf;
|
||||
char armag[SARMAG];
|
||||
int ret;
|
||||
|
||||
if (stat (file_name, &statbuf) < 0)
|
||||
{
|
||||
error (_("Cannot stat input file %s.\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = fopen (file_name, "rb");
|
||||
if (file == NULL)
|
||||
{
|
||||
error (_("Input file %s not found.\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fread (armag, SARMAG, 1, file) != 1)
|
||||
{
|
||||
error (_("%s: Failed to read file header\n"), file_name);
|
||||
fclose (file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp (armag, ARMAG, SARMAG) == 0)
|
||||
ret = process_archive (file_name, file);
|
||||
else
|
||||
{
|
||||
rewind (file);
|
||||
archive_file_size = archive_file_offset = 0;
|
||||
ret = process_object (file_name, file);
|
||||
}
|
||||
|
||||
fclose (file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_DISASSEMBLY
|
||||
/* Needed by the i386 disassembler. For extra credit, someone could
|
||||
fix this so that we insert symbolic addresses here, esp for GOT/PLT
|
||||
|
Loading…
Reference in New Issue
Block a user