]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - binutils/readelf.c
Add mingw I64 support for printing long and long long values
[thirdparty/binutils-gdb.git] / binutils / readelf.c
index 4f865b029c8a3a00133bf05181974e2aeaefde4a..807b0f1f26ed14ca2ee1464d0e40ef4c42d65250 100644 (file)
@@ -1,6 +1,6 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-   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>
@@ -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,
   ELF file than is provided by objdump.  In particular it can display DWARF
   debugging information which (at the moment) objdump cannot.  */
 \f
+#include "sysdep.h"
 #include <assert.h>
-#include <sys/types.h>
 #include <sys/stat.h>
-#include <stdio.h>
 #include <time.h>
 
+/* for PATH_MAX */
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef PATH_MAX
+/* for MAXPATHLEN */
+# ifdef HAVE_SYS_PARAM_H
+#  include <sys/param.h>
+# endif
+# ifndef PATH_MAX
+#  ifdef MAXPATHLEN
+#   define PATH_MAX MAXPATHLEN
+#  else
+#   define PATH_MAX 1024
+#  endif
+# endif
+#endif
+
 #if __GNUC__ >= 2
 /* Define BFD64 here, even if our default architecture is 32 bit ELF
    as this will allow us to read in and parse 64bit and 32bit ELF files.
 #endif
 
 #include "bfd.h"
+#include "bucomm.h"
+#include "dwarf.h"
 
 #include "elf/common.h"
 #include "elf/external.h"
 #include "elf/internal.h"
-#include "elf/dwarf2.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
 #include "elf/arc.h"
 #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 "elf/d30v.h"
 #include "elf/dlx.h"
 #include "elf/i960.h"
 #include "elf/ia64.h"
 #include "elf/ip2k.h"
+#include "elf/iq2000.h"
 #include "elf/m32c.h"
 #include "elf/m32r.h"
 #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"
 #include "elf/mn10300.h"
-#include "elf/ms1.h"
+#include "elf/mt.h"
 #include "elf/msp430.h"
 #include "elf/or32.h"
 #include "elf/pj.h"
 #include "elf/ppc.h"
 #include "elf/ppc64.h"
 #include "elf/s390.h"
+#include "elf/score.h"
 #include "elf/sh.h"
 #include "elf/sparc.h"
+#include "elf/spu.h"
 #include "elf/v850.h"
 #include "elf/vax.h"
 #include "elf/x86-64.h"
 #include "elf/xstormy16.h"
-#include "elf/crx.h"
-#include "elf/iq2000.h"
 #include "elf/xtensa.h"
 
 #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;
@@ -133,8 +175,9 @@ static Elf_Internal_Sym *dynamic_symbols;
 static Elf_Internal_Syminfo *dynamic_syminfo;
 static unsigned long dynamic_syminfo_offset;
 static unsigned int dynamic_syminfo_nent;
-static char program_interpreter[64];
+static char program_interpreter[PATH_MAX];
 static bfd_vma dynamic_info[DT_JMPREL + 1];
+static bfd_vma dynamic_info_DT_GNU_HASH;
 static bfd_vma version_info[16];
 static Elf_Internal_Ehdr elf_header;
 static Elf_Internal_Shdr *section_headers;
@@ -157,23 +200,10 @@ static int do_version;
 static int do_wide;
 static int do_histogram;
 static int do_debugging;
-static int do_debug_info;
-static int do_debug_abbrevs;
-static int do_debug_lines;
-static int do_debug_pubnames;
-static int do_debug_aranges;
-static int do_debug_ranges;
-static int do_debug_frames;
-static int do_debug_frames_interp;
-static int do_debug_macinfo;
-static int do_debug_str;
-static int do_debug_loc;
 static int do_arch;
 static int do_notes;
+static int do_archive_index;
 static int is_32bit_elf;
-static int have_frame_base;
-static int need_base_address;
-static bfd_vma eh_addr_size;
 
 struct group_list
 {
@@ -191,22 +221,37 @@ static size_t group_count;
 static struct group *section_groups;
 static struct group **section_headers_groups;
 
-/* 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;
+
+/* 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;
+  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 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 and
-   the results of interpreting the -w switch.  */
-char *dump_sects = NULL;
-unsigned int num_dump_sects = 0;
+   basis and then initialised from the cmdline_dump_sects array,
+   the results of interpreting the -w switch, and the
+   dump_sects_byname list.  */
+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
@@ -221,14 +266,15 @@ typedef enum print_mode
 }
 print_mode;
 
-static bfd_vma (*byte_get) (unsigned char *, int);
 static void (*byte_put) (unsigned char *, bfd_vma, int);
 
 #define UNKNOWN -1
 
-#define SECTION_NAME(X)        ((X) == NULL ? "<none>" : \
-                        ((X)->sh_name >= string_table_length \
-                         ? "<corrupt>" : string_table + (X)->sh_name))
+#define SECTION_NAME(X)        \
+  ((X) == NULL ? "<none>" \
+  : string_table == NULL ? "<no-name>" \
+  : ((X)->sh_name >= string_table_length ? "<corrupt>" \
+  : string_table + (X)->sh_name))
 
 /* Given st_shndx I, map to section_headers index.  */
 #define SECTION_HEADER_INDEX(I)                                \
@@ -250,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))
@@ -262,61 +306,10 @@ 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 ATTRIBUTE_PRINTF_1
-error (const char *message, ...)
-{
-  va_list args;
-
-  va_start (args, message);
-  fprintf (stderr, _("%s: Error: "), program_name);
-  vfprintf (stderr, message, args);
-  va_end (args);
-}
-
-static void ATTRIBUTE_PRINTF_1
-warn (const char *message, ...)
-{
-  va_list args;
-
-  va_start (args, message);
-  fprintf (stderr, _("%s: Warning: "), program_name);
-  vfprintf (stderr, message, args);
-  va_end (args);
-}
-
-static void *
-cmalloc (size_t nmemb, size_t size)
-{
-  /* Check for overflow.  */
-  if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return malloc (nmemb * size);
-}
-
-static void *
-xcmalloc (size_t nmemb, size_t size)
-{
-  /* Check for overflow.  */
-  if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return xmalloc (nmemb * size);
-}
-
-static void *
-xcrealloc (void *ptr, size_t nmemb, size_t size)
-{
-  /* Check for overflow.  */
-  if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return xrealloc (ptr, nmemb * size);
-}
-
 static void *
 get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
          const char *reason)
@@ -363,68 +356,6 @@ get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
   return mvar;
 }
 
-static bfd_vma
-byte_get_little_endian (unsigned char *field, int size)
-{
-  switch (size)
-    {
-    case 1:
-      return *field;
-
-    case 2:
-      return  ((unsigned int) (field[0]))
-       |    (((unsigned int) (field[1])) << 8);
-
-#ifndef BFD64
-    case 8:
-      /* We want to extract data from an 8 byte wide field and
-        place it into a 4 byte wide field.  Since this is a little
-        endian source we can just use the 4 byte extraction code.  */
-      /* Fall through.  */
-#endif
-    case 4:
-      return  ((unsigned long) (field[0]))
-       |    (((unsigned long) (field[1])) << 8)
-       |    (((unsigned long) (field[2])) << 16)
-       |    (((unsigned long) (field[3])) << 24);
-
-#ifdef BFD64
-    case 8:
-      return  ((bfd_vma) (field[0]))
-       |    (((bfd_vma) (field[1])) << 8)
-       |    (((bfd_vma) (field[2])) << 16)
-       |    (((bfd_vma) (field[3])) << 24)
-       |    (((bfd_vma) (field[4])) << 32)
-       |    (((bfd_vma) (field[5])) << 40)
-       |    (((bfd_vma) (field[6])) << 48)
-       |    (((bfd_vma) (field[7])) << 56);
-#endif
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
-    }
-}
-
-static bfd_vma
-byte_get_signed (unsigned char *field, int size)
-{
-  bfd_vma x = byte_get (field, size);
-
-  switch (size)
-    {
-    case 1:
-      return (x ^ 0x80) - 0x80;
-    case 2:
-      return (x ^ 0x8000) - 0x8000;
-    case 4:
-      return (x ^ 0x80000000) - 0x80000000;
-    case 8:
-      return x;
-    default:
-      abort ();
-    }
-}
-
 static void
 byte_put_little_endian (unsigned char *field, bfd_vma value, int size)
 {
@@ -453,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)
 {
@@ -561,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
@@ -568,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
@@ -578,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));
@@ -588,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
@@ -614,48 +575,6 @@ print_symbol (int width, const char *symbol)
     printf ("%-.*s", width, symbol);
 }
 
-static bfd_vma
-byte_get_big_endian (unsigned char *field, int size)
-{
-  switch (size)
-    {
-    case 1:
-      return *field;
-
-    case 2:
-      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
-
-#ifndef BFD64
-    case 8:
-      /* Although we are extracing data from an 8 byte wide field,
-        we are returning only 4 bytes of data.  */
-      field += 4;
-      /* Fall thru */
-#endif
-    case 4:
-      return ((unsigned long) (field[3]))
-       |   (((unsigned long) (field[2])) << 8)
-       |   (((unsigned long) (field[1])) << 16)
-       |   (((unsigned long) (field[0])) << 24);
-
-#ifdef BFD64
-    case 8:
-      return ((bfd_vma) (field[7]))
-       |   (((bfd_vma) (field[6])) << 8)
-       |   (((bfd_vma) (field[5])) << 16)
-       |   (((bfd_vma) (field[4])) << 24)
-       |   (((bfd_vma) (field[3])) << 32)
-       |   (((bfd_vma) (field[2])) << 40)
-       |   (((bfd_vma) (field[1])) << 48)
-       |   (((bfd_vma) (field[0])) << 56);
-#endif
-
-    default:
-      error (_("Unhandled data length: %d\n"), size);
-      abort ();
-    }
-}
-
 static void
 byte_put_big_endian (unsigned char *field, bfd_vma value, int size)
 {
@@ -710,85 +629,92 @@ guess_is_rela (unsigned long e_machine)
   switch (e_machine)
     {
       /* Targets that use REL relocations.  */
-    case EM_ARM:
     case EM_386:
     case EM_486:
     case EM_960:
-    case EM_DLX:
-    case EM_OPENRISC:
-    case EM_OR32:
-    case EM_CYGNUS_M32R:
+    case EM_ARM:
     case EM_D10V:
     case EM_CYGNUS_D10V:
+    case EM_DLX:
     case EM_MIPS:
     case EM_MIPS_RS3_LE:
+    case EM_CYGNUS_M32R:
+    case EM_OPENRISC:
+    case EM_OR32:
+    case EM_SCORE:
       return FALSE;
 
       /* Targets that use RELA relocations.  */
     case EM_68K:
-    case EM_H8_300:
-    case EM_H8_300H:
-    case EM_H8S:
-    case EM_SPARC32PLUS:
-    case EM_SPARCV9:
-    case EM_SPARC:
-    case EM_PPC:
-    case EM_PPC64:
-    case EM_V850:
-    case EM_CYGNUS_V850:
+    case EM_860:
+    case EM_ALPHA:
+    case EM_ALTERA_NIOS2:
+    case EM_AVR:
+    case EM_AVR_OLD:
+    case EM_BLACKFIN:
+    case EM_CR16:
+    case EM_CRIS:
+    case EM_CRX:
     case EM_D30V:
     case EM_CYGNUS_D30V:
-    case EM_MN10200:
-    case EM_CYGNUS_MN10200:
-    case EM_MN10300:
-    case EM_CYGNUS_MN10300:
     case EM_FR30:
     case EM_CYGNUS_FR30:
     case EM_CYGNUS_FRV:
-    case EM_SH:
-    case EM_ALPHA:
-    case EM_MCORE:
+    case EM_H8S:
+    case EM_H8_300:
+    case EM_H8_300H:
     case EM_IA_64:
-    case EM_AVR:
-    case EM_AVR_OLD:
-    case EM_CRIS:
-    case EM_860:
-    case EM_X86_64:
-    case EM_S390:
-    case EM_S390_OLD:
+    case EM_IP2K:
+    case EM_IP2K_OLD:
+    case EM_IQ2000:
+    case EM_M32C:
+    case EM_M32R:
+    case EM_MCORE:
+    case EM_CYGNUS_MEP:
     case EM_MMIX:
+    case EM_MN10200:
+    case EM_CYGNUS_MN10200:
+    case EM_MN10300:
+    case EM_CYGNUS_MN10300:
     case EM_MSP430:
     case EM_MSP430_OLD:
-    case EM_XSTORMY16:
-    case EM_CRX:
+    case EM_MT:
+    case EM_NIOS32:
+    case EM_PPC64:
+    case EM_PPC:
+    case EM_S390:
+    case EM_S390_OLD:
+    case EM_SH:
+    case EM_SPARC:
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+    case EM_SPU:
+    case EM_V850:
+    case EM_CYGNUS_V850:
     case EM_VAX:
-    case EM_IP2K:
-    case EM_IP2K_OLD:
-    case EM_IQ2000:
+    case EM_X86_64:
+    case EM_XSTORMY16:
     case EM_XTENSA:
     case EM_XTENSA_OLD:
-    case EM_M32R:
-    case EM_M32C:
-    case EM_MS1:
       return TRUE;
 
+    case EM_68HC05:
+    case EM_68HC08:
+    case EM_68HC11:
+    case EM_68HC16:
+    case EM_FX66:
+    case EM_ME16:
     case EM_MMA:
-    case EM_PCP:
     case EM_NCPU:
     case EM_NDR1:
-    case EM_STARCORE:
-    case EM_ME16:
+    case EM_PCP:
     case EM_ST100:
-    case EM_TINYJ:
-    case EM_FX66:
-    case EM_ST9PLUS:
+    case EM_ST19:
     case EM_ST7:
-    case EM_68HC16:
-    case EM_68HC11:
-    case EM_68HC08:
-    case EM_68HC05:
+    case EM_ST9PLUS:
+    case EM_STARCORE:
     case EM_SVX:
-    case EM_ST19:
+    case EM_TINYJ:
     default:
       warn (_("Don't know about relocations on this machine architecture\n"));
       return FALSE;
@@ -821,7 +747,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;
        }
 
@@ -849,7 +775,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;
        }
 
@@ -893,7 +819,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;
        }
 
@@ -921,7 +847,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;
        }
 
@@ -939,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,
@@ -962,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)
@@ -1008,77 +964,70 @@ 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
-         printf (do_wide
-                 ? "%8.8lx%8.8lx  %8.8lx%8.8lx "
-                 : "%4.4lx%8.8lx  %4.4lx%8.8lx ",
-                 _bfd_int64_high (offset),
-                 _bfd_int64_low (offset),
-                 _bfd_int64_high (info),
-                 _bfd_int64_low (info));
-#else
+#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 ",
+                 _bfd_int64_high (offset),
+                 _bfd_int64_low (offset),
+                 _bfd_int64_high (info),
+                 _bfd_int64_low (info));
 #endif
        }
 
@@ -1123,6 +1072,10 @@ dump_relocations (FILE *file,
          rtype = elf_sparc_reloc_type (type);
          break;
 
+       case EM_SPU:
+         rtype = elf_spu_reloc_type (type);
+         break;
+
        case EM_V850:
        case EM_CYGNUS_V850:
          rtype = v850_reloc_type (type);
@@ -1189,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:
@@ -1252,6 +1200,10 @@ dump_relocations (FILE *file,
          rtype = elf_s390_reloc_type (type);
          break;
 
+       case EM_SCORE:
+         rtype = elf_score_reloc_type (type);
+         break;
+
        case EM_XSTORMY16:
          rtype = elf_xstormy16_reloc_type (type);
          break;
@@ -1282,21 +1234,30 @@ dump_relocations (FILE *file,
          rtype = elf_m32c_reloc_type (type);
          break;
 
-       case EM_MS1:
-         rtype = elf_ms1_reloc_type (type);
+       case EM_MT:
+         rtype = elf_mt_reloc_type (type);
+         break;
+
+       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);
 
       if (elf_header.e_machine == EM_ALPHA
+         && rtype != NULL
          && streq (rtype, "R_ALPHA_LITUSE")
          && is_rela)
        {
@@ -1355,6 +1316,12 @@ dump_relocations (FILE *file,
                        sec_name = "ABS";
                      else if (psym->st_shndx == SHN_COMMON)
                        sec_name = "COMMON";
+                     else if (elf_header.e_machine == EM_MIPS
+                              && psym->st_shndx == SHN_MIPS_SCOMMON)
+                       sec_name = "SCOMMON";
+                     else if (elf_header.e_machine == EM_MIPS
+                              && psym->st_shndx == SHN_MIPS_SUNDEFINED)
+                       sec_name = "SUNDEF";
                      else if (elf_header.e_machine == EM_X86_64
                               && psym->st_shndx == SHN_X86_64_LCOMMON)
                        sec_name = "LARGE_COMMON";
@@ -1389,42 +1356,43 @@ dump_relocations (FILE *file,
          print_vma (rels[i].r_addend, LONG_HEX);
        }
 
-      if (elf_header.e_machine == EM_SPARCV9 && streq (rtype, "R_SPARC_OLO10"))
+      if (elf_header.e_machine == EM_SPARCV9
+         && rtype != NULL
+         && streq (rtype, "R_SPARC_OLO10"))
        printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info));
 
       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 *
@@ -1571,6 +1539,23 @@ get_alpha_dynamic_type (unsigned long type)
     }
 }
 
+static const char *
+get_score_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    case DT_SCORE_BASE_ADDRESS: return "SCORE_BASE_ADDRESS";
+    case DT_SCORE_LOCAL_GOTNO:  return "SCORE_LOCAL_GOTNO";
+    case DT_SCORE_SYMTABNO:     return "SCORE_SYMTABNO";
+    case DT_SCORE_GOTSYM:       return "SCORE_GOTSYM";
+    case DT_SCORE_UNREFEXTNO:   return "SCORE_UNREFEXTNO";
+    case DT_SCORE_HIPAGENO:     return "SCORE_HIPAGENO";
+    default:
+      return NULL;
+    }
+}
+
+
 static const char *
 get_dynamic_type (unsigned long type)
 {
@@ -1632,6 +1617,8 @@ get_dynamic_type (unsigned long type)
 
     case DT_VERSYM:    return "VERSYM";
 
+    case DT_TLSDESC_GOT: return "TLSDESC_GOT";
+    case DT_TLSDESC_PLT: return "TLSDESC_PLT";
     case DT_RELACOUNT: return "RELACOUNT";
     case DT_RELCOUNT:  return "RELCOUNT";
     case DT_FLAGS_1:   return "FLAGS_1";
@@ -1649,6 +1636,7 @@ get_dynamic_type (unsigned long type)
     case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ";
     case DT_GNU_LIBLIST: return "GNU_LIBLIST";
     case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ";
+    case DT_GNU_HASH:  return "GNU_HASH";
 
     default:
       if ((type >= DT_LOPROC) && (type <= DT_HIPROC))
@@ -1676,6 +1664,9 @@ get_dynamic_type (unsigned long type)
            case EM_ALPHA:
              result = get_alpha_dynamic_type (type);
              break;
+           case EM_SCORE:
+             result = get_score_dynamic_type (type);
+             break;
            default:
              result = NULL;
              break;
@@ -1749,6 +1740,7 @@ get_machine_name (unsigned e_machine)
     case EM_NONE:              return _("None");
     case EM_M32:               return "WE32100";
     case EM_SPARC:             return "Sparc";
+    case EM_SPU:               return "SPU";
     case EM_386:               return "Intel 80386";
     case EM_68K:               return "MC68000";
     case EM_88K:               return "MC88000";
@@ -1830,6 +1822,7 @@ get_machine_name (unsigned e_machine)
     case EM_X86_64:            return "Advanced Micro Devices X86-64";
     case EM_S390_OLD:
     case EM_S390:              return "IBM S/390";
+    case EM_SCORE:             return "SUNPLUS S+Core";
     case EM_XSTORMY16:         return "Sanyo Xstormy16 CPU core";
     case EM_OPENRISC:
     case EM_OR32:              return "OpenRISC";
@@ -1841,9 +1834,15 @@ get_machine_name (unsigned e_machine)
     case EM_XTENSA_OLD:
     case EM_XTENSA:            return "Tensilica Xtensa Processor";
     case EM_M32C:              return "Renesas M32c";
-    case EM_MS1:                return "Morpho Techologies MS1 processor";
+    case EM_MT:                 return "Morpho Techologies MT processor";
+    case EM_BLACKFIN:          return "Analog Devices Blackfin";
+    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), _("<unknown>: %x"), e_machine);
+      snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
       return buff;
     }
 }
@@ -1939,6 +1938,11 @@ decode_ARM_machine_flags (unsigned e_flags, char buf[])
 
     case EF_ARM_EABI_VER4:
       strcat (buf, ", Version4 EABI");
+      goto eabi;
+
+    case EF_ARM_EABI_VER5:
+      strcat (buf, ", Version5 EABI");
+    eabi:
       while (e_flags)
        {
          unsigned flag;
@@ -2087,10 +2091,62 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
          break;
 
        case EM_68K:
-         if (e_flags & EF_CPU32)
-           strcat (buf, ", cpu32");
-         if (e_flags & EF_M68000)
+         if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_M68000)
            strcat (buf, ", m68000");
+         else if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32)
+           strcat (buf, ", cpu32");
+         else if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO)
+           strcat (buf, ", fido_a");
+         else
+           {
+             char const *isa = _("unknown");
+             char const *mac = _("unknown mac");
+             char const *additional = NULL;
+
+             switch (e_flags & EF_M68K_CF_ISA_MASK)
+               {
+               case EF_M68K_CF_ISA_A_NODIV:
+                 isa = "A";
+                 additional = ", nodiv";
+                 break;
+               case EF_M68K_CF_ISA_A:
+                 isa = "A";
+                 break;
+               case EF_M68K_CF_ISA_A_PLUS:
+                 isa = "A+";
+                 break;
+               case EF_M68K_CF_ISA_B_NOUSP:
+                 isa = "B";
+                 additional = ", nousp";
+                 break;
+               case EF_M68K_CF_ISA_B:
+                 isa = "B";
+                 break;
+               }
+             strcat (buf, ", cf, isa ");
+             strcat (buf, isa);
+             if (additional)
+               strcat (buf, additional);
+             if (e_flags & EF_M68K_CF_FLOAT)
+               strcat (buf, ", float");
+             switch (e_flags & EF_M68K_CF_MAC_MASK)
+               {
+               case 0:
+                 mac = NULL;
+                 break;
+               case EF_M68K_CF_MAC:
+                 mac = "mac";
+                 break;
+               case EF_M68K_CF_EMAC:
+                 mac = "emac";
+                 break;
+               }
+             if (mac)
+               {
+                 strcat (buf, ", ");
+                 strcat (buf, mac);
+               }
+           }
          break;
 
        case EM_PPC:
