* ld-ifunc/ifunc.exp: Match R_PPC64_JUMP_IREL.
[deliverable/binutils-gdb.git] / binutils / readelf.c
index 1c4c7152a5a81a1832e230b3128b4d3c8bd08d12..a8c16914c32aebe90162a1a1b1d3912b8e708292 100644 (file)
@@ -1,6 +1,6 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+   2008, 2009  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 "config.h"
 #include "sysdep.h"
 #include <assert.h>
 #include <sys/stat.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
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
 #endif
 
 #if __GNUC__ >= 2
 #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/i960.h"
 #include "elf/ia64.h"
 #include "elf/ip2k.h"
+#include "elf/lm32.h"
 #include "elf/iq2000.h"
 #include "elf/m32c.h"
 #include "elf/m32r.h"
 #include "elf/m68hc11.h"
 #include "elf/mcore.h"
 #include "elf/mep.h"
+#include "elf/microblaze.h"
 #include "elf/mips.h"
 #include "elf/mmix.h"
 #include "elf/mn10200.h"
 
 #include "getopt.h"
 #include "libiberty.h"
+#include "safe-ctype.h"
+#include "filenames.h"
 
-char *program_name = "readelf";
+char * program_name = "readelf";
+int do_wide;
 static long archive_file_offset;
 static unsigned long archive_file_size;
 static unsigned long dynamic_addr;
 static bfd_size_type dynamic_size;
 static unsigned int dynamic_nent;
-static char *dynamic_strings;
+static char * dynamic_strings;
 static unsigned long dynamic_strings_length;
-static char *string_table;
+static char * string_table;
 static unsigned long string_table_length;
 static unsigned long num_dynamic_syms;
-static Elf_Internal_Sym *dynamic_symbols;
-static Elf_Internal_Syminfo *dynamic_syminfo;
+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[PATH_MAX];
@@ -178,10 +169,10 @@ 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;
-static Elf_Internal_Phdr *program_headers;
-static Elf_Internal_Dyn *dynamic_section;
-static Elf_Internal_Shdr *symtab_shndx_hdr;
+static Elf_Internal_Shdr * section_headers;
+static Elf_Internal_Phdr * program_headers;
+static Elf_Internal_Dyn *  dynamic_section;
+static Elf_Internal_Shdr * symtab_shndx_hdr;
 static int show_name;
 static int do_dynamic;
 static int do_syms;
@@ -195,56 +186,61 @@ static int do_using_dynamic;
 static int do_header;
 static int do_dump;
 static int do_version;
-static int do_wide;
 static int do_histogram;
 static int do_debugging;
 static int do_arch;
 static int do_notes;
+static int do_archive_index;
 static int is_32bit_elf;
 
 struct group_list
 {
-  struct group_list *next;
+  struct group_list * next;
   unsigned int section_index;
 };
 
 struct group
 {
-  struct group_list *root;
+  struct group_list * root;
   unsigned int group_index;
 };
 
 static size_t group_count;
-static struct group *section_groups;
-static struct group **section_headers_groups;
+static struct group * section_groups;
+static struct group ** section_headers_groups;
+
 
-/* A linked list of the section names for which dumps were requested
-   by name.  */
+/* Flag bits indicating particular types of dump.  */
+#define HEX_DUMP       (1 << 0)        /* The -x command line switch.  */
+#define DISASS_DUMP    (1 << 1)        /* The -i command line switch.  */
+#define DEBUG_DUMP     (1 << 2)        /* The -w command line switch.  */
+#define STRING_DUMP     (1 << 3)       /* The -p command line switch.  */
+#define RELOC_DUMP      (1 << 4)       /* The -R command line switch.  */
+
+typedef unsigned char dump_type;
+
+/* A linked list of the section names for which dumps were requested.  */
 struct dump_list_entry
 {
-  char *name;
-  int type;
-  struct dump_list_entry *next;
+  char * name;
+  dump_type type;
+  struct dump_list_entry * next;
 };
-static struct dump_list_entry *dump_sects_byname;
+static struct dump_list_entry * dump_sects_byname;
 
-/* A dynamic array of flags indicating for which sections a hex dump
-   has been requested (via the -x switch) and/or a disassembly dump
-   (via the -i switch).  */
-char *cmdline_dump_sects = NULL;
-unsigned num_cmdline_dump_sects = 0;
+/* A dynamic array of flags indicating for which sections a dump
+   has been requested via command line switches.  */
+static dump_type *   cmdline_dump_sects = NULL;
+static unsigned int  num_cmdline_dump_sects = 0;
 
 /* A dynamic array of flags indicating for which sections a dump of
    some kind has been requested.  It is reset on a per-object file
    basis and then initialised from the cmdline_dump_sects array,
    the results of interpreting the -w switch, and the
    dump_sects_byname list.  */
-char *dump_sects = NULL;
-unsigned int num_dump_sects = 0;
+static dump_type *   dump_sects = NULL;
+static unsigned int  num_dump_sects = 0;
 
-#define HEX_DUMP       (1 << 0)
-#define DISASS_DUMP    (1 << 1)
-#define DEBUG_DUMP     (1 << 2)
 
 /* How to print a vma value.  */
 typedef enum print_mode
@@ -259,7 +255,7 @@ typedef enum print_mode
 }
 print_mode;
 
-static void (*byte_put) (unsigned char *, bfd_vma, int);
+static void (* byte_put) (unsigned char *, bfd_vma, int);
 
 #define UNKNOWN -1
 
@@ -269,28 +265,10 @@ static void (*byte_put) (unsigned char *, bfd_vma, int);
   : ((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)                                \
-  ((I) < SHN_LORESERVE                                 \
-   ? (I)                                               \
-   : ((I) <= SHN_HIRESERVE                             \
-      ? 0                                              \
-      : (I) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))
-
-/* Reverse of the above.  */
-#define SECTION_HEADER_NUM(N)                          \
-  ((N) < SHN_LORESERVE                                 \
-   ? (N)                                               \
-   : (N) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))
-
-#define SECTION_HEADER(I) (section_headers + SECTION_HEADER_INDEX (I))
-
 #define DT_VERSIONTAGIDX(tag)  (DT_VERNEEDNUM - (tag)) /* Reverse order!  */
 
 #define BYTE_GET(field)        byte_get (field, sizeof (field))
 
-#define NUM_ELEM(array)        (sizeof (array) / sizeof ((array)[0]))
-
 #define GET_ELF_SYMBOLS(file, section)                 \
   (is_32bit_elf ? get_32bit_elf_symbols (file, section)        \
    : get_64bit_elf_symbols (file, section))
@@ -301,15 +279,15 @@ 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 *
-get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
-         const char *reason)
+get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
+         const char * reason)
 {
-  void *mvar;
+  void * mvar;
 
   if (size == 0 || nmemb == 0)
     return NULL;
@@ -317,7 +295,7 @@ get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
   if (fseek (file, archive_file_offset + offset, SEEK_SET))
     {
       error (_("Unable to seek to 0x%lx for %s\n"),
-            archive_file_offset + offset, reason);
+            (unsigned long) archive_file_offset + offset, reason);
       return NULL;
     }
 
@@ -352,7 +330,7 @@ get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
 }
 
 static void
-byte_put_little_endian (unsigned char *field, bfd_vma value, int size)
+byte_put_little_endian (unsigned char * field, bfd_vma value, int size)
 {
   switch (size)
     {
@@ -379,169 +357,141 @@ byte_put_little_endian (unsigned char *field, bfd_vma value, int size)
     }
 }
 
-#if defined BFD64 && !BFD_HOST_64BIT_LONG
+/* Print a VMA value.  */
+
 static int
-print_dec_vma (bfd_vma vma, int is_signed)
+print_vma (bfd_vma vma, print_mode mode)
 {
-  char buf[40];
-  char *bufp = buf;
   int nc = 0;
 
-  if (is_signed && (bfd_signed_vma) vma < 0)
+  switch (mode)
     {
-      vma = -vma;
-      putchar ('-');
-      nc = 1;
-    }
+    case FULL_HEX:
+      nc = printf ("0x");
+      /* Drop through.  */
 
-  do
-    {
-      *bufp++ = '0' + vma % 10;
-      vma /= 10;
-    }
-  while (vma != 0);
-  nc += bufp - buf;
+    case LONG_HEX:
+#ifdef BFD64
+      if (is_32bit_elf)
+       return nc + printf ("%8.8" BFD_VMA_FMT "x", vma);
+#endif
+      printf_vma (vma);
+      return nc + 16;
+
+    case DEC_5:
+      if (vma <= 99999)
+       return printf ("%5" BFD_VMA_FMT "d", vma);
+      /* Drop through.  */
+
+    case PREFIX_HEX:
+      nc = printf ("0x");
+      /* Drop through.  */
+
+    case HEX:
+      return nc + printf ("%" BFD_VMA_FMT "x", vma);
 
-  while (bufp > buf)
-    putchar (*--bufp);
-  return nc;
+    case DEC:
+      return printf ("%" BFD_VMA_FMT "d", vma);
+
+    case UNSIGNED:
+      return printf ("%" BFD_VMA_FMT "u", vma);
+    }
+  return 0;
 }
 
-static int
-print_hex_vma (bfd_vma vma)
+/* Display a symbol on stdout.  Handles the display of non-printing characters.
+
+   If DO_WIDE is not true then format the symbol to be at most WIDTH characters,
+   truncating as necessary.  If WIDTH is negative then format the string to be
+   exactly - WIDTH characters, truncating or padding as necessary.
+
+   Returns the number of emitted characters.  */
+
+static unsigned int
+print_symbol (int width, const char * symbol)
 {
-  char buf[32];
-  char *bufp = buf;
-  int nc;
+  const char * c;
+  bfd_boolean extra_padding = FALSE;
+  unsigned int num_printed = 0;
 
-  do
+  if (do_wide)
     {
-      char digit = '0' + (vma & 0x0f);
-      if (digit > '9')
-       digit += 'a' - '0' - 10;
-      *bufp++ = digit;
-      vma >>= 4;
+      /* Set the width to a very large value.  This simplifies the code below.  */
+      width = INT_MAX;
+    }
+  else if (width < 0)
+    {
+      /* Keep the width positive.  This also helps.  */
+      width = - width;
+      extra_padding = TRUE;
     }
-  while (vma != 0);
-  nc = bufp - buf;
-
-  while (bufp > buf)
-    putchar (*--bufp);
-  return nc;
-}
-#endif
 
