]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - binutils/readelf.c
binutils/
[thirdparty/binutils-gdb.git] / binutils / readelf.c
index 9305d04ffac3ce06114df17cd1c6a29cf32319ce..55ab8423b13e4762542ea5ddff8b1ee5e935cefd 100644 (file)
@@ -1,6 +1,6 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+   2008  Free Software Foundation, Inc.
 
    Originally developed by Eric Youngdale <eric@andante.jic.com>
    Modifications by Nick Clifton <nickc@redhat.com>
 #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"
 
 #include "getopt.h"
 #include "libiberty.h"
+#include "safe-ctype.h"
 
 char *program_name = "readelf";
 static long archive_file_offset;
@@ -200,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
@@ -218,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
@@ -289,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))
@@ -301,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)
 \f
 static void *
@@ -379,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)
 {
@@ -487,6 +492,12 @@ 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
+#ifndef __MSVCRT__
+         return nc + printf ("%llx", vma);
+#else
+         return nc + printf ("%I64x", vma);
+#endif
 #else
          return nc + print_hex_vma (vma);
 #endif
@@ -494,6 +505,12 @@ 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
+#ifndef __MSVCRT__
+         return printf ("%lld", vma);
+#else
+         return printf ("%I64d", vma);
+#endif
 #else
          return print_dec_vma (vma, 1);
 #endif
@@ -504,6 +521,18 @@ print_vma (bfd_vma vma, print_mode mode)
            return printf ("%5ld", vma);
          else
            return printf ("%#lx", vma);
+#elif BFD_HOST_64BIT_LONG_LONG
+#ifndef __MSVCRT__
+         if (vma <= 99999)
+           return printf ("%5lld", vma);
+         else
+           return printf ("%#llx", vma);
+#else
+         if (vma <= 99999)
+           return printf ("%5I64d", vma);
+         else
+           return printf ("%#I64x", vma);
+#endif
 #else
          if (vma <= 99999)
            return printf ("%5ld", _bfd_int64_low (vma));
@@ -514,6 +543,12 @@ 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
+#ifndef __MSVCRT__
+         return printf ("%llu", vma);
+#else
+         return printf ("%I64u", vma);
+#endif
 #else
          return print_dec_vma (vma, 0);
 #endif
@@ -589,7 +624,7 @@ find_section (const char *name)
 /* Guess the relocation size commonly used by the specific machines.  */
 
 static int
-guess_is_rela (unsigned long e_machine)
+guess_is_rela (unsigned int e_machine)
 {
   switch (e_machine)
     {
@@ -617,6 +652,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:
@@ -829,10 +865,40 @@ slurp_rel_relocs (FILE *file,
   return 1;
 }
 
+/* Returns the reloc type extracted from the reloc info field.  */
+
+static unsigned int
+get_reloc_type (bfd_vma reloc_info)
+{
+  if (is_32bit_elf)
+    return ELF32_R_TYPE (reloc_info);
+
+  switch (elf_header.e_machine)
+    {
+    case EM_MIPS:
+      /* Note: We assume that reloc_info has already been adjusted for us.  */
+      return ELF64_MIPS_R_TYPE (reloc_info);
+
+    case EM_SPARCV9:
+      return ELF64_R_TYPE_ID (reloc_info);
+
+    default:
+      return ELF64_R_TYPE (reloc_info);
+    }
+}
+
+/* Return the symbol index extracted from the reloc info field.  */
+
+static bfd_vma
+get_reloc_symindex (bfd_vma reloc_info)
+{
+  return is_32bit_elf ? ELF32_R_SYM (reloc_info) : ELF64_R_SYM (reloc_info);
+}
+
 /* Display the contents of the relocation data found at the specified
    offset.  */
 
-static int
+static void
 dump_relocations (FILE *file,
                  unsigned long rel_offset,
                  unsigned long rel_size,
@@ -852,12 +918,12 @@ dump_relocations (FILE *file,
   if (is_rela)
     {
       if (!slurp_rela_relocs (file, rel_offset, rel_size, &rels, &rel_size))
-       return 0;
+       return;
     }
   else
     {
       if (!slurp_rel_relocs (file, rel_offset, rel_size, &rels, &rel_size))
-       return 0;
+       return;
     }
 
   if (is_32bit_elf)
@@ -898,65 +964,63 @@ dump_relocations (FILE *file,
   for (i = 0; i < rel_size; i++)
     {
       const char *rtype;
-      const char *rtype2 = NULL;
-      const char *rtype3 = NULL;
       bfd_vma offset;
       bfd_vma info;
       bfd_vma symtab_index;
       bfd_vma type;
-      bfd_vma type2 = 0;
-      bfd_vma type3 = 0;
 
       offset = rels[i].r_offset;
       info   = rels[i].r_info;
 
-      if (is_32bit_elf)
+      /* The #ifdef BFD64 below is to prevent a compile time warning.
+        We know that if we do not have a 64 bit data type that we
+        will never execute this code anyway.  */
+#ifdef BFD64
+      if (!is_32bit_elf
+         && elf_header.e_machine == EM_MIPS
+         && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
        {
-         type         = ELF32_R_TYPE (info);
-         symtab_index = ELF32_R_SYM  (info);
+         /* In little-endian objects, r_info isn't really a 64-bit
+            little-endian value: it has a 32-bit little-endian
+            symbol index followed by four individual byte fields.
+            Reorder INFO accordingly.  */
+         info = (((info & 0xffffffff) << 32)
+                 | ((info >> 56) & 0xff)
+                 | ((info >> 40) & 0xff00)
+                 | ((info >> 24) & 0xff0000)
+                 | ((info >> 8) & 0xff000000));
        }
-      else
-       {
-         /* The #ifdef BFD64 below is to prevent a compile time warning.
-            We know that if we do not have a 64 bit data type that we
-            will never execute this code anyway.  */
-#ifdef BFD64
-         if (elf_header.e_machine == EM_MIPS)
-           {
-             /* In little-endian objects, r_info isn't really a 64-bit
-                little-endian value: it has a 32-bit little-endian
-                symbol index followed by four individual byte fields.
-                Reorder INFO accordingly.  */
-             if (elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
-               info = (((info & 0xffffffff) << 32)
-                       | ((info >> 56) & 0xff)
-                       | ((info >> 40) & 0xff00)
-                       | ((info >> 24) & 0xff0000)
-                       | ((info >> 8) & 0xff000000));
-             type  = ELF64_MIPS_R_TYPE (info);
-             type2 = ELF64_MIPS_R_TYPE2 (info);
-             type3 = ELF64_MIPS_R_TYPE3 (info);
-           }
-         else if (elf_header.e_machine == EM_SPARCV9)
-           type = ELF64_R_TYPE_ID (info);
-         else
-           type = ELF64_R_TYPE (info);
+#endif /* BFD64 */
 
-         symtab_index = ELF64_R_SYM  (info);
-#endif
-       }
+      type = get_reloc_type (info);
+      symtab_index = get_reloc_symindex  (info);
 
       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
+#ifndef __MSVCRT__
+         printf (do_wide
+                 ? "%16.16llx  %16.16llx "
+                 : "%12.12llx  %12.12llx ",
+                 offset, info);
+#else
+         printf (do_wide
+                 ? "%16.16I64x  %16.16I64x "
+                 : "%12.12I64x  %12.12I64x ",
+                 offset, info);
+#endif
+#else
          printf (do_wide
                  ? "%8.8lx%8.8lx  %8.8lx%8.8lx "
                  : "%4.4lx%8.8lx  %4.4lx%8.8lx ",
@@ -964,11 +1028,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
        }
 
@@ -1083,11 +1142,6 @@ dump_relocations (FILE *file,
        case EM_MIPS:
        case EM_MIPS_RS3_LE:
          rtype = elf_mips_reloc_type (type);
-         if (!is_32bit_elf)
-           {
-             rtype2 = elf_mips_reloc_type (type2);
-             rtype3 = elf_mips_reloc_type (type3);
-           }
          break;
 
        case EM_ALPHA:
@@ -1191,14 +1245,14 @@ dump_relocations (FILE *file,
        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);
 
@@ -1309,37 +1363,36 @@ dump_relocations (FILE *file,
 
       putchar ('\n');
 
+#ifdef BFD64
       if (! is_32bit_elf && elf_header.e_machine == EM_MIPS)
        {
+         bfd_vma type2 = ELF64_MIPS_R_TYPE2 (info);
+         bfd_vma type3 = ELF64_MIPS_R_TYPE3 (info);
+         const char *rtype2 = elf_mips_reloc_type (type2);
+         const char *rtype3 = elf_mips_reloc_type (type3);
+
          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);
 
          putchar ('\n');
        }
+#endif /* BFD64 */
     }
 
   free (rels);
-
-  return 1;
 }
 
 static const char *
@@ -1787,6 +1840,7 @@ get_machine_name (unsigned e_machine)
     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), _("<unknown>: 0x%x"), e_machine);
       return buff;
@@ -2166,6 +2220,8 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            case E_MIPS_MACH_5500: strcat (buf, ", 5500"); break;
            case E_MIPS_MACH_SB1:  strcat (buf, ", sb1");  break;
            case E_MIPS_MACH_9000: strcat (buf, ", 9000"); break;
+           case E_MIPS_MACH_LS2E: strcat (buf, ", loongson-2e"); break;
+           case E_MIPS_MACH_LS2F: strcat (buf, ", loongson-2f"); break;
            case 0:
            /* We simply ignore the field in this case to avoid confusion:
               MIPS ELF does not specify EF_MIPS_MACH, it is a GNU
@@ -2740,9 +2796,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
@@ -2776,15 +2834,19 @@ usage (FILE *stream)
   -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=<number> Dump the contents of section <number>\n\
+  -x --hex-dump=<number|name>\n\
+                         Dump the contents of section <number|name> as bytes\n\
+  -p --string-dump=<number|name>\n\
+                         Dump the contents of section <number|name> 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 (stream, _("\
-  -i --instruction-dump=<number>\n\
-                         Disassemble the contents of section <number>\n"));
+  -i --instruction-dump=<number|name>\n\
+                         Disassemble the contents of section <number|name>\n"));
 #endif
   fprintf (stream, _("\
   -I --histogram         Display histogram of bucket list lengths\n\
@@ -2792,7 +2854,7 @@ usage (FILE *stream)
   @<file>                Read options from <file>\n\
   -H --help              Display this information\n\
   -v --version           Display the version number of readelf\n"));
-  
+
   if (REPORT_BUGS_TO[0] && stream == stdout)
     fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO);
 
@@ -2805,20 +2867,20 @@ usage (FILE *stream)
    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.\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);
 
@@ -2836,7 +2898,7 @@ 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;
 
@@ -2863,7 +2925,7 @@ parse_args (int argc, char **argv)
     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;
@@ -2937,14 +2999,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)
@@ -2959,22 +3032,18 @@ parse_args (int argc, char **argv)
                switch (optarg[index++])
                  {
                  case 'i':
-                 case 'I':
                    do_debug_info = 1;
                    break;
 
                  case 'a':
-                 case 'A':
                    do_debug_abbrevs = 1;
                    break;
 
                  case 'l':
-                 case 'L':
                    do_debug_lines = 1;
                    break;
 
                  case 'p':
-                 case 'P':
                    do_debug_pubnames = 1;
                    break;
 
@@ -2993,17 +3062,14 @@ parse_args (int argc, char **argv)
                    break;
 
                  case 'm':
-                 case 'M':
                    do_debug_macinfo = 1;
                    break;
 
                  case 's':
-                 case 'S':
                    do_debug_str = 1;
                    break;
 
                  case 'o':
-                 case 'O':
                    do_debug_loc = 1;
                    break;
 
@@ -3092,11 +3158,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);
@@ -3108,9 +3172,6 @@ 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.  */
@@ -3122,7 +3183,7 @@ parse_args (int argc, char **argv)
   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)
+      && !do_section_groups && !do_archive_index)
     usage (stderr);
   else if (argc < 3)
     {
@@ -3178,6 +3239,8 @@ process_file_header (void)
       return 0;
     }
 
+  init_dwarf_regnames (elf_header.e_machine);
+
   if (do_header)
     {
       int i;
@@ -3503,6 +3566,11 @@ process_program_headers (FILE *file)
          if (dynamic_addr)
            error (_("more than one dynamic segment\n"));
 
+         /* By default, assume that the .dynamic section is the first
+            section in the DYNAMIC segment.  */
+         dynamic_addr = segment->p_offset;
+         dynamic_size = segment->p_filesz;
+
          /* Try to locate the .dynamic section. If there is
             a section header table, we can easily locate it.  */
          if (section_headers != NULL)
@@ -3517,23 +3585,21 @@ process_program_headers (FILE *file)
                }
 
              if (sec->sh_type == SHT_NOBITS)
-               break;
+               {
+                 dynamic_size = 0;
+                 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\n"));
+               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.\n"));
-           }
-         else
-           {
-             /* Otherwise, we can only assume that the .dynamic
-                section is the first section in the DYNAMIC segment.  */
-             dynamic_addr = segment->p_offset;
-             dynamic_size = segment->p_filesz;
+               warn (_("the .dynamic section is not the first section"
+                       " in the dynamic segment.\n"));
            }
          break;
 
@@ -4091,6 +4157,16 @@ process_section_headers (FILE *file)
          eh_addr_size = 4;
          break;
        }
+      break;
+
+    case EM_M32C:
+      switch (elf_header.e_flags & EF_M32C_CPU_MASK)
+       {
+       case EF_M32C_CPU_M16C:
+         eh_addr_size = 2;
+         break;
+       }
+      break;
     }
 
 #define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \
@@ -4177,14 +4253,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)
@@ -4989,8 +5065,7 @@ slurp_ia64_unwind_table (FILE *file,
     }
   free (table);
 
-  /* Third, apply any relocations to the unwind table: */
-
+  /* Third, apply any relocations to the unwind table:  */
   for (relsec = section_headers;
        relsec < section_headers + elf_header.e_shnum;
        ++relsec)
@@ -5006,16 +5081,8 @@ slurp_ia64_unwind_table (FILE *file,
 
       for (rp = rela; rp < rela + nrelas; ++rp)
        {
-         if (is_32bit_elf)
-           {
-             relname = elf_ia64_reloc_type (ELF32_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF32_R_SYM (rp->r_info);
-           }
-         else
-           {
-             relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF64_R_SYM (rp->r_info);
-           }
+         relname = elf_ia64_reloc_type (get_reloc_type (rp->r_info));
+         sym = aux->symtab + get_reloc_symindex (rp->r_info);
 
          if (! const_strneq (relname, "R_IA64_SEGREL"))
            {
@@ -5402,7 +5469,6 @@ slurp_hppa_unwind_table (FILE *file,
   free (table);
 
   /* Third, apply any relocations to the unwind table.  */
-
   for (relsec = section_headers;
        relsec < section_headers + elf_header.e_shnum;
        ++relsec)
@@ -5418,16 +5484,8 @@ slurp_hppa_unwind_table (FILE *file,
 
       for (rp = rela; rp < rela + nrelas; ++rp)
        {
-         if (is_32bit_elf)
-           {
-             relname = elf_hppa_reloc_type (ELF32_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF32_R_SYM (rp->r_info);
-           }
-         else
-           {
-             relname = elf_hppa_reloc_type (ELF64_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF64_R_SYM (rp->r_info);
-           }
+         relname = elf_hppa_reloc_type (get_reloc_type (rp->r_info));
+         sym = aux->symtab + get_reloc_symindex (rp->r_info);
 
          /* R_PARISC_SEGREL32 or R_PARISC_SEGREL64.  */
          if (! const_strneq (relname, "R_PARISC_SEGREL"))
@@ -5568,7 +5626,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]);
@@ -5657,7 +5715,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)
@@ -6437,6 +6495,7 @@ process_version_sections (FILE *file)
            Elf_External_Verdef *edefs;
            unsigned int idx;
            unsigned int cnt;
+           char *endbuf;
 
            found = 1;
 
@@ -6456,6 +6515,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;
 
@@ -6470,6 +6530,8 @@ process_version_sections (FILE *file)
                int isum;
 
                vstart = ((char *) edefs) + idx;
+               if (vstart + sizeof (*edef) > endbuf)
+                 break;
 
                edef = (Elf_External_Verdef *) vstart;
 
@@ -6507,6 +6569,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);
@@ -6518,9 +6582,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);
          }
@@ -6531,6 +6599,7 @@ process_version_sections (FILE *file)
            Elf_External_Verneed *eneed;
            unsigned int idx;
            unsigned int cnt;
+           char *endbuf;
 
            found = 1;
 
@@ -6549,6 +6618,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;
 
@@ -6561,6 +6631,8 @@ process_version_sections (FILE *file)
                char *vstart;
 
                vstart = ((char *) eneed) + idx;
+               if (vstart + sizeof (*entry) > endbuf)
+                 break;
 
                entry = (Elf_External_Verneed *) vstart;
 
@@ -6586,6 +6658,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);
@@ -6607,9 +6681,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);
          }
@@ -6754,7 +6832,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),
@@ -6806,7 +6887,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),
@@ -7031,6 +7115,39 @@ get_dynamic_data (FILE *file, unsigned int number, unsigned int ent_size)
   return i_data;
 }
 