@@ -2127,7 +2183,6 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
        case EM_CYGNUS_M32R:
          if ((e_flags & EF_M32R_ARCH) == E_M32R_ARCH)
            strcat (buf, ", m32r");
-
          break;
 
        case EM_MIPS:
@@ -2165,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
@@ -2228,6 +2285,12 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            case EF_SH4_NOFPU: strcat (buf, ", sh4-nofpu"); break;
            case EF_SH4A_NOFPU: strcat (buf, ", sh4a-nofpu"); break;
            case EF_SH2A_NOFPU: strcat (buf, ", sh2a-nofpu"); break;
+           case EF_SH3_NOMMU: strcat (buf, ", sh3-nommu"); break;
+           case EF_SH4_NOMMU_NOFPU: strcat (buf, ", sh4-nommu-nofpu"); break;
+           case EF_SH2A_SH4_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh4-nommu-nofpu"); break;
+           case EF_SH2A_SH3_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh3-nommu"); break;
+           case EF_SH2A_SH4: strcat (buf, ", sh2a-or-sh4"); break;
+           case EF_SH2A_SH3E: strcat (buf, ", sh2a-or-sh3e"); break;
            default: strcat (buf, ", unknown ISA"); break;
            }
 
@@ -2622,6 +2685,10 @@ get_arm_section_type_name (unsigned int sh_type)
     {
     case SHT_ARM_EXIDX:
       return "ARM_EXIDX";
+    case SHT_ARM_PREEMPTMAP:
+      return "ARM_PREEMPTMAP";
+    case SHT_ARM_ATTRIBUTES:
+      return "ARM_ATTRIBUTES";
     default:
       break;
     }
@@ -2650,6 +2717,7 @@ get_section_type_name (unsigned int sh_type)
     case SHT_INIT_ARRAY:       return "INIT_ARRAY";
     case SHT_FINI_ARRAY:       return "FINI_ARRAY";
     case SHT_PREINIT_ARRAY:    return "PREINIT_ARRAY";
+    case SHT_GNU_HASH:         return "GNU_HASH";
     case SHT_GROUP:            return "GROUP";
     case SHT_SYMTAB_SHNDX:     return "SYMTAB SECTION INDICIES";
     case SHT_GNU_verdef:       return "VERDEF";
@@ -2728,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
@@ -2742,11 +2812,11 @@ static struct option options[] =
 };
 
 static void
-usage (void)
+usage (FILE *stream)
 {
-  fprintf (stdout, _("Usage: readelf <option(s)> 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 <option(s)> 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\
@@ -2764,24 +2834,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=<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 (stdout, _("\
-  -i --instruction-dump=<number>\n\
-                         Disassemble the contents of section <number>\n"));
+  fprintf (stream, _("\
+  -i --instruction-dump=<number|name>\n\
+                         Disassemble the contents of section <number|name>\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\
+  @<file>                Read options from <file>\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
@@ -2790,20 +2867,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);
 
@@ -2818,16 +2895,37 @@ request_dump (unsigned int section, int type)
   return;
 }
 
+/* Request a dump by section name.  */
+
+static void
+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.\n"));
+
+  new_request->name = strdup (section);
+  if (!new_request->name)
+    error (_("Out of memory allocating dump request table.\n"));
+
+  new_request->type = type;
+
+  new_request->next = dump_sects_byname;
+  dump_sects_byname = new_request;
+}
+
 static void
 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;
@@ -2838,7 +2936,7 @@ parse_args (int argc, char **argv)
          /* Long options.  */
          break;
        case 'H':
-         usage ();
+         usage (stdout);
          break;
 
        case 'a':
@@ -2901,15 +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);
-             break;
-           }
-         goto oops;
+           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)
@@ -3057,11 +3165,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);
@@ -3073,24 +3179,23 @@ parse_args (int argc, char **argv)
          do_wide++;
          break;
        default:
-       oops:
          /* 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);
     }
 }
 
@@ -3200,6 +3305,11 @@ process_file_header (void)
              (long) elf_header.e_shstrndx);
       if (section_headers != NULL && elf_header.e_shstrndx == SHN_XINDEX)
        printf (" (%ld)", (long) section_headers[0].sh_link);
+      else if (elf_header.e_shstrndx != SHN_UNDEF
+              && (elf_header.e_shstrndx >= elf_header.e_shnum
+                  || (elf_header.e_shstrndx >= SHN_LORESERVE
+                      && elf_header.e_shstrndx <= SHN_HIRESERVE)))
+       printf (" <corrupt: out of range>");
       putc ('\n', stdout);
     }
 
@@ -3209,6 +3319,11 @@ process_file_header (void)
        elf_header.e_shnum = section_headers[0].sh_size;
       if (elf_header.e_shstrndx == SHN_XINDEX)
        elf_header.e_shstrndx = section_headers[0].sh_link;
+      else if (elf_header.e_shstrndx != SHN_UNDEF
+              && (elf_header.e_shstrndx >= elf_header.e_shnum
+                  || (elf_header.e_shstrndx >= SHN_LORESERVE
+                      && elf_header.e_shstrndx <= SHN_HIRESERVE)))
+       elf_header.e_shstrndx = SHN_UNDEF;
       free (section_headers);
       section_headers = NULL;
     }
@@ -3456,6 +3571,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)
@@ -3465,7 +3585,13 @@ 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)
+               {
+                 dynamic_size = 0;
                  break;
                }
 
@@ -3474,16 +3600,11 @@ process_program_headers (FILE *file)
 
              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."));
-           }
-         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;
 
@@ -3493,8 +3614,15 @@ process_program_headers (FILE *file)
            error (_("Unable to find program interpreter name\n"));
          else
            {
+             char fmt [32];
+             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\n"));
+
              program_interpreter[0] = 0;
-             fscanf (file, "%63s", 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]"),
@@ -3524,21 +3652,7 @@ process_program_headers (FILE *file)
 
          for (j = 1; j < elf_header.e_shnum; j++, section++)
            {
-             if (section->sh_size > 0
-                 /* Compare allocated sections by VMA, unallocated
-                    sections by file offset.  */
-                 && (section->sh_flags & SHF_ALLOC
-                     ? (section->sh_addr >= segment->p_vaddr
-                        && section->sh_addr + section->sh_size
-                        <= segment->p_vaddr + segment->p_memsz)
-                     : ((bfd_vma) section->sh_offset >= segment->p_offset
-                        && (section->sh_offset + section->sh_size
-                            <= segment->p_offset + segment->p_filesz)))
-                 /* .tbss is special.  It doesn't contribute memory space
-                    to normal segments.  */
-                 && (!((section->sh_flags & SHF_TLS) != 0
-                       && section->sh_type == SHT_NOBITS)
-                     || segment->p_type == PT_TLS))
+             if (ELF_IS_SECTION_IN_SEGMENT_MEMORY(section, segment))
                printf ("%s ", SECTION_NAME (section));
            }
 
@@ -3794,7 +3908,11 @@ get_elf_section_flags (bfd_vma sh_flags)
 {
   static char buff[1024];
   char *p = buff;
-  int index, size = sizeof (buff) - (8 + 4 + 1);
+  int field_size = is_32bit_elf ? 8 : 16;
+  int index, size = sizeof (buff) - (field_size + 4 + 1);
+  bfd_vma os_flags = 0;
+  bfd_vma proc_flags = 0;
+  bfd_vma unknown_flags = 0;
   const struct
     {
       const char *str;
@@ -3816,8 +3934,9 @@ get_elf_section_flags (bfd_vma sh_flags)
 
   if (do_section_details)
     {
-      sprintf (buff, "[%8.8lx]: ", (unsigned long) sh_flags);
-      p += 8 + 4;
+      sprintf (buff, "[%*.*lx]: ",
+              field_size, field_size, (unsigned long) sh_flags);
+      p += field_size + 4;
     }
 
   while (sh_flags)
@@ -3847,38 +3966,26 @@ get_elf_section_flags (bfd_vma sh_flags)
              break;
            }
 
-         if (p != buff + 8 + 4)
-           {
-             if (size < 10 + 2)
-               abort ();
-             size -= 2;
-             *p++ = ',';
-             *p++ = ' ';
-           }
-
          if (index != -1)
            {
+             if (p != buff + field_size + 4)
+               {
+                 if (size < (10 + 2))
+                   abort ();
+                 size -= 2;
+                 *p++ = ',';
+                 *p++ = ' ';
+               }
+
              size -= flags [index].len;
              p = stpcpy (p, flags [index].str);
            }
          else if (flag & SHF_MASKOS)
-           {
-             size -= 5 + 8;
-             sprintf (p, "OS (%8.8lx)", (unsigned long) flag);
-             p += 5 + 8;
-           }
+           os_flags |= flag;
          else if (flag & SHF_MASKPROC)
-           {
-             size -= 7 + 8;
-             sprintf (p, "PROC (%8.8lx)", (unsigned long) flag);
-             p += 7 + 8;
-           }
+           proc_flags |= flag;
          else
-           {
-             size -= 10 + 8;
-             sprintf (p, "UNKNOWN (%8.8lx)", (unsigned long) flag);
-             p += 10 + 8;
-           }
+           unknown_flags |= flag;
        }
       else
        {
@@ -3917,6 +4024,55 @@ get_elf_section_flags (bfd_vma sh_flags)
        }
     }
 
+  if (do_section_details)
+    {
+      if (os_flags)
+       {
+         size -= 5 + field_size;
+         if (p != buff + field_size + 4)
+           {
+             if (size < (2 + 1))
+               abort ();
+             size -= 2;
+             *p++ = ',';
+             *p++ = ' ';
+           }
+         sprintf (p, "OS (%*.*lx)", field_size, field_size,
+                  (unsigned long) os_flags);
+         p += 5 + field_size;
+       }
+      if (proc_flags)
+       {
+         size -= 7 + field_size;
+         if (p != buff + field_size + 4)
+           {
+             if (size < (2 + 1))
+               abort ();
+             size -= 2;
+             *p++ = ',';
+             *p++ = ' ';
+           }
+         sprintf (p, "PROC (%*.*lx)", field_size, field_size,
+                  (unsigned long) proc_flags);
+         p += 7 + field_size;
+       }
+      if (unknown_flags)
+       {
+         size -= 10 + field_size;
+         if (p != buff + field_size + 4)
+           {
+             if (size < (2 + 1))
+               abort ();
+             size -= 2;
+             *p++ = ',';
+             *p++ = ' ';
+           }
+         sprintf (p, "UNKNOWN (%*.*lx)", field_size, field_size,
+                  (unsigned long) unknown_flags);
+         p += 10 + field_size;
+       }
+    }
+
   *p = '\0';
   return buff;
 }
@@ -3950,7 +4106,8 @@ process_section_headers (FILE *file)
     return 0;
 
   /* Read in the string table, so that we have names to display.  */
-  if (SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum)
+  if (elf_header.e_shstrndx != SHN_UNDEF
+       && SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum)
     {
       section = SECTION_HEADER (elf_header.e_shstrndx);
 
@@ -3988,6 +4145,23 @@ process_section_headers (FILE *file)
          && find_section (".gcc_compiled_long32") == NULL)
        eh_addr_size = 8;
       break;
+
+    case EM_H8_300:
+    case EM_H8_300H:
+      switch (elf_header.e_flags & EF_H8_MACH)
+       {
+       case E_H8_MACH_H8300:
+       case E_H8_MACH_H8300HN:
+       case E_H8_MACH_H8300SN:
+       case E_H8_MACH_H8300SXN:
+         eh_addr_size = 2;
+         break;
+       case E_H8_MACH_H8300H:
+       case E_H8_MACH_H8300S:
+       case E_H8_MACH_H8300SX:
+         eh_addr_size = 4;
+         break;
+       }
     }
 
 #define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \
@@ -4058,7 +4232,7 @@ process_section_headers (FILE *file)
                || do_debug_lines || do_debug_pubnames || do_debug_aranges
                || do_debug_frames || do_debug_macinfo || do_debug_str
                || do_debug_loc || do_debug_ranges)
-              && strneq (name, ".debug_", 7))
+              && const_strneq (name, ".debug_"))
        {
          name += 7;
 
@@ -4074,14 +4248,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)
-              && strneq (name, ".gnu.linkonce.wi.", 17))
-       request_dump (i, DEBUG_DUMP);
+              && const_strneq (name, ".gnu.linkonce.wi."))
+       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)
@@ -4698,6 +4872,11 @@ struct absaddr
     bfd_vma offset;
   };
 
+#define ABSADDR(a) \
+  ((a).section \
+   ? section_headers [(a).section].sh_addr + (a).offset \
+   : (a).offset)
+
 struct ia64_unw_aux_info
   {
     struct ia64_unw_table_entry
@@ -4790,7 +4969,7 @@ dump_ia64_unwind (struct ia64_unw_aux_info *aux)
       printf ("], info at +0x%lx\n",
              (unsigned long) (tp->info.offset - aux->seg_base));
 
-      head = aux->info + (tp->info.offset - aux->info_addr);
+      head = aux->info + (ABSADDR (tp->info) - aux->info_addr);
       stamp = byte_get ((unsigned char *) head, sizeof (stamp));
 
       printf ("  v%u, flags=0x%lx (%s%s), len=%lu bytes\n",
@@ -4881,8 +5060,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)
@@ -4898,18 +5076,10 @@ 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 (! strneq (relname, "R_IA64_SEGREL", 13))
+         if (! const_strneq (relname, "R_IA64_SEGREL"))
            {
              warn (_("Skipping unexpected relocation type %s\n"), relname);
              continue;
@@ -5294,7 +5464,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)
@@ -5310,19 +5479,11 @@ 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 (strncmp (relname, "R_PARISC_SEGREL", 15) != 0)
+         if (! const_strneq (relname, "R_PARISC_SEGREL"))
            {
              warn (_("Skipping unexpected relocation type %s\n"), relname);
              continue;
@@ -5460,7 +5621,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]);
@@ -5549,7 +5710,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)
@@ -5760,7 +5921,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;
            }
@@ -6240,6 +6401,15 @@ process_dynamic_section (FILE *file)
            }
          break;
 
+       case DT_GNU_HASH:
+         dynamic_info_DT_GNU_HASH = entry->d_un.d_val;
+         if (do_dynamic)
+           {
+             print_vma (entry->d_un.d_val, PREFIX_HEX);
+             putchar ('\n');
+           }
+         break;
+
        default:
          if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM))
            version_info[DT_VERSIONTAGIDX (entry->d_tag)] =
@@ -6320,6 +6490,7 @@ process_version_sections (FILE *file)
            Elf_External_Verdef *edefs;
            unsigned int idx;
            unsigned int cnt;
+           char *endbuf;
 
            found = 1;
 
@@ -6339,6 +6510,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;
 
@@ -6353,6 +6525,8 @@ process_version_sections (FILE *file)
                int isum;
 
                vstart = ((char *) edefs) + idx;
+               if (vstart + sizeof (*edef) > endbuf)
+                 break;
 
                edef = (Elf_External_Verdef *) vstart;
 
@@ -6390,6 +6564,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);
@@ -6401,9 +6577,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);
          }
@@ -6414,6 +6594,7 @@ process_version_sections (FILE *file)
            Elf_External_Verneed *eneed;
            unsigned int idx;
            unsigned int cnt;
+           char *endbuf;
 
            found = 1;
 
@@ -6432,6 +6613,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;
 
@@ -6444,6 +6626,8 @@ process_version_sections (FILE *file)
                char *vstart;
 
                vstart = ((char *) eneed) + idx;
+               if (vstart + sizeof (*entry) > endbuf)
+                 break;
 
                entry = (Elf_External_Verneed *) vstart;
 
@@ -6469,6 +6653,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);
@@ -6490,9 +6676,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);
          }
@@ -6637,7 +6827,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),
@@ -6689,7 +6882,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),
@@ -6757,6 +6953,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)
        {
@@ -6802,6 +7000,41 @@ get_symbol_visibility (unsigned int visibility)
     }
 }
 
+static const char *
+get_mips_symbol_other (unsigned int other)
+{
+  switch (other)
+    {
+    case STO_OPTIONAL:  return "OPTIONAL";
+    case STO_MIPS16:    return "MIPS16";
+    default:           return NULL;
+    }
+}
+
+static const char *
+get_symbol_other (unsigned int other)
+{
+  const char * result = NULL;
+  static char buff [32];
+
+  if (other == 0)
+    return "";
+
+  switch (elf_header.e_machine)
+    {
+    case EM_MIPS:
+      result = get_mips_symbol_other (other);
+    default:
+      break;
+    }
+
+  if (result)
+    return result;
+
+  snprintf (buff, sizeof buff, _("<other>: %x"), other);
+  return buff;
+}
+
 static const char *
 get_symbol_index_type (unsigned int type)
 {
@@ -6820,6 +7053,12 @@ get_symbol_index_type (unsigned int type)
       else if (elf_header.e_machine == EM_X86_64
               && type == SHN_X86_64_LCOMMON)
        return "LARGE_COM";
+      else if (type == SHN_MIPS_SCOMMON
+              && elf_header.e_machine == EM_MIPS)
+       return "SCOM";
+      else if (type == SHN_MIPS_SUNDEFINED
+              && elf_header.e_machine == EM_MIPS)
+       return "SUND";
       else if (type >= SHN_LOPROC && type <= SHN_HIPROC)
        sprintf (buff, "PRC[0x%04x]", type);
       else if (type >= SHN_LOOS && type <= SHN_HIOS)
@@ -6871,6 +7110,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)
@@ -6880,12 +7152,17 @@ process_symbol_table (FILE *file)
   bfd_vma nchains = 0;
   bfd_vma *buckets = NULL;
   bfd_vma *chains = NULL;
+  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];
@@ -6903,7 +7180,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;
        }
 
@@ -6929,60 +7206,168 @@ 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)));
-             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');
-           }
-       }
-    }
-  else if (do_syms && !do_using_dynamic)
-    {
-      unsigned int i;
+           if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
+             maxchain = gnubuckets[i];
+         }
 
-      for (i = 0, section = section_headers;
-          i < elf_header.e_shnum;
-          i++, section++)
-       {
-         unsigned int si;
-         char *strtab = NULL;
+      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;
+    }
+
+  if ((dynamic_info[DT_HASH] || dynamic_info_DT_GNU_HASH)
+      && do_syms
+      && do_using_dynamic
+      && dynamic_strings != NULL)
+    {
+      unsigned long hn;
+
+      if (dynamic_info[DT_HASH])
+       {
+         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"));
+
+         for (hn = 0; hn < nbuckets; hn++)
+           {
+             if (! buckets[hn])
+               continue;
+
+             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;
@@ -7031,6 +7416,11 @@ process_symbol_table (FILE *file)
              printf (" %-7s", 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 (" %4s ", get_symbol_index_type (psym->st_shndx));
              print_symbol (25, psym->st_name < strtab_size
                            ? strtab + psym->st_name : "<corrupt>");
@@ -7119,7 +7509,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;
                        }
@@ -7202,7 +7592,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)
@@ -7218,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;
        }
 
@@ -7249,6 +7639,70 @@ process_symbol_table (FILE *file)
       free (chains);
     }
 
+  if (do_histogram && dynamic_info_DT_GNU_HASH)
+    {
+      unsigned long *lengths;
+      unsigned long *counts;
+      unsigned long hn;
+      unsigned long maxlength = 0;
+      unsigned long nzero_counts = 0;
+      unsigned long nsyms = 0;
+
+      lengths = calloc (ngnubuckets, sizeof (*lengths));
+      if (lengths == NULL)
+       {
+         error (_("Out of memory\n"));
+         return 0;
+       }
+
+      printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"),
+             (unsigned long) ngnubuckets);
+      printf (_(" Length  Number     %% of total  Coverage\n"));
+
+      for (hn = 0; hn < ngnubuckets; ++hn)
+       if (gnubuckets[hn] != 0)
+         {
+           bfd_vma off, length = 1;
+
+           for (off = gnubuckets[hn] - gnusymidx;
+                (gnuchains[off] & 1) == 0; ++off)
+             ++length;
+           lengths[hn] = length;
+           if (length > maxlength)
+             maxlength = length;
+           nsyms += length;
+         }
+
+      counts = calloc (maxlength + 1, sizeof (*counts));
+      if (counts == NULL)
+       {
+         error (_("Out of memory\n"));
+         return 0;
+       }
+
+      for (hn = 0; hn < ngnubuckets; ++hn)
+       ++counts[lengths[hn]];
+
+      if (ngnubuckets > 0)
+       {
+         unsigned long j;
+         printf ("      0  %-10lu (%5.1f%%)\n",
+                 counts[0], (counts[0] * 100.0) / ngnubuckets);
+         for (j = 1; j <= maxlength; ++j)
+           {
+             nzero_counts += counts[j] * j;
+             printf ("%7lu  %-10lu (%5.1f%%)    %5.1f%%\n",
+                     j, counts[j], (counts[j] * 100.0) / ngnubuckets,
+                     (nzero_counts * 100.0) / nsyms);
+           }
+       }
+
+      free (counts);
+      free (lengths);
+      free (gnubuckets);
+      free (gnuchains);
+    }
+
   return 1;
 }
 
@@ -7332,8 +7786,90 @@ 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;
   bfd_vma addr;
   unsigned char *data;
@@ -7357,6 +7893,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)
@@ -7369,34 +7925,15 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
 
       printf ("  0x%8.8lx ", (unsigned long) addr);
 
-      switch (elf_header.e_ident[EI_DATA])
+      for (j = 0; j < 16; j++)
        {
-       default:
-       case ELFDATA2LSB:
-         for (j = 15; j >= 0; j --)
-           {
-             if (j < lbytes)
-               printf ("%2.2x", data[j]);
-             else
-               printf ("  ");
-
-             if (!(j & 0x3))
-               printf (" ");
-           }
-         break;
-
-       case ELFDATA2MSB:
-         for (j = 0; j < 16; j++)
-           {
-             if (j < lbytes)
-               printf ("%2.2x", data[j]);
-             else
-               printf ("  ");
+         if (j < lbytes)
+           printf ("%2.2x", data[j]);
+         else
+           printf ("  ");
 
-             if ((j & 3) == 3)
-               printf (" ");
-           }
-         break;
+         if ((j & 3) == 3)
+           printf (" ");
        }
 
       for (j = 0; j < lbytes; j++)
@@ -7417,3898 +7954,1116 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
 
   free (start);
 
+  putchar ('\n');
   return 1;
 }
 