-/* Print a VMA value.  */
-static int
-print_vma (bfd_vma vma, print_mode mode)
-{
-#ifdef BFD64
-  if (is_32bit_elf)
-#endif
+  while (width)
     {
-      switch (mode)
-       {
-       case FULL_HEX:
-         return printf ("0x%8.8lx", (unsigned long) vma);
+      int len;
 
-       case LONG_HEX:
-         return printf ("%8.8lx", (unsigned long) vma);
+      c = symbol;
 
-       case DEC_5:
-         if (vma <= 99999)
-           return printf ("%5ld", (long) vma);
-         /* Drop through.  */
+      /* Look for non-printing symbols inside the symbol's name.
+        This test is triggered in particular by the names generated
+        by the assembler for local labels.  */
+      while (ISPRINT (* c))
+       c++;
 
-       case PREFIX_HEX:
-         return printf ("0x%lx", (unsigned long) vma);
+      len = c - symbol;
 
-       case HEX:
-         return printf ("%lx", (unsigned long) vma);
+      if (len)
+       {
+         if (len > width)
+           len = width;
 
-       case DEC:
-         return printf ("%ld", (unsigned long) vma);
+         printf ("%.*s", len, symbol);
 
-       case UNSIGNED:
-         return printf ("%lu", (unsigned long) vma);
+         width -= len;
+         num_printed += len;
        }
-    }
-#ifdef BFD64
-  else
-    {
-      int nc = 0;
-
-      switch (mode)
-       {
-       case FULL_HEX:
-         nc = printf ("0x");
-         /* Drop through.  */
 
-       case LONG_HEX:
-         printf_vma (vma);
-         return nc + 16;
+      if (* c == 0 || width == 0)
+       break;
 
-       case PREFIX_HEX:
-         nc = printf ("0x");
-         /* Drop through.  */
+      /* Now display the non-printing character, if
+        there is room left in which to dipslay it.  */
+      if (*c < 32)
+       {
+         if (width < 2)
+           break;
 
-       case HEX:
-#if BFD_HOST_64BIT_LONG
-         return nc + printf ("%lx", vma);
-#else
-         return nc + print_hex_vma (vma);
-#endif
+         printf ("^%c", *c + 0x40);
 
-       case DEC:
-#if BFD_HOST_64BIT_LONG
-         return printf ("%ld", vma);
-#else
-         return print_dec_vma (vma, 1);
-#endif
+         width -= 2;
+         num_printed += 2;
+       }
+      else
+       {
+         if (width < 6)
+           break;
 
-       case DEC_5:
-#if BFD_HOST_64BIT_LONG
-         if (vma <= 99999)
-           return printf ("%5ld", vma);
-         else
-           return printf ("%#lx", vma);
-#else
-         if (vma <= 99999)
-           return printf ("%5ld", _bfd_int64_low (vma));
-         else
-           return print_hex_vma (vma);
-#endif
+         printf ("<0x%.2x>", *c);
 
-       case UNSIGNED:
-#if BFD_HOST_64BIT_LONG
-         return printf ("%lu", vma);
-#else
-         return print_dec_vma (vma, 0);
-#endif
+         width -= 6;
+         num_printed += 6;
        }
+
+      symbol = c + 1;
     }
-#endif
-  return 0;
-}
 
-/* Display a symbol on stdout.  If do_wide is not true then
-   format the symbol to be at most WIDTH characters,
-   truncating as necessary.  If WIDTH is negative then
-   format the string to be exactly - WIDTH characters,
-   truncating or padding as necessary.  */
+  if (extra_padding && width > 0)
+    {
+      /* Fill in the remaining spaces.  */
+      printf ("%-*s", width, " ");
+      num_printed += 2;
+    }
 
-static void
-print_symbol (int width, const char *symbol)
-{
-  if (do_wide)
-    printf ("%s", symbol);
-  else if (width < 0)
-    printf ("%-*.*s", width, width, symbol);
-  else
-    printf ("%-.*s", width, symbol);
+  return num_printed;
 }
 
 static void
-byte_put_big_endian (unsigned char *field, bfd_vma value, int size)
+byte_put_big_endian (unsigned char * field, bfd_vma value, int size)
 {
   switch (size)
     {
@@ -575,7 +525,7 @@ byte_put_big_endian (unsigned char *field, bfd_vma value, int size)
 /* Return a pointer to section NAME, or NULL if no such section exists.  */
 
 static Elf_Internal_Shdr *
-find_section (const char *name)
+find_section (const char * name)
 {
   unsigned int i;
 
@@ -589,7 +539,7 @@ find_section (const char *name)
 /* Guess the relocation size commonly used by the specific machines.  */
 
 static int
-guess_is_rela (unsigned long e_machine)
+guess_is_rela (unsigned int e_machine)
 {
   switch (e_machine)
     {
@@ -617,6 +567,8 @@ guess_is_rela (unsigned long e_machine)
     case EM_AVR:
     case EM_AVR_OLD:
     case EM_BLACKFIN:
+    case EM_CR16:
+    case EM_CR16_OLD:
     case EM_CRIS:
     case EM_CRX:
     case EM_D30V:
@@ -631,6 +583,8 @@ guess_is_rela (unsigned long e_machine)
     case EM_IP2K:
     case EM_IP2K_OLD:
     case EM_IQ2000:
+    case EM_LATTICEMICO32:
+    case EM_M32C_OLD:
     case EM_M32C:
     case EM_M32R:
     case EM_MCORE:
@@ -657,9 +611,12 @@ guess_is_rela (unsigned long e_machine)
     case EM_CYGNUS_V850:
     case EM_VAX:
     case EM_X86_64:
+    case EM_L1OM:
     case EM_XSTORMY16:
     case EM_XTENSA:
     case EM_XTENSA_OLD:
+    case EM_MICROBLAZE:
+    case EM_MICROBLAZE_OLD:
       return TRUE;
 
     case EM_68HC05:
@@ -686,19 +643,19 @@ guess_is_rela (unsigned long e_machine)
 }
 
 static int
-slurp_rela_relocs (FILE *file,
+slurp_rela_relocs (FILE * file,
                   unsigned long rel_offset,
                   unsigned long rel_size,
-                  Elf_Internal_Rela **relasp,
-                  unsigned long *nrelasp)
+                  Elf_Internal_Rela ** relasp,
+                  unsigned long * nrelasp)
 {
-  Elf_Internal_Rela *relas;
+  Elf_Internal_Rela * relas;
   unsigned long nrelas;
   unsigned int i;
 
   if (is_32bit_elf)
     {
-      Elf32_External_Rela *erelas;
+      Elf32_External_Rela * erelas;
 
       erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erelas)
@@ -726,7 +683,7 @@ slurp_rela_relocs (FILE *file,
     }
   else
     {
-      Elf64_External_Rela *erelas;
+      Elf64_External_Rela * erelas;
 
       erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erelas)
@@ -748,6 +705,28 @@ slurp_rela_relocs (FILE *file,
          relas[i].r_offset = BYTE_GET (erelas[i].r_offset);
          relas[i].r_info   = BYTE_GET (erelas[i].r_info);
          relas[i].r_addend = BYTE_GET (erelas[i].r_addend);
+
+         /* 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
+             && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
+           {
+             /* 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.  */
+             bfd_vma info = relas[i].r_info;
+             info = (((info & 0xffffffff) << 32)
+                     | ((info >> 56) & 0xff)
+                     | ((info >> 40) & 0xff00)
+                     | ((info >> 24) & 0xff0000)
+                     | ((info >> 8) & 0xff000000));
+             relas[i].r_info = info;
+           }
+#endif /* BFD64 */
        }
 
       free (erelas);
@@ -758,19 +737,19 @@ slurp_rela_relocs (FILE *file,
 }
 
 static int
-slurp_rel_relocs (FILE *file,
+slurp_rel_relocs (FILE * file,
                  unsigned long rel_offset,
                  unsigned long rel_size,
-                 Elf_Internal_Rela **relsp,
-                 unsigned long *nrelsp)
+                 Elf_Internal_Rela ** relsp,
+                 unsigned long * nrelsp)
 {
-  Elf_Internal_Rela *rels;
+  Elf_Internal_Rela * rels;
   unsigned long nrels;
   unsigned int i;
 
   if (is_32bit_elf)
     {
-      Elf32_External_Rel *erels;
+      Elf32_External_Rel * erels;
 
       erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erels)
@@ -798,7 +777,7 @@ slurp_rel_relocs (FILE *file,
     }
   else
     {
-      Elf64_External_Rel *erels;
+      Elf64_External_Rel * erels;
 
       erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erels)
@@ -820,6 +799,28 @@ slurp_rel_relocs (FILE *file,
          rels[i].r_offset = BYTE_GET (erels[i].r_offset);
          rels[i].r_info   = BYTE_GET (erels[i].r_info);
          rels[i].r_addend = 0;
+
+         /* 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
+             && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
+           {
+             /* 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.  */
+             bfd_vma info = rels[i].r_info;
+             info = (((info & 0xffffffff) << 32)
+                     | ((info >> 56) & 0xff)
+                     | ((info >> 40) & 0xff00)
+                     | ((info >> 24) & 0xff0000)
+                     | ((info >> 8) & 0xff000000));
+             rels[i].r_info = info;
+           }
+#endif /* BFD64 */
        }
 
       free (erels);
@@ -829,22 +830,51 @@ 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
-dump_relocations (FILE *file,
+static void
+dump_relocations (FILE * file,
                  unsigned long rel_offset,
                  unsigned long rel_size,
-                 Elf_Internal_Sym *symtab,
+                 Elf_Internal_Sym * symtab,
                  unsigned long nsyms,
-                 char *strtab,
+                 char * strtab,
                  unsigned long strtablen,
                  int is_rela)
 {
   unsigned int i;
-  Elf_Internal_Rela *rels;
-
+  Elf_Internal_Rela * rels;
 
   if (is_rela == UNKNOWN)
     is_rela = guess_is_rela (elf_header.e_machine);
@@ -852,12 +882,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)
@@ -897,66 +927,44 @@ dump_relocations (FILE *file,
 
   for (i = 0; i < rel_size; i++)
     {
-      const char *rtype;
-      const char *rtype2 = NULL;
-      const char *rtype3 = NULL;
+      const char * rtype;
       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;
 
+      type = get_reloc_type (info);
+      symtab_index = get_reloc_symindex  (info);
+
       if (is_32bit_elf)
        {
-         type         = ELF32_R_TYPE (info);
-         symtab_index = ELF32_R_SYM  (info);
+         printf ("%8.8lx  %8.8lx ",
+                 (unsigned long) offset & 0xffffffff,
+                 (unsigned long) info & 0xffffffff);
        }
       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);
-
-         symtab_index = ELF64_R_SYM  (info);
-#endif
-       }
-
-      if (is_32bit_elf)
-       {
-#ifdef _bfd_int64_low
-         printf ("%8.8lx  %8.8lx ", _bfd_int64_low (offset), _bfd_int64_low (info));
+#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 ("%8.8lx  %8.8lx ", offset, info);
+         printf (do_wide
+                 ? "%16.16I64x  %16.16I64x "
+                 : "%12.12I64x  %12.12I64x ",
+                 offset, info);
 #endif
-       }
-      else
-       {
-#ifdef _bfd_int64_low
+#else
          printf (do_wide
                  ? "%8.8lx%8.8lx  %8.8lx%8.8lx "
                  : "%4.4lx%8.8lx  %4.4lx%8.8lx ",
@@ -964,11 +972,6 @@ dump_relocations (FILE *file,
                  _bfd_int64_low (offset),
                  _bfd_int64_high (info),
                  _bfd_int64_low (info));
-#else
-         printf (do_wide
-                 ? "%16.16lx  %16.16lx "
-                 : "%12.12lx  %12.12lx ",
-                 offset, info);
 #endif
        }
 
@@ -1083,11 +1086,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:
@@ -1134,6 +1132,7 @@ dump_relocations (FILE *file,
          break;
 
        case EM_X86_64:
+       case EM_L1OM:
          rtype = elf_x86_64_reloc_type (type);
          break;
 
@@ -1176,6 +1175,11 @@ dump_relocations (FILE *file,
          rtype = elf_xtensa_reloc_type (type);
          break;
 
+       case EM_LATTICEMICO32:
+         rtype = elf_lm32_reloc_type (type);
+         break;
+
+       case EM_M32C_OLD:
        case EM_M32C:
          rtype = elf_m32c_reloc_type (type);
          break;
@@ -1191,14 +1195,20 @@ dump_relocations (FILE *file,
        case EM_CYGNUS_MEP:
          rtype = elf_mep_reloc_type (type);
          break;
+
+       case EM_CR16:
+       case EM_CR16_OLD:
+         rtype = elf_cr16_reloc_type (type);
+         break;
+       
+       case EM_MICROBLAZE:
+       case EM_MICROBLAZE_OLD:
+         rtype = elf_microblaze_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);
 
@@ -1233,31 +1243,55 @@ dump_relocations (FILE *file,
            printf (" bad symbol index: %08lx", (unsigned long) symtab_index);
          else
            {
-             Elf_Internal_Sym *psym;
+             Elf_Internal_Sym * psym;
 
              psym = symtab + symtab_index;
 
              printf (" ");
-             print_vma (psym->st_value, LONG_HEX);
-             printf (is_32bit_elf ? "   " : " ");
+
+             if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
+               {
+                 const char * name;
+                 unsigned int len;
+                 unsigned int width = is_32bit_elf ? 8 : 14;
+
+                 /* Relocations against GNU_IFUNC symbols do not use the value
+                    of the symbol as the address to relocate against.  Instead
+                    they invoke the function named by the symbol and use its
+                    result as the address for relocation.
+
+                    To indicate this to the user, do not display the value of
+                    the symbol in the "Symbols's Value" field.  Instead show
+                    its name followed by () as a hint that the symbol is
+                    invoked.  */
+
+                 if (strtab == NULL
+                     || psym->st_name == 0
+                     || psym->st_name >= strtablen)
+                   name = "??";
+                 else
+                   name = strtab + psym->st_name;
+
+                 len = print_symbol (width, name);
+                 printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
+               }
+             else
+               {
+                 print_vma (psym->st_value, LONG_HEX);
+
+                 printf (is_32bit_elf ? "   " : " ");
+               }
 
              if (psym->st_name == 0)
                {
-                 const char *sec_name = "<null>";
+                 const char * sec_name = "<null>";
                  char name_buf[40];
 
                  if (ELF_ST_TYPE (psym->st_info) == STT_SECTION)
                    {
-                     bfd_vma sec_index = (bfd_vma) -1;
-
-                     if (psym->st_shndx < SHN_LORESERVE)
-                       sec_index = psym->st_shndx;
-                     else if (psym->st_shndx > SHN_HIRESERVE)
-                       sec_index = psym->st_shndx - (SHN_HIRESERVE + 1
-                                                     - SHN_LORESERVE);
-
-                     if (sec_index != (bfd_vma) -1)
-                       sec_name = SECTION_NAME (section_headers + sec_index);
+                     if (psym->st_shndx < elf_header.e_shnum)
+                       sec_name
+                         = SECTION_NAME (section_headers + psym->st_shndx);
                      else if (psym->st_shndx == SHN_ABS)
                        sec_name = "ABS";
                      else if (psym->st_shndx == SHN_COMMON)
@@ -1268,13 +1302,19 @@ dump_relocations (FILE *file,
                      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
+                     else if ((elf_header.e_machine == EM_X86_64
+                               || elf_header.e_machine == EM_L1OM)
                               && psym->st_shndx == SHN_X86_64_LCOMMON)
                        sec_name = "LARGE_COMMON";
                      else if (elf_header.e_machine == EM_IA_64
                               && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX
                               && psym->st_shndx == SHN_IA_64_ANSI_COMMON)
                        sec_name = "ANSI_COM";
+                     else if (elf_header.e_machine == EM_IA_64
+                              && (elf_header.e_ident[EI_OSABI]
+                                  == ELFOSABI_OPENVMS)
+                              && psym->st_shndx == SHN_IA_64_VMS_SYMVEC)
+                       sec_name = "VMS_SYMVEC";
                      else
                        {
                          sprintf (name_buf, "<section 0x%x>",
@@ -1292,7 +1332,14 @@ dump_relocations (FILE *file,
                print_symbol (22, strtab + psym->st_name);
 
              if (is_rela)
-               printf (" + %lx", (unsigned long) rels[i].r_addend);
+               {
+                 long offset = (long) (bfd_signed_vma) rels[i].r_addend;
+
+                 if (offset < 0)
+                   printf (" - %lx", - offset);
+                 else
+                   printf (" + %lx", offset);
+               }
            }
        }
       else if (is_rela)
@@ -1309,37 +1356,36 @@ dump_relocations (FILE *file,
 
       putchar ('\n');
 
+#ifdef BFD64
       if (! is_32bit_elf && elf_header.e_machine == EM_MIPS)
        {
+         bfd_vma type2 = ELF64_MIPS_R_TYPE2 (info);
+         bfd_vma type3 = ELF64_MIPS_R_TYPE3 (info);
+         const char * rtype2 = elf_mips_reloc_type (type2);
+         const char * rtype3 = elf_mips_reloc_type (type3);
+
          printf ("                    Type2: ");
 
          if (rtype2 == NULL)
-#ifdef _bfd_int64_low
-           printf (_("unrecognized: %-7lx"), _bfd_int64_low (type2));
-#else
-           printf (_("unrecognized: %-7lx"), type2);
-#endif
+           printf (_("unrecognized: %-7lx"),
+                   (unsigned long) type2 & 0xffffffff);
          else
            printf ("%-17.17s", rtype2);
 
          printf ("\n                    Type3: ");
 
          if (rtype3 == NULL)
-#ifdef _bfd_int64_low
-           printf (_("unrecognized: %-7lx"), _bfd_int64_low (type3));
-#else
-           printf (_("unrecognized: %-7lx"), type3);
-#endif
+           printf (_("unrecognized: %-7lx"),
+                   (unsigned long) type3 & 0xffffffff);
          else
            printf ("%-17.17s", rtype3);
 
          putchar ('\n');
        }
+#endif /* BFD64 */
     }
 
   free (rels);
-
-  return 1;
 }
 
 static const char *
@@ -1390,6 +1436,8 @@ get_mips_dynamic_type (unsigned long type)
     case DT_MIPS_COMPACT_SIZE: return "MIPS_COMPACT_SIZE";
     case DT_MIPS_GP_VALUE: return "MIPS_GP_VALUE";
     case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC";
+    case DT_MIPS_PLTGOT: return "MIPS_PLTGOT";
+    case DT_MIPS_RWPLT: return "MIPS_RWPLT";
     default:
       return NULL;
     }
@@ -1469,7 +1517,37 @@ get_ia64_dynamic_type (unsigned long type)
 {
   switch (type)
     {
-    case DT_IA_64_PLT_RESERVE: return "IA_64_PLT_RESERVE";
+    case DT_IA_64_PLT_RESERVE:         return "IA_64_PLT_RESERVE";
+    case DT_IA_64_VMS_SUBTYPE:         return "VMS_SUBTYPE";
+    case DT_IA_64_VMS_IMGIOCNT:        return "VMS_IMGIOCNT";
+    case DT_IA_64_VMS_LNKFLAGS:        return "VMS_LNKFLAGS";
+    case DT_IA_64_VMS_VIR_MEM_BLK_SIZ: return "VMS_VIR_MEM_BLK_SIZ";
+    case DT_IA_64_VMS_IDENT:           return "VMS_IDENT";
+    case DT_IA_64_VMS_NEEDED_IDENT:    return "VMS_NEEDED_IDENT";
+    case DT_IA_64_VMS_IMG_RELA_CNT:    return "VMS_IMG_RELA_CNT";
+    case DT_IA_64_VMS_SEG_RELA_CNT:    return "VMS_SEG_RELA_CNT";
+    case DT_IA_64_VMS_FIXUP_RELA_CNT:  return "VMS_FIXUP_RELA_CNT";
+    case DT_IA_64_VMS_FIXUP_NEEDED:    return "VMS_FIXUP_NEEDED";
+    case DT_IA_64_VMS_SYMVEC_CNT:      return "VMS_SYMVEC_CNT";
+    case DT_IA_64_VMS_XLATED:          return "VMS_XLATED";
+    case DT_IA_64_VMS_STACKSIZE:       return "VMS_STACKSIZE";
+    case DT_IA_64_VMS_UNWINDSZ:        return "VMS_UNWINDSZ";
+    case DT_IA_64_VMS_UNWIND_CODSEG:   return "VMS_UNWIND_CODSEG";
+    case DT_IA_64_VMS_UNWIND_INFOSEG:  return "VMS_UNWIND_INFOSEG";
+    case DT_IA_64_VMS_LINKTIME:        return "VMS_LINKTIME";
+    case DT_IA_64_VMS_SEG_NO:          return "VMS_SEG_NO";
+    case DT_IA_64_VMS_SYMVEC_OFFSET:   return "VMS_SYMVEC_OFFSET";
+    case DT_IA_64_VMS_SYMVEC_SEG:      return "VMS_SYMVEC_SEG";
+    case DT_IA_64_VMS_UNWIND_OFFSET:   return "VMS_UNWIND_OFFSET";
+    case DT_IA_64_VMS_UNWIND_SEG:      return "VMS_UNWIND_SEG";
+    case DT_IA_64_VMS_STRTAB_OFFSET:   return "VMS_STRTAB_OFFSET";
+    case DT_IA_64_VMS_SYSVER_OFFSET:   return "VMS_SYSVER_OFFSET";
+    case DT_IA_64_VMS_IMG_RELA_OFF:    return "VMS_IMG_RELA_OFF";
+    case DT_IA_64_VMS_SEG_RELA_OFF:    return "VMS_SEG_RELA_OFF";
+    case DT_IA_64_VMS_FIXUP_RELA_OFF:  return "VMS_FIXUP_RELA_OFF";
+    case DT_IA_64_VMS_PLTGOT_OFFSET:   return "VMS_PLTGOT_OFFSET";
+    case DT_IA_64_VMS_PLTGOT_SEG:      return "VMS_PLTGOT_SEG";
+    case DT_IA_64_VMS_FPMODE:          return "VMS_FPMODE";
     default:
       return NULL;
     }
@@ -1588,7 +1666,7 @@ get_dynamic_type (unsigned long type)
     default:
       if ((type >= DT_LOPROC) && (type <= DT_HIPROC))
        {
-         const char *result;
+         const char * result;
 
          switch (elf_header.e_machine)
            {
@@ -1628,13 +1706,16 @@ get_dynamic_type (unsigned long type)
               || (elf_header.e_machine == EM_PARISC
                   && (type >= OLD_DT_LOOS) && (type <= OLD_DT_HIOS)))
        {
-         const char *result;
+         const char * result;
 
          switch (elf_header.e_machine)
            {
            case EM_PARISC:
              result = get_parisc_dynamic_type (type);
              break;
+           case EM_IA_64:
+             result = get_ia64_dynamic_type (type);
+             break;
            default:
              result = NULL;
              break;
@@ -1767,6 +1848,7 @@ get_machine_name (unsigned e_machine)
     case EM_HUANY:             return "Harvard Universitys's machine-independent object format";
     case EM_PRISM:             return "Vitesse Prism";
     case EM_X86_64:            return "Advanced Micro Devices X86-64";
+    case EM_L1OM:              return "Intel L1OM";
     case EM_S390_OLD:
     case EM_S390:              return "IBM S/390";
     case EM_SCORE:             return "SUNPLUS S+Core";
@@ -1780,6 +1862,8 @@ get_machine_name (unsigned e_machine)
     case EM_IQ2000:            return "Vitesse IQ2000";
     case EM_XTENSA_OLD:
     case EM_XTENSA:            return "Tensilica Xtensa Processor";
+    case EM_LATTICEMICO32:     return "Lattice Mico32";
+    case EM_M32C_OLD:
     case EM_M32C:              return "Renesas M32c";
     case EM_MT:                 return "Morpho Techologies MT processor";
     case EM_BLACKFIN:          return "Analog Devices Blackfin";
@@ -1787,6 +1871,10 @@ get_machine_name (unsigned e_machine)
     case EM_ALTERA_NIOS2:      return "Altera Nios II";
     case EM_XC16X:             return "Infineon Technologies xc16x";
     case EM_CYGNUS_MEP:         return "Toshiba MeP Media Engine";
+    case EM_CR16:
+    case EM_CR16_OLD:          return "National Semiconductor's CR16";
+    case EM_MICROBLAZE:                return "Xilinx MicroBlaze";
+    case EM_MICROBLAZE_OLD:    return "Xilinx MicroBlaze";
     default:
       snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
       return buff;
@@ -2045,9 +2133,9 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            strcat (buf, ", fido_a");
          else
            {
-             char const *isa = _("unknown");
-             char const *mac = _("unknown mac");
-             char const *additional = NULL;
+             char const * isa = _("unknown");
+             char const * mac = _("unknown mac");
+             char const * additional = NULL;
 
              switch (e_flags & EF_M68K_CF_ISA_MASK)
                {
@@ -2166,6 +2254,10 @@ 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 E_MIPS_MACH_OCTEON: strcat (buf, ", octeon"); break;
+           case E_MIPS_MACH_XLR:  strcat (buf, ", xlr"); 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
@@ -2354,7 +2446,7 @@ get_osabi_name (unsigned int osabi)
     case ELFOSABI_OPENBSD:     return "UNIX - OpenBSD";
     case ELFOSABI_OPENVMS:     return "VMS - OpenVMS";
     case ELFOSABI_NSK:         return "HP - Non-Stop Kernel";
-    case ELFOSABI_AROS:                return "Amiga Research OS";
+    case ELFOSABI_AROS:                return "AROS";
     case ELFOSABI_STANDALONE:  return _("Standalone App");
     case ELFOSABI_ARM:         return "ARM";
     default:
@@ -2468,7 +2560,7 @@ get_segment_type (unsigned long p_type)
     default:
       if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
        {
-         const char *result;
+         const char * result;
 
          switch (elf_header.e_machine)
            {
@@ -2497,7 +2589,7 @@ get_segment_type (unsigned long p_type)
        }
       else if ((p_type >= PT_LOOS) && (p_type <= PT_HIOS))
        {
-         const char *result;
+         const char * result;
 
          switch (elf_header.e_machine)
            {
@@ -2601,9 +2693,16 @@ get_ia64_section_type_name (unsigned int sh_type)
 
   switch (sh_type)
     {
-    case SHT_IA_64_EXT:                  return "IA_64_EXT";
-    case SHT_IA_64_UNWIND:       return "IA_64_UNWIND";
-    case SHT_IA_64_PRIORITY_INIT: return "IA_64_PRIORITY_INIT";
+    case SHT_IA_64_EXT:                       return "IA_64_EXT";
+    case SHT_IA_64_UNWIND:            return "IA_64_UNWIND";
+    case SHT_IA_64_PRIORITY_INIT:      return "IA_64_PRIORITY_INIT";
+    case SHT_IA_64_VMS_TRACE:          return "VMS_TRACE";
+    case SHT_IA_64_VMS_TIE_SIGNATURES: return "VMS_TIE_SIGNATURES";
+    case SHT_IA_64_VMS_DEBUG:          return "VMS_DEBUG";
+    case SHT_IA_64_VMS_DEBUG_STR:      return "VMS_DEBUG_STR";
+    case SHT_IA_64_VMS_LINKAGES:       return "VMS_LINKAGES";
+    case SHT_IA_64_VMS_SYMBOL_VECTOR:  return "VMS_SYMBOL_VECTOR";
+    case SHT_IA_64_VMS_FIXUP:          return "VMS_FIXUP";
     default:
       break;
     }
@@ -2627,12 +2726,11 @@ get_arm_section_type_name (unsigned int sh_type)
 {
   switch (sh_type)
     {
-    case SHT_ARM_EXIDX:
-      return "ARM_EXIDX";
-    case SHT_ARM_PREEMPTMAP:
-      return "ARM_PREEMPTMAP";
-    case SHT_ARM_ATTRIBUTES:
-      return "ARM_ATTRIBUTES";
+    case SHT_ARM_EXIDX:           return "ARM_EXIDX";
+    case SHT_ARM_PREEMPTMAP:      return "ARM_PREEMPTMAP";
+    case SHT_ARM_ATTRIBUTES:      return "ARM_ATTRIBUTES";
+    case SHT_ARM_DEBUGOVERLAY:    return "ARM_DEBUGOVERLAY";
+    case SHT_ARM_OVERLAYSECTION:  return "ARM_OVERLAYSECTION";
     default:
       break;
     }
@@ -2676,7 +2774,7 @@ get_section_type_name (unsigned int sh_type)
     default:
       if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC))
        {
-         const char *result;
+         const char * result;
 
          switch (elf_header.e_machine)
            {
@@ -2691,6 +2789,7 @@ get_section_type_name (unsigned int sh_type)
              result = get_ia64_section_type_name (sh_type);
              break;
            case EM_X86_64:
+           case EM_L1OM:
              result = get_x86_64_section_type_name (sh_type);
              break;
            case EM_ARM:
@@ -2707,7 +2806,24 @@ get_section_type_name (unsigned int sh_type)
          sprintf (buff, "LOPROC+%x", sh_type - SHT_LOPROC);
        }
       else if ((sh_type >= SHT_LOOS) && (sh_type <= SHT_HIOS))
-       sprintf (buff, "LOOS+%x", sh_type - SHT_LOOS);
+       {
+         const char * result;
+
+         switch (elf_header.e_machine)
+           {
+           case EM_IA_64:
+             result = get_ia64_section_type_name (sh_type);
+             break;
+           default:
+             result = NULL;
+             break;
+           }
+
+         if (result != NULL)
+           return result;
+
+         sprintf (buff, "LOOS+%x", sh_type - SHT_LOOS);
+       }
       else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER))
        sprintf (buff, "LOUSER+%x", sh_type - SHT_LOUSER);
       else
@@ -2740,12 +2856,15 @@ static struct option options[] =
   {"arch-specific",    no_argument, 0, 'A'},
   {"version-info",     no_argument, 0, 'V'},
   {"use-dynamic",      no_argument, 0, 'D'},
-  {"hex-dump",        required_argument, 0, 'x'},
-  {"debug-dump",       optional_argument, 0, OPTION_DEBUG_DUMP},
   {"unwind",          no_argument, 0, 'u'},
+  {"archive-index",    no_argument, 0, 'c'},
+  {"hex-dump",        required_argument, 0, 'x'},
+  {"relocated-dump",   required_argument, 0, 'R'},
+  {"string-dump",      required_argument, 0, 'p'},
 #ifdef SUPPORT_DISASSEMBLY
   {"instruction-dump", required_argument, 0, 'i'},
 #endif
+  {"debug-dump",       optional_argument, 0, OPTION_DEBUG_DUMP},
 
   {"version",         no_argument, 0, 'v'},
   {"wide",            no_argument, 0, 'W'},
@@ -2754,7 +2873,7 @@ static struct option options[] =
 };
 
 static void
-usage (FILE *stream)
+usage (FILE * stream)
 {
   fprintf (stream, _("Usage: readelf <option(s)> elf-file(s)\n"));
   fprintf (stream, _(" Display information about the contents of ELF format files\n"));
@@ -2776,15 +2895,21 @@ usage (FILE *stream)
   -d --dynamic           Display the dynamic section (if present)\n\
   -V --version-info      Display the version sections (if present)\n\
   -A --arch-specific     Display architecture specific information (if any).\n\
+  -c --archive-index     Display the symbol/file index in an archive\n\
   -D --use-dynamic       Use the dynamic section info when displaying symbols\n\
-  -x --hex-dump=<number> Dump the contents of section <number>\n\
-  -w[liaprmfFsoR] or\n\
-  --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\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\
+  -R --relocated-dump=<number|name>\n\
+                         Dump the contents of section <number|name> as relocated bytes\n\
+  -w[lLiaprmfFsoR] or\n\
+  --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\
                          Display the contents of DWARF2 debug sections\n"));
 #ifdef SUPPORT_DISASSEMBLY
   fprintf (stream, _("\
-  -i --instruction-dump=<number>\n\
-                         Disassemble the contents of section <number>\n"));
+  -i --instruction-dump=<number|name>\n\
+                         Disassemble the contents of section <number|name>\n"));
 #endif
   fprintf (stream, _("\
   -I --histogram         Display histogram of bucket list lengths\n\
@@ -2792,7 +2917,7 @@ usage (FILE *stream)
   @<file>                Read options from <file>\n\
   -H --help              Display this information\n\
   -v --version           Display the version number of readelf\n"));
-  
+
   if (REPORT_BUGS_TO[0] && stream == stdout)
     fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO);
 
@@ -2805,20 +2930,20 @@ usage (FILE *stream)
    the first time.  */
 
 static void
-request_dump (unsigned int section, int type)
+request_dump_bynumber (unsigned int section, dump_type type)
 {
   if (section >= num_dump_sects)
     {
-      char *new_dump_sects;
+      dump_type * new_dump_sects;
 
-      new_dump_sects = calloc (section + 1, 1);
+      new_dump_sects = calloc (section + 1, sizeof (* dump_sects));
 
       if (new_dump_sects == NULL)
        error (_("Out of memory allocating dump request table.\n"));
       else
        {
          /* Copy current flag settings.  */
-         memcpy (new_dump_sects, dump_sects, num_dump_sects);
+         memcpy (new_dump_sects, dump_sects, num_dump_sects * sizeof (* dump_sects));
 
          free (dump_sects);
 
@@ -2836,9 +2961,9 @@ request_dump (unsigned int section, int type)
 /* Request a dump by section name.  */
 
 static void
-request_dump_byname (const char *section, int type)
+request_dump_byname (const char * section, dump_type type)
 {
-  struct dump_list_entry *new_request;
+  struct dump_list_entry * new_request;
 
   new_request = malloc (sizeof (struct dump_list_entry));
   if (!new_request)
@@ -2854,8 +2979,24 @@ request_dump_byname (const char *section, int type)
   dump_sects_byname = new_request;
 }
 
+static inline void
+request_dump (dump_type type)
+{
+  int section;
+  char * cp;
+
+  do_dump++;
+  section = strtoul (optarg, & cp, 0);
+
+  if (! *cp && section >= 0)
+    request_dump_bynumber (section, type);
+  else
+    request_dump_byname (optarg, type);
+}
+
+
 static void
-parse_args (int argc, char **argv)
+parse_args (int argc, char ** argv)
 {
   int c;
 
@@ -2863,11 +3004,8 @@ parse_args (int argc, char **argv)
     usage (stderr);
 
   while ((c = getopt_long
-         (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF)
+         (argc, argv, "ADHINR:SVWacdeghi:lnp:rstuvw::x:", options, NULL)) != EOF)
     {
-      char *cp;
-      int section;
-
       switch (c)
        {
        case 0:
@@ -2937,80 +3075,29 @@ 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);
-         else
-           request_dump_byname (optarg, HEX_DUMP);
+         request_dump (HEX_DUMP);
+         break;
+       case 'p':
+         request_dump (STRING_DUMP);
+         break;
+       case 'R':
+         request_dump (RELOC_DUMP);
          break;
        case 'w':
          do_dump++;
          if (optarg == 0)
-           do_debugging = 1;
+           {
+             do_debugging = 1;
+             dwarf_select_sections_all ();
+           }
          else
            {
-             unsigned int index = 0;
-
              do_debugging = 0;
-
-             while (optarg[index])
-               switch (optarg[index++])
-                 {
-                 case 'i':
-                 case 'I':
-                   do_debug_info = 1;
-                   break;
-
-                 case 'a':
-                 case 'A':
-                   do_debug_abbrevs = 1;
-                   break;
-
-                 case 'l':
-                 case 'L':
-                   do_debug_lines = 1;
-                   break;
-
-                 case 'p':
-                 case 'P':
-                   do_debug_pubnames = 1;
-                   break;
-
-                 case 'r':
-                   do_debug_aranges = 1;
-                   break;
-
-                 case 'R':
-                   do_debug_ranges = 1;
-                   break;
-
-                 case 'F':
-                   do_debug_frames_interp = 1;
-                 case 'f':
-                   do_debug_frames = 1;
-                   break;
-
-                 case 'm':
-                 case 'M':
-                   do_debug_macinfo = 1;
-                   break;
-
-                 case 's':
-                 case 'S':
-                   do_debug_str = 1;
-                   break;
-
-                 case 'o':
-                 case 'O':
-                   do_debug_loc = 1;
-                   break;
-
-                 default:
-                   warn (_("Unrecognized debug option '%s'\n"), optarg);
-                   break;
-                 }
+             dwarf_select_sections_by_letters (optarg);
            }
          break;
        case OPTION_DEBUG_DUMP:
@@ -3019,84 +3106,14 @@ parse_args (int argc, char **argv)
            do_debugging = 1;
          else
            {
-             typedef struct
-             {
-               const char * option;
-               int *        variable;
-             }
-             debug_dump_long_opts;
-
-             debug_dump_long_opts opts_table [] =
-               {
-                 /* Please keep this table alpha- sorted.  */
-                 { "Ranges", & do_debug_ranges },
-                 { "abbrev", & do_debug_abbrevs },
-                 { "aranges", & do_debug_aranges },
-                 { "frames", & do_debug_frames },
-                 { "frames-interp", & do_debug_frames_interp },
-                 { "info", & do_debug_info },
-                 { "line", & do_debug_lines },
-                 { "loc",  & do_debug_loc },
-                 { "macro", & do_debug_macinfo },
-                 { "pubnames", & do_debug_pubnames },
-                 /* This entry is for compatability
-                    with earlier versions of readelf.  */
-                 { "ranges", & do_debug_aranges },
-                 { "str", & do_debug_str },
-                 { NULL, NULL }
-               };
-
-             const char *p;
-
              do_debugging = 0;
-
-             p = optarg;
-             while (*p)
-               {
-                 debug_dump_long_opts * entry;
-
-                 for (entry = opts_table; entry->option; entry++)
-                   {
-                     size_t len = strlen (entry->option);
-
-                     if (strneq (p, entry->option, len)
-                         && (p[len] == ',' || p[len] == '\0'))
-                       {
-                         * entry->variable = 1;
-
-                         /* The --debug-dump=frames-interp option also
-                            enables the --debug-dump=frames option.  */
-                         if (do_debug_frames_interp)
-                           do_debug_frames = 1;
-
-                         p += len;
-                         break;
-                       }
-                   }
-
-                 if (entry->option == NULL)
-                   {
-                     warn (_("Unrecognized debug option '%s'\n"), p);
-                     p = strchr (p, ',');
-                     if (p == NULL)
-                       break;
-                   }
-
-                 if (*p == ',')
-                   p++;
-               }
+             dwarf_select_sections_by_names (optarg);
            }
          break;
 #ifdef SUPPORT_DISASSEMBLY
        case 'i':
-         do_dump++;
-         section = strtoul (optarg, & cp, 0);
-         if (! *cp && section >= 0)
-           {
-             request_dump (section, DISASS_DUMP);
-             break;
-           }
-         goto oops;
+         request_dump (DISASS_DUMP);
+         break;
 #endif
        case 'v':
          print_version (program_name);
@@ -3108,9 +3125,6 @@ parse_args (int argc, char **argv)
          do_wide++;
          break;
        default:
-#ifdef SUPPORT_DISASSEMBLY
-       oops:
-#endif
          /* xgettext:c-format */
          error (_("Invalid option '-%c'\n"), c);
          /* Drop through.  */
@@ -3122,7 +3136,7 @@ parse_args (int argc, char **argv)
   if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections
       && !do_segments && !do_header && !do_dump && !do_version
       && !do_histogram && !do_debugging && !do_arch && !do_notes
-      && !do_section_groups)
+      && !do_section_groups && !do_archive_index)
     usage (stderr);
   else if (argc < 3)
     {
@@ -3178,6 +3192,8 @@ process_file_header (void)
       return 0;
     }
 
+  init_dwarf_regnames (elf_header.e_machine);
+
   if (do_header)
     {
       int i;
@@ -3230,31 +3246,27 @@ process_file_header (void)
              (long) elf_header.e_shentsize);
       printf (_("  Number of section headers:         %ld"),
              (long) elf_header.e_shnum);
-      if (section_headers != NULL && elf_header.e_shnum == 0)
+      if (section_headers != NULL && elf_header.e_shnum == SHN_UNDEF)
        printf (" (%ld)", (long) section_headers[0].sh_size);
       putc ('\n', stdout);
       printf (_("  Section header string table index: %ld"),
              (long) elf_header.e_shstrndx);
-      if (section_headers != NULL && elf_header.e_shstrndx == SHN_XINDEX)
-       printf (" (%ld)", (long) section_headers[0].sh_link);
+      if (section_headers != NULL
+         && elf_header.e_shstrndx == (SHN_XINDEX & 0xffff))
+       printf (" (%u)", 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 >= elf_header.e_shnum)
        printf (" <corrupt: out of range>");
       putc ('\n', stdout);
     }
 
   if (section_headers != NULL)
     {
-      if (elf_header.e_shnum == 0)
+      if (elf_header.e_shnum == SHN_UNDEF)
        elf_header.e_shnum = section_headers[0].sh_size;
-      if (elf_header.e_shstrndx == SHN_XINDEX)
+      if (elf_header.e_shstrndx == (SHN_XINDEX & 0xffff))
        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)))
+      else if (elf_header.e_shstrndx >= elf_header.e_shnum)
        elf_header.e_shstrndx = SHN_UNDEF;
       free (section_headers);
       section_headers = NULL;
@@ -3265,11 +3277,11 @@ process_file_header (void)
 
 
 static int
-get_32bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers)
+get_32bit_program_headers (FILE * file, Elf_Internal_Phdr * program_headers)
 {
-  Elf32_External_Phdr *phdrs;
-  Elf32_External_Phdr *external;
-  Elf_Internal_Phdr *internal;
+  Elf32_External_Phdr * phdrs;
+  Elf32_External_Phdr * external;
+  Elf_Internal_Phdr *   internal;
   unsigned int i;
 
   phdrs = get_data (NULL, file, elf_header.e_phoff,
@@ -3298,11 +3310,11 @@ get_32bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers)
 }
 
 static int
-get_64bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers)
+get_64bit_program_headers (FILE * file, Elf_Internal_Phdr * program_headers)
 {
-  Elf64_External_Phdr *phdrs;
-  Elf64_External_Phdr *external;
-  Elf_Internal_Phdr *internal;
+  Elf64_External_Phdr * phdrs;
+  Elf64_External_Phdr * external;
+  Elf_Internal_Phdr *   internal;
   unsigned int i;
 
   phdrs = get_data (NULL, file, elf_header.e_phoff,
@@ -3333,9 +3345,9 @@ get_64bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers)
 /* Returns 1 if the program headers were read into `program_headers'.  */
 
 static int
-get_program_headers (FILE *file)
+get_program_headers (FILE * file)
 {
-  Elf_Internal_Phdr *phdrs;
+  Elf_Internal_Phdr * phdrs;
 
   /* Check cache of prior read.  */
   if (program_headers != NULL)
@@ -3364,9 +3376,9 @@ get_program_headers (FILE *file)
 /* Returns 1 if the program headers were loaded.  */
 
 static int
-process_program_headers (FILE *file)
+process_program_headers (FILE * file)
 {
-  Elf_Internal_Phdr *segment;
+  Elf_Internal_Phdr * segment;
   unsigned int i;
 
   if (elf_header.e_phnum == 0)
@@ -3503,11 +3515,16 @@ 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)
            {
-             Elf_Internal_Shdr *sec;
+             Elf_Internal_Shdr * sec;
 
              sec = find_section (".dynamic");
              if (sec == NULL || sec->sh_size == 0)
@@ -3517,23 +3534,21 @@ process_program_headers (FILE *file)
                }
 
              if (sec->sh_type == SHT_NOBITS)
-               break;
+               {
+                 dynamic_size = 0;
+                 break;
+               }
 
              dynamic_addr = sec->sh_offset;
              dynamic_size = sec->sh_size;
 
              if (dynamic_addr < segment->p_offset
                  || dynamic_addr > segment->p_offset + segment->p_filesz)
-               warn (_("the .dynamic section is not contained within the dynamic segment\n"));
+               warn (_("the .dynamic section is not contained"
+                       " within the dynamic segment\n"));
              else if (dynamic_addr > segment->p_offset)
-               warn (_("the .dynamic section is not the first section in the dynamic segment.\n"));
-           }
-         else
-           {
-             /* Otherwise, we can only assume that the .dynamic
-                section is the first section in the DYNAMIC segment.  */
-             dynamic_addr = segment->p_offset;
-             dynamic_size = segment->p_filesz;
+               warn (_("the .dynamic section is not the first section"
+                       " in the dynamic segment.\n"));
            }
          break;
 
@@ -3572,16 +3587,16 @@ process_program_headers (FILE *file)
       for (i = 0; i < elf_header.e_phnum; i++)
        {
          unsigned int j;
-         Elf_Internal_Shdr *section;
+         Elf_Internal_Shdr * section;
 
          segment = program_headers + i;
-         section = section_headers;
+         section = section_headers + 1;
 
          printf ("   %2.2d     ", i);
 
          for (j = 1; j < elf_header.e_shnum; j++, section++)
            {
-             if (ELF_IS_SECTION_IN_SEGMENT_MEMORY(section, segment))
+             if (ELF_IS_SECTION_IN_SEGMENT_MEMORY (section, segment))
                printf ("%s ", SECTION_NAME (section));
            }
 
@@ -3596,9 +3611,9 @@ process_program_headers (FILE *file)
 /* Find the file offset corresponding to VMA by using the program headers.  */
 
 static long
-offset_from_vma (FILE *file, bfd_vma vma, bfd_size_type size)
+offset_from_vma (FILE * file, bfd_vma vma, bfd_size_type size)
 {
-  Elf_Internal_Phdr *seg;
+  Elf_Internal_Phdr * seg;
 
   if (! get_program_headers (file))
     {
@@ -3619,16 +3634,16 @@ offset_from_vma (FILE *file, bfd_vma vma, bfd_size_type size)
     }
 
   warn (_("Virtual address 0x%lx not located in any PT_LOAD segment.\n"),
-       (long) vma);
+       (unsigned long) vma);
   return (long) vma;
 }
 
 
 static int
-get_32bit_section_headers (FILE *file, unsigned int num)
+get_32bit_section_headers (FILE * file, unsigned int num)
 {
-  Elf32_External_Shdr *shdrs;
-  Elf_Internal_Shdr *internal;
+  Elf32_External_Shdr * shdrs;
+  Elf_Internal_Shdr *   internal;
   unsigned int i;
 
   shdrs = get_data (NULL, file, elf_header.e_shoff,
@@ -3666,10 +3681,10 @@ get_32bit_section_headers (FILE *file, unsigned int num)
 }
 
 static int
-get_64bit_section_headers (FILE *file, unsigned int num)
+get_64bit_section_headers (FILE * file, unsigned int num)
 {
-  Elf64_External_Shdr *shdrs;
-  Elf_Internal_Shdr *internal;
+  Elf64_External_Shdr * shdrs;
+  Elf_Internal_Shdr *   internal;
   unsigned int i;
 
   shdrs = get_data (NULL, file, elf_header.e_shoff,
@@ -3707,13 +3722,13 @@ get_64bit_section_headers (FILE *file, unsigned int num)
 }
 
 static Elf_Internal_Sym *
-get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
+get_32bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section)
 {
   unsigned long number;
-  Elf32_External_Sym *esyms;
-  Elf_External_Sym_Shndx *shndx;
-  Elf_Internal_Sym *isyms;
-  Elf_Internal_Sym *psym;
+  Elf32_External_Sym * esyms;
+  Elf_External_Sym_Shndx * shndx;
+  Elf_Internal_Sym * isyms;
+  Elf_Internal_Sym * psym;
   unsigned int j;
 
   esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
@@ -3724,7 +3739,7 @@ get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
   shndx = NULL;
   if (symtab_shndx_hdr != NULL
       && (symtab_shndx_hdr->sh_link
-         == (unsigned long) SECTION_HEADER_NUM (section - section_headers)))
+         == (unsigned long) (section - section_headers)))
     {
       shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset,
                        1, symtab_shndx_hdr->sh_size, _("symtab shndx"));
@@ -3755,9 +3770,11 @@ get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
       psym->st_value = BYTE_GET (esyms[j].st_value);
       psym->st_size  = BYTE_GET (esyms[j].st_size);
       psym->st_shndx = BYTE_GET (esyms[j].st_shndx);
-      if (psym->st_shndx == SHN_XINDEX && shndx != NULL)
+      if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
        psym->st_shndx
          = byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j]));
+      else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
+       psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
       psym->st_info  = BYTE_GET (esyms[j].st_info);
       psym->st_other = BYTE_GET (esyms[j].st_other);
     }
@@ -3770,13 +3787,13 @@ get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
 }
 
 static Elf_Internal_Sym *
-get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
+get_64bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section)
 {
   unsigned long number;
-  Elf64_External_Sym *esyms;
-  Elf_External_Sym_Shndx *shndx;
-  Elf_Internal_Sym *isyms;
-  Elf_Internal_Sym *psym;
+  Elf64_External_Sym * esyms;
+  Elf_External_Sym_Shndx * shndx;
+  Elf_Internal_Sym * isyms;
+  Elf_Internal_Sym * psym;
   unsigned int j;
 
   esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
@@ -3787,7 +3804,7 @@ get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
   shndx = NULL;
   if (symtab_shndx_hdr != NULL
       && (symtab_shndx_hdr->sh_link
-         == (unsigned long) SECTION_HEADER_NUM (section - section_headers)))
+         == (unsigned long) (section - section_headers)))
     {
       shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset,
                        1, symtab_shndx_hdr->sh_size, _("symtab shndx"));
@@ -3818,9 +3835,11 @@ get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
       psym->st_info  = BYTE_GET (esyms[j].st_info);
       psym->st_other = BYTE_GET (esyms[j].st_other);
       psym->st_shndx = BYTE_GET (esyms[j].st_shndx);
-      if (psym->st_shndx == SHN_XINDEX && shndx != NULL)
+      if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
        psym->st_shndx
          = byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j]));
+      else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
+       psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
       psym->st_value = BYTE_GET (esyms[j].st_value);
       psym->st_size  = BYTE_GET (esyms[j].st_size);
     }
@@ -3836,15 +3855,15 @@ static const char *
 get_elf_section_flags (bfd_vma sh_flags)
 {
   static char buff[1024];
-  char *p = buff;
+  char * p = buff;
   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
+  static const struct
     {
-      const char *str;
+      const char * str;
       int len;
     }
   flags [] =
@@ -3858,7 +3877,17 @@ get_elf_section_flags (bfd_vma sh_flags)
        { "LINK ORDER", 10 },
        { "OS NONCONF", 10 },
        { "GROUP", 5 },
-       { "TLS", 3 }
+       { "TLS", 3 },
+       /* IA-64 specific.  */
+       { "SHORT", 5 },
+       { "NORECOV", 7 },
+       /* IA-64 OpenVMS specific.  */
+       { "VMS_GLOBAL", 10 },
+       { "VMS_OVERLAID", 12 },
+       { "VMS_SHARED", 10 },
+       { "VMS_VECTOR", 10 },
+       { "VMS_ALLOC_64BIT", 15 },
+       { "VMS_PROTECTED", 13}
     };
 
   if (do_section_details)
@@ -3892,6 +3921,26 @@ get_elf_section_flags (bfd_vma sh_flags)
 
            default:
              index = -1;
+             if (elf_header.e_machine == EM_IA_64)
+               {
+                 if (flag == SHF_IA_64_SHORT)
+                   index = 10;
+                 else if (flag == SHF_IA_64_NORECOV)
+                   index = 11;
+#ifdef BFD64
+                 else if (elf_header.e_ident[EI_OSABI] == ELFOSABI_OPENVMS)
+                   switch (flag)
+                     {
+                     case SHF_IA_64_VMS_GLOBAL:      index = 12; break;
+                     case SHF_IA_64_VMS_OVERLAID:    index = 13; break;
+                     case SHF_IA_64_VMS_SHARED:      index = 14; break;
+                     case SHF_IA_64_VMS_VECTOR:      index = 15; break;
+                     case SHF_IA_64_VMS_ALLOC_64BIT: index = 16; break;
+                     case SHF_IA_64_VMS_PROTECTED:   index = 17; break;
+                     default:                        break;
+                     }
+#endif
+               }
              break;
            }
 
@@ -3932,7 +3981,8 @@ get_elf_section_flags (bfd_vma sh_flags)
            case SHF_TLS:               *p = 'T'; break;
 
            default:
-             if (elf_header.e_machine == EM_X86_64
+             if ((elf_header.e_machine == EM_X86_64
+                  || elf_header.e_machine == EM_L1OM)
                  && flag == SHF_X86_64_LARGE)
                *p = 'l';
              else if (flag & SHF_MASKOS)
@@ -4007,9 +4057,9 @@ get_elf_section_flags (bfd_vma sh_flags)
 }
 
 static int
-process_section_headers (FILE *file)
+process_section_headers (FILE * file)
 {
-  Elf_Internal_Shdr *section;
+  Elf_Internal_Shdr * section;
   unsigned int i;
 
   section_headers = NULL;
@@ -4036,9 +4086,9 @@ process_section_headers (FILE *file)
 
   /* Read in the string table, so that we have names to display.  */
   if (elf_header.e_shstrndx != SHN_UNDEF
-       && SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum)
+       && elf_header.e_shstrndx < elf_header.e_shnum)
     {
-      section = SECTION_HEADER (elf_header.e_shstrndx);
+      section = section_headers + elf_header.e_shstrndx;
 
       if (section->sh_size != 0)
        {
@@ -4091,6 +4141,17 @@ process_section_headers (FILE *file)
          eh_addr_size = 4;
          break;
        }
+      break;
+
+    case EM_M32C_OLD:
+    case EM_M32C:
+      switch (elf_header.e_flags & EF_M32C_CPU_MASK)
+       {
+       case EF_M32C_CPU_M16C:
+         eh_addr_size = 2;
+         break;
+       }
+      break;
     }
 
 #define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \
@@ -4113,7 +4174,7 @@ process_section_headers (FILE *file)
        i < elf_header.e_shnum;
        i++, section++)
     {
-      char *name = SECTION_NAME (section);
+      char * name = SECTION_NAME (section);
 
       if (section->sh_type == SHT_DYNSYM)
        {
@@ -4158,12 +4219,16 @@ process_section_headers (FILE *file)
       else if (section->sh_type == SHT_RELA)
        CHECK_ENTSIZE (section, i, Rela);
       else if ((do_debugging || do_debug_info || do_debug_abbrevs
-               || do_debug_lines || do_debug_pubnames || do_debug_aranges
-               || do_debug_frames || do_debug_macinfo || do_debug_str
-               || do_debug_loc || do_debug_ranges)
-              && const_strneq (name, ".debug_"))
+               || do_debug_lines || do_debug_pubnames
+               || do_debug_aranges || do_debug_frames || do_debug_macinfo
+               || do_debug_str || do_debug_loc || do_debug_ranges)
+              && (const_strneq (name, ".debug_")
+                   || const_strneq (name, ".zdebug_")))
        {
-         name += 7;
+          if (name[1] == 'z')
+            name += sizeof (".zdebug_") - 1;
+          else
+            name += sizeof (".debug_") - 1;
 
          if (do_debugging
              || (do_debug_info     && streq (name, "info"))
@@ -4177,14 +4242,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.  */
+      /* Linkonce section to be combined with .debug_info at link time.  */
       else if ((do_debugging || do_debug_info)
               && const_strneq (name, ".gnu.linkonce.wi."))
-       request_dump (i, DEBUG_DUMP);
+       request_dump_bynumber (i, DEBUG_DUMP);
       else if (do_debug_frames && streq (name, ".eh_frame"))
-       request_dump (i, DEBUG_DUMP);
+       request_dump_bynumber (i, DEBUG_DUMP);
     }
 
   if (! do_sections)
@@ -4242,15 +4307,16 @@ process_section_headers (FILE *file)
       if (do_section_details)
        {
          printf ("  [%2u] %s\n",
-                 SECTION_HEADER_NUM (i),
+                 i,
                  SECTION_NAME (section));
          if (is_32bit_elf || do_wide)
            printf ("       %-15.15s ",
                    get_section_type_name (section->sh_type));
        }
       else
-       printf ("  [%2u] %-17.17s %-15.15s ",
-               SECTION_HEADER_NUM (i),
+       printf ((do_wide ? "  [%2u] %-17s %-15s "
+                        : "  [%2u] %-17.17s %-15.15s "),
+               i,
                SECTION_NAME (section),
                get_section_type_name (section->sh_type));
 
@@ -4268,9 +4334,9 @@ process_section_headers (FILE *file)
          else
            printf (" %3s ", get_elf_section_flags (section->sh_flags));
 
-         printf ("%2ld %3lu %2ld\n",
-                 (unsigned long) section->sh_link,
-                 (unsigned long) section->sh_info,
+         printf ("%2u %3u %2lu\n",
+                 section->sh_link,
+                 section->sh_info,
                  (unsigned long) section->sh_addralign);
        }
       else if (do_wide)
@@ -4306,12 +4372,10 @@ process_section_headers (FILE *file)
          else
            printf (" %3s ", get_elf_section_flags (section->sh_flags));
 
-         printf ("%2ld %3lu ",
-                 (unsigned long) section->sh_link,
-                 (unsigned long) section->sh_info);
+         printf ("%2u %3u ", section->sh_link, section->sh_info);
 
          if ((unsigned long) section->sh_addralign == section->sh_addralign)
-           printf ("%2ld\n", (unsigned long) section->sh_addralign);
+           printf ("%2lu\n", (unsigned long) section->sh_addralign);
          else
            {
              print_vma (section->sh_addralign, DEC);
@@ -4330,13 +4394,13 @@ process_section_headers (FILE *file)
              printf ("  ");
              print_vma (section->sh_offset, LONG_HEX);
            }
-         printf ("  %ld\n       ", (unsigned long) section->sh_link);
+         printf ("  %u\n       ", section->sh_link);
          print_vma (section->sh_size, LONG_HEX);
          putchar (' ');
          print_vma (section->sh_entsize, LONG_HEX);
 
-         printf ("  %-16lu  %ld\n",
-                 (unsigned long) section->sh_info,
+         printf ("  %-16u  %lu\n",
+                 section->sh_info,
                  (unsigned long) section->sh_addralign);
        }
       else
@@ -4357,9 +4421,9 @@ process_section_headers (FILE *file)
 
          printf (" %3s ", get_elf_section_flags (section->sh_flags));
 
-         printf ("     %2ld   %3lu     %ld\n",
-                 (unsigned long) section->sh_link,
-                 (unsigned long) section->sh_info,
+         printf ("     %2u   %3u     %lu\n",
+                 section->sh_link,
+                 section->sh_info,
                  (unsigned long) section->sh_addralign);
        }
 
@@ -4393,14 +4457,15 @@ get_group_flags (unsigned int flags)
 }
 
 static int
-process_section_groups (FILE *file)
+process_section_groups (FILE * file)
 {
-  Elf_Internal_Shdr *section;
+  Elf_Internal_Shdr * section;
   unsigned int i;
-  struct group *group;
-  Elf_Internal_Shdr *symtab_sec, *strtab_sec;
-  Elf_Internal_Sym *symtab;
-  char *strtab;
+  struct group * group;
+  Elf_Internal_Shdr * symtab_sec;
+  Elf_Internal_Shdr * strtab_sec;
+  Elf_Internal_Sym * symtab;
+  char * strtab;
   size_t strtab_size;
 
   /* Don't process section groups unless needed.  */
@@ -4465,16 +4530,17 @@ process_section_groups (FILE *file)
     {
       if (section->sh_type == SHT_GROUP)
        {
-         char *name = SECTION_NAME (section);
-         char *group_name;
-         unsigned char *start, *indices;
+         char * name = SECTION_NAME (section);
+         char * group_name;
+         unsigned char * start;
+         unsigned char * indices;
          unsigned int entry, j, size;
-         Elf_Internal_Shdr *sec;
-         Elf_Internal_Sym *sym;
+         Elf_Internal_Shdr * sec;
+         Elf_Internal_Sym * sym;
 
          /* Get the symbol table.  */
-         if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum
-             || ((sec = SECTION_HEADER (section->sh_link))->sh_type
+         if (section->sh_link >= elf_header.e_shnum
+             || ((sec = section_headers + section->sh_link)->sh_type
                  != SHT_SYMTAB))
            {
              error (_("Bad sh_link in group section `%s'\n"), name);
@@ -4493,14 +4559,14 @@ process_section_groups (FILE *file)
 
          if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
            {
-             bfd_vma sec_index = SECTION_HEADER_INDEX (sym->st_shndx);
-             if (sec_index == 0)
+             if (sym->st_shndx == 0
+                 || sym->st_shndx >= elf_header.e_shnum)
                {
                  error (_("Bad sh_info in group section `%s'\n"), name);
                  continue;
                }
 
-             group_name = SECTION_NAME (section_headers + sec_index);
+             group_name = SECTION_NAME (section_headers + sym->st_shndx);
              strtab_sec = NULL;
              if (strtab)
                free (strtab);
@@ -4510,8 +4576,7 @@ process_section_groups (FILE *file)
          else
            {
              /* Get the string table.  */
-             if (SECTION_HEADER_INDEX (symtab_sec->sh_link)
-                 >= elf_header.e_shnum)
+             if (symtab_sec->sh_link >= elf_header.e_shnum)
                {
                  strtab_sec = NULL;
                  if (strtab)
@@ -4520,7 +4585,7 @@ process_section_groups (FILE *file)
                  strtab_size = 0;
                }
              else if (strtab_sec
-                      != (sec = SECTION_HEADER (symtab_sec->sh_link)))
+                      != (sec = section_headers + symtab_sec->sh_link))
                {
                  strtab_sec = sec;
                  if (strtab)
@@ -4554,32 +4619,25 @@ process_section_groups (FILE *file)
 
          for (j = 0; j < size; j++)
            {
-             struct group_list *g;
+             struct group_list * g;
 
              entry = byte_get (indices, 4);
              indices += 4;
 
-             if (SECTION_HEADER_INDEX (entry) >= elf_header.e_shnum)
+             if (entry >= elf_header.e_shnum)
                {
                  error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"),
                         entry, i, elf_header.e_shnum - 1);
                  continue;
                }
-             else if (entry >= SHN_LORESERVE && entry <= SHN_HIRESERVE)
-               {
-                 error (_("invalid section [%5u] in group section [%5u]\n"),
-                        entry, i);
-                 continue;
-               }
 
-             if (section_headers_groups [SECTION_HEADER_INDEX (entry)]
-                 != NULL)
+             if (section_headers_groups [entry] != NULL)
                {
                  if (entry)
                    {
                      error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"),
                             entry, i,
-                            section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index);
+                            section_headers_groups [entry]->group_index);
                      continue;
                    }
                  else
@@ -4591,18 +4649,17 @@ process_section_groups (FILE *file)
                      if (!warned)
                        {
                          error (_("section 0 in group section [%5u]\n"),
-                                section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index);
+                                section_headers_groups [entry]->group_index);
                          warned++;
                        }
                    }
                }
 
-             section_headers_groups [SECTION_HEADER_INDEX (entry)]
-               = group;
+             section_headers_groups [entry] = group;
 
              if (do_section_groups)
                {
-                 sec = SECTION_HEADER (entry);
+                 sec = section_headers + entry;
                  printf ("   [%5u]   %s\n", entry, SECTION_NAME (sec));
                }
 
@@ -4628,7 +4685,7 @@ process_section_groups (FILE *file)
 
 static struct
 {
-  const char *name;
+  const char * name;
   int reloc;
   int size;
   int rela;
@@ -4642,7 +4699,7 @@ static struct
 /* Process the reloc section.  */
 
 static int
-process_relocs (FILE *file)
+process_relocs (FILE * file)
 {
   unsigned long rel_size;
   unsigned long rel_offset;
@@ -4654,7 +4711,7 @@ process_relocs (FILE *file)
   if (do_using_dynamic)
     {
       int is_rela;
-      const char *name;
+      const char * name;
       int has_dynamic_reloc;
       unsigned int i;
 
@@ -4702,7 +4759,7 @@ process_relocs (FILE *file)
     }
   else
     {
-      Elf_Internal_Shdr *section;
+      Elf_Internal_Shdr * section;
       unsigned long i;
       int found = 0;
 
@@ -4719,7 +4776,7 @@ process_relocs (FILE *file)
 
          if (rel_size)
            {
-             Elf_Internal_Shdr *strsec;
+             Elf_Internal_Shdr * strsec;
              int is_rela;
 
              printf (_("\nRelocation section "));
@@ -4734,17 +4791,16 @@ process_relocs (FILE *file)
 
              is_rela = section->sh_type == SHT_RELA;
 
-             if (section->sh_link
-                 && SECTION_HEADER_INDEX (section->sh_link)
-                    < elf_header.e_shnum)
+             if (section->sh_link != 0
+                 && section->sh_link < elf_header.e_shnum)
                {
-                 Elf_Internal_Shdr *symsec;
-                 Elf_Internal_Sym *symtab;
+                 Elf_Internal_Shdr * symsec;
+                 Elf_Internal_Sym *  symtab;
                  unsigned long nsyms;
                  unsigned long strtablen = 0;
-                 char *strtab = NULL;
+                 char * strtab = NULL;
 
-                 symsec = SECTION_HEADER (section->sh_link);
+                 symsec = section_headers + section->sh_link;
                  if (symsec->sh_type != SHT_SYMTAB
                      && symsec->sh_type != SHT_DYNSYM)
                     continue;
@@ -4755,10 +4811,10 @@ process_relocs (FILE *file)
                  if (symtab == NULL)
                    continue;
 
-                 if (SECTION_HEADER_INDEX (symsec->sh_link)
-                     < elf_header.e_shnum)
+                 if (symsec->sh_link != 0
+                     && symsec->sh_link < elf_header.e_shnum)
                    {
-                     strsec = SECTION_HEADER (symsec->sh_link);
+                     strsec = section_headers + symsec->sh_link;
 
                      strtab = get_data (NULL, file, strsec->sh_offset,
                                         1, strsec->sh_size,
@@ -4816,27 +4872,28 @@ struct ia64_unw_aux_info
       }
     *table;                    /* Unwind table.  */
     unsigned long table_len;   /* Length of unwind table.  */
-    unsigned char *info;       /* Unwind info.  */
+    unsigned char * info;      /* Unwind info.  */
     unsigned long info_size;   /* Size of unwind info.  */
     bfd_vma info_addr;         /* starting address of unwind info.  */
     bfd_vma seg_base;          /* Starting address of segment.  */
-    Elf_Internal_Sym *symtab;  /* The symbol table.  */
+    Elf_Internal_Sym * symtab; /* The symbol table.  */
     unsigned long nsyms;       /* Number of symbols.  */
-    char *strtab;              /* The string table.  */
+    char * strtab;             /* The string table.  */
     unsigned long strtab_size; /* Size of string table.  */
   };
 
 static void
-find_symbol_for_address (Elf_Internal_Sym *symtab,
+find_symbol_for_address (Elf_Internal_Sym * symtab,
                         unsigned long nsyms,
-                        const char *strtab,
+                        const char * strtab,
                         unsigned long strtab_size,
                         struct absaddr addr,
-                        const char **symname,
-                        bfd_vma *offset)
+                        const char ** symname,
+                        bfd_vma * offset)
 {
   bfd_vma dist = 0x100000;
-  Elf_Internal_Sym *sym, *best = NULL;
+  Elf_Internal_Sym * sym;
+  Elf_Internal_Sym * best = NULL;
   unsigned long i;
 
   for (i = 0, sym = symtab; i < nsyms; ++i, ++sym)
@@ -4865,18 +4922,18 @@ find_symbol_for_address (Elf_Internal_Sym *symtab,
 }
 
 static void
-dump_ia64_unwind (struct ia64_unw_aux_info *aux)
+dump_ia64_unwind (struct ia64_unw_aux_info * aux)
 {
-  struct ia64_unw_table_entry *tp;
+  struct ia64_unw_table_entry * tp;
   int in_body;
 
   for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
     {
       bfd_vma stamp;
       bfd_vma offset;
-      const unsigned char *dp;
-      const unsigned char *head;
-      const char *procname;
+      const unsigned char * dp;
+      const unsigned char * head;
+      const char * procname;
 
       find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
                               aux->strtab_size, tp->start, &procname, &offset);
@@ -4921,18 +4978,20 @@ dump_ia64_unwind (struct ia64_unw_aux_info *aux)
 }
 
 static int
-slurp_ia64_unwind_table (FILE *file,
-                        struct ia64_unw_aux_info *aux,
-                        Elf_Internal_Shdr *sec)
+slurp_ia64_unwind_table (FILE * file,
+                        struct ia64_unw_aux_info * aux,
+                        Elf_Internal_Shdr * sec)
 {
   unsigned long size, nrelas, i;
-  Elf_Internal_Phdr *seg;
-  struct ia64_unw_table_entry *tep;
-  Elf_Internal_Shdr *relsec;
-  Elf_Internal_Rela *rela, *rp;
-  unsigned char *table, *tp;
-  Elf_Internal_Sym *sym;
-  const char *relname;
+  Elf_Internal_Phdr * seg;
+  struct ia64_unw_table_entry * tep;
+  Elf_Internal_Shdr * relsec;
+  Elf_Internal_Rela * rela;
+  Elf_Internal_Rela * rp;
+  unsigned char * table;
+  unsigned char * tp;
+  Elf_Internal_Sym * sym;
+  const char * relname;
 
   /* First, find the starting address of the segment that includes
      this section: */
@@ -4966,38 +5025,28 @@ slurp_ia64_unwind_table (FILE *file,
 
   aux->table = xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0]));
   tep = aux->table;
-  for (tp = table; tp < table + size; tp += 3 * eh_addr_size, ++tep)
+  for (tp = table; tp < table + size; ++tep)
     {
       tep->start.section = SHN_UNDEF;
       tep->end.section   = SHN_UNDEF;
       tep->info.section  = SHN_UNDEF;
-      if (is_32bit_elf)
-       {
-         tep->start.offset = byte_get ((unsigned char *) tp + 0, 4);
-         tep->end.offset   = byte_get ((unsigned char *) tp + 4, 4);
-         tep->info.offset  = byte_get ((unsigned char *) tp + 8, 4);
-       }
-      else
-       {
-         tep->start.offset = BYTE_GET ((unsigned char *) tp +  0);
-         tep->end.offset   = BYTE_GET ((unsigned char *) tp +  8);
-         tep->info.offset  = BYTE_GET ((unsigned char *) tp + 16);
-       }
+      tep->start.offset = byte_get (tp, eh_addr_size); tp += eh_addr_size;
+      tep->end.offset   = byte_get (tp, eh_addr_size); tp += eh_addr_size;
+      tep->info.offset  = byte_get (tp, eh_addr_size); tp += eh_addr_size;
       tep->start.offset += aux->seg_base;
       tep->end.offset   += aux->seg_base;
       tep->info.offset  += aux->seg_base;
     }
   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)
     {
       if (relsec->sh_type != SHT_RELA
-         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
-         || SECTION_HEADER (relsec->sh_info) != sec)
+         || relsec->sh_info >= elf_header.e_shnum
+         || section_headers + relsec->sh_info != sec)
        continue;
 
       if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
@@ -5006,16 +5055,8 @@ slurp_ia64_unwind_table (FILE *file,
 
       for (rp = rela; rp < rela + nrelas; ++rp)
        {
-         if (is_32bit_elf)
-           {
-             relname = elf_ia64_reloc_type (ELF32_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF32_R_SYM (rp->r_info);
-           }
-         else
-           {
-             relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF64_R_SYM (rp->r_info);
-           }
+         relname = elf_ia64_reloc_type (get_reloc_type (rp->r_info));
+         sym = aux->symtab + get_reloc_symindex (rp->r_info);
 
          if (! const_strneq (relname, "R_IA64_SEGREL"))
            {
@@ -5052,9 +5093,11 @@ slurp_ia64_unwind_table (FILE *file,
 }
 
 static int
-ia64_process_unwind (FILE *file)
+ia64_process_unwind (FILE * file)
 {
-  Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec;
+  Elf_Internal_Shdr * sec;
+  Elf_Internal_Shdr * unwsec = NULL;
+  Elf_Internal_Shdr * strsec;
   unsigned long i, unwcount = 0, unwstart = 0;
   struct ia64_unw_aux_info aux;
 
@@ -5063,12 +5106,12 @@ ia64_process_unwind (FILE *file)
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
       if (sec->sh_type == SHT_SYMTAB
-         && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum)
+         && sec->sh_link < elf_header.e_shnum)
        {
          aux.nsyms = sec->sh_size / sec->sh_entsize;
          aux.symtab = GET_ELF_SYMBOLS (file, sec);
 
-         strsec = SECTION_HEADER (sec->sh_link);
+         strsec = section_headers + sec->sh_link;
          aux.strtab = get_data (NULL, file, strsec->sh_offset,
                                 1, strsec->sh_size, _("string table"));
          aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
@@ -5082,7 +5125,7 @@ ia64_process_unwind (FILE *file)
 
   while (unwcount-- > 0)
     {
-      char *suffix;
+      char * suffix;
       size_t len, len2;
 
       for (i = unwstart, sec = section_headers + unwstart;
@@ -5099,11 +5142,11 @@ ia64_process_unwind (FILE *file)
       if ((unwsec->sh_flags & SHF_GROUP) != 0)
        {
          /* We need to find which section group it is in.  */
-         struct group_list *g = section_headers_groups [i]->root;
+         struct group_list * g = section_headers_groups [i]->root;
 
          for (; g != NULL; g = g->next)
            {
-             sec = SECTION_HEADER (g->section_index);
+             sec = section_headers + g->section_index;
 
              if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info))
                break;
@@ -5229,21 +5272,21 @@ struct hppa_unw_aux_info
     *table;                    /* Unwind table.  */
     unsigned long table_len;   /* Length of unwind table.  */
     bfd_vma seg_base;          /* Starting address of segment.  */
-    Elf_Internal_Sym *symtab;  /* The symbol table.  */
+    Elf_Internal_Sym * symtab; /* The symbol table.  */
     unsigned long nsyms;       /* Number of symbols.  */
-    char *strtab;              /* The string table.  */
+    char * strtab;             /* The string table.  */
     unsigned long strtab_size; /* Size of string table.  */
   };
 
 static void
-dump_hppa_unwind (struct hppa_unw_aux_info *aux)
+dump_hppa_unwind (struct hppa_unw_aux_info * aux)
 {
-  struct hppa_unw_table_entry *tp;
+  struct hppa_unw_table_entry * tp;
 
   for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
     {
       bfd_vma offset;
-      const char *procname;
+      const char * procname;
 
       find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
                               aux->strtab_size, tp->start, &procname,
@@ -5302,18 +5345,20 @@ dump_hppa_unwind (struct hppa_unw_aux_info *aux)
 }
 
 static int
-slurp_hppa_unwind_table (FILE *file,
-                        struct hppa_unw_aux_info *aux,
-                        Elf_Internal_Shdr *sec)
+slurp_hppa_unwind_table (FILE * file,
+                        struct hppa_unw_aux_info * aux,
+                        Elf_Internal_Shdr * sec)
 {
   unsigned long size, unw_ent_size, nentries, nrelas, i;
-  Elf_Internal_Phdr *seg;
-  struct hppa_unw_table_entry *tep;
-  Elf_Internal_Shdr *relsec;
-  Elf_Internal_Rela *rela, *rp;
-  unsigned char *table, *tp;
-  Elf_Internal_Sym *sym;
-  const char *relname;
+  Elf_Internal_Phdr * seg;
+  struct hppa_unw_table_entry * tep;
+  Elf_Internal_Shdr * relsec;
+  Elf_Internal_Rela * rela;
+  Elf_Internal_Rela * rp;
+  unsigned char * table;
+  unsigned char * tp;
+  Elf_Internal_Sym * sym;
+  const char * relname;
 
   /* First, find the starting address of the segment that includes
      this section.  */
@@ -5402,14 +5447,13 @@ 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)
     {
       if (relsec->sh_type != SHT_RELA
-         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
-         || SECTION_HEADER (relsec->sh_info) != sec)
+         || relsec->sh_info >= elf_header.e_shnum
+         || section_headers + relsec->sh_info != sec)
        continue;
 
       if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
@@ -5418,16 +5462,8 @@ slurp_hppa_unwind_table (FILE *file,
 
       for (rp = rela; rp < rela + nrelas; ++rp)
        {
-         if (is_32bit_elf)
-           {
-             relname = elf_hppa_reloc_type (ELF32_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF32_R_SYM (rp->r_info);
-           }
-         else
-           {
-             relname = elf_hppa_reloc_type (ELF64_R_TYPE (rp->r_info));
-             sym = aux->symtab + ELF64_R_SYM (rp->r_info);
-           }
+         relname = elf_hppa_reloc_type (get_reloc_type (rp->r_info));
+         sym = aux->symtab + get_reloc_symindex (rp->r_info);
 
          /* R_PARISC_SEGREL32 or R_PARISC_SEGREL64.  */
          if (! const_strneq (relname, "R_PARISC_SEGREL"))
@@ -5462,12 +5498,12 @@ slurp_hppa_unwind_table (FILE *file,
 }
 
 static int
-hppa_process_unwind (FILE *file)
+hppa_process_unwind (FILE * file)
 {
   struct hppa_unw_aux_info aux;
-  Elf_Internal_Shdr *unwsec = NULL;
-  Elf_Internal_Shdr *strsec;
-  Elf_Internal_Shdr *sec;
+  Elf_Internal_Shdr * unwsec = NULL;
+  Elf_Internal_Shdr * strsec;
+  Elf_Internal_Shdr * sec;
   unsigned long i;
 
   memset (& aux, 0, sizeof (aux));
@@ -5478,12 +5514,12 @@ hppa_process_unwind (FILE *file)
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
       if (sec->sh_type == SHT_SYMTAB
-         && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum)
+         && sec->sh_link < elf_header.e_shnum)
        {
          aux.nsyms = sec->sh_size / sec->sh_entsize;
          aux.symtab = GET_ELF_SYMBOLS (file, sec);
 
-         strsec = SECTION_HEADER (sec->sh_link);
+         strsec = section_headers + sec->sh_link;
          aux.strtab = get_data (NULL, file, strsec->sh_offset,
                                 1, strsec->sh_size, _("string table"));
          aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
@@ -5525,12 +5561,14 @@ hppa_process_unwind (FILE *file)
 }
 
 static int
-process_unwind (FILE *file)
+process_unwind (FILE * file)
 {
-  struct unwind_handler {
+  struct unwind_handler
+  {
     int machtype;
-    int (*handler)(FILE *file);
-  } handlers[] = {
+    int (* handler)(FILE *);
+  } handlers[] =
+  {
     { EM_IA_64, ia64_process_unwind },
     { EM_PARISC, hppa_process_unwind },
     { 0, 0 }
@@ -5549,7 +5587,7 @@ process_unwind (FILE *file)
 }
 
 static void
-dynamic_section_mips_val (Elf_Internal_Dyn *entry)
+dynamic_section_mips_val (Elf_Internal_Dyn * entry)
 {
   switch (entry->d_tag)
     {
@@ -5568,7 +5606,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]);
@@ -5588,7 +5626,7 @@ dynamic_section_mips_val (Elf_Internal_Dyn *entry)
     case DT_MIPS_TIME_STAMP:
       {
        char timebuf[20];
-       struct tm *tmp;
+       struct tm * tmp;
 
        time_t time = entry->d_un.d_val;
        tmp = gmtime (&time);
@@ -5616,13 +5654,13 @@ dynamic_section_mips_val (Elf_Internal_Dyn *entry)
       break;
 
     default:
-      printf ("%#lx\n", (long) entry->d_un.d_ptr);
+      printf ("%#lx\n", (unsigned long) entry->d_un.d_ptr);
     }
 }
 
 
 static void
-dynamic_section_parisc_val (Elf_Internal_Dyn *entry)
+dynamic_section_parisc_val (Elf_Internal_Dyn * entry)
 {
   switch (entry->d_tag)
     {
@@ -5631,7 +5669,7 @@ dynamic_section_parisc_val (Elf_Internal_Dyn *entry)
        static struct
        {
          long int bit;
-         const char *str;
+         const char * str;
        }
        flags[] =
        {
@@ -5657,7 +5695,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)
@@ -5684,7 +5722,7 @@ dynamic_section_parisc_val (Elf_Internal_Dyn *entry)
 }
 
 static void
-dynamic_section_ia64_val (Elf_Internal_Dyn *entry)
+dynamic_section_ia64_val (Elf_Internal_Dyn * entry)
 {
   switch (entry->d_tag)
     {
@@ -5703,10 +5741,11 @@ dynamic_section_ia64_val (Elf_Internal_Dyn *entry)
 }
 
 static int
-get_32bit_dynamic_section (FILE *file)
+get_32bit_dynamic_section (FILE * file)
 {
-  Elf32_External_Dyn *edyn, *ext;
-  Elf_Internal_Dyn *entry;
+  Elf32_External_Dyn * edyn;
+  Elf32_External_Dyn * ext;
+  Elf_Internal_Dyn * entry;
 
   edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
                   _("dynamic section"));
@@ -5725,7 +5764,7 @@ get_32bit_dynamic_section (FILE *file)
        break;
     }
 
-  dynamic_section = cmalloc (dynamic_nent, sizeof (*entry));
+  dynamic_section = cmalloc (dynamic_nent, sizeof (* entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -5747,10 +5786,11 @@ get_32bit_dynamic_section (FILE *file)
 }
 
 static int
-get_64bit_dynamic_section (FILE *file)
+get_64bit_dynamic_section (FILE * file)
 {
-  Elf64_External_Dyn *edyn, *ext;
-  Elf_Internal_Dyn *entry;
+  Elf64_External_Dyn * edyn;
+  Elf64_External_Dyn * ext;
+  Elf_Internal_Dyn * entry;
 
   edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
                   _("dynamic section"));
@@ -5769,7 +5809,7 @@ get_64bit_dynamic_section (FILE *file)
        break;
     }
 
-  dynamic_section = cmalloc (dynamic_nent, sizeof (*entry));
+  dynamic_section = cmalloc (dynamic_nent, sizeof (* entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -5823,9 +5863,9 @@ print_dynamic_flags (bfd_vma flags)
 /* Parse and display the contents of the dynamic section.  */
 
 static int
-process_dynamic_section (FILE *file)
+process_dynamic_section (FILE * file)
 {
-  Elf_Internal_Dyn *entry;
+  Elf_Internal_Dyn * entry;
 
   if (dynamic_size == 0)
     {
@@ -5958,8 +5998,9 @@ process_dynamic_section (FILE *file)
 
       if (dynamic_syminfo_offset != 0 && syminsz != 0)
        {
-         Elf_External_Syminfo *extsyminfo, *extsym;
-         Elf_Internal_Syminfo *syminfo;
+         Elf_External_Syminfo * extsyminfo;
+         Elf_External_Syminfo * extsym;
+         Elf_Internal_Syminfo * syminfo;
 
          /* There is a syminfo section.  Read the data.  */
          extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, 1,
@@ -5999,7 +6040,7 @@ process_dynamic_section (FILE *file)
     {
       if (do_dynamic)
        {
-         const char *dtype;
+         const char * dtype;
 
          putchar (' ');
          print_vma (entry->d_tag, FULL_HEX);
@@ -6228,7 +6269,7 @@ process_dynamic_section (FILE *file)
 
          if (do_dynamic)
            {
-             char *name;
+             char * name;
 
              if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
                name = GET_DYNAMIC_NAME (entry->d_un.d_val);
@@ -6314,7 +6355,7 @@ process_dynamic_section (FILE *file)
              if (entry->d_tag == DT_USED
                  && VALID_DYNAMIC_NAME (entry->d_un.d_val))
                {
-                 char *name = GET_DYNAMIC_NAME (entry->d_un.d_val);
+                 char * name = GET_DYNAMIC_NAME (entry->d_un.d_val);
 
                  if (*name)
                    {
@@ -6337,7 +6378,7 @@ process_dynamic_section (FILE *file)
        case DT_GNU_PRELINKED:
          if (do_dynamic)
            {
-             struct tm *tmp;
+             struct tm * tmp;
              time_t time = entry->d_un.d_val;
 
              tmp = gmtime (&time);
@@ -6416,10 +6457,11 @@ get_ver_flags (unsigned int flags)
 }
 
 /* Display the contents of the version sections.  */
+
 static int
-process_version_sections (FILE *file)
+process_version_sections (FILE * file)
 {
-  Elf_Internal_Shdr *section;
+  Elf_Internal_Shdr * section;
   unsigned i;
   int found = 0;
 
@@ -6434,42 +6476,45 @@ process_version_sections (FILE *file)
        {
        case SHT_GNU_verdef:
          {
-           Elf_External_Verdef *edefs;
+           Elf_External_Verdef * edefs;
            unsigned int idx;
            unsigned int cnt;
+           char * endbuf;
 
            found = 1;
 
            printf
-             (_("\nVersion definition section '%s' contains %ld entries:\n"),
+             (_("\nVersion definition section '%s' contains %u entries:\n"),
               SECTION_NAME (section), section->sh_info);
 
            printf (_("  Addr: 0x"));
            printf_vma (section->sh_addr);
-           printf (_("  Offset: %#08lx  Link: %lx (%s)\n"),
+           printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   SECTION_HEADER_INDEX (section->sh_link)
-                   < elf_header.e_shnum
-                   ? SECTION_NAME (SECTION_HEADER (section->sh_link))
+                   section->sh_link < elf_header.e_shnum
+                   ? SECTION_NAME (section_headers + section->sh_link)
                    : "<corrupt>");
 
            edefs = get_data (NULL, file, section->sh_offset, 1,
                              section->sh_size,
                              _("version definition section"));
+           endbuf = (char *) edefs + section->sh_size;
            if (!edefs)
              break;
 
            for (idx = cnt = 0; cnt < section->sh_info; ++cnt)
              {
-               char *vstart;
-               Elf_External_Verdef *edef;
+               char * vstart;
+               Elf_External_Verdef * edef;
                Elf_Internal_Verdef ent;
-               Elf_External_Verdaux *eaux;
+               Elf_External_Verdaux * eaux;
                Elf_Internal_Verdaux aux;
                int j;
                int isum;
 
                vstart = ((char *) edefs) + idx;
+               if (vstart + sizeof (*edef) > endbuf)
+                 break;
 
                edef = (Elf_External_Verdef *) vstart;
 
@@ -6507,6 +6552,8 @@ process_version_sections (FILE *file)
                    vstart += aux.vda_next;
 
                    eaux = (Elf_External_Verdaux *) vstart;
+                   if (vstart + sizeof (*eaux) > endbuf)
+                     break;
 
                    aux.vda_name = BYTE_GET (eaux->vda_name);
                    aux.vda_next = BYTE_GET (eaux->vda_next);
@@ -6518,9 +6565,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);
          }
@@ -6528,39 +6579,42 @@ process_version_sections (FILE *file)
 
        case SHT_GNU_verneed:
          {
-           Elf_External_Verneed *eneed;
+           Elf_External_Verneed * eneed;
            unsigned int idx;
            unsigned int cnt;
+           char * endbuf;
 
            found = 1;
 
-           printf (_("\nVersion needs section '%s' contains %ld entries:\n"),
+           printf (_("\nVersion needs section '%s' contains %u entries:\n"),
                    SECTION_NAME (section), section->sh_info);
 
            printf (_(" Addr: 0x"));
            printf_vma (section->sh_addr);
-           printf (_("  Offset: %#08lx  Link to section: %ld (%s)\n"),
+           printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   SECTION_HEADER_INDEX (section->sh_link)
-                   < elf_header.e_shnum
-                   ? SECTION_NAME (SECTION_HEADER (section->sh_link))
+                   section->sh_link < elf_header.e_shnum
+                   ? SECTION_NAME (section_headers + section->sh_link)
                    : "<corrupt>");
 
            eneed = get_data (NULL, file, section->sh_offset, 1,
                              section->sh_size,
                              _("version need section"));
+           endbuf = (char *) eneed + section->sh_size;
            if (!eneed)
              break;
 
            for (idx = cnt = 0; cnt < section->sh_info; ++cnt)
              {
-               Elf_External_Verneed *entry;
+               Elf_External_Verneed * entry;
                Elf_Internal_Verneed ent;
                int j;
                int isum;
-               char *vstart;
+               char * vstart;
 
                vstart = ((char *) eneed) + idx;
+               if (vstart + sizeof (*entry) > endbuf)
+                 break;
 
                entry = (Elf_External_Verneed *) vstart;
 
@@ -6583,9 +6637,11 @@ process_version_sections (FILE *file)
 
                for (j = 0, isum = idx + ent.vn_aux; j < ent.vn_cnt; ++j)
                  {
-                   Elf_External_Vernaux *eaux;
+                   Elf_External_Vernaux * eaux;
                    Elf_Internal_Vernaux aux;
 
+                   if (vstart + sizeof (*eaux) > endbuf)
+                     break;
                    eaux = (Elf_External_Vernaux *) vstart;
 
                    aux.vna_hash  = BYTE_GET (eaux->vna_hash);
@@ -6607,9 +6663,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);
          }
@@ -6617,31 +6677,30 @@ process_version_sections (FILE *file)
 
        case SHT_GNU_versym:
          {
-           Elf_Internal_Shdr *link_section;
+           Elf_Internal_Shdr * link_section;
            int total;
            int cnt;
-           unsigned char *edata;
-           unsigned short *data;
-           char *strtab;
-           Elf_Internal_Sym *symbols;
-           Elf_Internal_Shdr *string_sec;
+           unsigned char * edata;
+           unsigned short * data;
+           char * strtab;
+           Elf_Internal_Sym * symbols;
+           Elf_Internal_Shdr * string_sec;
            long off;
 
-           if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum)
+           if (section->sh_link >= elf_header.e_shnum)
              break;
 
-           link_section = SECTION_HEADER (section->sh_link);
+           link_section = section_headers + section->sh_link;
            total = section->sh_size / sizeof (Elf_External_Versym);
 
-           if (SECTION_HEADER_INDEX (link_section->sh_link)
-               >= elf_header.e_shnum)
+           if (link_section->sh_link >= elf_header.e_shnum)
              break;
 
            found = 1;
 
            symbols = GET_ELF_SYMBOLS (file, link_section);
 
-           string_sec = SECTION_HEADER (link_section->sh_link);
+           string_sec = section_headers + link_section->sh_link;
 
            strtab = get_data (NULL, file, string_sec->sh_offset, 1,
                               string_sec->sh_size, _("version string table"));
@@ -6653,7 +6712,7 @@ process_version_sections (FILE *file)
 
            printf (_(" Addr: "));
            printf_vma (section->sh_addr);
-           printf (_("  Offset: %#08lx  Link: %lx (%s)\n"),
+           printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
                    SECTION_NAME (link_section));
 
@@ -6680,7 +6739,7 @@ process_version_sections (FILE *file)
              {
                int j, nn;
                int check_def, check_need;
-               char *name;
+               char * name;
 
                printf ("  %03x:", cnt);
 
@@ -6701,9 +6760,8 @@ process_version_sections (FILE *file)
 
                      check_def = 1;
                      check_need = 1;
-                     if (SECTION_HEADER_INDEX (symbols[cnt + j].st_shndx)
-                         >= elf_header.e_shnum
-                         || SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type
+                     if (symbols[cnt + j].st_shndx >= elf_header.e_shnum
+                         || section_headers[symbols[cnt + j].st_shndx].sh_type
                             != SHT_NOBITS)
                        {
                          if (symbols[cnt + j].st_shndx == SHN_UNDEF)
@@ -6754,7 +6812,10 @@ process_version_sections (FILE *file)
                                {
                                  ivna.vna_name = BYTE_GET (evna.vna_name);
 
-                                 name = strtab + ivna.vna_name;
+                                 if (ivna.vna_name >= string_sec->sh_size)
+                                   name = _("*invalid*");
+                                 else
+                                   name = strtab + ivna.vna_name;
                                  nn += printf ("(%s%-*s",
                                                name,
                                                12 - (int) strlen (name),
@@ -6806,7 +6867,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),
@@ -6853,7 +6917,14 @@ get_symbol_binding (unsigned int binding)
        snprintf (buff, sizeof (buff), _("<processor specific>: %d"),
                  binding);
       else if (binding >= STB_LOOS && binding <= STB_HIOS)
-       snprintf (buff, sizeof (buff), _("<OS specific>: %d"), binding);
+       {
+         if (binding == STB_GNU_UNIQUE
+             && (elf_header.e_ident[EI_OSABI] == ELFOSABI_LINUX
+                 /* GNU/Linux is still using the default value 0.  */
+                 || elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
+           return "UNIQUE";
+         snprintf (buff, sizeof (buff), _("<OS specific>: %d"), binding);
+       }
       else
        snprintf (buff, sizeof (buff), _("<unknown>: %d"), binding);
       return buff;
@@ -6900,6 +6971,12 @@ get_symbol_type (unsigned int type)
                return "HP_STUB";
            }
 
+         if (type == STT_GNU_IFUNC
+             && (elf_header.e_ident[EI_OSABI] == ELFOSABI_LINUX
+                 /* GNU/Linux is still using the default value 0.  */
+                 || elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
+           return "IFUNC";
+
          snprintf (buff, sizeof (buff), _("<OS specific>: %d"), type);
        }
       else
@@ -6928,6 +7005,8 @@ get_mips_symbol_other (unsigned int other)
     {
     case STO_OPTIONAL:  return "OPTIONAL";
     case STO_MIPS16:    return "MIPS16";
+    case STO_MIPS_PLT: return "MIPS PLT";
+    case STO_MIPS_PIC: return "MIPS PIC";
     default:           return NULL;
     }
 }
@@ -6971,7 +7050,8 @@ get_symbol_index_type (unsigned int type)
          && elf_header.e_machine == EM_IA_64
          && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX)
        return "ANSI_COM";
-      else if (elf_header.e_machine == EM_X86_64
+      else if ((elf_header.e_machine == EM_X86_64
+               || elf_header.e_machine == EM_L1OM)
               && type == SHN_X86_64_LCOMMON)
        return "LARGE_COM";
       else if (type == SHN_MIPS_SCOMMON
@@ -6981,11 +7061,11 @@ get_symbol_index_type (unsigned int type)
               && elf_header.e_machine == EM_MIPS)
        return "SUND";
       else if (type >= SHN_LOPROC && type <= SHN_HIPROC)
-       sprintf (buff, "PRC[0x%04x]", type);
+       sprintf (buff, "PRC[0x%04x]", type & 0xffff);
       else if (type >= SHN_LOOS && type <= SHN_HIOS)
-       sprintf (buff, "OS [0x%04x]", type);
-      else if (type >= SHN_LORESERVE && type <= SHN_HIRESERVE)
-       sprintf (buff, "RSV[0x%04x]", type);
+       sprintf (buff, "OS [0x%04x]", type & 0xffff);
+      else if (type >= SHN_LORESERVE)
+       sprintf (buff, "RSV[0x%04x]", type & 0xffff);
       else
        sprintf (buff, "%3d", type);
       break;
@@ -6995,10 +7075,10 @@ get_symbol_index_type (unsigned int type)
 }
 
 static bfd_vma *
-get_dynamic_data (FILE *file, unsigned int number, unsigned int ent_size)
+get_dynamic_data (FILE * file, unsigned int number, unsigned int ent_size)
 {
-  unsigned char *e_data;
-  bfd_vma *i_data;
+  unsigned char * e_data;
+  bfd_vma * i_data;
 
   e_data = cmalloc (number, ent_size);
 
@@ -7031,24 +7111,59 @@ 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)
+process_symbol_table (FILE * file)
 {
-  Elf_Internal_Shdr *section;
+  Elf_Internal_Shdr * section;
   bfd_vma nbuckets = 0;
   bfd_vma nchains = 0;
-  bfd_vma *buckets = NULL;
-  bfd_vma *chains = NULL;
+  bfd_vma * buckets = NULL;
+  bfd_vma * chains = NULL;
   bfd_vma ngnubuckets = 0;
-  bfd_vma *gnubuckets = NULL;
-  bfd_vma *gnuchains = NULL;
+  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];
@@ -7067,19 +7182,19 @@ process_symbol_table (FILE *file)
                 SEEK_SET))
        {
          error (_("Unable to seek to start of dynamic information\n"));
-         return 0;
+         goto no_hash;
        }
 
       if (fread (nb, hash_ent_size, 1, file) != 1)
        {
          error (_("Failed to read in number of buckets\n"));
-         return 0;
+         goto no_hash;
        }
 
       if (fread (nc, hash_ent_size, 1, file) != 1)
        {
          error (_("Failed to read in number of chains\n"));
-         return 0;
+         goto no_hash;
        }
 
       nbuckets = byte_get (nb, hash_ent_size);
@@ -7088,58 +7203,178 @@ process_symbol_table (FILE *file)
       buckets = get_dynamic_data (file, nbuckets, hash_ent_size);
       chains  = get_dynamic_data (file, nchains, hash_ent_size);
 
+    no_hash:
       if (buckets == NULL || chains == NULL)
-       return 0;
+       {
+         if (do_using_dynamic)
+           return 0;
+         free (buckets);
+         free (chains);
+         buckets = NULL;
+         chains = NULL;
+         nbuckets = 0;
+         nchains = 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;
 
-      printf (_("\nSymbol table for image:\n"));
+      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"));
+         goto no_gnu_hash;
+       }
+
+      if (fread (nb, 16, 1, file) != 1)
+       {
+         error (_("Failed to read in number of buckets\n"));
+         goto no_gnu_hash;
+       }
+
+      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"));
+         goto no_gnu_hash;
+       }
+
+      gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
+
+      if (gnubuckets == NULL)
+       goto no_gnu_hash;
+
+      for (i = 0; i < ngnubuckets; i++)
+       if (gnubuckets[i] != 0)
+         {
+           if (gnubuckets[i] < gnusymidx)
+             return 0;
+
+           if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
+             maxchain = gnubuckets[i];
+         }
+
+      if (maxchain == 0xffffffff)
+       goto no_gnu_hash;
+
+      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"));
+         goto no_gnu_hash;
+       }
 
-         for (si = buckets[hn]; si < nchains && si > 0; si = chains[si])
+      do
+       {
+         if (fread (nb, 4, 1, file) != 1)
            {
-             Elf_Internal_Sym *psym;
-             int n;
+             error (_("Failed to determine last chain length\n"));
+             goto no_gnu_hash;
+           }
 
-             psym = dynamic_symbols + si;
+         if (maxchain + 1 == 0)
+           goto no_gnu_hash;
 
-             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);
+         ++maxchain;
+       }
+      while ((byte_get (nb, 4) & 1) == 0);
 
-             printf ("  %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
-             printf (" %6s",  get_symbol_binding (ELF_ST_BIND (psym->st_info)));
-             printf (" %3s",  get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
-             /* Check to see if any other bits in the st_other field are set.
-                Note - displaying this information disrupts the layout of the
-                table being generated, but for the moment this case is very rare.  */
-             if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
-               printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
-             printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
-             if (VALID_DYNAMIC_NAME (psym->st_name))
-               print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
-             else
-               printf (" <corrupt: %14ld>", psym->st_name);
-             putchar ('\n');
+      if (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"));
+         goto no_gnu_hash;
+       }
+
+      gnuchains = get_dynamic_data (file, maxchain, 4);
+
+    no_gnu_hash:
+      if (gnuchains == NULL)
+       {
+         free (gnubuckets);
+         gnubuckets = NULL;
+         ngnubuckets = 0;
+         if (do_using_dynamic)
+           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)
     {
@@ -7150,11 +7385,10 @@ process_symbol_table (FILE *file)
           i++, section++)
        {
          unsigned int si;
-         char *strtab = NULL;
+         char * strtab = NULL;
          unsigned long int strtab_size = 0;
-         Elf_Internal_Sym *symtab;
-         Elf_Internal_Sym *psym;
-
+         Elf_Internal_Sym * symtab;
+         Elf_Internal_Sym * psym;
 
          if (   section->sh_type != SHT_SYMTAB
              && section->sh_type != SHT_DYNSYM)
@@ -7177,11 +7411,11 @@ process_symbol_table (FILE *file)
              strtab = string_table;
              strtab_size = string_table_length;
            }
-         else if (SECTION_HEADER_INDEX (section->sh_link) < elf_header.e_shnum)
+         else if (section->sh_link < elf_header.e_shnum)
            {
-             Elf_Internal_Shdr *string_sec;
+             Elf_Internal_Shdr * string_sec;
 
-             string_sec = SECTION_HEADER (section->sh_link);
+             string_sec = section_headers + section->sh_link;
 
              strtab = get_data (NULL, file, string_sec->sh_offset,
                                 1, string_sec->sh_size, _("string table"));
@@ -7226,9 +7460,8 @@ process_symbol_table (FILE *file)
 
                  vers_data = byte_get (data, 2);
 
-                 is_nobits = (SECTION_HEADER_INDEX (psym->st_shndx)
-                              < elf_header.e_shnum
-                              && SECTION_HEADER (psym->st_shndx)->sh_type
+                 is_nobits = (psym->st_shndx < elf_header.e_shnum
+                              && section_headers[psym->st_shndx].sh_type
                                  == SHT_NOBITS);
 
                  check_def = (psym->st_shndx != SHN_UNDEF);
@@ -7360,8 +7593,8 @@ process_symbol_table (FILE *file)
 
   if (do_histogram && buckets != NULL)
     {
-      unsigned long *lengths;
-      unsigned long *counts;
+      unsigned long * lengths;
+      unsigned long * counts;
       unsigned long hn;
       bfd_vma si;
       unsigned long maxlength = 0;
@@ -7422,145 +7655,49 @@ process_symbol_table (FILE *file)
       free (chains);
     }
 
-  if (do_histogram && dynamic_info_DT_GNU_HASH)
+  if (do_histogram && gnubuckets != NULL)
     {
-      unsigned char nb[16];
-      bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords;
-      unsigned long *lengths;
-      unsigned long *counts;
+      unsigned long * lengths;
+      unsigned long * counts;
       unsigned long hn;
       unsigned long maxlength = 0;
       unsigned long nzero_counts = 0;
       unsigned long nsyms = 0;
-      bfd_vma buckets_vma;
 
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
-                                    sizeof nb)),
-                SEEK_SET))
+      lengths = calloc (ngnubuckets, sizeof (*lengths));
+      if (lengths == NULL)
        {
-         error (_("Unable to seek to start of dynamic information\n"));
+         error (_("Out of memory\n"));
          return 0;
        }
 
-      if (fread (nb, 16, 1, file) != 1)
-       {
-         error (_("Failed to read in number of buckets\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"));
 
-      ngnubuckets = byte_get (nb, 4);
-      symidx = byte_get (nb + 4, 4);
-      bitmaskwords = byte_get (nb + 8, 4);
-      buckets_vma = dynamic_info_DT_GNU_HASH + 16;
-      if (is_32bit_elf)
-       buckets_vma += bitmaskwords * 4;
-      else
-       buckets_vma += bitmaskwords * 8;
+      for (hn = 0; hn < ngnubuckets; ++hn)
+       if (gnubuckets[hn] != 0)
+         {
+           bfd_vma off, length = 1;
 
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, buckets_vma, 4)),
-                SEEK_SET))
+           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 (_("Unable to seek to start of dynamic information\n"));
+         error (_("Out of memory\n"));
          return 0;
        }
 
-      gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
-
-      if (gnubuckets == NULL)
-       return 0;
-
-      for (i = 0; i < ngnubuckets; i++)
-       if (gnubuckets[i] != 0)
-         {
-           if (gnubuckets[i] < symidx)
-             return 0;
-
-           if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
-             maxchain = gnubuckets[i];
-         }
-
-      if (maxchain == 0xffffffff)
-       return 0;
-
-      maxchain -= symidx;
-
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, buckets_vma
-                                          + 4 * (ngnubuckets + maxchain), 4)),
-                SEEK_SET))
-       {
-         error (_("Unable to seek to start of dynamic information\n"));
-         return 0;
-       }
-
-      do
-       {
-         if (fread (nb, 4, 1, file) != 1)
-           {
-             error (_("Failed to determine last chain length\n"));
-             return 0;
-           }
-
-         if (maxchain + 1 == 0)
-           return 0;
-
-         ++maxchain;
-       }
-      while ((byte_get (nb, 4) & 1) == 0);
-
-      if (fseek (file,
-                (archive_file_offset
-                 + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
-                SEEK_SET))
-       {
-         error (_("Unable to seek to start of dynamic information\n"));
-         return 0;
-       }
-
-      gnuchains = get_dynamic_data (file, maxchain, 4);
-
-      if (gnuchains == NULL)
-       return 0;
-
-      lengths = calloc (ngnubuckets, sizeof (*lengths));
-      if (lengths == NULL)
-       {
-         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] - symidx;
-                (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]];
+      for (hn = 0; hn < ngnubuckets; ++hn)
+       ++counts[lengths[hn]];
 
       if (ngnubuckets > 0)
        {
@@ -7586,7 +7723,7 @@ process_symbol_table (FILE *file)
 }
 
 static int
-process_syminfo (FILE *file ATTRIBUTE_UNUSED)
+process_syminfo (FILE * file ATTRIBUTE_UNUSED)
 {
   unsigned int i;
 
@@ -7651,9 +7788,529 @@ process_syminfo (FILE *file ATTRIBUTE_UNUSED)
   return 1;
 }
 
+/* Check to see if the given reloc needs to be handled in a target specific
+   manner.  If so then process the reloc and return TRUE otherwise return
+   FALSE.  */
+
+static bfd_boolean
+target_specific_reloc_handling (Elf_Internal_Rela * reloc,
+                               unsigned char *     start,
+                               Elf_Internal_Sym *  symtab)
+{
+  unsigned int reloc_type = get_reloc_type (reloc->r_info);
+
+  switch (elf_header.e_machine)
+    {
+    case EM_MN10300:
+    case EM_CYGNUS_MN10300:
+      {
+       static Elf_Internal_Sym * saved_sym = NULL;
+
+       switch (reloc_type)
+         {
+         case 34: /* R_MN10300_ALIGN */
+           return TRUE;
+         case 33: /* R_MN10300_SYM_DIFF */
+           saved_sym = symtab + get_reloc_symindex (reloc->r_info);
+           return TRUE;
+         case 1: /* R_MN10300_32 */
+         case 2: /* R_MN10300_16 */
+           if (saved_sym != NULL)
+             {
+               bfd_vma value;
+
+               value = reloc->r_addend
+                 + (symtab[get_reloc_symindex (reloc->r_info)].st_value
+                    - saved_sym->st_value);
+
+               byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+
+               saved_sym = NULL;
+               return TRUE;
+             }
+           break;
+         default:
+           if (saved_sym != NULL)
+             error (_("Unhandled MN10300 reloc type found after SYM_DIFF reloc"));
+           break;
+         }
+       break;
+      }
+    }
+
+  return FALSE;
+}
+
+/* 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 bfd_boolean
+is_32bit_abs_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_386:
+    case EM_486:
+      return reloc_type == 1; /* R_386_32.  */
+    case EM_68K:
+      return reloc_type == 1; /* R_68K_32.  */
+    case EM_860:
+      return reloc_type == 1; /* R_860_32.  */
+    case EM_ALPHA:
+      return reloc_type == 1; /* XXX Is this right ?  */
+    case EM_ARC:
+      return reloc_type == 1; /* R_ARC_32.  */
+    case EM_ARM:
+      return reloc_type == 2; /* R_ARM_ABS32 */
+    case EM_AVR_OLD:
+    case EM_AVR:
+      return reloc_type == 1;
+    case EM_BLACKFIN:
+      return reloc_type == 0x12; /* R_byte4_data.  */
+    case EM_CRIS:
+      return reloc_type == 3; /* R_CRIS_32.  */
+    case EM_CR16:
+    case EM_CR16_OLD:
+      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_LATTICEMICO32:
+      return reloc_type == 3; /* R_LM32_32.  */
+    case EM_M32C_OLD:
+    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.  */
+             || reloc_type == 41); /* R_PARISC_SECREL32.  */
+    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:
+    case EM_L1OM:
+      return reloc_type == 10; /* R_X86_64_32.  */
+    case EM_XSTORMY16:
+      return reloc_type == 1; /* R_XSTROMY16_32.  */
+    case EM_XTENSA_OLD:
+    case EM_XTENSA:
+      return reloc_type == 1; /* R_XTENSA_32.  */
+
+    default:
+      error (_("Missing knowledge of 32-bit reloc types used in DWARF sections of machine number %d\n"),
+            elf_header.e_machine);
+      abort ();
+    }
+}
+
+/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
+   a 32-bit pc-relative RELA relocation used in DWARF debug sections.  */
+
+static bfd_boolean
+is_32bit_pcrel_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_386:
+    case EM_486:
+      return reloc_type == 2;  /* R_386_PC32.  */
+    case EM_68K:
+      return reloc_type == 4;  /* R_68K_PC32.  */
+    case EM_ALPHA:
+      return reloc_type == 10; /* R_ALPHA_SREL32.  */
+    case EM_ARM:
+      return reloc_type == 3;  /* R_ARM_REL32 */
+    case EM_PARISC:
+      return reloc_type == 9;  /* R_PARISC_PCREL32.  */
+    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:
+    case EM_L1OM:
+      return reloc_type == 2;  /* R_X86_64_PC32.  */
+    case EM_XTENSA_OLD:
+    case EM_XTENSA:
+      return reloc_type == 14; /* R_XTENSA_32_PCREL.  */
+    default:
+      /* 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 apply_relocations
+        anyway, so just return.  */
+      return FALSE;
+    }
+}
+
+/* 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 bfd_boolean
+is_64bit_abs_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_ALPHA:
+      return reloc_type == 2; /* R_ALPHA_REFQUAD.  */
+    case EM_IA_64:
+      return reloc_type == 0x27; /* R_IA64_DIR64LSB.  */
+    case EM_PARISC:
+      return reloc_type == 80; /* R_PARISC_DIR64.  */
+    case EM_PPC64:
+      return reloc_type == 38; /* R_PPC64_ADDR64.  */
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+    case EM_SPARC:
+      return reloc_type == 54; /* R_SPARC_UA64.  */
+    case EM_X86_64:
+    case EM_L1OM:
+      return reloc_type == 1; /* R_X86_64_64.  */
+    case EM_S390_OLD:
+    case EM_S390:
+      return reloc_type == 22; /* R_S390_64 */
+    case EM_MIPS:
+      return reloc_type == 18; /* R_MIPS_64 */
+    default:
+      return FALSE;
+    }
+}
+
+/* Like is_32bit_pcrel_reloc except that it returns TRUE iff RELOC_TYPE is
+   a 64-bit pc-relative RELA relocation used in DWARF debug sections.  */
+
+static bfd_boolean
+is_64bit_pcrel_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_ALPHA:
+      return reloc_type == 11; /* R_ALPHA_SREL64 */
+    case EM_IA_64:
+      return reloc_type == 0x4f; /* R_IA64_PCREL64LSB */
+    case EM_PARISC:
+      return reloc_type == 72; /* R_PARISC_PCREL64 */
+    case EM_PPC64:
+      return reloc_type == 44; /* R_PPC64_REL64 */
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+    case EM_SPARC:
+      return reloc_type == 46; /* R_SPARC_DISP64 */
+    case EM_X86_64:
+    case EM_L1OM:
+      return reloc_type == 24; /* R_X86_64_PC64 */
+    case EM_S390_OLD:
+    case EM_S390:
+      return reloc_type == 23; /* R_S390_PC64 */
+    default:
+      return FALSE;
+    }
+}
+
+/* Like is_32bit_abs_reloc except that it returns TRUE iff RELOC_TYPE is
+   a 16-bit absolute RELA relocation used in DWARF debug sections.  */
+
+static bfd_boolean
+is_16bit_abs_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_AVR_OLD:
+    case EM_AVR:
+      return reloc_type == 4; /* R_AVR_16.  */
+    case EM_CYGNUS_D10V:
+    case EM_D10V:
+      return reloc_type == 3; /* R_D10V_16.  */
+    case EM_H8S:
+    case EM_H8_300:
+    case EM_H8_300H:
+      return reloc_type == R_H8_DIR16;
+    case EM_IP2K_OLD:
+    case EM_IP2K:
+      return reloc_type == 1; /* R_IP2K_16.  */
+    case EM_M32C_OLD:
+    case EM_M32C:
+      return reloc_type == 1; /* R_M32C_16 */
+    case EM_MSP430_OLD:
+    case EM_MSP430:
+      return reloc_type == 5; /* R_MSP430_16_BYTE.  */
+    case EM_ALTERA_NIOS2:
+    case EM_NIOS32:
+      return reloc_type == 9; /* R_NIOS_16.  */
+    default:
+      return FALSE;
+    }
+}
+
+/* Returns TRUE iff RELOC_TYPE is a NONE relocation used for discarded
+   relocation entries (possibly formerly used for SHT_GROUP sections).  */
+
+static bfd_boolean
+is_none_reloc (unsigned int reloc_type)
+{
+  switch (elf_header.e_machine)
+    {
+    case EM_68K:     /* R_68K_NONE.  */
+    case EM_386:     /* R_386_NONE.  */
+    case EM_SPARC32PLUS:
+    case EM_SPARCV9:
+    case EM_SPARC:   /* R_SPARC_NONE.  */
+    case EM_MIPS:    /* R_MIPS_NONE.  */
+    case EM_PARISC:  /* R_PARISC_NONE.  */
+    case EM_ALPHA:   /* R_ALPHA_NONE.  */
+    case EM_PPC:     /* R_PPC_NONE.  */
+    case EM_PPC64:   /* R_PPC64_NONE.  */
+    case EM_ARM:     /* R_ARM_NONE.  */
+    case EM_IA_64:   /* R_IA64_NONE.  */
+    case EM_SH:      /* R_SH_NONE.  */
+    case EM_S390_OLD:
+    case EM_S390:    /* R_390_NONE.  */
+    case EM_CRIS:    /* R_CRIS_NONE.  */
+    case EM_X86_64:  /* R_X86_64_NONE.  */
+    case EM_L1OM:    /* R_X86_64_NONE.  */
+    case EM_MN10300: /* R_MN10300_NONE.  */
+    case EM_M32R:    /* R_M32R_NONE.  */
+      return reloc_type == 0;
+    }
+  return FALSE;
+}
+
+/* Apply relocations to a section.
+   Note: So far support has been added only for those relocations
+   which can be found in debug sections.
+   FIXME: Add support for more relocations ?  */
+
+static void
+apply_relocations (void * file,
+                  Elf_Internal_Shdr * section,
+                  unsigned char * start)
+{
+  Elf_Internal_Shdr * relsec;
+  unsigned char * end = start + section->sh_size;
+
+  if (elf_header.e_type != ET_REL)
+    return;
+
+  /* Find the reloc section associated with the section.  */
+  for (relsec = section_headers;
+       relsec < section_headers + elf_header.e_shnum;
+       ++relsec)
+    {
+      bfd_boolean is_rela;
+      unsigned long num_relocs;
+      Elf_Internal_Rela * relocs;
+      Elf_Internal_Rela * rp;
+      Elf_Internal_Shdr * symsec;
+      Elf_Internal_Sym * symtab;
+      Elf_Internal_Sym * sym;
+
+      if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL)
+         || relsec->sh_info >= elf_header.e_shnum
+         || section_headers + relsec->sh_info != section
+         || relsec->sh_size == 0
+         || relsec->sh_link >= elf_header.e_shnum)
+       continue;
+
+      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_headers + relsec->sh_link;
+      symtab = GET_ELF_SYMBOLS (file, symsec);
+
+      for (rp = relocs; rp < relocs + num_relocs; ++rp)
+       {
+         bfd_vma         addend;
+         unsigned int    reloc_type;
+         unsigned int    reloc_size;
+         unsigned char * loc;
+
+         reloc_type = get_reloc_type (rp->r_info);
+
+         if (target_specific_reloc_handling (rp, start, symtab))
+           continue;
+         else if (is_none_reloc (reloc_type))
+           continue;
+         else if (is_32bit_abs_reloc (reloc_type)
+                  || is_32bit_pcrel_reloc (reloc_type))
+           reloc_size = 4;
+         else if (is_64bit_abs_reloc (reloc_type)
+                  || is_64bit_pcrel_reloc (reloc_type))
+           reloc_size = 8;
+         else if (is_16bit_abs_reloc (reloc_type))
+           reloc_size = 2;
+         else
+           {
+             warn (_("unable to apply unsupported reloc type %d to section %s\n"),
+                   reloc_type, SECTION_NAME (section));
+             continue;
+           }
+
+         loc = start + rp->r_offset;
+         if ((loc + reloc_size) > end)
+           {
+             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.
+
+            Relocations against symbols without type can happen.
+            Gcc -feliminate-dwarf2-dups may generate symbols
+            without type for debug info.
+
+            Icc generates relocations against function symbols
+            instead of local labels.
+
+            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.  */
+         if (sym != symtab
+             && ELF_ST_TYPE (sym->st_info) > STT_SECTION)
+           {
+             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;
+           }
+
+         addend = is_rela ? rp->r_addend : byte_get (loc, reloc_size);
+
+         if (is_32bit_pcrel_reloc (reloc_type)
+             || is_64bit_pcrel_reloc (reloc_type))
+           {
+             /* On HPPA, all pc-relative relocations are biased by 8.  */
+             if (elf_header.e_machine == EM_PARISC)
+               addend -= 8;
+             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 (relocs);
+      break;
+    }
+}
+
 #ifdef SUPPORT_DISASSEMBLY
 static int
-disassemble_section (Elf_Internal_Shdr *section, FILE *file)
+disassemble_section (Elf_Internal_Shdr * section, FILE * file)
 {
   printf (_("\nAssembly dump of section %s\n"),
          SECTION_NAME (section));
@@ -7664,32 +8321,45 @@ disassemble_section (Elf_Internal_Shdr *section, FILE *file)
 }
 #endif
 
-static int
-dump_section (Elf_Internal_Shdr *section, FILE *file)
+/* Reads in the contents of SECTION from FILE, returning a pointer
+   to a malloc'ed buffer or NULL if something went wrong.  */
+
+static char *
+get_section_contents (Elf_Internal_Shdr * section, FILE * file)
 {
-  Elf_Internal_Shdr *relsec;
-  bfd_size_type bytes;
-  bfd_vma addr;
-  unsigned char *data;
-  unsigned char *start;
+  bfd_size_type num_bytes;
 
-  bytes = section->sh_size;
+  num_bytes = section->sh_size;
 
-  if (bytes == 0 || section->sh_type == SHT_NOBITS)
+  if (num_bytes == 0 || section->sh_type == SHT_NOBITS)
     {
       printf (_("\nSection '%s' has no data to dump.\n"),
              SECTION_NAME (section));
-      return 0;
+      return NULL;
     }
-  else
-    printf (_("\nHex dump of section '%s':\n"), SECTION_NAME (section));
 
-  addr = section->sh_addr;
+  return get_data (NULL, file, section->sh_offset, 1, num_bytes,
+                  _("section contents"));
+}
 
-  start = get_data (NULL, file, section->sh_offset, 1, bytes,
-                   _("section data"));
-  if (!start)
-    return 0;
+                     
+static void
+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;
+
+  start = get_section_contents (section, file);
+  if (start == NULL)
+    return;
+
+  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
@@ -7701,253 +8371,269 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
        ++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_info >= elf_header.e_shnum
+         || section_headers + relsec->sh_info != section
          || relsec->sh_size == 0
-         || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum)
+         || 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"));
+      printf (_("  Note: This section has relocations against it, but these have NOT been applied to this dump.\n"));
       break;
     }
-  
+
+  num_bytes = section->sh_size;
+  addr = section->sh_addr;
   data = start;
+  end  = start + num_bytes;
+  some_strings_shown = FALSE;
 
-  while (bytes)
+  while (data < end)
     {
-      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", data[j]);
-         else
-           printf ("  ");
-
-         if ((j & 3) == 3)
-           printf (" ");
-       }
+      while (!ISPRINT (* data))
+       if (++ data >= end)
+         break;
 
-      for (j = 0; j < lbytes; j++)
+      if (data < end)
        {
-         k = data[j];
-         if (k >= ' ' && k < 0x7f)
-           printf ("%c", k);
-         else
-           printf (".");
+#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;
        }
-
-      putchar ('\n');
-
-      data  += lbytes;
-      addr  += lbytes;
-      bytes -= lbytes;
     }
 
+  if (! some_strings_shown)
+    printf (_("  No strings found in this section."));
+
   free (start);
 
   putchar ('\n');
-  return 1;
 }
 
-/* Return the number of bytes affected by a given reloc.
-   This information is architecture and reloc dependent.
-   Returns 4 by default, although this is not always correct.
-   It should return 0 if a decision cannot be made.
-   FIXME: This is not the correct way to solve this problem.
-   The proper way is to have target specific reloc sizing functions
-   created by the reloc-macros.h header, in the same way that it
-   already creates the reloc naming functions.  */
-
-static unsigned int
-get_reloc_size (Elf_Internal_Rela * reloc)
+static void
+dump_section_as_bytes (Elf_Internal_Shdr * section,
+                      FILE * file,
+                      bfd_boolean relocate)
 {
-  switch (elf_header.e_machine)
-    {
-    case EM_H8S:
-    case EM_H8_300:
-    case EM_H8_300H:
-    case EM_H8_500:
-      switch (ELF32_R_TYPE (reloc->r_info))
-       {
-         /* PR gas/3800 - without this information we do not correctly
-            decode the debug information generated by the h8300 assembler.  */
-       case R_H8_DIR16:
-         return 2;
-       default:
-         return 4;
-       }
-    default:
-      /* FIXME: We need to extend this switch statement to cope with other
-        architecture's relocs.  (When those relocs are used against debug
-        sections, and when their size is not 4).  But see the multiple
-        inclusions of <elf/h8.h> for an example of the hoops that we need
-        to jump through in order to obtain the reloc numbers.  */
-      return 4;
-    }
-}
+  Elf_Internal_Shdr * relsec;
+  bfd_size_type bytes;
+  bfd_vma addr;
+  unsigned char * data;
+  unsigned char * start;
 
-/* Apply addends of RELA relocations.  */
+  start = (unsigned char *) get_section_contents (section, file);
+  if (start == NULL)
+    return;
 
-static int
-debug_apply_rela_addends (void *file,
-                         Elf_Internal_Shdr *section,
-                         unsigned char *start)
-{
-  Elf_Internal_Shdr *relsec;
-  unsigned char *end = start + section->sh_size;
+  printf (_("\nHex dump of section '%s':\n"), SECTION_NAME (section));
 
-  if (!is_relocatable)
-    return 1;
+  if (relocate)
+    {
+      apply_relocations (file, section, start);
+    }
+  else
+    {
+      /* 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)
+             || relsec->sh_info >= elf_header.e_shnum
+             || section_headers + relsec->sh_info != section
+             || relsec->sh_size == 0
+             || relsec->sh_link >= elf_header.e_shnum)
+           continue;
 
-  /* SH uses RELA but uses in place value instead of the addend field.  */
-  if (elf_header.e_machine == EM_SH)
-    return 0;
+         printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n"));
+         break;
+       }
+    }
 
-  for (relsec = section_headers;
-       relsec < section_headers + elf_header.e_shnum;
-       ++relsec)
-    {
-      unsigned long nrelas;
-      Elf_Internal_Rela *rela, *rp;
-      Elf_Internal_Shdr *symsec;
-      Elf_Internal_Sym *symtab;
-      Elf_Internal_Sym *sym;
+  addr = section->sh_addr;
+  bytes = section->sh_size;
+  data = start;
 
-      if (relsec->sh_type != SHT_RELA
-         || 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;
+  while (bytes)
+    {
+      int j;
+      int k;
+      int lbytes;
 
-      if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
-                             &rela, &nrelas))
-       return 0;
+      lbytes = (bytes > 16 ? 16 : bytes);
 
-      symsec = SECTION_HEADER (relsec->sh_link);
-      symtab = GET_ELF_SYMBOLS (file, symsec);
+      printf ("  0x%8.8lx ", (unsigned long) addr);
 
-      for (rp = rela; rp < rela + nrelas; ++rp)
+      for (j = 0; j < 16; j++)
        {
-         unsigned char *loc;
-         unsigned int reloc_size;
-
-         reloc_size = get_reloc_size (rp);
-         if (reloc_size == 0)
-           {
-             warn (_("skipping relocation of unknown size against offset 0x%lx in section %s\n"),
-                   (unsigned long) rp->r_offset,
-                   SECTION_NAME (section));
-             continue;
-           }
+         if (j < lbytes)
+           printf ("%2.2x", data[j]);
+         else
+           printf ("  ");
 
-         loc = start + rp->r_offset;
-         if ((loc + reloc_size) > end)
-           {
-             warn (_("skipping invalid relocation offset 0x%lx in section %s\n"),
-                   (unsigned long) rp->r_offset,
-                   SECTION_NAME (section));
-             continue;
-           }
+         if ((j & 3) == 3)
+           printf (" ");
+       }
 
-         if (is_32bit_elf)
-           {
-             sym = symtab + ELF32_R_SYM (rp->r_info);
-
-             if (ELF32_R_SYM (rp->r_info) != 0
-                 && ELF32_ST_TYPE (sym->st_info) != STT_SECTION
-                 /* Relocations against symbols without type can happen.
-                    Gcc -feliminate-dwarf2-dups may generate symbols
-                    without type for debug info.  */
-                 && ELF32_ST_TYPE (sym->st_info) != STT_NOTYPE
-                 /* Relocations against object symbols can happen,
-                    eg when referencing a global array.  For an
-                    example of this see the _clz.o binary in libgcc.a.  */
-                 && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT)
-               {
-                 warn (_("skipping unexpected symbol type %s in relocation in section .rela%s\n"),
-                       get_symbol_type (ELF32_ST_TYPE (sym->st_info)),
-                       SECTION_NAME (section));
-                 continue;
-               }
-           }
+      for (j = 0; j < lbytes; j++)
+       {
+         k = data[j];
+         if (k >= ' ' && k < 0x7f)
+           printf ("%c", k);
          else
-           {
-             /* In MIPS little-endian objects, r_info isn't really a
-                64-bit little-endian value: it has a 32-bit little-endian
-                symbol index followed by four individual byte fields.
-                Reorder INFO accordingly.  */
-             if (elf_header.e_machine == EM_MIPS
-                 && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
-               rp->r_info = (((rp->r_info & 0xffffffff) << 32)
-                             | ((rp->r_info >> 56) & 0xff)
-                             | ((rp->r_info >> 40) & 0xff00)
-                             | ((rp->r_info >> 24) & 0xff0000)
-                             | ((rp->r_info >> 8) & 0xff000000));
-
-             sym = symtab + ELF64_R_SYM (rp->r_info);
-
-             if (ELF64_R_SYM (rp->r_info) != 0
-                 && ELF64_ST_TYPE (sym->st_info) != STT_SECTION
-                 && ELF64_ST_TYPE (sym->st_info) != STT_NOTYPE
-                 && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
-               {
-                 warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"),
-                       get_symbol_type (ELF64_ST_TYPE (sym->st_info)),
-                       SECTION_NAME (section));
-                 continue;
-               }
-           }
-
-         byte_put (loc, rp->r_addend, reloc_size);
+           printf (".");
        }
 
-      free (symtab);
-      free (rela);
-      break;
+      putchar ('\n');
+
+      data  += lbytes;
+      addr  += lbytes;
+      bytes -= lbytes;
     }
+
+  free (start);
+
+  putchar ('\n');
+}
+
+/* Uncompresses a section that was compressed using zlib, in place.
+   This is a copy of bfd_uncompress_section_contents, in bfd/compress.c  */
+
+static int
+uncompress_section_contents (unsigned char ** buffer, dwarf_size_type * size)
+{
+#ifndef HAVE_ZLIB_H
+  /* These are just to quiet gcc.  */
+  buffer = 0;
+  size = 0;
+  return FALSE;
+#else
+  dwarf_size_type compressed_size = *size;
+  unsigned char * compressed_buffer = *buffer;
+  dwarf_size_type uncompressed_size;
+  unsigned char * uncompressed_buffer;
+  z_stream strm;
+  int rc;
+  dwarf_size_type header_size = 12;
+
+  /* Read the zlib header.  In this case, it should be "ZLIB" followed
+     by the uncompressed section size, 8 bytes in big-endian order.  */
+  if (compressed_size < header_size
+      || ! streq ((char *) compressed_buffer, "ZLIB"))
+    return 0;
+
+  uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8;
+  uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8;
+  uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8;
+  uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8;
+  uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8;
+  uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8;
+  uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8;
+  uncompressed_size += compressed_buffer[11];
+
+  /* It is possible the section consists of several compressed
+     buffers concatenated together, so we uncompress in a loop.  */
+  strm.zalloc = NULL;
+  strm.zfree = NULL;
+  strm.opaque = NULL;
+  strm.avail_in = compressed_size - header_size;
+  strm.next_in = (Bytef *) compressed_buffer + header_size;
+  strm.avail_out = uncompressed_size;
+  uncompressed_buffer = xmalloc (uncompressed_size);
+
+  rc = inflateInit (& strm);
+  while (strm.avail_in > 0)
+    {
+      if (rc != Z_OK)
+        goto fail;
+      strm.next_out = ((Bytef *) uncompressed_buffer
+                       + (uncompressed_size - strm.avail_out));
+      rc = inflate (&strm, Z_FINISH);
+      if (rc != Z_STREAM_END)
+        goto fail;
+      rc = inflateReset (& strm);
+    }
+  rc = inflateEnd (& strm);
+  if (rc != Z_OK
+      || strm.avail_out != 0)
+    goto fail;
+
+  free (compressed_buffer);
+  *buffer = uncompressed_buffer;
+  *size = uncompressed_size;
   return 1;
+
+ fail:
+  free (uncompressed_buffer);
+  return 0;
+#endif  /* HAVE_ZLIB_H */
 }
 
-int
-load_debug_section (enum dwarf_section_display_enum debug, void *file)
+static int
+load_specific_debug_section (enum dwarf_section_display_enum debug,
+                            Elf_Internal_Shdr * sec, void * file)
 {
-  struct dwarf_section *section = &debug_displays [debug].section;
-  Elf_Internal_Shdr *sec;
+  struct dwarf_section * section = &debug_displays [debug].section;
   char buf [64];
+  int section_is_compressed;
 
   /* If it is already loaded, do nothing.  */
   if (section->start != NULL)
     return 1;
 
-  /* Locate the debug section.  */
-  sec = find_section (section->name);
-  if (sec == NULL)
-    return 0;
+  section_is_compressed = section->name == section->compressed_name;
 
   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);
+  if (section->start == NULL)
+    return 0;
+
+  if (section_is_compressed)
+    if (! uncompress_section_contents (&section->start, &section->size))
+      return 0;
 
   if (debug_displays [debug].relocate)
-    debug_apply_rela_addends (file, sec, section->start);
+    apply_relocations (file, sec, section->start);
 
-  return section->start != NULL;
+  return 1;
+}
+
+int
+load_debug_section (enum dwarf_section_display_enum debug, void * file)
+{
+  struct dwarf_section * section = &debug_displays [debug].section;
+  Elf_Internal_Shdr * sec;
+
+  /* Locate the debug section.  */
+  sec = find_section (section->uncompressed_name);
+  if (sec != NULL)
+    section->name = section->uncompressed_name;
+  else
+    {
+      sec = find_section (section->compressed_name);
+      if (sec != NULL)
+       section->name = section->compressed_name;
+    }
+  if (sec == NULL)
+    return 0;
+
+  return load_specific_debug_section (debug, sec, file);
 }
 
 void
 free_debug_section (enum dwarf_section_display_enum debug)
 {
-  struct dwarf_section *section = &debug_displays [debug].section;
+  struct dwarf_section * section = &debug_displays [debug].section;
 
   if (section->start == NULL)
     return;
@@ -7959,9 +8645,9 @@ free_debug_section (enum dwarf_section_display_enum debug)
 }
 
 static int
-display_debug_section (Elf_Internal_Shdr *section, FILE *file)
+display_debug_section (Elf_Internal_Shdr * section, FILE * file)
 {
-  char *name = SECTION_NAME (section);
+  char * name = SECTION_NAME (section);
   bfd_size_type length;
   int result = 1;
   enum dwarf_section_display_enum i;
@@ -7972,21 +8658,39 @@ display_debug_section (Elf_Internal_Shdr *section, FILE *file)
       printf (_("\nSection '%s' has no debugging data.\n"), name);
       return 0;
     }
+  if (section->sh_type == SHT_NOBITS)
+    {
+      /* There is no point in dumping the contents of a debugging section
+        which has the NOBITS type - the bits in the file will be random.
+        This can happen when a file containing a .eh_frame section is
+        stripped with the --only-keep-debug command line option.  */
+      printf (_("section '%s' has the NOBITS type - its contents are unreliable.\n"), name);
+      return 0;
+    }
 
   if (const_strneq (name, ".gnu.linkonce.wi."))
     name = ".debug_info";
 
   /* 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))
+    if (streq (debug_displays[i].section.uncompressed_name, name)
+        || streq (debug_displays[i].section.compressed_name, name))
       {
-       struct dwarf_section *sec = &debug_displays [i].section;
+       struct dwarf_section * sec = &debug_displays [i].section;
+       int secondary = (section != find_section (name));
 
-       if (load_debug_section (i, file))
+       if (secondary)
+         free_debug_section (i);
+
+       if (streq (debug_displays[i].section.uncompressed_name, name))
+         sec->name = sec->uncompressed_name;
+       else
+         sec->name = sec->compressed_name;
+       if (load_specific_debug_section (i, section, file))
          {
            result &= debug_displays[i].display (sec, file);
 
-           if (i != info && i != abbrev)
+           if (secondary || (i != info && i != abbrev))
              free_debug_section (i);
          }
 
@@ -8008,7 +8712,7 @@ display_debug_section (Elf_Internal_Shdr *section, FILE *file)
 static void
 initialise_dumps_byname (void)
 {
-  struct dump_list_entry *cur;
+  struct dump_list_entry * cur;
 
   for (cur = dump_sects_byname; cur; cur = cur->next)
     {
@@ -8018,7 +8722,7 @@ initialise_dumps_byname (void)
       for (i = 0, any = 0; i < elf_header.e_shnum; i++)
        if (streq (SECTION_NAME (section_headers + i), cur->name))
          {
-           request_dump (i, cur->type);
+           request_dump_bynumber (i, cur->type);
            any = 1;
          }
 
@@ -8029,9 +8733,9 @@ initialise_dumps_byname (void)
 }
 
 static void
-process_section_contents (FILE *file)
+process_section_contents (FILE * file)
 {
-  Elf_Internal_Shdr *section;
+  Elf_Internal_Shdr * section;
   unsigned int i;
 
   if (! do_dump)
@@ -8048,7 +8752,13 @@ process_section_contents (FILE *file)
        disassemble_section (section, file);
 #endif
       if (dump_sects[i] & HEX_DUMP)
-       dump_section (section, file);
+       dump_section_as_bytes (section, file, FALSE);
+
+      if (dump_sects[i] & RELOC_DUMP)
+       dump_section_as_bytes (section, file, TRUE);
+
+      if (dump_sects[i] & STRING_DUMP)
+       dump_section_as_strings (section, file);
 
       if (dump_sects[i] & DEBUG_DUMP)
        display_debug_section (section, file);
@@ -8086,58 +8796,68 @@ process_mips_fpe_exception (int mask)
 typedef struct
 {
   int tag;
-  const char *name;
+  const char * name;
   /* 0 = special, 1 = string, 2 = uleb123, > 0x80 == table lookup.  */
   int type;
-  const char **table;
+  const char ** table;
 } arm_attr_public_tag;
 
-static const char *arm_attr_tag_CPU_arch[] =
+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[] =
+   "v6K", "v7", "v6-M", "v6S-M"};
+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[] =
+static const char * arm_attr_tag_VFP_arch[] =
+  {"No", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16"};
+static const char * arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1", "WMMXv2"};
+static const char * arm_attr_tag_Advanced_SIMD_arch[] = {"No", "NEONv1"};
+static const char * arm_attr_tag_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[] =
+static const char * arm_attr_tag_ABI_PCS_R9_use[] =
   {"V6", "SB", "TLS", "Unused"};
-static const char *arm_attr_tag_ABI_PCS_RW_data[] =
+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[] =
+static const char * arm_attr_tag_ABI_PCS_RO_data[] =
   {"Absolute", "PC-relative", "None"};
-static const char *arm_attr_tag_ABI_PCS_GOT_use[] =
+static const char * arm_attr_tag_ABI_PCS_GOT_use[] =
   {"None", "direct", "GOT-indirect"};
-static const char *arm_attr_tag_ABI_PCS_wchar_t[] =
+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[] =
+static const char * arm_attr_tag_ABI_FP_rounding[] = {"Unused", "Needed"};
+static const char * arm_attr_tag_ABI_FP_denormal[] =
+  {"Unused", "Needed", "Sign only"};
+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[] =
+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[] =
+static const char * arm_attr_tag_ABI_enum_size[] =
   {"Unused", "small", "int", "forced to int"};
-static const char *arm_attr_tag_ABI_HardFP_use[] =
+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[] =
+static const char * arm_attr_tag_ABI_VFP_args[] =
   {"AAPCS", "VFP registers", "custom"};
-static const char *arm_attr_tag_ABI_WMMX_args[] =
+static const char * arm_attr_tag_ABI_WMMX_args[] =
   {"AAPCS", "WMMX registers", "custom"};
-static const char *arm_attr_tag_ABI_optimization_goals[] =
+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[] =
+static const char * arm_attr_tag_ABI_FP_optimization_goals[] =
   {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size",
     "Aggressive Size", "Prefer Accuracy", "Aggressive Accuracy"};
+static const char * arm_attr_tag_CPU_unaligned_access[] = {"None", "v6"};
+static const char * arm_attr_tag_VFP_HP_extension[] =
+  {"Not Allowed", "Allowed"};
+static const char * arm_attr_tag_ABI_FP_16bit_format[] =
+  {"None", "IEEE 754", "Alternative Format"};
+static const char * arm_attr_tag_T2EE_use[] = {"Not Allowed", "Allowed"};
+static const char * arm_attr_tag_Virtualization_use[] =
+  {"Not Allowed", "Allowed"};
+static const char * arm_attr_tag_MPextension_use[] = {"Not Allowed", "Allowed"};
 
 #define LOOKUP(id, name) \
   {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name}
@@ -8151,11 +8871,11 @@ static arm_attr_public_tag arm_attr_public_tags[] =
   LOOKUP(9, THUMB_ISA_use),
   LOOKUP(10, VFP_arch),
   LOOKUP(11, WMMX_arch),
-  LOOKUP(12, NEON_arch),
-  LOOKUP(13, ABI_PCS_config),
+  LOOKUP(12, Advanced_SIMD_arch),
+  LOOKUP(13, PCS_config),
   LOOKUP(14, ABI_PCS_R9_use),
   LOOKUP(15, ABI_PCS_RW_data),
-  LOOKUP(16, ABI_PCS_RO_DATA),
+  LOOKUP(16, ABI_PCS_RO_data),
   LOOKUP(17, ABI_PCS_GOT_use),
   LOOKUP(18, ABI_PCS_wchar_t),
   LOOKUP(19, ABI_FP_rounding),
@@ -8171,14 +8891,24 @@ static arm_attr_public_tag arm_attr_public_tags[] =
   LOOKUP(29, ABI_WMMX_args),
   LOOKUP(30, ABI_optimization_goals),
   LOOKUP(31, ABI_FP_optimization_goals),
-  {32, "compatibility", 0, NULL}
+  {32, "compatibility", 0, NULL},
+  LOOKUP(34, CPU_unaligned_access),
+  LOOKUP(36, VFP_HP_extension),
+  LOOKUP(38, ABI_FP_16bit_format),
+  {64, "nodefaults", 0, NULL},
+  {65, "also_compatible_with", 0, NULL},
+  LOOKUP(66, T2EE_use),
+  {67, "conformance", 1, NULL},
+  LOOKUP(68, Virtualization_use),
+  LOOKUP(70, MPextension_use)
 };
 #undef LOOKUP
 
 /* 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)
+read_uleb128 (unsigned char * p, unsigned int * plen)
 {
   unsigned char c;
   unsigned int val;
@@ -8202,19 +8932,19 @@ read_uleb128 (unsigned char *p, unsigned int *plen)
 }
 
 static unsigned char *
-display_arm_attribute (unsigned char *p)
+display_arm_attribute (unsigned char * p)
 {
   int tag;
   unsigned int len;
   int val;
-  arm_attr_public_tag *attr;
+  arm_attr_public_tag * attr;
   unsigned i;
   int type;
 
   tag = read_uleb128 (p, &len);
   p += len;
   attr = NULL;
-  for (i = 0; i < ARRAY_SIZE(arm_attr_public_tags); i++)
+  for (i = 0; i < ARRAY_SIZE (arm_attr_public_tags); i++)
     {
       if (arm_attr_public_tags[i].tag == tag)
        {
@@ -8248,11 +8978,33 @@ display_arm_attribute (unsigned char *p)
              val = read_uleb128 (p, &len);
              p += len;
              printf ("flag = %d, vendor = %s\n", val, p);
-             p += strlen((char *)p) + 1;
+             p += strlen ((char *) p) + 1;
+             break;
+
+           case 64: /* Tag_nodefaults.  */
+             p++;
+             printf ("True\n");
+             break;
+
+           case 65: /* Tag_also_compatible_with.  */
+             val = read_uleb128 (p, &len);
+             p += len;
+             if (val == 6 /* Tag_CPU_arch.  */)
+               {
+                 val = read_uleb128 (p, &len);
+                 p += len;
+                 if ((unsigned int)val >= ARRAY_SIZE (arm_attr_tag_CPU_arch))
+                   printf ("??? (%d)\n", val);
+                 else
+                   printf ("%s\n", arm_attr_tag_CPU_arch[val]);
+               }
+             else
+               printf ("???\n");
+             while (*(p++) != '\0' /* NUL terminator.  */);
              break;
 
            default:
-             abort();
+             abort ();
            }
          return p;
 
@@ -8285,7 +9037,7 @@ display_arm_attribute (unsigned char *p)
   if (type == 1)
     {
       printf ("\"%s\"\n", p);
-      p += strlen((char *)p) + 1;
+      p += strlen ((char *) p) + 1;
     }
   else
     {
@@ -8297,11 +9049,9 @@ display_arm_attribute (unsigned char *p)
   return p;
 }
 
-
 static unsigned char *
-display_gnu_attribute (unsigned char *p,
-                      unsigned char *(*display_proc_gnu_attribute)
-                           (unsigned char *, int))
+display_gnu_attribute (unsigned char * p,
+                      unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int))
 {
   int tag;
   unsigned int len;
@@ -8318,7 +9068,7 @@ display_gnu_attribute (unsigned char *p,
       val = read_uleb128 (p, &len);
       p += len;
       printf ("flag = %d, vendor = %s\n", val, p);
-      p += strlen((char *)p) + 1;
+      p += strlen ((char *) p) + 1;
       return p;
     }
 
@@ -8334,7 +9084,169 @@ display_gnu_attribute (unsigned char *p,
   if (type == 1)
     {
       printf ("\"%s\"\n", p);
-      p += strlen ((char *)p) + 1;
+      p += strlen ((char *) p) + 1;
+    }
+  else
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("%d (0x%x)\n", val, val);
+    }
+
+  return p;
+}
+
+static unsigned char *
+display_power_gnu_attribute (unsigned char * p, int tag)
+{
+  int type;
+  unsigned int len;
+  int val;
+
+  if (tag == Tag_GNU_Power_ABI_FP)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_Power_ABI_FP: ");
+
+      switch (val)
+       {
+       case 0:
+         printf ("Hard or soft float\n");
+         break;
+       case 1:
+         printf ("Hard float\n");
+         break;
+       case 2:
+         printf ("Soft float\n");
+         break;
+       case 3:
+         printf ("Single-precision hard float\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
+       }
+      return p;
+   }
+
+  if (tag == Tag_GNU_Power_ABI_Vector)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_Power_ABI_Vector: ");
+      switch (val)
+       {
+       case 0:
+         printf ("Any\n");
+         break;
+       case 1:
+         printf ("Generic\n");
+         break;
+       case 2:
+         printf ("AltiVec\n");
+         break;
+       case 3:
+         printf ("SPE\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
+       }
+      return p;
+   }
+
+  if (tag == Tag_GNU_Power_ABI_Struct_Return)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_Power_ABI_Struct_Return: ");
+      switch (val)
+       {
+       case 0:
+         printf ("Any\n");
+         break;
+       case 1:
+         printf ("r3/r4\n");
+         break;
+       case 2:
+         printf ("Memory\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
+       }
+      return p;
+    }
+
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
+
+  if (type == 1)
+    {
+      printf ("\"%s\"\n", p);
+      p += strlen ((char *) p) + 1;
+    }
+  else
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("%d (0x%x)\n", val, val);
+    }
+
+  return p;
+}
+
+static unsigned char *
+display_mips_gnu_attribute (unsigned char * p, int tag)
+{
+  int type;
+  unsigned int len;
+  int val;
+
+  if (tag == Tag_GNU_MIPS_ABI_FP)
+    {
+      val = read_uleb128 (p, &len);
+      p += len;
+      printf ("  Tag_GNU_MIPS_ABI_FP: ");
+
+      switch (val)
+       {
+       case 0:
+         printf ("Hard or soft float\n");
+         break;
+       case 1:
+         printf ("Hard float (-mdouble-float)\n");
+         break;
+       case 2:
+         printf ("Hard float (-msingle-float)\n");
+         break;
+       case 3:
+         printf ("Soft float\n");
+         break;
+       case 4:
+         printf ("64-bit float (-mips32r2 -mfp64)\n");
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+         break;
+       }
+      return p;
+   }
+
+  if (tag & 1)
+    type = 1; /* String.  */
+  else
+    type = 2; /* uleb128.  */
+  printf ("  Tag_unknown_%d: ", tag);
+
+  if (type == 1)
+    {
+      printf ("\"%s\"\n", p);
+      p += strlen ((char *) p) + 1;
     }
   else
     {
@@ -8347,16 +9259,16 @@ display_gnu_attribute (unsigned char *p,
 }
 
 static int
-process_attributes (FILE *file, const char *public_name,
+process_attributes (FILE * file,
+                   const char * public_name,
                    unsigned int proc_type,
-                   unsigned char *(*display_pub_attribute) (unsigned char *),
-                   unsigned char *(*display_proc_gnu_attribute)
-                        (unsigned char *, int))
-{
-  Elf_Internal_Shdr *sect;
-  unsigned char *contents;
-  unsigned char *p;
-  unsigned char *end;
+                   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;
@@ -8371,14 +9283,15 @@ process_attributes (FILE *file, const char *public_name,
 
       contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size,
                           _("attributes"));
-
-      if (!contents)
+      if (contents == NULL)
        continue;
+
       p = contents;
       if (*p == 'A')
        {
          len = sect->sh_size - 1;
          p++;
+
          while (len > 0)
            {
              int namelen;
@@ -8387,40 +9300,49 @@ process_attributes (FILE *file, const char *public_name,
 
              section_len = byte_get (p, 4);
              p += 4;
+
              if (section_len > len)
                {
                  printf (_("ERROR: Bad section length (%d > %d)\n"),
-                         (int)section_len, (int)len);
+                         (int) section_len, (int) len);
                  section_len = len;
                }
+
              len -= section_len;
              printf ("Attribute Section: %s\n", p);
-             if (public_name && strcmp ((char *)p, public_name) == 0)
+
+             if (public_name && streq ((char *) p, public_name))
                public_section = TRUE;
              else
                public_section = FALSE;
-             if (strcmp ((char *)p, "gnu") == 0)
+
+             if (streq ((char *) p, "gnu"))
                gnu_section = TRUE;
              else
                gnu_section = FALSE;
-             namelen = strlen ((char *)p) + 1;
+
+             namelen = strlen ((char *) p) + 1;
              p += namelen;
              section_len -= namelen + 4;
+
              while (section_len > 0)
                {
                  int tag = *(p++);
                  int val;
                  bfd_vma size;
+
                  size = byte_get (p, 4);
                  if (size > section_len)
                    {
                      printf (_("ERROR: Bad subsection length (%d > %d)\n"),
-                             (int)size, (int)section_len);
+                             (int) size, (int) section_len);
                      size = section_len;
                    }
+
                  section_len -= size;
                  end = p + size - 1;
                  p += 4;
+
                  switch (tag)
                    {
                    case 1:
@@ -8435,6 +9357,7 @@ process_attributes (FILE *file, const char *public_name,
                      for (;;)
                        {
                          unsigned int i;
+
                          val = read_uleb128 (p, &i);
                          p += i;
                          if (val == 0)
@@ -8448,6 +9371,7 @@ process_attributes (FILE *file, const char *public_name,
                      public_section = FALSE;
                      break;
                    }
+
                  if (public_section)
                    {
                      while (p < end)
@@ -8469,31 +9393,96 @@ process_attributes (FILE *file, const char *public_name,
            }
        }
       else
-       {
-         printf (_("Unknown format '%c'\n"), *p);
-       }
+       printf (_("Unknown format '%c'\n"), *p);
 
-      free(contents);
+      free (contents);
     }
   return 1;
 }
 
-static int
-process_arm_specific (FILE *file)
+static int
+process_arm_specific (FILE * file)
+{
+  return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES,
+                            display_arm_attribute, NULL);
+}
+
+static int
+process_power_specific (FILE * file)
+{
+  return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
+                            display_power_gnu_attribute);
+}
+
+/* DATA points to the contents of a MIPS GOT that starts at VMA PLTGOT.
+   Print the Address, Access and Initial fields of an entry at VMA ADDR
+   and return the VMA of the next entry.  */
+
+static bfd_vma
+print_mips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr)
+{
+  printf ("  ");
+  print_vma (addr, LONG_HEX);
+  printf (" ");
+  if (addr < pltgot + 0xfff0)
+    printf ("%6d(gp)", (int) (addr - pltgot - 0x7ff0));
+  else
+    printf ("%10s", "");
+  printf (" ");
+  if (data == NULL)
+    printf ("%*s", is_32bit_elf ? 8 : 16, "<unknown>");
+  else
+    {
+      bfd_vma entry;
+
+      entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
+      print_vma (entry, LONG_HEX);
+    }
+  return addr + (is_32bit_elf ? 4 : 8);
+}
+
+/* DATA points to the contents of a MIPS PLT GOT that starts at VMA
+   PLTGOT.  Print the Address and Initial fields of an entry at VMA
+   ADDR and return the VMA of the next entry.  */
+
+static bfd_vma
+print_mips_pltgot_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr)
 {
-  return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES,
-                            display_arm_attribute, NULL);
+  printf ("  ");
+  print_vma (addr, LONG_HEX);
+  printf (" ");
+  if (data == NULL)
+    printf ("%*s", is_32bit_elf ? 8 : 16, "<unknown>");
+  else
+    {
+      bfd_vma entry;
+
+      entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
+      print_vma (entry, LONG_HEX);
+    }
+  return addr + (is_32bit_elf ? 4 : 8);
 }
 
 static int
-process_mips_specific (FILE *file)
+process_mips_specific (FILE * file)
 {
-  Elf_Internal_Dyn *entry;
+  Elf_Internal_Dyn * entry;
   size_t liblist_offset = 0;
   size_t liblistno = 0;
   size_t conflictsno = 0;
   size_t options_offset = 0;
   size_t conflicts_offset = 0;
+  size_t pltrelsz = 0;
+  size_t pltrel = 0;
+  bfd_vma pltgot = 0;
+  bfd_vma mips_pltgot = 0;
+  bfd_vma jmprel = 0;
+  bfd_vma local_gotno = 0;
+  bfd_vma gotsym = 0;
+  bfd_vma symtabno = 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)
@@ -8522,13 +9511,37 @@ process_mips_specific (FILE *file)
       case DT_MIPS_CONFLICTNO:
        conflictsno = entry->d_un.d_val;
        break;
+      case DT_PLTGOT:
+       pltgot = entry->d_un.d_ptr;
+       break;
+      case DT_MIPS_LOCAL_GOTNO:
+       local_gotno = entry->d_un.d_val;
+       break;
+      case DT_MIPS_GOTSYM:
+       gotsym = entry->d_un.d_val;
+       break;
+      case DT_MIPS_SYMTABNO:
+       symtabno = entry->d_un.d_val;
+       break;
+      case DT_MIPS_PLTGOT:
+       mips_pltgot = entry->d_un.d_ptr;
+       break;
+      case DT_PLTREL:
+       pltrel = entry->d_un.d_val;
+       break;
+      case DT_PLTRELSZ:
+       pltrelsz = entry->d_un.d_val;
+       break;
+      case DT_JMPREL:
+       jmprel = entry->d_un.d_ptr;
+       break;
       default:
        break;
       }
 
   if (liblist_offset != 0 && liblistno != 0 && do_dynamic)
     {
-      Elf32_External_Lib *elib;
+      Elf32_External_Lib * elib;
       size_t cnt;
 
       elib = get_data (NULL, file, liblist_offset,
@@ -8546,7 +9559,7 @@ process_mips_specific (FILE *file)
              Elf32_Lib liblist;
              time_t time;
              char timebuf[20];
-             struct tm *tmp;
+             struct tm * tmp;
 
              liblist.l_name = BYTE_GET (elib[cnt].l_name);
              time = BYTE_GET (elib[cnt].l_time_stamp);
@@ -8574,7 +9587,7 @@ process_mips_specific (FILE *file)
                {
                  static const struct
                  {
-                   const char *name;
+                   const char * name;
                    int bit;
                  }
                  l_flags_vals[] =
@@ -8589,9 +9602,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);
@@ -8610,10 +9621,10 @@ process_mips_specific (FILE *file)
 
   if (options_offset != 0)
     {
-      Elf_External_Options *eopt;
-      Elf_Internal_Shdr *sect = section_headers;
-      Elf_Internal_Options *iopt;
-      Elf_Internal_Options *option;
+      Elf_External_Options * eopt;
+      Elf_Internal_Shdr * sect = section_headers;
+      Elf_Internal_Options * iopt;
+      Elf_Internal_Options * option;
       size_t offset;
       int cnt;
 
@@ -8625,7 +9636,7 @@ process_mips_specific (FILE *file)
                       _("options"));
       if (eopt)
        {
-         iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt));
+         iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (* iopt));
          if (iopt == NULL)
            {
              error (_("Out of memory\n"));
@@ -8637,7 +9648,7 @@ process_mips_specific (FILE *file)
 
          while (offset < sect->sh_size)
            {
-             Elf_External_Options *eoption;
+             Elf_External_Options * eoption;
 
              eoption = (Elf_External_Options *) ((char *) eopt + offset);
 
@@ -8672,7 +9683,7 @@ process_mips_specific (FILE *file)
                  if (elf_header.e_machine == EM_MIPS)
                    {
                      /* 32bit form.  */
-                     Elf32_External_RegInfo *ereg;
+                     Elf32_External_RegInfo * ereg;
                      Elf32_RegInfo reginfo;
 
                      ereg = (Elf32_External_RegInfo *) (option + 1);
@@ -8693,7 +9704,7 @@ process_mips_specific (FILE *file)
                  else
                    {
                      /* 64 bit form.  */
-                     Elf64_External_RegInfo *ereg;
+                     Elf64_External_RegInfo * ereg;
                      Elf64_Internal_RegInfo reginfo;
 
                      ereg = (Elf64_External_RegInfo *) (option + 1);
@@ -8790,7 +9801,7 @@ process_mips_specific (FILE *file)
                  break;
                }
 
-             len = sizeof (*eopt);
+             len = sizeof (* eopt);
              while (len < option->size)
                if (((char *) option)[len] >= ' '
                    && ((char *) option)[len] < 0x7f)
@@ -8808,7 +9819,7 @@ process_mips_specific (FILE *file)
 
   if (conflicts_offset != 0 && conflictsno != 0)
     {
-      Elf32_Conflict *iconf;
+      Elf32_Conflict * iconf;
       size_t cnt;
 
       if (dynamic_symbols == NULL)
@@ -8817,7 +9828,7 @@ process_mips_specific (FILE *file)
          return 0;
        }
 
-      iconf = cmalloc (conflictsno, sizeof (*iconf));
+      iconf = cmalloc (conflictsno, sizeof (* iconf));
       if (iconf == NULL)
        {
          error (_("Out of memory\n"));
@@ -8826,10 +9837,10 @@ process_mips_specific (FILE *file)
 
       if (is_32bit_elf)
        {
-         Elf32_External_Conflict *econf32;
+         Elf32_External_Conflict * econf32;
 
          econf32 = get_data (NULL, file, conflicts_offset,
-                             conflictsno, sizeof (*econf32), _("conflict"));
+                             conflictsno, sizeof (* econf32), _("conflict"));
          if (!econf32)
            return 0;
 
@@ -8840,10 +9851,10 @@ process_mips_specific (FILE *file)
        }
       else
        {
-         Elf64_External_Conflict *econf64;
+         Elf64_External_Conflict * econf64;
 
          econf64 = get_data (NULL, file, conflicts_offset,
-                             conflictsno, sizeof (*econf64), _("conflict"));
+                             conflictsno, sizeof (* econf64), _("conflict"));
          if (!econf64)
            return 0;
 
@@ -8859,7 +9870,7 @@ process_mips_specific (FILE *file)
 
       for (cnt = 0; cnt < conflictsno; ++cnt)
        {
-         Elf_Internal_Sym *psym = & dynamic_symbols[iconf[cnt]];
+         Elf_Internal_Sym * psym = & dynamic_symbols[iconf[cnt]];
 
          printf ("%5lu: %8lu  ", (unsigned long) cnt, iconf[cnt]);
          print_vma (psym->st_value, FULL_HEX);
@@ -8874,15 +9885,165 @@ process_mips_specific (FILE *file)
       free (iconf);
     }
 
+  if (pltgot != 0 && local_gotno != 0)
+    {
+      bfd_vma entry, local_end, global_end;
+      size_t i, offset;
+      unsigned char * data;
+      int addr_size;
+
+      entry = pltgot;
+      addr_size = (is_32bit_elf ? 4 : 8);
+      local_end = pltgot + local_gotno * addr_size;
+      global_end = local_end + (symtabno - gotsym) * addr_size;
+
+      offset = offset_from_vma (file, pltgot, global_end - pltgot);
+      data = get_data (NULL, file, offset, global_end - pltgot, 1, _("GOT"));
+      printf (_("\nPrimary GOT:\n"));
+      printf (_(" Canonical gp value: "));
+      print_vma (pltgot + 0x7ff0, LONG_HEX);
+      printf ("\n\n");
+
+      printf (_(" Reserved entries:\n"));
+      printf (_("  %*s %10s %*s Purpose\n"),
+             addr_size * 2, "Address", "Access",
+             addr_size * 2, "Initial");
+      entry = print_mips_got_entry (data, pltgot, entry);
+      printf (" Lazy resolver\n");
+      if (data
+         && (byte_get (data + entry - pltgot, addr_size)
+             >> (addr_size * 8 - 1)) != 0)
+       {
+         entry = print_mips_got_entry (data, pltgot, entry);
+         printf (" Module pointer (GNU extension)\n");
+       }
+      printf ("\n");
+
+      if (entry < local_end)
+       {
+         printf (_(" Local entries:\n"));
+         printf (_("  %*s %10s %*s\n"),
+                 addr_size * 2, "Address", "Access",
+                 addr_size * 2, "Initial");
+         while (entry < local_end)
+           {
+             entry = print_mips_got_entry (data, pltgot, entry);
+             printf ("\n");
+           }
+         printf ("\n");
+       }
+
+      if (gotsym < symtabno)
+       {
+         int sym_width;
+
+         printf (_(" Global entries:\n"));
+         printf (_("  %*s %10s %*s %*s %-7s %3s %s\n"),
+                 addr_size * 2, "Address", "Access",
+                 addr_size * 2, "Initial",
+                 addr_size * 2, "Sym.Val.", "Type", "Ndx", "Name");
+         sym_width = (is_32bit_elf ? 80 : 160) - 28 - addr_size * 6 - 1;
+         for (i = gotsym; i < symtabno; i++)
+           {
+             Elf_Internal_Sym * psym;
+
+             psym = dynamic_symbols + i;
+             entry = print_mips_got_entry (data, pltgot, entry);
+             printf (" ");
+             print_vma (psym->st_value, LONG_HEX);
+             printf (" %-7s %3s ",
+                     get_symbol_type (ELF_ST_TYPE (psym->st_info)),
+                     get_symbol_index_type (psym->st_shndx));
+             if (VALID_DYNAMIC_NAME (psym->st_name))
+               print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
+             else
+               printf ("<corrupt: %14ld>", psym->st_name);
+             printf ("\n");
+           }
+         printf ("\n");
+       }
+
+      if (data)
+       free (data);
+    }
+
+  if (mips_pltgot != 0 && jmprel != 0 && pltrel != 0 && pltrelsz != 0)
+    {
+      bfd_vma entry, end;
+      size_t offset, rel_offset;
+      unsigned long count, i;
+      unsigned char * data;
+      int addr_size, sym_width;
+      Elf_Internal_Rela * rels;
+
+      rel_offset = offset_from_vma (file, jmprel, pltrelsz);
+      if (pltrel == DT_RELA)
+       {
+         if (!slurp_rela_relocs (file, rel_offset, pltrelsz, &rels, &count))
+           return 0;
+       }
+      else
+       {
+         if (!slurp_rel_relocs (file, rel_offset, pltrelsz, &rels, &count))
+           return 0;
+       }
+
+      entry = mips_pltgot;
+      addr_size = (is_32bit_elf ? 4 : 8);
+      end = mips_pltgot + (2 + count) * addr_size;
+
+      offset = offset_from_vma (file, mips_pltgot, end - mips_pltgot);
+      data = get_data (NULL, file, offset, end - mips_pltgot, 1, _("PLT GOT"));
+      printf (_("\nPLT GOT:\n\n"));
+      printf (_(" Reserved entries:\n"));
+      printf (_("  %*s %*s Purpose\n"),
+             addr_size * 2, "Address", addr_size * 2, "Initial");
+      entry = print_mips_pltgot_entry (data, mips_pltgot, entry);
+      printf (" PLT lazy resolver\n");
+      entry = print_mips_pltgot_entry (data, mips_pltgot, entry);
+      printf (" Module pointer\n");
+      printf ("\n");
+
+      printf (_(" Entries:\n"));
+      printf (_("  %*s %*s %*s %-7s %3s %s\n"),
+             addr_size * 2, "Address",
+             addr_size * 2, "Initial",
+             addr_size * 2, "Sym.Val.", "Type", "Ndx", "Name");
+      sym_width = (is_32bit_elf ? 80 : 160) - 17 - addr_size * 6 - 1;
+      for (i = 0; i < count; i++)
+       {
+         Elf_Internal_Sym * psym;
+
+         psym = dynamic_symbols + get_reloc_symindex (rels[i].r_info);
+         entry = print_mips_pltgot_entry (data, mips_pltgot, entry);
+         printf (" ");
+         print_vma (psym->st_value, LONG_HEX);
+         printf (" %-7s %3s ",
+                 get_symbol_type (ELF_ST_TYPE (psym->st_info)),
+                 get_symbol_index_type (psym->st_shndx));
+         if (VALID_DYNAMIC_NAME (psym->st_name))
+           print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
+         else
+           printf ("<corrupt: %14ld>", psym->st_name);
+         printf ("\n");
+       }
+      printf ("\n");
+
+      if (data)
+       free (data);
+      free (rels);
+    }
+
   return 1;
 }
 
 static int
-process_gnu_liblist (FILE *file)
+process_gnu_liblist (FILE * file)
 {
-  Elf_Internal_Shdr *section, *string_sec;
-  Elf32_External_Lib *elib;
-  char *strtab;
+  Elf_Internal_Shdr * section;
+  Elf_Internal_Shdr * string_sec;
+  Elf32_External_Lib * elib;
+  char * strtab;
   size_t strtab_size;
   size_t cnt;
   unsigned i;
@@ -8897,7 +10058,7 @@ process_gnu_liblist (FILE *file)
       switch (section->sh_type)
        {
        case SHT_GNU_LIBLIST:
-         if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum)
+         if (section->sh_link >= elf_header.e_shnum)
            break;
 
          elib = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
@@ -8905,7 +10066,7 @@ process_gnu_liblist (FILE *file)
 
          if (elib == NULL)
            break;
-         string_sec = SECTION_HEADER (section->sh_link);
+         string_sec = section_headers + section->sh_link;
 
          strtab = get_data (NULL, file, string_sec->sh_offset, 1,
                             string_sec->sh_size, _("liblist string table"));
@@ -8920,7 +10081,7 @@ process_gnu_liblist (FILE *file)
 
          printf (_("\nLibrary list section '%s' contains %lu entries:\n"),
                  SECTION_NAME (section),
-                 (long) (section->sh_size / sizeof (Elf32_External_Lib)));
+                 (unsigned long) (section->sh_size / sizeof (Elf32_External_Lib)));
 
          puts ("     Library              Time Stamp          Checksum   Version Flags");
 
@@ -8930,7 +10091,7 @@ process_gnu_liblist (FILE *file)
              Elf32_Lib liblist;
              time_t time;
              char timebuf[20];
-             struct tm *tmp;
+             struct tm * tmp;
 
              liblist.l_name = BYTE_GET (elib[cnt].l_name);
              time = BYTE_GET (elib[cnt].l_time_stamp);
@@ -8982,6 +10143,10 @@ 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_PPC_VSX:
+       return _("NT_PPC_VSX (ppc VSX registers)");
       case NT_PSTATUS:
        return _("NT_PSTATUS (pstatus structure)");
       case NT_FPREGS:
@@ -9012,6 +10177,29 @@ 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)");
+    case NT_GNU_GOLD_VERSION:
+      return _("NT_GNU_GOLD_VERSION (gold version)");
+    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)
 {
@@ -9080,36 +10268,46 @@ get_netbsd_elfcore_note_type (unsigned e_type)
 
    If the value of namesz is zero, there is no name present.  */
 static int
-process_note (Elf_Internal_Note *pnote)
+process_note (Elf_Internal_Note * pnote)
 {
-  const char *nt;
+  const char * name = pnote->namesz ? pnote->namedata : "(NONE)";
+  const char * nt;
 
   if (pnote->namesz == 0)
     /* If there is no note name, then use the default set of
        note type strings.  */
     nt = get_note_type (pnote->type);
 
+  else if (const_strneq (pnote->namedata, "GNU"))
+    /* GNU-specific object file notes.  */
+    nt = get_gnu_elf_note_type (pnote->type);
+
   else if (const_strneq (pnote->namedata, "NetBSD-CORE"))
     /* NetBSD-specific core file notes.  */
     nt = get_netbsd_elfcore_note_type (pnote->type);
 
+  else if (strneq (pnote->namedata, "SPU/", 4))
+    {
+      /* SPU-specific core file notes.  */
+      nt = pnote->namedata + 4;
+      name = "SPU";
+    }
+
   else
     /* Don't recognize this note name; just use the default set of
        note type strings.  */
       nt = get_note_type (pnote->type);
 
-  printf ("  %s\t\t0x%08lx\t%s\n",
-         pnote->namesz ? pnote->namedata : "(NONE)",
-         pnote->descsz, nt);
+  printf ("  %s\t\t0x%08lx\t%s\n", name, pnote->descsz, nt);
   return 1;
 }
 
 
 static int
-process_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length)
+process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length)
 {
-  Elf_External_Note *pnotes;
-  Elf_External_Note *external;
+  Elf_External_Note * pnotes;
+  Elf_External_Note * external;
   int res = 1;
 
   if (length <= 0)
@@ -9125,11 +10323,11 @@ process_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length)
          (unsigned long) offset, (unsigned long) length);
   printf (_("  Owner\t\tData size\tDescription\n"));
 
-  while (external < (Elf_External_Note *)((char *) pnotes + length))
+  while (external < (Elf_External_Note *) ((char *) pnotes + length))
     {
-      Elf_External_Note *next;
+      Elf_External_Note * next;
       Elf_Internal_Note inote;
-      char *temp = NULL;
+      char * temp = NULL;
 
       inote.type     = BYTE_GET (external->type);
       inote.namesz   = BYTE_GET (external->namesz);
@@ -9138,12 +10336,12 @@ process_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length)
       inote.descdata = inote.namedata + align_power (inote.namesz, 2);
       inote.descpos  = offset + (inote.descdata - (char *) pnotes);
 
-      next = (Elf_External_Note *)(inote.descdata + align_power (inote.descsz, 2));
+      next = (Elf_External_Note *) (inote.descdata + align_power (inote.descsz, 2));
 
       if (((char *) next) > (((char *) pnotes) + length))
        {
          warn (_("corrupt note found at offset %lx into core notes\n"),
-               (long)((char *)external - (char *)pnotes));
+               (unsigned long) ((char *) external - (char *) pnotes));
          warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"),
                inote.type, inote.namesz, inote.descsz);
          break;
@@ -9188,9 +10386,9 @@ process_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length)
 }
 
 static int
-process_corefile_note_segments (FILE *file)
+process_corefile_note_segments (FILE * file)
 {
-  Elf_Internal_Phdr *segment;
+  Elf_Internal_Phdr * segment;
   unsigned int i;
   int res = 1;
 
@@ -9211,9 +10409,9 @@ process_corefile_note_segments (FILE *file)
 }
 
 static int
-process_note_sections (FILE *file)
+process_note_sections (FILE * file)
 {
-  Elf_Internal_Shdr *section;
+  Elf_Internal_Shdr * section;
   unsigned long i;
   int res = 1;
 
@@ -9229,7 +10427,7 @@ process_note_sections (FILE *file)
 }
 
 static int
-process_notes (FILE *file)
+process_notes (FILE * file)
 {
   /* If we have not been asked to display the notes then do nothing.  */
   if (! do_notes)
@@ -9247,7 +10445,7 @@ process_notes (FILE *file)
 }
 
 static int
-process_arch_specific (FILE *file)
+process_arch_specific (FILE * file)
 {
   if (! do_arch)
     return 1;
@@ -9260,6 +10458,9 @@ process_arch_specific (FILE *file)
     case EM_MIPS_RS3_LE:
       return process_mips_specific (file);
       break;
+    case EM_PPC:
+      return process_power_specific (file);
+      break;
     default:
       break;
     }
@@ -9267,7 +10468,7 @@ process_arch_specific (FILE *file)
 }
 
 static int
-get_file_header (FILE *file)
+get_file_header (FILE * file)
 {
   /* Read in the identity array.  */
   if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1)
@@ -9356,8 +10557,6 @@ get_file_header (FILE *file)
        get_64bit_section_headers (file, 1);
     }
 
-  is_relocatable = elf_header.e_type == ET_REL;
-
   return 1;
 }
 
@@ -9366,7 +10565,7 @@ get_file_header (FILE *file)
    positioned at the start of the ELF object.  */
 
 static int
-process_object (char *file_name, FILE *file)
+process_object (char * file_name, FILE * file)
 {
   unsigned int i;
 
@@ -9377,10 +10576,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.  */
@@ -9392,16 +10591,17 @@ process_object (char *file_name, FILE *file)
      must make sure that the dump_sets array is zeroed out before each
      object file is processed.  */
   if (num_dump_sects > num_cmdline_dump_sects)
-    memset (dump_sects, 0, num_dump_sects);
+    memset (dump_sects, 0, num_dump_sects * sizeof (* dump_sects));
 
   if (num_cmdline_dump_sects > 0)
     {
       if (num_dump_sects == 0)
        /* A sneaky way of allocating the dump_sects array.  */
-       request_dump (num_cmdline_dump_sects, 0);
+       request_dump_bynumber (num_cmdline_dump_sects, 0);
 
       assert (num_dump_sects >= num_cmdline_dump_sects);
-      memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects);
+      memcpy (dump_sects, cmdline_dump_sects,
+             num_cmdline_dump_sects * sizeof (* dump_sects));
     }
 
   if (! process_file_header ())
@@ -9491,7 +10691,8 @@ process_object (char *file_name, FILE *file)
 
   if (section_groups)
     {
-      struct group_list *g, *next;
+      struct group_list * g;
+      struct group_list * next;
 
       for (i = 0; i < group_count; i++)
        {
@@ -9511,24 +10712,98 @@ process_object (char *file_name, FILE *file)
   return 0;
 }
 
-/* Process an ELF archive.  The file is positioned just after the
-   ARMAG string.  */
+/* Return the path name for a proxy entry in a thin archive, adjusted relative
+   to the path name of the thin archive itself if necessary.  Always returns
+   a pointer to malloc'ed memory.  */
+
+static char *
+adjust_relative_path (char * file_name, char * name, int name_len)
+{
+  char * member_file_name;
+  const char * base_name = lbasename (file_name);
+
+  /* This is a proxy entry for a thin archive member.
+     If the extended name table contains an absolute path
+     name, or if the archive is in the current directory,
+     use the path name as given.  Otherwise, we need to
+     find the member relative to the directory where the
+     archive is located.  */
+  if (IS_ABSOLUTE_PATH (name) || base_name == file_name)
+    {
+      member_file_name = malloc (name_len + 1);
+      if (member_file_name == NULL)
+        {
+          error (_("Out of memory\n"));
+          return NULL;
+        }
+      memcpy (member_file_name, name, name_len);
+      member_file_name[name_len] = '\0';
+    }
+  else
+    {
+      /* Concatenate the path components of the archive file name
+         to the relative path name from the extended name table.  */
+      size_t prefix_len = base_name - file_name;
+      member_file_name = malloc (prefix_len + name_len + 1);
+      if (member_file_name == NULL)
+        {
+          error (_("Out of memory\n"));
+          return NULL;
+        }
+      memcpy (member_file_name, file_name, prefix_len);
+      memcpy (member_file_name + prefix_len, name, name_len);
+      member_file_name[prefix_len + name_len] = '\0';
+    }
+  return member_file_name;
+}
+
+/* Structure to hold information about an archive file.  */
+
+struct archive_info
+{
+  char * file_name;                     /* Archive file name.  */
+  FILE * file;                          /* Open file descriptor.  */
+  unsigned long index_num;              /* Number of symbols in table.  */
+  unsigned long * index_array;          /* The array of member offsets.  */
+  char * sym_table;                     /* The symbol table.  */
+  unsigned long sym_size;               /* Size of the symbol table.  */
+  char * longnames;                     /* The long file names table.  */
+  unsigned long longnames_size;         /* Size of the long file names table.  */
+  unsigned long nested_member_origin;   /* Origin in the nested archive of the current member.  */
+  unsigned long next_arhdr_offset;      /* Offset of the next archive header.  */
+  bfd_boolean is_thin_archive;          /* TRUE if this is a thin archive.  */
+  struct ar_hdr arhdr;                  /* Current archive header.  */
+};
+
+/* Read the symbol table and long-name table from an archive.  */
 
 static int
-process_archive (char *file_name, FILE *file)
+setup_archive (struct archive_info * arch, char * file_name, FILE * file,
+               bfd_boolean is_thin_archive, bfd_boolean read_symbols)
 {
-  struct ar_hdr arhdr;
   size_t got;
   unsigned long size;
-  char *longnames = NULL;
-  unsigned long longnames_size = 0;
-  size_t file_name_size;
-  int ret;
-
-  show_name = 1;
 
-  got = fread (&arhdr, 1, sizeof arhdr, file);
-  if (got != sizeof arhdr)
+  arch->file_name = strdup (file_name);
+  arch->file = file;
+  arch->index_num = 0;
+  arch->index_array = NULL;
+  arch->sym_table = NULL;
+  arch->sym_size = 0;
+  arch->longnames = NULL;
+  arch->longnames_size = 0;
+  arch->nested_member_origin = 0;
+  arch->is_thin_archive = is_thin_archive;
+  arch->next_arhdr_offset = SARMAG;
+
+  /* Read the first archive member header.  */
+  if (fseek (file, SARMAG, SEEK_SET) != 0)
+    {
+      error (_("%s: failed to seek to first archive header\n"), file_name);
+      return 1;
+    }
+  got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
+  if (got != sizeof arch->arhdr)
     {
       if (got == 0)
        return 0;
@@ -9537,156 +10812,538 @@ process_archive (char *file_name, FILE *file)
       return 1;
     }
 
-  if (const_strneq (arhdr.ar_name, "/               "))
+  /* See if this is the archive symbol table.  */
+  if (const_strneq (arch->arhdr.ar_name, "/               ")
+      || const_strneq (arch->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 = strtoul (arch->arhdr.ar_size, NULL, 10);
+      size = size + (size & 1);
+
+      arch->next_arhdr_offset += sizeof arch->arhdr + size;
+
+      if (read_symbols)
        {
-         error (_("%s: failed to skip archive symbol table\n"), file_name);
-         return 1;
+         unsigned long i;
+         /* A buffer used to hold numbers read in from an archive index.
+            These are always 4 bytes long and stored in big-endian format.  */
+#define SIZEOF_AR_INDEX_NUMBERS 4
+         unsigned char integer_buffer[SIZEOF_AR_INDEX_NUMBERS];
+         unsigned char * index_buffer;
+
+         /* Check the size of the archive index.  */
+         if (size < SIZEOF_AR_INDEX_NUMBERS)
+           {
+             error (_("%s: the archive index is empty\n"), file_name);
+             return 1;
+           }
+
+         /* Read the numer of entries in the archive index.  */
+         got = fread (integer_buffer, 1, sizeof integer_buffer, file);
+         if (got != sizeof (integer_buffer))
+           {
+             error (_("%s: failed to read archive index\n"), file_name);
+             return 1;
+           }
+         arch->index_num = byte_get_big_endian (integer_buffer, sizeof integer_buffer);
+         size -= SIZEOF_AR_INDEX_NUMBERS;
+
+         /* Read in the archive index.  */
+         if (size < arch->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, arch->index_num);
+             return 1;
+           }
+         index_buffer = malloc (arch->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, arch->index_num, file);
+         if (got != arch->index_num)
+           {
+             free (index_buffer);
+             error (_("%s: failed to read archive index\n"), file_name);
+             return 1;
+           }
+         size -= arch->index_num * SIZEOF_AR_INDEX_NUMBERS;
+
+         /* Convert the index numbers into the host's numeric format.  */
+         arch->index_array = malloc (arch->index_num * sizeof (* arch->index_array));
+         if (arch->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 < arch->index_num; i++)
+           arch->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);
+             return 1;
+           }
+         arch->sym_table = malloc (size);
+         arch->sym_size = size;
+         if (arch->sym_table == NULL)
+           {
+             error (_("Out of memory whilst trying to read archive index symbol table\n"));
+             return 1;
+           }
+         got = fread (arch->sym_table, 1, size, file);
+         if (got != size)
+           {
+             error (_("%s: failed to read archive index symbol table\n"), file_name);
+             return 1;
+           }
+       }
+      else
+       {
+         if (fseek (file, size, SEEK_CUR) != 0)
+           {
+             error (_("%s: failed to skip archive symbol table\n"), file_name);
+             return 1;
+           }
        }
 
-      got = fread (&arhdr, 1, sizeof arhdr, file);
-      if (got != sizeof arhdr)
+      /* Read the next archive header.  */
+      got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
+      if (got != sizeof arch->arhdr)
        {
          if (got == 0)
-           return 0;
-
-         error (_("%s: failed to read archive header\n"), file_name);
+            return 0;
+         error (_("%s: failed to read archive header following archive index\n"), file_name);
          return 1;
        }
     }
+  else if (read_symbols)
+    printf (_("%s has no archive index\n"), file_name);
 
-  if (const_strneq (arhdr.ar_name, "//              "))
+  if (const_strneq (arch->arhdr.ar_name, "//              "))
     {
-      /* This is the archive string table holding long member
-        names.  */
+      /* This is the archive string table holding long member names.  */
+      arch->longnames_size = strtoul (arch->arhdr.ar_size, NULL, 10);
+      arch->next_arhdr_offset += sizeof arch->arhdr + arch->longnames_size;
 
-      longnames_size = strtoul (arhdr.ar_size, NULL, 10);
-
-      longnames = malloc (longnames_size);
-      if (longnames == NULL)
+      arch->longnames = malloc (arch->longnames_size);
+      if (arch->longnames == NULL)
        {
-         error (_("Out of memory\n"));
+         error (_("Out of memory reading long symbol names in archive\n"));
          return 1;
        }
 
-      if (fread (longnames, longnames_size, 1, file) != 1)
+      if (fread (arch->longnames, arch->longnames_size, 1, file) != 1)
        {
-         free (longnames);
-         error (_("%s: failed to read string table\n"), file_name);
+         free (arch->longnames);
+         arch->longnames = NULL;
+         error (_("%s: failed to read long symbol name string table\n"), file_name);
          return 1;
        }
 
-      if ((longnames_size & 1) != 0)
+      if ((arch->longnames_size & 1) != 0)
        getc (file);
+    }
 
-      got = fread (&arhdr, 1, sizeof arhdr, file);
-      if (got != sizeof arhdr)
-       {
-         free (longnames);
+  return 0;
+}
 
-         if (got == 0)
-           return 0;
+/* Release the memory used for the archive information.  */
 
-         error (_("%s: failed to read archive header\n"), file_name);
-         return 1;
-       }
+static void
+release_archive (struct archive_info * arch)
+{
+  if (arch->file_name != NULL)
+    free (arch->file_name);
+  if (arch->index_array != NULL)
+    free (arch->index_array);
+  if (arch->sym_table != NULL)
+    free (arch->sym_table);
+  if (arch->longnames != NULL)
+    free (arch->longnames);
+}
+
+/* Open and setup a nested archive, if not already open.  */
+
+static int
+setup_nested_archive (struct archive_info * nested_arch, char * member_file_name)
+{
+  FILE * member_file;
+
+  /* Have we already setup this archive?  */
+  if (nested_arch->file_name != NULL
+      && streq (nested_arch->file_name, member_file_name))
+    return 0;
+
+  /* Close previous file and discard cached information.  */
+  if (nested_arch->file != NULL)
+    fclose (nested_arch->file);
+  release_archive (nested_arch);
+
+  member_file = fopen (member_file_name, "rb");
+  if (member_file == NULL)
+    return 1;
+  return setup_archive (nested_arch, member_file_name, member_file, FALSE, FALSE);
+}
+
+static char *
+get_archive_member_name_at (struct archive_info *  arch,
+                           unsigned long          offset,
+                           struct archive_info *  nested_arch);
+
+/* Get the name of an archive member from the current archive header.
+   For simple names, this will modify the ar_name field of the current
+   archive header.  For long names, it will return a pointer to the
+   longnames table.  For nested archives, it will open the nested archive
+   and get the name recursively.  NESTED_ARCH is a single-entry cache so
+   we don't keep rereading the same information from a nested archive.  */
+
+static char *
+get_archive_member_name (struct archive_info *  arch,
+                         struct archive_info *  nested_arch)
+{
+  unsigned long j, k;
+
+  if (arch->arhdr.ar_name[0] == '/')
+    {
+      /* We have a long name.  */
+      char * endp;
+      char * member_file_name;
+      char * member_name;
+
+      arch->nested_member_origin = 0;
+      k = j = strtoul (arch->arhdr.ar_name + 1, &endp, 10);
+      if (arch->is_thin_archive && endp != NULL && * endp == ':')
+        arch->nested_member_origin = strtoul (endp + 1, NULL, 10);
+
+      while ((j < arch->longnames_size)
+             && (arch->longnames[j] != '\n')
+             && (arch->longnames[j] != '\0'))
+        j++;
+      if (arch->longnames[j-1] == '/')
+        j--;
+      arch->longnames[j] = '\0';
+
+      if (!arch->is_thin_archive || arch->nested_member_origin == 0)
+        return arch->longnames + k;
+
+      /* This is a proxy for a member of a nested archive.
+         Find the name of the member in that archive.  */
+      member_file_name = adjust_relative_path (arch->file_name, arch->longnames + k, j - k);
+      if (member_file_name != NULL
+          && setup_nested_archive (nested_arch, member_file_name) == 0
+          && (member_name = get_archive_member_name_at (nested_arch, arch->nested_member_origin, NULL)) != NULL)
+        {
+          free (member_file_name);
+          return member_name;
+        }
+      free (member_file_name);
+
+      /* Last resort: just return the name of the nested archive.  */
+      return arch->longnames + k;
+    }
+
+  /* We have a normal (short) name.  */
+  j = 0;
+  while ((arch->arhdr.ar_name[j] != '/') && (j < 16))
+    j++;
+  arch->arhdr.ar_name[j] = '\0';
+  return arch->arhdr.ar_name;
+}
+
+/* Get the name of an archive member at a given OFFSET within an archive ARCH.  */
+
+static char *
+get_archive_member_name_at (struct archive_info * arch,
+                            unsigned long         offset,
+                           struct archive_info * nested_arch)
+{
+  size_t got;
+
+  if (fseek (arch->file, offset, SEEK_SET) != 0)
+    {
+      error (_("%s: failed to seek to next file name\n"), arch->file_name);
+      return NULL;
+    }
+  got = fread (&arch->arhdr, 1, sizeof arch->arhdr, arch->file);
+  if (got != sizeof arch->arhdr)
+    {
+      error (_("%s: failed to read archive header\n"), arch->file_name);
+      return NULL;
+    }
+  if (memcmp (arch->arhdr.ar_fmag, ARFMAG, 2) != 0)
+    {
+      error (_("%s: did not find a valid archive header\n"), arch->file_name);
+      return NULL;
     }
 
-  file_name_size = strlen (file_name);
-  ret = 0;
+  return get_archive_member_name (arch, nested_arch);
+}
 
-  while (1)
+/* Construct a string showing the name of the archive member, qualified
+   with the name of the containing archive file.  For thin archives, we
+   use square brackets to denote the indirection.  For nested archives,
+   we show the qualified name of the external member inside the square
+   brackets (e.g., "thin.a[normal.a(foo.o)]").  */
+
+static char *
+make_qualified_name (struct archive_info * arch,
+                     struct archive_info * nested_arch,
+                     char * member_name)
+{
+  size_t len;
+  char * name;
+
+  len = strlen (arch->file_name) + strlen (member_name) + 3;
+  if (arch->is_thin_archive && arch->nested_member_origin != 0)
+    len += strlen (nested_arch->file_name) + 2;
+
+  name = malloc (len);
+  if (name == NULL)
+    {
+      error (_("Out of memory\n"));
+      return NULL;
+    }
+
+  if (arch->is_thin_archive && arch->nested_member_origin != 0)
+    snprintf (name, len, "%s[%s(%s)]", arch->file_name, nested_arch->file_name, member_name);
+  else if (arch->is_thin_archive)
+    snprintf (name, len, "%s[%s]", arch->file_name, member_name);
+  else
+    snprintf (name, len, "%s(%s)", arch->file_name, member_name);
+
+  return name;
+}
+
+/* Process an ELF archive.
+   On entry the file is positioned just after the ARMAG string.  */
+
+static int
+process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive)
+{
+  struct archive_info arch;
+  struct archive_info nested_arch;
+  size_t got;
+  size_t file_name_size;
+  int ret;
+
+  show_name = 1;
+
+  /* The ARCH structure is used to hold information about this archive.  */
+  arch.file_name = NULL;
+  arch.file = NULL;
+  arch.index_array = NULL;
+  arch.sym_table = NULL;
+  arch.longnames = NULL;
+
+  /* The NESTED_ARCH structure is used as a single-item cache of information
+     about a nested archive (when members of a thin archive reside within
+     another regular archive file).  */
+  nested_arch.file_name = NULL;
+  nested_arch.file = NULL;
+  nested_arch.index_array = NULL;
+  nested_arch.sym_table = NULL;
+  nested_arch.longnames = NULL;
+
+  if (setup_archive (&arch, file_name, file, is_thin_archive, do_archive_index) != 0)
     {
-      char *name;
-      char *nameend;
-      char *namealc;
+      ret = 1;
+      goto out;
+    }
 
-      if (arhdr.ar_name[0] == '/')
+  if (do_archive_index)
+    {
+      if (arch.sym_table == NULL)
+       error (_("%s: unable to dump the index as none was found\n"), file_name);
+      else
        {
-         unsigned long off;
+         unsigned int i, l;
+         unsigned long current_pos;
 
-         off = strtoul (arhdr.ar_name + 1, NULL, 10);
-         if (off >= longnames_size)
+         printf (_("Index of archive %s: (%ld entries, 0x%lx bytes in the symbol table)\n"),
+                 file_name, arch.index_num, arch.sym_size);
+         current_pos = ftell (file);
+
+         for (i = l = 0; i < arch.index_num; i++)
            {
-             error (_("%s: invalid archive string table offset %lu\n"), file_name, off);
-             ret = 1;
-             break;
+             if ((i == 0) || ((i > 0) && (arch.index_array[i] != arch.index_array[i - 1])))
+               {
+                 char * member_name;
+
+                 member_name = get_archive_member_name_at (&arch, arch.index_array[i], &nested_arch);
+
+                  if (member_name != NULL)
+                    {
+                     char * qualified_name = make_qualified_name (&arch, &nested_arch, member_name);
+
+                      if (qualified_name != NULL)
+                        {
+                         printf (_("Binary %s contains:\n"), qualified_name);
+                         free (qualified_name);
+                       }
+                   }
+               }
+
+             if (l >= arch.sym_size)
+               {
+                 error (_("%s: end of the symbol table reached before the end of the index\n"),
+                        file_name);
+                 break;
+               }
+             printf ("\t%s\n", arch.sym_table + l);
+             l += strlen (arch.sym_table + l) + 1;
            }
 
-         name = longnames + off;
-         nameend = memchr (name, '/', longnames_size - off);
+          if (l & 01)
+            ++l;
+         if (l < arch.sym_size)
+           error (_("%s: symbols remain in the index symbol table, but without corresponding entries in the index table\n"),
+                  file_name);
+
+         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);
+             ret = 1;
+             goto out;
+           }
        }
-      else
+
+      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)
        {
-         name = arhdr.ar_name;
-         nameend = memchr (name, '/', 16);
+         ret = 0; /* Archive index only.  */
+         goto out;
        }
+    }
+
+  file_name_size = strlen (file_name);
+  ret = 0;
 
-      if (nameend == NULL)
+  while (1)
+    {
+      char * name;
+      size_t namelen;
+      char * qualified_name;
+
+      /* Read the next archive header.  */
+      if (fseek (file, arch.next_arhdr_offset, SEEK_SET) != 0)
+        {
+          error (_("%s: failed to seek to next archive header\n"), file_name);
+          return 1;
+        }
+      got = fread (&arch.arhdr, 1, sizeof arch.arhdr, file);
+      if (got != sizeof arch.arhdr)
+        {
+          if (got == 0)
+           break;
+          error (_("%s: failed to read archive header\n"), file_name);
+          ret = 1;
+          break;
+        }
+      if (memcmp (arch.arhdr.ar_fmag, ARFMAG, 2) != 0)
+        {
+          error (_("%s: did not find a valid archive header\n"), arch.file_name);
+          ret = 1;
+          break;
+        }
+
+      arch.next_arhdr_offset += sizeof arch.arhdr;
+
+      archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10);
+      if (archive_file_size & 01)
+        ++archive_file_size;
+
+      name = get_archive_member_name (&arch, &nested_arch);
+      if (name == NULL)
        {
          error (_("%s: bad archive file name\n"), file_name);
          ret = 1;
          break;
        }
+      namelen = strlen (name);
 
-      namealc = malloc (file_name_size + (nameend - name) + 3);
-      if (namealc == NULL)
+      qualified_name = make_qualified_name (&arch, &nested_arch, name);
+      if (qualified_name == NULL)
        {
-         error (_("Out of memory\n"));
+         error (_("%s: bad archive file name\n"), file_name);
          ret = 1;
          break;
        }
 
-      memcpy (namealc, file_name, file_name_size);
-      namealc[file_name_size] = '(';
-      memcpy (namealc + file_name_size + 1, name, nameend - name);
-      namealc[file_name_size + 1 + (nameend - name)] = ')';
-      namealc[file_name_size + 2 + (nameend - name)] = '\0';
-
-      archive_file_offset = ftell (file);
-      archive_file_size = strtoul (arhdr.ar_size, NULL, 10);
-
-      ret |= process_object (namealc, file);
-
-      free (namealc);
-
-      if (fseek (file,
-                (archive_file_offset
-                 + archive_file_size
-                 + (archive_file_size & 1)),
-                SEEK_SET) != 0)
-       {
-         error (_("%s: failed to seek to next archive header\n"), file_name);
-         ret = 1;
-         break;
-       }
+      if (is_thin_archive && arch.nested_member_origin == 0)
+        {
+          /* This is a proxy for an external member of a thin archive.  */
+          FILE * member_file;
+          char * member_file_name = adjust_relative_path (file_name, name, namelen);
+          if (member_file_name == NULL)
+            {
+              ret = 1;
+              break;
+            }
+
+          member_file = fopen (member_file_name, "rb");
+          if (member_file == NULL)
+            {
+              error (_("Input file '%s' is not readable.\n"), member_file_name);
+              free (member_file_name);
+              ret = 1;
+              break;
+            }
+
+          archive_file_offset = arch.nested_member_origin;
+
+          ret |= process_object (qualified_name, member_file);
+
+          fclose (member_file);
+          free (member_file_name);
+        }
+      else if (is_thin_archive)
+        {
+          /* This is a proxy for a member of a nested archive.  */
+          archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr;
+
+          /* The nested archive file will have been opened and setup by
+             get_archive_member_name.  */
+          if (fseek (nested_arch.file, archive_file_offset, SEEK_SET) != 0)
+            {
+              error (_("%s: failed to seek to archive member.\n"), nested_arch.file_name);
+              ret = 1;
+              break;
+            }
+
+          ret |= process_object (qualified_name, nested_arch.file);
+        }
+      else
+        {
+          archive_file_offset = arch.next_arhdr_offset;
+          arch.next_arhdr_offset += archive_file_size;
 
-      got = fread (&arhdr, 1, sizeof arhdr, file);
-      if (got != sizeof arhdr)
-       {
-         if (got == 0)
-           break;
+          ret |= process_object (qualified_name, file);
+        }
 
-         error (_("%s: failed to read archive header\n"), file_name);
-         ret = 1;
-         break;
-       }
+      free (qualified_name);
     }
 
-  if (longnames != 0)
-    free (longnames);
+ out:
+  if (nested_arch.file != NULL)
+    fclose (nested_arch.file);
+  release_archive (&nested_arch);
+  release_archive (&arch);
 
   return ret;
 }
 
 static int
-process_file (char *file_name)
+process_file (char * file_name)
 {
-  FILE *file;
+  FILE * file;
   struct stat statbuf;
   char armag[SARMAG];
   int ret;
@@ -9716,15 +11373,21 @@ 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;
     }
 
   if (memcmp (armag, ARMAG, SARMAG) == 0)
-    ret = process_archive (file_name, file);
+    ret = process_archive (file_name, file, FALSE);
+  else if (memcmp (armag, ARMAGT, SARMAG) == 0)
+    ret = process_archive (file_name, file, TRUE);
   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);
@@ -9741,7 +11404,7 @@ process_file (char *file_name)
    symbols.  */
 
 void
-print_address (unsigned int addr, FILE *outfile)
+print_address (unsigned int addr, FILE * outfile)
 {
   fprintf (outfile,"0x%8.8x", addr);
 }
@@ -9755,7 +11418,7 @@ db_task_printsym (unsigned int addr)
 #endif
 
 int
-main (int argc, char **argv)
+main (int argc, char ** argv)
 {
   int err;
 
@@ -9775,12 +11438,13 @@ main (int argc, char **argv)
   if (num_dump_sects > 0)
     {
       /* Make a copy of the dump_sects array.  */
-      cmdline_dump_sects = malloc (num_dump_sects);
+      cmdline_dump_sects = malloc (num_dump_sects * sizeof (* dump_sects));
       if (cmdline_dump_sects == NULL)
        error (_("Out of memory allocating dump request table.\n"));
       else
        {
-         memcpy (cmdline_dump_sects, dump_sects, num_dump_sects);
+         memcpy (cmdline_dump_sects, dump_sects,
+                 num_dump_sects * sizeof (* dump_sects));
          num_cmdline_dump_sects = num_dump_sects;
        }
     }
This page took 0.159215 seconds and 4 git commands to generate.