+static void
+print_dynamic_symbol (bfd_vma si, unsigned long hn)
+{
+  Elf_Internal_Sym *psym;
+  int n;
+
+  psym = dynamic_symbols + si;
+
+  n = print_vma (si, DEC_5);
+  if (n < 5)
+    fputs ("     " + n, stdout);
+  printf (" %3lu: ", hn);
+  print_vma (psym->st_value, LONG_HEX);
+  putchar (' ');
+  print_vma (psym->st_size, DEC_5);
+
+  printf ("  %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
+  printf (" %6s",  get_symbol_binding (ELF_ST_BIND (psym->st_info)));
+  printf (" %3s",  get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
+  /* Check to see if any other bits in the st_other field are set.
+     Note - displaying this information disrupts the layout of the
+     table being generated, but for the moment this case is very
+     rare.  */
+  if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
+    printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
+  printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
+  if (VALID_DYNAMIC_NAME (psym->st_name))
+    print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
+  else
+    printf (" <corrupt: %14ld>", psym->st_name);
+  putchar ('\n');
+}
+
 /* Dump the symbol table.  */
 static int
 process_symbol_table (FILE *file)
@@ -7043,12 +7160,14 @@ process_symbol_table (FILE *file)
   bfd_vma ngnubuckets = 0;
   bfd_vma *gnubuckets = NULL;
   bfd_vma *gnuchains = NULL;
+  bfd_vma gnusymidx = 0;
 
   if (! do_syms && !do_histogram)
     return 1;
 
-  if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL)
-                               || do_histogram))
+  if (dynamic_info[DT_HASH]
+      && (do_histogram
+         || (do_using_dynamic && dynamic_strings != NULL)))
     {
       unsigned char nb[8];
       unsigned char nc[8];
@@ -7092,76 +7211,179 @@ process_symbol_table (FILE *file)
        return 0;
     }
 