+/* 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 long int
-read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
+static bfd_boolean
+is_32bit_abs_reloc (unsigned int reloc_type)
 {
-  unsigned long int result = 0;
-  unsigned int num_read = 0;
-  unsigned int shift = 0;
-  unsigned char byte;
-
-  do
+  switch (elf_header.e_machine)
     {
-      byte = *data++;
-      num_read++;
-
-      result |= ((unsigned long int) (byte & 0x7f)) << shift;
-
-      shift += 7;
+    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:
+      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 ();
     }
-  while (byte & 0x80);
-
-  if (length_return != NULL)
-    *length_return = num_read;
-
-  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
-    result |= -1L << shift;
-
-  return result;
 }
 
-typedef struct State_Machine_Registers
-{
-  unsigned long address;
-  unsigned int file;
-  unsigned int line;
-  unsigned int column;
-  int is_stmt;
-  int basic_block;
-  int end_sequence;
-/* This variable hold the number of the last entry seen
-   in the File Table.  */
-  unsigned int last_file_entry;
-} SMR;
-
-static SMR state_machine_regs;
-
-static void
-reset_state_machine (int is_stmt)
-{
-  state_machine_regs.address = 0;
-  state_machine_regs.file = 1;
-  state_machine_regs.line = 1;
-  state_machine_regs.column = 0;
-  state_machine_regs.is_stmt = is_stmt;
-  state_machine_regs.basic_block = 0;
-  state_machine_regs.end_sequence = 0;
-  state_machine_regs.last_file_entry = 0;
-}
+/* 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.  */
 
-/* Handled an extend line op.
-   Returns the number of bytes read.  */
-
-static int
-process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
+static bfd_boolean
+is_32bit_pcrel_reloc (unsigned int reloc_type)
 {
-  unsigned char op_code;
-  unsigned int bytes_read;
-  unsigned int len;
-  unsigned char *name;
-  unsigned long adr;
-
-  len = read_leb128 (data, & bytes_read, 0);
-  data += bytes_read;
-
-  if (len == 0)
-    {
-      warn (_("badly formed extended line op encountered!\n"));
-      return bytes_read;
-    }
-
-  len += bytes_read;
-  op_code = *data++;
-
-  printf (_("  Extended opcode %d: "), op_code);
-
-  switch (op_code)
+  switch (elf_header.e_machine)
     {
-    case DW_LNE_end_sequence:
-      printf (_("End of Sequence\n\n"));
-      reset_state_machine (is_stmt);
-      break;
-
-    case DW_LNE_set_address:
-      adr = byte_get (data, pointer_size);
-      printf (_("set Address to 0x%lx\n"), adr);
-      state_machine_regs.address = adr;
-      break;
-
-    case DW_LNE_define_file:
-      printf (_("  define new File Table entry\n"));
-      printf (_("  Entry\tDir\tTime\tSize\tName\n"));
-
-      printf (_("   %d\t"), ++state_machine_regs.last_file_entry);
-      name = data;
-      data += strlen ((char *) data) + 1;
-      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-      data += bytes_read;
-      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-      data += bytes_read;
-      printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-      printf (_("%s\n\n"), name);
-      break;
-
+    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:
-      printf (_("UNKNOWN: length %d\n"), len - bytes_read);
-      break;
+      /* 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;
     }
-
-  return len;
-}
-
-static const char *debug_str_contents;
-static bfd_vma debug_str_size;
-
-static void
-load_debug_str (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
-
-  /* If it is already loaded, do nothing.  */
-  if (debug_str_contents != NULL)
-    return;
-
-  /* Locate the .debug_str section.  */
-  sec = find_section (".debug_str");
-  if (sec == NULL)
-    return;
-
-  debug_str_size = sec->sh_size;
-
-  debug_str_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
-                                _("debug_str section data"));
 }
 
-static void
-free_debug_str (void)
-{
-  if (debug_str_contents == NULL)
-    return;
-
-  free ((char *) debug_str_contents);
-  debug_str_contents = NULL;
-  debug_str_size = 0;
-}
+/* 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 const char *
-fetch_indirect_string (unsigned long offset)
+static bfd_boolean
+is_64bit_abs_reloc (unsigned int reloc_type)
 {
-  if (debug_str_contents == NULL)
-    return _("<no .debug_str section>");
-
-  if (offset > debug_str_size)
+  switch (elf_header.e_machine)
     {
-      warn (_("DW_FORM_strp offset too big: %lx\n"), offset);
-      return _("<offset is too big>");
+    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;
     }
-
-  return debug_str_contents + offset;
-}
-
-static const char *debug_loc_contents;
-static bfd_vma debug_loc_size;
-
-static void
-load_debug_loc (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
-
-  /* If it is already loaded, do nothing.  */
-  if (debug_loc_contents != NULL)
-    return;
-
-  /* Locate the .debug_loc section.  */
-  sec = find_section (".debug_loc");
-  if (sec == NULL)
-    return;
-
-  debug_loc_size = sec->sh_size;
-
-  debug_loc_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
-                                _("debug_loc section data"));
-}
-
-static void
-free_debug_loc (void)
-{
-  if (debug_loc_contents == NULL)
-    return;
-
-  free ((char *) debug_loc_contents);
-  debug_loc_contents = NULL;
-  debug_loc_size = 0;
 }
 
-static const char *   debug_range_contents;
-static unsigned long  debug_range_size;
+/* 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 void
-load_debug_range (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
-
-  /* If it is already loaded, do nothing.  */
-  if (debug_range_contents != NULL)
-    return;
-
-  /* Locate the .debug_ranges section.  */
-  sec = find_section (".debug_ranges");
-  if (sec == NULL)
-    return;
-
-  debug_range_size = sec->sh_size;
-
-  debug_range_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
-                                  _("debug_range section data"));
-}
-
-static void
-free_debug_range (void)
+static bfd_boolean
+is_16bit_abs_reloc (unsigned int reloc_type)
 {
-  if (debug_range_contents == NULL)
-    return;
-
-  free ((char *) debug_range_contents);
-  debug_range_contents = NULL;
-  debug_range_size = 0;
+  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_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;
+    }
 }
 
-static unsigned char *debug_abbrev_contents;
-static unsigned long debug_abbrev_size;
+/* Apply relocations to a debug section.  */
 
 static void
-load_debug_abbrev (FILE *file)
-{
-  Elf_Internal_Shdr *sec;
-
-  /* If it is already loaded, do nothing.  */
-  if (debug_abbrev_contents != NULL)
-    return;
-
-  /* Locate the .debug_ranges section.  */
-  sec = find_section (".debug_abbrev");
-  if (sec == NULL)
-    return;
-
-  debug_abbrev_size = sec->sh_size;
-
-  debug_abbrev_contents = get_data (NULL, file, sec->sh_offset, 1,
-                                   sec->sh_size,
-                                   _("debug_abbrev section data"));
-}
-
-static void
-free_debug_abbrev (void)
-{
-  if (debug_abbrev_contents == NULL)
-    return;
-
-  free ((char *) debug_abbrev_contents);
-  debug_abbrev_contents = NULL;
-  debug_abbrev_size = 0;
-}
-
-/* Apply addends of RELA relocations.  */
-
-static int
-debug_apply_rela_addends (FILE *file,
-                         Elf_Internal_Shdr *section,
-                         int reloc_size,
-                         unsigned char *sec_data,
-                         unsigned char *start,
-                         unsigned char *end)
+debug_apply_relocations (void *file,
+                        Elf_Internal_Shdr *section,
+                        unsigned char *start)
 {
   Elf_Internal_Shdr *relsec;
+  unsigned char *end = start + section->sh_size;
 
-  if (end - start < reloc_size)
-    return 1;
+  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;
-
-         if (rp->r_offset >= (bfd_vma) (start - sec_data)
-             && rp->r_offset < (bfd_vma) (end - sec_data) - reloc_size)
-           loc = sec_data + rp->r_offset;
+      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
-           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 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;
-               }
+             warn (_("unable to apply unsupported reloc type %d to section %s\n"),
+                   reloc_type, SECTION_NAME (section));
+             continue;
            }
