This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: PATCH: Add archive support to ELF
"H. J. Lu" <hjl@lucon.org> writes:
> There is such a tool, which is work in progress. Also not every place
> is ELF-only. We have to deal with EFI/COFF on ia64. I don't see bintils
> will go away anytime soon. All I want to do is read archive with
> readelf without extracting a 100MB archive first. If people object, I
> will leave this feature in my Linux binutils. I will take it out if
> Linux people don't like it :-).
Why don't you do just do it the right way? Why fight to do it the
wrong way?
I have appended an example of what the right way might look like.
Ian
Index: readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.215
diff -u -p -r1.215 readelf.c
--- readelf.c 5 Aug 2003 14:40:54 -0000 1.215
+++ readelf.c 10 Aug 2003 06:16:39 -0000
@@ -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,7 +248,7 @@ get_data (void *var, FILE *file, long of
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);
return NULL;
@@ -3064,7 +3068,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 +4508,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 +4555,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 +5615,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 +10161,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 +10188,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 +10221,6 @@ process_file (char *file_name)
process_arch_specific (file);
- fclose (file);
-
if (program_headers)
{
free (program_headers);
@@ -10258,6 +10260,209 @@ 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);
+ ret = process_object (file_name, file);
+ }
+
+ fclose (file);
+
+ return ret;
}
#ifdef SUPPORT_DISASSEMBLY