-  if (do_syms
-      && dynamic_info[DT_HASH] && do_using_dynamic && dynamic_strings != NULL)
+  if (dynamic_info_DT_GNU_HASH
+      && (do_histogram
+         || (do_using_dynamic && dynamic_strings != NULL)))
     {
-      unsigned long hn;
-      bfd_vma si;
+      unsigned char nb[16];
+      bfd_vma i, maxchain = 0xffffffff, bitmaskwords;
+      bfd_vma buckets_vma;
+
+      if (fseek (file,
+                (archive_file_offset
+                 + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
+                                    sizeof nb)),
+                SEEK_SET))
+       {
+         error (_("Unable to seek to start of dynamic information\n"));
+         return 0;
+       }
+
+      if (fread (nb, 16, 1, file) != 1)
+       {
+         error (_("Failed to read in number of buckets\n"));
+         return 0;
+       }
 
-      printf (_("\nSymbol table for image:\n"));
+      ngnubuckets = byte_get (nb, 4);
+      gnusymidx = byte_get (nb + 4, 4);
+      bitmaskwords = byte_get (nb + 8, 4);
+      buckets_vma = dynamic_info_DT_GNU_HASH + 16;
       if (is_32bit_elf)
-       printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
+       buckets_vma += bitmaskwords * 4;
       else