-         else
+
+         loc = start + rp->r_offset;
+         if ((loc + reloc_size) > end)
            {
-             /* 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_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 invalid relocation offset 0x%lx in section %s\n"),
+                   (unsigned long) rp->r_offset,
+                   SECTION_NAME (section));
+             continue;
+           }
+
+         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)
+           {
+             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;
 }
 
-/* FIXME:  There are better and more efficient ways to handle
-   these structures.  For now though, I just want something that
-   is simple to implement.  */
-typedef struct abbrev_attr
-{
-  unsigned long attribute;
-  unsigned long form;
-  struct abbrev_attr *next;
-}
-abbrev_attr;
-
-typedef struct abbrev_entry
-{
-  unsigned long entry;
-  unsigned long tag;
-  int children;
-  struct abbrev_attr *first_attr;
-  struct abbrev_attr *last_attr;
-  struct abbrev_entry *next;
-}
-abbrev_entry;
-
-static abbrev_entry *first_abbrev = NULL;
-static abbrev_entry *last_abbrev = NULL;
-
-static void
-free_abbrevs (void)
+int
+load_debug_section (enum dwarf_section_display_enum debug, void *file)
 {
-  abbrev_entry *abbrev;
+  struct dwarf_section *section = &debug_displays [debug].section;
+  Elf_Internal_Shdr *sec;
+  char buf [64];
 
-  for (abbrev = first_abbrev; abbrev;)
-    {
-      abbrev_entry *next = abbrev->next;
-      abbrev_attr *attr;
+  /* If it is already loaded, do nothing.  */
+  if (section->start != NULL)
+    return 1;
 
-      for (attr = abbrev->first_attr; attr;)
-       {
-         abbrev_attr *next = attr->next;
+  /* Locate the debug section.  */
+  sec = find_section (section->name);
+  if (sec == NULL)
+    return 0;
 
-         free (attr);
-         attr = next;
-       }
+  snprintf (buf, sizeof (buf), _("%s section data"), section->name);
+  section->address = sec->sh_addr;
+  section->size = sec->sh_size;
+  section->start = get_data (NULL, file, sec->sh_offset, 1,
+                            sec->sh_size, buf);
 
-      free (abbrev);
-      abbrev = next;
-    }
+  if (debug_displays [debug].relocate)
+    debug_apply_relocations (file, sec, section->start);
 
-  last_abbrev = first_abbrev = NULL;
+  return section->start != NULL;
 }
 
-static void
-add_abbrev (unsigned long number, unsigned long tag, int children)
+void
+free_debug_section (enum dwarf_section_display_enum debug)
 {
-  abbrev_entry *entry;
+  struct dwarf_section *section = &debug_displays [debug].section;
 
-  entry = malloc (sizeof (*entry));
-
-  if (entry == NULL)
-    /* ugg */
+  if (section->start == NULL)
     return;
 
-  entry->entry      = number;
-  entry->tag        = tag;
-  entry->children   = children;
-  entry->first_attr = NULL;
-  entry->last_attr  = NULL;
-  entry->next       = NULL;
-
-  if (first_abbrev == NULL)
-    first_abbrev = entry;
-  else
-    last_abbrev->next = entry;
-
-  last_abbrev = entry;
+  free ((char *) section->start);
+  section->start = NULL;
+  section->address = 0;
+  section->size = 0;
 }
 
-static void
-add_abbrev_attr (unsigned long attribute, unsigned long form)
+static int
+display_debug_section (Elf_Internal_Shdr *section, FILE *file)
 {
-  abbrev_attr *attr;
-
-  attr = malloc (sizeof (*attr));
+  char *name = SECTION_NAME (section);
+  bfd_size_type length;
+  int result = 1;
+  enum dwarf_section_display_enum i;
 
-  if (attr == NULL)
-    /* ugg */
-    return;
+  length = section->sh_size;
+  if (length == 0)
+    {
+      printf (_("\nSection '%s' has no debugging data.\n"), name);
+      return 0;
+    }
 
-  attr->attribute = attribute;
-  attr->form      = form;
-  attr->next      = NULL;
+  if (const_strneq (name, ".gnu.linkonce.wi."))
+    name = ".debug_info";
 
-  if (last_abbrev->first_attr == NULL)
-    last_abbrev->first_attr = attr;
-  else
-    last_abbrev->last_attr->next = attr;
+  /* See if we know how to display the contents of this section.  */
+  for (i = 0; i < max; i++)
+    if (streq (debug_displays[i].section.name, name))
+      {
+       struct dwarf_section *sec = &debug_displays [i].section;
 
-  last_abbrev->last_attr = attr;
-}
+       if (load_debug_section (i, file))
+         {
+           result &= debug_displays[i].display (sec, file);
 
-/* Processes the (partial) contents of a .debug_abbrev section.
-   Returns NULL if the end of the section was encountered.
-   Returns the address after the last byte read if the end of
-   an abbreviation set was found.  */
+           if (i != info && i != abbrev)
+             free_debug_section (i);
+         }
 
-static unsigned char *
-process_abbrev_section (unsigned char *start, unsigned char *end)
-{
-  if (first_abbrev != NULL)
-    return NULL;
+       break;
+      }
 
-  while (start < end)
+  if (i == max)
     {
-      unsigned int bytes_read;
-      unsigned long entry;
-      unsigned long tag;
-      unsigned long attribute;
-      int children;
-
-      entry = read_leb128 (start, & bytes_read, 0);
-      start += bytes_read;
-
-      /* A single zero is supposed to end the section according
-        to the standard.  If there's more, then signal that to
-        the caller.  */
-      if (entry == 0)
-       return start == end ? NULL : start;
-
-      tag = read_leb128 (start, & bytes_read, 0);
-      start += bytes_read;
+      printf (_("Unrecognized debug section: %s\n"), name);
+      result = 0;
+    }
 
-      children = *start++;
+  return result;
+}
 
-      add_abbrev (entry, tag, children);
+/* Set DUMP_SECTS for all sections where dumps were requested
+   based on section name.  */
 
-      do
-       {
-         unsigned long form;
+static void
+initialise_dumps_byname (void)
+{
+  struct dump_list_entry *cur;
 
-         attribute = read_leb128 (start, & bytes_read, 0);
-         start += bytes_read;
+  for (cur = dump_sects_byname; cur; cur = cur->next)
+    {
+      unsigned int i;
+      int any;
 
-         form = read_leb128 (start, & bytes_read, 0);
-         start += bytes_read;
+      for (i = 0, any = 0; i < elf_header.e_shnum; i++)
+       if (streq (SECTION_NAME (section_headers + i), cur->name))
+         {
+           request_dump_bynumber (i, cur->type);
+           any = 1;
+         }
 
-         if (attribute != 0)
-           add_abbrev_attr (attribute, form);
-       }
-      while (attribute != 0);
+      if (!any)
+       warn (_("Section '%s' was not dumped because it does not exist!\n"),
+             cur->name);
     }
-
-  return NULL;
 }
 
-static char *
-get_TAG_name (unsigned long tag)
-{
-  switch (tag)
-    {
-    case DW_TAG_padding:               return "DW_TAG_padding";
-    case DW_TAG_array_type:            return "DW_TAG_array_type";
-    case DW_TAG_class_type:            return "DW_TAG_class_type";
-    case DW_TAG_entry_point:           return "DW_TAG_entry_point";
-    case DW_TAG_enumeration_type:      return "DW_TAG_enumeration_type";
-    case DW_TAG_formal_parameter:      return "DW_TAG_formal_parameter";
-    case DW_TAG_imported_declaration:  return "DW_TAG_imported_declaration";
-    case DW_TAG_label:                 return "DW_TAG_label";
-    case DW_TAG_lexical_block:         return "DW_TAG_lexical_block";
-    case DW_TAG_member:                        return "DW_TAG_member";
-    case DW_TAG_pointer_type:          return "DW_TAG_pointer_type";
-    case DW_TAG_reference_type:                return "DW_TAG_reference_type";
-    case DW_TAG_compile_unit:          return "DW_TAG_compile_unit";
-    case DW_TAG_string_type:           return "DW_TAG_string_type";
-    case DW_TAG_structure_type:                return "DW_TAG_structure_type";
-    case DW_TAG_subroutine_type:       return "DW_TAG_subroutine_type";
-    case DW_TAG_typedef:               return "DW_TAG_typedef";
-    case DW_TAG_union_type:            return "DW_TAG_union_type";
-    case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters";
-    case DW_TAG_variant:               return "DW_TAG_variant";
-    case DW_TAG_common_block:          return "DW_TAG_common_block";
-    case DW_TAG_common_inclusion:      return "DW_TAG_common_inclusion";
-    case DW_TAG_inheritance:           return "DW_TAG_inheritance";
-    case DW_TAG_inlined_subroutine:    return "DW_TAG_inlined_subroutine";
-    case DW_TAG_module:                        return "DW_TAG_module";
-    case DW_TAG_ptr_to_member_type:    return "DW_TAG_ptr_to_member_type";
-    case DW_TAG_set_type:              return "DW_TAG_set_type";
-    case DW_TAG_subrange_type:         return "DW_TAG_subrange_type";
-    case DW_TAG_with_stmt:             return "DW_TAG_with_stmt";
-    case DW_TAG_access_declaration:    return "DW_TAG_access_declaration";
-    case DW_TAG_base_type:             return "DW_TAG_base_type";
-    case DW_TAG_catch_block:           return "DW_TAG_catch_block";
-    case DW_TAG_const_type:            return "DW_TAG_const_type";
-    case DW_TAG_constant:              return "DW_TAG_constant";
-    case DW_TAG_enumerator:            return "DW_TAG_enumerator";
-    case DW_TAG_file_type:             return "DW_TAG_file_type";
-    case DW_TAG_friend:                        return "DW_TAG_friend";
-    case DW_TAG_namelist:              return "DW_TAG_namelist";
-    case DW_TAG_namelist_item:         return "DW_TAG_namelist_item";
-    case DW_TAG_packed_type:           return "DW_TAG_packed_type";
-    case DW_TAG_subprogram:            return "DW_TAG_subprogram";
-    case DW_TAG_template_type_param:   return "DW_TAG_template_type_param";
-    case DW_TAG_template_value_param:  return "DW_TAG_template_value_param";
-    case DW_TAG_thrown_type:           return "DW_TAG_thrown_type";
-    case DW_TAG_try_block:             return "DW_TAG_try_block";
-    case DW_TAG_variant_part:          return "DW_TAG_variant_part";
-    case DW_TAG_variable:              return "DW_TAG_variable";
-    case DW_TAG_volatile_type:         return "DW_TAG_volatile_type";
-    case DW_TAG_MIPS_loop:             return "DW_TAG_MIPS_loop";
-    case DW_TAG_format_label:          return "DW_TAG_format_label";
-    case DW_TAG_function_template:     return "DW_TAG_function_template";
-    case DW_TAG_class_template:                return "DW_TAG_class_template";
-      /* DWARF 2.1 values.  */
-    case DW_TAG_dwarf_procedure:       return "DW_TAG_dwarf_procedure";
-    case DW_TAG_restrict_type:         return "DW_TAG_restrict_type";
-    case DW_TAG_interface_type:                return "DW_TAG_interface_type";
-    case DW_TAG_namespace:             return "DW_TAG_namespace";
-    case DW_TAG_imported_module:       return "DW_TAG_imported_module";
-    case DW_TAG_unspecified_type:      return "DW_TAG_unspecified_type";
-    case DW_TAG_partial_unit:          return "DW_TAG_partial_unit";
-    case DW_TAG_imported_unit:         return "DW_TAG_imported_unit";
-      /* UPC values.  */
-    case DW_TAG_upc_shared_type:       return "DW_TAG_upc_shared_type";
-    case DW_TAG_upc_strict_type:       return "DW_TAG_upc_strict_type";
-    case DW_TAG_upc_relaxed_type:      return "DW_TAG_upc_relaxed_type";
-    default:
-      {
-       static char buffer[100];
+static void
+process_section_contents (FILE *file)
+{
+  Elf_Internal_Shdr *section;
+  unsigned int i;
 
-       snprintf (buffer, sizeof (buffer), _("Unknown TAG value: %lx"), tag);
-       return buffer;
-      }
-    }
-}
+  if (! do_dump)
+    return;
 
-static char *
-get_FORM_name (unsigned long form)
-{
-  switch (form)
-    {
-    case DW_FORM_addr:         return "DW_FORM_addr";
-    case DW_FORM_block2:       return "DW_FORM_block2";
-    case DW_FORM_block4:       return "DW_FORM_block4";
-    case DW_FORM_data2:                return "DW_FORM_data2";
-    case DW_FORM_data4:                return "DW_FORM_data4";
-    case DW_FORM_data8:                return "DW_FORM_data8";
-    case DW_FORM_string:       return "DW_FORM_string";
-    case DW_FORM_block:                return "DW_FORM_block";
-    case DW_FORM_block1:       return "DW_FORM_block1";
-    case DW_FORM_data1:                return "DW_FORM_data1";
-    case DW_FORM_flag:         return "DW_FORM_flag";
-    case DW_FORM_sdata:                return "DW_FORM_sdata";
-    case DW_FORM_strp:         return "DW_FORM_strp";
-    case DW_FORM_udata:                return "DW_FORM_udata";
-    case DW_FORM_ref_addr:     return "DW_FORM_ref_addr";
-    case DW_FORM_ref1:         return "DW_FORM_ref1";
-    case DW_FORM_ref2:         return "DW_FORM_ref2";
-    case DW_FORM_ref4:         return "DW_FORM_ref4";
-    case DW_FORM_ref8:         return "DW_FORM_ref8";
-    case DW_FORM_ref_udata:    return "DW_FORM_ref_udata";
-    case DW_FORM_indirect:     return "DW_FORM_indirect";
-    default:
-      {
-       static char buffer[100];
+  initialise_dumps_byname ();
 
-       snprintf (buffer, sizeof (buffer), _("Unknown FORM value: %lx"), form);
-       return buffer;
-      }
-    }
-}
+  for (i = 0, section = section_headers;
+       i < elf_header.e_shnum && i < num_dump_sects;
+       i++, section++)
+    {
+#ifdef SUPPORT_DISASSEMBLY
+      if (dump_sects[i] & DISASS_DUMP)
+       disassemble_section (section, file);
+#endif
+      if (dump_sects[i] & HEX_DUMP)
+       dump_section_as_bytes (section, file);
 
-static unsigned char *
-display_block (unsigned char *data, unsigned long length)
-{
-  printf (_(" %lu byte block: "), length);
+      if (dump_sects[i] & DEBUG_DUMP)
+       display_debug_section (section, file);
 
-  while (length --)
-    printf ("%lx ", (unsigned long) byte_get (data++, 1));
+      if (dump_sects[i] & STRING_DUMP)
+       dump_section_as_strings (section, file);
+    }
 
-  return data;
+  /* Check to see if the user requested a
+     dump of a section that does not exist.  */
+  while (i++ < num_dump_sects)
+    if (dump_sects[i])
+      warn (_("Section %d was not dumped because it does not exist!\n"), i);
 }
 
-static int
-decode_location_expression (unsigned char * data,
-                           unsigned int pointer_size,
-                           unsigned long length,
-                           unsigned long cu_offset)
+static void
+process_mips_fpe_exception (int mask)
 {
-  unsigned op;
-  unsigned int bytes_read;
-  unsigned long uvalue;
-  unsigned char *end = data + length;
-  int need_frame_base = 0;
-
-  while (data < end)
+  if (mask)
     {
-      op = *data++;
+      int first = 1;
+      if (mask & OEX_FPU_INEX)
+       fputs ("INEX", stdout), first = 0;
+      if (mask & OEX_FPU_UFLO)
+       printf ("%sUFLO", first ? "" : "|"), first = 0;
+      if (mask & OEX_FPU_OFLO)
+       printf ("%sOFLO", first ? "" : "|"), first = 0;
+      if (mask & OEX_FPU_DIV0)
+       printf ("%sDIV0", first ? "" : "|"), first = 0;
+      if (mask & OEX_FPU_INVAL)
+       printf ("%sINVAL", first ? "" : "|");
+    }
+  else
+    fputs ("0", stdout);
+}
 
-      switch (op)
-       {
-       case DW_OP_addr:
-         printf ("DW_OP_addr: %lx",
-                 (unsigned long) byte_get (data, pointer_size));
-         data += pointer_size;
-         break;
-       case DW_OP_deref:
-         printf ("DW_OP_deref");
-         break;
-       case DW_OP_const1u:
-         printf ("DW_OP_const1u: %lu", (unsigned long) byte_get (data++, 1));
-         break;
-       case DW_OP_const1s:
-         printf ("DW_OP_const1s: %ld", (long) byte_get_signed (data++, 1));
-         break;
-       case DW_OP_const2u:
-         printf ("DW_OP_const2u: %lu", (unsigned long) byte_get (data, 2));
-         data += 2;
-         break;
-       case DW_OP_const2s:
-         printf ("DW_OP_const2s: %ld", (long) byte_get_signed (data, 2));
-         data += 2;
-         break;
-       case DW_OP_const4u:
-         printf ("DW_OP_const4u: %lu", (unsigned long) byte_get (data, 4));
-         data += 4;
-         break;
-       case DW_OP_const4s:
-         printf ("DW_OP_const4s: %ld", (long) byte_get_signed (data, 4));
-         data += 4;
-         break;
-       case DW_OP_const8u:
-         printf ("DW_OP_const8u: %lu %lu", (unsigned long) byte_get (data, 4),
-                 (unsigned long) byte_get (data + 4, 4));
-         data += 8;
-         break;
-       case DW_OP_const8s:
-         printf ("DW_OP_const8s: %ld %ld", (long) byte_get (data, 4),
-                 (long) byte_get (data + 4, 4));
-         data += 8;
-         break;
-       case DW_OP_constu:
-         printf ("DW_OP_constu: %lu", read_leb128 (data, &bytes_read, 0));
-         data += bytes_read;
-         break;
-       case DW_OP_consts:
-         printf ("DW_OP_consts: %ld", read_leb128 (data, &bytes_read, 1));
-         data += bytes_read;
-         break;
-       case DW_OP_dup:
-         printf ("DW_OP_dup");
-         break;
-       case DW_OP_drop:
-         printf ("DW_OP_drop");
-         break;
-       case DW_OP_over:
-         printf ("DW_OP_over");
-         break;
-       case DW_OP_pick:
-         printf ("DW_OP_pick: %ld", (unsigned long) byte_get (data++, 1));
-         break;
-       case DW_OP_swap:
-         printf ("DW_OP_swap");
-         break;
-       case DW_OP_rot:
-         printf ("DW_OP_rot");
-         break;
-       case DW_OP_xderef:
-         printf ("DW_OP_xderef");
-         break;
-       case DW_OP_abs:
-         printf ("DW_OP_abs");
-         break;
-       case DW_OP_and:
-         printf ("DW_OP_and");
-         break;
-       case DW_OP_div:
-         printf ("DW_OP_div");
-         break;
-       case DW_OP_minus:
-         printf ("DW_OP_minus");
-         break;
-       case DW_OP_mod:
-         printf ("DW_OP_mod");
-         break;
-       case DW_OP_mul:
-         printf ("DW_OP_mul");
-         break;
-       case DW_OP_neg:
-         printf ("DW_OP_neg");
-         break;
-       case DW_OP_not:
-         printf ("DW_OP_not");
-         break;
-       case DW_OP_or:
-         printf ("DW_OP_or");
-         break;
-       case DW_OP_plus:
-         printf ("DW_OP_plus");
-         break;
-       case DW_OP_plus_uconst:
-         printf ("DW_OP_plus_uconst: %lu",
-                 read_leb128 (data, &bytes_read, 0));
-         data += bytes_read;
-         break;
-       case DW_OP_shl:
-         printf ("DW_OP_shl");
-         break;
-       case DW_OP_shr:
-         printf ("DW_OP_shr");
-         break;
-       case DW_OP_shra:
-         printf ("DW_OP_shra");
-         break;
-       case DW_OP_xor:
-         printf ("DW_OP_xor");
-         break;
-       case DW_OP_bra:
-         printf ("DW_OP_bra: %ld", (long) byte_get_signed (data, 2));
-         data += 2;
-         break;
-       case DW_OP_eq:
-         printf ("DW_OP_eq");
-         break;
-       case DW_OP_ge:
-         printf ("DW_OP_ge");
-         break;
-       case DW_OP_gt:
-         printf ("DW_OP_gt");
-         break;
-       case DW_OP_le:
-         printf ("DW_OP_le");
-         break;
-       case DW_OP_lt:
-         printf ("DW_OP_lt");
-         break;
-       case DW_OP_ne:
-         printf ("DW_OP_ne");
-         break;
-       case DW_OP_skip:
-         printf ("DW_OP_skip: %ld", (long) byte_get_signed (data, 2));
-         data += 2;
-         break;
-
-       case DW_OP_lit0:
-       case DW_OP_lit1:
-       case DW_OP_lit2:
-       case DW_OP_lit3:
-       case DW_OP_lit4:
-       case DW_OP_lit5:
-       case DW_OP_lit6:
-       case DW_OP_lit7:
-       case DW_OP_lit8:
-       case DW_OP_lit9:
-       case DW_OP_lit10:
-       case DW_OP_lit11:
-       case DW_OP_lit12:
-       case DW_OP_lit13:
-       case DW_OP_lit14:
-       case DW_OP_lit15:
-       case DW_OP_lit16:
-       case DW_OP_lit17:
-       case DW_OP_lit18:
-       case DW_OP_lit19:
-       case DW_OP_lit20:
-       case DW_OP_lit21:
-       case DW_OP_lit22:
-       case DW_OP_lit23:
-       case DW_OP_lit24:
-       case DW_OP_lit25:
-       case DW_OP_lit26:
-       case DW_OP_lit27:
-       case DW_OP_lit28:
-       case DW_OP_lit29:
-       case DW_OP_lit30:
-       case DW_OP_lit31:
-         printf ("DW_OP_lit%d", op - DW_OP_lit0);
-         break;
-
-       case DW_OP_reg0:
-       case DW_OP_reg1:
-       case DW_OP_reg2:
-       case DW_OP_reg3:
-       case DW_OP_reg4:
-       case DW_OP_reg5:
-       case DW_OP_reg6:
-       case DW_OP_reg7:
-       case DW_OP_reg8:
-       case DW_OP_reg9:
-       case DW_OP_reg10:
-       case DW_OP_reg11:
-       case DW_OP_reg12:
-       case DW_OP_reg13:
-       case DW_OP_reg14:
-       case DW_OP_reg15:
-       case DW_OP_reg16:
-       case DW_OP_reg17:
-       case DW_OP_reg18:
-       case DW_OP_reg19:
-       case DW_OP_reg20:
-       case DW_OP_reg21:
-       case DW_OP_reg22:
-       case DW_OP_reg23:
-       case DW_OP_reg24:
-       case DW_OP_reg25:
-       case DW_OP_reg26:
-       case DW_OP_reg27:
-       case DW_OP_reg28:
-       case DW_OP_reg29:
-       case DW_OP_reg30:
-       case DW_OP_reg31:
-         printf ("DW_OP_reg%d", op - DW_OP_reg0);
-         break;
-
-       case DW_OP_breg0:
-       case DW_OP_breg1:
-       case DW_OP_breg2:
-       case DW_OP_breg3:
-       case DW_OP_breg4:
-       case DW_OP_breg5:
-       case DW_OP_breg6:
-       case DW_OP_breg7:
-       case DW_OP_breg8:
-       case DW_OP_breg9:
-       case DW_OP_breg10:
-       case DW_OP_breg11:
-       case DW_OP_breg12:
-       case DW_OP_breg13:
-       case DW_OP_breg14:
-       case DW_OP_breg15:
-       case DW_OP_breg16:
-       case DW_OP_breg17:
-       case DW_OP_breg18:
-       case DW_OP_breg19:
-       case DW_OP_breg20:
-       case DW_OP_breg21:
-       case DW_OP_breg22:
-       case DW_OP_breg23:
-       case DW_OP_breg24:
-       case DW_OP_breg25:
-       case DW_OP_breg26:
-       case DW_OP_breg27:
-       case DW_OP_breg28:
-       case DW_OP_breg29:
-       case DW_OP_breg30:
-       case DW_OP_breg31:
-         printf ("DW_OP_breg%d: %ld", op - DW_OP_breg0,
-                 read_leb128 (data, &bytes_read, 1));
-         data += bytes_read;
-         break;
-
-       case DW_OP_regx:
-         printf ("DW_OP_regx: %lu", read_leb128 (data, &bytes_read, 0));
-         data += bytes_read;
-         break;
-       case DW_OP_fbreg:
-         need_frame_base = 1;
-         printf ("DW_OP_fbreg: %ld", read_leb128 (data, &bytes_read, 1));
-         data += bytes_read;
-         break;
-       case DW_OP_bregx:
-         uvalue = read_leb128 (data, &bytes_read, 0);
-         data += bytes_read;
-         printf ("DW_OP_bregx: %lu %ld", uvalue,
-                 read_leb128 (data, &bytes_read, 1));
-         data += bytes_read;
-         break;
-       case DW_OP_piece:
-         printf ("DW_OP_piece: %lu", read_leb128 (data, &bytes_read, 0));
-         data += bytes_read;
-         break;
-       case DW_OP_deref_size:
-         printf ("DW_OP_deref_size: %ld", (long) byte_get (data++, 1));
-         break;
-       case DW_OP_xderef_size:
-         printf ("DW_OP_xderef_size: %ld", (long) byte_get (data++, 1));
-         break;
-       case DW_OP_nop:
-         printf ("DW_OP_nop");
-         break;
-
-         /* DWARF 3 extensions.  */
-       case DW_OP_push_object_address:
-         printf ("DW_OP_push_object_address");
-         break;
-       case DW_OP_call2:
-         /* XXX: Strictly speaking for 64-bit DWARF3 files
-            this ought to be an 8-byte wide computation.  */
-         printf ("DW_OP_call2: <%lx>", (long) byte_get (data, 2) + cu_offset);
-         data += 2;
-         break;
-       case DW_OP_call4:
-         /* XXX: Strictly speaking for 64-bit DWARF3 files
-            this ought to be an 8-byte wide computation.  */
-         printf ("DW_OP_call4: <%lx>", (long) byte_get (data, 4) + cu_offset);
-         data += 4;
-         break;
-       case DW_OP_call_ref:
-         printf ("DW_OP_call_ref");
-         break;
-
-         /* GNU extensions.  */
-       case DW_OP_GNU_push_tls_address:
-         printf ("DW_OP_GNU_push_tls_address");
-         break;
+/* ARM EABI attributes section.  */
+typedef struct
+{
+  int tag;
+  const char *name;
+  /* 0 = special, 1 = string, 2 = uleb123, > 0x80 == table lookup.  */
+  int type;
+  const char **table;
+} arm_attr_public_tag;
+
+static const char *arm_attr_tag_CPU_arch[] =
+  {"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2",
+   "v6K", "v7"};
+static const char *arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"};
+static const char *arm_attr_tag_THUMB_ISA_use[] =
+  {"No", "Thumb-1", "Thumb-2"};
+/* FIXME: VFPv3 encoding was extrapolated!  */
+static const char *arm_attr_tag_VFP_arch[] = {"No", "VFPv1", "VFPv2", "VFPv3"};
+static const char *arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1"};
+static const char *arm_attr_tag_NEON_arch[] = {"No", "NEONv1"};
+static const char *arm_attr_tag_ABI_PCS_config[] =
+  {"None", "Bare platform", "Linux application", "Linux DSO", "PalmOS 2004",
+   "PalmOS (reserved)", "SymbianOS 2004", "SymbianOS (reserved)"};
+static const char *arm_attr_tag_ABI_PCS_R9_use[] =
+  {"V6", "SB", "TLS", "Unused"};
+static const char *arm_attr_tag_ABI_PCS_RW_data[] =
+  {"Absolute", "PC-relative", "SB-relative", "None"};
+static const char *arm_attr_tag_ABI_PCS_RO_DATA[] =
+  {"Absolute", "PC-relative", "None"};
+static const char *arm_attr_tag_ABI_PCS_GOT_use[] =
+  {"None", "direct", "GOT-indirect"};
+static const char *arm_attr_tag_ABI_PCS_wchar_t[] =
+  {"None", "??? 1", "2", "??? 3", "4"};
+static const char *arm_attr_tag_ABI_FP_rounding[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_denormal[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_exceptions[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_user_exceptions[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_number_model[] =
+  {"Unused", "Finite", "RTABI", "IEEE 754"};
+static const char *arm_attr_tag_ABI_align8_needed[] = {"No", "Yes", "4-byte"};
+static const char *arm_attr_tag_ABI_align8_preserved[] =
+  {"No", "Yes, except leaf SP", "Yes"};
+static const char *arm_attr_tag_ABI_enum_size[] =
+  {"Unused", "small", "int", "forced to int"};
+static const char *arm_attr_tag_ABI_HardFP_use[] =
+  {"As Tag_VFP_arch", "SP only", "DP only", "SP and DP"};
+static const char *arm_attr_tag_ABI_VFP_args[] =
+  {"AAPCS", "VFP registers", "custom"};
+static const char *arm_attr_tag_ABI_WMMX_args[] =
+  {"AAPCS", "WMMX registers", "custom"};
+static const char *arm_attr_tag_ABI_optimization_goals[] =
+  {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size",
+    "Aggressive Size", "Prefer Debug", "Aggressive Debug"};
+static const char *arm_attr_tag_ABI_FP_optimization_goals[] =
+  {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size",
+    "Aggressive Size", "Prefer Accuracy", "Aggressive Accuracy"};
+
+#define LOOKUP(id, name) \
+  {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name}
+static arm_attr_public_tag arm_attr_public_tags[] =
+{
+  {4, "CPU_raw_name", 1, NULL},
+  {5, "CPU_name", 1, NULL},
+  LOOKUP(6, CPU_arch),
+  {7, "CPU_arch_profile", 0, NULL},
+  LOOKUP(8, ARM_ISA_use),
+  LOOKUP(9, THUMB_ISA_use),
+  LOOKUP(10, VFP_arch),
+  LOOKUP(11, WMMX_arch),
+  LOOKUP(12, NEON_arch),
+  LOOKUP(13, ABI_PCS_config),
+  LOOKUP(14, ABI_PCS_R9_use),
+  LOOKUP(15, ABI_PCS_RW_data),
+  LOOKUP(16, ABI_PCS_RO_DATA),
+  LOOKUP(17, ABI_PCS_GOT_use),
+  LOOKUP(18, ABI_PCS_wchar_t),
+  LOOKUP(19, ABI_FP_rounding),
+  LOOKUP(20, ABI_FP_denormal),
+  LOOKUP(21, ABI_FP_exceptions),
+  LOOKUP(22, ABI_FP_user_exceptions),
+  LOOKUP(23, ABI_FP_number_model),
+  LOOKUP(24, ABI_align8_needed),
+  LOOKUP(25, ABI_align8_preserved),
+  LOOKUP(26, ABI_enum_size),
+  LOOKUP(27, ABI_HardFP_use),
+  LOOKUP(28, ABI_VFP_args),
+  LOOKUP(29, ABI_WMMX_args),
+  LOOKUP(30, ABI_optimization_goals),
+  LOOKUP(31, ABI_FP_optimization_goals),
+  {32, "compatibility", 0, NULL}
+};
+#undef LOOKUP
 
-       default:
-         if (op >= DW_OP_lo_user
-             && op <= DW_OP_hi_user)
-           printf (_("(User defined location op)"));
-         else
-           printf (_("(Unknown location op)"));
-         /* No way to tell where the next op is, so just bail.  */
-         return need_frame_base;
-       }
+/* Read an unsigned LEB128 encoded value from p.  Set *PLEN to the number of
+   bytes read.  */
+static unsigned int
+read_uleb128 (unsigned char *p, unsigned int *plen)
+{
+  unsigned char c;
+  unsigned int val;
+  int shift;
+  int len;
 
-      /* Separate the ops.  */
-      if (data < end)
-       printf ("; ");
+  val = 0;
+  shift = 0;
+  len = 0;
+  do
+    {
+      c = *(p++);
+      len++;
+      val |= ((unsigned int)c & 0x7f) << shift;
+      shift += 7;
     }
+  while (c & 0x80);
 
-  return need_frame_base;
+  *plen = len;
+  return val;
 }
 
-/* This structure records the information that
-   we extract from the.debug_info section.  */
-typedef struct
+static unsigned char *
+display_arm_attribute (unsigned char *p)
 {
-  unsigned int   pointer_size;
-  unsigned long  cu_offset;
-  unsigned long         base_address;
-  /* This is an array of offsets to the location list table.  */
-  unsigned long *loc_offsets;
-  int          *have_frame_base;
-  unsigned int   num_loc_offsets;
-  unsigned int   max_loc_offsets;
-  unsigned long *range_lists;
-  unsigned int   num_range_lists;
-  unsigned int   max_range_lists;
-}
-debug_info;
-
-static debug_info *   debug_information = NULL;
-static unsigned int   num_debug_info_entries = 0;
-static unsigned int   last_pointer_size = 0;
-static int            warned_about_missing_comp_units = FALSE;
+  int tag;
+  unsigned int len;
+  int val;
+  arm_attr_public_tag *attr;
+  unsigned i;
+  int type;
 
-static unsigned char *
-read_and_display_attr_value (unsigned long attribute,
-                            unsigned long form,
-                            unsigned char *data,
-                            unsigned long cu_offset,
-                            unsigned long pointer_size,
-                            unsigned long offset_size,
-                            int dwarf_version,
-                            debug_info *debug_info_p,
-                            int do_loc)
-{
-  unsigned long uvalue = 0;
-  unsigned char *block_start = NULL;
-  unsigned int bytes_read;
-
-  switch (form)
+  tag = read_uleb128 (p, &len);
+  p += len;
+  attr = NULL;
+  for (i = 0; i < ARRAY_SIZE(arm_attr_public_tags); i++)
     {
-    default:
-      break;
-
-    case DW_FORM_ref_addr:
-      if (dwarf_version == 2)
-       {
-         uvalue = byte_get (data, pointer_size);
-         data += pointer_size;
-       }
-      else if (dwarf_version == 3)
-       {
-         uvalue = byte_get (data, offset_size);
-         data += offset_size;
-       }
-      else
+      if (arm_attr_public_tags[i].tag == tag)
        {
-         error (_("Internal error: DWARF version is not 2 or 3.\n"));
+         attr = &arm_attr_public_tags[i];
+         break;
        }
-      break;
-
-    case DW_FORM_addr:
-      uvalue = byte_get (data, pointer_size);
-      data += pointer_size;
-      break;
-
-    case DW_FORM_strp:
-      uvalue = byte_get (data, offset_size);
-      data += offset_size;
-      break;
-
-    case DW_FORM_ref1:
-    case DW_FORM_flag:
-    case DW_FORM_data1:
-      uvalue = byte_get (data++, 1);
-      break;
-
-    case DW_FORM_ref2:
-    case DW_FORM_data2:
-      uvalue = byte_get (data, 2);
-      data += 2;
-      break;
-
-    case DW_FORM_ref4:
-    case DW_FORM_data4:
-      uvalue = byte_get (data, 4);
-      data += 4;
-      break;
-
-    case DW_FORM_sdata:
-      uvalue = read_leb128 (data, & bytes_read, 1);
-      data += bytes_read;
-      break;
-
-    case DW_FORM_ref_udata:
-    case DW_FORM_udata:
-      uvalue = read_leb128 (data, & bytes_read, 0);
-      data += bytes_read;
-      break;
-
-    case DW_FORM_indirect:
-      form = read_leb128 (data, & bytes_read, 0);
-      data += bytes_read;
-      if (!do_loc)
-       printf (" %s", get_FORM_name (form));
-      return read_and_display_attr_value (attribute, form, data,
-                                         cu_offset, pointer_size,
-                                         offset_size, dwarf_version,
-                                         debug_info_p, do_loc);
     }
 
-  switch (form)
+  if (attr)
     {
-    case DW_FORM_ref_addr:
-      if (!do_loc)
-       printf (" <#%lx>", uvalue);
-      break;
+      printf ("  Tag_%s: ", attr->name);
+      switch (attr->type)
+       {
+       case 0:
+         switch (tag)
+           {
+           case 7: /* Tag_CPU_arch_profile.  */
+             val = read_uleb128 (p, &len);
+             p += len;
+             switch (val)
+               {
+               case 0: printf ("None\n"); break;
+               case 'A': printf ("Application\n"); break;
+               case 'R': printf ("Realtime\n"); break;
+               case 'M': printf ("Microcontroller\n"); break;
+               default: printf ("??? (%d)\n", val); break;
+               }
+             break;
 
-    case DW_FORM_ref1:
-    case DW_FORM_ref2:
-    case DW_FORM_ref4:
-    case DW_FORM_ref_udata:
-      if (!do_loc)
-       printf (" <%lx>", uvalue + cu_offset);
-      break;
+           case 32: /* Tag_compatibility.  */
+             val = read_uleb128 (p, &len);
+             p += len;
+             printf ("flag = %d, vendor = %s\n", val, p);
+             p += strlen((char *)p) + 1;
+             break;
 
-    case DW_FORM_data4:
-    case DW_FORM_addr:
-      if (!do_loc)
-       printf (" %#lx", uvalue);
-      break;
+           default:
+             abort();
+           }
+         return p;
 
-    case DW_FORM_flag:
-    case DW_FORM_data1:
-    case DW_FORM_data2:
-    case DW_FORM_sdata:
-    case DW_FORM_udata:
-      if (!do_loc)
-       printf (" %ld", uvalue);
-      break;
+       case 1:
+       case 2:
+         type = attr->type;
+         break;
 
-    case DW_FORM_ref8:
-    case DW_FORM_data8:
-      if (!do_loc)
-       {
-         uvalue = byte_get (data, 4);
-         printf (" %lx", uvalue);
-         printf (" %lx", (unsigned long) byte_get (data + 4, 4));
-       }
-      if ((do_loc || do_debug_loc || do_debug_ranges)
-         && num_debug_info_entries == 0)
-       {
-         if (sizeof (uvalue) == 8)
-           uvalue = byte_get (data, 8);
+       default:
+         assert (attr->type & 0x80);
+         val = read_uleb128 (p, &len);
+         p += len;
+         type = attr->type & 0x7f;
+         if (val >= type)
+           printf ("??? (%d)\n", val);
          else
-           error (_("DW_FORM_data8 is unsupported when sizeof (unsigned long) != 8\n"));
+           printf ("%s\n", attr->table[val]);
+         return p;
        }
-      data += 8;
-      break;
-
-    case DW_FORM_string:
-      if (!do_loc)
-       printf (" %s", data);
-      data += strlen ((char *) data) + 1;
-      break;
-
-    case DW_FORM_block:
-      uvalue = read_leb128 (data, & bytes_read, 0);
-      block_start = data + bytes_read;
-      if (do_loc)
-       data = block_start + uvalue;
-      else
-       data = display_block (block_start, uvalue);
-      break;
-
-    case DW_FORM_block1:
-      uvalue = byte_get (data, 1);
-      block_start = data + 1;
-      if (do_loc)
-       data = block_start + uvalue;
+    }
+  else
+    {
+      if (tag & 1)
+       type = 1; /* String.  */
       else
-       data = display_block (block_start, uvalue);
-      break;
+       type = 2; /* uleb128.  */
+      printf ("  Tag_unknown_%d: ", tag);
+    }
 
-    case DW_FORM_block2:
-      uvalue = byte_get (data, 2);
-      block_start = data + 2;
-      if (do_loc)
-       data = block_start + uvalue;
-      else
-       data = display_block (block_start, uvalue);
-      break;
+  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);
+    }
 
-    case DW_FORM_block4:
-      uvalue = byte_get (data, 4);
-      block_start = data + 4;
-      if (do_loc)
-       data = block_start + uvalue;
-      else
-       data = display_block (block_start, uvalue);
-      break;
+  return p;
+}
 
-    case DW_FORM_strp:
-      if (!do_loc)
-       printf (_(" (indirect string, offset: 0x%lx): %s"),
-               uvalue, fetch_indirect_string (uvalue));
-      break;
+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;
 
-    case DW_FORM_indirect:
-      /* Handled above.  */
-      break;
+  tag = read_uleb128 (p, &len);
+  p += len;
 
-    default:
-      warn (_("Unrecognized form: %lu\n"), form);
-      break;
+  /* 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;
     }
 
-  /* For some attributes we can display further information.  */
-  if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
-    {
-      switch (attribute)
-       {
-       case DW_AT_frame_base:
-         have_frame_base = 1;
-       case DW_AT_location:
-       case DW_AT_data_member_location:
-       case DW_AT_vtable_elem_location:
-       case DW_AT_allocated:
-       case DW_AT_associated:
-       case DW_AT_data_location:
-       case DW_AT_stride:
-       case DW_AT_upper_bound:
-       case DW_AT_lower_bound:
-         if (form == DW_FORM_data4 || form == DW_FORM_data8)
-           {
-             /* Process location list.  */
-             unsigned int max = debug_info_p->max_loc_offsets;
-             unsigned int num = debug_info_p->num_loc_offsets;
-
-             if (max == 0 || num >= max)
-               {
-                 max += 1024;
-                 debug_info_p->loc_offsets
-                   = xcrealloc (debug_info_p->loc_offsets,
-                                max, sizeof (*debug_info_p->loc_offsets));
-                 debug_info_p->have_frame_base
-                   = xcrealloc (debug_info_p->have_frame_base,
-                                max, sizeof (*debug_info_p->have_frame_base));
-                 debug_info_p->max_loc_offsets = max;
-               }
-             debug_info_p->loc_offsets [num] = uvalue;
-             debug_info_p->have_frame_base [num] = have_frame_base;
-             debug_info_p->num_loc_offsets++;
-           }
-         break;
-       
-       case DW_AT_low_pc:
-         if (need_base_address)
-           debug_info_p->base_address = uvalue;
-         break;
-
-       case DW_AT_ranges:
-         if (form == DW_FORM_data4 || form == DW_FORM_data8)
-           {
-             /* Process range list.  */
-             unsigned int max = debug_info_p->max_range_lists;
-             unsigned int num = debug_info_p->num_range_lists;
+  if ((tag & 2) == 0 && display_proc_gnu_attribute)
+    return display_proc_gnu_attribute (p, tag);
 
-             if (max == 0 || num >= max)
-               {
-                 max += 1024;
-                 debug_info_p->range_lists
-                   = xcrealloc (debug_info_p->range_lists,
-                                max, sizeof (*debug_info_p->range_lists));
-                 debug_info_p->max_range_lists = max;
-               }
-             debug_info_p->range_lists [num] = uvalue;
-             debug_info_p->num_range_lists++;
-           }
-         break;
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
 
-       default:
-         break;
-       }
+  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);
     }
 
-  if (do_loc)
-    return data;
+  return p;
+}
 
-  printf ("\t");
+static unsigned char *
+display_power_gnu_attribute (unsigned char *p, int tag)
+{
+  int type;
+  unsigned int len;
+  int val;
 
-  switch (attribute)
+  if (tag == Tag_GNU_Power_ABI_FP)
     {
-    case DW_AT_inline:
-      switch (uvalue)
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_Power_ABI_FP: ");
+
+      switch (val)
        {
-       case DW_INL_not_inlined:
-         printf (_("(not inlined)"));
-         break;
-       case DW_INL_inlined:
-         printf (_("(inlined)"));
+       case 0:
+         printf ("Hard or soft float\n");
          break;
-       case DW_INL_declared_not_inlined:
-         printf (_("(declared as inline but ignored)"));
+       case 1:
+         printf ("Hard float\n");
          break;
-       case DW_INL_declared_inlined:
-         printf (_("(declared as inline and inlined)"));
+       case 2:
+         printf ("Soft float\n");
          break;
        default:
-         printf (_("  (Unknown inline attribute value: %lx)"), uvalue);
+         printf ("??? (%d)\n", val);
          break;
        }
-      break;
+      return p;
+   }
 
-    case DW_AT_language:
-      switch (uvalue)
-       {
-       case DW_LANG_C:                 printf ("(non-ANSI C)"); break;
-       case DW_LANG_C89:               printf ("(ANSI C)"); break;
-       case DW_LANG_C_plus_plus:       printf ("(C++)"); break;
-       case DW_LANG_Fortran77:         printf ("(FORTRAN 77)"); break;
-       case DW_LANG_Fortran90:         printf ("(Fortran 90)"); break;
-       case DW_LANG_Modula2:           printf ("(Modula 2)"); break;
-       case DW_LANG_Pascal83:          printf ("(ANSI Pascal)"); break;
-       case DW_LANG_Ada83:             printf ("(Ada)"); break;
-       case DW_LANG_Cobol74:           printf ("(Cobol 74)"); break;
-       case DW_LANG_Cobol85:           printf ("(Cobol 85)"); break;
-         /* DWARF 2.1 values.  */
-       case DW_LANG_C99:               printf ("(ANSI C99)"); break;
-       case DW_LANG_Ada95:             printf ("(ADA 95)"); break;
-       case DW_LANG_Fortran95:         printf ("(Fortran 95)"); break;
-         /* MIPS extension.  */
-       case DW_LANG_Mips_Assembler:    printf ("(MIPS assembler)"); break;
-         /* UPC extension.  */
-       case DW_LANG_Upc:               printf ("(Unified Parallel C)"); break;
-       default:
-         printf ("(Unknown: %lx)", uvalue);
+  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;
-       }
-      break;
-
-    case DW_AT_encoding:
-      switch (uvalue)
-       {
-       case DW_ATE_void:               printf ("(void)"); break;
-       case DW_ATE_address:            printf ("(machine address)"); break;
-       case DW_ATE_boolean:            printf ("(boolean)"); break;
-       case DW_ATE_complex_float:      printf ("(complex float)"); break;
-       case DW_ATE_float:              printf ("(float)"); break;
-       case DW_ATE_signed:             printf ("(signed)"); break;
-       case DW_ATE_signed_char:        printf ("(signed char)"); break;
-       case DW_ATE_unsigned:           printf ("(unsigned)"); break;
-       case DW_ATE_unsigned_char:      printf ("(unsigned char)"); break;
-         /* DWARF 2.1 value.  */
-       case DW_ATE_imaginary_float:    printf ("(imaginary float)"); break;
-       case DW_ATE_decimal_float:      printf ("(decimal float)"); break;
-       default:
-         if (uvalue >= DW_ATE_lo_user
-             && uvalue <= DW_ATE_hi_user)
-           printf ("(user defined type)");
-         else
-           printf ("(unknown type)");
+       case 1:
+         printf ("Generic\n");
          break;
-       }
-      break;
-
-    case DW_AT_accessibility:
-      switch (uvalue)
-       {
-       case DW_ACCESS_public:          printf ("(public)"); break;
-       case DW_ACCESS_protected:       printf ("(protected)"); break;
-       case DW_ACCESS_private:         printf ("(private)"); break;
-       default:
-         printf ("(unknown accessibility)");
+       case 2:
+         printf ("AltiVec\n");
+         break;
+       case 3:
+         printf ("SPE\n");
          break;
-       }
-      break;
-
-    case DW_AT_visibility:
-      switch (uvalue)
-       {
-       case DW_VIS_local:              printf ("(local)"); break;
-       case DW_VIS_exported:           printf ("(exported)"); break;
-       case DW_VIS_qualified:          printf ("(qualified)"); break;
-       default:                        printf ("(unknown visibility)"); break;
-       }
-      break;
-
-    case DW_AT_virtuality:
-      switch (uvalue)
-       {
-       case DW_VIRTUALITY_none:        printf ("(none)"); break;
-       case DW_VIRTUALITY_virtual:     printf ("(virtual)"); break;
-       case DW_VIRTUALITY_pure_virtual:printf ("(pure_virtual)"); break;
-       default:                        printf ("(unknown virtuality)"); break;
-       }
-      break;
-
-    case DW_AT_identifier_case:
-      switch (uvalue)
-       {
-       case DW_ID_case_sensitive:      printf ("(case_sensitive)"); break;
-       case DW_ID_up_case:             printf ("(up_case)"); break;
-       case DW_ID_down_case:           printf ("(down_case)"); break;
-       case DW_ID_case_insensitive:    printf ("(case_insensitive)"); break;
-       default:                        printf ("(unknown case)"); break;
-       }
-      break;
-
-    case DW_AT_calling_convention:
-      switch (uvalue)
-       {
-       case DW_CC_normal:      printf ("(normal)"); break;
-       case DW_CC_program:     printf ("(program)"); break;
-       case DW_CC_nocall:      printf ("(nocall)"); break;
        default:
-         if (uvalue >= DW_CC_lo_user
-             && uvalue <= DW_CC_hi_user)
-           printf ("(user defined)");
-         else
-           printf ("(unknown convention)");
-       }
-      break;
-
-    case DW_AT_ordering:
-      switch (uvalue)
-       {
-       case -1: printf ("(undefined)"); break;
-       case 0:  printf ("(row major)"); break;
-       case 1:  printf ("(column major)"); break;
+         printf ("??? (%d)\n", val);
+         break;
        }
-      break;
+      return p;
+   }
 
-    case DW_AT_frame_base:
-      have_frame_base = 1;
-    case DW_AT_location:
-    case DW_AT_data_member_location:
-    case DW_AT_vtable_elem_location:
-    case DW_AT_allocated:
-    case DW_AT_associated:
-    case DW_AT_data_location:
-    case DW_AT_stride:
-    case DW_AT_upper_bound:
-    case DW_AT_lower_bound:
-      if (block_start)
-       {
-         int need_frame_base;
-
-         printf ("(");
-         need_frame_base = decode_location_expression (block_start,
-                                                       pointer_size,
-                                                       uvalue,
-                                                       cu_offset);
-         printf (")");
-         if (need_frame_base && !have_frame_base)
-           printf (_(" [without DW_AT_frame_base]"));
-       }
-      else if (form == DW_FORM_data4 || form == DW_FORM_data8)
-       printf (_("(location list)"));
-
-      break;
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
 
-    default:
-      break;
+  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 data;
-}
-
-static char *
-get_AT_name (unsigned long attribute)
-{
-  switch (attribute)
-    {
-    case DW_AT_sibling:                        return "DW_AT_sibling";
-    case DW_AT_location:               return "DW_AT_location";
-    case DW_AT_name:                   return "DW_AT_name";
-    case DW_AT_ordering:               return "DW_AT_ordering";
-    case DW_AT_subscr_data:            return "DW_AT_subscr_data";
-    case DW_AT_byte_size:              return "DW_AT_byte_size";
-    case DW_AT_bit_offset:             return "DW_AT_bit_offset";
-    case DW_AT_bit_size:               return "DW_AT_bit_size";
-    case DW_AT_element_list:           return "DW_AT_element_list";
-    case DW_AT_stmt_list:              return "DW_AT_stmt_list";
-    case DW_AT_low_pc:                 return "DW_AT_low_pc";
-    case DW_AT_high_pc:                        return "DW_AT_high_pc";
-    case DW_AT_language:               return "DW_AT_language";
-    case DW_AT_member:                 return "DW_AT_member";
-    case DW_AT_discr:                  return "DW_AT_discr";
-    case DW_AT_discr_value:            return "DW_AT_discr_value";
-    case DW_AT_visibility:             return "DW_AT_visibility";
-    case DW_AT_import:                 return "DW_AT_import";
-    case DW_AT_string_length:          return "DW_AT_string_length";
-    case DW_AT_common_reference:       return "DW_AT_common_reference";
-    case DW_AT_comp_dir:               return "DW_AT_comp_dir";
-    case DW_AT_const_value:            return "DW_AT_const_value";
-    case DW_AT_containing_type:                return "DW_AT_containing_type";
-    case DW_AT_default_value:          return "DW_AT_default_value";
-    case DW_AT_inline:                 return "DW_AT_inline";
-    case DW_AT_is_optional:            return "DW_AT_is_optional";
-    case DW_AT_lower_bound:            return "DW_AT_lower_bound";
-    case DW_AT_producer:               return "DW_AT_producer";
-    case DW_AT_prototyped:             return "DW_AT_prototyped";
-    case DW_AT_return_addr:            return "DW_AT_return_addr";
-    case DW_AT_start_scope:            return "DW_AT_start_scope";
-    case DW_AT_stride_size:            return "DW_AT_stride_size";
-    case DW_AT_upper_bound:            return "DW_AT_upper_bound";
-    case DW_AT_abstract_origin:                return "DW_AT_abstract_origin";
-    case DW_AT_accessibility:          return "DW_AT_accessibility";
-    case DW_AT_address_class:          return "DW_AT_address_class";
-    case DW_AT_artificial:             return "DW_AT_artificial";
-    case DW_AT_base_types:             return "DW_AT_base_types";
-    case DW_AT_calling_convention:     return "DW_AT_calling_convention";
-    case DW_AT_count:                  return "DW_AT_count";
-    case DW_AT_data_member_location:   return "DW_AT_data_member_location";
-    case DW_AT_decl_column:            return "DW_AT_decl_column";
-    case DW_AT_decl_file:              return "DW_AT_decl_file";
-    case DW_AT_decl_line:              return "DW_AT_decl_line";
-    case DW_AT_declaration:            return "DW_AT_declaration";
-    case DW_AT_discr_list:             return "DW_AT_discr_list";
-    case DW_AT_encoding:               return "DW_AT_encoding";
-    case DW_AT_external:               return "DW_AT_external";
-    case DW_AT_frame_base:             return "DW_AT_frame_base";
-    case DW_AT_friend:                 return "DW_AT_friend";
-    case DW_AT_identifier_case:                return "DW_AT_identifier_case";
-    case DW_AT_macro_info:             return "DW_AT_macro_info";
-    case DW_AT_namelist_items:         return "DW_AT_namelist_items";
-    case DW_AT_priority:               return "DW_AT_priority";
-    case DW_AT_segment:                        return "DW_AT_segment";
-    case DW_AT_specification:          return "DW_AT_specification";
-    case DW_AT_static_link:            return "DW_AT_static_link";
-    case DW_AT_type:                   return "DW_AT_type";
-    case DW_AT_use_location:           return "DW_AT_use_location";
-    case DW_AT_variable_parameter:     return "DW_AT_variable_parameter";
-    case DW_AT_virtuality:             return "DW_AT_virtuality";
-    case DW_AT_vtable_elem_location:   return "DW_AT_vtable_elem_location";
-      /* DWARF 2.1 values.  */
-    case DW_AT_allocated:              return "DW_AT_allocated";
-    case DW_AT_associated:             return "DW_AT_associated";
-    case DW_AT_data_location:          return "DW_AT_data_location";
-    case DW_AT_stride:                 return "DW_AT_stride";
-    case DW_AT_entry_pc:               return "DW_AT_entry_pc";
-    case DW_AT_use_UTF8:               return "DW_AT_use_UTF8";
-    case DW_AT_extension:              return "DW_AT_extension";
-    case DW_AT_ranges:                 return "DW_AT_ranges";
-    case DW_AT_trampoline:             return "DW_AT_trampoline";
-    case DW_AT_call_column:            return "DW_AT_call_column";
-    case DW_AT_call_file:              return "DW_AT_call_file";
-    case DW_AT_call_line:              return "DW_AT_call_line";
-      /* SGI/MIPS extensions.  */
-    case DW_AT_MIPS_fde:               return "DW_AT_MIPS_fde";
-    case DW_AT_MIPS_loop_begin:                return "DW_AT_MIPS_loop_begin";
-    case DW_AT_MIPS_tail_loop_begin:   return "DW_AT_MIPS_tail_loop_begin";
-    case DW_AT_MIPS_epilog_begin:      return "DW_AT_MIPS_epilog_begin";
-    case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor";
-    case DW_AT_MIPS_software_pipeline_depth:
-      return "DW_AT_MIPS_software_pipeline_depth";
-    case DW_AT_MIPS_linkage_name:      return "DW_AT_MIPS_linkage_name";
-    case DW_AT_MIPS_stride:            return "DW_AT_MIPS_stride";
-    case DW_AT_MIPS_abstract_name:     return "DW_AT_MIPS_abstract_name";
-    case DW_AT_MIPS_clone_origin:      return "DW_AT_MIPS_clone_origin";
-    case DW_AT_MIPS_has_inlines:       return "DW_AT_MIPS_has_inlines";
-      /* GNU extensions.  */
-    case DW_AT_sf_names:               return "DW_AT_sf_names";
-    case DW_AT_src_info:               return "DW_AT_src_info";
-    case DW_AT_mac_info:               return "DW_AT_mac_info";
-    case DW_AT_src_coords:             return "DW_AT_src_coords";
-    case DW_AT_body_begin:             return "DW_AT_body_begin";
-    case DW_AT_body_end:               return "DW_AT_body_end";
-    case DW_AT_GNU_vector:             return "DW_AT_GNU_vector";
-      /* UPC extension.  */
-    case DW_AT_upc_threads_scaled:     return "DW_AT_upc_threads_scaled";
-    default:
-      {
-       static char buffer[100];
-
-       snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"),
-                 attribute);
-       return buffer;
-      }
-    }
+  return p;
 }
 
 static unsigned char *
-read_and_display_attr (unsigned long attribute,
-                      unsigned long form,
-                      unsigned char *data,
-                      unsigned long cu_offset,
-                      unsigned long pointer_size,
-                      unsigned long offset_size,
-                      int dwarf_version,
-                      debug_info *debug_info_p,
-                      int do_loc)
-{
-  if (!do_loc)
-    printf ("     %-18s:", get_AT_name (attribute));
-  data = read_and_display_attr_value (attribute, form, data, cu_offset,
-                                     pointer_size, offset_size,
-                                     dwarf_version, debug_info_p,
-                                     do_loc);
-  if (!do_loc)
-    printf ("\n");
-  return data;
-}
-
-
-/* Process the contents of a .debug_info section.  If do_loc is non-zero
-   then we are scanning for location lists and we do not want to display
-   anything to the user.  */
-
-static int
-process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
-                   FILE *file, int do_loc)
-{
-  unsigned char *end = start + section->sh_size;
-  unsigned char *section_begin;
-  unsigned int unit;
-  unsigned int num_units = 0;
-
-  if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
-    {
-      unsigned long length;
-
-      /* First scan the section to get the number of comp units.  */
-      for (section_begin = start, num_units = 0; section_begin < end;
-          num_units ++)
-       {
-         /* Read the first 4 bytes.  For a 32-bit DWARF section, this
-            will be the length.  For a 64-bit DWARF section, it'll be
-            the escape code 0xffffffff followed by an 8 byte length.  */
-         length = byte_get (section_begin, 4);
-
-         if (length == 0xffffffff)
-           {
-             length = byte_get (section_begin + 4, 8);
-             section_begin += length + 12;
-           }
-         else
-           section_begin += length + 4;
-       }
-
-      if (num_units == 0)
-       {
-         error (_("No comp units in .debug_info section ?"));
-         return 0;
-       }
-
-      /* Then allocate an array to hold the information.  */
-      debug_information = cmalloc (num_units,
-                                  sizeof (* debug_information));
-      if (debug_information == NULL)
-       {
-         error (_("Not enough memory for a debug info array of %u entries"),
-                num_units);
-         return 0;
-       }
-    }
-
-  if (!do_loc)
-    {
-      printf (_("The section %s contains:\n\n"),
-             SECTION_NAME (section));
-
-      load_debug_str (file);
-      load_debug_loc (file);
-      load_debug_range (file);
-    }
-
-  load_debug_abbrev (file);
-  if (debug_abbrev_contents == NULL)
-    {
-      warn (_("Unable to locate .debug_abbrev section!\n"));
-      return 0;
-    }
-
-  for (section_begin = start, unit = 0; start < end; unit++)
-    {
-      DWARF2_Internal_CompUnit compunit;
-      unsigned char *hdrptr;
-      unsigned char *cu_abbrev_offset_ptr;
-      unsigned char *tags;
-      int level;
-      unsigned long cu_offset;
-      int offset_size;
-      int initial_length_size;
-
-      hdrptr = start;
-
-      compunit.cu_length = byte_get (hdrptr, 4);
-      hdrptr += 4;
-
-      if (compunit.cu_length == 0xffffffff)
-       {
-         compunit.cu_length = byte_get (hdrptr, 8);
-         hdrptr += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
-
-      compunit.cu_version = byte_get (hdrptr, 2);
-      hdrptr += 2;
-
-      cu_offset = start - section_begin;
-      start += compunit.cu_length + initial_length_size;
-
-      if (elf_header.e_type == ET_REL
-         && !debug_apply_rela_addends (file, section, offset_size,
-                                       section_begin, hdrptr, start))
-       return 0;
-
-      cu_abbrev_offset_ptr = hdrptr;
-      compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
-      hdrptr += offset_size;
-
-      compunit.cu_pointer_size = byte_get (hdrptr, 1);
-      hdrptr += 1;
-      if ((do_loc || do_debug_loc || do_debug_ranges)
-         && num_debug_info_entries == 0)
-       {
-         debug_information [unit].cu_offset = cu_offset;
-         debug_information [unit].pointer_size
-           = compunit.cu_pointer_size;
-         debug_information [unit].base_address = 0;
-         debug_information [unit].loc_offsets = NULL;
-         debug_information [unit].have_frame_base = NULL;
-         debug_information [unit].max_loc_offsets = 0;
-         debug_information [unit].num_loc_offsets = 0;
-         debug_information [unit].range_lists = NULL;
-         debug_information [unit].max_range_lists= 0;
-         debug_information [unit].num_range_lists = 0;
-       }
-
-      tags = hdrptr;
-
-      if (!do_loc)
-       {
-         printf (_("  Compilation Unit @ offset 0x%lx:\n"), cu_offset);
-         printf (_("   Length:        %ld\n"), compunit.cu_length);
-         printf (_("   Version:       %d\n"), compunit.cu_version);
-         printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
-         printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
-       }
-
-      if (compunit.cu_version != 2 && compunit.cu_version != 3)
-       {
-         warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
-         continue;
-       }
-
-      free_abbrevs ();
-
-      /* Process the abbrevs used by this compilation unit.  */
-      process_abbrev_section
-       (debug_abbrev_contents + compunit.cu_abbrev_offset,
-        debug_abbrev_contents + debug_abbrev_size);
-
-      level = 0;
-      while (tags < start)
-       {
-         unsigned int bytes_read;
-         unsigned long abbrev_number;
-         abbrev_entry *entry;
-         abbrev_attr *attr;
-
-         abbrev_number = read_leb128 (tags, & bytes_read, 0);
-         tags += bytes_read;
-
-         /* A null DIE marks the end of a list of children.  */
-         if (abbrev_number == 0)
-           {
-             --level;
-             continue;
-           }
-
-         /* Scan through the abbreviation list until we reach the
-            correct entry.  */
-         for (entry = first_abbrev;
-              entry && entry->entry != abbrev_number;
-              entry = entry->next)
-           continue;
-
-         if (entry == NULL)
-           {
-             warn (_("Unable to locate entry %lu in the abbreviation table\n"),
-                   abbrev_number);
-             return 0;
-           }
-
-         if (!do_loc)
-           printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
-                   level,
-                   (unsigned long) (tags - section_begin
-                                    - bytes_read),
-                   abbrev_number,
-                   get_TAG_name (entry->tag));
-         switch (entry->tag)
-           {
-           default:
-             need_base_address = 0;
-             break;
-           case DW_TAG_compile_unit:
-             need_base_address = 1;
-             break;
-           case DW_TAG_entry_point:
-           case DW_TAG_inlined_subroutine:
-           case DW_TAG_subprogram:
-             need_base_address = 0;
-             /* Assuming that there is no DW_AT_frame_base.  */
-             have_frame_base = 0;
-             break;
-           }
-
-         for (attr = entry->first_attr; attr; attr = attr->next)
-           tags = read_and_display_attr (attr->attribute,
-                                         attr->form,
-                                         tags, cu_offset,
-                                         compunit.cu_pointer_size,
-                                         offset_size,
-                                         compunit.cu_version,
-                                         &debug_information [unit],
-                                         do_loc);
-         if (entry->children)
-           ++level;
-       }
-    }
-  free_debug_abbrev ();
-
-  /* Set num_debug_info_entries here so that it can be used to check if
-     we need to process .debug_loc and .debug_ranges sections.  */
-  if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0)
-    num_debug_info_entries = num_units;
-      
-  if (!do_loc)
-    {
-      free_debug_range ();
-      free_debug_str ();
-      free_debug_loc (); 
-
-      printf ("\n");
-    }
-  return 1;
-}
-
-/* Retrieve the pointer size associated with the given compilation unit.
-   Optionally the offset of this unit into the .debug_info section is
-   also retutned.  If there is no .debug_info section then an error
-   message is issued and 0 is returned.  If the requested comp unit has
-   not been defined in the .debug_info section then a warning message
-   is issued and the last know pointer size is returned.  This message
-   is only issued once per section dumped per file dumped.  */
-
-static unsigned int
-get_pointer_size_and_offset_of_comp_unit (unsigned int comp_unit,
-                                         const char * section_name,
-                                         unsigned long * offset_return)
-{
-  unsigned long offset = 0;
-
-  if (num_debug_info_entries == 0)
-    error (_("%s section needs a populated .debug_info section\n"),
-          section_name);
-
-  else if (comp_unit >= num_debug_info_entries)
-    {
-      if (!warned_about_missing_comp_units)
-       {
-         warn (_("%s section has more comp units than .debug_info section\n"),
-               section_name);
-         warn (_("assuming that the pointer size is %d, from the last comp unit in .debug_info\n\n"),
-               last_pointer_size);
-         warned_about_missing_comp_units = TRUE;
-       }
-    }
-  else
-    {
-      last_pointer_size = debug_information [comp_unit].pointer_size;
-      offset = debug_information [comp_unit].cu_offset;
-    }
-
-  if (offset_return != NULL)
-    * offset_return = offset;
-
-  return last_pointer_size;
-}
-
-/* Locate and scan the .debug_info section in the file and record the pointer
-   sizes and offsets for the compilation units in it.  Usually an executable
-   will have just one pointer size, but this is not guaranteed, and so we try
-   not to make any assumptions.  Returns zero upon failure, or the number of
-   compilation units upon success.  */
-
-static unsigned int
-get_debug_info (FILE * file)
-{
-  Elf_Internal_Shdr * section;
-  unsigned char *     start;
-  int                ret;
-
-  /* Reset the last pointer size so that we can issue correct error
-     messages if we are displaying the contents of more than one section.  */
-  last_pointer_size = 0;
-  warned_about_missing_comp_units = FALSE;
-
-  /* If we already have the information there is nothing else to do.  */
-  if (num_debug_info_entries > 0)
-    return num_debug_info_entries;
-
-  section = find_section (".debug_info");
-  if (section == NULL)
-    return 0;
-
-  start = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
-                   _("extracting information from .debug_info section"));
-  if (start == NULL)
-    return 0;
-
-  ret = process_debug_info (section, start, file, 1);
-  free (start);
-
-  return ret ? num_debug_info_entries : 0;
-}
-
-static int
-display_debug_lines (Elf_Internal_Shdr *section,
-                    unsigned char *start, FILE *file)
-{
-  unsigned char *data = start;
-  unsigned char *end = start + section->sh_size;
-  unsigned int comp_unit = 0;
-
-  printf (_("\nDump of debug contents of section %s:\n\n"),
-         SECTION_NAME (section));
-
-  get_debug_info (file);
-
-  while (data < end)
-    {
-      DWARF2_Internal_LineInfo info;
-      unsigned char *standard_opcodes;
-      unsigned char *end_of_sequence;
-      unsigned char *hdrptr;
-      unsigned int pointer_size;
-      int initial_length_size;
-      int offset_size;
-      int i;
-
-      hdrptr = data;
-
-      /* Check the length of the block.  */
-      info.li_length = byte_get (hdrptr, 4);
-      hdrptr += 4;
-
-      if (info.li_length == 0xffffffff)
-       {
-         /* This section is 64-bit DWARF 3.  */
-         info.li_length = byte_get (hdrptr, 8);
-         hdrptr += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
-
-      if (info.li_length + initial_length_size > section->sh_size)
-       {
-         warn
-           (_("The line info appears to be corrupt - the section is too small\n"));
-         return 0;
-       }
-
-      /* Check its version number.  */
-      info.li_version = byte_get (hdrptr, 2);
-      hdrptr += 2;
-      if (info.li_version != 2 && info.li_version != 3)
-       {
-         warn (_("Only DWARF version 2 and 3 line info is currently supported.\n"));
-         return 0;
-       }
-
-      info.li_prologue_length = byte_get (hdrptr, offset_size);
-      hdrptr += offset_size;
-      info.li_min_insn_length = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_default_is_stmt = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_line_base = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_line_range = byte_get (hdrptr, 1);
-      hdrptr++;
-      info.li_opcode_base = byte_get (hdrptr, 1);
-      hdrptr++;
-
-      /* Sign extend the line base field.  */
-      info.li_line_base <<= 24;
-      info.li_line_base >>= 24;
-
-      /* Get the pointer size from the comp unit associated
-        with this block of line number information.  */
-      pointer_size = get_pointer_size_and_offset_of_comp_unit
-       (comp_unit, ".debug_line", NULL);
-      comp_unit ++;
-
-      printf (_("  Length:                      %ld\n"), info.li_length);
-      printf (_("  DWARF Version:               %d\n"), info.li_version);
-      printf (_("  Prologue Length:             %d\n"), info.li_prologue_length);
-      printf (_("  Minimum Instruction Length:  %d\n"), info.li_min_insn_length);
-      printf (_("  Initial value of 'is_stmt':  %d\n"), info.li_default_is_stmt);
-      printf (_("  Line Base:                   %d\n"), info.li_line_base);
-      printf (_("  Line Range:                  %d\n"), info.li_line_range);
-      printf (_("  Opcode Base:                 %d\n"), info.li_opcode_base);
-      printf (_("  (Pointer size:               %u)%s\n"),
-             pointer_size,
-             warned_about_missing_comp_units ? " [assumed]" : "" );
-
-      end_of_sequence = data + info.li_length + initial_length_size;
-
-      reset_state_machine (info.li_default_is_stmt);
-
-      /* Display the contents of the Opcodes table.  */
-      standard_opcodes = hdrptr;
-
-      printf (_("\n Opcodes:\n"));
-
-      for (i = 1; i < info.li_opcode_base; i++)
-       printf (_("  Opcode %d has %d args\n"), i, standard_opcodes[i - 1]);
-
-      /* Display the contents of the Directory table.  */
-      data = standard_opcodes + info.li_opcode_base - 1;
-
-      if (*data == 0)
-       printf (_("\n The Directory Table is empty.\n"));
-      else
-       {
-         printf (_("\n The Directory Table:\n"));
-
-         while (*data != 0)
-           {
-             printf (_("  %s\n"), data);
-
-             data += strlen ((char *) data) + 1;
-           }
-       }
-
-      /* Skip the NUL at the end of the table.  */
-      data++;
-
-      /* Display the contents of the File Name table.  */
-      if (*data == 0)
-       printf (_("\n The File Name Table is empty.\n"));
-      else
-       {
-         printf (_("\n The File Name Table:\n"));
-         printf (_("  Entry\tDir\tTime\tSize\tName\n"));
-
-         while (*data != 0)
-           {
-             unsigned char *name;
-             unsigned int bytes_read;
-
-             printf (_("  %d\t"), ++state_machine_regs.last_file_entry);
-             name = data;
-
-             data += strlen ((char *) data) + 1;
-
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-             data += bytes_read;
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-             data += bytes_read;
-             printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0));
-             data += bytes_read;
-             printf (_("%s\n"), name);
-           }
-       }
-
-      /* Skip the NUL at the end of the table.  */
-      data++;
-
-      /* Now display the statements.  */
-      printf (_("\n Line Number Statements:\n"));
-
-      while (data < end_of_sequence)
-       {
-         unsigned char op_code;
-         int adv;
-         unsigned int bytes_read;
-
-         op_code = *data++;
-
-         if (op_code >= info.li_opcode_base)
-           {
-             op_code -= info.li_opcode_base;
-             adv      = (op_code / info.li_line_range) * info.li_min_insn_length;
-             state_machine_regs.address += adv;
-             printf (_("  Special opcode %d: advance Address by %d to 0x%lx"),
-                     op_code, adv, state_machine_regs.address);
-             adv = (op_code % info.li_line_range) + info.li_line_base;
-             state_machine_regs.line += adv;
-             printf (_(" and Line by %d to %d\n"),
-                     adv, state_machine_regs.line);
-           }
-         else switch (op_code)
-           {
-           case DW_LNS_extended_op:
-             if (pointer_size == 0)
-               {
-                 warn (_("Extend line ops need a valid pointer size, guessing at 4\n"));
-                 pointer_size = 4;
-               }
-
-             data += process_extended_line_op (data, info.li_default_is_stmt,
-                                               pointer_size);
-             break;
-
-           case DW_LNS_copy:
-             printf (_("  Copy\n"));
-             break;
-
-           case DW_LNS_advance_pc:
-             adv = info.li_min_insn_length * read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             state_machine_regs.address += adv;
-             printf (_("  Advance PC by %d to %lx\n"), adv,
-                     state_machine_regs.address);
-             break;
-
-           case DW_LNS_advance_line:
-             adv = read_leb128 (data, & bytes_read, 1);
-             data += bytes_read;
-             state_machine_regs.line += adv;
-             printf (_("  Advance Line by %d to %d\n"), adv,
-                     state_machine_regs.line);
-             break;
-
-           case DW_LNS_set_file:
-             adv = read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             printf (_("  Set File Name to entry %d in the File Name Table\n"),
-                     adv);
-             state_machine_regs.file = adv;
-             break;
-
-           case DW_LNS_set_column:
-             adv = read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             printf (_("  Set column to %d\n"), adv);
-             state_machine_regs.column = adv;
-             break;
-
-           case DW_LNS_negate_stmt:
-             adv = state_machine_regs.is_stmt;
-             adv = ! adv;
-             printf (_("  Set is_stmt to %d\n"), adv);
-             state_machine_regs.is_stmt = adv;
-             break;
-
-           case DW_LNS_set_basic_block:
-             printf (_("  Set basic block\n"));
-             state_machine_regs.basic_block = 1;
-             break;
-
-           case DW_LNS_const_add_pc:
-             adv = (((255 - info.li_opcode_base) / info.li_line_range)
-                    * info.li_min_insn_length);
-             state_machine_regs.address += adv;
-             printf (_("  Advance PC by constant %d to 0x%lx\n"), adv,
-                     state_machine_regs.address);
-             break;
-
-           case DW_LNS_fixed_advance_pc:
-             adv = byte_get (data, 2);
-             data += 2;
-             state_machine_regs.address += adv;
-             printf (_("  Advance PC by fixed size amount %d to 0x%lx\n"),
-                     adv, state_machine_regs.address);
-             break;
-
-           case DW_LNS_set_prologue_end:
-             printf (_("  Set prologue_end to true\n"));
-             break;
-
-           case DW_LNS_set_epilogue_begin:
-             printf (_("  Set epilogue_begin to true\n"));
-             break;
-
-           case DW_LNS_set_isa:
-             adv = read_leb128 (data, & bytes_read, 0);
-             data += bytes_read;
-             printf (_("  Set ISA to %d\n"), adv);
-             break;
-
-           default:
-             printf (_("  Unknown opcode %d with operands: "), op_code);
-
-             for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
-               {
-                 printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0),
-                         i == 1 ? "" : ", ");
-                 data += bytes_read;
-               }
-             putchar ('\n');
-             break;
-           }
-       }
-      putchar ('\n');
-    }
-
-  return 1;
-}
-
-static int
-display_debug_pubnames (Elf_Internal_Shdr *section,
-                       unsigned char *start,
-                       FILE *file ATTRIBUTE_UNUSED)
-{
-  DWARF2_Internal_PubNames pubnames;
-  unsigned char *end;
-
-  end = start + section->sh_size;
-
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
-
-  while (start < end)
-    {
-      unsigned char *data;
-      unsigned long offset;
-      int offset_size, initial_length_size;
-
-      data = start;
-
-      pubnames.pn_length = byte_get (data, 4);
-      data += 4;
-      if (pubnames.pn_length == 0xffffffff)
-       {
-         pubnames.pn_length = byte_get (data, 8);
-         data += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
-
-      pubnames.pn_version = byte_get (data, 2);
-      data += 2;
-      pubnames.pn_offset = byte_get (data, offset_size);
-      data += offset_size;
-      pubnames.pn_size = byte_get (data, offset_size);
-      data += offset_size;
-
-      start += pubnames.pn_length + initial_length_size;
-
-      if (pubnames.pn_version != 2 && pubnames.pn_version != 3)
-       {
-         static int warned = 0;
-
-         if (! warned)
-           {
-             warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
-             warned = 1;
-           }
-
-         continue;
-       }
-
-      printf (_("  Length:                              %ld\n"),
-             pubnames.pn_length);
-      printf (_("  Version:                             %d\n"),
-             pubnames.pn_version);
-      printf (_("  Offset into .debug_info section:     %ld\n"),
-             pubnames.pn_offset);
-      printf (_("  Size of area in .debug_info section: %ld\n"),
-             pubnames.pn_size);
-
-      printf (_("\n    Offset\tName\n"));
-
-      do
-       {
-         offset = byte_get (data, offset_size);
-
-         if (offset != 0)
-           {
-             data += offset_size;
-             printf ("    %-6ld\t\t%s\n", offset, data);
-             data += strlen ((char *) data) + 1;
-           }
-       }
-      while (offset != 0);
-    }
-
-  printf ("\n");
-  return 1;
-}
-
-static int
-display_debug_macinfo (Elf_Internal_Shdr *section,
-                      unsigned char *start,
-                      FILE *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *end = start + section->sh_size;
-  unsigned char *curr = start;
-  unsigned int bytes_read;
-  enum dwarf_macinfo_record_type op;
-
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
-
-  while (curr < end)
-    {
-      unsigned int lineno;
-      const char *string;
-
-      op = *curr;
-      curr++;
-
-      switch (op)
-       {
-       case DW_MACINFO_start_file:
-         {
-           unsigned int filenum;
-
-           lineno = read_leb128 (curr, & bytes_read, 0);
-           curr += bytes_read;
-           filenum = read_leb128 (curr, & bytes_read, 0);
-           curr += bytes_read;
-
-           printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"),
-                   lineno, filenum);
-         }
-         break;
-
-       case DW_MACINFO_end_file:
-         printf (_(" DW_MACINFO_end_file\n"));
-         break;
-
-       case DW_MACINFO_define:
-         lineno = read_leb128 (curr, & bytes_read, 0);
-         curr += bytes_read;
-         string = (char *) curr;
-         curr += strlen (string) + 1;
-         printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"),
-                 lineno, string);
-         break;
-
-       case DW_MACINFO_undef:
-         lineno = read_leb128 (curr, & bytes_read, 0);
-         curr += bytes_read;
-         string = (char *) curr;
-         curr += strlen (string) + 1;
-         printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"),
-                 lineno, string);
-         break;
-
-       case DW_MACINFO_vendor_ext:
-         {
-           unsigned int constant;
-
-           constant = read_leb128 (curr, & bytes_read, 0);
-           curr += bytes_read;
-           string = (char *) curr;
-           curr += strlen (string) + 1;
-           printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"),
-                   constant, string);
-         }
-         break;
-       }
-    }
-
-  return 1;
-}
-
-
-static int
-display_debug_abbrev (Elf_Internal_Shdr *section,
-                     unsigned char *start,
-                     FILE *file ATTRIBUTE_UNUSED)
-{
-  abbrev_entry *entry;
-  unsigned char *end = start + section->sh_size;
-
-  printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
-
-  do
-    {
-      start = process_abbrev_section (start, end);
-
-      if (first_abbrev == NULL)
-       continue;
-
-      printf (_("  Number TAG\n"));
-
-      for (entry = first_abbrev; entry; entry = entry->next)
-       {
-         abbrev_attr *attr;
-
-         printf (_("   %ld      %s    [%s]\n"),
-                 entry->entry,
-                 get_TAG_name (entry->tag),
-                 entry->children ? _("has children") : _("no children"));
-
-         for (attr = entry->first_attr; attr; attr = attr->next)
-           printf (_("    %-18s %s\n"),
-                   get_AT_name (attr->attribute),
-                   get_FORM_name (attr->form));
-       }
-
-      free_abbrevs ();
-    }
-  while (start);
-
-  printf ("\n");
-
-  return 1;
-}
-
-static int
-display_debug_loc (Elf_Internal_Shdr *section,
-                  unsigned char *start, FILE *file)
-{
-  unsigned char *section_end;
-  unsigned long bytes;
-  unsigned char *section_begin = start;
-  unsigned int num_loc_list = 0;
-  unsigned long last_offset = 0;
-  unsigned int first = 0;
-  unsigned int i;
-  unsigned int j;
-  int seen_first_offset = 0;
-  int use_debug_info = 1;
-  unsigned char *next;
-
-  bytes = section->sh_size;
-  section_end = start + bytes;
-
-  if (bytes == 0)
-    {
-      printf (_("\nThe .debug_loc section is empty.\n"));
-      return 0;
-    }
-
-  get_debug_info (file);
-
-  /* Check the order of location list in .debug_info section. If
-     offsets of location lists are in the ascending order, we can
-     use `debug_information' directly.  */
-  for (i = 0; i < num_debug_info_entries; i++)
-    {
-      unsigned int num;
-
-      num = debug_information [i].num_loc_offsets;
-      num_loc_list += num;
-
-      /* Check if we can use `debug_information' directly.  */
-      if (use_debug_info && num != 0)
-       {
-         if (!seen_first_offset)
-           {
-             /* This is the first location list.  */
-             last_offset = debug_information [i].loc_offsets [0];
-             first = i;
-             seen_first_offset = 1;
-             j = 1;
-           }
-         else
-           j = 0;
-
-         for (; j < num; j++)
-           {
-             if (last_offset >
-                 debug_information [i].loc_offsets [j])
-               {
-                 use_debug_info = 0;
-                 break;
-               }
-             last_offset = debug_information [i].loc_offsets [j];
-           }
-       }
-    }
-
-  if (!use_debug_info)
-    /* FIXME: Should we handle this case?  */
-    error (_("Location lists in .debug_info section aren't in ascending order!\n"));
-
-  if (!seen_first_offset)
-    error (_("No location lists in .debug_info section!\n"));
-
-  if (debug_information [first].loc_offsets [0] != 0)
-    warn (_("Location lists in .debug_loc section start at 0x%lx\n"),
-         debug_information [first].loc_offsets [0]);
-
-  printf (_("Contents of the .debug_loc section:\n\n"));
-  printf (_("    Offset   Begin    End      Expression\n"));
-
-  seen_first_offset = 0;
-  for (i = first; i < num_debug_info_entries; i++)
-    {
-      unsigned long begin;
-      unsigned long end;
-      unsigned short length;
-      unsigned long offset;
-      unsigned int pointer_size;
-      unsigned long cu_offset;
-      unsigned long base_address;
-      int need_frame_base;
-      int has_frame_base;
-
-      pointer_size = debug_information [i].pointer_size;
-      cu_offset = debug_information [i].cu_offset;
-
-      for (j = 0; j < debug_information [i].num_loc_offsets; j++)
-       {
-         has_frame_base = debug_information [i].have_frame_base [j];
-         offset = debug_information [i].loc_offsets [j];
-         next = section_begin + offset;
-         base_address = debug_information [i].base_address;
-
-         if (!seen_first_offset)
-           seen_first_offset = 1;
-         else
-           {
-             if (start < next)
-               warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
-                     (long)(start - section_begin), (long)(next - section_begin));
-             else if (start > next)
-               warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
-                     (long)(start - section_begin), (long)(next - section_begin));
-           }
-         start = next;
-
-         if (offset >= bytes)
-           {
-             warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"),
-                   offset);
-             continue;
-           }
-
-         while (1)
-           {
-             if (start + 2 * pointer_size > section_end)
-               {
-                 warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
-                       offset);
-                 break;
-               }
-
-             begin = byte_get (start, pointer_size);
-             start += pointer_size;
-             end = byte_get (start, pointer_size);
-             start += pointer_size;
-
-             if (begin == 0 && end == 0)
-               {
-                 printf (_("    %8.8lx <End of list>\n"), offset);
-                 break;
-               }
-
-             /* Check base address specifiers.  */
-             if (begin == -1UL && end != -1UL)
-               {
-                 base_address = end;
-                 printf (_("    %8.8lx %8.8lx %8.8lx (base address)\n"),
-                         offset, begin, end);
-                 continue;
-               }
-
-             if (start + 2 > section_end)
-               {
-                 warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
-                       offset);
-                 break;
-               }
-
-             length = byte_get (start, 2);
-             start += 2;
-
-             if (start + length > section_end)
-               {
-                 warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
-                       offset);
-                 break;
-               }
-
-             printf ("    %8.8lx %8.8lx %8.8lx (",
-                     offset, begin + base_address, end + base_address);
-             need_frame_base = decode_location_expression (start,
-                                                           pointer_size,
-                                                           length,
-                                                           cu_offset);
-             putchar (')');
-
-             if (need_frame_base && !has_frame_base)
-               printf (_(" [without DW_AT_frame_base]"));
-
-             if (begin == end)
-               fputs (_(" (start == end)"), stdout);
-             else if (begin > end)
-               fputs (_(" (start > end)"), stdout);
-
-             putchar ('\n');
-
-             start += length;
-           }
-       }
-    }
-  return 1;
-}
-
-static int
-display_debug_str (Elf_Internal_Shdr *section,
-                  unsigned char *start,
-                  FILE *file ATTRIBUTE_UNUSED)
-{
-  unsigned long bytes;
-  bfd_vma addr;
-
-  addr  = section->sh_addr;
-  bytes = section->sh_size;
-
-  if (bytes == 0)
-    {
-      printf (_("\nThe .debug_str section is empty.\n"));
-      return 0;
-    }
-
-  printf (_("Contents of the .debug_str section:\n\n"));
-
-  while (bytes)
-    {
-      int j;
-      int k;
-      int lbytes;
-
-      lbytes = (bytes > 16 ? 16 : bytes);
-
-      printf ("  0x%8.8lx ", (unsigned long) addr);
-
-      for (j = 0; j < 16; j++)
-       {
-         if (j < lbytes)
-           printf ("%2.2x", start[j]);
-         else
-           printf ("  ");
-
-         if ((j & 3) == 3)
-           printf (" ");
-       }
-
-      for (j = 0; j < lbytes; j++)
-       {
-         k = start[j];
-         if (k >= ' ' && k < 0x80)
-           printf ("%c", k);
-         else
-           printf (".");
-       }
-
-      putchar ('\n');
-
-      start += lbytes;
-      addr  += lbytes;
-      bytes -= lbytes;
-    }
-
-  putchar ('\n');
-
-  return 1;
-}
-
-
-static int
-display_debug_info (Elf_Internal_Shdr * section,
-                   unsigned char * start, FILE * file)
-{
-  return process_debug_info (section, start, file, 0);
-}
-
-
-static int
-display_debug_aranges (Elf_Internal_Shdr *section,
-                      unsigned char *start,
-                      FILE *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *end = start + section->sh_size;
-
-  printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
-
-  while (start < end)
-    {
-      unsigned char *hdrptr;
-      DWARF2_Internal_ARange arange;
-      unsigned char *ranges;
-      unsigned long length;
-      unsigned long address;
-      int excess;
-      int offset_size;
-      int initial_length_size;
-
-      hdrptr = start;
-
-      arange.ar_length = byte_get (hdrptr, 4);
-      hdrptr += 4;
-
-      if (arange.ar_length == 0xffffffff)
-       {
-         arange.ar_length = byte_get (hdrptr, 8);
-         hdrptr += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
-
-      arange.ar_version = byte_get (hdrptr, 2);
-      hdrptr += 2;
-
-      arange.ar_info_offset = byte_get (hdrptr, offset_size);
-      hdrptr += offset_size;
-
-      arange.ar_pointer_size = byte_get (hdrptr, 1);
-      hdrptr += 1;
-
-      arange.ar_segment_size = byte_get (hdrptr, 1);
-      hdrptr += 1;
-
-      if (arange.ar_version != 2 && arange.ar_version != 3)
-       {
-         warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
-         break;
-       }
-
-      printf (_("  Length:                   %ld\n"), arange.ar_length);
-      printf (_("  Version:                  %d\n"), arange.ar_version);
-      printf (_("  Offset into .debug_info:  %lx\n"), arange.ar_info_offset);
-      printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
-      printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);
-
-      printf (_("\n    Address  Length\n"));
-
-      ranges = hdrptr;
-
-      /* Must pad to an alignment boundary that is twice the pointer size.  */
-      excess = (hdrptr - start) % (2 * arange.ar_pointer_size);
-      if (excess)
-       ranges += (2 * arange.ar_pointer_size) - excess;
-
-      for (;;)
-       {
-         address = byte_get (ranges, arange.ar_pointer_size);
-
-         ranges += arange.ar_pointer_size;
-
-         length  = byte_get (ranges, arange.ar_pointer_size);
-
-         ranges += arange.ar_pointer_size;
-
-         /* A pair of zeros marks the end of the list.  */
-         if (address == 0 && length == 0)
-           break;
-
-         printf ("    %8.8lx %lu\n", address, length);
-       }
-
-      start += arange.ar_length + initial_length_size;
-    }
-
-  printf ("\n");
-
-  return 1;
-}
-
-static int
-display_debug_ranges (Elf_Internal_Shdr *section,
-                     unsigned char *start,
-                     FILE *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *section_end;
-  unsigned long bytes;
-  unsigned char *section_begin = start;
-  unsigned int num_range_list = 0;
-  unsigned long last_offset = 0;
-  unsigned int first = 0;
-  unsigned int i;
-  unsigned int j;
-  int seen_first_offset = 0;
-  int use_debug_info = 1;
-  unsigned char *next;
-
-  bytes = section->sh_size;
-  section_end = start + bytes;
-
-  if (bytes == 0)
-    {
-      printf (_("\nThe .debug_ranges section is empty.\n"));
-      return 0;
-    }
-
-  get_debug_info (file);
-
-  /* Check the order of range list in .debug_info section. If
-     offsets of range lists are in the ascending order, we can
-     use `debug_information' directly.  */
-  for (i = 0; i < num_debug_info_entries; i++)
-    {
-      unsigned int num;
-
-      num = debug_information [i].num_range_lists;
-      num_range_list += num;
-
-      /* Check if we can use `debug_information' directly.  */
-      if (use_debug_info && num != 0)
-       {
-         if (!seen_first_offset)
-           {
-             /* This is the first range list.  */
-             last_offset = debug_information [i].range_lists [0];
-             first = i;
-             seen_first_offset = 1;
-             j = 1;
-           }
-         else
-           j = 0;
-
-         for (; j < num; j++)
-           {
-             if (last_offset >
-                 debug_information [i].range_lists [j])
-               {
-                 use_debug_info = 0;
-                 break;
-               }
-             last_offset = debug_information [i].range_lists [j];
-           }
-       }
-    }
-
-  if (!use_debug_info)
-    /* FIXME: Should we handle this case?  */
-    error (_("Range lists in .debug_info section aren't in ascending order!\n"));
-
-  if (!seen_first_offset)
-    error (_("No range lists in .debug_info section!\n"));
-
-  if (debug_information [first].range_lists [0] != 0)
-    warn (_("Range lists in .debug_ranges section start at 0x%lx\n"),
-         debug_information [first].range_lists [0]);
-
-  printf (_("Contents of the .debug_ranges section:\n\n"));
-  printf (_("    Offset   Begin    End\n"));
-
-  seen_first_offset = 0;
-  for (i = first; i < num_debug_info_entries; i++)
-    {
-      unsigned long begin;
-      unsigned long end;
-      unsigned long offset;
-      unsigned int pointer_size;
-      unsigned long base_address;
-
-      pointer_size = debug_information [i].pointer_size;
-
-      for (j = 0; j < debug_information [i].num_range_lists; j++)
-       {
-         offset = debug_information [i].range_lists [j];
-         next = section_begin + offset;
-         base_address = debug_information [i].base_address;
-
-         if (!seen_first_offset)
-           seen_first_offset = 1;
-         else
-           {
-             if (start < next)
-               warn (_("There is a hole [0x%lx - 0x%lx] in .debug_ranges section.\n"),
-                     (long)(start - section_begin), (long)(next - section_begin));
-             else if (start > next)
-               warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_ranges section.\n"),
-                     (long)(start - section_begin), (long)(next - section_begin));
-           }
-         start = next;
-
-         while (1)
-           {
-             begin = byte_get (start, pointer_size);
-             start += pointer_size;
-             end = byte_get (start, pointer_size);
-             start += pointer_size;
-
-             if (begin == 0 && end == 0)
-               {
-                 printf (_("    %8.8lx <End of list>\n"), offset);
-                 break;
-               }
-
-             /* Check base address specifiers.  */
-             if (begin == -1UL && end != -1UL)
-               {
-                 base_address = end;
-                 printf ("    %8.8lx %8.8lx %8.8lx (base address)\n",
-                         offset, begin, end);
-                 continue;
-               }
-
-             printf ("    %8.8lx %8.8lx %8.8lx",
-                     offset, begin + base_address, end + base_address);
-
-             if (begin == end)
-               fputs (_(" (start == end)"), stdout);
-             else if (begin > end)
-               fputs (_(" (start > end)"), stdout);
-
-             putchar ('\n');
-           }
-       }
-    }
-  putchar ('\n');
-  return 1;
-}
-
-typedef struct Frame_Chunk
-{
-  struct Frame_Chunk *next;
-  unsigned char *chunk_start;
-  int ncols;
-  /* DW_CFA_{undefined,same_value,offset,register,unreferenced}  */
-  short int *col_type;
-  int *col_offset;
-  char *augmentation;
-  unsigned int code_factor;
-  int data_factor;
-  unsigned long pc_begin;
-  unsigned long pc_range;
-  int cfa_reg;
-  int cfa_offset;
-  int ra;
-  unsigned char fde_encoding;
-  unsigned char cfa_exp;
-}
-Frame_Chunk;
-
-/* A marker for a col_type that means this column was never referenced
-   in the frame info.  */
-#define DW_CFA_unreferenced (-1)
-
-static void
-frame_need_space (Frame_Chunk *fc, int reg)
-{
-  int prev = fc->ncols;
-
-  if (reg < fc->ncols)
-    return;
-
-  fc->ncols = reg + 1;
-  fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
-  fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
-
-  while (prev < fc->ncols)
-    {
-      fc->col_type[prev] = DW_CFA_unreferenced;
-      fc->col_offset[prev] = 0;
-      prev++;
-    }
-}
-
-static void
-frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
-{
-  int r;
-  char tmp[100];
-
-  if (*max_regs < fc->ncols)
-    *max_regs = fc->ncols;
-
-  if (*need_col_headers)
-    {
-      *need_col_headers = 0;
-
-      printf ("   LOC   CFA      ");
-
-      for (r = 0; r < *max_regs; r++)
-       if (fc->col_type[r] != DW_CFA_unreferenced)
-         {
-           if (r == fc->ra)
-             printf ("ra   ");
-           else
-             printf ("r%-4d", r);
-         }
-
-      printf ("\n");
-    }
-
-  printf ("%08lx ", fc->pc_begin);
-  if (fc->cfa_exp)
-    strcpy (tmp, "exp");
-  else
-    sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
-  printf ("%-8s ", tmp);
-
-  for (r = 0; r < fc->ncols; r++)
-    {
-      if (fc->col_type[r] != DW_CFA_unreferenced)
-       {
-         switch (fc->col_type[r])
-           {
-           case DW_CFA_undefined:
-             strcpy (tmp, "u");
-             break;
-           case DW_CFA_same_value:
-             strcpy (tmp, "s");
-             break;
-           case DW_CFA_offset:
-             sprintf (tmp, "c%+d", fc->col_offset[r]);
-             break;
-           case DW_CFA_register:
-             sprintf (tmp, "r%d", fc->col_offset[r]);
-             break;
-           case DW_CFA_expression:
-             strcpy (tmp, "exp");
-             break;
-           default:
-             strcpy (tmp, "n/a");
-             break;
-           }
-         printf ("%-5s", tmp);
-       }
-    }
-  printf ("\n");
-}
-
-static int
-size_of_encoded_value (int encoding)
-{
-  switch (encoding & 0x7)
-    {
-    default:   /* ??? */
-    case 0:    return eh_addr_size;
-    case 2:    return 2;
-    case 3:    return 4;
-    case 4:    return 8;
-    }
-}
-
-static bfd_vma
-get_encoded_value (unsigned char *data, int encoding)
-{
-  int size = size_of_encoded_value (encoding);
-  if (encoding & DW_EH_PE_signed)
-    return byte_get_signed (data, size);
-  else
-    return byte_get (data, size);
-}
-
-#define GET(N) byte_get (start, N); start += N
-#define LEB()  read_leb128 (start, & length_return, 0); start += length_return
-#define SLEB() read_leb128 (start, & length_return, 1); start += length_return
-
-static int
-display_debug_frames (Elf_Internal_Shdr *section,
-                     unsigned char *start,
-                     FILE *file ATTRIBUTE_UNUSED)
-{
-  unsigned char *end = start + section->sh_size;
-  unsigned char *section_start = start;
-  Frame_Chunk *chunks = 0;
-  Frame_Chunk *remembered_state = 0;
-  Frame_Chunk *rs;
-  int is_eh = streq (SECTION_NAME (section), ".eh_frame");
-  unsigned int length_return;
-  int max_regs = 0;
-
-  printf (_("The section %s contains:\n"), SECTION_NAME (section));
-
-  while (start < end)
-    {
-      unsigned char *saved_start;
-      unsigned char *block_end;
-      unsigned long length;
-      unsigned long cie_id;
-      Frame_Chunk *fc;
-      Frame_Chunk *cie;
-      int need_col_headers = 1;
-      unsigned char *augmentation_data = NULL;
-      unsigned long augmentation_data_len = 0;
-      int encoded_ptr_size = eh_addr_size;
-      int offset_size;
-      int initial_length_size;
-
-      saved_start = start;
-      length = byte_get (start, 4); start += 4;
-
-      if (length == 0)
-       {
-         printf ("\n%08lx ZERO terminator\n\n",
-                   (unsigned long)(saved_start - section_start));
-         return 1;
-       }
-
-      if (length == 0xffffffff)
-       {
-         length = byte_get (start, 8);
-         start += 8;
-         offset_size = 8;
-         initial_length_size = 12;
-       }
-      else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
-
-      block_end = saved_start + length + initial_length_size;
-      cie_id = byte_get (start, offset_size); start += offset_size;
-
-      if (elf_header.e_type == ET_REL
-         && !debug_apply_rela_addends (file, section, offset_size,
-                                       section_start, start, block_end))
-       return 0;
-
-      if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
-       {
-         int version;
-
-         fc = xmalloc (sizeof (Frame_Chunk));
-         memset (fc, 0, sizeof (Frame_Chunk));
-
-         fc->next = chunks;
-         chunks = fc;
-         fc->chunk_start = saved_start;
-         fc->ncols = 0;
-         fc->col_type = xmalloc (sizeof (short int));
-         fc->col_offset = xmalloc (sizeof (int));
-         frame_need_space (fc, max_regs-1);
-
-         version = *start++;
-
-         fc->augmentation = (char *) start;
-         start = (unsigned char *) strchr ((char *) start, '\0') + 1;
-
-         if (fc->augmentation[0] == 'z')
-           {
-             fc->code_factor = LEB ();
-             fc->data_factor = SLEB ();
-             if (version == 1)
-               {
-                 fc->ra = GET (1);
-               }
-             else
-               {
-                 fc->ra = LEB ();
-               }
-             augmentation_data_len = LEB ();
-             augmentation_data = start;
-             start += augmentation_data_len;
-           }
-         else if (streq (fc->augmentation, "eh"))
-           {
-             start += eh_addr_size;
-             fc->code_factor = LEB ();
-             fc->data_factor = SLEB ();
-             if (version == 1)
-               {
-                 fc->ra = GET (1);
-               }
-             else
-               {
-                 fc->ra = LEB ();
-               }
-           }
-         else
-           {
-             fc->code_factor = LEB ();
-             fc->data_factor = SLEB ();
-             if (version == 1)
-               {
-                 fc->ra = GET (1);
-               }
-             else
-               {
-                 fc->ra = LEB ();
-               }
-           }
-         cie = fc;
-
-         if (do_debug_frames_interp)
-           printf ("\n%08lx %08lx %08lx CIE \"%s\" cf=%d df=%d ra=%d\n",
-                   (unsigned long)(saved_start - section_start), length, cie_id,
-                   fc->augmentation, fc->code_factor, fc->data_factor,
-                   fc->ra);
-         else
-           {
-             printf ("\n%08lx %08lx %08lx CIE\n",
-                     (unsigned long)(saved_start - section_start), length, cie_id);
-             printf ("  Version:               %d\n", version);
-             printf ("  Augmentation:          \"%s\"\n", fc->augmentation);
-             printf ("  Code alignment factor: %u\n", fc->code_factor);
-             printf ("  Data alignment factor: %d\n", fc->data_factor);
-             printf ("  Return address column: %d\n", fc->ra);
-
-             if (augmentation_data_len)
-               {
-                 unsigned long i;
-                 printf ("  Augmentation data:    ");
-                 for (i = 0; i < augmentation_data_len; ++i)
-                   printf (" %02x", augmentation_data[i]);
-                 putchar ('\n');
-               }
-             putchar ('\n');
-           }
-
-         if (augmentation_data_len)
-           {
-             unsigned char *p, *q;
-             p = (unsigned char *) fc->augmentation + 1;
-             q = augmentation_data;
-
-             while (1)
-               {
-                 if (*p == 'L')
-                   q++;
-                 else if (*p == 'P')
-                   q += 1 + size_of_encoded_value (*q);
-                 else if (*p == 'R')
-                   fc->fde_encoding = *q++;
-                 else
-                   break;
-                 p++;
-               }
-
-             if (fc->fde_encoding)
-               encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
-           }
-
-         frame_need_space (fc, fc->ra);
-       }
-      else
-       {
-         unsigned char *look_for;
-         static Frame_Chunk fde_fc;
-
-         fc = & fde_fc;
-         memset (fc, 0, sizeof (Frame_Chunk));
-
-         look_for = is_eh ? start - 4 - cie_id : section_start + cie_id;
-
-         for (cie = chunks; cie ; cie = cie->next)
-           if (cie->chunk_start == look_for)
-             break;
-
-         if (!cie)
-           {
-             warn ("Invalid CIE pointer %08lx in FDE at %p\n",
-                   cie_id, saved_start);
-             start = block_end;
-             fc->ncols = 0;
-             fc->col_type = xmalloc (sizeof (short int));
-             fc->col_offset = xmalloc (sizeof (int));
-             frame_need_space (fc, max_regs - 1);
-             cie = fc;
-             fc->augmentation = "";
-             fc->fde_encoding = 0;
-           }
-         else
-           {
-             fc->ncols = cie->ncols;
-             fc->col_type = xcmalloc (fc->ncols, sizeof (short int));
-             fc->col_offset = xcmalloc (fc->ncols, sizeof (int));
-             memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int));
-             memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int));
-             fc->augmentation = cie->augmentation;
-             fc->code_factor = cie->code_factor;
-             fc->data_factor = cie->data_factor;
-             fc->cfa_reg = cie->cfa_reg;
-             fc->cfa_offset = cie->cfa_offset;
-             fc->ra = cie->ra;
-             frame_need_space (fc, max_regs-1);
-             fc->fde_encoding = cie->fde_encoding;
-           }
-
-         if (fc->fde_encoding)
-           encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
-
-         fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
-         if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
-             /* Don't adjust for ET_REL since there's invariably a pcrel
-                reloc here, which we haven't applied.  */
-             && elf_header.e_type != ET_REL)
-           fc->pc_begin += section->sh_addr + (start - section_start);
-         start += encoded_ptr_size;
-         fc->pc_range = byte_get (start, encoded_ptr_size);
-         start += encoded_ptr_size;
-
-         if (cie->augmentation[0] == 'z')
-           {
-             augmentation_data_len = LEB ();
-             augmentation_data = start;
-             start += augmentation_data_len;
-           }
-
-         printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=%08lx..%08lx\n",
-                 (unsigned long)(saved_start - section_start), length, cie_id,
-                 (unsigned long)(cie->chunk_start - section_start),
-                 fc->pc_begin, fc->pc_begin + fc->pc_range);
-         if (! do_debug_frames_interp && augmentation_data_len)
-           {
-             unsigned long i;
-
-             printf ("  Augmentation data:    ");
-             for (i = 0; i < augmentation_data_len; ++i)
-               printf (" %02x", augmentation_data[i]);
-             putchar ('\n');
-             putchar ('\n');
-           }
-       }
-
-      /* At this point, fc is the current chunk, cie (if any) is set, and
-        we're about to interpret instructions for the chunk.  */
-      /* ??? At present we need to do this always, since this sizes the
-        fc->col_type and fc->col_offset arrays, which we write into always.
-        We should probably split the interpreted and non-interpreted bits
-        into two different routines, since there's so much that doesn't
-        really overlap between them.  */
-      if (1 || do_debug_frames_interp)
-       {
-         /* Start by making a pass over the chunk, allocating storage
-            and taking note of what registers are used.  */
-         unsigned char *tmp = start;
-
-         while (start < block_end)
-           {
-             unsigned op, opa;
-             unsigned long reg, tmp;
-
-             op = *start++;
-             opa = op & 0x3f;
-             if (op & 0xc0)
-               op &= 0xc0;
-
-             /* Warning: if you add any more cases to this switch, be
-                sure to add them to the corresponding switch below.  */
-             switch (op)
-               {
-               case DW_CFA_advance_loc:
-                 break;
-               case DW_CFA_offset:
-                 LEB ();
-                 frame_need_space (fc, opa);
-                 fc->col_type[opa] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_restore:
-                 frame_need_space (fc, opa);
-                 fc->col_type[opa] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_set_loc:
-                 start += encoded_ptr_size;
-                 break;
-               case DW_CFA_advance_loc1:
-                 start += 1;
-                 break;
-               case DW_CFA_advance_loc2:
-                 start += 2;
-                 break;
-               case DW_CFA_advance_loc4:
-                 start += 4;
-                 break;
-               case DW_CFA_offset_extended:
-                 reg = LEB (); LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_restore_extended:
-                 reg = LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_undefined:
-                 reg = LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_same_value:
-                 reg = LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_register:
-                 reg = LEB (); LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_def_cfa:
-                 LEB (); LEB ();
-                 break;
-               case DW_CFA_def_cfa_register:
-                 LEB ();
-                 break;
-               case DW_CFA_def_cfa_offset:
-                 LEB ();
-                 break;
-               case DW_CFA_def_cfa_expression:
-                 tmp = LEB ();
-                 start += tmp;
-                 break;
-               case DW_CFA_expression:
-                 reg = LEB ();
-                 tmp = LEB ();
-                 start += tmp;
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_offset_extended_sf:
-                 reg = LEB (); SLEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-                 break;
-               case DW_CFA_def_cfa_sf:
-                 LEB (); SLEB ();
-                 break;
-               case DW_CFA_def_cfa_offset_sf:
-                 SLEB ();
-                 break;
-               case DW_CFA_MIPS_advance_loc8:
-                 start += 8;
-                 break;
-               case DW_CFA_GNU_args_size:
-                 LEB ();
-                 break;
-               case DW_CFA_GNU_negative_offset_extended:
-                 reg = LEB (); LEB ();
-                 frame_need_space (fc, reg);
-                 fc->col_type[reg] = DW_CFA_undefined;
-
-               default:
-                 break;
-               }
-           }
-         start = tmp;
-       }
-
-      /* Now we know what registers are used, make a second pass over
-        the chunk, this time actually printing out the info.  */
-
-      while (start < block_end)
-       {
-         unsigned op, opa;
-         unsigned long ul, reg, roffs;
-         long l, ofs;
-         bfd_vma vma;
-
-         op = *start++;
-         opa = op & 0x3f;
-         if (op & 0xc0)
-           op &= 0xc0;
-
-         /* Warning: if you add any more cases to this switch, be
-            sure to add them to the corresponding switch above.  */
-         switch (op)
-           {
-           case DW_CFA_advance_loc:
-             if (do_debug_frames_interp)
-               frame_display_row (fc, &need_col_headers, &max_regs);
-             else
-               printf ("  DW_CFA_advance_loc: %d to %08lx\n",
-                       opa * fc->code_factor,
-                       fc->pc_begin + opa * fc->code_factor);
-             fc->pc_begin += opa * fc->code_factor;
-             break;
-
-           case DW_CFA_offset:
-             roffs = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_offset: r%d at cfa%+ld\n",
-                       opa, roffs * fc->data_factor);
-             fc->col_type[opa] = DW_CFA_offset;
-             fc->col_offset[opa] = roffs * fc->data_factor;
-             break;
-
-           case DW_CFA_restore:
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_restore: r%d\n", opa);
-             fc->col_type[opa] = cie->col_type[opa];
-             fc->col_offset[opa] = cie->col_offset[opa];
-             break;
-
-           case DW_CFA_set_loc:
-             vma = get_encoded_value (start, fc->fde_encoding);
-             if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
-                 && elf_header.e_type != ET_REL)
-               vma += section->sh_addr + (start - section_start);
-             start += encoded_ptr_size;
-             if (do_debug_frames_interp)
-               frame_display_row (fc, &need_col_headers, &max_regs);
-             else
-               printf ("  DW_CFA_set_loc: %08lx\n", (unsigned long)vma);
-             fc->pc_begin = vma;
-             break;
-
-           case DW_CFA_advance_loc1:
-             ofs = byte_get (start, 1); start += 1;
-             if (do_debug_frames_interp)
-               frame_display_row (fc, &need_col_headers, &max_regs);
-             else
-               printf ("  DW_CFA_advance_loc1: %ld to %08lx\n",
-                       ofs * fc->code_factor,
-                       fc->pc_begin + ofs * fc->code_factor);
-             fc->pc_begin += ofs * fc->code_factor;
-             break;
-
-           case DW_CFA_advance_loc2:
-             ofs = byte_get (start, 2); start += 2;
-             if (do_debug_frames_interp)
-               frame_display_row (fc, &need_col_headers, &max_regs);
-             else
-               printf ("  DW_CFA_advance_loc2: %ld to %08lx\n",
-                       ofs * fc->code_factor,
-                       fc->pc_begin + ofs * fc->code_factor);
-             fc->pc_begin += ofs * fc->code_factor;
-             break;
-
-           case DW_CFA_advance_loc4:
-             ofs = byte_get (start, 4); start += 4;
-             if (do_debug_frames_interp)
-               frame_display_row (fc, &need_col_headers, &max_regs);
-             else
-               printf ("  DW_CFA_advance_loc4: %ld to %08lx\n",
-                       ofs * fc->code_factor,
-                       fc->pc_begin + ofs * fc->code_factor);
-             fc->pc_begin += ofs * fc->code_factor;
-             break;
-
-           case DW_CFA_offset_extended:
-             reg = LEB ();
-             roffs = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_offset_extended: r%ld at cfa%+ld\n",
-                       reg, roffs * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_offset;
-             fc->col_offset[reg] = roffs * fc->data_factor;
-             break;
-
-           case DW_CFA_restore_extended:
-             reg = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_restore_extended: r%ld\n", reg);
-             fc->col_type[reg] = cie->col_type[reg];
-             fc->col_offset[reg] = cie->col_offset[reg];
-             break;
-
-           case DW_CFA_undefined:
-             reg = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_undefined: r%ld\n", reg);
-             fc->col_type[reg] = DW_CFA_undefined;
-             fc->col_offset[reg] = 0;
-             break;
-
-           case DW_CFA_same_value:
-             reg = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_same_value: r%ld\n", reg);
-             fc->col_type[reg] = DW_CFA_same_value;
-             fc->col_offset[reg] = 0;
-             break;
-
-           case DW_CFA_register:
-             reg = LEB ();
-             roffs = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_register: r%ld in r%ld\n", reg, roffs);
-             fc->col_type[reg] = DW_CFA_register;
-             fc->col_offset[reg] = roffs;
-             break;
-
-           case DW_CFA_remember_state:
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_remember_state\n");
-             rs = xmalloc (sizeof (Frame_Chunk));
-             rs->ncols = fc->ncols;
-             rs->col_type = xcmalloc (rs->ncols, sizeof (short int));
-             rs->col_offset = xcmalloc (rs->ncols, sizeof (int));
-             memcpy (rs->col_type, fc->col_type, rs->ncols);
-             memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int));
-             rs->next = remembered_state;
-             remembered_state = rs;
-             break;
-
-           case DW_CFA_restore_state:
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_restore_state\n");
-             rs = remembered_state;
-             if (rs)
-               {
-                 remembered_state = rs->next;
-                 frame_need_space (fc, rs->ncols-1);
-                 memcpy (fc->col_type, rs->col_type, rs->ncols);
-                 memcpy (fc->col_offset, rs->col_offset,
-                         rs->ncols * sizeof (int));
-                 free (rs->col_type);
-                 free (rs->col_offset);
-                 free (rs);
-               }
-             else if (do_debug_frames_interp)
-               printf ("Mismatched DW_CFA_restore_state\n");
-             break;
-
-           case DW_CFA_def_cfa:
-             fc->cfa_reg = LEB ();
-             fc->cfa_offset = LEB ();
-             fc->cfa_exp = 0;
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_def_cfa: r%d ofs %d\n",
-                       fc->cfa_reg, fc->cfa_offset);
-             break;
-
-           case DW_CFA_def_cfa_register:
-             fc->cfa_reg = LEB ();
-             fc->cfa_exp = 0;
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg);
-             break;
-
-           case DW_CFA_def_cfa_offset:
-             fc->cfa_offset = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset);
-             break;
-
-           case DW_CFA_nop:
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_nop\n");
-             break;
-
-           case DW_CFA_def_cfa_expression:
-             ul = LEB ();
-             if (! do_debug_frames_interp)
-               {
-                 printf ("  DW_CFA_def_cfa_expression (");
-                 decode_location_expression (start, eh_addr_size, ul, 0);
-                 printf (")\n");
-               }
-             fc->cfa_exp = 1;
-             start += ul;
-             break;
-
-           case DW_CFA_expression:
-             reg = LEB ();
-             ul = LEB ();
-             if (! do_debug_frames_interp)
-               {
-                 printf ("  DW_CFA_expression: r%ld (", reg);
-                 decode_location_expression (start, eh_addr_size, ul, 0);
-                 printf (")\n");
-               }
-             fc->col_type[reg] = DW_CFA_expression;
-             start += ul;
-             break;
-
-           case DW_CFA_offset_extended_sf:
-             reg = LEB ();
-             l = SLEB ();
-             frame_need_space (fc, reg);
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n",
-                       reg, l * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_offset;
-             fc->col_offset[reg] = l * fc->data_factor;
-             break;
-
-           case DW_CFA_def_cfa_sf:
-             fc->cfa_reg = LEB ();
-             fc->cfa_offset = SLEB ();
-             fc->cfa_offset = fc->cfa_offset * fc->data_factor;
-             fc->cfa_exp = 0;
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_def_cfa_sf: r%d ofs %d\n",
-                       fc->cfa_reg, fc->cfa_offset);
-             break;
-
-           case DW_CFA_def_cfa_offset_sf:
-             fc->cfa_offset = SLEB ();
-             fc->cfa_offset = fc->cfa_offset * fc->data_factor;
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset);
-             break;
-
-           case DW_CFA_MIPS_advance_loc8:
-             ofs = byte_get (start, 8); start += 8;
-             if (do_debug_frames_interp)
-               frame_display_row (fc, &need_col_headers, &max_regs);
-             else
-               printf ("  DW_CFA_MIPS_advance_loc8: %ld to %08lx\n",
-                       ofs * fc->code_factor,
-                       fc->pc_begin + ofs * fc->code_factor);
-             fc->pc_begin += ofs * fc->code_factor;
-             break;
-
-           case DW_CFA_GNU_window_save:
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_GNU_window_save\n");
-             break;
-
-           case DW_CFA_GNU_args_size:
-             ul = LEB ();
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_GNU_args_size: %ld\n", ul);
-             break;
+display_mips_gnu_attribute (unsigned char *p, int tag)
+{
+  int type;
+  unsigned int len;
+  int val;
 
-           case DW_CFA_GNU_negative_offset_extended:
-             reg = LEB ();
-             l = - LEB ();
-             frame_need_space (fc, reg);
-             if (! do_debug_frames_interp)
-               printf ("  DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n",
-                       reg, l * fc->data_factor);
-             fc->col_type[reg] = DW_CFA_offset;
-             fc->col_offset[reg] = l * fc->data_factor;
-             break;
+  if (tag == Tag_GNU_MIPS_ABI_FP)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_MIPS_ABI_FP: ");
 
-           default:
-             warn (_("unsupported or unknown DW_CFA_%d\n"), op);
-             start = block_end;
-           }
+      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;
+       case 4:
+         printf ("64-bit float (-mips32r2 -mfp64)\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
        }
