X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=sidebyside;f=binutils%2Freadelf.c;h=e51e8b013ca0ee9f405ab8230623d81e355e9994;hb=8c838dbd52a91ecd0c1080f6d301ccd2314fff9d;hp=8f19a32ed418217c2f99ac448607fd58cacc23d4;hpb=3bdcfdf41f04c851af504aa0b653e0c806a930f4;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index 8f19a32ed4..e51e8b013c 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1,5 +1,5 @@ /* readelf.c -- display contents of an ELF format file - Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Originally developed by Eric Youngdale @@ -9,7 +9,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -41,10 +41,9 @@ ELF file than is provided by objdump. In particular it can display DWARF debugging information which (at the moment) objdump cannot. */ +#include "sysdep.h" #include -#include #include -#include #include /* for PATH_MAX */ @@ -74,12 +73,32 @@ #define BFD64 #endif +#include "bfd.h" +#include "bucomm.h" #include "dwarf.h" #include "elf/common.h" #include "elf/external.h" #include "elf/internal.h" + +/* Included here, before RELOC_MACROS_GEN_FUNC is defined, so that + we can obtain the H8 reloc numbers. We need these for the + get_reloc_size() function. We include h8.h again after defining + RELOC_MACROS_GEN_FUNC so that we get the naming function as well. */ + +#include "elf/h8.h" +#undef _ELF_H8_H + +/* Undo the effects of #including reloc-macros.h. */ + +#undef START_RELOC_NUMBERS +#undef RELOC_NUMBER +#undef FAKE_RELOC +#undef EMPTY_RELOC +#undef END_RELOC_NUMBERS +#undef _RELOC_MACROS_H + /* The following headers use the elf/reloc-macros.h file to automatically generate relocation recognition functions such as elf_mips_reloc_type() */ @@ -91,6 +110,7 @@ #include "elf/arm.h" #include "elf/avr.h" #include "elf/bfin.h" +#include "elf/cr16.h" #include "elf/cris.h" #include "elf/crx.h" #include "elf/d10v.h" @@ -112,6 +132,7 @@ #include "elf/m68k.h" #include "elf/m68hc11.h" #include "elf/mcore.h" +#include "elf/mep.h" #include "elf/mips.h" #include "elf/mmix.h" #include "elf/mn10200.h" @@ -135,9 +156,9 @@ #include "aout/ar.h" -#include "bucomm.h" #include "getopt.h" #include "libiberty.h" +#include "safe-ctype.h" char *program_name = "readelf"; static long archive_file_offset; @@ -181,6 +202,7 @@ static int do_histogram; static int do_debugging; static int do_arch; static int do_notes; +static int do_archive_index; static int is_32bit_elf; struct group_list @@ -199,33 +221,37 @@ static size_t group_count; static struct group *section_groups; static struct group **section_headers_groups; -/* A linked list of the section names for which dumps were requested - by name. */ + +/* Flag bits indicating particular types of dump. */ +#define HEX_DUMP (1 << 0) /* The -x command line switch. */ +#define DISASS_DUMP (1 << 1) /* The -i command line switch. */ +#define DEBUG_DUMP (1 << 2) /* The -w command line switch. */ +#define STRING_DUMP (1 << 3) /* The -p command line switch. */ + +typedef unsigned char dump_type; + +/* A linked list of the section names for which dumps were requested. */ struct dump_list_entry { char *name; - int type; + dump_type type; struct dump_list_entry *next; }; static struct dump_list_entry *dump_sects_byname; -/* A dynamic array of flags indicating for which sections a hex dump - has been requested (via the -x switch) and/or a disassembly dump - (via the -i switch). */ -char *cmdline_dump_sects = NULL; -unsigned num_cmdline_dump_sects = 0; +/* A dynamic array of flags indicating for which sections a dump + has been requested via command line switches. */ +static dump_type * cmdline_dump_sects = NULL; +static unsigned int num_cmdline_dump_sects = 0; /* A dynamic array of flags indicating for which sections a dump of some kind has been requested. It is reset on a per-object file basis and then initialised from the cmdline_dump_sects array, the results of interpreting the -w switch, and the dump_sects_byname list. */ -char *dump_sects = NULL; -unsigned int num_dump_sects = 0; +static dump_type * dump_sects = NULL; +static unsigned int num_dump_sects = 0; -#define HEX_DUMP (1 << 0) -#define DISASS_DUMP (1 << 1) -#define DEBUG_DUMP (1 << 2) /* How to print a vma value. */ typedef enum print_mode @@ -270,8 +296,6 @@ static void (*byte_put) (unsigned char *, bfd_vma, int); #define BYTE_GET(field) byte_get (field, sizeof (field)) -#define NUM_ELEM(array) (sizeof (array) / sizeof ((array)[0])) - #define GET_ELF_SYMBOLS(file, section) \ (is_32bit_elf ? get_32bit_elf_symbols (file, section) \ : get_64bit_elf_symbols (file, section)) @@ -282,8 +306,8 @@ static void (*byte_put) (unsigned char *, bfd_vma, int); #define GET_DYNAMIC_NAME(offset) (dynamic_strings + offset) /* This is just a bit of syntatic sugar. */ -#define streq(a,b) (strcmp ((a), (b)) == 0) -#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) +#define streq(a,b) (strcmp ((a), (b)) == 0) +#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) #define const_strneq(a,b) (strncmp ((a), (b), sizeof (b) - 1) == 0) static void * @@ -360,7 +384,7 @@ byte_put_little_endian (unsigned char *field, bfd_vma value, int size) } } -#if defined BFD64 && !BFD_HOST_64BIT_LONG +#if defined BFD64 && !BFD_HOST_64BIT_LONG && !BFD_HOST_64BIT_LONG_LONG static int print_dec_vma (bfd_vma vma, int is_signed) { @@ -468,6 +492,8 @@ print_vma (bfd_vma vma, print_mode mode) case HEX: #if BFD_HOST_64BIT_LONG return nc + printf ("%lx", vma); +#elif BFD_HOST_64BIT_LONG_LONG + return nc + printf ("%llx", vma); #else return nc + print_hex_vma (vma); #endif @@ -475,6 +501,8 @@ print_vma (bfd_vma vma, print_mode mode) case DEC: #if BFD_HOST_64BIT_LONG return printf ("%ld", vma); +#elif BFD_HOST_64BIT_LONG_LONG + return printf ("%lld", vma); #else return print_dec_vma (vma, 1); #endif @@ -485,6 +513,11 @@ print_vma (bfd_vma vma, print_mode mode) return printf ("%5ld", vma); else return printf ("%#lx", vma); +#elif BFD_HOST_64BIT_LONG_LONG + if (vma <= 99999) + return printf ("%5lld", vma); + else + return printf ("%#llx", vma); #else if (vma <= 99999) return printf ("%5ld", _bfd_int64_low (vma)); @@ -495,6 +528,8 @@ print_vma (bfd_vma vma, print_mode mode) case UNSIGNED: #if BFD_HOST_64BIT_LONG return printf ("%lu", vma); +#elif BFD_HOST_64BIT_LONG_LONG + return printf ("%llu", vma); #else return print_dec_vma (vma, 0); #endif @@ -598,6 +633,7 @@ guess_is_rela (unsigned long e_machine) case EM_AVR: case EM_AVR_OLD: case EM_BLACKFIN: + case EM_CR16: case EM_CRIS: case EM_CRX: case EM_D30V: @@ -615,6 +651,7 @@ guess_is_rela (unsigned long e_machine) case EM_M32C: case EM_M32R: case EM_MCORE: + case EM_CYGNUS_MEP: case EM_MMIX: case EM_MN10200: case EM_CYGNUS_MN10200: @@ -691,7 +728,7 @@ slurp_rela_relocs (FILE *file, if (relas == NULL) { free (erelas); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -719,7 +756,7 @@ slurp_rela_relocs (FILE *file, if (relas == NULL) { free (erelas); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -763,7 +800,7 @@ slurp_rel_relocs (FILE *file, if (rels == NULL) { free (erels); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -791,7 +828,7 @@ slurp_rel_relocs (FILE *file, if (rels == NULL) { free (erels); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -928,15 +965,23 @@ dump_relocations (FILE *file, if (is_32bit_elf) { -#ifdef _bfd_int64_low - printf ("%8.8lx %8.8lx ", _bfd_int64_low (offset), _bfd_int64_low (info)); -#else - printf ("%8.8lx %8.8lx ", offset, info); -#endif + printf ("%8.8lx %8.8lx ", + (unsigned long) offset & 0xffffffff, + (unsigned long) info & 0xffffffff); } else { -#ifdef _bfd_int64_low +#if BFD_HOST_64BIT_LONG + printf (do_wide + ? "%16.16lx %16.16lx " + : "%12.12lx %12.12lx ", + offset, info); +#elif BFD_HOST_64BIT_LONG_LONG + printf (do_wide + ? "%16.16llx %16.16llx " + : "%12.12llx %12.12llx ", + offset, info); +#else printf (do_wide ? "%8.8lx%8.8lx %8.8lx%8.8lx " : "%4.4lx%8.8lx %4.4lx%8.8lx ", @@ -944,11 +989,6 @@ dump_relocations (FILE *file, _bfd_int64_low (offset), _bfd_int64_high (info), _bfd_int64_low (info)); -#else - printf (do_wide - ? "%16.16lx %16.16lx " - : "%12.12lx %12.12lx ", - offset, info); #endif } @@ -1167,14 +1207,18 @@ dump_relocations (FILE *file, case EM_BLACKFIN: rtype = elf_bfin_reloc_type (type); break; + + case EM_CYGNUS_MEP: + rtype = elf_mep_reloc_type (type); + break; + + case EM_CR16: + rtype = elf_cr16_reloc_type (type); + break; } if (rtype == NULL) -#ifdef _bfd_int64_low - printf (_("unrecognized: %-7lx"), _bfd_int64_low (type)); -#else - printf (_("unrecognized: %-7lx"), type); -#endif + printf (_("unrecognized: %-7lx"), (unsigned long) type & 0xffffffff); else printf (do_wide ? "%-22.22s" : "%-17.17s", rtype); @@ -1290,22 +1334,16 @@ dump_relocations (FILE *file, printf (" Type2: "); if (rtype2 == NULL) -#ifdef _bfd_int64_low - printf (_("unrecognized: %-7lx"), _bfd_int64_low (type2)); -#else - printf (_("unrecognized: %-7lx"), type2); -#endif + printf (_("unrecognized: %-7lx"), + (unsigned long) type2 & 0xffffffff); else printf ("%-17.17s", rtype2); printf ("\n Type3: "); if (rtype3 == NULL) -#ifdef _bfd_int64_low - printf (_("unrecognized: %-7lx"), _bfd_int64_low (type3)); -#else - printf (_("unrecognized: %-7lx"), type3); -#endif + printf (_("unrecognized: %-7lx"), + (unsigned long) type3 & 0xffffffff); else printf ("%-17.17s", rtype3); @@ -1762,8 +1800,10 @@ get_machine_name (unsigned e_machine) case EM_NIOS32: return "Altera Nios"; case EM_ALTERA_NIOS2: return "Altera Nios II"; case EM_XC16X: return "Infineon Technologies xc16x"; + case EM_CYGNUS_MEP: return "Toshiba MeP Media Engine"; + case EM_CR16: return "National Semiconductor's CR16"; default: - snprintf (buff, sizeof (buff), _(": %x"), e_machine); + snprintf (buff, sizeof (buff), _(": 0x%x"), e_machine); return buff; } } @@ -2715,9 +2755,11 @@ static struct option options[] = {"arch-specific", no_argument, 0, 'A'}, {"version-info", no_argument, 0, 'V'}, {"use-dynamic", no_argument, 0, 'D'}, + {"unwind", no_argument, 0, 'u'}, + {"archive-index", no_argument, 0, 'c'}, {"hex-dump", required_argument, 0, 'x'}, {"debug-dump", optional_argument, 0, OPTION_DEBUG_DUMP}, - {"unwind", no_argument, 0, 'u'}, + {"string-dump", required_argument, 0, 'p'}, #ifdef SUPPORT_DISASSEMBLY {"instruction-dump", required_argument, 0, 'i'}, #endif @@ -2729,11 +2771,11 @@ static struct option options[] = }; static void -usage (void) +usage (FILE *stream) { - fprintf (stdout, _("Usage: readelf elf-file(s)\n")); - fprintf (stdout, _(" Display information about the contents of ELF format files\n")); - fprintf (stdout, _(" Options are:\n\ + fprintf (stream, _("Usage: readelf elf-file(s)\n")); + fprintf (stream, _(" Display information about the contents of ELF format files\n")); + fprintf (stream, _(" Options are:\n\ -a --all Equivalent to: -h -l -S -s -r -d -V -A -I\n\ -h --file-header Display the ELF file header\n\ -l --program-headers Display the program headers\n\ @@ -2751,25 +2793,31 @@ usage (void) -d --dynamic Display the dynamic section (if present)\n\ -V --version-info Display the version sections (if present)\n\ -A --arch-specific Display architecture specific information (if any).\n\ + -c --archive-index Display the symbol/file index in an archive\n\ -D --use-dynamic Use the dynamic section info when displaying symbols\n\ - -x --hex-dump= Dump the contents of section \n\ + -x --hex-dump=\n\ + Dump the contents of section as bytes\n\ + -p --string-dump=\n\ + Dump the contents of section as strings\n\ -w[liaprmfFsoR] or\n\ --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\ Display the contents of DWARF2 debug sections\n")); #ifdef SUPPORT_DISASSEMBLY - fprintf (stdout, _("\ - -i --instruction-dump=\n\ - Disassemble the contents of section \n")); + fprintf (stream, _("\ + -i --instruction-dump=\n\ + Disassemble the contents of section \n")); #endif - fprintf (stdout, _("\ + fprintf (stream, _("\ -I --histogram Display histogram of bucket list lengths\n\ -W --wide Allow output width to exceed 80 characters\n\ @ Read options from \n\ -H --help Display this information\n\ -v --version Display the version number of readelf\n")); - fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO); - exit (0); + if (REPORT_BUGS_TO[0] && stream == stdout) + fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO); + + exit (stream == stdout ? 0 : 1); } /* Record the fact that the user wants the contents of section number @@ -2778,20 +2826,20 @@ usage (void) the first time. */ static void -request_dump (unsigned int section, int type) +request_dump_bynumber (unsigned int section, dump_type type) { if (section >= num_dump_sects) { - char *new_dump_sects; + dump_type *new_dump_sects; - new_dump_sects = calloc (section + 1, 1); + new_dump_sects = calloc (section + 1, sizeof (* dump_sects)); if (new_dump_sects == NULL) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); else { /* Copy current flag settings. */ - memcpy (new_dump_sects, dump_sects, num_dump_sects); + memcpy (new_dump_sects, dump_sects, num_dump_sects * sizeof (* dump_sects)); free (dump_sects); @@ -2809,17 +2857,17 @@ request_dump (unsigned int section, int type) /* Request a dump by section name. */ static void -request_dump_byname (const char *section, int type) +request_dump_byname (const char *section, dump_type type) { struct dump_list_entry *new_request; new_request = malloc (sizeof (struct dump_list_entry)); if (!new_request) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); new_request->name = strdup (section); if (!new_request->name) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); new_request->type = type; @@ -2833,10 +2881,10 @@ parse_args (int argc, char **argv) int c; if (argc < 2) - usage (); + usage (stderr); while ((c = getopt_long - (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF) + (argc, argv, "ADHINSVWacdeghi:lnp:rstuvw::x:", options, NULL)) != EOF) { char *cp; int section; @@ -2847,7 +2895,7 @@ parse_args (int argc, char **argv) /* Long options. */ break; case 'H': - usage (); + usage (stdout); break; case 'a': @@ -2910,14 +2958,25 @@ parse_args (int argc, char **argv) case 'n': do_notes++; break; + case 'c': + do_archive_index++; + break; case 'x': do_dump++; section = strtoul (optarg, & cp, 0); if (! *cp && section >= 0) - request_dump (section, HEX_DUMP); + request_dump_bynumber (section, HEX_DUMP); else request_dump_byname (optarg, HEX_DUMP); break; + case 'p': + do_dump++; + section = strtoul (optarg, & cp, 0); + if (! *cp && section >= 0) + request_dump_bynumber (section, STRING_DUMP); + else + request_dump_byname (optarg, STRING_DUMP); + break; case 'w': do_dump++; if (optarg == 0) @@ -3065,11 +3124,9 @@ parse_args (int argc, char **argv) do_dump++; section = strtoul (optarg, & cp, 0); if (! *cp && section >= 0) - { - request_dump (section, DISASS_DUMP); - break; - } - goto oops; + request_dump_bynumber (section, DISASS_DUMP); + else + request_dump_byname (optarg, DISASS_DUMP); #endif case 'v': print_version (program_name); @@ -3081,26 +3138,23 @@ parse_args (int argc, char **argv) do_wide++; break; default: -#ifdef SUPPORT_DISASSEMBLY - oops: -#endif /* xgettext:c-format */ error (_("Invalid option '-%c'\n"), c); /* Drop through. */ case '?': - usage (); + usage (stderr); } } if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections && !do_segments && !do_header && !do_dump && !do_version && !do_histogram && !do_debugging && !do_arch && !do_notes - && !do_section_groups) - usage (); + && !do_section_groups && !do_archive_index) + usage (stderr); else if (argc < 3) { warn (_("Nothing to do.\n")); - usage (); + usage (stderr); } } @@ -3485,18 +3539,21 @@ process_program_headers (FILE *file) sec = find_section (".dynamic"); if (sec == NULL || sec->sh_size == 0) { - error (_("no .dynamic section in the dynamic segment")); + error (_("no .dynamic section in the dynamic segment\n")); break; } + if (sec->sh_type == SHT_NOBITS) + break; + dynamic_addr = sec->sh_offset; dynamic_size = sec->sh_size; if (dynamic_addr < segment->p_offset || dynamic_addr > segment->p_offset + segment->p_filesz) - warn (_("the .dynamic section is not contained within the dynamic segment")); + warn (_("the .dynamic section is not contained within the dynamic segment\n")); else if (dynamic_addr > segment->p_offset) - warn (_("the .dynamic section is not the first section in the dynamic segment.")); + warn (_("the .dynamic section is not the first section in the dynamic segment.\n")); } else { @@ -3517,10 +3574,11 @@ process_program_headers (FILE *file) int ret = snprintf (fmt, sizeof (fmt), "%%%ds", PATH_MAX); if (ret >= (int) sizeof (fmt) || ret < 0) - error (_("Internal error: failed to create format string to display program interpreter")); + error (_("Internal error: failed to create format string to display program interpreter\n")); program_interpreter[0] = 0; - fscanf (file, fmt, program_interpreter); + if (fscanf (file, fmt, program_interpreter) <= 0) + error (_("Unable to read program interpreter name\n")); if (do_segments) printf (_("\n [Requesting program interpreter: %s]"), @@ -4146,14 +4204,14 @@ process_section_headers (FILE *file) || (do_debug_str && streq (name, "str")) || (do_debug_loc && streq (name, "loc")) ) - request_dump (i, DEBUG_DUMP); + request_dump_bynumber (i, DEBUG_DUMP); } /* linkonce section to be combined with .debug_info at link time. */ else if ((do_debugging || do_debug_info) && const_strneq (name, ".gnu.linkonce.wi.")) - request_dump (i, DEBUG_DUMP); + request_dump_bynumber (i, DEBUG_DUMP); else if (do_debug_frames && streq (name, ".eh_frame")) - request_dump (i, DEBUG_DUMP); + request_dump_bynumber (i, DEBUG_DUMP); } if (! do_sections) @@ -5537,7 +5595,7 @@ dynamic_section_mips_val (Elf_Internal_Dyn *entry) }; unsigned int cnt; int first = 1; - for (cnt = 0; cnt < NUM_ELEM (opts); ++cnt) + for (cnt = 0; cnt < ARRAY_SIZE (opts); ++cnt) if (entry->d_un.d_val & (1 << cnt)) { printf ("%s%s", first ? "" : " ", opts[cnt]); @@ -5626,7 +5684,7 @@ dynamic_section_parisc_val (Elf_Internal_Dyn *entry) size_t cnt; bfd_vma val = entry->d_un.d_val; - for (cnt = 0; cnt < sizeof (flags) / sizeof (flags[0]); ++cnt) + for (cnt = 0; cnt < ARRAY_SIZE (flags); ++cnt) if (val & flags[cnt].bit) { if (! first) @@ -5837,7 +5895,7 @@ process_dynamic_section (FILE *file) else { if (fseek (file, 0, SEEK_END)) - error (_("Unable to seek to end of file!")); + error (_("Unable to seek to end of file!\n")); section.sh_size = ftell (file) - section.sh_offset; } @@ -6406,6 +6464,7 @@ process_version_sections (FILE *file) Elf_External_Verdef *edefs; unsigned int idx; unsigned int cnt; + char *endbuf; found = 1; @@ -6425,6 +6484,7 @@ process_version_sections (FILE *file) edefs = get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("version definition section")); + endbuf = (char *) edefs + section->sh_size; if (!edefs) break; @@ -6439,6 +6499,8 @@ process_version_sections (FILE *file) int isum; vstart = ((char *) edefs) + idx; + if (vstart + sizeof (*edef) > endbuf) + break; edef = (Elf_External_Verdef *) vstart; @@ -6476,6 +6538,8 @@ process_version_sections (FILE *file) vstart += aux.vda_next; eaux = (Elf_External_Verdaux *) vstart; + if (vstart + sizeof (*eaux) > endbuf) + break; aux.vda_name = BYTE_GET (eaux->vda_name); aux.vda_next = BYTE_GET (eaux->vda_next); @@ -6487,9 +6551,13 @@ process_version_sections (FILE *file) printf (_(" %#06x: Parent %d, name index: %ld\n"), isum, j, aux.vda_name); } + if (j < ent.vd_cnt) + printf (_(" Version def aux past end of section\n")); idx += ent.vd_next; } + if (cnt < section->sh_info) + printf (_(" Version definition past end of section\n")); free (edefs); } @@ -6500,6 +6568,7 @@ process_version_sections (FILE *file) Elf_External_Verneed *eneed; unsigned int idx; unsigned int cnt; + char *endbuf; found = 1; @@ -6518,6 +6587,7 @@ process_version_sections (FILE *file) eneed = get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("version need section")); + endbuf = (char *) eneed + section->sh_size; if (!eneed) break; @@ -6530,6 +6600,8 @@ process_version_sections (FILE *file) char *vstart; vstart = ((char *) eneed) + idx; + if (vstart + sizeof (*entry) > endbuf) + break; entry = (Elf_External_Verneed *) vstart; @@ -6555,6 +6627,8 @@ process_version_sections (FILE *file) Elf_External_Vernaux *eaux; Elf_Internal_Vernaux aux; + if (vstart + sizeof (*eaux) > endbuf) + break; eaux = (Elf_External_Vernaux *) vstart; aux.vna_hash = BYTE_GET (eaux->vna_hash); @@ -6576,9 +6650,13 @@ process_version_sections (FILE *file) isum += aux.vna_next; vstart += aux.vna_next; } + if (j < ent.vn_cnt) + printf (_(" Version need aux past end of section\n")); idx += ent.vn_next; } + if (cnt < section->sh_info) + printf (_(" Version need past end of section\n")); free (eneed); } @@ -6723,7 +6801,10 @@ process_version_sections (FILE *file) { ivna.vna_name = BYTE_GET (evna.vna_name); - name = strtab + ivna.vna_name; + if (ivna.vna_name >= string_sec->sh_size) + name = _("*invalid*"); + else + name = strtab + ivna.vna_name; nn += printf ("(%s%-*s", name, 12 - (int) strlen (name), @@ -6775,7 +6856,10 @@ process_version_sections (FILE *file) ivda.vda_name = BYTE_GET (evda.vda_name); - name = strtab + ivda.vda_name; + if (ivda.vda_name >= string_sec->sh_size) + name = _("*invalid*"); + else + name = strtab + ivda.vda_name; nn += printf ("(%s%-*s", name, 12 - (int) strlen (name), @@ -6843,6 +6927,8 @@ get_symbol_type (unsigned int type) case STT_FILE: return "FILE"; case STT_COMMON: return "COMMON"; case STT_TLS: return "TLS"; + case STT_RELC: return "RELC"; + case STT_SRELC: return "SRELC"; default: if (type >= STT_LOPROC && type <= STT_HIPROC) { @@ -7033,7 +7119,7 @@ process_symbol_table (FILE *file) sizeof nb + sizeof nc)), SEEK_SET)) { - error (_("Unable to seek to start of dynamic information")); + error (_("Unable to seek to start of dynamic information\n")); return 0; } @@ -7259,7 +7345,7 @@ process_symbol_table (FILE *file) check_def = 0; } else if (! is_nobits) - error (_("bad dynamic symbol")); + error (_("bad dynamic symbol\n")); else check_def = 1; } @@ -7342,7 +7428,7 @@ process_symbol_table (FILE *file) lengths = calloc (nbuckets, sizeof (*lengths)); if (lengths == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } for (hn = 0; hn < nbuckets; ++hn) @@ -7358,7 +7444,7 @@ process_symbol_table (FILE *file) counts = calloc (maxlength + 1, sizeof (*counts)); if (counts == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -7407,7 +7493,7 @@ process_symbol_table (FILE *file) sizeof nb)), SEEK_SET)) { - error (_("Unable to seek to start of dynamic information")); + error (_("Unable to seek to start of dynamic information\n")); return 0; } @@ -7431,7 +7517,7 @@ process_symbol_table (FILE *file) + offset_from_vma (file, buckets_vma, 4)), SEEK_SET)) { - error (_("Unable to seek to start of dynamic information")); + error (_("Unable to seek to start of dynamic information\n")); return 0; } @@ -7461,7 +7547,7 @@ process_symbol_table (FILE *file) + 4 * (ngnubuckets + maxchain), 4)), SEEK_SET)) { - error (_("Unable to seek to start of dynamic information")); + error (_("Unable to seek to start of dynamic information\n")); return 0; } @@ -7485,7 +7571,7 @@ process_symbol_table (FILE *file) + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)), SEEK_SET)) { - error (_("Unable to seek to start of dynamic information")); + error (_("Unable to seek to start of dynamic information\n")); return 0; } @@ -7497,7 +7583,7 @@ process_symbol_table (FILE *file) lengths = calloc (ngnubuckets, sizeof (*lengths)); if (lengths == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -7522,7 +7608,7 @@ process_symbol_table (FILE *file) counts = calloc (maxlength + 1, sizeof (*counts)); if (counts == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -7632,8 +7718,86 @@ disassemble_section (Elf_Internal_Shdr *section, FILE *file) #endif static int -dump_section (Elf_Internal_Shdr *section, FILE *file) +dump_section_as_strings (Elf_Internal_Shdr *section, FILE *file) { + Elf_Internal_Shdr *relsec; + bfd_size_type num_bytes; + bfd_vma addr; + char *data; + char *end; + char *start; + char *name = SECTION_NAME (section); + bfd_boolean some_strings_shown; + + num_bytes = section->sh_size; + + if (num_bytes == 0 || section->sh_type == SHT_NOBITS) + { + printf (_("\nSection '%s' has no data to dump.\n"), name); + return 0; + } + + addr = section->sh_addr; + + start = get_data (NULL, file, section->sh_offset, 1, num_bytes, + _("section data")); + if (!start) + return 0; + + printf (_("\nString dump of section '%s':\n"), name); + + /* If the section being dumped has relocations against it the user might + be expecting these relocations to have been applied. Check for this + case and issue a warning message in order to avoid confusion. + FIXME: Maybe we ought to have an option that dumps a section with + relocs applied ? */ + for (relsec = section_headers; + relsec < section_headers + elf_header.e_shnum; + ++relsec) + { + if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL) + || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum + || SECTION_HEADER (relsec->sh_info) != section + || relsec->sh_size == 0 + || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) + continue; + + printf (_(" Note: This section has relocations against it, but these have NOT been applied to this dump.\n")); + break; + } + + data = start; + end = start + num_bytes; + some_strings_shown = FALSE; + + while (data < end) + { + while (!ISPRINT (* data)) + if (++ data >= end) + break; + + if (data < end) + { + printf (" [%6zx] %s\n", data - start, data); + data += strlen (data); + some_strings_shown = TRUE; + } + } + + if (! some_strings_shown) + printf (_(" No strings found in this section.")); + + free (start); + + putchar ('\n'); + return 1; +} + + +static int +dump_section_as_bytes (Elf_Internal_Shdr *section, FILE *file) +{ + Elf_Internal_Shdr *relsec; bfd_size_type bytes; bfd_vma addr; unsigned char *data; @@ -7657,6 +7821,26 @@ dump_section (Elf_Internal_Shdr *section, FILE *file) if (!start) return 0; + /* If the section being dumped has relocations against it the user might + be expecting these relocations to have been applied. Check for this + case and issue a warning message in order to avoid confusion. + FIXME: Maybe we ought to have an option that dumps a section with + relocs applied ? */ + for (relsec = section_headers; + relsec < section_headers + elf_header.e_shnum; + ++relsec) + { + if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL) + || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum + || SECTION_HEADER (relsec->sh_info) != section + || relsec->sh_size == 0 + || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) + continue; + + printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n")); + break; + } + data = start; while (bytes) @@ -7698,9 +7882,47 @@ dump_section (Elf_Internal_Shdr *section, FILE *file) free (start); + putchar ('\n'); return 1; } +/* Return the number of bytes affected by a given reloc. + This information is architecture and reloc dependent. + Returns 4 by default, although this is not always correct. + It should return 0 if a decision cannot be made. + FIXME: This is not the correct way to solve this problem. + The proper way is to have target specific reloc sizing functions + created by the reloc-macros.h header, in the same way that it + already creates the reloc naming functions. */ + +static unsigned int +get_reloc_size (Elf_Internal_Rela * reloc) +{ + switch (elf_header.e_machine) + { + case EM_H8S: + case EM_H8_300: + case EM_H8_300H: + case EM_H8_500: + switch (ELF32_R_TYPE (reloc->r_info)) + { + /* PR gas/3800 - without this information we do not correctly + decode the debug information generated by the h8300 assembler. */ + case R_H8_DIR16: + return 2; + default: + return 4; + } + default: + /* FIXME: We need to extend this switch statement to cope with other + architecture's relocs. (When those relocs are used against debug + sections, and when their size is not 4). But see the multiple + inclusions of for an example of the hoops that we need + to jump through in order to obtain the reloc numbers. */ + return 4; + } +} + /* Apply addends of RELA relocations. */ static int @@ -7710,14 +7932,13 @@ debug_apply_rela_addends (void *file, { Elf_Internal_Shdr *relsec; unsigned char *end = start + section->sh_size; - /* FIXME: The relocation field size is relocation type dependent. */ - unsigned int reloc_size = 4; if (!is_relocatable) return 1; - if (section->sh_size < reloc_size) - return 1; + /* SH uses RELA but uses in place value instead of the addend field. */ + if (elf_header.e_machine == EM_SH) + return 0; for (relsec = section_headers; relsec < section_headers + elf_header.e_shnum; @@ -7746,6 +7967,16 @@ debug_apply_rela_addends (void *file, for (rp = rela; rp < rela + nrelas; ++rp) { unsigned char *loc; + unsigned int reloc_size; + + reloc_size = get_reloc_size (rp); + if (reloc_size == 0) + { + warn (_("skipping relocation of unknown size against offset 0x%lx in section %s\n"), + (unsigned long) rp->r_offset, + SECTION_NAME (section)); + continue; + } loc = start + rp->r_offset; if ((loc + reloc_size) > end) @@ -7917,7 +8148,7 @@ initialise_dumps_byname (void) for (i = 0, any = 0; i < elf_header.e_shnum; i++) if (streq (SECTION_NAME (section_headers + i), cur->name)) { - request_dump (i, cur->type); + request_dump_bynumber (i, cur->type); any = 1; } @@ -7947,10 +8178,13 @@ process_section_contents (FILE *file) disassemble_section (section, file); #endif if (dump_sects[i] & HEX_DUMP) - dump_section (section, file); + dump_section_as_bytes (section, file); if (dump_sects[i] & DEBUG_DUMP) display_debug_section (section, file); + + if (dump_sects[i] & STRING_DUMP) + dump_section_as_strings (section, file); } /* Check to see if the user requested a @@ -8196,8 +8430,166 @@ display_arm_attribute (unsigned char *p) return p; } +static unsigned char * +display_gnu_attribute (unsigned char * p, + unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int)) +{ + int tag; + unsigned int len; + int val; + int type; + + tag = read_uleb128 (p, &len); + p += len; + + /* Tag_compatibility is the only generic GNU attribute defined at + present. */ + if (tag == 32) + { + val = read_uleb128 (p, &len); + p += len; + printf ("flag = %d, vendor = %s\n", val, p); + p += strlen ((char *) p) + 1; + return p; + } + + if ((tag & 2) == 0 && display_proc_gnu_attribute) + return display_proc_gnu_attribute (p, tag); + + if (tag & 1) + type = 1; /* String. */ + else + type = 2; /* uleb128. */ + printf (" Tag_unknown_%d: ", tag); + + if (type == 1) + { + printf ("\"%s\"\n", p); + p += strlen ((char *) p) + 1; + } + else + { + val = read_uleb128 (p, &len); + p += len; + printf ("%d (0x%x)\n", val, val); + } + + return p; +} + +static unsigned char * +display_power_gnu_attribute (unsigned char *p, int tag) +{ + int type; + unsigned int len; + int val; + + if (tag == Tag_GNU_Power_ABI_FP) + { + val = read_uleb128 (p, &len); + p += len; + printf (" Tag_GNU_Power_ABI_FP: "); + + switch (val) + { + case 0: + printf ("Hard or soft float\n"); + break; + case 1: + printf ("Hard float\n"); + break; + case 2: + printf ("Soft float\n"); + break; + default: + printf ("??? (%d)\n", val); + break; + } + return p; + } + + if (tag & 1) + type = 1; /* String. */ + else + type = 2; /* uleb128. */ + printf (" Tag_unknown_%d: ", tag); + + if (type == 1) + { + printf ("\"%s\"\n", p); + p += strlen ((char *) p) + 1; + } + else + { + val = read_uleb128 (p, &len); + p += len; + printf ("%d (0x%x)\n", val, val); + } + + return p; +} + +static unsigned char * +display_mips_gnu_attribute (unsigned char *p, int tag) +{ + int type; + unsigned int len; + int val; + + if (tag == Tag_GNU_MIPS_ABI_FP) + { + val = read_uleb128 (p, &len); + p += len; + printf (" Tag_GNU_MIPS_ABI_FP: "); + + switch (val) + { + case 0: + printf ("Hard or soft float\n"); + break; + case 1: + printf ("Hard float (-mdouble-float)\n"); + break; + case 2: + printf ("Hard float (-msingle-float)\n"); + break; + case 3: + printf ("Soft float\n"); + break; + default: + printf ("??? (%d)\n", val); + break; + } + return p; + } + + if (tag & 1) + type = 1; /* String. */ + else + type = 2; /* uleb128. */ + printf (" Tag_unknown_%d: ", tag); + + if (type == 1) + { + printf ("\"%s\"\n", p); + p += strlen ((char *) p) + 1; + } + else + { + val = read_uleb128 (p, &len); + p += len; + printf ("%d (0x%x)\n", val, val); + } + + return p; +} + static int -process_arm_specific (FILE *file) +process_attributes (FILE * file, + const char * public_name, + unsigned int proc_type, + unsigned char * (* display_pub_attribute) (unsigned char *), + unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int)) { Elf_Internal_Shdr *sect; unsigned char *contents; @@ -8212,56 +8604,71 @@ process_arm_specific (FILE *file) i < elf_header.e_shnum; i++, sect++) { - if (sect->sh_type != SHT_ARM_ATTRIBUTES) + if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES) continue; contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size, _("attributes")); - - if (!contents) + if (contents == NULL) continue; + p = contents; if (*p == 'A') { len = sect->sh_size - 1; p++; + while (len > 0) { int namelen; bfd_boolean public_section; + bfd_boolean gnu_section; section_len = byte_get (p, 4); p += 4; + if (section_len > len) { printf (_("ERROR: Bad section length (%d > %d)\n"), - (int)section_len, (int)len); + (int) section_len, (int) len); section_len = len; } + len -= section_len; printf ("Attribute Section: %s\n", p); - if (strcmp ((char *)p, "aeabi") == 0) + + if (public_name && streq ((char *) p, public_name)) public_section = TRUE; else public_section = FALSE; - namelen = strlen ((char *)p) + 1; + + if (streq ((char *) p, "gnu")) + gnu_section = TRUE; + else + gnu_section = FALSE; + + namelen = strlen ((char *) p) + 1; p += namelen; section_len -= namelen + 4; + while (section_len > 0) { int tag = *(p++); int val; bfd_vma size; + size = byte_get (p, 4); if (size > section_len) { printf (_("ERROR: Bad subsection length (%d > %d)\n"), - (int)size, (int)section_len); + (int) size, (int) section_len); size = section_len; } + section_len -= size; end = p + size - 1; p += 4; + switch (tag) { case 1: @@ -8276,6 +8683,7 @@ process_arm_specific (FILE *file) for (;;) { unsigned int i; + val = read_uleb128 (p, &i); p += i; if (val == 0) @@ -8289,10 +8697,17 @@ process_arm_specific (FILE *file) public_section = FALSE; break; } + if (public_section) { while (p < end) - p = display_arm_attribute(p); + p = display_pub_attribute (p); + } + else if (gnu_section) + { + while (p < end) + p = display_gnu_attribute (p, + display_proc_gnu_attribute); } else { @@ -8304,15 +8719,27 @@ process_arm_specific (FILE *file) } } else - { - printf (_("Unknown format '%c'\n"), *p); - } + printf (_("Unknown format '%c'\n"), *p); - free(contents); + free (contents); } return 1; } +static int +process_arm_specific (FILE *file) +{ + return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES, + display_arm_attribute, NULL); +} + +static int +process_power_specific (FILE *file) +{ + return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, + display_power_gnu_attribute); +} + static int process_mips_specific (FILE *file) { @@ -8323,6 +8750,9 @@ process_mips_specific (FILE *file) size_t options_offset = 0; size_t conflicts_offset = 0; + process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, + display_mips_gnu_attribute); + /* We have a lot of special sections. Thanks SGI! */ if (dynamic_section == NULL) /* No information available. */ @@ -8417,9 +8847,7 @@ process_mips_specific (FILE *file) int flags = liblist.l_flags; size_t fcnt; - for (fcnt = 0; - fcnt < sizeof (l_flags_vals) / sizeof (l_flags_vals[0]); - ++fcnt) + for (fcnt = 0; fcnt < ARRAY_SIZE (l_flags_vals); ++fcnt) if ((flags & l_flags_vals[fcnt].bit) != 0) { fputs (l_flags_vals[fcnt].name, stdout); @@ -8456,7 +8884,7 @@ process_mips_specific (FILE *file) iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt)); if (iopt == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -8641,14 +9069,14 @@ process_mips_specific (FILE *file) if (dynamic_symbols == NULL) { - error (_("conflict list found without a dynamic symbol table")); + error (_("conflict list found without a dynamic symbol table\n")); return 0; } iconf = cmalloc (conflictsno, sizeof (*iconf)); if (iconf == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -8840,6 +9268,27 @@ get_note_type (unsigned e_type) return buff; } +static const char * +get_gnu_elf_note_type (unsigned e_type) +{ + static char buff[64]; + + switch (e_type) + { + case NT_GNU_ABI_TAG: + return _("NT_GNU_ABI_TAG (ABI version tag)"); + case NT_GNU_HWCAP: + return _("NT_GNU_HWCAP (DSO-supplied software HWCAP info)"); + case NT_GNU_BUILD_ID: + return _("NT_GNU_BUILD_ID (unique build ID bitstring)"); + default: + break; + } + + snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); + return buff; +} + static const char * get_netbsd_elfcore_note_type (unsigned e_type) { @@ -8910,6 +9359,7 @@ get_netbsd_elfcore_note_type (unsigned e_type) static int process_note (Elf_Internal_Note *pnote) { + const char *name = pnote->namesz ? pnote->namedata : "(NONE)"; const char *nt; if (pnote->namesz == 0) @@ -8917,18 +9367,27 @@ process_note (Elf_Internal_Note *pnote) note type strings. */ nt = get_note_type (pnote->type); + else if (const_strneq (pnote->namedata, "GNU")) + /* GNU-specific object file notes. */ + nt = get_gnu_elf_note_type (pnote->type); + else if (const_strneq (pnote->namedata, "NetBSD-CORE")) /* NetBSD-specific core file notes. */ nt = get_netbsd_elfcore_note_type (pnote->type); + else if (strneq (pnote->namedata, "SPU/", 4)) + { + /* SPU-specific core file notes. */ + nt = pnote->namedata + 4; + name = "SPU"; + } + else /* Don't recognize this note name; just use the default set of note type strings. */ nt = get_note_type (pnote->type); - printf (" %s\t\t0x%08lx\t%s\n", - pnote->namesz ? pnote->namedata : "(NONE)", - pnote->descsz, nt); + printf (" %s\t\t0x%08lx\t%s\n", name, pnote->descsz, nt); return 1; } @@ -9088,6 +9547,9 @@ process_arch_specific (FILE *file) case EM_MIPS_RS3_LE: return process_mips_specific (file); break; + case EM_PPC: + return process_power_specific (file); + break; default: break; } @@ -9205,10 +9667,10 @@ process_object (char *file_name, FILE *file) } /* Initialise per file variables. */ - for (i = NUM_ELEM (version_info); i--;) + for (i = ARRAY_SIZE (version_info); i--;) version_info[i] = 0; - for (i = NUM_ELEM (dynamic_info); i--;) + for (i = ARRAY_SIZE (dynamic_info); i--;) dynamic_info[i] = 0; /* Process the file. */ @@ -9220,16 +9682,17 @@ process_object (char *file_name, FILE *file) must make sure that the dump_sets array is zeroed out before each object file is processed. */ if (num_dump_sects > num_cmdline_dump_sects) - memset (dump_sects, 0, num_dump_sects); + memset (dump_sects, 0, num_dump_sects * sizeof (* dump_sects)); if (num_cmdline_dump_sects > 0) { if (num_dump_sects == 0) /* A sneaky way of allocating the dump_sects array. */ - request_dump (num_cmdline_dump_sects, 0); + request_dump_bynumber (num_cmdline_dump_sects, 0); assert (num_dump_sects >= num_cmdline_dump_sects); - memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); + memcpy (dump_sects, cmdline_dump_sects, + num_cmdline_dump_sects * sizeof (* dump_sects)); } if (! process_file_header ()) @@ -9339,8 +9802,8 @@ process_object (char *file_name, FILE *file) return 0; } -/* Process an ELF archive. The file is positioned just after the - ARMAG string. */ +/* Process an ELF archive. + On entry the file is positioned just after the ARMAG string. */ static int process_archive (char *file_name, FILE *file) @@ -9348,6 +9811,10 @@ process_archive (char *file_name, FILE *file) 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; @@ -9365,27 +9832,124 @@ process_archive (char *file_name, FILE *file) return 1; } - if (const_strneq (arhdr.ar_name, "/ ")) + /* See if this is the archive symbol table. */ + if (const_strneq (arhdr.ar_name, "/ ") + || const_strneq (arhdr.ar_name, "/SYM64/ ")) { - /* 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) + size = size + (size & 1); + + if (do_archive_index) { - error (_("%s: failed to skip archive symbol table\n"), file_name); - return 1; + unsigned long i; + /* A buffer used to hold numbers read in from an archive index. + These are always 4 bytes long and stored in big-endian format. */ +#define SIZEOF_AR_INDEX_NUMBERS 4 + unsigned char integer_buffer[SIZEOF_AR_INDEX_NUMBERS]; + unsigned char * index_buffer; + + /* Check the size of the archive index. */ + if (size < SIZEOF_AR_INDEX_NUMBERS) + { + error (_("%s: the archive index is empty\n"), file_name); + return 1; + } + + /* Read the numer of entries in the archive index. */ + got = fread (integer_buffer, 1, sizeof integer_buffer, file); + if (got != sizeof (integer_buffer)) + { + error (_("%s: failed to read archive index\n"), file_name); + return 1; + } + 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) + { + 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); + return 1; + } + index_buffer = malloc (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) + { + free (index_buffer); + error (_("%s: failed to read archive index\n"), file_name); + ret = 1; + goto out; + } + size -= 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) + { + 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); + 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; + } + sym_table = malloc (size); + sym_size = size; + if (sym_table == NULL) + { + error (_("Out of memory whilst trying to read archive index symbol table\n")); + ret = 1; + goto out; + } + got = fread (sym_table, 1, size, file); + if (got != size) + { + error (_("%s: failed to read archive index symbol table\n"), file_name); + ret = 1; + goto out; + } + } + else + { + if (fseek (file, size, SEEK_CUR) != 0) + { + error (_("%s: failed to skip archive symbol table\n"), file_name); + return 1; + } } - got = fread (&arhdr, 1, sizeof arhdr, file); + got = fread (& arhdr, 1, sizeof arhdr, file); if (got != sizeof arhdr) { if (got == 0) - return 0; + { + ret = 0; + goto out; + } - error (_("%s: failed to read archive header\n"), file_name); - return 1; + error (_("%s: failed to read archive header following archive index\n"), file_name); + ret = 1; + goto out; } } + else if (do_archive_index) + printf (_("%s has no archive index\n"), file_name); if (const_strneq (arhdr.ar_name, "// ")) { @@ -9393,35 +9957,120 @@ process_archive (char *file_name, FILE *file) names. */ longnames_size = strtoul (arhdr.ar_size, NULL, 10); - longnames = malloc (longnames_size); if (longnames == NULL) { - error (_("Out of memory\n")); - return 1; + error (_("Out of memory reading long symbol names in archive\n")); + ret = 1; + goto out; } if (fread (longnames, longnames_size, 1, file) != 1) { free (longnames); - error (_("%s: failed to read string table\n"), file_name); - return 1; + error (_("%s: failed to read long symbol name string table\n"), file_name); + ret = 1; + goto out; } if ((longnames_size & 1) != 0) getc (file); - got = fread (&arhdr, 1, sizeof arhdr, file); + got = fread (& arhdr, 1, sizeof arhdr, file); if (got != sizeof arhdr) { - free (longnames); - if (got == 0) - return 0; + ret = 0; + else + { + error (_("%s: failed to read archive header following long symbol names\n"), file_name); + ret = 1; + } + goto out; + } + } - error (_("%s: failed to read archive header\n"), file_name); - return 1; + if (do_archive_index) + { + if (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 long current_pos; + + printf (_("Index of archive %s: (%ld entries, 0x%lx bytes in the symbol table)\n"), + file_name, index_num, sym_size); + current_pos = ftell (file); + + for (i = l = 0; i < 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 (l >= 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; + } + + if (l < 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; + } } + + if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections + && !do_segments && !do_header && !do_dump && !do_version + && !do_histogram && !do_debugging && !do_arch && !do_notes + && !do_section_groups) + return 0; /* Archive index only. */ } file_name_size = strlen (file_name); @@ -9505,7 +10154,12 @@ process_archive (char *file_name, FILE *file) } } - if (longnames != 0) + out: + if (index_array != NULL) + free (index_array); + if (sym_table != NULL) + free (sym_table); + if (longnames != NULL) free (longnames); return ret; @@ -9544,7 +10198,7 @@ process_file (char *file_name) if (fread (armag, SARMAG, 1, file) != 1) { - error (_("%s: Failed to read file header\n"), file_name); + error (_("%s: Failed to read file's magic number\n"), file_name); fclose (file); return 1; } @@ -9553,6 +10207,10 @@ process_file (char *file_name) ret = process_archive (file_name, file); else { + if (do_archive_index) + error (_("File %s is not an archive so its index cannot be displayed.\n"), + file_name); + rewind (file); archive_file_size = archive_file_offset = 0; ret = process_object (file_name, file); @@ -9603,12 +10261,13 @@ main (int argc, char **argv) if (num_dump_sects > 0) { /* Make a copy of the dump_sects array. */ - cmdline_dump_sects = malloc (num_dump_sects); + cmdline_dump_sects = malloc (num_dump_sects * sizeof (* dump_sects)); if (cmdline_dump_sects == NULL) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); else { - memcpy (cmdline_dump_sects, dump_sects, num_dump_sects); + memcpy (cmdline_dump_sects, dump_sects, + num_dump_sects * sizeof (* dump_sects)); num_cmdline_dump_sects = num_dump_sects; } }