-       printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
+       buckets_vma += bitmaskwords * 8;
 
-      for (hn = 0; hn < nbuckets; hn++)
+      if (fseek (file,
+                (archive_file_offset
+                 + offset_from_vma (file, buckets_vma, 4)),
+                SEEK_SET))
        {
-         if (! buckets[hn])
-           continue;
+         error (_("Unable to seek to start of dynamic information\n"));
+         return 0;
+       }
 
-         for (si = buckets[hn]; si < nchains && si > 0; si = chains[si])
-           {
-             Elf_Internal_Sym *psym;
-             int n;
+      gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
 
-             psym = dynamic_symbols + si;
+      if (gnubuckets == NULL)
+       return 0;
 
-             n = print_vma (si, DEC_5);
-             if (n < 5)
-               fputs ("     " + n, stdout);
-             printf (" %3lu: ", hn);
-             print_vma (psym->st_value, LONG_HEX);
-             putchar (' ');
-             print_vma (psym->st_size, DEC_5);
+      for (i = 0; i < ngnubuckets; i++)
+       if (gnubuckets[i] != 0)
+         {
+           if (gnubuckets[i] < gnusymidx)
+             return 0;
 
-             printf ("  %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
-             printf (" %6s",  get_symbol_binding (ELF_ST_BIND (psym->st_info)));
-             printf (" %3s",  get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
-             /* Check to see if any other bits in the st_other field are set.
-                Note - displaying this information disrupts the layout of the
-                table being generated, but for the moment this case is very rare.  */
-             if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
-               printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
-             printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
-             if (VALID_DYNAMIC_NAME (psym->st_name))
-               print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
-             else
-               printf (" <corrupt: %14ld>", psym->st_name);
-             putchar ('\n');
+           if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
+             maxchain = gnubuckets[i];
+         }
+
+      if (maxchain == 0xffffffff)
+       return 0;
+
+      maxchain -= gnusymidx;
+
+      if (fseek (file,
+                (archive_file_offset
+                 + offset_from_vma (file, buckets_vma
+                                          + 4 * (ngnubuckets + maxchain), 4)),
+                SEEK_SET))
+       {
+         error (_("Unable to seek to start of dynamic information\n"));
+         return 0;
+       }
+
+      do
+       {
+         if (fread (nb, 4, 1, file) != 1)
+           {
+             error (_("Failed to determine last chain length\n"));
+             return 0;
            }
+
+         if (maxchain + 1 == 0)
+           return 0;
+
+         ++maxchain;
+       }
+      while ((byte_get (nb, 4) & 1) == 0);
+
+      if (fseek (file,
+                (archive_file_offset
+                 + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
+                SEEK_SET))
+       {
+         error (_("Unable to seek to start of dynamic information\n"));
+         return 0;
        }
+
+      gnuchains = get_dynamic_data (file, maxchain, 4);
+
+      if (gnuchains == NULL)
+       return 0;
     }
-  else if (do_syms && !do_using_dynamic)
+
+  if ((dynamic_info[DT_HASH] || dynamic_info_DT_GNU_HASH)
+      && do_syms
+      && do_using_dynamic
+      && dynamic_strings != NULL)
     {
-      unsigned int i;
+      unsigned long hn;
 
-      for (i = 0, section = section_headers;
-          i < elf_header.e_shnum;
-          i++, section++)
+      if (dynamic_info[DT_HASH])
        {
-         unsigned int si;
-         char *strtab = NULL;
-         unsigned long int strtab_size = 0;
-         Elf_Internal_Sym *symtab;
-         Elf_Internal_Sym *psym;
+         bfd_vma si;
 
+         printf (_("\nSymbol table for image:\n"));
+         if (is_32bit_elf)
+           printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
+         else
+           printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
 
-         if (   section->sh_type != SHT_SYMTAB
-             && section->sh_type != SHT_DYNSYM)
-           continue;
+         for (hn = 0; hn < nbuckets; hn++)
+           {
+             if (! buckets[hn])
+               continue;
 
-         printf (_("\nSymbol table '%s' contains %lu entries:\n"),
-                 SECTION_NAME (section),
+             for (si = buckets[hn]; si < nchains && si > 0; si = chains[si])
+               print_dynamic_symbol (si, hn);
+           }
+       }
+
+      if (dynamic_info_DT_GNU_HASH)
+       {
+         printf (_("\nSymbol table of `.gnu.hash' for image:\n"));
+         if (is_32bit_elf)
+           printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
+         else
+           printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
+
+         for (hn = 0; hn < ngnubuckets; ++hn)
+           if (gnubuckets[hn] != 0)
+             {
+               bfd_vma si = gnubuckets[hn];
+               bfd_vma off = si - gnusymidx;
+
+               do
+                 {
+                   print_dynamic_symbol (si, hn);
+                   si++;
+                 }
+               while ((gnuchains[off++] & 1) == 0);
+             }
+       }
+    }
+  else if (do_syms && !do_using_dynamic)
+    {
+      unsigned int i;
+
+      for (i = 0, section = section_headers;
+          i < elf_header.e_shnum;
+          i++, section++)
+       {
+         unsigned int si;
+         char *strtab = NULL;
+         unsigned long int strtab_size = 0;
+         Elf_Internal_Sym *symtab;
+         Elf_Internal_Sym *psym;
+
+
+         if (   section->sh_type != SHT_SYMTAB
+             && section->sh_type != SHT_DYNSYM)
+           continue;
+
+         printf (_("\nSymbol table '%s' contains %lu entries:\n"),
+                 SECTION_NAME (section),
                  (unsigned long) (section->sh_size / section->sh_entsize));
          if (is_32bit_elf)
            printf (_("   Num:    Value  Size Type    Bind   Vis      Ndx Name\n"));
@@ -7424,108 +7646,12 @@ process_symbol_table (FILE *file)
 
   if (do_histogram && dynamic_info_DT_GNU_HASH)
     {
-      unsigned char nb[16];
-      bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords;
       unsigned long *lengths;
       unsigned long *counts;
       unsigned long hn;
       unsigned long maxlength = 0;
       unsigned long nzero_counts = 0;
       unsigned long nsyms = 0;
-      bfd_vma buckets_vma;
-
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
-                                    sizeof nb)),
-                SEEK_SET))
-       {
-         error (_("Unable to seek to start of dynamic information\n"));
-         return 0;
-       }
-
-      if (fread (nb, 16, 1, file) != 1)
-       {
-         error (_("Failed to read in number of buckets\n"));
-         return 0;
-       }
-
-      ngnubuckets = byte_get (nb, 4);
-      symidx = byte_get (nb + 4, 4);
-      bitmaskwords = byte_get (nb + 8, 4);
-      buckets_vma = dynamic_info_DT_GNU_HASH + 16;
-      if (is_32bit_elf)
-       buckets_vma += bitmaskwords * 4;
-      else
-       buckets_vma += bitmaskwords * 8;
-
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, buckets_vma, 4)),
-                SEEK_SET))
-       {
-         error (_("Unable to seek to start of dynamic information\n"));
-         return 0;
-       }
-
-      gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
-
-      if (gnubuckets == NULL)
-       return 0;
-
-      for (i = 0; i < ngnubuckets; i++)
-       if (gnubuckets[i] != 0)
-         {
-           if (gnubuckets[i] < symidx)
-             return 0;
-
-           if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
-             maxchain = gnubuckets[i];
-         }
-
-      if (maxchain == 0xffffffff)
-       return 0;
-
-      maxchain -= symidx;
-
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, buckets_vma
-                                          + 4 * (ngnubuckets + maxchain), 4)),
-                SEEK_SET))
-       {
-         error (_("Unable to seek to start of dynamic information\n"));
-         return 0;
-       }
-
-      do
-       {
-         if (fread (nb, 4, 1, file) != 1)
-           {
-             error (_("Failed to determine last chain length\n"));
-             return 0;
-           }
-
-         if (maxchain + 1 == 0)
-           return 0;
-
-         ++maxchain;
-       }
-      while ((byte_get (nb, 4) & 1) == 0);
-
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
-                SEEK_SET))
-       {
-         error (_("Unable to seek to start of dynamic information\n"));
-         return 0;
-       }
-
-      gnuchains = get_dynamic_data (file, maxchain, 4);
-
-      if (gnuchains == NULL)
-       return 0;
 
       lengths = calloc (ngnubuckets, sizeof (*lengths));
       if (lengths == NULL)