+      return p;
+   }
 
-      if (do_debug_frames_interp)
-       frame_display_row (fc, &need_col_headers, &max_regs);
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
 
-      start = block_end;
+  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);
     }
 
-  printf ("\n");
-
-  return 1;
+  return p;
 }
 
-#undef GET
-#undef LEB
-#undef SLEB
-
 static int
-display_debug_not_supported (Elf_Internal_Shdr *section,
-                            unsigned char *start ATTRIBUTE_UNUSED,
-                            FILE *file ATTRIBUTE_UNUSED)
-{
-  printf (_("Displaying the debug contents of section %s is not yet supported.\n"),
-           SECTION_NAME (section));
+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;
+  unsigned char *p;
+  unsigned char *end;
+  bfd_vma section_len;
+  bfd_vma len;
+  unsigned i;
 
-  return 1;
-}
+  /* Find the section header so that we get the size.  */
+  for (i = 0, sect = section_headers;
+       i < elf_header.e_shnum;
+       i++, sect++)
+    {
+      if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES)
+       continue;
 
-/* A structure containing the name of a debug section
-   and a pointer to a function that can decode it.  */
-static struct
-{
-  const char *const name;
-  int (*display) (Elf_Internal_Shdr *, unsigned char *, FILE *);
-}
-debug_displays[] =
-{
-  { ".debug_abbrev",           display_debug_abbrev },
-  { ".debug_aranges",          display_debug_aranges },
-  { ".debug_frame",            display_debug_frames },
-  { ".debug_info",             display_debug_info },
-  { ".debug_line",             display_debug_lines },
-  { ".debug_pubnames",         display_debug_pubnames },
-  { ".eh_frame",               display_debug_frames },
-  { ".debug_macinfo",          display_debug_macinfo },
-  { ".debug_str",              display_debug_str },
-  { ".debug_loc",              display_debug_loc },
-  { ".debug_pubtypes",         display_debug_pubnames },
-  { ".debug_ranges",           display_debug_ranges },
-  { ".debug_static_func",      display_debug_not_supported },
-  { ".debug_static_vars",      display_debug_not_supported },
-  { ".debug_types",            display_debug_not_supported },
-  { ".debug_weaknames",                display_debug_not_supported }
-};
+      contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size,
+                          _("attributes"));
+      if (contents == NULL)
+       continue;
 