@@ -7543,7 +7669,7 @@ process_symbol_table (FILE *file)
          {
            bfd_vma off, length = 1;
 
-           for (off = gnubuckets[hn] - symidx;
+           for (off = gnubuckets[hn] - gnusymidx;
                 (gnuchains[off] & 1) == 0; ++off)
              ++length;
            lengths[hn] = length;
@@ -7665,7 +7791,88 @@ 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)
+       {
+#ifndef __MSVCRT__
+         printf ("  [%6tx]  %s\n", data - start, data);
+#else
+         printf ("  [%6Ix]  %s\n", (size_t) (data - start), data);
+#endif
+         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;
@@ -7710,7 +7917,7 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
       printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n"));
       break;
     }
-  
+
   data = start;
 
   while (bytes)
@@ -7756,95 +7963,344 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
   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.  */
+/* Returns TRUE iff RELOC_TYPE is a 32-bit absolute RELA relocation used in
+   DWARF debug sections.  This is a target specific test.  Note - we do not
+   go through the whole including-target-headers-multiple-times route, (as
+   we have already done with <elf/h8.h>) because this would become very
+   messy and even then this function would have to contain target specific
+   information (the names of the relocs instead of their numeric values).
+   FIXME: This is not the correct way to solve this problem.  The proper way
+   is to have target specific reloc sizing and typing 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)
+static bfd_boolean
+is_32bit_abs_reloc (unsigned int reloc_type)
 {
   switch (elf_header.e_machine)
     {
+    case EM_386:
+    case EM_486:
+      return reloc_type == 1; /* R_386_32.  */
+    case EM_68K:
+      return reloc_type == 1; /* R_68K_32.  */
+    case EM_860:
+      return reloc_type == 1; /* R_860_32.  */
+    case EM_ALPHA:
+      return reloc_type == 1; /* XXX Is this right ?  */
+    case EM_ARC:
+      return reloc_type == 1; /* R_ARC_32.  */
+    case EM_ARM:
+      return reloc_type == 2; /* R_ARM_ABS32 */
+    case EM_AVR_OLD: 
+    case EM_AVR:
+      return reloc_type == 1;
+    case EM_BLACKFIN:
+      return reloc_type == 0x12; /* R_byte4_data.  */
+    case EM_CRIS:
+      return reloc_type == 3; /* R_CRIS_32.  */
+    case EM_CR16:
+      return reloc_type == 3; /* R_CR16_NUM32.  */
+    case EM_CRX:
+      return reloc_type == 15; /* R_CRX_NUM32.  */
+    case EM_CYGNUS_FRV:
+      return reloc_type == 1;
+    case EM_CYGNUS_D10V:
+    case EM_D10V:
+      return reloc_type == 6; /* R_D10V_32.  */
+    case EM_CYGNUS_D30V:
+    case EM_D30V:
+      return reloc_type == 12; /* R_D30V_32_NORMAL.  */
+    case EM_DLX:
+      return reloc_type == 3; /* R_DLX_RELOC_32.  */
+    case EM_CYGNUS_FR30:
+    case EM_FR30:
+      return reloc_type == 3; /* R_FR30_32.  */
     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;
-       }
+      return reloc_type == 1; /* R_H8_DIR32.  */
+    case EM_IA_64:
+      return reloc_type == 0x65; /* R_IA64_SECREL32LSB.  */
+    case EM_IP2K_OLD:
+    case EM_IP2K:
+      return reloc_type == 2; /* R_IP2K_32.  */
+    case EM_IQ2000:
+      return reloc_type == 2; /* R_IQ2000_32.  */
+    case EM_M32C:
+      return reloc_type == 3; /* R_M32C_32.  */
+    case EM_M32R:
+      return reloc_type == 34; /* R_M32R_32_RELA.  */
+    case EM_MCORE:
+      return reloc_type == 1; /* R_MCORE_ADDR32.  */
+    case EM_CYGNUS_MEP:
+      return reloc_type == 4; /* R_MEP_32.  */
+    case EM_MIPS:
+      return reloc_type == 2; /* R_MIPS_32.  */
+    case EM_MMIX:
+      return reloc_type == 4; /* R_MMIX_32.  */
+    case EM_CYGNUS_MN10200:
+    case EM_MN10200:
+      return reloc_type == 1; /* R_MN10200_32.  */
+    case EM_CYGNUS_MN10300:
+    case EM_MN10300:
+      return reloc_type == 1; /* R_MN10300_32.  */
+    case EM_MSP430_OLD:
+    case EM_MSP430:
+      return reloc_type == 1; /* R_MSP43_32.  */
+    case EM_MT:
+      return reloc_type == 2; /* R_MT_32.  */
+    case EM_ALTERA_NIOS2:
+    case EM_NIOS32:
+      return reloc_type == 1; /* R_NIOS_32.  */
+    case EM_OPENRISC:
+    case EM_OR32:
+      return reloc_type == 1; /* R_OR32_32.  */
+    case EM_PARISC:
+      return reloc_type == 1; /* R_PARISC_DIR32.  */
+    case EM_PJ:
+    case EM_PJ_OLD:
+      return reloc_type == 1; /* R_PJ_DATA_DIR32.  */
+    case EM_PPC64:
+      return reloc_type == 1; /* R_PPC64_ADDR32.  */
+    case EM_PPC:
+      return reloc_type == 1; /* R_PPC_ADDR32.  */
+    case EM_S370:
+      return reloc_type == 1; /* R_I370_ADDR31.  */
+    case EM_S390_OLD:
+    case EM_S390:
+      return reloc_type == 4; /* R_S390_32.  */
+    case EM_SCORE:
+      return reloc_type == 8; /* R_SCORE_ABS32.  */
+    case EM_SH:
+      return reloc_type == 1; /* R_SH_DIR32.  */
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+    case EM_SPARC:
+      return reloc_type == 3 /* R_SPARC_32.  */
+       || reloc_type == 23; /* R_SPARC_UA32.  */
+    case EM_SPU:
+      return reloc_type == 6; /* R_SPU_ADDR32 */
+    case EM_CYGNUS_V850:
+    case EM_V850:
+      return reloc_type == 6; /* R_V850_ABS32.  */
+    case EM_VAX:
+      return reloc_type == 1; /* R_VAX_32.  */
+    case EM_X86_64:
+      return reloc_type == 10; /* R_X86_64_32.  */
+    case EM_XSTORMY16:
+      return reloc_type == 1; /* R_XSTROMY16_32.  */
+    case EM_XTENSA_OLD:
+    case EM_XTENSA:
+      return reloc_type == 1; /* R_XTENSA_32.  */
+
+    default:
+      error (_("Missing knowledge of 32-bit reloc types used in DWARF sections of machine number %d\n"),
+            elf_header.e_machine);
+      abort ();
+    }
+}
+
+/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
+   a 32-bit pc-relative RELA relocation used in DWARF debug sections.  */
+
+static bfd_boolean
+is_32bit_pcrel_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_386:
+    case EM_486:
+      return reloc_type == 2;  /* R_386_PC32.  */
+    case EM_68K:
+      return reloc_type == 4;  /* R_68K_PC32.  */
+    case EM_ALPHA:
+      return reloc_type == 10; /* R_ALPHA_SREL32.  */
+    case EM_ARM:
+      return reloc_type == 3;  /* R_ARM_REL32 */
+    case EM_PARISC:
+      return reloc_type == 0;  /* R_PARISC_NONE.  *//* FIXME: This reloc is generated, but it may be a bug.  */
+    case EM_PPC:
+      return reloc_type == 26; /* R_PPC_REL32.  */
+    case EM_PPC64:
+      return reloc_type == 26; /* R_PPC64_REL32.  */
+    case EM_S390_OLD:
+    case EM_S390:
+      return reloc_type == 5;  /* R_390_PC32.  */
+    case EM_SH:
+      return reloc_type == 2;  /* R_SH_REL32.  */
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+    case EM_SPARC:
+      return reloc_type == 6;  /* R_SPARC_DISP32.  */
+    case EM_SPU:
+      return reloc_type == 13; /* R_SPU_REL32.  */
+    case EM_X86_64:
+      return reloc_type == 2;  /* R_X86_64_PC32.  */
+    case EM_XTENSA_OLD:
+    case EM_XTENSA:
+      return reloc_type == 14; /* R_XTENSA_32_PCREL.  */
     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 <elf/h8.h> for an example of the hoops that we need