-static int
-display_debug_section (Elf_Internal_Shdr *section, FILE *file)
-{
-  char *name = SECTION_NAME (section);
-  bfd_size_type length;
-  int result = 1;
-  int i;
+      p = contents;
+      if (*p == 'A')
+       {
+         len = sect->sh_size - 1;
+         p++;
 
-  length = section->sh_size;
-  if (length == 0)
-    {
-      printf (_("\nSection '%s' has no debugging data.\n"), name);
-      return 0;
-    }
+         while (len > 0)
+           {
+             int namelen;
+             bfd_boolean public_section;
+             bfd_boolean gnu_section;
 
-  if (strneq (name, ".gnu.linkonce.wi.", 17))
-    name = ".debug_info";
+             section_len = byte_get (p, 4);
+             p += 4;
 
-  /* See if we know how to display the contents of this section.  */
-  for (i = NUM_ELEM (debug_displays); i--;)
-    if (streq (debug_displays[i].name, name))
-      {
-       unsigned char *start;
+             if (section_len > len)
+               {
+                 printf (_("ERROR: Bad section length (%d > %d)\n"),
+                         (int) section_len, (int) len);
+                 section_len = len;
+               }
 
-       start = get_data (NULL, file, section->sh_offset, 1, length,
-                         _("debug section data"));
-       if (start == NULL)
-         {
-           result = 0;
-           break;
-         }
+             len -= section_len;
+             printf ("Attribute Section: %s\n", p);
 
-       result &= debug_displays[i].display (section, start, file);
-       free (start);
+             if (public_name && streq ((char *) p, public_name))
+               public_section = TRUE;
+             else
+               public_section = FALSE;
 
-       /* If we loaded in the abbrev section
-          at some point, we must release it here.  */
-       free_abbrevs ();
+             if (streq ((char *) p, "gnu"))
+               gnu_section = TRUE;
+             else
+               gnu_section = FALSE;
 
-       break;
-      }
+             namelen = strlen ((char *) p) + 1;
+             p += namelen;
+             section_len -= namelen + 4;
 
-  if (i == -1)
-    {
-      printf (_("Unrecognized debug section: %s\n"), name);
-      result = 0;
-    }
+             while (section_len > 0)
+               {
+                 int tag = *(p++);
+                 int val;
+                 bfd_vma size;
 
-  return result;
-}
+                 size = byte_get (p, 4);
+                 if (size > section_len)
+                   {
+                     printf (_("ERROR: Bad subsection length (%d > %d)\n"),
+                             (int) size, (int) section_len);
+                     size = section_len;
+                   }
 
-static void
-process_section_contents (FILE *file)
-{
-  Elf_Internal_Shdr *section;
-  unsigned int i;
+                 section_len -= size;
+                 end = p + size - 1;
+                 p += 4;
 
-  if (! do_dump)
-    return;
+                 switch (tag)
+                   {
+                   case 1:
+                     printf ("File Attributes\n");
+                     break;
+                   case 2:
+                     printf ("Section Attributes:");
+                     goto do_numlist;
+                   case 3:
+                     printf ("Symbol Attributes:");
+                   do_numlist:
+                     for (;;)
+                       {
+                         unsigned int i;
 
-  for (i = 0, section = section_headers;
-       i < elf_header.e_shnum && i < num_dump_sects;
-       i++, section++)
-    {
-#ifdef SUPPORT_DISASSEMBLY
-      if (dump_sects[i] & DISASS_DUMP)
-       disassemble_section (section, file);
-#endif
-      if (dump_sects[i] & HEX_DUMP)
-       dump_section (section, file);
+                         val = read_uleb128 (p, &i);
+                         p += i;
+                         if (val == 0)
+                           break;
+                         printf (" %d", val);
+                       }
+                     printf ("\n");
+                     break;
+                   default:
+                     printf ("Unknown tag: %d\n", tag);
+                     public_section = FALSE;
+                     break;
+                   }
 
-      if (dump_sects[i] & DEBUG_DUMP)
-       display_debug_section (section, file);
+                 if (public_section)
+                   {
+                     while (p < end)
+                       p = display_pub_attribute (p);
+                   }
+                 else if (gnu_section)
+                   {
+                     while (p < end)
+                       p = display_gnu_attribute (p,
+                                                  display_proc_gnu_attribute);
+                   }
+                 else
+                   {
+                     /* ??? Do something sensible, like dump hex.  */
+                     printf ("  Unknown section contexts\n");
+                     p = end;
+                   }
+               }
+           }
+       }
+      else
+       printf (_("Unknown format '%c'\n"), *p);
+
+      free (contents);
     }
+  return 1;
+}
 