-        to jump through in order to obtain the reloc numbers.  */
-      return 4;
+      /* Do not abort or issue an error message here.  Not all targets use
+        pc-relative 32-bit relocs in their DWARF debug information and we
+        have already tested for target coverage in is_32bit_abs_reloc.  A
+        more helpful warning message will be generated by
+        debug_apply_relocations anyway, so just return.  */
+      return FALSE;
     }
 }
 
-/* Apply addends of RELA relocations.  */
+/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
+   a 64-bit absolute RELA relocation used in DWARF debug sections.  */
 
-static int
-debug_apply_rela_addends (void *file,
-                         Elf_Internal_Shdr *section,
-                         unsigned char *start)
+static bfd_boolean
+is_64bit_abs_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_ALPHA:
+      return reloc_type == 2; /* R_ALPHA_REFQUAD.  */
+    case EM_IA_64:
+      return reloc_type == 0x27; /* R_IA64_DIR64LSB.  */
+    case EM_PARISC:
+      return reloc_type == 80; /* R_PARISC_DIR64.  */
+    case EM_PPC64:
+      return reloc_type == 38; /* R_PPC64_ADDR64.  */
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+    case EM_SPARC:
+      return reloc_type == 54; /* R_SPARC_UA64.  */
+    case EM_X86_64:
+      return reloc_type == 1; /* R_X86_64_64.  */
+    case EM_S390_OLD:
+    case EM_S390:
+      return reloc_type == 22; /* R_S390_64 */
+    default:
+      return FALSE;
+    }
+}
+
+/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
+   a 16-bit absolute RELA relocation used in DWARF debug sections.  */
+
+static bfd_boolean
+is_16bit_abs_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_AVR_OLD:
+    case EM_AVR:
+      return reloc_type == 4; /* R_AVR_16.  */
+    case EM_CYGNUS_D10V:
+    case EM_D10V:
+      return reloc_type == 3; /* R_D10V_16.  */
+    case EM_H8S:
+    case EM_H8_300:
+    case EM_H8_300H:
+      return reloc_type == R_H8_DIR16;
+    case EM_IP2K_OLD:
+    case EM_IP2K:
+      return reloc_type == 1; /* R_IP2K_16.  */
+    case EM_M32C:
+      return reloc_type == 1; /* R_M32C_16 */
+    case EM_MSP430_OLD:
+    case EM_MSP430:
+      return reloc_type == 5; /* R_MSP430_16_BYTE.  */
+    case EM_ALTERA_NIOS2:
+    case EM_NIOS32:
+      return reloc_type == 9; /* R_NIOS_16.  */
+    default:
+      return FALSE;
+    }
+}
+
+/* Apply relocations to a debug section.  */
+
+static void
+debug_apply_relocations (void *file,
+                        Elf_Internal_Shdr *section,
+                        unsigned char *start)
 {
   Elf_Internal_Shdr *relsec;
   unsigned char *end = start + section->sh_size;
 
-  if (!is_relocatable)
-    return 1;
-
-  /* SH uses RELA but uses in place value instead of the addend field.  */
-  if (elf_header.e_machine == EM_SH)
-    return 0;
+  if (elf_header.e_type != ET_REL)
+    return;
 
+  /* Find the reloc section associated with the debug section.  */
   for (relsec = section_headers;
        relsec < section_headers + elf_header.e_shnum;
        ++relsec)
     {
-      unsigned long nrelas;
-      Elf_Internal_Rela *rela, *rp;
+      bfd_boolean is_rela;
+      unsigned long num_relocs;
+      Elf_Internal_Rela *relocs, *rp;
       Elf_Internal_Shdr *symsec;
       Elf_Internal_Sym *symtab;
       Elf_Internal_Sym *sym;
 
-      if (relsec->sh_type != SHT_RELA
+      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;
 
-      if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
-                             &rela, &nrelas))
-       return 0;
+      is_rela = relsec->sh_type == SHT_RELA;
+
+      if (is_rela)
+       {
+         if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
+                                 & relocs, & num_relocs))
+           return;
+       }
+      else
+       {
+         if (!slurp_rel_relocs (file, relsec->sh_offset, relsec->sh_size,
+                                & relocs, & num_relocs))
+           return;
+       }
+
+      /* SH uses RELA but uses in place value instead of the addend field.  */
+      if (elf_header.e_machine == EM_SH)
+       is_rela = FALSE;
 
       symsec = SECTION_HEADER (relsec->sh_link);
       symtab = GET_ELF_SYMBOLS (file, symsec);
 