-  /* Check to see if the user requested a
-     dump of a section that does not exist.  */
-  while (i++ < num_dump_sects)
-    if (dump_sects[i])
-      warn (_("Section %d was not dumped because it does not exist!\n"), i);
+static int
+process_arm_specific (FILE *file)
+{
+  return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES,
+                            display_arm_attribute, NULL);
 }
 
-static void
-process_mips_fpe_exception (int mask)
+static int
+process_power_specific (FILE *file)
 {
-  if (mask)
-    {
-      int first = 1;
-      if (mask & OEX_FPU_INEX)
-       fputs ("INEX", stdout), first = 0;
-      if (mask & OEX_FPU_UFLO)
-       printf ("%sUFLO", first ? "" : "|"), first = 0;
-      if (mask & OEX_FPU_OFLO)
-       printf ("%sOFLO", first ? "" : "|"), first = 0;
-      if (mask & OEX_FPU_DIV0)
-       printf ("%sDIV0", first ? "" : "|"), first = 0;
-      if (mask & OEX_FPU_INVAL)
-       printf ("%sINVAL", first ? "" : "|");
-    }
-  else
-    fputs ("0", stdout);
+  return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
+                            display_power_gnu_attribute);
 }
 
 static int
@@ -11321,6 +9076,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.  */
@@ -11415,9 +9173,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);
@@ -11454,7 +9210,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;
            }
 