-      for (rp = rela; rp < rela + nrelas; ++rp)
-       {
-         unsigned char *loc;
-         unsigned int reloc_size;
-
-         reloc_size = get_reloc_size (rp);
-         if (reloc_size == 0)
+      for (rp = relocs; rp < relocs + num_relocs; ++rp)
+       {
+         bfd_vma         addend;
+         unsigned int    reloc_type;
+         unsigned int    reloc_size;
+         unsigned char * loc;
+
+         /* In MIPS little-endian objects, r_info isn't really a
+            64-bit little-endian value: it has a 32-bit little-endian
+            symbol index followed by four individual byte fields.
+            Reorder INFO accordingly.  */
+         if (!is_32bit_elf
+             && elf_header.e_machine == EM_MIPS
+             && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
+           rp->r_info = (((rp->r_info & 0xffffffff) << 32)
+                         | ((rp->r_info >> 56) & 0xff)
+                         | ((rp->r_info >> 40) & 0xff00)
+                         | ((rp->r_info >> 24) & 0xff0000)
+                         | ((rp->r_info >> 8) & 0xff000000));
+
+         reloc_type = get_reloc_type (rp->r_info);
+
+         if (is_32bit_abs_reloc (reloc_type)
+             || is_32bit_pcrel_reloc (reloc_type))
+           reloc_size = 4;
+         else if (is_64bit_abs_reloc (reloc_type))
+           reloc_size = 8;
+         else if (is_16bit_abs_reloc (reloc_type))
+           reloc_size = 2;
+         else
            {
-             warn (_("skipping relocation of unknown size against offset 0x%lx in section %s\n"),
-                   (unsigned long) rp->r_offset,
-                   SECTION_NAME (section));
+             warn (_("unable to apply unsupported reloc type %d to section %s\n"),
+                   reloc_type, SECTION_NAME (section));
              continue;
            }
 
@@ -7857,63 +8313,41 @@ debug_apply_rela_addends (void *file,
              continue;
            }
 
-         if (is_32bit_elf)
-           {
-             sym = symtab + ELF32_R_SYM (rp->r_info);
-
-             if (ELF32_R_SYM (rp->r_info) != 0
-                 && ELF32_ST_TYPE (sym->st_info) != STT_SECTION
-                 /* Relocations against symbols without type can happen.
-                    Gcc -feliminate-dwarf2-dups may generate symbols
-                    without type for debug info.  */
-                 && ELF32_ST_TYPE (sym->st_info) != STT_NOTYPE
-                 /* Relocations against object symbols can happen,
-                    eg when referencing a global array.  For an
-                    example of this see the _clz.o binary in libgcc.a.  */
-                 && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT)
-               {
-                 warn (_("skipping unexpected symbol type %s in relocation in section .rela%s\n"),
-                       get_symbol_type (ELF32_ST_TYPE (sym->st_info)),
-                       SECTION_NAME (section));
-                 continue;
-               }
-           }
-         else
+         sym = symtab + get_reloc_symindex (rp->r_info);
+
+         /* If the reloc has a symbol associated with it,
+            make sure that it is of an appropriate type.  */
+         if (sym != symtab
+             && ELF_ST_TYPE (sym->st_info) != STT_SECTION
+             /* Relocations against symbols without type can happen.
+                Gcc -feliminate-dwarf2-dups may generate symbols
+                without type for debug info.  */
+             && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
+             /* Relocations against object symbols can happen,
+                eg when referencing a global array.  For an
+                example of this see the _clz.o binary in libgcc.a.  */
+             && ELF_ST_TYPE (sym->st_info) != STT_OBJECT)
            {
-             /* In MIPS little-endian objects, r_info isn't really a
-                64-bit little-endian value: it has a 32-bit little-endian
-                symbol index followed by four individual byte fields.
-                Reorder INFO accordingly.  */
-             if (elf_header.e_machine == EM_MIPS
-                 && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
-               rp->r_info = (((rp->r_info & 0xffffffff) << 32)
-                             | ((rp->r_info >> 56) & 0xff)
-                             | ((rp->r_info >> 40) & 0xff00)
-                             | ((rp->r_info >> 24) & 0xff0000)
-                             | ((rp->r_info >> 8) & 0xff000000));
-
-             sym = symtab + ELF64_R_SYM (rp->r_info);
-
-             if (ELF64_R_SYM (rp->r_info) != 0
-                 && ELF64_ST_TYPE (sym->st_info) != STT_SECTION
-                 && ELF64_ST_TYPE (sym->st_info) != STT_NOTYPE
-                 && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
-               {
-                 warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"),
-                       get_symbol_type (ELF64_ST_TYPE (sym->st_info)),
-                       SECTION_NAME (section));
-                 continue;
-               }
+             warn (_("skipping unexpected symbol type %s in %ld'th relocation in section %s\n"),
+                   get_symbol_type (ELF_ST_TYPE (sym->st_info)),
+                   (long int)(rp - relocs),
+                   SECTION_NAME (relsec));
+             continue;
            }
 
-         byte_put (loc, rp->r_addend, reloc_size);
+         addend = is_rela ? rp->r_addend : byte_get (loc, reloc_size);
+         
+         if (is_32bit_pcrel_reloc (reloc_type))
+           byte_put (loc, (addend + sym->st_value) - rp->r_offset,
+                     reloc_size);
+         else
+           byte_put (loc, addend + sym->st_value, reloc_size);
        }
 
       free (symtab);
-      free (rela);
+      free (relocs);
       break;
     }
-  return 1;
 }
 
 int
@@ -7939,7 +8373,7 @@ load_debug_section (enum dwarf_section_display_enum debug, void *file)
                             sec->sh_size, buf);
 
   if (debug_displays [debug].relocate)