@@ -11639,14 +9395,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;
        }
 
@@ -11808,6 +9564,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:
@@ -11838,6 +9596,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)
 {
@@ -11908,6 +9687,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)
@@ -11915,18 +9695,27 @@ process_note (Elf_Internal_Note *pnote)
        note type strings.  */
     nt = get_note_type (pnote->type);
 
-  else if (strneq (pnote->namedata, "NetBSD-CORE", 11))
+  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;
 }
 
@@ -12080,10 +9869,15 @@ process_arch_specific (FILE *file)
 
   switch (elf_header.e_machine)
     {
+    case EM_ARM:
+      return process_arm_specific (file);
     case EM_MIPS:
     case EM_MIPS_RS3_LE:
       return process_mips_specific (file);
       break;
+    case EM_PPC:
+      return process_power_specific (file);
+      break;
     default:
       break;
     }
@@ -12199,10 +9993,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.  */
@@ -12214,18 +10008,19 @@ 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 ())
     return 1;
 
@@ -12328,28 +10123,13 @@ process_object (char *file_name, FILE *file)
       section_groups = NULL;
     }
 
-  if (debug_information)
-    {
-      for (i = 0; i < num_debug_info_entries; i++)
-       {
-         if (!debug_information [i].max_loc_offsets)
-           {
-             free (debug_information [i].loc_offsets);
-             free (debug_information [i].have_frame_base);
-           }
-         if (!debug_information [i].max_range_lists)
-           free (debug_information [i].range_lists);
-       }
-      free (debug_information);
-      debug_information = NULL;
-      num_debug_info_entries = 0;
-    }
+  free_debug_memory ();
 
   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)
@@ -12357,6 +10137,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;
@@ -12374,63 +10158,245 @@ process_archive (char *file_name, FILE *file)
       return 1;
     }
 
-  if (memcmp (arhdr.ar_name, "/               ", 16) == 0)
+  /* 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)
+       {
+         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
        {
-         error (_("%s: failed to skip archive symbol table\n"), file_name);
-         return 1;
+         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 (memcmp (arhdr.ar_name, "//              ", 16) == 0)
+  if (const_strneq (arhdr.ar_name, "//              "))
     {
       /* This is the archive string table holding long member
         names.  */
 
       longnames_size = strtoul (arhdr.ar_size, NULL, 10);
-
       longnames = malloc (longnames_size);
       if (longnames == NULL)
        {
-         error (_("Out of memory\n"));
-         return 1;
+         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);
@@ -12486,7 +10452,7 @@ process_archive (char *file_name, FILE *file)
 
       archive_file_offset = ftell (file);
       archive_file_size = strtoul (arhdr.ar_size, NULL, 10);
-      
+
       ret |= process_object (namealc, file);
 
       free (namealc);
@@ -12514,7 +10480,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;
@@ -12553,7 +10524,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;
     }
@@ -12562,6 +10533,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);
@@ -12605,17 +10580,20 @@ main (int argc, char **argv)
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 
+  expandargv (&argc, &argv);
+
   parse_args (argc, 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;
        }
     }