-    debug_apply_rela_addends (file, sec, section->start);
+    debug_apply_relocations (file, sec, section->start);
 
   return section->start != NULL;
 }
@@ -8018,7 +8452,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;
          }
 
@@ -8048,10 +8482,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
@@ -8297,11 +8734,9 @@ 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))
+display_gnu_attribute (unsigned char * p,
+                      unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int))
 {
   int tag;
   unsigned int len;
@@ -8318,7 +8753,7 @@ display_gnu_attribute (unsigned char *p,
       val = read_uleb128 (p, &len);
       p += len;
       printf ("flag = %d, vendor = %s\n", val, p);
-      p += strlen((char *)p) + 1;
+      p += strlen ((char *) p) + 1;
       return p;
     }
 
@@ -8334,7 +8769,7 @@ display_gnu_attribute (unsigned char *p,
   if (type == 1)
     {
       printf ("\"%s\"\n", p);
-      p += strlen ((char *)p) + 1;
+      p += strlen ((char *) p) + 1;
     }
   else
     {
@@ -8358,6 +8793,7 @@ display_power_gnu_attribute (unsigned char *p, int tag)
       val = read_uleb128 (p, &len);
       p += len;
       printf ("  Tag_GNU_Power_ABI_FP: ");
+
       switch (val)
        {
        case 0:
@@ -8376,6 +8812,32 @@ display_power_gnu_attribute (unsigned char *p, int tag)
       return p;
    }
 
+  if (tag == Tag_GNU_Power_ABI_Vector)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_Power_ABI_Vector: ");
+      switch (val)
+       {
+       case 0:
+         printf ("Any\n");
+         break;
+       case 1:
+         printf ("Generic\n");
+         break;
+       case 2:
+         printf ("AltiVec\n");
+         break;
+       case 3:
+         printf ("SPE\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
+       }
+      return p;
+   }
+
   if (tag & 1)
     type = 1; /* String.  */
   else
@@ -8385,7 +8847,7 @@ display_power_gnu_attribute (unsigned char *p, int tag)
   if (type == 1)
     {
       printf ("\"%s\"\n", p);
-      p += strlen ((char *)p) + 1;
+      p += strlen ((char *) p) + 1;
     }
   else
     {
@@ -8409,6 +8871,7 @@ display_mips_gnu_attribute (unsigned char *p, int tag)
       val = read_uleb128 (p, &len);
       p += len;
       printf ("  Tag_GNU_MIPS_ABI_FP: ");
+
       switch (val)
        {
        case 0:
@@ -8423,6 +8886,9 @@ display_mips_gnu_attribute (unsigned char *p, int tag)
        case 3:
          printf ("Soft float\n");
          break;
+       case 4:
+         printf ("64-bit float (-mips32r2 -mfp64)\n");
+         break;
        default:
          printf ("??? (%d)\n", val);
          break;
@@ -8439,7 +8905,7 @@ display_mips_gnu_attribute (unsigned char *p, int tag)
   if (type == 1)
     {
       printf ("\"%s\"\n", p);
-      p += strlen ((char *)p) + 1;
+      p += strlen ((char *) p) + 1;
     }
   else
     {
@@ -8452,11 +8918,11 @@ display_mips_gnu_attribute (unsigned char *p, int tag)
 }
 
 static int
-process_attributes (FILE *file, const char *public_name,
+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))
+                   unsigned char * (* display_pub_attribute) (unsigned char *),
+                   unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int))
 {
   Elf_Internal_Shdr *sect;
   unsigned char *contents;
@@ -8476,14 +8942,15 @@ process_attributes (FILE *file, const char *public_name,
 
       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;
@@ -8492,40 +8959,49 @@ process_attributes (FILE *file, const char *public_name,
 
              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 (public_name && strcmp ((char *)p, public_name) == 0)
+
+             if (public_name && streq ((char *) p, public_name))
                public_section = TRUE;
              else
                public_section = FALSE;
-             if (strcmp ((char *)p, "gnu") == 0)
+
+             if (streq ((char *) p, "gnu"))
                gnu_section = TRUE;
              else
                gnu_section = FALSE;
-             namelen = strlen ((char *)p) + 1;
+
+             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:
@@ -8540,6 +9016,7 @@ process_attributes (FILE *file, const char *public_name,
                      for (;;)
                        {
                          unsigned int i;
+
                          val = read_uleb128 (p, &i);
                          p += i;
                          if (val == 0)
@@ -8553,6 +9030,7 @@ process_attributes (FILE *file, const char *public_name,
                      public_section = FALSE;
                      break;
                    }
+
                  if (public_section)
                    {
                      while (p < end)
@@ -8574,11 +9052,9 @@ process_attributes (FILE *file, const char *public_name,
            }
        }
       else
-       {
-         printf (_("Unknown format '%c'\n"), *p);
-       }
+       printf (_("Unknown format '%c'\n"), *p);
 
-      free(contents);
+      free (contents);
     }
   return 1;
 }
@@ -8704,9 +9180,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);
@@ -9097,6 +9571,8 @@ get_note_type (unsigned e_type)
        return _("NT_TASKSTRUCT (task structure)");
       case NT_PRXFPREG:
        return _("NT_PRXFPREG (user_xfpregs structure)");
+      case NT_PPC_VMX:
+       return _("NT_PPC_VMX (ppc Altivec registers)");
       case NT_PSTATUS:
        return _("NT_PSTATUS (pstatus structure)");
       case NT_FPREGS:
@@ -9127,6 +9603,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)
 {
@@ -9197,6 +9694,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)
@@ -9204,18 +9702,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;
 }
 
@@ -9474,8 +9981,6 @@ get_file_header (FILE *file)
        get_64bit_section_headers (file, 1);
     }
 
-  is_relocatable = elf_header.e_type == ET_REL;
-
   return 1;
 }
 
@@ -9495,10 +10000,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.  */
@@ -9510,16 +10015,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 ())
@@ -9629,8 +10135,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)
@@ -9638,6 +10144,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;
@@ -9655,27 +10165,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, "//              "))
     {
@@ -9683,35 +10290,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);
@@ -9795,7 +10487,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;
@@ -9834,7 +10531,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;
     }
@@ -9843,6 +10540,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);
@@ -9893,12 +10594,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.\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;
        }
     }