Add ld_list_options
[deliverable/binutils-gdb.git] / binutils / readelf.c
index 63ab14b0958024428d4ad4b98f78d28f819d2f46..fea372fd4bb449b98595a412d56bd2db724b5005 100644 (file)
@@ -1,7 +1,5 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 1998-2015 Free Software Foundation, Inc.
 
    Originally developed by Eric Youngdale <eric@andante.jic.com>
    Modifications by Nick Clifton <nickc@redhat.com>
@@ -45,9 +43,7 @@
 #include "sysdep.h"
 #include <assert.h>
 #include <time.h>
-#ifdef HAVE_ZLIB_H
 #include <zlib.h>
-#endif
 #ifdef HAVE_WCHAR_H
 #include <wchar.h>
 #endif
 #include "elf/epiphany.h"
 #include "elf/fr30.h"
 #include "elf/frv.h"
+#include "elf/ft32.h"
 #include "elf/h8.h"
 #include "elf/hppa.h"
 #include "elf/i386.h"
 #include "elf/m68hc11.h"
 #include "elf/mcore.h"
 #include "elf/mep.h"
+#include "elf/metag.h"
 #include "elf/microblaze.h"
 #include "elf/mips.h"
 #include "elf/mmix.h"
 #include "elf/moxie.h"
 #include "elf/mt.h"
 #include "elf/msp430.h"
-#include "elf/or32.h"
+#include "elf/nds32.h"
+#include "elf/nios2.h"
+#include "elf/or1k.h"
 #include "elf/pj.h"
 #include "elf/ppc.h"
 #include "elf/ppc64.h"
 #include "elf/tilepro.h"
 #include "elf/v850.h"
 #include "elf/vax.h"
+#include "elf/visium.h"
 #include "elf/x86-64.h"
 #include "elf/xc16x.h"
 #include "elf/xgate.h"
 #include "safe-ctype.h"
 #include "filenames.h"
 
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE *) 0)->MEMBER))
+#endif
+
 char * program_name = "readelf";
-static long archive_file_offset;
+static unsigned long archive_file_offset;
 static unsigned long archive_file_size;
+static bfd_size_type current_file_size;
 static unsigned long dynamic_addr;
 static bfd_size_type dynamic_size;
-static unsigned int dynamic_nent;
+static size_t dynamic_nent;
 static char * dynamic_strings;
 static unsigned long dynamic_strings_length;
 static char * string_table;
@@ -266,6 +272,20 @@ typedef enum print_mode
 }
 print_mode;
 
+/* Versioned symbol info.  */
+enum versioned_symbol_info
+{
+  symbol_undefined,
+  symbol_hidden,
+  symbol_public
+};
+
+static const char *get_symbol_version_string
+  (FILE *file, int is_dynsym, const char *strtab,
+   unsigned long int strtab_size, unsigned int si,
+   Elf_Internal_Sym *psym, enum versioned_symbol_info *sym_info,
+   unsigned short *vna_other);
+
 #define UNKNOWN -1
 
 #define SECTION_NAME(X)                                                \
@@ -293,25 +313,62 @@ print_mode;
     }                                          \
   while (0)
 \f
-/* Retrieve NMEMB structures, each SIZE bytes long from FILE starting at OFFSET.
+/* Retrieve NMEMB structures, each SIZE bytes long from FILE starting at OFFSET +
+   the offset of the current archive member, if we are examining an archive.
    Put the retrieved data into VAR, if it is not NULL.  Otherwise allocate a buffer
    using malloc and fill that.  In either case return the pointer to the start of
    the retrieved data or NULL if something went wrong.  If something does go wrong
-   emit an error message using REASON as part of the context.  */
+   and REASON is not NULL then emit an error message using REASON as part of the
+   context.  */
 
 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, unsigned long offset, bfd_size_type size,
+         bfd_size_type nmemb, const char * reason)
 {
   void * mvar;
+  bfd_size_type amt = size * nmemb;
 
   if (size == 0 || nmemb == 0)
     return NULL;
 
+  /* If the size_t type is smaller than the bfd_size_type, eg because
+     you are building a 32-bit tool on a 64-bit host, then make sure
+     that when the sizes are cast to (size_t) no information is lost.  */
+  if (sizeof (size_t) < sizeof (bfd_size_type)
+      && (   (bfd_size_type) ((size_t) size) != size
+         || (bfd_size_type) ((size_t) nmemb) != nmemb))
+    {
+      if (reason)
+       error (_("Size truncation prevents reading 0x%llx elements of size 0x%llx for %s\n"),
+              (unsigned long long) nmemb, (unsigned long long) size, reason);
+      return NULL;
+    }
+
+  /* Check for size overflow.  */
+  if (amt < nmemb)
+    {
+      if (reason)
+       error (_("Size overflow prevents reading 0x%llx elements of size 0x%llx for %s\n"),
+              (unsigned long long) nmemb, (unsigned long long) size, reason);
+      return NULL;
+    }
+
+  /* Be kind to memory chekers (eg valgrind, address sanitizer) by not
+     attempting to allocate memory when the read is bound to fail.  */
+  if (amt > current_file_size
+      || offset + archive_file_offset + amt > current_file_size)
+    {
+      if (reason)
+       error (_("Reading 0x%llx bytes extends past end of file for %s\n"),
+              (unsigned long long) amt, reason);
+      return NULL;
+    }
+
   if (fseek (file, archive_file_offset + offset, SEEK_SET))
     {
-      error (_("Unable to seek to 0x%lx for %s\n"),
-            (unsigned long) archive_file_offset + offset, reason);
+      if (reason)
+       error (_("Unable to seek to 0x%lx for %s\n"),
+              (unsigned long) archive_file_offset + offset, reason);
       return NULL;
     }
 
@@ -319,24 +376,26 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
   if (mvar == NULL)
     {
       /* Check for overflow.  */
-      if (nmemb < (~(size_t) 0 - 1) / size)
+      if (nmemb < (~(bfd_size_type) 0 - 1) / size)
        /* + 1 so that we can '\0' terminate invalid string table sections.  */
-       mvar = malloc (size * nmemb + 1);
+       mvar = malloc ((size_t) amt + 1);
 
       if (mvar == NULL)
        {
-         error (_("Out of memory allocating 0x%lx bytes for %s\n"),
-                (unsigned long)(size * nmemb), reason);
+         if (reason)
+           error (_("Out of memory allocating 0x%llx bytes for %s\n"),
+                  (unsigned long long) amt, reason);
          return NULL;
        }
 
-      ((char *) mvar)[size * nmemb] = '\0';
+      ((char *) mvar)[amt] = '\0';
     }
 
-  if (fread (mvar, size, nmemb, file) != nmemb)
+  if (fread (mvar, (size_t) size, (size_t) nmemb, file) != nmemb)
     {
-      error (_("Unable to read in 0x%lx bytes of %s\n"),
-            (unsigned long)(size * nmemb), reason);
+      if (reason)
+       error (_("Unable to read in 0x%llx bytes of %s\n"),
+              (unsigned long long) amt, reason);
       if (mvar != var)
        free (mvar);
       return NULL;
@@ -412,7 +471,8 @@ print_symbol (int width, const char *symbol)
       /* Keep the width positive.  This also helps.  */
       width = - width;
       extra_padding = TRUE;
-    }  
+    }
+  assert (width != 0);
 
   if (do_wide)
     /* Set the remaining width to a very large value.
@@ -485,6 +545,66 @@ print_symbol (int width, const char *symbol)
   return num_printed;
 }
 
+/* Returns a pointer to a static buffer containing a  printable version of
+   the given section's name.  Like print_symbol, except that it does not try
+   to print multibyte characters, it just interprets them as hex values.  */
+
+static const char *
+printable_section_name (Elf_Internal_Shdr * sec)
+{
+#define MAX_PRINT_SEC_NAME_LEN 128
+  static char  sec_name_buf [MAX_PRINT_SEC_NAME_LEN + 1];
+  const char * name = SECTION_NAME (sec);
+  char *       buf = sec_name_buf;
+  char         c;
+  unsigned int remaining = MAX_PRINT_SEC_NAME_LEN;
+
+  while ((c = * name ++) != 0)
+    {
+      if (ISCNTRL (c))
+       {
+         if (remaining < 2)
+           break;
+
+         * buf ++ = '^';
+         * buf ++ = c + 0x40;
+         remaining -= 2;
+       }
+      else if (ISPRINT (c))
+       {
+         * buf ++ = c;
+         remaining -= 1;
+       }
+      else
+       {
+         static char hex[17] = "0123456789ABCDEF";
+
+         if (remaining < 4)
+           break;
+         * buf ++ = '<';
+         * buf ++ = hex[(c & 0xf0) >> 4];
+         * buf ++ = hex[c & 0x0f];
+         * buf ++ = '>';
+         remaining -= 4;
+       }
+
+      if (remaining == 0)
+       break;
+    }
+
+  * buf = 0;
+  return sec_name_buf;
+}
+
+static const char *
+printable_section_name_from_index (unsigned long ndx)
+{
+  if (ndx >= elf_header.e_shnum)
+    return _("<corrupt>");
+
+  return printable_section_name (section_headers + ndx);
+}
+
 /* Return a pointer to section NAME, or NULL if no such section exists.  */
 
 static Elf_Internal_Shdr *
@@ -517,6 +637,21 @@ find_section_by_address (bfd_vma addr)
   return NULL;
 }
 
+static Elf_Internal_Shdr *
+find_section_by_type (unsigned int type)
+{
+  unsigned int i;
+
+  for (i = 0; i < elf_header.e_shnum; i++)
+    {
+      Elf_Internal_Shdr *sec = section_headers + i;
+      if (sec->sh_type == type)
+       return sec;
+    }
+
+  return NULL;
+}
+
 /* Return a pointer to section NAME, or NULL if no such section exists,
    restricted to the list of sections given in SET.  */
 
@@ -538,10 +673,12 @@ find_section_in_set (const char * name, unsigned int * set)
 /* Read an unsigned LEB128 encoded value from p.  Set *PLEN to the number of
    bytes read.  */
 
-static unsigned long
-read_uleb128 (unsigned char *data, unsigned int *length_return)
+static inline unsigned long
+read_uleb128 (unsigned char *data,
+             unsigned int *length_return,
+             const unsigned char * const end)
 {
-  return read_leb128 (data, length_return, 0);
+  return read_leb128 (data, length_return, FALSE, end);
 }
 
 /* Return true if the current file is for IA-64 machine and OpenVMS ABI.
@@ -573,8 +710,6 @@ guess_is_rela (unsigned int e_machine)
     case EM_MIPS:
     case EM_MIPS_RS3_LE:
     case EM_CYGNUS_M32R:
-    case EM_OPENRISC:
-    case EM_OR32:
     case EM_SCORE:
     case EM_XGATE:
       return FALSE;
@@ -595,6 +730,7 @@ guess_is_rela (unsigned int e_machine)
     case EM_D30V:
     case EM_CYGNUS_D30V:
     case EM_FR30:
+    case EM_FT32:
     case EM_CYGNUS_FR30:
     case EM_CYGNUS_FRV:
     case EM_H8S:
@@ -610,6 +746,7 @@ guess_is_rela (unsigned int e_machine)
     case EM_M32R:
     case EM_MCORE:
     case EM_CYGNUS_MEP:
+    case EM_METAG:
     case EM_MMIX:
     case EM_MN10200:
     case EM_CYGNUS_MN10200:
@@ -619,7 +756,9 @@ guess_is_rela (unsigned int e_machine)
     case EM_MSP430:
     case EM_MSP430_OLD:
     case EM_MT:
+    case EM_NDS32:
     case EM_NIOS32:
+    case EM_OR1K:
     case EM_PPC64:
     case EM_PPC:
     case EM_RL78:
@@ -634,9 +773,11 @@ guess_is_rela (unsigned int e_machine)
     case EM_TI_C6000:
     case EM_TILEGX:
     case EM_TILEPRO:
+    case EM_V800:
     case EM_V850:
     case EM_CYGNUS_V850:
     case EM_VAX:
+    case EM_VISIUM:
     case EM_X86_64:
     case EM_L1OM:
     case EM_K1OM:
@@ -678,7 +819,7 @@ slurp_rela_relocs (FILE * file,
                   unsigned long * nrelasp)
 {
   Elf_Internal_Rela * relas;
-  unsigned long nrelas;
+  size_t nrelas;
   unsigned int i;
 
   if (is_32bit_elf)
@@ -776,7 +917,7 @@ slurp_rel_relocs (FILE * file,
                  unsigned long * nrelsp)
 {
   Elf_Internal_Rela * rels;
-  unsigned long nrels;
+  size_t nrels;
   unsigned int i;
 
   if (is_32bit_elf)
@@ -894,6 +1035,17 @@ get_reloc_symindex (bfd_vma reloc_info)
   return is_32bit_elf ? ELF32_R_SYM (reloc_info) : ELF64_R_SYM (reloc_info);
 }
 
+static inline bfd_boolean
+uses_msp430x_relocs (void)
+{
+  return
+    elf_header.e_machine == EM_MSP430 /* Paranoia.  */
+    /* GCC uses osabi == ELFOSBI_STANDALONE.  */
+    && (((elf_header.e_flags & EF_MSP430_MACH) == E_MSP430_MACH_MSP430X)
+       /* TI compiler uses ELFOSABI_NONE.  */
+       || (elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE));
+}
+
 /* Display the contents of the relocation data found at the specified
    offset.  */
 
@@ -905,7 +1057,8 @@ dump_relocations (FILE * file,
                  unsigned long nsyms,
                  char * strtab,
                  unsigned long strtablen,
-                 int is_rela)
+                 int is_rela,
+                 int is_dynsym)
 {
   unsigned int i;
   Elf_Internal_Rela * rels;
@@ -1058,6 +1211,9 @@ dump_relocations (FILE * file,
          rtype = elf_spu_reloc_type (type);
          break;
 
+       case EM_V800:
+         rtype = v800_reloc_type (type);
+         break;
        case EM_V850:
        case EM_CYGNUS_V850:
          rtype = v850_reloc_type (type);
@@ -1100,6 +1256,10 @@ dump_relocations (FILE * file,
          rtype = elf_frv_reloc_type (type);
          break;
 
+       case EM_FT32:
+         rtype = elf_ft32_reloc_type (type);
+         break;
+
        case EM_MCORE:
          rtype = elf_mcore_reloc_type (type);
          break;
@@ -1113,10 +1273,19 @@ dump_relocations (FILE * file,
          break;
 
        case EM_MSP430:
+         if (uses_msp430x_relocs ())
+           {
+             rtype = elf_msp430x_reloc_type (type);
+             break;
+           }
        case EM_MSP430_OLD:
          rtype = elf_msp430_reloc_type (type);
          break;
 
+       case EM_NDS32:
+         rtype = elf_nds32_reloc_type (type);
+         break;
+
        case EM_PPC:
          rtype = elf_ppc_reloc_type (type);
          break;
@@ -1152,9 +1321,8 @@ dump_relocations (FILE * file,
          rtype = elf_h8_reloc_type (type);
          break;
 
-       case EM_OPENRISC:
-       case EM_OR32:
-         rtype = elf_or32_reloc_type (type);
+       case EM_OR1K:
+         rtype = elf_or1k_reloc_type (type);
          break;
 
        case EM_PJ:
@@ -1204,6 +1372,10 @@ dump_relocations (FILE * file,
          rtype = elf_vax_reloc_type (type);
          break;
 
+       case EM_VISIUM:
+         rtype = elf_visium_reloc_type (type);
+         break;
+
        case EM_ADAPTEVA_EPIPHANY:
          rtype = elf_epiphany_reloc_type (type);
          break;
@@ -1260,6 +1432,10 @@ dump_relocations (FILE * file,
          rtype = elf_rx_reloc_type (type);
          break;
 
+       case EM_METAG:
+         rtype = elf_metag_reloc_type (type);
+         break;
+
        case EM_XC16X:
        case EM_C166:
          rtype = elf_xc16x_reloc_type (type);
@@ -1280,6 +1456,10 @@ dump_relocations (FILE * file,
        case EM_XGATE:
          rtype = elf_xgate_reloc_type (type);
          break;
+
+       case EM_ALTERA_NIOS2:
+         rtype = elf_nios2_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1319,9 +1499,20 @@ dump_relocations (FILE * file,
          else
            {
              Elf_Internal_Sym * psym;
+             const char * version_string;
+             enum versioned_symbol_info sym_info;
+             unsigned short vna_other;
 
              psym = symtab + symtab_index;
 
+             version_string
+               = get_symbol_version_string (file, is_dynsym,
+                                            strtab, strtablen,
+                                            symtab_index,
+                                            psym,
+                                            &sym_info,
+                                            &vna_other);
+
              printf (" ");
 
              if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
@@ -1348,6 +1539,9 @@ dump_relocations (FILE * file,
                    name = strtab + psym->st_name;
 
                  len = print_symbol (width, name);
+                 if (version_string)
+                   printf (sym_info == symbol_public ? "@@%s" : "@%s",
+                           version_string);
                  printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
                }
              else
@@ -1365,8 +1559,7 @@ dump_relocations (FILE * file,
                  if (ELF_ST_TYPE (psym->st_info) == STT_SECTION)
                    {
                      if (psym->st_shndx < elf_header.e_shnum)
-                       sec_name
-                         = SECTION_NAME (section_headers + psym->st_shndx);
+                       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)
@@ -1405,13 +1598,21 @@ dump_relocations (FILE * file,
              else if (psym->st_name >= strtablen)
                printf (_("<corrupt string table index: %3ld>"), psym->st_name);
              else
-               print_symbol (22, strtab + psym->st_name);
+               {
+                 print_symbol (22, strtab + psym->st_name);
+                 if (version_string)
+                   printf (sym_info == symbol_public ? "@@%s" : "@%s",
+                           version_string);
+               }
 
              if (is_rela)
                {
                  bfd_signed_vma off = rels[i].r_addend;
 
-                 if (off < 0)
+                 /* PR 17531: file: 2e63226f.  */
+                 if (off == ((bfd_signed_vma) 1) << ((sizeof (bfd_signed_vma) * 8) - 1))
+                   printf (" + %" BFD_VMA_FMT "x", off);
+                 else if (off < 0)
                    printf (" - %" BFD_VMA_FMT "x", - off);
                  else
                    printf (" + %" BFD_VMA_FMT "x", off);
@@ -1423,7 +1624,10 @@ dump_relocations (FILE * file,
          bfd_signed_vma off = rels[i].r_addend;
 
          printf ("%*c", is_32bit_elf ? 12 : 20, ' ');
-         if (off < 0)
+         /* PR 17531: file: 2e63226f.  */
+         if (off == ((bfd_signed_vma) 1) << ((sizeof (bfd_signed_vma) * 8) - 1))
+           printf ("%" BFD_VMA_FMT "x", off);
+         else if (off < 0)
            printf ("-%" BFD_VMA_FMT "x", - off);
          else
            printf ("%" BFD_VMA_FMT "x", off);
@@ -1540,7 +1744,7 @@ get_ppc_dynamic_type (unsigned long type)
   switch (type)
     {
     case DT_PPC_GOT:    return "PPC_GOT";
-    case DT_PPC_TLSOPT: return "PPC_TLSOPT";
+    case DT_PPC_OPT:    return "PPC_OPT";
     default:
       return NULL;
     }
@@ -1554,7 +1758,7 @@ get_ppc64_dynamic_type (unsigned long type)
     case DT_PPC64_GLINK:  return "PPC64_GLINK";
     case DT_PPC64_OPD:    return "PPC64_OPD";
     case DT_PPC64_OPDSZ:  return "PPC64_OPDSZ";
-    case DT_PPC64_TLSOPT: return "PPC64_TLSOPT";
+    case DT_PPC64_OPT:    return "PPC64_OPT";
     default:
       return NULL;
     }
@@ -1678,6 +1882,17 @@ get_tic6x_dynamic_type (unsigned long type)
     }
 }
 
+static const char *
+get_nios2_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    case DT_NIOS2_GP: return "NIOS2_GP";
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_dynamic_type (unsigned long type)
 {
@@ -1792,6 +2007,9 @@ get_dynamic_type (unsigned long type)
            case EM_TI_C6000:
              result = get_tic6x_dynamic_type (type);
              break;
+           case EM_ALTERA_NIOS2:
+             result = get_nios2_dynamic_type (type);
+             break;
            default:
              result = NULL;
              break;
@@ -1885,8 +2103,8 @@ get_machine_name (unsigned e_machine)
     case EM_960:               return "Intel 90860";
     case EM_PPC:               return "PowerPC";
     case EM_PPC64:             return "PowerPC64";
-    case EM_V800:              return "NEC V800";
     case EM_FR20:              return "Fujitsu FR20";
+    case EM_FT32:              return "FTDI FT32";
     case EM_RH32:              return "TRW RH32";
     case EM_MCORE:             return "MCORE";
     case EM_ARM:               return "ARM";
@@ -1910,6 +2128,7 @@ get_machine_name (unsigned e_machine)
     case EM_CYGNUS_M32R:
     case EM_M32R:              return "Renesas M32R (formerly Mitsubishi M32r)";
     case EM_CYGNUS_V850:
+    case EM_V800:              return "Renesas V850 (using RH850 ABI)";
     case EM_V850:              return "Renesas V850";
     case EM_CYGNUS_MN10300:
     case EM_MN10300:           return "mn10300";
@@ -1943,6 +2162,7 @@ get_machine_name (unsigned e_machine)
     case EM_SVX:               return "Silicon Graphics SVx";
     case EM_ST19:              return "STMicroelectronics ST19 8-bit microcontroller";
     case EM_VAX:               return "Digital VAX";
+    case EM_VISIUM:            return "CDS VISIUMcore processor";
     case EM_AVR_OLD:
     case EM_AVR:               return "Atmel AVR 8-bit microcontroller";
     case EM_CRIS:              return "Axis Communications 32-bit embedded processor";
@@ -1959,8 +2179,7 @@ get_machine_name (unsigned e_machine)
     case EM_S390:              return "IBM S/390";
     case EM_SCORE:             return "SUNPLUS S+Core";
     case EM_XSTORMY16:         return "Sanyo XStormy16 CPU core";
-    case EM_OPENRISC:
-    case EM_OR32:              return "OpenRISC";
+    case EM_OR1K:              return "OpenRISC 1000";
     case EM_ARC_A5:            return "ARC International ARCompact processor";
     case EM_CRX:               return "National Semiconductor CRX microprocessor";
     case EM_ADAPTEVA_EPIPHANY: return "Adapteva EPIPHANY";
@@ -2025,7 +2244,7 @@ get_machine_name (unsigned e_machine)
     case EM_MICROBLAZE_OLD:    return "Xilinx MicroBlaze";
     case EM_RL78:              return "Renesas RL78";
     case EM_RX:                        return "Renesas RX";
-    case EM_METAG:             return "Imagination Technologies META processor architecture";
+    case EM_METAG:             return "Imagination Technologies Meta processor architecture";
     case EM_MCST_ELBRUS:       return "MCST Elbrus general purpose hardware architecture";
     case EM_ECOG16:            return "Cyan Technology eCOG16 family";
     case EM_ETPU:              return "Freescale Extended Time Processing Unit";
@@ -2059,12 +2278,6 @@ decode_ARM_machine_flags (unsigned e_flags, char buf[])
       e_flags &= ~ EF_ARM_RELEXEC;
     }
 
-  if (e_flags & EF_ARM_HASENTRY)
-    {
-      strcat (buf, ", has entry point");
-      e_flags &= ~ EF_ARM_HASENTRY;
-    }
-
   /* Now handle EABI specific flags.  */
   switch (eabi)
     {
@@ -2258,6 +2471,280 @@ decode_ARM_machine_flags (unsigned e_flags, char buf[])
     strcat (buf,_(", <unknown>"));
 }
 
+static void
+decode_AVR_machine_flags (unsigned e_flags, char buf[], size_t size)
+{
+  --size; /* Leave space for null terminator.  */
+
+  switch (e_flags & EF_AVR_MACH)
+    {
+    case E_AVR_MACH_AVR1:
+      strncat (buf, ", avr:1", size);
+      break;
+    case E_AVR_MACH_AVR2:
+      strncat (buf, ", avr:2", size);
+      break;
+    case E_AVR_MACH_AVR25:
+      strncat (buf, ", avr:25", size);
+      break;
+    case E_AVR_MACH_AVR3:
+      strncat (buf, ", avr:3", size);
+      break;
+    case E_AVR_MACH_AVR31:
+      strncat (buf, ", avr:31", size);
+      break;
+    case E_AVR_MACH_AVR35:
+      strncat (buf, ", avr:35", size);
+      break;
+    case E_AVR_MACH_AVR4:
+      strncat (buf, ", avr:4", size);
+      break;
+    case E_AVR_MACH_AVR5:
+      strncat (buf, ", avr:5", size);
+      break;
+    case E_AVR_MACH_AVR51:
+      strncat (buf, ", avr:51", size);
+      break;
+    case E_AVR_MACH_AVR6:
+      strncat (buf, ", avr:6", size);
+      break;
+    case E_AVR_MACH_AVRTINY:
+      strncat (buf, ", avr:100", size);
+      break;
+    case E_AVR_MACH_XMEGA1:
+      strncat (buf, ", avr:101", size);
+      break;
+    case E_AVR_MACH_XMEGA2:
+      strncat (buf, ", avr:102", size);
+      break;
+    case E_AVR_MACH_XMEGA3:
+      strncat (buf, ", avr:103", size);
+      break;
+    case E_AVR_MACH_XMEGA4:
+      strncat (buf, ", avr:104", size);
+      break;
+    case E_AVR_MACH_XMEGA5:
+      strncat (buf, ", avr:105", size);
+      break;
+    case E_AVR_MACH_XMEGA6:
+      strncat (buf, ", avr:106", size);
+      break;
+    case E_AVR_MACH_XMEGA7:
+      strncat (buf, ", avr:107", size);
+      break;
+    default:
+      strncat (buf, ", avr:<unknown>", size);
+      break;
+    }
+
+  size -= strlen (buf);
+  if (e_flags & EF_AVR_LINKRELAX_PREPARED)
+    strncat (buf, ", link-relax", size);
+}
+
+static void
+decode_NDS32_machine_flags (unsigned e_flags, char buf[], size_t size)
+{
+  unsigned abi;
+  unsigned arch;
+  unsigned config;
+  unsigned version;
+  int has_fpu = 0;
+  int r = 0;
+
+  static const char *ABI_STRINGS[] =
+  {
+    "ABI v0", /* use r5 as return register; only used in N1213HC */
+    "ABI v1", /* use r0 as return register */
+    "ABI v2", /* use r0 as return register and don't reserve 24 bytes for arguments */
+    "ABI v2fp", /* for FPU */
+    "AABI",
+    "ABI2 FP+"
+  };
+  static const char *VER_STRINGS[] =
+  {
+    "Andes ELF V1.3 or older",
+    "Andes ELF V1.3.1",
+    "Andes ELF V1.4"
+  };
+  static const char *ARCH_STRINGS[] =
+  {
+    "",
+    "Andes Star v1.0",
+    "Andes Star v2.0",
+    "Andes Star v3.0",
+    "Andes Star v3.0m"
+  };
+
+  abi = EF_NDS_ABI & e_flags;
+  arch = EF_NDS_ARCH & e_flags;
+  config = EF_NDS_INST & e_flags;
+  version = EF_NDS32_ELF_VERSION & e_flags;
+
+  memset (buf, 0, size);
+
+  switch (abi)
+    {
+    case E_NDS_ABI_V0:
+    case E_NDS_ABI_V1:
+    case E_NDS_ABI_V2:
+    case E_NDS_ABI_V2FP:
+    case E_NDS_ABI_AABI:
+    case E_NDS_ABI_V2FP_PLUS:
+      /* In case there are holes in the array.  */
+      r += snprintf (buf + r, size - r, ", %s", ABI_STRINGS[abi >> EF_NDS_ABI_SHIFT]);
+      break;
+
+    default:
+      r += snprintf (buf + r, size - r, ", <unrecognized ABI>");
+      break;
+    }
+
+  switch (version)
+    {
+    case E_NDS32_ELF_VER_1_2:
+    case E_NDS32_ELF_VER_1_3:
+    case E_NDS32_ELF_VER_1_4:
+      r += snprintf (buf + r, size - r, ", %s", VER_STRINGS[version >> EF_NDS32_ELF_VERSION_SHIFT]);
+      break;
+
+    default:
+      r += snprintf (buf + r, size - r, ", <unrecognized ELF version number>");
+      break;
+    }
+
+  if (E_NDS_ABI_V0 == abi)
+    {
+      /* OLD ABI; only used in N1213HC, has performance extension 1.  */
+      r += snprintf (buf + r, size - r, ", Andes Star v1.0, N1213HC, MAC, PERF1");
+      if (arch == E_NDS_ARCH_STAR_V1_0)
+       r += snprintf (buf + r, size -r, ", 16b"); /* has 16-bit instructions */
+      return;
+    }
+
+  switch (arch)
+    {
+    case E_NDS_ARCH_STAR_V1_0:
+    case E_NDS_ARCH_STAR_V2_0:
+    case E_NDS_ARCH_STAR_V3_0:
+    case E_NDS_ARCH_STAR_V3_M:
+      r += snprintf (buf + r, size - r, ", %s", ARCH_STRINGS[arch >> EF_NDS_ARCH_SHIFT]);
+      break;
+
+    default:
+      r += snprintf (buf + r, size - r, ", <unrecognized architecture>");
+      /* ARCH version determines how the e_flags are interpreted.
+        If it is unknown, we cannot proceed.  */
+      return;
+    }
+
+  /* Newer ABI; Now handle architecture specific flags.  */
+  if (arch == E_NDS_ARCH_STAR_V1_0)
+    {
+      if (config & E_NDS32_HAS_MFUSR_PC_INST)
+       r += snprintf (buf + r, size -r, ", MFUSR_PC");
+
+      if (!(config & E_NDS32_HAS_NO_MAC_INST))
+       r += snprintf (buf + r, size -r, ", MAC");
+
+      if (config & E_NDS32_HAS_DIV_INST)
+       r += snprintf (buf + r, size -r, ", DIV");
+
+      if (config & E_NDS32_HAS_16BIT_INST)
+       r += snprintf (buf + r, size -r, ", 16b");
+    }
+  else
+    {
+      if (config & E_NDS32_HAS_MFUSR_PC_INST)
+       {
+         if (version <= E_NDS32_ELF_VER_1_3)
+           r += snprintf (buf + r, size -r, ", [B8]");
+         else
+           r += snprintf (buf + r, size -r, ", EX9");
+       }
+
+      if (config & E_NDS32_HAS_MAC_DX_INST)
+       r += snprintf (buf + r, size -r, ", MAC_DX");
+
+      if (config & E_NDS32_HAS_DIV_DX_INST)
+       r += snprintf (buf + r, size -r, ", DIV_DX");
+
+      if (config & E_NDS32_HAS_16BIT_INST)
+       {
+         if (version <= E_NDS32_ELF_VER_1_3)
+           r += snprintf (buf + r, size -r, ", 16b");
+         else
+           r += snprintf (buf + r, size -r, ", IFC");
+       }
+    }
+
+  if (config & E_NDS32_HAS_EXT_INST)
+    r += snprintf (buf + r, size -r, ", PERF1");
+
+  if (config & E_NDS32_HAS_EXT2_INST)
+    r += snprintf (buf + r, size -r, ", PERF2");
+
+  if (config & E_NDS32_HAS_FPU_INST)
+    {
+      has_fpu = 1;
+      r += snprintf (buf + r, size -r, ", FPU_SP");
+    }
+
+  if (config & E_NDS32_HAS_FPU_DP_INST)
+    {
+      has_fpu = 1;
+      r += snprintf (buf + r, size -r, ", FPU_DP");
+    }
+
+  if (config & E_NDS32_HAS_FPU_MAC_INST)
+    {
+      has_fpu = 1;
+      r += snprintf (buf + r, size -r, ", FPU_MAC");
+    }
+
+  if (has_fpu)
+    {
+      switch ((config & E_NDS32_FPU_REG_CONF) >> E_NDS32_FPU_REG_CONF_SHIFT)
+       {
+       case E_NDS32_FPU_REG_8SP_4DP:
+         r += snprintf (buf + r, size -r, ", FPU_REG:8/4");
+         break;
+       case E_NDS32_FPU_REG_16SP_8DP:
+         r += snprintf (buf + r, size -r, ", FPU_REG:16/8");
+         break;
+       case E_NDS32_FPU_REG_32SP_16DP:
+         r += snprintf (buf + r, size -r, ", FPU_REG:32/16");
+         break;
+       case E_NDS32_FPU_REG_32SP_32DP:
+         r += snprintf (buf + r, size -r, ", FPU_REG:32/32");
+         break;
+       }
+    }
+
+  if (config & E_NDS32_HAS_AUDIO_INST)
+    r += snprintf (buf + r, size -r, ", AUDIO");
+
+  if (config & E_NDS32_HAS_STRING_INST)
+    r += snprintf (buf + r, size -r, ", STR");
+
+  if (config & E_NDS32_HAS_REDUCED_REGS)
+    r += snprintf (buf + r, size -r, ", 16REG");
+
+  if (config & E_NDS32_HAS_VIDEO_INST)
+    {
+      if (version <= E_NDS32_ELF_VER_1_3)
+       r += snprintf (buf + r, size -r, ", VIDEO");
+      else
+       r += snprintf (buf + r, size -r, ", SATURATION");
+    }
+
+  if (config & E_NDS32_HAS_ENCRIPT_INST)
+    r += snprintf (buf + r, size -r, ", ENCRP");
+
+  if (config & E_NDS32_HAS_L2C_INST)
+    r += snprintf (buf + r, size -r, ", L2C");
+}
+
 static char *
 get_machine_flags (unsigned e_flags, unsigned e_machine)
 {
@@ -2276,6 +2763,10 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
          decode_ARM_machine_flags (e_flags, buf);
          break;
 
+        case EM_AVR:
+          decode_AVR_machine_flags (e_flags, buf, sizeof buf);
+          break;
+
        case EM_BLACKFIN:
          if (e_flags & EF_BFIN_PIC)
            strcat (buf, ", PIC");
@@ -2412,10 +2903,69 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            strcat (buf, _(", relocatable-lib"));
          break;
 
+       case EM_PPC64:
+         if (e_flags & EF_PPC64_ABI)
+           {
+             char abi[] = ", abiv0";
+
+             abi[6] += e_flags & EF_PPC64_ABI;
+             strcat (buf, abi);
+           }
+         break;
+
+       case EM_V800:
+         if ((e_flags & EF_RH850_ABI) == EF_RH850_ABI)
+           strcat (buf, ", RH850 ABI");
+
+         if (e_flags & EF_V800_850E3)
+           strcat (buf, ", V3 architecture");
+
+         if ((e_flags & (EF_RH850_FPU_DOUBLE | EF_RH850_FPU_SINGLE)) == 0)
+           strcat (buf, ", FPU not used");
+
+         if ((e_flags & (EF_RH850_REGMODE22 | EF_RH850_REGMODE32)) == 0)
+           strcat (buf, ", regmode: COMMON");
+
+         if ((e_flags & (EF_RH850_GP_FIX | EF_RH850_GP_NOFIX)) == 0)
+           strcat (buf, ", r4 not used");
+
+         if ((e_flags & (EF_RH850_EP_FIX | EF_RH850_EP_NOFIX)) == 0)
+           strcat (buf, ", r30 not used");
+
+         if ((e_flags & (EF_RH850_TP_FIX | EF_RH850_TP_NOFIX)) == 0)
+           strcat (buf, ", r5 not used");
+
+         if ((e_flags & (EF_RH850_REG2_RESERVE | EF_RH850_REG2_NORESERVE)) == 0)
+           strcat (buf, ", r2 not used");
+
+         for (e_flags &= 0xFFFF; e_flags; e_flags &= ~ (e_flags & - e_flags))
+           {
+             switch (e_flags & - e_flags)
+               {
+               case EF_RH850_FPU_DOUBLE: strcat (buf, ", double precision FPU"); break;
+               case EF_RH850_FPU_SINGLE: strcat (buf, ", single precision FPU"); break;
+               case EF_RH850_REGMODE22: strcat (buf, ", regmode:22"); break;
+               case EF_RH850_REGMODE32: strcat (buf, ", regmode:23"); break;
+               case EF_RH850_GP_FIX: strcat (buf, ", r4 fixed"); break;
+               case EF_RH850_GP_NOFIX: strcat (buf, ", r4 free"); break;
+               case EF_RH850_EP_FIX: strcat (buf, ", r30 fixed"); break;
+               case EF_RH850_EP_NOFIX: strcat (buf, ", r30 free"); break;
+               case EF_RH850_TP_FIX: strcat (buf, ", r5 fixed"); break;
+               case EF_RH850_TP_NOFIX: strcat (buf, ", r5 free"); break;
+               case EF_RH850_REG2_RESERVE: strcat (buf, ", r2 fixed"); break;
+               case EF_RH850_REG2_NORESERVE: strcat (buf, ", r2 free"); break;
+               default: break;
+               }
+           }
+         break;
+
        case EM_V850:
        case EM_CYGNUS_V850:
          switch (e_flags & EF_V850_ARCH)
            {
+           case E_V850E3V5_ARCH:
+             strcat (buf, ", v850e3v5");
+             break;
            case E_V850E2V3_ARCH:
              strcat (buf, ", v850e2v3");
              break;
@@ -2466,6 +3016,12 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
          if (e_flags & EF_MIPS_32BITMODE)
            strcat (buf, ", 32bitmode");
 
+         if (e_flags & EF_MIPS_NAN2008)
+           strcat (buf, ", nan2008");
+
+         if (e_flags & EF_MIPS_FP64)
+           strcat (buf, ", fp64");
+
          switch ((e_flags & EF_MIPS_MACH))
            {
            case E_MIPS_MACH_3900: strcat (buf, ", 3900"); break;
@@ -2483,6 +3039,7 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            case E_MIPS_MACH_LS3A: strcat (buf, ", loongson-3a"); break;
            case E_MIPS_MACH_OCTEON: strcat (buf, ", octeon"); break;
            case E_MIPS_MACH_OCTEON2: strcat (buf, ", octeon2"); break;
+           case E_MIPS_MACH_OCTEON3: strcat (buf, ", octeon3"); break;
            case E_MIPS_MACH_XLR:  strcat (buf, ", xlr"); break;
            case 0:
            /* We simply ignore the field in this case to avoid confusion:
@@ -2525,16 +3082,16 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            case E_MIPS_ARCH_5: strcat (buf, ", mips5"); break;
            case E_MIPS_ARCH_32: strcat (buf, ", mips32"); break;
            case E_MIPS_ARCH_32R2: strcat (buf, ", mips32r2"); break;
+           case E_MIPS_ARCH_32R6: strcat (buf, ", mips32r6"); break;
            case E_MIPS_ARCH_64: strcat (buf, ", mips64"); break;
            case E_MIPS_ARCH_64R2: strcat (buf, ", mips64r2"); break;
+           case E_MIPS_ARCH_64R6: strcat (buf, ", mips64r6"); break;
            default: strcat (buf, _(", unknown ISA")); break;
            }
+         break;
 
-         if (e_flags & EF_SH_PIC)
-           strcat (buf, ", pic");
-
-         if (e_flags & EF_SH_FDPIC)
-           strcat (buf, ", fdpic");
+       case EM_NDS32:
+         decode_NDS32_machine_flags (e_flags, buf, sizeof buf);
          break;
 
        case EM_SH:
@@ -2564,8 +3121,18 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            default: strcat (buf, _(", unknown ISA")); break;
            }
 
+         if (e_flags & EF_SH_PIC)
+           strcat (buf, ", pic");
+
+         if (e_flags & EF_SH_FDPIC)
+           strcat (buf, ", fdpic");
          break;
 
+        case EM_OR1K:
+          if (e_flags & EF_OR1K_NODELAY)
+            strcat (buf, ", no delay");
+          break;
+
        case EM_SPARCV9:
          if (e_flags & EF_SPARC_32PLUS)
            strcat (buf, ", v8+");
@@ -2661,7 +3228,9 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
                   strcat (buf, ", abort");
                   break;
                 default:
-                  abort ();
+                 warn (_("Unrecognised IA64 VMS Command Code: %x\n"),
+                       e_flags & EF_IA_64_VMS_COMCOD);
+                 strcat (buf, ", <unknown>");
                 }
             }
          break;
@@ -2675,13 +3244,36 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            strcat (buf, ", G-Float");
          break;
 
-       case EM_RX:
-         if (e_flags & E_FLAG_RX_64BIT_DOUBLES)
-           strcat (buf, ", 64-bit doubles");
-         if (e_flags & E_FLAG_RX_DSP)
-           strcat (buf, ", dsp");
-         if (e_flags & E_FLAG_RX_PID)
-           strcat (buf, ", pid");        
+        case EM_VISIUM:
+         if (e_flags & EF_VISIUM_ARCH_MCM)
+           strcat (buf, ", mcm");
+         else if (e_flags & EF_VISIUM_ARCH_MCM24)
+           strcat (buf, ", mcm24");
+         if (e_flags & EF_VISIUM_ARCH_GR6)
+           strcat (buf, ", gr6");
+         break;
+
+       case EM_RL78:
+         switch (e_flags & E_FLAG_RL78_CPU_MASK)
+           {
+           case E_FLAG_RL78_ANY_CPU: break;
+           case E_FLAG_RL78_G10: strcat (buf, ", G10"); break;
+           case E_FLAG_RL78_G13: strcat (buf, ", G13"); break;
+           case E_FLAG_RL78_G14: strcat (buf, ", G14"); break;
+           }
+         if (e_flags & E_FLAG_RL78_64BIT_DOUBLES)
+           strcat (buf, ", 64-bit doubles");
+         break;
+
+       case EM_RX:
+         if (e_flags & E_FLAG_RX_64BIT_DOUBLES)
+           strcat (buf, ", 64-bit doubles");
+         if (e_flags & E_FLAG_RX_DSP)
+           strcat (buf, ", dsp");
+         if (e_flags & E_FLAG_RX_PID)
+           strcat (buf, ", pid");
+         if (e_flags & E_FLAG_RX_ABI)
+           strcat (buf, ", RX ABI");
          break;
 
        case EM_S390:
@@ -2693,6 +3285,32 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
          if ((e_flags & EF_C6000_REL))
            strcat (buf, ", relocatable module");
          break;
+
+       case EM_MSP430:
+         strcat (buf, _(": architecture variant: "));
+         switch (e_flags & EF_MSP430_MACH)
+           {
+           case E_MSP430_MACH_MSP430x11: strcat (buf, "MSP430x11"); break;
+           case E_MSP430_MACH_MSP430x11x1 : strcat (buf, "MSP430x11x1 "); break;
+           case E_MSP430_MACH_MSP430x12: strcat (buf, "MSP430x12"); break;
+           case E_MSP430_MACH_MSP430x13: strcat (buf, "MSP430x13"); break;
+           case E_MSP430_MACH_MSP430x14: strcat (buf, "MSP430x14"); break;
+           case E_MSP430_MACH_MSP430x15: strcat (buf, "MSP430x15"); break;
+           case E_MSP430_MACH_MSP430x16: strcat (buf, "MSP430x16"); break;
+           case E_MSP430_MACH_MSP430x31: strcat (buf, "MSP430x31"); break;
+           case E_MSP430_MACH_MSP430x32: strcat (buf, "MSP430x32"); break;
+           case E_MSP430_MACH_MSP430x33: strcat (buf, "MSP430x33"); break;
+           case E_MSP430_MACH_MSP430x41: strcat (buf, "MSP430x41"); break;
+           case E_MSP430_MACH_MSP430x42: strcat (buf, "MSP430x42"); break;
+           case E_MSP430_MACH_MSP430x43: strcat (buf, "MSP430x43"); break;
+           case E_MSP430_MACH_MSP430x44: strcat (buf, "MSP430x44"); break;
+           case E_MSP430_MACH_MSP430X  : strcat (buf, "MSP430X"); break;
+           default:
+             strcat (buf, _(": unknown")); break;
+           }
+
+         if (e_flags & ~ EF_MSP430_MACH)
+           strcat (buf, _(": unknown extra flag bits also present"));
        }
     }
 
@@ -2736,6 +3354,7 @@ get_osabi_name (unsigned int osabi)
 
          case EM_MSP430:
          case EM_MSP430_OLD:
+         case EM_VISIUM:
            switch (osabi)
              {
              case ELFOSABI_STANDALONE: return _("Standalone App");
@@ -2801,6 +3420,8 @@ get_mips_segment_type (unsigned long type)
       return "RTPROC";
     case PT_MIPS_OPTIONS:
       return "OPTIONS";
+    case PT_MIPS_ABIFLAGS:
+      return "ABIFLAGS";
     default:
       break;
     }
@@ -3000,6 +3621,7 @@ get_mips_section_type_name (unsigned int sh_type)
     case SHT_MIPS_EH_REGION:    return "MIPS_EH_REGION";
     case SHT_MIPS_XLATE_OLD:    return "MIPS_XLATE_OLD";
     case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION";
+    case SHT_MIPS_ABIFLAGS:     return "MIPS_ABIFLAGS";
     default:
       break;
     }
@@ -3117,6 +3739,32 @@ get_tic6x_section_type_name (unsigned int sh_type)
   return NULL;
 }
 
+static const char *
+get_msp430x_section_type_name (unsigned int sh_type)
+{
+  switch (sh_type)
+    {
+    case SHT_MSP430_SEC_FLAGS:   return "MSP430_SEC_FLAGS";
+    case SHT_MSP430_SYM_ALIASES: return "MSP430_SYM_ALIASES";
+    case SHT_MSP430_ATTRIBUTES:  return "MSP430_ATTRIBUTES";
+    default: return NULL;
+    }
+}
+
+static const char *
+get_v850_section_type_name (unsigned int sh_type)
+{
+  switch (sh_type)
+    {
+    case SHT_V850_SCOMMON: return "V850 Small Common";
+    case SHT_V850_TCOMMON: return "V850 Tiny Common";
+    case SHT_V850_ZCOMMON: return "V850 Zero Common";
+    case SHT_RENESAS_IOP:  return "RENESAS IOP";
+    case SHT_RENESAS_INFO: return "RENESAS INFO";
+    default: return NULL;
+    }
+}
+
 static const char *
 get_section_type_name (unsigned int sh_type)
 {
@@ -3182,6 +3830,14 @@ get_section_type_name (unsigned int sh_type)
            case EM_TI_C6000:
              result = get_tic6x_section_type_name (sh_type);
              break;
+           case EM_MSP430:
+             result = get_msp430x_section_type_name (sh_type);
+             break;
+           case EM_V800:
+           case EM_V850:
+           case EM_CYGNUS_V850:
+             result = get_v850_section_type_name (sh_type);
+             break;
            default:
              result = NULL;
              break;
@@ -3212,7 +3868,19 @@ get_section_type_name (unsigned int sh_type)
          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);
+       {
+         switch (elf_header.e_machine)
+           {
+           case EM_V800:
+           case EM_V850:
+           case EM_CYGNUS_V850:
+             return get_v850_section_type_name (sh_type);
+           default:
+             break;
+           }
+
+         sprintf (buff, "LOUSER+%x", sh_type - SHT_LOUSER);
+       }
       else
        /* This message is probably going to be displayed in a 15
           character wide field, so put the hex value first.  */
@@ -3567,11 +4235,6 @@ parse_args (int argc, char ** argv)
       && !do_section_groups && !do_archive_index
       && !do_dyn_syms)
     usage (stderr);
-  else if (argc < 3)
-    {
-      warn (_("Nothing to do.\n"));
-      usage (stderr);
-    }
 }
 
 static const char *
@@ -3712,21 +4375,31 @@ process_file_header (void)
   return 1;
 }
 
-
-static int
+static bfd_boolean
 get_32bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
 {
   Elf32_External_Phdr * phdrs;
   Elf32_External_Phdr * external;
   Elf_Internal_Phdr *   internal;
   unsigned int i;
+  unsigned int size = elf_header.e_phentsize;
+  unsigned int num  = elf_header.e_phnum;
+
+  /* PR binutils/17531: Cope with unexpected section header sizes.  */
+  if (size == 0 || num == 0)
+    return FALSE;
+  if (size < sizeof * phdrs)
+    {
+      error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
+      return FALSE;
+    }
+  if (size > sizeof * phdrs)
+    warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
 
   phdrs = (Elf32_External_Phdr *) get_data (NULL, file, elf_header.e_phoff,
-                                            elf_header.e_phentsize,
-                                            elf_header.e_phnum,
-                                            _("program headers"));
-  if (!phdrs)
-    return 0;
+                                            size, num, _("program headers"));
+  if (phdrs == NULL)
+    return FALSE;
 
   for (i = 0, internal = pheaders, external = phdrs;
        i < elf_header.e_phnum;
@@ -3743,24 +4416,34 @@ get_32bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
     }
 
   free (phdrs);
-
-  return 1;
+  return TRUE;
 }
 
-static int
+static bfd_boolean
 get_64bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
 {
   Elf64_External_Phdr * phdrs;
   Elf64_External_Phdr * external;
   Elf_Internal_Phdr *   internal;
   unsigned int i;
+  unsigned int size = elf_header.e_phentsize;
+  unsigned int num  = elf_header.e_phnum;
+
+  /* PR binutils/17531: Cope with unexpected section header sizes.  */
+  if (size == 0 || num == 0)
+    return FALSE;
+  if (size < sizeof * phdrs)
+    {
+      error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
+      return FALSE;
+    }
+  if (size > sizeof * phdrs)
+    warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
 
   phdrs = (Elf64_External_Phdr *) get_data (NULL, file, elf_header.e_phoff,
-                                            elf_header.e_phentsize,
-                                            elf_header.e_phnum,
-                                            _("program headers"));
+                                            size, num, _("program headers"));
   if (!phdrs)
-    return 0;
+    return FALSE;
 
   for (i = 0, internal = pheaders, external = phdrs;
        i < elf_header.e_phnum;
@@ -3777,8 +4460,7 @@ get_64bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
     }
 
   free (phdrs);
-
-  return 1;
+  return TRUE;
 }
 
 /* Returns 1 if the program headers were read into `program_headers'.  */
@@ -3797,7 +4479,8 @@ get_program_headers (FILE * file)
 
   if (phdrs == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory reading %u program headers\n"),
+            elf_header.e_phnum);
       return 0;
     }
 
@@ -3826,7 +4509,7 @@ process_program_headers (FILE * file)
       /* PR binutils/12467.  */
       if (elf_header.e_phoff != 0)
        warn (_("possibly corrupt ELF header - it has a non-zero program"
-               " header offset, but no program headers"));
+               " header offset, but no program headers\n"));
       else if (do_segments)
        printf (_("\nThere are no program headers in this file.\n"));
       return 0;
@@ -3953,6 +4636,9 @@ process_program_headers (FILE * file)
            }
        }
 
+      if (do_segments)
+       putc ('\n', stdout);
+
       switch (segment->p_type)
        {
        case PT_DYNAMIC:
@@ -3963,6 +4649,12 @@ process_program_headers (FILE * file)
             section in the DYNAMIC segment.  */
          dynamic_addr = segment->p_offset;
          dynamic_size = segment->p_filesz;
+         /* PR binutils/17512: Avoid corrupt dynamic section info in the segment.  */
+         if (dynamic_addr + dynamic_size >= current_file_size)
+           {
+             error (_("the dynamic segment offset + size exceeds the size of the file\n"));
+             dynamic_addr = dynamic_size = 0;
+           }
 
          /* Try to locate the .dynamic section. If there is
             a section header table, we can easily locate it.  */
@@ -4006,7 +4698,7 @@ process_program_headers (FILE * file)
          else
            {
              char fmt [32];
-             int ret = snprintf (fmt, sizeof (fmt), "%%%ds", PATH_MAX);
+             int ret = snprintf (fmt, sizeof (fmt), "%%%ds", PATH_MAX - 1);
 
              if (ret >= (int) sizeof (fmt) || ret < 0)
                error (_("Internal error: failed to create format string to display program interpreter\n"));
@@ -4016,14 +4708,11 @@ process_program_headers (FILE * file)
                error (_("Unable to read program interpreter name\n"));
 
              if (do_segments)
-               printf (_("\n      [Requesting program interpreter: %s]"),
+               printf (_("      [Requesting program interpreter: %s]\n"),
                    program_interpreter);
            }
          break;
        }
-
-      if (do_segments)
-       putc ('\n', stdout);
     }
 
   if (do_segments && section_headers != NULL && string_table != NULL)
@@ -4045,7 +4734,7 @@ process_program_headers (FILE * file)
            {
              if (!ELF_TBSS_SPECIAL (section, segment)
                  && ELF_SECTION_IN_SEGMENT_STRICT (section, segment))
-               printf ("%s ", SECTION_NAME (section));
+               printf ("%s ", printable_section_name (section));
            }
 
          putc ('\n',stdout);
@@ -4087,26 +4776,46 @@ offset_from_vma (FILE * file, bfd_vma vma, bfd_size_type size)
 }
 
 
-static int
-get_32bit_section_headers (FILE * file, unsigned int num)
+/* Allocate memory and load the sections headers into the global pointer
+   SECTION_HEADERS.  If PROBE is true, this is just a probe and we do not
+   generate any error messages if the load fails.  */
+
+static bfd_boolean
+get_32bit_section_headers (FILE * file, bfd_boolean probe)
 {
   Elf32_External_Shdr * shdrs;
   Elf_Internal_Shdr *   internal;
   unsigned int i;
+  unsigned int size = elf_header.e_shentsize;
+  unsigned int num = probe ? 1 : elf_header.e_shnum;
+
+  /* PR binutils/17531: Cope with unexpected section header sizes.  */
+  if (size == 0 || num == 0)
+    return FALSE;
+  if (size < sizeof * shdrs)
+    {
+      if (! probe)
+       error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
+      return FALSE;
+    }
+  if (!probe && size > sizeof * shdrs)
+    warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
 
   shdrs = (Elf32_External_Shdr *) get_data (NULL, file, elf_header.e_shoff,
-                                            elf_header.e_shentsize, num,
-                                            _("section headers"));
-  if (!shdrs)
-    return 0;
+                                            size, num,
+                                           probe ? NULL : _("section headers"));
+  if (shdrs == NULL)
+    return FALSE;
 
+  if (section_headers != NULL)
+    free (section_headers);
   section_headers = (Elf_Internal_Shdr *) cmalloc (num,
                                                    sizeof (Elf_Internal_Shdr));
-
   if (section_headers == NULL)
     {
-      error (_("Out of memory\n"));
-      return 0;
+      if (!probe)
+       error (_("Out of memory reading %u section headers\n"), num);
+      return FALSE;
     }
 
   for (i = 0, internal = section_headers;
@@ -4126,30 +4835,45 @@ get_32bit_section_headers (FILE * file, unsigned int num)
     }
 
   free (shdrs);
-
-  return 1;
+  return TRUE;
 }
 
-static int
-get_64bit_section_headers (FILE * file, unsigned int num)
+static bfd_boolean
+get_64bit_section_headers (FILE * file, bfd_boolean probe)
 {
   Elf64_External_Shdr * shdrs;
   Elf_Internal_Shdr *   internal;
   unsigned int i;
+  unsigned int size = elf_header.e_shentsize;
+  unsigned int num = probe ? 1 : elf_header.e_shnum;
+
+  /* PR binutils/17531: Cope with unexpected section header sizes.  */
+  if (size == 0 || num == 0)
+    return FALSE;
+  if (size < sizeof * shdrs)
+    {
+      if (! probe)
+       error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
+      return FALSE;
+    }
+  if (! probe && size > sizeof * shdrs)
+    warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
 
   shdrs = (Elf64_External_Shdr *) get_data (NULL, file, elf_header.e_shoff,
-                                            elf_header.e_shentsize, num,
-                                            _("section headers"));
-  if (!shdrs)
-    return 0;
+                                            size, num,
+                                           probe ? NULL : _("section headers"));
+  if (shdrs == NULL)
+    return FALSE;
 
+  if (section_headers != NULL)
+    free (section_headers);
   section_headers = (Elf_Internal_Shdr *) cmalloc (num,
                                                    sizeof (Elf_Internal_Shdr));
-
   if (section_headers == NULL)
     {
-      error (_("Out of memory\n"));
-      return 0;
+      if (! probe)
+       error (_("Out of memory reading %u section headers\n"), num);
+      return FALSE;
     }
 
   for (i = 0, internal = section_headers;
@@ -4169,8 +4893,7 @@ get_64bit_section_headers (FILE * file, unsigned int num)
     }
 
   free (shdrs);
-
-  return 1;
+  return TRUE;
 }
 
 static Elf_Internal_Sym *
@@ -4185,10 +4908,25 @@ get_32bit_elf_symbols (FILE * file,
   Elf_Internal_Sym * psym;
   unsigned int j;
 
+  if (section->sh_size == 0)
+    {
+      if (num_syms_return != NULL)
+       * num_syms_return = 0;
+      return NULL;
+    }
+
   /* Run some sanity checks first.  */
-  if (section->sh_entsize == 0)
+  if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size)
+    {
+      error (_("Section %s has an invalid sh_entsize of 0x%lx\n"),
+            printable_section_name (section), (unsigned long) section->sh_entsize);
+      goto exit_point;
+    }
+
+  if (section->sh_size > current_file_size)
     {
-      error (_("sh_entsize is zero\n"));
+      error (_("Section %s has an invalid sh_size of 0x%lx\n"),
+            printable_section_name (section), (unsigned long) section->sh_size);
       goto exit_point;
     }
 
@@ -4196,7 +4934,10 @@ get_32bit_elf_symbols (FILE * file,
 
   if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1)
     {
-      error (_("Invalid sh_entsize\n"));
+      error (_("Size (0x%lx) of section %s is not a multiple of its sh_entsize (0x%lx)\n"),
+            (unsigned long) section->sh_size,
+            printable_section_name (section),
+            (unsigned long) section->sh_entsize);
       goto exit_point;
     }
 
@@ -4216,13 +4957,23 @@ get_32bit_elf_symbols (FILE * file,
                                                    _("symbol table section indicies"));
       if (shndx == NULL)
        goto exit_point;
+      /* PR17531: file: heap-buffer-overflow */
+      else if (symtab_shndx_hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number)
+       {
+         error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"),
+                printable_section_name (symtab_shndx_hdr),
+                (unsigned long) symtab_shndx_hdr->sh_size,
+                (unsigned long) section->sh_size);
+         goto exit_point;
+       }
     }
 
   isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym));
 
   if (isyms == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory reading %lu symbols\n"),
+            (unsigned long) number);
       goto exit_point;
     }
 
@@ -4265,10 +5016,27 @@ get_64bit_elf_symbols (FILE * file,
   Elf_Internal_Sym * psym;
   unsigned int j;
 
+  if (section->sh_size == 0)
+    {
+      if (num_syms_return != NULL)
+       * num_syms_return = 0;
+      return NULL;
+    }
+
   /* Run some sanity checks first.  */
-  if (section->sh_entsize == 0)
+  if (section->sh_entsize == 0 || section->sh_entsize > section->sh_size)
+    {
+      error (_("Section %s has an invalid sh_entsize of 0x%lx\n"),
+            printable_section_name (section),
+            (unsigned long) section->sh_entsize);
+      goto exit_point;
+    }
+
+  if (section->sh_size > current_file_size)
     {
-      error (_("sh_entsize is zero\n"));
+      error (_("Section %s has an invalid sh_size of 0x%lx\n"),
+            printable_section_name (section),
+            (unsigned long) section->sh_size);
       goto exit_point;
     }
 
@@ -4276,7 +5044,10 @@ get_64bit_elf_symbols (FILE * file,
 
   if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1)
     {
-      error (_("Invalid sh_entsize\n"));
+      error (_("Size (0x%lx) of section %s is not a multiple of its sh_entsize (0x%lx)\n"),
+            (unsigned long) section->sh_size,
+            printable_section_name (section),
+            (unsigned long) section->sh_entsize);
       goto exit_point;
     }
 
@@ -4295,13 +5066,22 @@ get_64bit_elf_symbols (FILE * file,
                                                    _("symbol table section indicies"));
       if (shndx == NULL)
        goto exit_point;
+      else if (symtab_shndx_hdr->sh_size / sizeof (Elf_External_Sym_Shndx) < number)
+       {
+         error (_("Index section %s has an sh_size of 0x%lx - expected 0x%lx\n"),
+                printable_section_name (symtab_shndx_hdr),
+                (unsigned long) symtab_shndx_hdr->sh_size,
+                (unsigned long) section->sh_size);
+         goto exit_point;
+       }
     }
 
   isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym));
 
   if (isyms == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory reading %lu symbols\n"),
+            (unsigned long) number);
       goto exit_point;
     }
 
@@ -4375,7 +5155,8 @@ get_elf_section_flags (bfd_vma sh_flags)
       /* Generic.  */
       /* 18 */ { STRING_COMMA_LEN ("EXCLUDE") },
       /* SPARC specific.  */
-      /* 19 */ { STRING_COMMA_LEN ("ORDERED") }
+      /* 19 */ { STRING_COMMA_LEN ("ORDERED") },
+      /* 20 */ { STRING_COMMA_LEN ("COMPRESSED") }
     };
 
   if (do_section_details)
@@ -4407,6 +5188,7 @@ get_elf_section_flags (bfd_vma sh_flags)
            case SHF_GROUP:             sindex = 8; break;
            case SHF_TLS:               sindex = 9; break;
            case SHF_EXCLUDE:           sindex = 18; break;
+           case SHF_COMPRESSED:        sindex = 20; break;
 
            default:
              sindex = -1;
@@ -4454,7 +5236,10 @@ get_elf_section_flags (bfd_vma sh_flags)
              if (p != buff + field_size + 4)
                {
                  if (size < (10 + 2))
-                   abort ();
+                   {
+                     warn (_("Internal error: not enough buffer room for section flag info"));
+                     return _("<unknown>");
+                   }
                  size -= 2;
                  *p++ = ',';
                  *p++ = ' ';
@@ -4485,6 +5270,7 @@ get_elf_section_flags (bfd_vma sh_flags)
            case SHF_GROUP:             *p = 'G'; break;
            case SHF_TLS:               *p = 'T'; break;
            case SHF_EXCLUDE:           *p = 'E'; break;
+           case SHF_COMPRESSED:        *p = 'C'; break;
 
            default:
              if ((elf_header.e_machine == EM_X86_64
@@ -4518,7 +5304,10 @@ get_elf_section_flags (bfd_vma sh_flags)
          if (p != buff + field_size + 4)
            {
              if (size < (2 + 1))
-               abort ();
+               {
+                 warn (_("Internal error: not enough buffer room for section flag info"));
+                 return _("<unknown>");
+               }
              size -= 2;
              *p++ = ',';
              *p++ = ' ';
@@ -4533,7 +5322,10 @@ get_elf_section_flags (bfd_vma sh_flags)
          if (p != buff + field_size + 4)
            {
              if (size < (2 + 1))
-               abort ();
+               {
+                 warn (_("Internal error: not enough buffer room for section flag info"));
+                 return _("<unknown>");
+               }
              size -= 2;
              *p++ = ',';
              *p++ = ' ';
@@ -4548,7 +5340,10 @@ get_elf_section_flags (bfd_vma sh_flags)
          if (p != buff + field_size + 4)
            {
              if (size < (2 + 1))
-               abort ();
+               {
+                 warn (_("Internal error: not enough buffer room for section flag info"));
+                 return _("<unknown>");
+               }
              size -= 2;
              *p++ = ',';
              *p++ = ' ';
@@ -4563,6 +5358,27 @@ get_elf_section_flags (bfd_vma sh_flags)
   return buff;
 }
 
+static unsigned int
+get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf)
+{
+  if (is_32bit_elf)
+    {
+      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) buf;
+      chdr->ch_type = BYTE_GET (echdr->ch_type);
+      chdr->ch_size = BYTE_GET (echdr->ch_size);
+      chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
+      return sizeof (*echdr);
+    }
+  else
+    {
+      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) buf;
+      chdr->ch_type = BYTE_GET (echdr->ch_type);
+      chdr->ch_size = BYTE_GET (echdr->ch_size);
+      chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
+      return sizeof (*echdr);
+    }
+}
+
 static int
 process_section_headers (FILE * file)
 {
@@ -4589,10 +5405,10 @@ process_section_headers (FILE * file)
 
   if (is_32bit_elf)
     {
-      if (! get_32bit_section_headers (file, elf_header.e_shnum))
+      if (! get_32bit_section_headers (file, FALSE))
        return 0;
     }
-  else if (! get_64bit_section_headers (file, elf_header.e_shnum))
+  else if (! get_64bit_section_headers (file, FALSE))
     return 0;
 
   /* Read in the string table, so that we have names to display.  */
@@ -4666,19 +5482,25 @@ process_section_headers (FILE * file)
       break;
     }
 
-#define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \
-  do                                                                       \
-    {                                                                      \
-      size_t expected_entsize                                              \
-       = is_32bit_elf ? size32 : size64;                                   \
-      if (section->sh_entsize != expected_entsize)                         \
-       error (_("Section %d has invalid sh_entsize %lx (expected %lx)\n"), \
-              i, (unsigned long int) section->sh_entsize,                  \
-              (unsigned long int) expected_entsize);                       \
-      section->sh_entsize = expected_entsize;                              \
-    }                                                                      \
+#define CHECK_ENTSIZE_VALUES(section, i, size32, size64)               \
+  do                                                                   \
+    {                                                                  \
+      bfd_size_type expected_entsize = is_32bit_elf ? size32 : size64; \
+      if (section->sh_entsize != expected_entsize)                     \
+       {                                                               \
+         char buf[40];                                                 \
+         sprintf_vma (buf, section->sh_entsize);                       \
+         /* Note: coded this way so that there is a single string for  \
+            translation.  */ \
+         error (_("Section %d has invalid sh_entsize of %s\n"), i, buf); \
+         error (_("(Using the expected size of %u for the rest of this dump)\n"), \
+                  (unsigned) expected_entsize);                        \
+         section->sh_entsize = expected_entsize;                       \
+       }                                                               \
+    }                                                                  \
   while (0)
-#define CHECK_ENTSIZE(section, i, type) \
+
+#define CHECK_ENTSIZE(section, i, type)                                        \
   CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type),        \
                        sizeof (Elf64_External_##type))
 
@@ -4747,9 +5569,12 @@ process_section_headers (FILE * file)
              || (do_debug_info     && const_strneq (name, "info"))
              || (do_debug_info     && const_strneq (name, "types"))
              || (do_debug_abbrevs  && const_strneq (name, "abbrev"))
-             || (do_debug_lines    && const_strneq (name, "line"))
+             || (do_debug_lines    && strcmp (name, "line") == 0)
+             || (do_debug_lines    && const_strneq (name, "line."))
              || (do_debug_pubnames && const_strneq (name, "pubnames"))
              || (do_debug_pubtypes && const_strneq (name, "pubtypes"))
+             || (do_debug_pubnames && const_strneq (name, "gnu_pubnames"))
+             || (do_debug_pubtypes && const_strneq (name, "gnu_pubtypes"))
              || (do_debug_aranges  && const_strneq (name, "aranges"))
              || (do_debug_ranges   && const_strneq (name, "ranges"))
              || (do_debug_frames   && const_strneq (name, "frame"))
@@ -4785,7 +5610,6 @@ process_section_headers (FILE * file)
              )
            request_dump_bynumber (i, DEBUG_DUMP);
        }
-
     }
 
   if (! do_sections)
@@ -4842,18 +5666,13 @@ process_section_headers (FILE * file)
     {
       printf ("  [%2u] ", i);
       if (do_section_details)
-       {
-         print_symbol (INT_MAX, SECTION_NAME (section));
-         printf ("\n      ");
-       }
+       printf ("%s\n      ", printable_section_name (section));
       else
-       {
-         print_symbol (-17, SECTION_NAME (section));
-       }
-      
+       print_symbol (-17, SECTION_NAME (section));
+
       printf (do_wide ? " %-15s " : " %-15.15s ",
              get_section_type_name (section->sh_type));
-      
+
       if (is_32bit_elf)
        {
          const char * link_too_big = NULL;
@@ -5004,7 +5823,29 @@ process_section_headers (FILE * file)
        }
 
       if (do_section_details)
-       printf ("       %s\n", get_elf_section_flags (section->sh_flags));
+       {
+         printf ("       %s\n", get_elf_section_flags (section->sh_flags));
+         if ((section->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             /* Minimum section size is 12 bytes for 32-bit compression
+                header + 12 bytes for compressed data header.  */
+             unsigned char buf[24];
+             assert (sizeof (buf) >= sizeof (Elf64_External_Chdr));
+             if (get_data (&buf, (FILE *) file, section->sh_offset, 1,
+                           sizeof (buf), _("compression header")))
+               {
+                 Elf_Internal_Chdr chdr;
+                 get_compression_header (&chdr, buf);
+                 if (chdr.ch_type == ELFCOMPRESS_ZLIB)
+                   printf ("       ZLIB, ");
+                 else
+                   printf (_("       [<unknown>: 0x%x], "),
+                           chdr.ch_type);
+                 print_vma (chdr.ch_size, LONG_HEX);
+                 printf (", %lu\n", (unsigned long) chdr.ch_addralign);
+               }
+           }
+       }
     }
 
   if (!do_section_details)
@@ -5021,7 +5862,7 @@ process_section_headers (FILE * file)
   W (write), A (alloc), X (execute), M (merge), S (strings)\n\
   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\n\
   O (extra OS processing required) o (OS specific), p (processor specific)\n"));
-    }  
+    }
 
   return 1;
 }
@@ -5082,7 +5923,8 @@ process_section_groups (FILE * file)
 
   if (section_headers_groups == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory reading %u section group headers\n"),
+            elf_header.e_shnum);
       return 0;
     }
 
@@ -5106,7 +5948,8 @@ process_section_groups (FILE * file)
 
   if (section_groups == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory reading %lu groups\n"),
+            (unsigned long) group_count);
       return 0;
     }
 
@@ -5122,8 +5965,8 @@ process_section_groups (FILE * file)
     {
       if (section->sh_type == SHT_GROUP)
        {
-         char * name = SECTION_NAME (section);
-         char * group_name;
+         const char * name = printable_section_name (section);
+         const char * group_name;
          unsigned char * start;
          unsigned char * indices;
          unsigned int entry, j, size;
@@ -5194,15 +6037,26 @@ process_section_groups (FILE * file)
                  strtab_sec = sec;
                  if (strtab)
                    free (strtab);
+
                  strtab = (char *) get_data (NULL, file, strtab_sec->sh_offset,
-                                              1, strtab_sec->sh_size,
-                                              _("string table"));
+                                             1, strtab_sec->sh_size,
+                                             _("string table"));
                  strtab_size = strtab != NULL ? strtab_sec->sh_size : 0;
                }
              group_name = sym->st_name < strtab_size
                ? strtab + sym->st_name : _("<corrupt>");
            }
 
+         /* PR 17531: file: loop.  */
+         if (section->sh_entsize > section->sh_size)
+           {
+             error (_("Section %s has sh_entsize (0x%lx) which is larger than its size (0x%lx)\n"),
+                    printable_section_name (section),
+                    (unsigned long) section->sh_entsize,
+                    (unsigned long) section->sh_size);
+             break;
+           }
+
          start = (unsigned char *) get_data (NULL, file, section->sh_offset,
                                               1, section->sh_size,
                                               _("section data"));
@@ -5233,8 +6087,15 @@ process_section_groups (FILE * file)
 
              if (entry >= elf_header.e_shnum)
                {
-                 error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"),
-                        entry, i, elf_header.e_shnum - 1);
+                 static unsigned num_group_errors = 0;
+
+                 if (num_group_errors ++ < 10)
+                   {
+                     error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"),
+                            entry, i, elf_header.e_shnum - 1);
+                     if (num_group_errors == 10)
+                       warn (_("Futher error messages about overlarge group section indicies suppressed\n"));
+                   }
                  continue;
                }
 
@@ -5242,9 +6103,16 @@ process_section_groups (FILE * file)
                {
                  if (entry)
                    {
-                     error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"),
-                            entry, i,
-                            section_headers_groups [entry]->group_index);
+                     static unsigned num_errs = 0;
+
+                     if (num_errs ++ < 10)
+                       {
+                         error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"),
+                                entry, i,
+                                section_headers_groups [entry]->group_index);
+                         if (num_errs == 10)
+                           warn (_("Further error messages about already contained group sections suppressed\n"));
+                       }
                      continue;
                    }
                  else
@@ -5267,7 +6135,7 @@ process_section_groups (FILE * file)
              if (do_section_groups)
                {
                  sec = section_headers + entry;
-                 printf ("   [%5u]   %s\n", entry, SECTION_NAME (sec));
+                 printf ("   [%5u]   %s\n", entry, printable_section_name (sec));
                }
 
              g = (struct group_list *) xmalloc (sizeof (struct group_list));
@@ -5538,7 +6406,8 @@ process_relocs (FILE * file)
                                offset_from_vma (file, rel_offset, rel_size),
                                rel_size,
                                dynamic_symbols, num_dynamic_syms,
-                               dynamic_strings, dynamic_strings_length, is_rela);
+                               dynamic_strings, dynamic_strings_length,
+                               is_rela, 1);
            }
        }
 
@@ -5575,7 +6444,7 @@ process_relocs (FILE * file)
              if (string_table == NULL)
                printf ("%d", section->sh_name);
              else
-               printf ("'%s'", SECTION_NAME (section));
+               printf ("'%s'", printable_section_name (section));
 
              printf (_(" at offset 0x%lx contains %lu entries:\n"),
                 rel_offset, (unsigned long) (rel_size / section->sh_entsize));
@@ -5607,20 +6476,22 @@ process_relocs (FILE * file)
                      strsec = section_headers + symsec->sh_link;
 
                      strtab = (char *) get_data (NULL, file, strsec->sh_offset,
-                                                  1, strsec->sh_size,
-                                                  _("string table"));
+                                                 1, strsec->sh_size,
+                                                 _("string table"));
                      strtablen = strtab == NULL ? 0 : strsec->sh_size;
                    }
 
                  dump_relocations (file, rel_offset, rel_size,
-                                   symtab, nsyms, strtab, strtablen, is_rela);
+                                   symtab, nsyms, strtab, strtablen,
+                                   is_rela,
+                                   symsec->sh_type == SHT_DYNSYM);
                  if (strtab)
                    free (strtab);
                  free (symtab);
                }
              else
                dump_relocations (file, rel_offset, rel_size,
-                                 NULL, 0, NULL, 0, is_rela);
+                                 NULL, 0, NULL, 0, is_rela, 0);
 
              found = 1;
            }
@@ -5633,71 +6504,53 @@ process_relocs (FILE * file)
   return 1;
 }
 
-/* Process the unwind section.  */
-
-#include "unwind-ia64.h"
-
 /* An absolute address consists of a section and an offset.  If the
    section is NULL, the offset itself is the address, otherwise, the
    address equals to LOAD_ADDRESS(section) + offset.  */
 
 struct absaddr
-  {
-    unsigned short section;
-    bfd_vma offset;
-  };
+{
+  unsigned short section;
+  bfd_vma offset;
+};
 
 #define ABSADDR(a) \
   ((a).section \
    ? section_headers [(a).section].sh_addr + (a).offset \
    : (a).offset)
 
-struct ia64_unw_table_entry
-  {
-    struct absaddr start;
-    struct absaddr end;
-    struct absaddr info;
-  };
-
-struct ia64_unw_aux_info
-  {
-
-    struct ia64_unw_table_entry *table;        /* Unwind table.  */
-    unsigned long table_len;   /* Length of unwind table.  */
-    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.  */
-    unsigned long nsyms;       /* Number of symbols.  */
-    char * strtab;             /* The string table.  */
-    unsigned long strtab_size; /* Size of string table.  */
-  };
+/* Find the nearest symbol at or below ADDR.  Returns the symbol
+   name, if found, and the offset from the symbol to ADDR.  */
 
 static void
 find_symbol_for_address (Elf_Internal_Sym * symtab,
-                        unsigned long nsyms,
-                        const char * strtab,
-                        unsigned long strtab_size,
-                        struct absaddr addr,
-                        const char ** symname,
-                        bfd_vma * offset)
+                        unsigned long      nsyms,
+                        const char *       strtab,
+                        unsigned long      strtab_size,
+                        struct absaddr     addr,
+                        const char **      symname,
+                        bfd_vma *          offset)
 {
   bfd_vma dist = 0x100000;
   Elf_Internal_Sym * sym;
+  Elf_Internal_Sym * beg;
+  Elf_Internal_Sym * end;
   Elf_Internal_Sym * best = NULL;
-  unsigned long i;
 
   REMOVE_ARCH_BITS (addr.offset);
+  beg = symtab;
+  end = symtab + nsyms;
 
-  for (i = 0, sym = symtab; i < nsyms; ++i, ++sym)
+  while (beg < end)
     {
-      bfd_vma value = sym->st_value;
+      bfd_vma value;
+
+      sym = beg + (end - beg) / 2;
 
+      value = sym->st_value;
       REMOVE_ARCH_BITS (value);
 
-      if (ELF_ST_TYPE (sym->st_info) == STT_FUNC
-         && sym->st_name != 0
+      if (sym->st_name != 0
          && (addr.section == SHN_UNDEF || addr.section == sym->st_shndx)
          && addr.offset >= value
          && addr.offset - value < dist)
@@ -5707,6 +6560,11 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
          if (!dist)
            break;
        }
+
+      if (addr.offset < value)
+       end = sym;
+      else
+       beg = sym + 1;
     }
 
   if (best)
@@ -5721,21 +6579,66 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
   *offset = addr.offset;
 }
 
+static int
+symcmp (const void *p, const void *q)
+{
+  Elf_Internal_Sym *sp = (Elf_Internal_Sym *) p;
+  Elf_Internal_Sym *sq = (Elf_Internal_Sym *) q;
+
+  return sp->st_value > sq->st_value ? 1 : (sp->st_value < sq->st_value ? -1 : 0);
+}
+
+/* Process the unwind section.  */
+
+#include "unwind-ia64.h"
+
+struct ia64_unw_table_entry
+{
+  struct absaddr start;
+  struct absaddr end;
+  struct absaddr info;
+};
+
+struct ia64_unw_aux_info
+{
+  struct ia64_unw_table_entry *table;  /* Unwind table.  */
+  unsigned long table_len;             /* Length of unwind table.  */
+  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.  */
+  unsigned long nsyms;                 /* Number of symbols.  */
+  Elf_Internal_Sym * funtab;           /* Sorted table of STT_FUNC symbols.  */
+  unsigned long nfuns;                 /* Number of entries in funtab.  */
+  char * strtab;                       /* The string table.  */
+  unsigned long strtab_size;           /* Size of string table.  */
+};
+
 static void
 dump_ia64_unwind (struct ia64_unw_aux_info * aux)
 {
   struct ia64_unw_table_entry * tp;
+  unsigned long j, nfuns;
   int in_body;
 
+  aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym));
+  for (nfuns = 0, j = 0; j < aux->nsyms; j++)
+    if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC)
+      aux->funtab[nfuns++] = aux->symtab[j];
+  aux->nfuns = nfuns;
+  qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp);
+
   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 unsigned char * end;
       const char * procname;
 
-      find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
+      find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab,
                               aux->strtab_size, tp->start, &procname, &offset);
 
       fputs ("\n<", stdout);
@@ -5755,6 +6658,18 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
       printf ("], info at +0x%lx\n",
              (unsigned long) (tp->info.offset - aux->seg_base));
 
+      /* PR 17531: file: 86232b32.  */
+      if (aux->info == NULL)
+       continue;
+
+      /* PR 17531: file: 0997b4d1.  */
+      if ((ABSADDR (tp->info) - aux->info_addr) >= aux->info_size)
+       {
+         warn (_("Invalid offset %lx in table entry %ld\n"),
+               (long) tp->info.offset, (long) (tp - aux->table));
+         continue;
+       }
+
       head = aux->info + (ABSADDR (tp->info) - aux->info_addr);
       stamp = byte_get ((unsigned char *) head, sizeof (stamp));
 
@@ -5772,12 +6687,18 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
        }
 
       in_body = 0;
-      for (dp = head + 8; dp < head + 8 + eh_addr_size * UNW_LENGTH (stamp);)
+      end = head + 8 + eh_addr_size * UNW_LENGTH (stamp);
+      /* PR 17531: file: 16ceda89.  */
+      if (end > aux->info + aux->info_size)
+       end = aux->info + aux->info_size;
+      for (dp = head + 8; dp < end;)
        dp = unw_decode (dp, in_body, & in_body);
     }
+
+  free (aux->funtab);
 }
 
-static int
+static bfd_boolean
 slurp_ia64_unwind_table (FILE * file,
                         struct ia64_unw_aux_info * aux,
                         Elf_Internal_Shdr * sec)
@@ -5793,13 +6714,15 @@ slurp_ia64_unwind_table (FILE * file,
   Elf_Internal_Sym * sym;
   const char * relname;
 
+  aux->table_len = 0;
+
   /* First, find the starting address of the segment that includes
      this section: */
 
   if (elf_header.e_phnum)
     {
       if (! get_program_headers (file))
-         return 0;
+         return FALSE;
 
       for (seg = program_headers;
           seg < program_headers + elf_header.e_phnum;
@@ -5822,12 +6745,14 @@ slurp_ia64_unwind_table (FILE * file,
   table = (unsigned char *) get_data (NULL, file, sec->sh_offset, 1, size,
                                       _("unwind table"));
   if (!table)
-    return 0;
+    return FALSE;
 
+  aux->table_len = size / (3 * eh_addr_size);
   aux->table = (struct ia64_unw_table_entry *)
-      xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0]));
+    xcmalloc (aux->table_len, sizeof (aux->table[0]));
   tep = aux->table;
-  for (tp = table; tp < table + size; ++tep)
+
+  for (tp = table; tp <= table + size - (3 * eh_addr_size); ++tep)
     {
       tep->start.section = SHN_UNDEF;
       tep->end.section   = SHN_UNDEF;
@@ -5853,22 +6778,41 @@ slurp_ia64_unwind_table (FILE * file,
 
       if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
                              & rela, & nrelas))
-       return 0;
+       {
+         free (aux->table);
+         aux->table = NULL;
+         aux->table_len = 0;
+         return FALSE;
+       }
 
       for (rp = rela; rp < rela + nrelas; ++rp)
        {
          relname = elf_ia64_reloc_type (get_reloc_type (rp->r_info));
          sym = aux->symtab + get_reloc_symindex (rp->r_info);
 
+         /* PR 17531: file: 9fa67536.  */
+         if (relname == NULL)
+           {
+             warn (_("Skipping unknown relocation type: %u\n"), get_reloc_type (rp->r_info));
+             continue;
+           }
+
          if (! const_strneq (relname, "R_IA64_SEGREL"))
            {
-             warn (_("Skipping unexpected relocation type %s\n"), relname);
+             warn (_("Skipping unexpected relocation type: %s\n"), relname);
              continue;
            }
 
          i = rp->r_offset / (3 * eh_addr_size);
 
-         switch (rp->r_offset/eh_addr_size % 3)
+         /* PR 17531: file: 5bc8d9bf.  */
+         if (i >= aux->table_len)
+           {
+             warn (_("Skipping reloc with overlarge offset: %lx\n"), i);
+             continue;
+           }
+
+         switch (rp->r_offset / eh_addr_size % 3)
            {
            case 0:
              aux->table[i].start.section = sym->st_shndx;
@@ -5890,8 +6834,7 @@ slurp_ia64_unwind_table (FILE * file,
       free (rela);
     }
 
-  aux->table_len = size / (3 * eh_addr_size);
-  return 1;
+  return TRUE;
 }
 
 static void
@@ -5913,7 +6856,11 @@ ia64_process_unwind (FILE * file)
          aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms);
 
          strsec = section_headers + sec->sh_link;
-         assert (aux.strtab == NULL);
+         if (aux.strtab != NULL)
+           {
+             error (_("Multiple auxillary string tables encountered\n"));
+             free (aux.strtab);
+           }
          aux.strtab = (char *) get_data (NULL, file, strsec->sh_offset,
                                           1, strsec->sh_size,
                                           _("string table"));
@@ -5931,13 +6878,16 @@ ia64_process_unwind (FILE * file)
       char * suffix;
       size_t len, len2;
 
-      for (i = unwstart, sec = section_headers + unwstart;
+      for (i = unwstart, sec = section_headers + unwstart, unwsec = NULL;
           i < elf_header.e_shnum; ++i, ++sec)
        if (sec->sh_type == SHT_IA_64_UNWIND)
          {
            unwsec = sec;
            break;
          }
+      /* We have already counted the number of SHT_IA64_UNWIND
+        sections so the loop above should never fail.  */
+      assert (unwsec != NULL);
 
       unwstart = i + 1;
       len = sizeof (ELF_STRING_ia64_unwind_once) - 1;
@@ -5945,18 +6895,26 @@ 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;
 
-         for (; g != NULL; g = g->next)
+         if (section_headers_groups == NULL
+             || section_headers_groups [i] == NULL)
+           i = elf_header.e_shnum;
+         else
            {
-             sec = section_headers + g->section_index;
+             g = section_headers_groups [i]->root;
 
-             if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info))
-               break;
-           }
+             for (; g != NULL; g = g->next)
+               {
+                 sec = section_headers + g->section_index;
 
-         if (g == NULL)
-           i = elf_header.e_shnum;
+                 if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info))
+                   break;
+               }
+
+             if (g == NULL)
+               i = elf_header.e_shnum;
+           }
        }
       else if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once, len))
        {
@@ -5992,14 +6950,14 @@ ia64_process_unwind (FILE * file)
          if (string_table == NULL)
            printf ("%d", unwsec->sh_name);
          else
-           printf (_("'%s'"), SECTION_NAME (unwsec));
+           printf ("'%s'", printable_section_name (unwsec));
        }
       else
        {
          aux.info_addr = sec->sh_addr;
          aux.info = (unsigned char *) get_data (NULL, file, sec->sh_offset, 1,
-                                                 sec->sh_size,
-                                                 _("unwind info"));
+                                                sec->sh_size,
+                                                _("unwind info"));
          aux.info_size = aux.info == NULL ? 0 : sec->sh_size;
 
          printf (_("\nUnwind section "));
@@ -6007,15 +6965,14 @@ ia64_process_unwind (FILE * file)
          if (string_table == NULL)
            printf ("%d", unwsec->sh_name);
          else
-           printf (_("'%s'"), SECTION_NAME (unwsec));
+           printf ("'%s'", printable_section_name (unwsec));
 
          printf (_(" at offset 0x%lx contains %lu entries:\n"),
                  (unsigned long) unwsec->sh_offset,
                  (unsigned long) (unwsec->sh_size / (3 * eh_addr_size)));
 
-         (void) slurp_ia64_unwind_table (file, & aux, unwsec);
-
-         if (aux.table_len > 0)
+         if (slurp_ia64_unwind_table (file, & aux, unwsec)
+             && aux.table_len > 0)
            dump_ia64_unwind (& aux);
 
          if (aux.table)
@@ -6037,7 +6994,7 @@ struct hppa_unw_table_entry
   {
     struct absaddr start;
     struct absaddr end;
-    unsigned int Cannot_unwind:1;                      /* 0 */
+    unsigned int Cannot_unwind:1;              /* 0 */
     unsigned int Millicode:1;                  /* 1 */
     unsigned int Millicode_save_sr0:1;         /* 2 */
     unsigned int Region_description:2;         /* 3..4 */
@@ -6046,52 +7003,62 @@ struct hppa_unw_table_entry
     unsigned int Entry_FR:4;     /* number saved */    /* 7..10 */
     unsigned int Entry_GR:5;     /* number saved */    /* 11..15 */
     unsigned int Args_stored:1;                        /* 16 */
-    unsigned int Variable_Frame:1;                     /* 17 */
-    unsigned int Separate_Package_Body:1;              /* 18 */
+    unsigned int Variable_Frame:1;             /* 17 */
+    unsigned int Separate_Package_Body:1;      /* 18 */
     unsigned int Frame_Extension_Millicode:1;  /* 19 */
-    unsigned int Stack_Overflow_Check:1;               /* 20 */
-    unsigned int Two_Instruction_SP_Increment:1;       /* 21 */
+    unsigned int Stack_Overflow_Check:1;       /* 20 */
+    unsigned int Two_Instruction_SP_Increment:1;/* 21 */
     unsigned int Ada_Region:1;                 /* 22 */
     unsigned int cxx_info:1;                   /* 23 */
-    unsigned int cxx_try_catch:1;                      /* 24 */
-    unsigned int sched_entry_seq:1;                    /* 25 */
+    unsigned int cxx_try_catch:1;              /* 24 */
+    unsigned int sched_entry_seq:1;            /* 25 */
     unsigned int reserved2:1;                  /* 26 */
-    unsigned int Save_SP:1;                            /* 27 */
-    unsigned int Save_RP:1;                            /* 28 */
+    unsigned int Save_SP:1;                    /* 27 */
+    unsigned int Save_RP:1;                    /* 28 */
     unsigned int Save_MRP_in_frame:1;          /* 29 */
     unsigned int extn_ptr_defined:1;           /* 30 */
-    unsigned int Cleanup_defined:1;                    /* 31 */
+    unsigned int Cleanup_defined:1;            /* 31 */
 
-    unsigned int MPE_XL_interrupt_marker:1;            /* 0 */
-    unsigned int HP_UX_interrupt_marker:1;             /* 1 */
+    unsigned int MPE_XL_interrupt_marker:1;    /* 0 */
+    unsigned int HP_UX_interrupt_marker:1;     /* 1 */
     unsigned int Large_frame:1;                        /* 2 */
-    unsigned int Pseudo_SP_Set:1;                      /* 3 */
+    unsigned int Pseudo_SP_Set:1;              /* 3 */
     unsigned int reserved4:1;                  /* 4 */
     unsigned int Total_frame_size:27;          /* 5..31 */
   };
 
 struct hppa_unw_aux_info
-  {
-    struct hppa_unw_table_entry *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.  */
-    unsigned long nsyms;       /* Number of symbols.  */
-    char * strtab;             /* The string table.  */
-    unsigned long strtab_size; /* Size of string table.  */
-  };
+{
+  struct hppa_unw_table_entry * 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.  */
+  unsigned long nsyms;                 /* Number of symbols.  */
+  Elf_Internal_Sym * funtab;           /* Sorted table of STT_FUNC symbols.  */
+  unsigned long nfuns;                 /* Number of entries in funtab.  */
+  char * strtab;                       /* The string table.  */
+  unsigned long strtab_size;           /* Size of string table.  */
+};
 
 static void
 dump_hppa_unwind (struct hppa_unw_aux_info * aux)
 {
   struct hppa_unw_table_entry * tp;
+  unsigned long j, nfuns;
+
+  aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym));
+  for (nfuns = 0, j = 0; j < aux->nsyms; j++)
+    if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC)
+      aux->funtab[nfuns++] = aux->symtab[j];
+  aux->nfuns = nfuns;
+  qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp);
 
   for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
     {
       bfd_vma offset;
       const char * procname;
 
-      find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
+      find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab,
                               aux->strtab_size, tp->start, &procname,
                               &offset);
 
@@ -6145,6 +7112,8 @@ dump_hppa_unwind (struct hppa_unw_aux_info * aux)
     }
 
   printf ("\n");
+
+  free (aux->funtab);
 }
 
 static int
@@ -6324,7 +7293,11 @@ hppa_process_unwind (FILE * file)
          aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms);
 
          strsec = section_headers + sec->sh_link;
-         assert (aux.strtab == NULL);
+         if (aux.strtab != NULL)
+           {
+             error (_("Multiple auxillary string tables encountered\n"));
+             free (aux.strtab);
+           }
          aux.strtab = (char *) get_data (NULL, file, strsec->sh_offset,
                                           1, strsec->sh_size,
                                           _("string table"));
@@ -6341,10 +7314,8 @@ hppa_process_unwind (FILE * file)
     {
       if (streq (SECTION_NAME (sec), ".PARISC.unwind"))
        {
-         printf (_("\nUnwind section "));
-         printf (_("'%s'"), SECTION_NAME (sec));
-
-         printf (_(" at offset 0x%lx contains %lu entries:\n"),
+         printf (_("\nUnwind section '%s' at offset 0x%lx contains %lu entries:\n"),
+                 printable_section_name (sec),
                  (unsigned long) sec->sh_offset,
                  (unsigned long) (sec->sh_size / (2 * eh_addr_size + 8)));
 
@@ -6379,6 +7350,8 @@ struct arm_unw_aux_info
   FILE *              file;            /* The file containing the unwind sections.  */
   Elf_Internal_Sym *  symtab;          /* The file's symbol table.  */
   unsigned long       nsyms;           /* Number of symbols.  */
+  Elf_Internal_Sym *  funtab;          /* Sorted table of STT_FUNC symbols.  */
+  unsigned long       nfuns;           /* Number of these symbols.  */
   char *              strtab;          /* The file's string table.  */
   unsigned long       strtab_size;     /* Size of string table.  */
 };
@@ -6393,7 +7366,7 @@ arm_print_vma_and_name (struct arm_unw_aux_info *aux,
   if (addr.section == SHN_UNDEF)
     addr.offset = fn;
 
-  find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
+  find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab,
                           aux->strtab_size, addr, &procname,
                           &sym_offset);
 
@@ -6448,6 +7421,9 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
   unsigned int word;
   bfd_boolean wrapped;
 
+  if (sec == NULL || arm_sec == NULL)
+    return FALSE;
+
   addr->section = SHN_UNDEF;
   addr->offset = 0;
 
@@ -6472,7 +7448,10 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
           ++relsec)
        {
          if (relsec->sh_info >= elf_header.e_shnum
-             || section_headers + relsec->sh_info != sec)
+             || section_headers + relsec->sh_info != sec
+             /* PR 15745: Check the section type as well.  */
+             || (relsec->sh_type != SHT_REL
+                 && relsec->sh_type != SHT_RELA))
            continue;
 
          arm_sec->rel_type = relsec->sh_type;
@@ -6482,19 +7461,15 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
                                     relsec->sh_size,
                                     & arm_sec->rela, & arm_sec->nrelas))
                return FALSE;
-             break;
            }
-         else if (relsec->sh_type == SHT_RELA)
+         else /* relsec->sh_type == SHT_RELA */
            {
              if (!slurp_rela_relocs (aux->file, relsec->sh_offset,
                                      relsec->sh_size,
                                      & arm_sec->rela, & arm_sec->nrelas))
                return FALSE;
-             break;
            }
-         else
-           warn (_("unexpected relocation type (%d) for section %d"),
-                 relsec->sh_type, relsec->sh_info);
+         break;
        }
 
       arm_sec->next_rela = arm_sec->rela;
@@ -6504,9 +7479,20 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
   if (arm_sec->data == NULL)
     return FALSE;
 
+  /* If the offset is invalid then fail.  */
+  if (word_offset > sec->sh_size - 4)
+    return FALSE;
+
   /* Get the word at the required offset.  */
   word = byte_get (arm_sec->data + word_offset, 4);
 
+  /* PR 17531: file: id:000001,src:001266+003044,op:splice,rep:128.  */
+  if (arm_sec->rela == NULL)
+    {
+      * wordp = word;
+      return TRUE;
+    }
+
   /* Look through the relocs to find the one that applies to the provided offset.  */
   wrapped = FALSE;
   for (rp = arm_sec->next_rela; rp != arm_sec->rela + arm_sec->nrelas; rp++)
@@ -6531,7 +7517,9 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
       if (rp->r_offset < word_offset)
        continue;
 
-      sym = aux->symtab + ELF32_R_SYM (rp->r_info);
+      /* PR 17531: file: 027-161405-0.004  */
+      if (aux->symtab == NULL)
+       continue;
 
       if (arm_sec->rel_type == SHT_REL)
        {
@@ -6542,8 +7530,21 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
       else if (arm_sec->rel_type == SHT_RELA)
        offset = rp->r_addend;
       else
-       abort ();
+       {
+         error (_("Unknown section relocation type %d encountered\n"),
+                arm_sec->rel_type);
+         break;
+       }
+
+      /* PR 17531 file: 027-1241568-0.004.  */
+      if (ELF32_R_SYM (rp->r_info) >= aux->nsyms)
+       {
+         error (_("Bad symbol index in unwind relocation (%lu > %lu)\n"),
+                (unsigned long) ELF32_R_SYM (rp->r_info), aux->nsyms);
+         break;
+       }
 
+      sym = aux->symtab + ELF32_R_SYM (rp->r_info);
       offset += sym->st_value;
       prelval = offset - (arm_sec->sec->sh_addr + rp->r_offset);
 
@@ -6551,38 +7552,54 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
       if (elf_header.e_machine == EM_ARM)
        {
          relname = elf_arm_reloc_type (ELF32_R_TYPE (rp->r_info));
+         if (relname == NULL)
+           {
+             warn (_("Skipping unknown ARM relocation type: %d\n"),
+                   (int) ELF32_R_TYPE (rp->r_info));
+             continue;
+           }
 
          if (streq (relname, "R_ARM_NONE"))
              continue;
-         
+
          if (! streq (relname, "R_ARM_PREL31"))
            {
-             warn (_("Skipping unexpected relocation type %s\n"), relname);
+             warn (_("Skipping unexpected ARM relocation type %s\n"), relname);
              continue;
            }
        }
       else if (elf_header.e_machine == EM_TI_C6000)
        {
          relname = elf_tic6x_reloc_type (ELF32_R_TYPE (rp->r_info));
-         
+         if (relname == NULL)
+           {
+             warn (_("Skipping unknown C6000 relocation type: %d\n"),
+                   (int) ELF32_R_TYPE (rp->r_info));
+             continue;
+           }
+
          if (streq (relname, "R_C6000_NONE"))
            continue;
 
          if (! streq (relname, "R_C6000_PREL31"))
            {
-             warn (_("Skipping unexpected relocation type %s\n"), relname);
+             warn (_("Skipping unexpected C6000 relocation type %s\n"), relname);
              continue;
            }
 
          prelval >>= 1;
        }
       else
-       /* This function currently only supports ARM and TI unwinders.  */
-       abort ();
+       {
+         /* This function currently only supports ARM and TI unwinders.  */
+         warn (_("Only TI and ARM unwinders are currently supported\n"));
+         break;
+       }
 
       word = (word & ~ (bfd_vma) 0x7fffffff) | (prelval & 0x7fffffff);
       addr->section = sym->st_shndx;
       addr->offset = offset;
+
       if (sym_name)
        * sym_name = sym->st_name;
       break;
@@ -6596,8 +7613,8 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
 
 static const char *tic6x_unwind_regnames[16] =
 {
-  "A15", "B15", "B14", "B13", "B12", "B11", "B10", "B3", 
-  "A14", "A13", "A12", "A11", "A10", 
+  "A15", "B15", "B14", "B13", "B12", "B11", "B10", "B3",
+  "A14", "A13", "A12", "A11", "A10",
   "[invalid reg 13]", "[invalid reg 14]", "[invalid reg 15]"
 };
 
@@ -6644,11 +7661,13 @@ decode_tic6x_unwind_regmask (unsigned int mask)
   printf ("0x%02x ", OP)
 
 static void
-decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux,
-                           unsigned int word, unsigned int remaining,
-                           unsigned int more_words,
-                           bfd_vma data_offset, Elf_Internal_Shdr *data_sec,
-                           struct arm_section *data_arm_sec)
+decode_arm_unwind_bytecode (struct arm_unw_aux_info *  aux,
+                           unsigned int               word,
+                           unsigned int               remaining,
+                           unsigned int               more_words,
+                           bfd_vma                    data_offset,
+                           Elf_Internal_Shdr *        data_sec,
+                           struct arm_section *       data_arm_sec)
 {
   struct absaddr addr;
 
@@ -6770,11 +7789,15 @@ decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux,
              if ((buf[i] & 0x80) == 0)
                break;
            }
-         assert (i < sizeof (buf));
-         offset = read_uleb128 (buf, &len);
-         assert (len == i + 1);
-         offset = offset * 4 + 0x204;
-         printf ("vsp = vsp + %ld", offset);
+         if (i == sizeof (buf))
+           printf (_("corrupt change to vsp"));
+         else
+           {
+             offset = read_uleb128 (buf, &len, buf + i + 1);
+             assert (len == i + 1);
+             offset = offset * 4 + 0x204;
+             printf ("vsp = vsp + %ld", offset);
+           }
        }
       else if (op == 0xb3 || op == 0xc8 || op == 0xc9)
        {
@@ -6851,11 +7874,13 @@ decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux,
 }
 
 static void
-decode_tic6x_unwind_bytecode (struct arm_unw_aux_info *aux,
-                           unsigned int word, unsigned int remaining,
-                           unsigned int more_words,
-                           bfd_vma data_offset, Elf_Internal_Shdr *data_sec,
-                           struct arm_section *data_arm_sec)
+decode_tic6x_unwind_bytecode (struct arm_unw_aux_info *  aux,
+                             unsigned int               word,
+                             unsigned int               remaining,
+                             unsigned int               more_words,
+                             bfd_vma                    data_offset,
+                             Elf_Internal_Shdr *        data_sec,
+                             struct arm_section *       data_arm_sec)
 {
   struct absaddr addr;
 
@@ -6966,8 +7991,15 @@ decode_tic6x_unwind_bytecode (struct arm_unw_aux_info *aux,
              if ((buf[i] & 0x80) == 0)
                break;
            }
-         assert (i < sizeof (buf));
-         offset = read_uleb128 (buf, &len);
+         /* PR 17531: file: id:000001,src:001906+004739,op:splice,rep:2.  */
+         if (i == sizeof (buf))
+           {
+             printf ("<corrupt sp adjust>\n");
+             warn (_("Corrupt stack pointer adjustment detected\n"));
+             return;
+           }
+
+         offset = read_uleb128 (buf, &len, buf + i + 1);
          assert (len == i + 1);
          offset = offset * 8 + 0x408;
          printf (_("sp = sp + %ld"), offset);
@@ -7082,9 +8114,9 @@ decode_arm_unwind (struct arm_unw_aux_info *  aux,
   else
     {
       /* ARM EHABI Section 6.3:
-        
+
         An exception-handling table entry for the compact model looks like:
-        
+
            31 30-28 27-24 23-0
           -- ----- ----- ----
             1   0   index Data for personalityRoutine[index]    */
@@ -7149,7 +8181,7 @@ decode_arm_unwind (struct arm_unw_aux_info *  aux,
       break;
 
     default:
-      error (_("Unsupported architecture type %d encountered when decoding unwind table"),
+      error (_("Unsupported architecture type %d encountered when decoding unwind table\n"),
             elf_header.e_machine);
     }
 
@@ -7161,11 +8193,19 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
 {
   struct arm_section exidx_arm_sec, extab_arm_sec;
   unsigned int i, exidx_len;
+  unsigned long j, nfuns;
 
   memset (&exidx_arm_sec, 0, sizeof (exidx_arm_sec));
   memset (&extab_arm_sec, 0, sizeof (extab_arm_sec));
   exidx_len = exidx_sec->sh_size / 8;
 
+  aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym));
+  for (nfuns = 0, j = 0; j < aux->nsyms; j++)
+    if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC)
+      aux->funtab[nfuns++] = aux->symtab[j];
+  aux->nfuns = nfuns;
+  qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp);
+
   for (i = 0; i < exidx_len; i++)
     {
       unsigned int exidx_fn, exidx_entry;
@@ -7179,6 +8219,7 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
          || ! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec,
                                        8 * i + 4, & exidx_entry, & entry_addr, NULL))
        {
+         free (aux->funtab);
          arm_free_section (& exidx_arm_sec);
          arm_free_section (& extab_arm_sec);
          return;
@@ -7242,6 +8283,7 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
 
   printf ("\n");
 
+  free (aux->funtab);
   arm_free_section (&exidx_arm_sec);
   arm_free_section (&extab_arm_sec);
 }
@@ -7268,8 +8310,8 @@ arm_process_unwind (FILE *file)
       sec_type = SHT_C6000_UNWIND;
       break;
 
-    default: 
-      error (_("Unsupported architecture type %d encountered when processing unwind table"),
+    default:
+      error (_("Unsupported architecture type %d encountered when processing unwind table\n"),
             elf_header.e_machine);
       return;
     }
@@ -7287,7 +8329,13 @@ arm_process_unwind (FILE *file)
          aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms);
 
          strsec = section_headers + sec->sh_link;
-         assert (aux.strtab == NULL);
+
+         /* PR binutils/17531 file: 011-12666-0.004.  */
+         if (aux.strtab != NULL)
+           {
+             error (_("Multiple string tables found in file.\n"));
+             free (aux.strtab);
+           }
          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;
@@ -7304,7 +8352,7 @@ arm_process_unwind (FILE *file)
        if (sec->sh_type == sec_type)
          {
            printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"),
-                   SECTION_NAME (sec),
+                   printable_section_name (sec),
                    (unsigned long) sec->sh_offset,
                    (unsigned long) (sec->sh_size / (2 * eh_addr_size)));
 
@@ -7340,7 +8388,10 @@ process_unwind (FILE * file)
 
   for (i = 0; handlers[i].handler != NULL; i++)
     if (elf_header.e_machine == handlers[i].machtype)
-      return handlers[i].handler (file);
+      {
+       handlers[i].handler (file);
+       return;
+      }
 
   printf (_("\nThe decoding of unwind sections for machine type %s is not currently supported.\n"),
          get_machine_name (elf_header.e_machine));
@@ -7380,19 +8431,28 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry)
       if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
        printf (_("Interface Version: %s"), GET_DYNAMIC_NAME (entry->d_un.d_val));
       else
-       printf (_("<corrupt: %" BFD_VMA_FMT "d>"), entry->d_un.d_ptr);
+       {
+         char buf[40];
+         sprintf_vma (buf, entry->d_un.d_ptr);
+         /* Note: coded this way so that there is a single string for translation.  */
+         printf (_("<corrupt: %s>"), buf);
+       }
       break;
 
     case DT_MIPS_TIME_STAMP:
       {
        char timebuf[20];
        struct tm * tmp;
-
        time_t atime = entry->d_un.d_val;
+
        tmp = gmtime (&atime);
-       snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u",
-                 tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
-                 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+       /* PR 17531: file: 6accc532.  */
+       if (tmp == NULL)
+         snprintf (timebuf, sizeof (timebuf), _("<corrupt>"));
+       else
+         snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u",
+                   tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
+                   tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
        printf (_("Time Stamp: %s"), timebuf);
       }
       break;
@@ -7575,11 +8635,11 @@ get_32bit_dynamic_section (FILE * file)
   if (!edyn)
     return 0;
 
-/* SGI's ELF has more than one section in the DYNAMIC segment, and we
-   might not have the luxury of section headers.  Look for the DT_NULL
-   terminator to determine the number of entries.  */
+  /* SGI's ELF has more than one section in the DYNAMIC segment, and we
+     might not have the luxury of section headers.  Look for the DT_NULL
+     terminator to determine the number of entries.  */
   for (ext = edyn, dynamic_nent = 0;
-       (char *) ext < (char *) edyn + dynamic_size;
+       (char *) ext < (char *) edyn + dynamic_size - sizeof (* entry);
        ext++)
     {
       dynamic_nent++;
@@ -7591,7 +8651,8 @@ get_32bit_dynamic_section (FILE * file)
                                                   sizeof (* entry));
   if (dynamic_section == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory allocating space for %lu dynamic entries\n"),
+            (unsigned long) dynamic_nent);
       free (edyn);
       return 0;
     }
@@ -7616,16 +8677,18 @@ get_64bit_dynamic_section (FILE * file)
   Elf64_External_Dyn * ext;
   Elf_Internal_Dyn * entry;
 
+  /* Read in the data.  */
   edyn = (Elf64_External_Dyn *) get_data (NULL, file, dynamic_addr, 1,
                                           dynamic_size, _("dynamic section"));
   if (!edyn)
     return 0;
 
-/* SGI's ELF has more than one section in the DYNAMIC segment, and we
-   might not have the luxury of section headers.  Look for the DT_NULL
-   terminator to determine the number of entries.  */
+  /* SGI's ELF has more than one section in the DYNAMIC segment, and we
+     might not have the luxury of section headers.  Look for the DT_NULL
+     terminator to determine the number of entries.  */
   for (ext = edyn, dynamic_nent = 0;
-       (char *) ext < (char *) edyn + dynamic_size;
+       /* PR 17533 file: 033-67080-0.004 - do not read off the end of the buffer.  */
+       (char *) ext < ((char *) edyn) + dynamic_size - sizeof (* ext);
        ext++)
     {
       dynamic_nent++;
@@ -7637,11 +8700,13 @@ get_64bit_dynamic_section (FILE * file)
                                                   sizeof (* entry));
   if (dynamic_section == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory allocating space for %lu dynamic entries\n"),
+            (unsigned long) dynamic_nent);
       free (edyn);
       return 0;
     }
 
+  /* Convert from external to internal formats.  */
   for (ext = edyn, entry = dynamic_section;
        entry < dynamic_section + dynamic_nent;
        ext++, entry++)
@@ -7742,6 +8807,7 @@ process_dynamic_section (FILE * file)
            section.sh_entsize = sizeof (Elf32_External_Sym);
          else
            section.sh_entsize = sizeof (Elf64_External_Sym);
+         section.sh_name = string_table_length;
 
          dynamic_symbols = GET_ELF_SYMBOLS (file, &section, & num_dynamic_syms);
          if (num_dynamic_syms < 1)
@@ -7811,7 +8877,11 @@ process_dynamic_section (FILE * file)
            {
              /* Note: these braces are necessary to avoid a syntax
                 error from the SunOS4 C compiler.  */
-             assert (sizeof (Elf_External_Syminfo) == entry->d_un.d_val);
+             /* PR binutils/17531: A corrupt file can trigger this test.
+                So do not use an assert, instead generate an error message.  */
+             if (sizeof (Elf_External_Syminfo) != entry->d_un.d_val)
+               error (_("Bad value (%d) for SYMINENT entry\n"),
+                      (int) entry->d_un.d_val);
            }
          else if (entry->d_tag == DT_SYMINSZ)
            syminsz = entry->d_un.d_val;
@@ -7836,7 +8906,8 @@ process_dynamic_section (FILE * file)
          dynamic_syminfo = (Elf_Internal_Syminfo *) malloc (syminsz);
          if (dynamic_syminfo == NULL)
            {
-             error (_("Out of memory\n"));
+             error (_("Out of memory allocating %lu byte for dynamic symbol info\n"),
+                    (unsigned long) syminsz);
              return 0;
            }
 
@@ -7854,8 +8925,8 @@ process_dynamic_section (FILE * file)
     }
 
   if (do_dynamic && dynamic_addr)
-    printf (_("\nDynamic section at offset 0x%lx contains %u entries:\n"),
-           dynamic_addr, dynamic_nent);
+    printf (_("\nDynamic section at offset 0x%lx contains %lu entries:\n"),
+           dynamic_addr, (unsigned long) dynamic_nent);
   if (do_dynamic)
     printf (_("  Tag        Type                         Name/Value\n"));
 
@@ -8055,10 +9126,70 @@ process_dynamic_section (FILE * file)
                      printf (" NODUMP");
                      val ^= DF_1_NODUMP;
                    }
-                 if (val & DF_1_CONLFAT)
+                 if (val & DF_1_CONFALT)
+                   {
+                     printf (" CONFALT");
+                     val ^= DF_1_CONFALT;
+                   }
+                 if (val & DF_1_ENDFILTEE)
+                   {
+                     printf (" ENDFILTEE");
+                     val ^= DF_1_ENDFILTEE;
+                   }
+                 if (val & DF_1_DISPRELDNE)
+                   {
+                     printf (" DISPRELDNE");
+                     val ^= DF_1_DISPRELDNE;
+                   }
+                 if (val & DF_1_DISPRELPND)
+                   {
+                     printf (" DISPRELPND");
+                     val ^= DF_1_DISPRELPND;
+                   }
+                 if (val & DF_1_NODIRECT)
+                   {
+                     printf (" NODIRECT");
+                     val ^= DF_1_NODIRECT;
+                   }
+                 if (val & DF_1_IGNMULDEF)
+                   {
+                     printf (" IGNMULDEF");
+                     val ^= DF_1_IGNMULDEF;
+                   }
+                 if (val & DF_1_NOKSYMS)
+                   {
+                     printf (" NOKSYMS");
+                     val ^= DF_1_NOKSYMS;
+                   }
+                 if (val & DF_1_NOHDR)
+                   {
+                     printf (" NOHDR");
+                     val ^= DF_1_NOHDR;
+                   }
+                 if (val & DF_1_EDITED)
                    {
-                     printf (" CONLFAT");
-                     val ^= DF_1_CONLFAT;
+                     printf (" EDITED");
+                     val ^= DF_1_EDITED;
+                   }
+                 if (val & DF_1_NORELOC)
+                   {
+                     printf (" NORELOC");
+                     val ^= DF_1_NORELOC;
+                   }
+                 if (val & DF_1_SYMINTPOSE)
+                   {
+                     printf (" SYMINTPOSE");
+                     val ^= DF_1_SYMINTPOSE;
+                   }
+                 if (val & DF_1_GLOBAUDIT)
+                   {
+                     printf (" GLOBAUDIT");
+                     val ^= DF_1_GLOBAUDIT;
+                   }
+                 if (val & DF_1_SINGLETON)
+                   {
+                     printf (" SINGLETON");
+                     val ^= DF_1_SINGLETON;
                    }
                  if (val != 0)
                    printf (" %lx", val);
@@ -8207,9 +9338,14 @@ process_dynamic_section (FILE * file)
              time_t atime = entry->d_un.d_val;
 
              tmp = gmtime (&atime);
-             printf ("%04u-%02u-%02uT%02u:%02u:%02u\n",
-                     tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
-                     tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+             /* PR 17533 file: 041-1244816-0.004.  */
+             if (tmp == NULL)
+               printf (_("<corrupt time val: %lx"),
+                       (unsigned long) atime);
+             else
+               printf ("%04u-%02u-%02uT%02u:%02u:%02u\n",
+                       tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
+                       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 
            }
          break;
@@ -8316,17 +9452,15 @@ process_version_sections (FILE * file)
 
            found = 1;
 
-           printf
-             (_("\nVersion definition section '%s' contains %u entries:\n"),
-              SECTION_NAME (section), section->sh_info);
+           printf (_("\nVersion definition section '%s' contains %u entries:\n"),
+                   printable_section_name (section),
+                   section->sh_info);
 
            printf (_("  Addr: 0x"));
            printf_vma (section->sh_addr);
-           printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
+           printf (_("  Offset: %#08lx  Link: %u (%s)"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   section->sh_link < elf_header.e_shnum
-                   ? SECTION_NAME (section_headers + section->sh_link)
-                   : _("<corrupt>"));
+                   printable_section_name_from_index (section->sh_link));
 
            edefs = (Elf_External_Verdef *)
                 get_data (NULL, file, section->sh_offset, 1,section->sh_size,
@@ -8345,8 +9479,8 @@ process_version_sections (FILE * file)
                int j;
                int isum;
 
-               /* Check for negative or very large indicies.  */
-               if ((unsigned char *) edefs + idx < (unsigned char *) edefs)
+               /* Check for very large indicies.  */
+               if (idx > (size_t) (endbuf - (char *) edefs))
                  break;
 
                vstart = ((char *) edefs) + idx;
@@ -8370,8 +9504,7 @@ process_version_sections (FILE * file)
                        ent.vd_ndx, ent.vd_cnt);
 
                /* Check for overflow.  */
-               if ((unsigned char *)(vstart + ent.vd_aux) < (unsigned char *) vstart
-                   || (unsigned char *)(vstart + ent.vd_aux) > (unsigned char *) endbuf)
+               if (ent.vd_aux > (size_t) (endbuf - vstart))
                  break;
 
                vstart += ent.vd_aux;
@@ -8391,8 +9524,7 @@ process_version_sections (FILE * file)
                for (j = 1; j < ent.vd_cnt; j++)
                  {
                    /* Check for overflow.  */
-                   if ((unsigned char *)(vstart + aux.vda_next) < (unsigned char *) vstart
-                       || (unsigned char *)(vstart + aux.vda_next) > (unsigned char *) endbuf)
+                   if (aux.vda_next > (size_t) (endbuf - vstart))
                      break;
 
                    isum   += aux.vda_next;
@@ -8416,6 +9548,10 @@ process_version_sections (FILE * file)
                if (j < ent.vd_cnt)
                  printf (_("  Version def aux past end of section\n"));
 
+               /* PR 17531: file: id:000001,src:000172+005151,op:splice,rep:2.  */
+               if (idx + ent.vd_next <= idx)
+                 break;
+
                idx += ent.vd_next;
              }
 
@@ -8436,15 +9572,13 @@ process_version_sections (FILE * file)
            found = 1;
 
            printf (_("\nVersion needs section '%s' contains %u entries:\n"),
-                   SECTION_NAME (section), section->sh_info);
+                   printable_section_name (section), section->sh_info);
 
            printf (_(" Addr: 0x"));
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   section->sh_link < elf_header.e_shnum
-                   ? SECTION_NAME (section_headers + section->sh_link)
-                   : _("<corrupt>"));
+                   printable_section_name_from_index (section->sh_link));
 
            eneed = (Elf_External_Verneed *) get_data (NULL, file,
                                                        section->sh_offset, 1,
@@ -8462,7 +9596,7 @@ process_version_sections (FILE * file)
                int isum;
                char * vstart;
 
-               if ((unsigned char *) eneed + idx < (unsigned char *) eneed)
+               if (idx > (size_t) (endbuf - (char *) eneed))
                  break;
 
                vstart = ((char *) eneed) + idx;
@@ -8487,10 +9621,8 @@ process_version_sections (FILE * file)
                printf (_("  Cnt: %d\n"), ent.vn_cnt);
 
                /* Check for overflow.  */
-               if ((unsigned char *)(vstart + ent.vn_aux) < (unsigned char *) vstart
-                   || (unsigned char *)(vstart + ent.vn_aux) > (unsigned char *) endbuf)
+               if (ent.vn_aux > (size_t) (endbuf - vstart))
                  break;
-
                vstart += ent.vn_aux;
 
                for (j = 0, isum = idx + ent.vn_aux; j < ent.vn_cnt; ++j)
@@ -8519,10 +9651,14 @@ process_version_sections (FILE * file)
                            get_ver_flags (aux.vna_flags), aux.vna_other);
 
                    /* Check for overflow.  */
-                   if ((unsigned char *)(vstart + aux.vna_next) < (unsigned char *) vstart
-                       || (unsigned char *)(vstart + aux.vna_next) > (unsigned char *) endbuf)
-                     break;
-
+                   if (aux.vna_next > (size_t) (endbuf - vstart)
+                       || (aux.vna_next == 0 && j < ent.vn_cnt - 1))
+                     {
+                       warn (_("Invalid vna_next field of %lx\n"),
+                             aux.vna_next);
+                       j = ent.vn_cnt;
+                       break;
+                     }
                    isum   += aux.vna_next;
                    vstart += aux.vna_next;
                  }
@@ -8530,6 +9666,12 @@ process_version_sections (FILE * file)
                if (j < ent.vn_cnt)
                  warn (_("Missing Version Needs auxillary information\n"));
 
+               if (ent.vn_next == 0 && cnt < section->sh_info - 1)
+                 {
+                   warn (_("Corrupt Version Needs structure - offset to next structure is zero with entries still left to be processed\n"));
+                   cnt = section->sh_info;
+                   break;
+                 }
                idx += ent.vn_next;
              }
 
@@ -8543,8 +9685,8 @@ process_version_sections (FILE * file)
        case SHT_GNU_versym:
          {
            Elf_Internal_Shdr * link_section;
-           int total;
-           int cnt;
+           size_t total;
+           unsigned int cnt;
            unsigned char * edata;
            unsigned short * data;
            char * strtab;
@@ -8579,14 +9721,14 @@ process_version_sections (FILE * file)
                break;
              }
 
-           printf (_("\nVersion symbols section '%s' contains %d entries:\n"),
-                   SECTION_NAME (section), total);
+           printf (_("\nVersion symbols section '%s' contains %lu entries:\n"),
+                   printable_section_name (section), (unsigned long) total);
 
            printf (_(" Addr: "));
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   SECTION_NAME (link_section));
+                   printable_section_name (link_section));
 
            off = offset_from_vma (file,
                                   version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
@@ -8672,7 +9814,7 @@ process_version_sections (FILE * file)
                              if (get_data (&evn, file, offset, sizeof (evn), 1,
                                            _("version need")) == NULL)
                                break;
-                             
+
                              ivn.vn_aux  = BYTE_GET (evn.vn_aux);
                              ivn.vn_next = BYTE_GET (evn.vn_next);
 
@@ -8735,7 +9877,9 @@ process_version_sections (FILE * file)
                                            _("version def")) == NULL)
                                {
                                  ivd.vd_next = 0;
-                                 ivd.vd_ndx  = 0;
+                                 /* PR 17531: file: 046-1082287-0.004.  */
+                                 ivd.vd_ndx  = (data[cnt + j] & VERSYM_VERSION) + 1;
+                                 break;
                                }
                              else
                                {
@@ -8891,7 +10035,9 @@ get_symbol_visibility (unsigned int visibility)
     case STV_INTERNAL: return "INTERNAL";
     case STV_HIDDEN:   return "HIDDEN";
     case STV_PROTECTED: return "PROTECTED";
-    default: abort ();
+    default:
+      error (_("Unrecognized visibility value: %u"), visibility);
+      return _("<unknown>");
     }
 }
 
@@ -8946,7 +10092,10 @@ get_ia64_symbol_other (unsigned int other)
               strcat (res, " RSV");
               break;
             default:
-              abort ();
+             warn (_("Unrecognized IA64 VMS ST Function type: %d\n"),
+                   VMS_ST_FUNC_TYPE (other));
+             strcat (res, " <unknown>");
+             break;
             }
           break;
         default:
@@ -8967,7 +10116,10 @@ get_ia64_symbol_other (unsigned int other)
           strcat (res, " LNK");
           break;
         default:
-          abort ();
+         warn (_("Unrecognized IA64 VMS ST Linkage: %d\n"),
+               VMS_ST_LINKAGE (other));
+         strcat (res, " <unknown>");
+         break;
         }
 
       if (res[0] != 0)
@@ -8978,6 +10130,19 @@ get_ia64_symbol_other (unsigned int other)
   return NULL;
 }
 
+static const char *
+get_ppc64_symbol_other (unsigned int other)
+{
+  if (PPC64_LOCAL_ENTRY_OFFSET (other) != 0)
+    {
+      static char buf[32];
+      snprintf (buf, sizeof buf, _("<localentry>: %d"),
+               PPC64_LOCAL_ENTRY_OFFSET (other));
+      return buf;
+    }
+  return NULL;
+}
+
 static const char *
 get_symbol_other (unsigned int other)
 {
@@ -8995,6 +10160,9 @@ get_symbol_other (unsigned int other)
     case EM_IA_64:
       result = get_ia64_symbol_other (other);
       break;
+    case EM_PPC64:
+      result = get_ppc64_symbol_other (other);
+      break;
     default:
       break;
     }
@@ -9041,7 +10209,7 @@ get_symbol_index_type (unsigned int type)
       else if (type >= SHN_LORESERVE)
        sprintf (buff, "RSV[0x%04x]", type & 0xffff);
       else if (type >= elf_header.e_shnum)
-       sprintf (buff, "bad section index[%3d]", type);
+       sprintf (buff, _("bad section index[%3d]"), type);
       else
        sprintf (buff, "%3d", type);
       break;
@@ -9051,30 +10219,52 @@ 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, bfd_size_type number, unsigned int ent_size)
 {
   unsigned char * e_data;
   bfd_vma * i_data;
 
-  e_data = (unsigned char *) cmalloc (number, ent_size);
+  /* If the size_t type is smaller than the bfd_size_type, eg because
+     you are building a 32-bit tool on a 64-bit host, then make sure
+     that when (number) is cast to (size_t) no information is lost.  */
+  if (sizeof (size_t) < sizeof (bfd_size_type)
+      && (bfd_size_type) ((size_t) number) != number)
+    {
+      error (_("Size truncation prevents reading %llu elements of size %u\n"),
+            (unsigned long long) number, ent_size);
+      return NULL;
+    }
+
+  /* Be kind to memory chekers (eg valgrind, address sanitizer) by not
+     attempting to allocate memory when the read is bound to fail.  */
+  if (ent_size * number > current_file_size)
+    {
+      error (_("Invalid number of dynamic entries: %llu\n"),
+            (unsigned long long) number);
+      return NULL;
+    }
 
+  e_data = (unsigned char *) cmalloc ((size_t) number, ent_size);
   if (e_data == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory reading %llu dynamic entries\n"),
+            (unsigned long long) number);
       return NULL;
     }
 
-  if (fread (e_data, ent_size, number, file) != number)
+  if (fread (e_data, ent_size, (size_t) number, file) != number)
     {
-      error (_("Unable to read in dynamic data\n"));
+      error (_("Unable to read in %llu bytes of dynamic data\n"),
+            (unsigned long long) (number * ent_size));
+      free (e_data);
       return NULL;
     }
 
-  i_data = (bfd_vma *) cmalloc (number, sizeof (*i_data));
-
+  i_data = (bfd_vma *) cmalloc ((size_t) number, sizeof (*i_data));
   if (i_data == NULL)
     {
-      error (_("Out of memory\n"));
+      error (_("Out of memory allocating space for %llu dynamic entries\n"),
+            (unsigned long long) number);
       free (e_data);
       return NULL;
     }
@@ -9093,12 +10283,19 @@ 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);
+    fputs (&"     "[n], stdout);
   printf (" %3lu: ", hn);
+
+  if (dynamic_symbols == NULL || si >= num_dynamic_syms)
+    {
+      printf (_("<No info available for dynamic symbol number %lu>\n"),
+             (unsigned long) si);
+      return;
+    }
+
+  psym = dynamic_symbols + si;
   print_vma (psym->st_value, LONG_HEX);
   putchar (' ');
   print_vma (psym->st_size, DEC_5);
@@ -9120,19 +10317,196 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn)
   putchar ('\n');
 }
 
+static const char *
+get_symbol_version_string (FILE *file, int is_dynsym,
+                          const char *strtab,
+                          unsigned long int strtab_size,
+                          unsigned int si, Elf_Internal_Sym *psym,
+                          enum versioned_symbol_info *sym_info,
+                          unsigned short *vna_other)
+{
+  const char *version_string = NULL;
+
+  if (is_dynsym
+      && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
+    {
+      unsigned char data[2];
+      unsigned short vers_data;
+      unsigned long offset;
+      int is_nobits;
+      int check_def;
+
+      offset = offset_from_vma
+       (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
+        sizeof data + si * sizeof (vers_data));
+
+      if (get_data (&data, file, offset + si * sizeof (vers_data),
+                   sizeof (data), 1, _("version data")) == NULL)
+       return NULL;
+
+      vers_data = byte_get (data, 2);
+
+      is_nobits = (section_headers != NULL
+                  && psym->st_shndx < elf_header.e_shnum
+                  && section_headers[psym->st_shndx].sh_type
+                  == SHT_NOBITS);
+
+      check_def = (psym->st_shndx != SHN_UNDEF);
+
+      if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
+       {
+         if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
+             && (is_nobits || ! check_def))
+           {
+             Elf_External_Verneed evn;
+             Elf_Internal_Verneed ivn;
+             Elf_Internal_Vernaux ivna;
+
+             /* We must test both.  */
+             offset = offset_from_vma
+               (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
+                sizeof evn);
+
+             do
+               {
+                 unsigned long vna_off;
+
+                 if (get_data (&evn, file, offset, sizeof (evn), 1,
+                               _("version need")) == NULL)
+                   {
+                     ivna.vna_next = 0;
+                     ivna.vna_other = 0;
+                     ivna.vna_name = 0;
+                     break;
+                   }
+
+                 ivn.vn_aux  = BYTE_GET (evn.vn_aux);
+                 ivn.vn_next = BYTE_GET (evn.vn_next);
+
+                 vna_off = offset + ivn.vn_aux;
+
+                 do
+                   {
+                     Elf_External_Vernaux evna;
+
+                     if (get_data (&evna, file, vna_off,
+                                   sizeof (evna), 1,
+                                   _("version need aux (3)")) == NULL)
+                       {
+                         ivna.vna_next = 0;
+                         ivna.vna_other = 0;
+                         ivna.vna_name = 0;
+                       }
+                     else
+                       {
+                         ivna.vna_other = BYTE_GET (evna.vna_other);
+                         ivna.vna_next  = BYTE_GET (evna.vna_next);
+                         ivna.vna_name  = BYTE_GET (evna.vna_name);
+                       }
+
+                     vna_off += ivna.vna_next;
+                   }
+                 while (ivna.vna_other != vers_data
+                        && ivna.vna_next != 0);
+
+                 if (ivna.vna_other == vers_data)
+                   break;
+
+                 offset += ivn.vn_next;
+               }
+             while (ivn.vn_next != 0);
+
+             if (ivna.vna_other == vers_data)
+               {
+                 *sym_info = symbol_undefined;
+                 *vna_other = ivna.vna_other;
+                 version_string = (ivna.vna_name < strtab_size
+                                   ? strtab + ivna.vna_name
+                                   : _("<corrupt>"));
+                 check_def = 0;
+               }
+             else if (! is_nobits)
+               error (_("bad dynamic symbol\n"));
+             else
+               check_def = 1;
+           }
+
+         if (check_def)
+           {
+             if (vers_data != 0x8001
+                 && version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
+               {
+                 Elf_Internal_Verdef ivd;
+                 Elf_Internal_Verdaux ivda;
+                 Elf_External_Verdaux evda;
+                 unsigned long off;
+
+                 off = offset_from_vma
+                   (file,
+                    version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
+                    sizeof (Elf_External_Verdef));
+
+                 do
+                   {
+                     Elf_External_Verdef evd;
+
+                     if (get_data (&evd, file, off, sizeof (evd),
+                                   1, _("version def")) == NULL)
+                       {
+                         ivd.vd_ndx = 0;
+                         ivd.vd_aux = 0;
+                         ivd.vd_next = 0;
+                       }
+                     else
+                       {
+                         ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
+                         ivd.vd_aux = BYTE_GET (evd.vd_aux);
+                         ivd.vd_next = BYTE_GET (evd.vd_next);
+                       }
+
+                     off += ivd.vd_next;
+                   }
+                 while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
+                        && ivd.vd_next != 0);
+
+                 off -= ivd.vd_next;
+                 off += ivd.vd_aux;
+
+                 if (get_data (&evda, file, off, sizeof (evda),
+                               1, _("version def aux")) == NULL)
+                   return version_string;
+
+                 ivda.vda_name = BYTE_GET (evda.vda_name);
+
+                 if (psym->st_name != ivda.vda_name)
+                   {
+                     *sym_info = ((vers_data & VERSYM_HIDDEN) != 0
+                                  ? symbol_hidden : symbol_public);
+                     version_string = (ivda.vda_name < strtab_size
+                                       ? strtab + ivda.vda_name
+                                       : _("<corrupt>"));
+                   }
+               }
+           }
+       }
+    }
+  return version_string;
+}
+
 /* Dump the symbol table.  */
 static int
 process_symbol_table (FILE * file)
 {
   Elf_Internal_Shdr * section;
-  bfd_vma nbuckets = 0;
-  bfd_vma nchains = 0;
+  bfd_size_type nbuckets = 0;
+  bfd_size_type nchains = 0;
   bfd_vma * buckets = NULL;
   bfd_vma * chains = NULL;
   bfd_vma ngnubuckets = 0;
   bfd_vma * gnubuckets = NULL;
   bfd_vma * gnuchains = NULL;
   bfd_vma gnusymidx = 0;
+  bfd_size_type ngnuchains = 0;
 
   if (!do_syms && !do_dyn_syms && !do_histogram)
     return 1;
@@ -9145,7 +10519,7 @@ process_symbol_table (FILE * file)
     {
       unsigned char nb[8];
       unsigned char nc[8];
-      int hash_ent_size = 4;
+      unsigned int hash_ent_size = 4;
 
       if ((elf_header.e_machine == EM_ALPHA
           || elf_header.e_machine == EM_S390
@@ -9294,6 +10668,7 @@ process_symbol_table (FILE * file)
        }
 
       gnuchains = get_dynamic_data (file, maxchain, 4);
+      ngnuchains = maxchain;
 
     no_gnu_hash:
       if (gnuchains == NULL)
@@ -9309,7 +10684,8 @@ process_symbol_table (FILE * file)
   if ((dynamic_info[DT_HASH] || dynamic_info_DT_GNU_HASH)
       && do_syms
       && do_using_dynamic
-      && dynamic_strings != NULL)
+      && dynamic_strings != NULL
+      && dynamic_symbols != NULL)
     {
       unsigned long hn;
 
@@ -9352,11 +10728,12 @@ process_symbol_table (FILE * file)
                    print_dynamic_symbol (si, hn);
                    si++;
                  }
-               while ((gnuchains[off++] & 1) == 0);
+               while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
              }
        }
     }
-  else if (do_dyn_syms || (do_syms && !do_using_dynamic))
+  else if ((do_dyn_syms || (do_syms && !do_using_dynamic))
+          && section_headers != NULL)
     {
       unsigned int i;
 
@@ -9380,12 +10757,12 @@ process_symbol_table (FILE * file)
          if (section->sh_entsize == 0)
            {
              printf (_("\nSymbol table '%s' has a sh_entsize of zero!\n"),
-                     SECTION_NAME (section));
+                     printable_section_name (section));
              continue;
            }
 
          printf (_("\nSymbol table '%s' contains %lu entries:\n"),
-                 SECTION_NAME (section),
+                 printable_section_name (section),
                  (unsigned long) (section->sh_size / section->sh_entsize));
 
          if (is_32bit_elf)
@@ -9416,6 +10793,10 @@ process_symbol_table (FILE * file)
 
          for (si = 0, psym = symtab; si < num_syms; si++, psym++)
            {
+             const char *version_string;
+             enum versioned_symbol_info sym_info;
+             unsigned short vna_other;
+
              printf ("%6d: ", si);
              print_vma (psym->st_value, LONG_HEX);
              putchar (' ');
@@ -9432,211 +10813,80 @@ process_symbol_table (FILE * file)
              print_symbol (25, psym->st_name < strtab_size
                            ? strtab + psym->st_name : _("<corrupt>"));
 
-             if (section->sh_type == SHT_DYNSYM
-                 && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
+             version_string
+               = get_symbol_version_string (file,
+                                            section->sh_type == SHT_DYNSYM,
+                                            strtab, strtab_size, si,
+                                            psym, &sym_info, &vna_other);
+             if (version_string)
                {
-                 unsigned char data[2];
-                 unsigned short vers_data;
-                 unsigned long offset;
-                 int is_nobits;
-                 int check_def;
-
-                 offset = offset_from_vma
-                   (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
-                    sizeof data + si * sizeof (vers_data));
-
-                 if (get_data (&data, file, offset + si * sizeof (vers_data),
-                               sizeof (data), 1, _("version data")) == NULL)
-                   break;
-
-                 vers_data = byte_get (data, 2);
+                 if (sym_info == symbol_undefined)
+                   printf ("@%s (%d)", version_string, vna_other);
+                 else
+                   printf (sym_info == symbol_hidden ? "@%s" : "@@%s",
+                           version_string);
+               }
 
-                 is_nobits = (psym->st_shndx < elf_header.e_shnum
-                              && section_headers[psym->st_shndx].sh_type
-                                 == SHT_NOBITS);
+             putchar ('\n');
+           }
 
-                 check_def = (psym->st_shndx != SHN_UNDEF);
+         free (symtab);
+         if (strtab != string_table)
+           free (strtab);
+       }
+    }
+  else if (do_syms)
+    printf
+      (_("\nDynamic symbol information is not available for displaying symbols.\n"));
 
-                 if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
-                   {
-                     if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
-                         && (is_nobits || ! check_def))
-                       {
-                         Elf_External_Verneed evn;
-                         Elf_Internal_Verneed ivn;
-                         Elf_Internal_Vernaux ivna;
+  if (do_histogram && buckets != NULL)
+    {
+      unsigned long * lengths;
+      unsigned long * counts;
+      unsigned long hn;
+      bfd_vma si;
+      unsigned long maxlength = 0;
+      unsigned long nzero_counts = 0;
+      unsigned long nsyms = 0;
+      unsigned long chained;
 
-                         /* We must test both.  */
-                         offset = offset_from_vma
-                           (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
-                            sizeof evn);
+      printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"),
+             (unsigned long) nbuckets);
 
-                         do
-                           {
-                             unsigned long vna_off;
+      lengths = (unsigned long *) calloc (nbuckets, sizeof (*lengths));
+      if (lengths == NULL)
+       {
+         error (_("Out of memory allocating space for histogram buckets\n"));
+         return 0;
+       }
 
-                             if (get_data (&evn, file, offset, sizeof (evn), 1,
-                                           _("version need")) == NULL)
-                               {
-                                 ivna.vna_next = 0;
-                                 ivna.vna_other = 0;
-                                 ivna.vna_name = 0;
-                                 break;
-                               }
-
-                             ivn.vn_aux  = BYTE_GET (evn.vn_aux);
-                             ivn.vn_next = BYTE_GET (evn.vn_next);
-
-                             vna_off = offset + ivn.vn_aux;
-
-                             do
-                               {
-                                 Elf_External_Vernaux evna;
-
-                                 if (get_data (&evna, file, vna_off,
-                                               sizeof (evna), 1,
-                                               _("version need aux (3)")) == NULL)
-                                   {
-                                     ivna.vna_next = 0;
-                                     ivna.vna_other = 0;
-                                     ivna.vna_name = 0;
-                                   }
-                                 else
-                                   {
-                                     ivna.vna_other = BYTE_GET (evna.vna_other);
-                                     ivna.vna_next  = BYTE_GET (evna.vna_next);
-                                     ivna.vna_name  = BYTE_GET (evna.vna_name);
-                                   }
-
-                                 vna_off += ivna.vna_next;
-                               }
-                             while (ivna.vna_other != vers_data
-                                    && ivna.vna_next != 0);
-
-                             if (ivna.vna_other == vers_data)
-                               break;
-
-                             offset += ivn.vn_next;
-                           }
-                         while (ivn.vn_next != 0);
-
-                         if (ivna.vna_other == vers_data)
-                           {
-                             printf ("@%s (%d)",
-                                     ivna.vna_name < strtab_size
-                                     ? strtab + ivna.vna_name : _("<corrupt>"),
-                                     ivna.vna_other);
-                             check_def = 0;
-                           }
-                         else if (! is_nobits)
-                           error (_("bad dynamic symbol\n"));
-                         else
-                           check_def = 1;
-                       }
-
-                     if (check_def)
-                       {
-                         if (vers_data != 0x8001
-                             && version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
-                           {
-                             Elf_Internal_Verdef ivd;
-                             Elf_Internal_Verdaux ivda;
-                             Elf_External_Verdaux evda;
-                             unsigned long off;
-
-                             off = offset_from_vma
-                               (file,
-                                version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
-                                sizeof (Elf_External_Verdef));
-
-                             do
-                               {
-                                 Elf_External_Verdef evd;
-
-                                 if (get_data (&evd, file, off, sizeof (evd),
-                                               1, _("version def")) == NULL)
-                                   {
-                                     ivd.vd_ndx = 0;
-                                     ivd.vd_aux = 0;
-                                     ivd.vd_next = 0;
-                                   }
-                                 else
-                                   {
-                                     ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
-                                     ivd.vd_aux = BYTE_GET (evd.vd_aux);
-                                     ivd.vd_next = BYTE_GET (evd.vd_next);
-                                   }
-
-                                 off += ivd.vd_next;
-                               }
-                             while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
-                                    && ivd.vd_next != 0);
-
-                             off -= ivd.vd_next;
-                             off += ivd.vd_aux;
-
-                             if (get_data (&evda, file, off, sizeof (evda),
-                                           1, _("version def aux")) == NULL)
-                               break;
-
-                             ivda.vda_name = BYTE_GET (evda.vda_name);
-
-                             if (psym->st_name != ivda.vda_name)
-                               printf ((vers_data & VERSYM_HIDDEN)
-                                       ? "@%s" : "@@%s",
-                                       ivda.vda_name < strtab_size
-                                       ? strtab + ivda.vda_name : _("<corrupt>"));
-                           }
-                       }
-                   }
-               }
-
-             putchar ('\n');
-           }
-
-         free (symtab);
-         if (strtab != string_table)
-           free (strtab);
-       }
-    }
-  else if (do_syms)
-    printf
-      (_("\nDynamic symbol information is not available for displaying symbols.\n"));
-
-  if (do_histogram && buckets != NULL)
-    {
-      unsigned long * lengths;
-      unsigned long * counts;
-      unsigned long hn;
-      bfd_vma si;
-      unsigned long maxlength = 0;
-      unsigned long nzero_counts = 0;
-      unsigned long nsyms = 0;
-
-      printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"),
-             (unsigned long) nbuckets);
       printf (_(" Length  Number     %% of total  Coverage\n"));
-
-      lengths = (unsigned long *) calloc (nbuckets, sizeof (*lengths));
-      if (lengths == NULL)
-       {
-         error (_("Out of memory\n"));
-         return 0;
-       }
       for (hn = 0; hn < nbuckets; ++hn)
        {
-         for (si = buckets[hn]; si > 0 && si < nchains; si = chains[si])
+         for (si = buckets[hn], chained = 0;
+              si > 0 && si < nchains && si < nbuckets && chained <= nchains;
+              si = chains[si], ++chained)
            {
              ++nsyms;
              if (maxlength < ++lengths[hn])
                ++maxlength;
            }
+
+           /* PR binutils/17531: A corrupt binary could contain broken
+              histogram data.  Do not go into an infinite loop trying
+              to process it.  */
+           if (chained > nchains)
+             {
+               error (_("histogram chain is corrupt\n"));
+               break;
+             }
        }
 
       counts = (unsigned long *) calloc (maxlength + 1, sizeof (*counts));
       if (counts == NULL)
        {
-         error (_("Out of memory\n"));
+         free (lengths);
+         error (_("Out of memory allocating space for histogram counts\n"));
          return 0;
        }
 
@@ -9676,15 +10926,16 @@ process_symbol_table (FILE * file)
       unsigned long nzero_counts = 0;
       unsigned long nsyms = 0;
 
+      printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"),
+             (unsigned long) ngnubuckets);
+
       lengths = (unsigned long *) calloc (ngnubuckets, sizeof (*lengths));
       if (lengths == NULL)
        {
-         error (_("Out of memory\n"));
+         error (_("Out of memory allocating space for gnu histogram 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"));
 
       for (hn = 0; hn < ngnubuckets; ++hn)
@@ -9693,7 +10944,9 @@ process_symbol_table (FILE * file)
            bfd_vma off, length = 1;
 
            for (off = gnubuckets[hn] - gnusymidx;
-                (gnuchains[off] & 1) == 0; ++off)
+                /* PR 17531 file: 010-77222-0.004.  */
+                off < ngnuchains && (gnuchains[off] & 1) == 0;
+                ++off)
              ++length;
            lengths[hn] = length;
            if (length > maxlength)
@@ -9704,7 +10957,8 @@ process_symbol_table (FILE * file)
       counts = (unsigned long *) calloc (maxlength + 1, sizeof (*counts));
       if (counts == NULL)
        {
-         error (_("Out of memory\n"));
+         free (lengths);
+         error (_("Out of memory allocating space for gnu histogram counts\n"));
          return 0;
        }
 
@@ -9758,7 +11012,9 @@ process_syminfo (FILE * file ATTRIBUTE_UNUSED)
       unsigned short int flags = dynamic_syminfo[i].si_flags;
 
       printf ("%4d: ", i);
-      if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name))
+      if (i >= num_dynamic_syms)
+       printf (_("<corrupt index>"));
+      else if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name))
        print_symbol (30, GET_DYNAMIC_NAME (dynamic_symbols[i].st_name));
       else
        printf (_("<corrupt: %19ld>"), dynamic_symbols[i].st_name);
@@ -9813,6 +11069,60 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
 
   switch (elf_header.e_machine)
     {
+    case EM_MSP430:
+    case EM_MSP430_OLD:
+      {
+       static Elf_Internal_Sym * saved_sym = NULL;
+
+       switch (reloc_type)
+         {
+         case 10: /* R_MSP430_SYM_DIFF */
+           if (uses_msp430x_relocs ())
+             break;
+         case 21: /* R_MSP430X_SYM_DIFF */
+           saved_sym = symtab + get_reloc_symindex (reloc->r_info);
+           return TRUE;
+
+         case 1: /* R_MSP430_32 or R_MSP430_ABS32 */
+         case 3: /* R_MSP430_16 or R_MSP430_ABS8 */
+           goto handle_sym_diff;
+
+         case 5: /* R_MSP430_16_BYTE */
+         case 9: /* R_MSP430_8 */
+           if (uses_msp430x_relocs ())
+             break;
+           goto handle_sym_diff;
+
+         case 2: /* R_MSP430_ABS16 */
+         case 15: /* R_MSP430X_ABS16 */
+           if (! uses_msp430x_relocs ())
+             break;
+           goto handle_sym_diff;
+
+         handle_sym_diff:
+           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 MSP430 reloc type found after SYM_DIFF reloc\n"));
+           break;
+         }
+       break;
+      }
+
     case EM_MN10300:
     case EM_CYGNUS_MN10300:
       {
@@ -9843,7 +11153,7 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
            break;
          default:
            if (saved_sym != NULL)
-             error (_("Unhandled MN10300 reloc type found after SYM_DIFF reloc"));
+             error (_("Unhandled MN10300 reloc type found after SYM_DIFF reloc\n"));
            break;
          }
        break;
@@ -9912,6 +11222,8 @@ is_32bit_abs_reloc (unsigned int reloc_type)
     case EM_CYGNUS_FR30:
     case EM_FR30:
       return reloc_type == 3; /* R_FR30_32.  */
+    case EM_FT32:
+      return reloc_type == 1; /* R_FT32_32.  */
     case EM_H8S:
     case EM_H8_300:
     case EM_H8_300H:
@@ -9934,6 +11246,8 @@ is_32bit_abs_reloc (unsigned int reloc_type)
       return reloc_type == 1; /* R_MCORE_ADDR32.  */
     case EM_CYGNUS_MEP:
       return reloc_type == 4; /* R_MEP_32.  */
+    case EM_METAG:
+      return reloc_type == 2; /* R_METAG_ADDR32.  */
     case EM_MICROBLAZE:
       return reloc_type == 1; /* R_MICROBLAZE_32.  */
     case EM_MIPS:
@@ -9950,15 +11264,17 @@ is_32bit_abs_reloc (unsigned int reloc_type)
       return reloc_type == 1; /* R_MOXIE_32.  */
     case EM_MSP430_OLD:
     case EM_MSP430:
-      return reloc_type == 1; /* R_MSP43_32.  */
+      return reloc_type == 1; /* R_MSP430_32 or R_MSP320_ABS32.  */
     case EM_MT:
       return reloc_type == 2; /* R_MT_32.  */
+    case EM_NDS32:
+      return reloc_type == 20; /* R_NDS32_RELA.  */
     case EM_ALTERA_NIOS2:
+      return reloc_type == 12; /* R_NIOS2_BFD_RELOC_32.  */
     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_OR1K:
+      return reloc_type == 1; /* R_OR1K_32.  */
     case EM_PARISC:
       return (reloc_type == 1 /* R_PARISC_DIR32.  */
              || reloc_type == 41); /* R_PARISC_SECREL32.  */
@@ -9998,8 +11314,12 @@ is_32bit_abs_reloc (unsigned int reloc_type)
     case EM_CYGNUS_V850:
     case EM_V850:
       return reloc_type == 6; /* R_V850_ABS32.  */
+    case EM_V800:
+      return reloc_type == 0x33; /* R_V810_WORD.  */
     case EM_VAX:
       return reloc_type == 1; /* R_VAX_32.  */
+    case EM_VISIUM:
+      return reloc_type == 3;  /* R_VISIUM_32. */
     case EM_X86_64:
     case EM_L1OM:
     case EM_K1OM:
@@ -10015,9 +11335,16 @@ is_32bit_abs_reloc (unsigned int reloc_type)
     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 ();
+      {
+       static unsigned int prev_warn = 0;
+
+       /* Avoid repeating the same warning multiple times.  */
+       if (prev_warn != elf_header.e_machine)
+         error (_("Missing knowledge of 32-bit reloc types used in DWARF sections of machine number %d\n"),
+                elf_header.e_machine);
+       prev_warn = elf_header.e_machine;
+       return FALSE;
+      }
     }
 }
 
@@ -10044,6 +11371,8 @@ is_32bit_pcrel_reloc (unsigned int reloc_type)
       return reloc_type == 3;  /* R_ARM_REL32 */
     case EM_MICROBLAZE:
       return reloc_type == 2;  /* R_MICROBLAZE_32_PCREL.  */
+    case EM_OR1K:
+      return reloc_type == 9; /* R_OR1K_32_PCREL.  */
     case EM_PARISC:
       return reloc_type == 9;  /* R_PARISC_PCREL32.  */
     case EM_PPC:
@@ -10065,6 +11394,8 @@ is_32bit_pcrel_reloc (unsigned int reloc_type)
       return reloc_type == 6; /* R_TILEGX_32_PCREL.  */
     case EM_TILEPRO:
       return reloc_type == 4; /* R_TILEPRO_32_PCREL.  */
+    case EM_VISIUM:
+      return reloc_type == 6;  /* R_VISIUM_32_PCREL */
     case EM_X86_64:
     case EM_L1OM:
     case EM_K1OM:
@@ -10198,12 +11529,19 @@ is_16bit_abs_reloc (unsigned int reloc_type)
     case EM_M32C_OLD:
     case EM_M32C:
       return reloc_type == 1; /* R_M32C_16 */
-    case EM_MSP430_OLD:
     case EM_MSP430:
+      if (uses_msp430x_relocs ())
+       return reloc_type == 2; /* R_MSP430_ABS16.  */
+    case EM_MSP430_OLD:
       return reloc_type == 5; /* R_MSP430_16_BYTE.  */
+    case EM_NDS32:
+      return reloc_type == 19; /* R_NDS32_RELA.  */
     case EM_ALTERA_NIOS2:
+      return reloc_type == 13; /* R_NIOS2_BFD_RELOC_16.  */
     case EM_NIOS32:
       return reloc_type == 9; /* R_NIOS_16.  */
+    case EM_OR1K:
+      return reloc_type == 2; /* R_OR1K_16.  */
     case EM_TI_C6000:
       return reloc_type == 2; /* R_C6000_ABS16.  */
     case EM_XC16X:
@@ -10215,6 +11553,8 @@ is_16bit_abs_reloc (unsigned int reloc_type)
     case EM_CYGNUS_MN10300:
     case EM_MN10300:
       return reloc_type == 2; /* R_MN10300_16.  */
+    case EM_VISIUM:
+      return reloc_type == 2; /* R_VISIUM_16. */
     case EM_XGATE:
       return reloc_type == 3; /* R_XGATE_16.  */
     default:
@@ -10251,6 +11591,7 @@ is_none_reloc (unsigned int reloc_type)
     case EM_L1OM:    /* R_X86_64_NONE.  */
     case EM_K1OM:    /* R_X86_64_NONE.  */
     case EM_MN10300: /* R_MN10300_NONE.  */
+    case EM_FT32:    /* R_FT32_NONE.  */
     case EM_MOXIE:   /* R_MOXIE_NONE.  */
     case EM_M32R:    /* R_M32R_NONE.  */
     case EM_TI_C6000:/* R_C6000_NONE.  */
@@ -10258,15 +11599,26 @@ is_none_reloc (unsigned int reloc_type)
     case EM_TILEPRO: /* R_TILEPRO_NONE.  */
     case EM_XC16X:
     case EM_C166:    /* R_XC16X_NONE.  */
+    case EM_ALTERA_NIOS2: /* R_NIOS2_NONE.  */
+    case EM_NIOS32:  /* R_NIOS_NONE.  */
+    case EM_OR1K:    /* R_OR1K_NONE. */
       return reloc_type == 0;
     case EM_AARCH64:
       return reloc_type == 0 || reloc_type == 256;
+    case EM_NDS32:
+      return (reloc_type == 0       /* R_XTENSA_NONE.  */
+             || reloc_type == 204  /* R_NDS32_DIFF8.  */
+             || reloc_type == 205  /* R_NDS32_DIFF16.  */
+             || reloc_type == 206  /* R_NDS32_DIFF32.  */
+             || reloc_type == 207  /* R_NDS32_ULEB128.  */);
     case EM_XTENSA_OLD:
     case EM_XTENSA:
       return (reloc_type == 0      /* R_XTENSA_NONE.  */
              || reloc_type == 17  /* R_XTENSA_DIFF8.  */
              || reloc_type == 18  /* R_XTENSA_DIFF16.  */
              || reloc_type == 19  /* R_XTENSA_DIFF32.  */);
+    case EM_METAG:
+      return reloc_type == 3; /* R_METAG_NONE.  */
     }
   return FALSE;
 }
@@ -10356,17 +11708,20 @@ apply_relocations (void * file,
            reloc_size = 2;
          else
            {
-             warn (_("unable to apply unsupported reloc type %d to section %s\n"),
-                   reloc_type, SECTION_NAME (section));
+             static unsigned int prev_reloc = 0;
+             if (reloc_type != prev_reloc)
+               warn (_("unable to apply unsupported reloc type %d to section %s\n"),
+                     reloc_type, printable_section_name (section));
+             prev_reloc = reloc_type;
              continue;
            }
 
          rloc = start + rp->r_offset;
-         if ((rloc + reloc_size) > end)
+         if ((rloc + reloc_size) > end || (rloc < start))
            {
              warn (_("skipping invalid relocation offset 0x%lx in section %s\n"),
                    (unsigned long) rp->r_offset,
-                   SECTION_NAME (section));
+                   printable_section_name (section));
              continue;
            }
 
@@ -10374,7 +11729,7 @@ apply_relocations (void * file,
          if (sym_index >= num_syms)
            {
              warn (_("skipping invalid relocation symbol index 0x%lx in section %s\n"),
-                   sym_index, SECTION_NAME (section));
+                   sym_index, printable_section_name (section));
              continue;
            }
          sym = symtab + sym_index;
@@ -10398,7 +11753,7 @@ apply_relocations (void * file,
              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));
+                   printable_section_name (relsec));
              continue;
            }
 
@@ -10441,10 +11796,9 @@ apply_relocations (void * file,
 static int
 disassemble_section (Elf_Internal_Shdr * section, FILE * file)
 {
-  printf (_("\nAssembly dump of section %s\n"),
-         SECTION_NAME (section));
+  printf (_("\nAssembly dump of section %s\n"), printable_section_name (section));
 
-  /* XXX -- to be done --- XXX */
+  /* FIXME: XXX -- to be done --- XXX */
 
   return 1;
 }
@@ -10463,7 +11817,7 @@ get_section_contents (Elf_Internal_Shdr * section, FILE * file)
   if (num_bytes == 0 || section->sh_type == SHT_NOBITS)
     {
       printf (_("\nSection '%s' has no data to dump.\n"),
-             SECTION_NAME (section));
+             printable_section_name (section));
       return NULL;
     }
 
@@ -10480,14 +11834,13 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file)
   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);
+  printf (_("\nString dump of section '%s':\n"), printable_section_name (section));
 
   /* If the section being dumped has relocations against it the user might
      be expecting these relocations to have been applied.  Check for this
@@ -10522,15 +11875,26 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file)
 
       if (data < end)
        {
+         size_t maxlen = end - data;
+
 #ifndef __MSVCRT__
          /* PR 11128: Use two separate invocations in order to work
              around bugs in the Solaris 8 implementation of printf.  */
          printf ("  [%6tx]  ", data - start);
-         printf ("%s\n", data);
 #else
-         printf ("  [%6Ix]  %s\n", (size_t) (data - start), data);
+         printf ("  [%6Ix]  ", (size_t) (data - start));
 #endif
-         data += strlen (data);
+         if (maxlen > 0)
+           {
+             print_symbol ((int) maxlen, data);
+             putchar ('\n');
+             data += strnlen (data, maxlen);
+           }
+         else
+           {
+             printf (_("<corrupt>\n"));
+             data = end;
+           }
          some_strings_shown = TRUE;
        }
     }
@@ -10558,7 +11922,7 @@ dump_section_as_bytes (Elf_Internal_Shdr * section,
   if (start == NULL)
     return;
 
-  printf (_("\nHex dump of section '%s':\n"), SECTION_NAME (section));
+  printf (_("\nHex dump of section '%s':\n"), printable_section_name (section));
 
   if (relocate)
     {
@@ -10636,12 +12000,9 @@ dump_section_as_bytes (Elf_Internal_Shdr * section,
 /* Uncompresses a section that was compressed using zlib, in place.  */
 
 static int
-uncompress_section_contents (unsigned char **buffer ATTRIBUTE_UNUSED,
-                            dwarf_size_type *size ATTRIBUTE_UNUSED)
+uncompress_section_contents (unsigned char **buffer,
+                            dwarf_size_type *size)
 {
-#ifndef HAVE_ZLIB_H
-  return FALSE;
-#else
   dwarf_size_type compressed_size = *size;
   unsigned char * compressed_buffer = *buffer;
   dwarf_size_type uncompressed_size;
@@ -10692,7 +12053,6 @@ uncompress_section_contents (unsigned char **buffer ATTRIBUTE_UNUSED,
       || strm.avail_out != 0)
     goto fail;
 
-  free (compressed_buffer);
   *buffer = uncompressed_buffer;
   *size = uncompressed_size;
   return 1;
@@ -10702,7 +12062,6 @@ uncompress_section_contents (unsigned char **buffer ATTRIBUTE_UNUSED,
   /* Indicate decompression failure.  */
   *buffer = NULL;
   return 0;
-#endif  /* HAVE_ZLIB_H */
 }
 
 static int
@@ -10718,6 +12077,7 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
 
   snprintf (buf, sizeof (buf), _("%s section data"), section->name);
   section->address = sec->sh_addr;
+  section->user_data = NULL;
   section->start = (unsigned char *) get_data (NULL, (FILE *) file,
                                                sec->sh_offset, 1,
                                                sec->sh_size, buf);
@@ -10725,9 +12085,30 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
     section->size = 0;
   else
     {
-      section->size = sec->sh_size;
-      if (uncompress_section_contents (&section->start, &section->size))
-       sec->sh_size = section->size;
+      unsigned char *start = section->start;
+      dwarf_size_type size = sec->sh_size;
+
+      if ((sec->sh_flags & SHF_COMPRESSED) != 0)
+       {
+         Elf_Internal_Chdr chdr;
+         unsigned int compression_header_size
+           = get_compression_header (&chdr, start);
+         if (chdr.ch_type != ELFCOMPRESS_ZLIB
+             || chdr.ch_addralign != sec->sh_addralign)
+           return 0;
+         start += compression_header_size;
+         size -= compression_header_size;
+       }
+
+      if (uncompress_section_contents (&start, &size))
+       {
+         /* Free the compressed buffer, update the section buffer
+            and the section size if uncompress is successful.  */
+         free (section->start);
+         section->start = start;
+         sec->sh_size = size;
+       }
+      section->size = size;
     }
 
   if (section->start == NULL)
@@ -10789,6 +12170,7 @@ static int
 display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
 {
   char * name = SECTION_NAME (section);
+  const char * print_name = printable_section_name (section);
   bfd_size_type length;
   int result = 1;
   int i;
@@ -10796,7 +12178,7 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
   length = section->sh_size;
   if (length == 0)
     {
-      printf (_("\nSection '%s' has no debugging data.\n"), name);
+      printf (_("\nSection '%s' has no debugging data.\n"), print_name);
       return 0;
     }
   if (section->sh_type == SHT_NOBITS)
@@ -10805,7 +12187,8 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
         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);
+      printf (_("section '%s' has the NOBITS type - its contents are unreliable.\n"),
+             print_name);
       return 0;
     }
 
@@ -10815,6 +12198,7 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
   /* See if we know how to display the contents of this section.  */
   for (i = 0; i < max; i++)
     if (streq (debug_displays[i].section.uncompressed_name, name)
+       || (i == line && const_strneq (name, ".debug_line."))
         || streq (debug_displays[i].section.compressed_name, name))
       {
        struct dwarf_section * sec = &debug_displays [i].section;
@@ -10823,7 +12207,9 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
        if (secondary)
          free_debug_section ((enum dwarf_section_display_enum) i);
 
-       if (streq (sec->uncompressed_name, name))
+       if (i == line && const_strneq (name, ".debug_line."))
+         sec->name = name;
+       else if (streq (sec->uncompressed_name, name))
          sec->name = sec->uncompressed_name;
        else
          sec->name = sec->compressed_name;
@@ -10847,7 +12233,7 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, FILE * file)
 
   if (i == max)
     {
-      printf (_("Unrecognized debug section: %s\n"), name);
+      printf (_("Unrecognized debug section: %s\n"), print_name);
       result = 0;
     }
 
@@ -10940,13 +12326,72 @@ process_mips_fpe_exception (int mask)
     fputs ("0", stdout);
 }
 
+/* Display's the value of TAG at location P.  If TAG is
+   greater than 0 it is assumed to be an unknown tag, and
+   a message is printed to this effect.  Otherwise it is
+   assumed that a message has already been printed.
+
+   If the bottom bit of TAG is set it assumed to have a
+   string value, otherwise it is assumed to have an integer
+   value.
+
+   Returns an updated P pointing to the first unread byte
+   beyond the end of TAG's value.
+
+   Reads at or beyond END will not be made.  */
+
+static unsigned char *
+display_tag_value (int tag,
+                  unsigned char * p,
+                  const unsigned char * const end)
+{
+  unsigned long val;
+
+  if (tag > 0)
+    printf ("  Tag_unknown_%d: ", tag);
+
+  if (p >= end)
+    {
+      warn (_("<corrupt tag>\n"));
+    }
+  else if (tag & 1)
+    {
+      /* PR 17531 file: 027-19978-0.004.  */
+      size_t maxlen = (end - p) - 1;
+
+      putchar ('"');
+      if (maxlen > 0)
+       {
+         print_symbol ((int) maxlen, (const char *) p);
+         p += strnlen ((char *) p, maxlen) + 1;
+       }
+      else
+       {
+         printf (_("<corrupt string tag>"));
+         p = (unsigned char *) end;
+       }
+      printf ("\"\n");
+    }
+  else
+    {
+      unsigned int len;
+
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("%ld (0x%lx)\n", val, val);
+    }
+
+  assert (p <= end);
+  return p;
+}
+
 /* ARM EABI attributes section.  */
 typedef struct
 {
-  int tag;
+  unsigned int tag;
   const char * name;
   /* 0 = special, 1 = string, 2 = uleb123, > 0x80 == table lookup.  */
-  int type;
+  unsigned int type;
   const char ** table;
 } arm_attr_public_tag;
 
@@ -10958,7 +12403,7 @@ static const char * arm_attr_tag_THUMB_ISA_use[] =
   {"No", "Thumb-1", "Thumb-2"};
 static const char * arm_attr_tag_FP_arch[] =
   {"No", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", "VFPv4-D16",
-   "FP for ARMv8"};
+   "FP for ARMv8", "FPv5/FP-D16 for ARMv8"};
 static const char * arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1", "WMMXv2"};
 static const char * arm_attr_tag_Advanced_SIMD_arch[] =
   {"No", "NEONv1", "NEONv1 with Fused-MAC", "NEON for ARMv8"};
@@ -10985,9 +12430,9 @@ static const char * arm_attr_tag_ABI_FP_number_model[] =
 static const char * arm_attr_tag_ABI_enum_size[] =
   {"Unused", "small", "int", "forced to int"};
 static const char * arm_attr_tag_ABI_HardFP_use[] =
-  {"As Tag_FP_arch", "SP only", "DP only", "SP and DP"};
+  {"As Tag_FP_arch", "SP only", "Reserved", "Deprecated"};
 static const char * arm_attr_tag_ABI_VFP_args[] =
-  {"AAPCS", "VFP registers", "custom"};
+  {"AAPCS", "VFP registers", "custom", "compatible"};
 static const char * arm_attr_tag_ABI_WMMX_args[] =
   {"AAPCS", "WMMX registers", "custom"};
 static const char * arm_attr_tag_ABI_optimization_goals[] =
@@ -11061,16 +12506,17 @@ static arm_attr_public_tag arm_attr_public_tags[] =
 #undef LOOKUP
 
 static unsigned char *
-display_arm_attribute (unsigned char * p)
+display_arm_attribute (unsigned char * p,
+                      const unsigned char * const end)
 {
-  int tag;
+  unsigned int tag;
   unsigned int len;
-  int val;
+  unsigned int val;
   arm_attr_public_tag * attr;
   unsigned i;
-  int type;
+  unsigned int type;
 
-  tag = read_uleb128 (p, &len);
+  tag = read_uleb128 (p, &len, end);
   p += len;
   attr = NULL;
   for (i = 0; i < ARRAY_SIZE (arm_attr_public_tags); i++)
@@ -11091,7 +12537,7 @@ display_arm_attribute (unsigned char * p)
          switch (tag)
            {
            case 7: /* Tag_CPU_arch_profile.  */
-             val = read_uleb128 (p, &len);
+             val = read_uleb128 (p, &len, end);
              p += len;
              switch (val)
                {
@@ -11105,7 +12551,7 @@ display_arm_attribute (unsigned char * p)
              break;
 
            case 24: /* Tag_align_needed.  */
-             val = read_uleb128 (p, &len);
+             val = read_uleb128 (p, &len, end);
              p += len;
              switch (val)
                {
@@ -11124,7 +12570,7 @@ display_arm_attribute (unsigned char * p)
              break;
 
            case 25: /* Tag_align_preserved.  */
-             val = read_uleb128 (p, &len);
+             val = read_uleb128 (p, &len, end);
              p += len;
              switch (val)
                {
@@ -11143,47 +12589,65 @@ display_arm_attribute (unsigned char * p)
              break;
 
            case 32: /* Tag_compatibility.  */
-             val = read_uleb128 (p, &len);
-             p += len;
-             printf (_("flag = %d, vendor = %s\n"), val, p);
-             p += strlen ((char *) p) + 1;
+             {
+               val = read_uleb128 (p, &len, end);
+               p += len;
+               printf (_("flag = %d, vendor = "), val);
+               if (p < end - 1)
+                 {
+                   size_t maxlen = (end - p) - 1;
+
+                   print_symbol ((int) maxlen, (const char *) p);
+                   p += strnlen ((char *) p, maxlen) + 1;
+                 }
+               else
+                 {
+                   printf (_("<corrupt>"));
+                   p = (unsigned char *) end;
+                 }
+               putchar ('\n');
+             }
              break;
 
            case 64: /* Tag_nodefaults.  */
-             p++;
+             /* PR 17531: file: 001-505008-0.01.  */
+             if (p < end)
+               p++;
              printf (_("True\n"));
              break;
 
            case 65: /* Tag_also_compatible_with.  */
-             val = read_uleb128 (p, &len);
+             val = read_uleb128 (p, &len, end);
              p += len;
              if (val == 6 /* Tag_CPU_arch.  */)
                {
-                 val = read_uleb128 (p, &len);
+                 val = read_uleb128 (p, &len, end);
                  p += len;
-                 if ((unsigned int)val >= ARRAY_SIZE (arm_attr_tag_CPU_arch))
+                 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.  */);
+             while (p < end && *(p++) != '\0' /* NUL terminator.  */)
+               ;
              break;
 
            default:
-             abort ();
+             printf (_("<unknown: %d>\n"), tag);
+             break;
            }
          return p;
 
        case 1:
+         return display_tag_value (-1, p, end);
        case 2:
-         type = attr->type;
-         break;
+         return display_tag_value (0, p, end);
 
        default:
          assert (attr->type & 0x80);
-         val = read_uleb128 (p, &len);
+         val = read_uleb128 (p, &len, end);
          p += len;
          type = attr->type & 0x7f;
          if (val >= type)
@@ -11193,87 +12657,71 @@ display_arm_attribute (unsigned char * p)
          return p;
        }
     }
-  else
-    {
-      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;
+  return display_tag_value (tag, p, end);
 }
 
 static unsigned char *
 display_gnu_attribute (unsigned char * p,
-                      unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int))
+                      unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int, const unsigned char * const),
+                      const unsigned char * const end)
 {
   int tag;
   unsigned int len;
   int val;
-  int type;
 
-  tag = read_uleb128 (p, &len);
+  tag = read_uleb128 (p, &len, end);
   p += len;
 
   /* Tag_compatibility is the only generic GNU attribute defined at
      present.  */
   if (tag == 32)
     {
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
-      printf (_("flag = %d, vendor = %s\n"), val, p);
-      p += strlen ((char *) p) + 1;
+
+      printf (_("flag = %d, vendor = "), val);
+      if (p == end)
+       {
+         printf (_("<corrupt>\n"));
+         warn (_("corrupt vendor attribute\n"));
+       }
+      else
+       {
+         if (p < end - 1)
+           {
+             size_t maxlen = (end - p) - 1;
+
+             print_symbol ((int) maxlen, (const char *) p);
+             p += strnlen ((char *) p, maxlen) + 1;
+           }
+         else
+           {
+             printf (_("<corrupt>"));
+             p = (unsigned char *) end;
+           }
+         putchar ('\n');
+       }
       return p;
     }
 
   if ((tag & 2) == 0 && display_proc_gnu_attribute)
-    return display_proc_gnu_attribute (p, tag);
-
-  if (tag & 1)
-    type = 1; /* String.  */
-  else
-    type = 2; /* uleb128.  */
-  printf ("  Tag_unknown_%d: ", tag);
-
-  if (type == 1)
-    {
-      printf ("\"%s\"\n", p);
-      p += strlen ((char *) p) + 1;
-    }
-  else
-    {
-      val = read_uleb128 (p, &len);
-      p += len;
-      printf ("%d (0x%x)\n", val, val);
-    }
+    return display_proc_gnu_attribute (p, tag, end);
 
-  return p;
+  return display_tag_value (tag, p, end);
 }
 
 static unsigned char *
-display_power_gnu_attribute (unsigned char * p, int tag)
+display_power_gnu_attribute (unsigned char * p,
+                            int tag,
+                            const unsigned char * const end)
 {
-  int type;
   unsigned int len;
   int val;
 
   if (tag == Tag_GNU_Power_ABI_FP)
     {
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_GNU_Power_ABI_FP: ");
 
@@ -11300,7 +12748,7 @@ display_power_gnu_attribute (unsigned char * p, int tag)
 
   if (tag == Tag_GNU_Power_ABI_Vector)
     {
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_GNU_Power_ABI_Vector: ");
       switch (val)
@@ -11326,7 +12774,13 @@ display_power_gnu_attribute (unsigned char * p, int tag)
 
   if (tag == Tag_GNU_Power_ABI_Struct_Return)
     {
-      val = read_uleb128 (p, &len);
+      if (p == end)
+       {
+         warn (_("corrupt Tag_GNU_Power_ABI_Struct_Return\n"));
+         return p;
+       }
+
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_GNU_Power_ABI_Struct_Return: ");
       switch (val)
@@ -11347,25 +12801,7 @@ display_power_gnu_attribute (unsigned char * p, int tag)
       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;
+  return display_tag_value (tag & 1, p, end);
 }
 
 static void
@@ -11374,6 +12810,7 @@ display_sparc_hwcaps (int mask)
   if (mask)
     {
       int first = 1;
+
       if (mask & ELF_SPARC_HWCAP_MUL32)
        fputs ("mul32", stdout), first = 0;
       if (mask & ELF_SPARC_HWCAP_DIV32)
@@ -11408,120 +12845,169 @@ display_sparc_hwcaps (int mask)
        printf ("%scspare", first ? "" : "|"), first = 0;
     }
   else
-    fputc('0', stdout);
-  fputc('\n', stdout);
+    fputc ('0', stdout);
+  fputc ('\n', stdout);
+}
+
+static void
+display_sparc_hwcaps2 (int mask)
+{
+  if (mask)
+    {
+      int first = 1;
+
+      if (mask & ELF_SPARC_HWCAP2_FJATHPLUS)
+       fputs ("fjathplus", stdout), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_VIS3B)
+       printf ("%svis3b", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_ADP)
+       printf ("%sadp", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_SPARC5)
+       printf ("%ssparc5", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_MWAIT)
+       printf ("%smwait", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_XMPMUL)
+       printf ("%sxmpmul", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_XMONT)
+       printf ("%sxmont2", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_NSEC)
+       printf ("%snsec", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_FJATHHPC)
+       printf ("%sfjathhpc", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_FJDES)
+       printf ("%sfjdes", first ? "" : "|"), first = 0;
+      if (mask & ELF_SPARC_HWCAP2_FJAES)
+       printf ("%sfjaes", first ? "" : "|"), first = 0;
+    }
+  else
+    fputc ('0', stdout);
+  fputc ('\n', stdout);
 }
 
 static unsigned char *
-display_sparc_gnu_attribute (unsigned char * p, int tag)
+display_sparc_gnu_attribute (unsigned char * p,
+                            int tag,
+                            const unsigned char * const end)
 {
-  int type;
   unsigned int len;
   int val;
 
   if (tag == Tag_GNU_Sparc_HWCAPS)
     {
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_GNU_Sparc_HWCAPS: ");
-
       display_sparc_hwcaps (val);
       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
+  if (tag == Tag_GNU_Sparc_HWCAPS2)
     {
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
-      printf ("%d (0x%x)\n", val, val);
+      printf ("  Tag_GNU_Sparc_HWCAPS2: ");
+      display_sparc_hwcaps2 (val);
+      return p;
     }
 
-  return p;
+  return display_tag_value (tag, p, end);
 }
 
-static unsigned char *
-display_mips_gnu_attribute (unsigned char * p, int tag)
+static void
+print_mips_fp_abi_value (int val)
 {
-  int type;
-  unsigned int len;
-  int val;
+  switch (val)
+    {
+    case Val_GNU_MIPS_ABI_FP_ANY:
+      printf (_("Hard or soft float\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_DOUBLE:
+      printf (_("Hard float (double precision)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_SINGLE:
+      printf (_("Hard float (single precision)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_SOFT:
+      printf (_("Soft float\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_OLD_64:
+      printf (_("Hard float (MIPS32r2 64-bit FPU 12 callee-saved)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_XX:
+      printf (_("Hard float (32-bit CPU, Any FPU)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_64:
+      printf (_("Hard float (32-bit CPU, 64-bit FPU)\n"));
+      break;
+    case Val_GNU_MIPS_ABI_FP_64A:
+      printf (_("Hard float compat (32-bit CPU, 64-bit FPU)\n"));
+      break;
+    default:
+      printf ("??? (%d)\n", val);
+      break;
+    }
+}
 
+static unsigned char *
+display_mips_gnu_attribute (unsigned char * p,
+                           int tag,
+                           const unsigned char * const end)
+{
   if (tag == Tag_GNU_MIPS_ABI_FP)
     {
-      val = read_uleb128 (p, &len);
+      unsigned int len;
+      int val;
+
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_GNU_MIPS_ABI_FP: ");
 
+      print_mips_fp_abi_value (val);
+
+      return p;
+   }
+
+  if (tag == Tag_GNU_MIPS_ABI_MSA)
+    {
+      unsigned int len;
+      int val;
+
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_GNU_MIPS_ABI_MSA: ");
+
       switch (val)
        {
-       case 0:
-         printf (_("Hard or soft float\n"));
-         break;
-       case 1:
-         printf (_("Hard float (double precision)\n"));
-         break;
-       case 2:
-         printf (_("Hard float (single precision)\n"));
-         break;
-       case 3:
-         printf (_("Soft float\n"));
+       case Val_GNU_MIPS_ABI_MSA_ANY:
+         printf (_("Any MSA or not\n"));
          break;
-       case 4:
-         printf (_("Hard float (MIPS32r2 64-bit FPU)\n"));
+       case Val_GNU_MIPS_ABI_MSA_128:
+         printf (_("128-bit MSA\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;
+  return display_tag_value (tag & 1, p, end);
 }
 
 static unsigned char *
-display_tic6x_attribute (unsigned char * p)
+display_tic6x_attribute (unsigned char * p,
+                        const unsigned char * const end)
 {
   int tag;
   unsigned int len;
   int val;
 
-  tag = read_uleb128 (p, &len);
+  tag = read_uleb128 (p, &len, end);
   p += len;
 
   switch (tag)
     {
     case Tag_ISA:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ISA: ");
 
@@ -11555,7 +13041,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_wchar_t:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_wchar_t: ");
       switch (val)
@@ -11576,7 +13062,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_stack_align_needed:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_stack_align_needed: ");
       switch (val)
@@ -11594,7 +13080,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_stack_align_preserved:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_stack_align_preserved: ");
       switch (val)
@@ -11612,7 +13098,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_DSBT:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_DSBT: ");
       switch (val)
@@ -11630,7 +13116,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_PID:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_PID: ");
       switch (val)
@@ -11651,7 +13137,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_PIC:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_PIC: ");
       switch (val)
@@ -11669,7 +13155,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_array_object_alignment:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_array_object_alignment: ");
       switch (val)
@@ -11690,7 +13176,7 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_array_object_align_expected:
-      val = read_uleb128 (p, &len);
+      val = read_uleb128 (p, &len, end);
       p += len;
       printf ("  Tag_ABI_array_object_align_expected: ");
       switch (val)
@@ -11711,34 +13197,178 @@ display_tic6x_attribute (unsigned char * p)
       return p;
 
     case Tag_ABI_compatibility:
-      val = read_uleb128 (p, &len);
-      p += len;
-      printf ("  Tag_ABI_compatibility: ");
-      printf (_("flag = %d, vendor = %s\n"), val, p);
-      p += strlen ((char *) p) + 1;
-      return p;
+      {
+       val = read_uleb128 (p, &len, end);
+       p += len;
+       printf ("  Tag_ABI_compatibility: ");
+       printf (_("flag = %d, vendor = "), val);
+       if (p < end - 1)
+         {
+           size_t maxlen = (end - p) - 1;
+
+           print_symbol ((int) maxlen, (const char *) p);
+           p += strnlen ((char *) p, maxlen) + 1;
+         }
+       else
+         {
+           printf (_("<corrupt>"));
+           p = (unsigned char *) end;
+         }
+       putchar ('\n');
+       return p;
+      }
 
     case Tag_ABI_conformance:
-      printf ("  Tag_ABI_conformance: ");
-      printf ("\"%s\"\n", p);
-      p += strlen ((char *) p) + 1;
-      return p;
+      {
+       printf ("  Tag_ABI_conformance: \"");
+       if (p < end - 1)
+         {
+           size_t maxlen = (end - p) - 1;
+
+           print_symbol ((int) maxlen, (const char *) p);
+           p += strnlen ((char *) p, maxlen) + 1;
+         }
+       else
+         {
+           printf (_("<corrupt>"));
+           p = (unsigned char *) end;
+         }
+       printf ("\"\n");
+       return p;
+      }
     }
 
-  printf ("  Tag_unknown_%d: ", tag);
+  return display_tag_value (tag, p, end);
+}
 
-  if (tag & 1)
+static void
+display_raw_attribute (unsigned char * p, unsigned char * end)
+{
+  unsigned long addr = 0;
+  size_t bytes = end - p;
+
+  assert (end > p);
+  while (bytes)
     {
-      printf ("\"%s\"\n", p);
-      p += strlen ((char *) p) + 1;
+      int j;
+      int k;
+      int lbytes = (bytes > 16 ? 16 : bytes);
+
+      printf ("  0x%8.8lx ", addr);
+
+      for (j = 0; j < 16; j++)
+       {
+         if (j < lbytes)
+           printf ("%2.2x", p[j]);
+         else
+           printf ("  ");
+
+         if ((j & 3) == 3)
+           printf (" ");
+       }
+
+      for (j = 0; j < lbytes; j++)
+       {
+         k = p[j];
+         if (k >= ' ' && k < 0x7f)
+           printf ("%c", k);
+         else
+           printf (".");
+       }
+
+      putchar ('\n');
+
+      p  += lbytes;
+      bytes -= lbytes;
+      addr += lbytes;
     }
-  else
+
+  putchar ('\n');
+}
+
+static unsigned char *
+display_msp430x_attribute (unsigned char * p,
+                          const unsigned char * const end)
+{
+  unsigned int len;
+  int val;
+  int tag;
+
+  tag = read_uleb128 (p, & len, end);
+  p += len;
+
+  switch (tag)
     {
-      val = read_uleb128 (p, &len);
+    case OFBA_MSPABI_Tag_ISA:
+      val = read_uleb128 (p, &len, end);
       p += len;
-      printf ("%d (0x%x)\n", val, val);
-    }
+      printf ("  Tag_ISA: ");
+      switch (val)
+       {
+       case 0: printf (_("None\n")); break;
+       case 1: printf (_("MSP430\n")); break;
+       case 2: printf (_("MSP430X\n")); break;
+       default: printf ("??? (%d)\n", val); break;
+       }
+      break;
+
+    case OFBA_MSPABI_Tag_Code_Model:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_Code_Model: ");
+      switch (val)
+       {
+       case 0: printf (_("None\n")); break;
+       case 1: printf (_("Small\n")); break;
+       case 2: printf (_("Large\n")); break;
+       default: printf ("??? (%d)\n", val); break;
+       }
+      break;
 
+    case OFBA_MSPABI_Tag_Data_Model:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_Data_Model: ");
+      switch (val)
+       {
+       case 0: printf (_("None\n")); break;
+       case 1: printf (_("Small\n")); break;
+       case 2: printf (_("Large\n")); break;
+       case 3: printf (_("Restricted Large\n")); break;
+       default: printf ("??? (%d)\n", val); break;
+       }
+      break;
+
+    default:
+      printf (_("  <unknown tag %d>: "), tag);
+
+      if (tag & 1)
+       {
+         putchar ('"');
+         if (p < end - 1)
+           {
+             size_t maxlen = (end - p) - 1;
+
+             print_symbol ((int) maxlen, (const char *) p);
+             p += strnlen ((char *) p, maxlen) + 1;
+           }
+         else
+           {
+             printf (_("<corrupt>"));
+             p = (unsigned char *) end;
+           }
+         printf ("\"\n");
+       }
+      else
+       {
+         val = read_uleb128 (p, &len, end);
+         p += len;
+         printf ("%d (0x%x)\n", val, val);
+       }
+      break;
+   }
+
+  assert (p <= end);
   return p;
 }
 
@@ -11746,15 +13376,10 @@ static int
 process_attributes (FILE * file,
                    const char * public_name,
                    unsigned int proc_type,
-                   unsigned char * (* display_pub_attribute) (unsigned char *),
-                   unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int))
+                   unsigned char * (* display_pub_attribute) (unsigned char *, const unsigned char * const),
+                   unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int, const unsigned char * const))
 {
   Elf_Internal_Shdr * sect;
-  unsigned char * contents;
-  unsigned char * p;
-  unsigned char * end;
-  bfd_vma section_len;
-  bfd_vma len;
   unsigned i;
 
   /* Find the section header so that we get the size.  */
@@ -11762,6 +13387,9 @@ process_attributes (FILE * file,
        i < elf_header.e_shnum;
        i++, sect++)
     {
+      unsigned char * contents;
+      unsigned char * p;
+
       if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES)
        continue;
 
@@ -11773,27 +13401,52 @@ process_attributes (FILE * file,
       p = contents;
       if (*p == 'A')
        {
-         len = sect->sh_size - 1;
+         bfd_vma section_len;
+
+         section_len = sect->sh_size - 1;
          p++;
 
-         while (len > 0)
+         while (section_len > 0)
            {
-             int namelen;
+             bfd_vma attr_len;
+             unsigned int namelen;
              bfd_boolean public_section;
              bfd_boolean gnu_section;
 
-             section_len = byte_get (p, 4);
+             if (section_len <= 4)
+               {
+                 error (_("Tag section ends prematurely\n"));
+                 break;
+               }
+             attr_len = byte_get (p, 4);
              p += 4;
 
-             if (section_len > len)
+             if (attr_len > section_len)
                {
-                 printf (_("ERROR: Bad section length (%d > %d)\n"),
-                         (int) section_len, (int) len);
-                 section_len = len;
+                 error (_("Bad attribute length (%u > %u)\n"),
+                         (unsigned) attr_len, (unsigned) section_len);
+                 attr_len = section_len;
+               }
+             /* PR 17531: file: 001-101425-0.004  */
+             else if (attr_len < 5)
+               {
+                 error (_("Attribute length of %u is too small\n"), (unsigned) attr_len);
+                 break;
+               }
+
+             section_len -= attr_len;
+             attr_len -= 4;
+
+             namelen = strnlen ((char *) p, attr_len) + 1;
+             if (namelen == 0 || namelen >= attr_len)
+               {
+                 error (_("Corrupt attribute section name\n"));
+                 break;
                }
 
-             len -= section_len;
-             printf (_("Attribute Section: %s\n"), p);
+             printf (_("Attribute Section: "));
+             print_symbol (INT_MAX, (const char *) p);
+             putchar ('\n');
 
              if (public_name && streq ((char *) p, public_name))
                public_section = TRUE;
@@ -11805,26 +13458,44 @@ process_attributes (FILE * file,
              else
                gnu_section = FALSE;
 
-             namelen = strlen ((char *) p) + 1;
              p += namelen;
-             section_len -= namelen + 4;
+             attr_len -= namelen;
 
-             while (section_len > 0)
+             while (attr_len > 0 && p < contents + sect->sh_size)
                {
-                 int tag = *(p++);
+                 int tag;
                  int val;
                  bfd_vma size;
+                 unsigned char * end;
+
+                 /* PR binutils/17531: Safe handling of corrupt files.  */
+                 if (attr_len < 6)
+                   {
+                     error (_("Unused bytes at end of section\n"));
+                     section_len = 0;
+                     break;
+                   }
 
+                 tag = *(p++);
                  size = byte_get (p, 4);
-                 if (size > section_len)
+                 if (size > attr_len)
+                   {
+                     error (_("Bad subsection length (%u > %u)\n"),
+                             (unsigned) size, (unsigned) attr_len);
+                     size = attr_len;
+                   }
+                 /* PR binutils/17531: Safe handling of corrupt files.  */
+                 if (size < 6)
                    {
-                     printf (_("ERROR: Bad subsection length (%d > %d)\n"),
-                             (int) size, (int) section_len);
-                     size = section_len;
+                     error (_("Bad subsection length (%u < 6)\n"),
+                             (unsigned) size);
+                     section_len = 0;
+                     break;
                    }
 
-                 section_len -= size;
+                 attr_len -= size;
                  end = p + size - 1;
+                 assert (end <= contents + sect->sh_size);
                  p += 4;
 
                  switch (tag)
@@ -11842,7 +13513,7 @@ process_attributes (FILE * file,
                        {
                          unsigned int j;
 
-                         val = read_uleb128 (p, &j);
+                         val = read_uleb128 (p, &j, end);
                          p += j;
                          if (val == 0)
                            break;
@@ -11856,28 +13527,33 @@ process_attributes (FILE * file,
                      break;
                    }
 
-                 if (public_section)
+                 if (public_section && display_pub_attribute != NULL)
                    {
                      while (p < end)
-                       p = display_pub_attribute (p);
+                       p = display_pub_attribute (p, end);
+                     assert (p <= end);
                    }
-                 else if (gnu_section)
+                 else if (gnu_section && display_proc_gnu_attribute != NULL)
                    {
                      while (p < end)
                        p = display_gnu_attribute (p,
-                                                  display_proc_gnu_attribute);
+                                                  display_proc_gnu_attribute,
+                                                  end);
+                     assert (p <= end);
                    }
-                 else
+                 else if (p < end)
                    {
-                     /* ??? Do something sensible, like dump hex.  */
-                     printf (_("  Unknown section contexts\n"));
+                     printf (_("  Unknown attribute:\n"));
+                     display_raw_attribute (p, end);
                      p = end;
                    }
+                 else
+                   attr_len = 0;
                }
            }
        }
       else
-       printf (_("Unknown format '%c'\n"), *p);
+       printf (_("Unknown format '%c' (%d)\n"), *p, *p);
 
       free (contents);
     }
@@ -11912,12 +13588,21 @@ process_tic6x_specific (FILE * file)
                             display_tic6x_attribute, NULL);
 }
 
+static int
+process_msp430x_specific (FILE * file)
+{
+  return process_attributes (file, "mspabi", SHT_MSP430_ATTRIBUTES,
+                            display_msp430x_attribute, NULL);
+}
+
 /* 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.  */
+   and return the VMA of the next entry, or -1 if there was a problem.
+   Does not read from DATA_END or beyond.  */
 
 static bfd_vma
-print_mips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr)
+print_mips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr,
+                     unsigned char * data_end)
 {
   printf ("  ");
   print_vma (addr, LONG_HEX);
@@ -11932,9 +13617,19 @@ print_mips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr)
   else
     {
       bfd_vma entry;
+      unsigned char * from = data + addr - pltgot;
 
-      entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
-      print_vma (entry, LONG_HEX);
+      if (from + (is_32bit_elf ? 4 : 8) > data_end)
+       {
+         warn (_("MIPS GOT entry extends beyond the end of available data\n"));
+         printf ("%*s", is_32bit_elf ? 8 : 16, _("<corrupt>"));
+         return (bfd_vma) -1;
+       }
+      else
+       {
+         entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
+         print_vma (entry, LONG_HEX);
+       }
     }
   return addr + (is_32bit_elf ? 4 : 8);
 }
@@ -11961,10 +13656,126 @@ print_mips_pltgot_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr)
   return addr + (is_32bit_elf ? 4 : 8);
 }
 
+static void
+print_mips_ases (unsigned int mask)
+{
+  if (mask & AFL_ASE_DSP)
+    fputs ("\n\tDSP ASE", stdout);
+  if (mask & AFL_ASE_DSPR2)
+    fputs ("\n\tDSP R2 ASE", stdout);
+  if (mask & AFL_ASE_EVA)
+    fputs ("\n\tEnhanced VA Scheme", stdout);
+  if (mask & AFL_ASE_MCU)
+    fputs ("\n\tMCU (MicroController) ASE", stdout);
+  if (mask & AFL_ASE_MDMX)
+    fputs ("\n\tMDMX ASE", stdout);
+  if (mask & AFL_ASE_MIPS3D)
+    fputs ("\n\tMIPS-3D ASE", stdout);
+  if (mask & AFL_ASE_MT)
+    fputs ("\n\tMT ASE", stdout);
+  if (mask & AFL_ASE_SMARTMIPS)
+    fputs ("\n\tSmartMIPS ASE", stdout);
+  if (mask & AFL_ASE_VIRT)
+    fputs ("\n\tVZ ASE", stdout);
+  if (mask & AFL_ASE_MSA)
+    fputs ("\n\tMSA ASE", stdout);
+  if (mask & AFL_ASE_MIPS16)
+    fputs ("\n\tMIPS16 ASE", stdout);
+  if (mask & AFL_ASE_MICROMIPS)
+    fputs ("\n\tMICROMIPS ASE", stdout);
+  if (mask & AFL_ASE_XPA)
+    fputs ("\n\tXPA ASE", stdout);
+  if (mask == 0)
+    fprintf (stdout, "\n\t%s", _("None"));
+  else if ((mask & ~AFL_ASE_MASK) != 0)
+    fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~AFL_ASE_MASK);
+}
+
+static void
+print_mips_isa_ext (unsigned int isa_ext)
+{
+  switch (isa_ext)
+    {
+    case 0:
+      fputs (_("None"), stdout);
+      break;
+    case AFL_EXT_XLR:
+      fputs ("RMI XLR", stdout);
+      break;
+    case AFL_EXT_OCTEON3:
+      fputs ("Cavium Networks Octeon3", stdout);
+      break;
+    case AFL_EXT_OCTEON2:
+      fputs ("Cavium Networks Octeon2", stdout);
+      break;
+    case AFL_EXT_OCTEONP:
+      fputs ("Cavium Networks OcteonP", stdout);
+      break;
+    case AFL_EXT_LOONGSON_3A:
+      fputs ("Loongson 3A", stdout);
+      break;
+    case AFL_EXT_OCTEON:
+      fputs ("Cavium Networks Octeon", stdout);
+      break;
+    case AFL_EXT_5900:
+      fputs ("Toshiba R5900", stdout);
+      break;
+    case AFL_EXT_4650:
+      fputs ("MIPS R4650", stdout);
+      break;
+    case AFL_EXT_4010:
+      fputs ("LSI R4010", stdout);
+      break;
+    case AFL_EXT_4100:
+      fputs ("NEC VR4100", stdout);
+      break;
+    case AFL_EXT_3900:
+      fputs ("Toshiba R3900", stdout);
+      break;
+    case AFL_EXT_10000:
+      fputs ("MIPS R10000", stdout);
+      break;
+    case AFL_EXT_SB1:
+      fputs ("Broadcom SB-1", stdout);
+      break;
+    case AFL_EXT_4111:
+      fputs ("NEC VR4111/VR4181", stdout);
+      break;
+    case AFL_EXT_4120:
+      fputs ("NEC VR4120", stdout);
+      break;
+    case AFL_EXT_5400:
+      fputs ("NEC VR5400", stdout);
+      break;
+    case AFL_EXT_5500:
+      fputs ("NEC VR5500", stdout);
+      break;
+    case AFL_EXT_LOONGSON_2E:
+      fputs ("ST Microelectronics Loongson 2E", stdout);
+      break;
+    case AFL_EXT_LOONGSON_2F:
+      fputs ("ST Microelectronics Loongson 2F", stdout);
+      break;
+    default:
+      fprintf (stdout, "%s (%d)", _("Unknown"), isa_ext);
+    }
+}
+
+static int
+get_mips_reg_size (int reg_size)
+{
+  return (reg_size == AFL_REG_NONE) ? 0
+        : (reg_size == AFL_REG_32) ? 32
+        : (reg_size == AFL_REG_64) ? 64
+        : (reg_size == AFL_REG_128) ? 128
+        : -1;
+}
+
 static int
 process_mips_specific (FILE * file)
 {
   Elf_Internal_Dyn * entry;
+  Elf_Internal_Shdr *sect = NULL;
   size_t liblist_offset = 0;
   size_t liblistno = 0;
   size_t conflictsno = 0;
@@ -11979,15 +13790,69 @@ process_mips_specific (FILE * file)
   bfd_vma gotsym = 0;
   bfd_vma symtabno = 0;
 
-  process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
-                     display_mips_gnu_attribute);
+  process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
+                     display_mips_gnu_attribute);
+
+  sect = find_section (".MIPS.abiflags");
+
+  if (sect != NULL)
+    {
+      Elf_External_ABIFlags_v0 *abiflags_ext;
+      Elf_Internal_ABIFlags_v0 abiflags_in;
+
+      if (sizeof (Elf_External_ABIFlags_v0) != sect->sh_size)
+       fputs ("\nCorrupt ABI Flags section.\n", stdout);
+      else
+       {
+         abiflags_ext = get_data (NULL, file, sect->sh_offset, 1,
+                                  sect->sh_size, _("MIPS ABI Flags section"));
+         if (abiflags_ext)
+           {
+             abiflags_in.version = BYTE_GET (abiflags_ext->version);
+             abiflags_in.isa_level = BYTE_GET (abiflags_ext->isa_level);
+             abiflags_in.isa_rev = BYTE_GET (abiflags_ext->isa_rev);
+             abiflags_in.gpr_size = BYTE_GET (abiflags_ext->gpr_size);
+             abiflags_in.cpr1_size = BYTE_GET (abiflags_ext->cpr1_size);
+             abiflags_in.cpr2_size = BYTE_GET (abiflags_ext->cpr2_size);
+             abiflags_in.fp_abi = BYTE_GET (abiflags_ext->fp_abi);
+             abiflags_in.isa_ext = BYTE_GET (abiflags_ext->isa_ext);
+             abiflags_in.ases = BYTE_GET (abiflags_ext->ases);
+             abiflags_in.flags1 = BYTE_GET (abiflags_ext->flags1);
+             abiflags_in.flags2 = BYTE_GET (abiflags_ext->flags2);
+
+             printf ("\nMIPS ABI Flags Version: %d\n", abiflags_in.version);
+             printf ("\nISA: MIPS%d", abiflags_in.isa_level);
+             if (abiflags_in.isa_rev > 1)
+               printf ("r%d", abiflags_in.isa_rev);
+             printf ("\nGPR size: %d",
+                     get_mips_reg_size (abiflags_in.gpr_size));
+             printf ("\nCPR1 size: %d",
+                     get_mips_reg_size (abiflags_in.cpr1_size));
+             printf ("\nCPR2 size: %d",
+                     get_mips_reg_size (abiflags_in.cpr2_size));
+             fputs ("\nFP ABI: ", stdout);
+             print_mips_fp_abi_value (abiflags_in.fp_abi);
+             fputs ("ISA Extension: ", stdout);
+             print_mips_isa_ext (abiflags_in.isa_ext);
+             fputs ("\nASEs:", stdout);
+             print_mips_ases (abiflags_in.ases);
+             printf ("\nFLAGS 1: %8.8lx", abiflags_in.flags1);
+             printf ("\nFLAGS 2: %8.8lx", abiflags_in.flags2);
+             fputc ('\n', stdout);
+             free (abiflags_ext);
+           }
+       }
+    }
 
   /* We have a lot of special sections.  Thanks SGI!  */
   if (dynamic_section == NULL)
     /* No information available.  */
     return 0;
 
-  for (entry = dynamic_section; entry->d_tag != DT_NULL; ++entry)
+  for (entry = dynamic_section;
+       /* PR 17531 file: 012-50589-0.004.  */
+       entry < dynamic_section + dynamic_nent && entry->d_tag != DT_NULL;
+       ++entry)
     switch (entry->d_tag)
       {
       case DT_MIPS_LIBLIST:
@@ -12121,15 +13986,20 @@ 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;
       size_t offset;
       int cnt;
+      sect = section_headers;
 
       /* Find the section header so that we get the size.  */
-      while (sect->sh_type != SHT_MIPS_OPTIONS)
-       ++sect;
+      sect = find_section_by_type (SHT_MIPS_OPTIONS);
+      /* PR 17533 file: 012-277276-0.004.  */
+      if (sect == NULL)
+       {
+         error (_("No MIPS_OPTIONS header found\n"));
+         return 0;
+       }
 
       eopt = (Elf_External_Options *) get_data (NULL, file, options_offset, 1,
                                                 sect->sh_size, _("options"));
@@ -12139,14 +14009,14 @@ process_mips_specific (FILE * file)
               cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (* iopt));
          if (iopt == NULL)
            {
-             error (_("Out of memory\n"));
+             error (_("Out of memory allocatinf space for MIPS options\n"));
              return 0;
            }
 
          offset = cnt = 0;
          option = iopt;
 
-         while (offset < sect->sh_size)
+         while (offset <= sect->sh_size - sizeof (* eopt))
            {
              Elf_External_Options * eoption;
 
@@ -12157,16 +14027,24 @@ process_mips_specific (FILE * file)
              option->section = BYTE_GET (eoption->section);
              option->info = BYTE_GET (eoption->info);
 
+             /* PR 17531: file: ffa0fa3b.  */
+             if (option->size < sizeof (* eopt)
+                 || offset + option->size > sect->sh_size)
+               {
+                 error (_("Invalid size (%u) for MIPS option\n"), option->size);
+                 return 0;
+               }
              offset += option->size;
-
+               
              ++option;
              ++cnt;
            }
 
          printf (_("\nSection '%s' contains %d entries:\n"),
-                 SECTION_NAME (sect), cnt);
+                 printable_section_name (sect), cnt);
 
          option = iopt;
+         offset = 0;
 
          while (cnt-- > 0)
            {
@@ -12303,13 +14181,18 @@ process_mips_specific (FILE * file)
 
              len = sizeof (* eopt);
              while (len < option->size)
-               if (((char *) option)[len] >= ' '
-                   && ((char *) option)[len] < 0x7f)
-                 printf ("%c", ((char *) option)[len++]);
-               else
-                 printf ("\\%03o", ((char *) option)[len++]);
+               {
+                 char datum = * ((char *) eopt + offset + len);
 
+                 if (ISPRINT (datum))
+                   printf ("%c", datum);
+                 else
+                   printf ("\\%03o", datum);
+                 len ++;
+               }
              fputs ("\n", stdout);
+
+             offset += option->size;
              ++option;
            }
 
@@ -12331,7 +14214,7 @@ process_mips_specific (FILE * file)
       iconf = (Elf32_Conflict *) cmalloc (conflictsno, sizeof (* iconf));
       if (iconf == NULL)
        {
-         error (_("Out of memory\n"));
+         error (_("Out of memory allocating space for dynamic conflicts\n"));
          return 0;
        }
 
@@ -12372,15 +14255,22 @@ process_mips_specific (FILE * file)
 
       for (cnt = 0; cnt < conflictsno; ++cnt)
        {
-         Elf_Internal_Sym * psym = & dynamic_symbols[iconf[cnt]];
-
          printf ("%5lu: %8lu  ", (unsigned long) cnt, iconf[cnt]);
-         print_vma (psym->st_value, FULL_HEX);
-         putchar (' ');
-         if (VALID_DYNAMIC_NAME (psym->st_name))
-           print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
+
+         if (iconf[cnt] >= num_dynamic_syms)
+           printf (_("<corrupt symbol index>"));
          else
-           printf (_("<corrupt: %14ld>"), psym->st_name);
+           {
+             Elf_Internal_Sym * psym;
+
+             psym = & dynamic_symbols[iconf[cnt]];
+             print_vma (psym->st_value, FULL_HEX);
+             putchar (' ');
+             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');
        }
 
@@ -12392,12 +14282,28 @@ process_mips_specific (FILE * file)
       bfd_vma ent, local_end, global_end;
       size_t i, offset;
       unsigned char * data;
+      unsigned char * data_end;
       int addr_size;
 
       ent = pltgot;
       addr_size = (is_32bit_elf ? 4 : 8);
       local_end = pltgot + local_gotno * addr_size;
+
+      /* PR binutils/17533 file: 012-111227-0.004  */
+      if (symtabno < gotsym)
+       {
+         error (_("The GOT symbol offset (%lu) is greater than the symbol table size (%lu)\n"),
+                (unsigned long) gotsym, (unsigned long) symtabno);
+         return 0;
+       }
+
       global_end = local_end + (symtabno - gotsym) * addr_size;
+      /* PR 17531: file: 54c91a34.  */
+      if (global_end < local_end)
+       {
+         error (_("Too many GOT symbols: %lu\n"), (unsigned long) symtabno);
+         return 0;
+       }
 
       offset = offset_from_vma (file, pltgot, global_end - pltgot);
       data = (unsigned char *) get_data (NULL, file, offset,
@@ -12405,6 +14311,7 @@ process_mips_specific (FILE * file)
                                         _("Global Offset Table data"));
       if (data == NULL)
        return 0;
+      data_end = data + (global_end - pltgot);
 
       printf (_("\nPrimary GOT:\n"));
       printf (_(" Canonical gp value: "));
@@ -12415,14 +14322,18 @@ process_mips_specific (FILE * file)
       printf (_("  %*s %10s %*s Purpose\n"),
              addr_size * 2, _("Address"), _("Access"),
              addr_size * 2, _("Initial"));
-      ent = print_mips_got_entry (data, pltgot, ent);
+      ent = print_mips_got_entry (data, pltgot, ent, data_end);
       printf (_(" Lazy resolver\n"));
+      if (ent == (bfd_vma) -1)
+       goto got_print_fail;
       if (data
          && (byte_get (data + ent - pltgot, addr_size)
              >> (addr_size * 8 - 1)) != 0)
        {
-         ent = print_mips_got_entry (data, pltgot, ent);
+         ent = print_mips_got_entry (data, pltgot, ent, data_end);
          printf (_(" Module pointer (GNU extension)\n"));
+         if (ent == (bfd_vma) -1)
+           goto got_print_fail;
        }
       printf ("\n");
 
@@ -12434,8 +14345,10 @@ process_mips_specific (FILE * file)
                  addr_size * 2, _("Initial"));
          while (ent < local_end)
            {
-             ent = print_mips_got_entry (data, pltgot, ent);
+             ent = print_mips_got_entry (data, pltgot, ent, data_end);
              printf ("\n");
+             if (ent == (bfd_vma) -1)
+               goto got_print_fail;
            }
          printf ("\n");
        }
@@ -12453,28 +14366,42 @@ process_mips_specific (FILE * file)
                  _("Type"),
                  /* Note for translators: "Ndx" = abbreviated form of "Index".  */
                  _("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;
-             ent = print_mips_got_entry (data, pltgot, ent);
+             ent = print_mips_got_entry (data, pltgot, ent, data_end);
              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));
+
+             if (dynamic_symbols == NULL)
+               printf (_("<no dynamic symbols>"));
+             else if (i < num_dynamic_syms)
+               {
+                 Elf_Internal_Sym * psym = dynamic_symbols + i;
+
+                 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);
+               }
              else
-               printf (_("<corrupt: %14ld>"), psym->st_name);
+               printf (_("<symbol index %lu exceeds number of dynamic symbols>"),
+                       (unsigned long) i);
+
              printf ("\n");
+             if (ent == (bfd_vma) -1)
+               break;
            }
          printf ("\n");
        }
 
+    got_print_fail:
       if (data)
        free (data);
     }
@@ -12528,19 +14455,26 @@ process_mips_specific (FILE * file)
       sym_width = (is_32bit_elf ? 80 : 160) - 17 - addr_size * 6 - 1;
       for (i = 0; i < count; i++)
        {
-         Elf_Internal_Sym * psym;
+         unsigned long idx = get_reloc_symindex (rels[i].r_info);
 
-         psym = dynamic_symbols + get_reloc_symindex (rels[i].r_info);
          ent = print_mips_pltgot_entry (data, mips_pltgot, ent);
          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));
+
+         if (idx >= num_dynamic_syms)
+           printf (_("<corrupt symbol index: %lu>"), idx);
          else
-           printf (_("<corrupt: %14ld>"), psym->st_name);
+           {
+             Elf_Internal_Sym * psym = dynamic_symbols + idx;
+
+             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");
@@ -12553,6 +14487,40 @@ process_mips_specific (FILE * file)
   return 1;
 }
 
+static int
+process_nds32_specific (FILE * file)
+{
+  Elf_Internal_Shdr *sect = NULL;
+
+  sect = find_section (".nds32_e_flags");
+  if (sect != NULL)
+    {
+      unsigned int *flag;
+
+      printf ("\nNDS32 elf flags section:\n");
+      flag = get_data (NULL, file, sect->sh_offset, 1,
+                      sect->sh_size, _("NDS32 elf flags section"));
+
+      switch ((*flag) & 0x3)
+       {
+       case 0:
+         printf ("(VEC_SIZE):\tNo entry.\n");
+         break;
+       case 1:
+         printf ("(VEC_SIZE):\t4 bytes\n");
+         break;
+       case 2:
+         printf ("(VEC_SIZE):\t16 bytes\n");
+         break;
+       case 3:
+         printf ("(VEC_SIZE):\treserved\n");
+         break;
+       }
+    }
+
+  return TRUE;
+}
+
 static int
 process_gnu_liblist (FILE * file)
 {
@@ -12598,7 +14566,7 @@ process_gnu_liblist (FILE * file)
          strtab_size = string_sec->sh_size;
 
          printf (_("\nLibrary list section '%s' contains %lu entries:\n"),
-                 SECTION_NAME (section),
+                 printable_section_name (section),
                  (unsigned long) (section->sh_size / sizeof (Elf32_External_Lib)));
 
          puts (_("     Library              Time Stamp          Checksum   Version Flags"));
@@ -12684,8 +14652,24 @@ get_note_type (unsigned e_type)
        return _("NT_S390_CTRS (s390 control registers)");
       case NT_S390_PREFIX:
        return _("NT_S390_PREFIX (s390 prefix register)");
+      case NT_S390_LAST_BREAK:
+       return _("NT_S390_LAST_BREAK (s390 last breaking event address)");
+      case NT_S390_SYSTEM_CALL:
+       return _("NT_S390_SYSTEM_CALL (s390 system call restart data)");
+      case NT_S390_TDB:
+       return _("NT_S390_TDB (s390 transaction diagnostic block)");
+      case NT_S390_VXRS_LOW:
+       return _("NT_S390_VXRS_LOW (s390 vector registers 0-15 upper half)");
+      case NT_S390_VXRS_HIGH:
+       return _("NT_S390_VXRS_HIGH (s390 vector registers 16-31)");
       case NT_ARM_VFP:
        return _("NT_ARM_VFP (arm VFP registers)");
+      case NT_ARM_TLS:
+       return _("NT_ARM_TLS (AArch TLS registers)");
+      case NT_ARM_HW_BREAK:
+       return _("NT_ARM_HW_BREAK (AArch hardware breakpoint registers)");
+      case NT_ARM_HW_WATCH:
+       return _("NT_ARM_HW_WATCH (AArch hardware watchpoint registers)");
       case NT_PSTATUS:
        return _("NT_PSTATUS (pstatus structure)");
       case NT_FPREGS:
@@ -12850,6 +14834,13 @@ print_gnu_note (Elf_Internal_Note *pnote)
        unsigned long os, major, minor, subminor;
        const char *osname;
 
+       /* PR 17531: file: 030-599401-0.004.  */
+       if (pnote->descsz < 16)
+         {
+           printf (_("    <corrupt GNU_ABI_TAG>\n"));
+           break;
+         }
+
        os = byte_get ((unsigned char *) pnote->descdata, 4);
        major = byte_get ((unsigned char *) pnote->descdata + 4, 4);
        minor = byte_get ((unsigned char *) pnote->descdata + 8, 4);
@@ -12881,11 +14872,101 @@ print_gnu_note (Elf_Internal_Note *pnote)
                major, minor, subminor);
       }
       break;
+
+    case NT_GNU_GOLD_VERSION:
+      {
+       unsigned long i;
+
+       printf (_("    Version: "));
+       for (i = 0; i < pnote->descsz && pnote->descdata[i] != '\0'; ++i)
+         printf ("%c", pnote->descdata[i]);
+       printf ("\n");
+      }
+      break;
     }
 
   return 1;
 }
 
+static const char *
+get_v850_elf_note_type (enum v850_notes n_type)
+{
+  static char buff[64];
+
+  switch (n_type)
+    {
+    case V850_NOTE_ALIGNMENT:  return _("Alignment of 8-byte objects");
+    case V850_NOTE_DATA_SIZE:  return _("Sizeof double and long double");
+    case V850_NOTE_FPU_INFO:   return _("Type of FPU support needed");
+    case V850_NOTE_SIMD_INFO:  return _("Use of SIMD instructions");
+    case V850_NOTE_CACHE_INFO: return _("Use of cache");
+    case V850_NOTE_MMU_INFO:   return _("Use of MMU");
+    default:
+      snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), n_type);
+      return buff;
+    }
+}
+
+static int
+print_v850_note (Elf_Internal_Note * pnote)
+{
+  unsigned int val;
+
+  if (pnote->descsz != 4)
+    return 0;
+  val = byte_get ((unsigned char *) pnote->descdata, pnote->descsz);
+
+  if (val == 0)
+    {
+      printf (_("not set\n"));
+      return 1;
+    }
+
+  switch (pnote->type)
+    {
+    case V850_NOTE_ALIGNMENT:
+      switch (val)
+       {
+       case EF_RH850_DATA_ALIGN4: printf (_("4-byte\n")); return 1;
+       case EF_RH850_DATA_ALIGN8: printf (_("8-byte\n")); return 1;
+       }
+      break;
+       
+    case V850_NOTE_DATA_SIZE:
+      switch (val)
+       {
+       case EF_RH850_DOUBLE32: printf (_("4-bytes\n")); return 1;
+       case EF_RH850_DOUBLE64: printf (_("8-bytes\n")); return 1;
+       }
+      break;
+       
+    case V850_NOTE_FPU_INFO:
+      switch (val)
+       {
+       case EF_RH850_FPU20: printf (_("FPU-2.0\n")); return 1;
+       case EF_RH850_FPU30: printf (_("FPU-3.0\n")); return 1;
+       }
+      break;
+       
+    case V850_NOTE_MMU_INFO:
+    case V850_NOTE_CACHE_INFO:
+    case V850_NOTE_SIMD_INFO:
+      if (val == EF_RH850_SIMD)
+       {
+         printf (_("yes\n"));
+         return 1;
+       }
+      break;
+
+    default:
+      /* An 'unknown note type' message will already have been displayed.  */
+      break;
+    }
+
+  printf (_("unknown value: %x\n"), val);
+  return 0;
+}
+
 static const char *
 get_netbsd_elfcore_note_type (unsigned e_type)
 {
@@ -13068,7 +15149,7 @@ print_ia64_vms_note (Elf_Internal_Note * pnote)
     case NT_VMS_FPMODE:
       printf (_("   Floating Point mode: "));
       printf ("0x%016" BFD_VMA_FMT "x\n",
-              (bfd_vma)byte_get ((unsigned char *)pnote->descdata, 8));
+              (bfd_vma) byte_get ((unsigned char *)pnote->descdata, 8));
       break;
     case NT_VMS_LINKTIME:
       printf (_("   Link time: "));
@@ -13091,9 +15172,9 @@ print_ia64_vms_note (Elf_Internal_Note * pnote)
         ((bfd_int64_t) byte_get ((unsigned char *)pnote->descdata + 8, 8));
       printf (_("\n   Link flags  : "));
       printf ("0x%016" BFD_VMA_FMT "x\n",
-              (bfd_vma)byte_get ((unsigned char *)pnote->descdata + 16, 8));
+              (bfd_vma) byte_get ((unsigned char *)pnote->descdata + 16, 8));
       printf (_("   Header flags: 0x%08x\n"),
-              (unsigned)byte_get ((unsigned char *)pnote->descdata + 24, 4));
+              (unsigned) byte_get ((unsigned char *)pnote->descdata + 24, 4));
       printf (_("   Image id    : %s\n"), pnote->descdata + 32);
       break;
 #endif
@@ -13178,77 +15259,98 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length)
 {
   Elf_External_Note * pnotes;
   Elf_External_Note * external;
+  char * end;
   int res = 1;
 
   if (length <= 0)
     return 0;
 
   pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length,
-                                           _("notes"));
+                                          _("notes"));
   if (pnotes == NULL)
     return 0;
 
   external = pnotes;
 
-  printf (_("\nNotes at offset 0x%08lx with length 0x%08lx:\n"),
+  printf (_("\nDisplaying notes found at file offset 0x%08lx with length 0x%08lx:\n"),
          (unsigned long) offset, (unsigned long) length);
   printf (_("  %-20s %10s\tDescription\n"), _("Owner"), _("Data size"));
 
-  while (external < (Elf_External_Note *) ((char *) pnotes + length))
+  end = (char *) pnotes + length;
+  while ((char *) external < end)
     {
-      Elf_External_Note * next;
       Elf_Internal_Note inote;
+      size_t min_notesz;
+      char *next;
       char * temp = NULL;
+      size_t data_remaining = end - (char *) external;
 
       if (!is_ia64_vms ())
-        {
-          inote.type     = BYTE_GET (external->type);
-          inote.namesz   = BYTE_GET (external->namesz);
-          inote.namedata = external->name;
-          inote.descsz   = BYTE_GET (external->descsz);
-          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));
-        }
+       {
+         /* PR binutils/15191
+            Make sure that there is enough data to read.  */
+         min_notesz = offsetof (Elf_External_Note, name);
+         if (data_remaining < min_notesz)
+           {
+             warn (_("Corrupt note: only %d bytes remain, not enough for a full note\n"),
+                   (int) data_remaining);
+             break;
+           }
+         inote.type     = BYTE_GET (external->type);
+         inote.namesz   = BYTE_GET (external->namesz);
+         inote.namedata = external->name;
+         inote.descsz   = BYTE_GET (external->descsz);
+         inote.descdata = inote.namedata + align_power (inote.namesz, 2);
+         /* PR 17531: file: 3443835e.  */
+         if (inote.descdata < (char *) pnotes || inote.descdata > end)
+           {
+             warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz);
+             inote.descdata = inote.namedata;
+             inote.namesz   = 0;
+           }
+         inote.descpos  = offset + (inote.descdata - (char *) pnotes);
+         next = inote.descdata + align_power (inote.descsz, 2);
+       }
       else
-        {
-          Elf64_External_VMS_Note *vms_external;
-
-          vms_external = (Elf64_External_VMS_Note *)external;
-          inote.type     = BYTE_GET (vms_external->type);
-          inote.namesz   = BYTE_GET (vms_external->namesz);
-          inote.namedata = vms_external->name;
-          inote.descsz   = BYTE_GET (vms_external->descsz);
-          inote.descdata = inote.namedata + align_power (inote.namesz, 3);
-          inote.descpos  = offset + (inote.descdata - (char *) pnotes);
-
-          next = (Elf_External_Note *)
-            (inote.descdata + align_power (inote.descsz, 3));
-        }
+       {
+         Elf64_External_VMS_Note *vms_external;
 
-      if (   ((char *) next > ((char *) pnotes) + length)
-         || ((char *) next <  (char *) pnotes))
+         /* PR binutils/15191
+            Make sure that there is enough data to read.  */
+         min_notesz = offsetof (Elf64_External_VMS_Note, name);
+         if (data_remaining < min_notesz)
+           {
+             warn (_("Corrupt note: only %d bytes remain, not enough for a full note\n"),
+                   (int) data_remaining);
+             break;
+           }
+
+         vms_external = (Elf64_External_VMS_Note *) external;
+         inote.type     = BYTE_GET (vms_external->type);
+         inote.namesz   = BYTE_GET (vms_external->namesz);
+         inote.namedata = vms_external->name;
+         inote.descsz   = BYTE_GET (vms_external->descsz);
+         inote.descdata = inote.namedata + align_power (inote.namesz, 3);
+         inote.descpos  = offset + (inote.descdata - (char *) pnotes);
+         next = inote.descdata + align_power (inote.descsz, 3);
+       }
+
+      if (inote.descdata < (char *) external + min_notesz
+         || next < (char *) external + min_notesz
+         /* PR binutils/17531: file: id:000000,sig:11,src:006986,op:havoc,rep:4.  */
+         || inote.namedata + inote.namesz < inote.namedata
+         || inote.descdata + inote.descsz < inote.descdata
+         || data_remaining < (size_t)(next - (char *) external))
        {
-         warn (_("corrupt note found at offset %lx into core notes\n"),
+         warn (_("note with invalid namesz and/or descsz found at offset 0x%lx\n"),
                (unsigned long) ((char *) external - (char *) pnotes));
-         warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"),
+         warn (_(" type: 0x%lx, namesize: 0x%08lx, descsize: 0x%08lx\n"),
                inote.type, inote.namesz, inote.descsz);
          break;
        }
 
-      external = next;
-
-      /* Prevent out-of-bounds indexing.  */
-      if (inote.namedata + inote.namesz > (char *) pnotes + length
-         || inote.namedata + inote.namesz < inote.namedata)
-        {
-          warn (_("corrupt note found at offset %lx into core notes\n"),
-                (unsigned long) ((char *) external - (char *) pnotes));
-          warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"),
-                inote.type, inote.namesz, inote.descsz);
-          break;
-        }
+      external = (Elf_External_Note *) next;
 
       /* Verify that name is null terminated.  It appears that at least
         one version of Linux (RedHat 6.0) generates corefiles that don't
@@ -13257,10 +15359,9 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length)
       if (inote.namedata[inote.namesz - 1] != '\0')
        {
          temp = (char *) malloc (inote.namesz + 1);
-
          if (temp == NULL)
            {
-             error (_("Out of memory\n"));
+             error (_("Out of memory allocating space for inote name\n"));
              res = 0;
              break;
            }
@@ -13309,20 +15410,122 @@ process_corefile_note_segments (FILE * file)
   return res;
 }
 
+static int
+process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length)
+{
+  Elf_External_Note * pnotes;
+  Elf_External_Note * external;
+  char * end;
+  int res = 1;
+
+  if (length <= 0)
+    return 0;
+
+  pnotes = (Elf_External_Note *) get_data (NULL, file, offset, 1, length,
+                                           _("v850 notes"));
+  if (pnotes == NULL)
+    return 0;
+
+  external = pnotes;
+  end = (char*) pnotes + length;
+
+  printf (_("\nDisplaying contents of Renesas V850 notes section at offset 0x%lx with length 0x%lx:\n"),
+         (unsigned long) offset, (unsigned long) length);
+
+  while ((char *) external + sizeof (Elf_External_Note) < end)
+    {
+      Elf_External_Note * next;
+      Elf_Internal_Note inote;
+
+      inote.type     = BYTE_GET (external->type);
+      inote.namesz   = BYTE_GET (external->namesz);
+      inote.namedata = external->name;
+      inote.descsz   = BYTE_GET (external->descsz);
+      inote.descdata = inote.namedata + align_power (inote.namesz, 2);
+      inote.descpos  = offset + (inote.descdata - (char *) pnotes);
+
+      if (inote.descdata < (char *) pnotes || inote.descdata >= end)
+       {
+         warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz);
+         inote.descdata = inote.namedata;
+         inote.namesz   = 0;
+       }
+
+      next = (Elf_External_Note *) (inote.descdata + align_power (inote.descsz, 2));
+
+      if (   ((char *) next > end)
+         || ((char *) next <  (char *) pnotes))
+       {
+         warn (_("corrupt descsz found in note at offset 0x%lx\n"),
+               (unsigned long) ((char *) external - (char *) pnotes));
+         warn (_(" type: 0x%lx, namesize: 0x%lx, descsize: 0x%lx\n"),
+               inote.type, inote.namesz, inote.descsz);
+         break;
+       }
+
+      external = next;
+
+      /* Prevent out-of-bounds indexing.  */
+      if (   inote.namedata + inote.namesz > end
+         || inote.namedata + inote.namesz < inote.namedata)
+        {
+          warn (_("corrupt namesz found in note at offset 0x%lx\n"),
+                (unsigned long) ((char *) external - (char *) pnotes));
+          warn (_(" type: 0x%lx, namesize: 0x%lx, descsize: 0x%lx\n"),
+                inote.type, inote.namesz, inote.descsz);
+          break;
+        }
+
+      printf ("  %s: ", get_v850_elf_note_type (inote.type));
+
+      if (! print_v850_note (& inote))
+       {
+         res = 0;
+         printf ("<corrupt sizes: namesz: %lx, descsz: %lx>\n",
+                 inote.namesz, inote.descsz);
+       }
+    }
+
+  free (pnotes);
+
+  return res;
+}
+
 static int
 process_note_sections (FILE * file)
 {
   Elf_Internal_Shdr * section;
   unsigned long i;
+  int n = 0;
   int res = 1;
 
   for (i = 0, section = section_headers;
        i < elf_header.e_shnum && section != NULL;
        i++, section++)
-    if (section->sh_type == SHT_NOTE)
-      res &= process_corefile_note_segment (file,
-                                           (bfd_vma) section->sh_offset,
-                                           (bfd_vma) section->sh_size);
+    {
+      if (section->sh_type == SHT_NOTE)
+       {
+         res &= process_corefile_note_segment (file,
+                                               (bfd_vma) section->sh_offset,
+                                               (bfd_vma) section->sh_size);
+         n++;
+       }
+
+      if ((   elf_header.e_machine == EM_V800
+          || elf_header.e_machine == EM_V850
+          || elf_header.e_machine == EM_CYGNUS_V850)
+         && section->sh_type == SHT_RENESAS_INFO)
+       {
+         res &= process_v850_notes (file,
+                                    (bfd_vma) section->sh_offset,
+                                    (bfd_vma) section->sh_size);
+         n++;
+       }
+    }
+
+  if (n == 0)
+    /* Try processing NOTE segments instead.  */
+    return process_corefile_note_segments (file);
 
   return res;
 }
@@ -13359,6 +15562,9 @@ process_arch_specific (FILE * file)
     case EM_MIPS_RS3_LE:
       return process_mips_specific (file);
       break;
+    case EM_NDS32:
+      return process_nds32_specific (file);
+      break;
     case EM_PPC:
       return process_power_specific (file);
       break;
@@ -13370,6 +15576,8 @@ process_arch_specific (FILE * file)
     case EM_TI_C6000:
       return process_tic6x_specific (file);
       break;
+    case EM_MSP430:
+      return process_msp430x_specific (file);
     default:
       break;
     }
@@ -13461,9 +15669,9 @@ get_file_header (FILE * file)
       /* There may be some extensions in the first section header.  Don't
         bomb if we can't read it.  */
       if (is_32bit_elf)
-       get_32bit_section_headers (file, 1);
+       get_32bit_section_headers (file, TRUE);
       else
-       get_64bit_section_headers (file, 1);
+       get_64bit_section_headers (file, TRUE);
     }
 
   return 1;
@@ -13669,11 +15877,11 @@ process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive)
        error (_("%s: unable to dump the index as none was found\n"), file_name);
       else
        {
-         unsigned int i, l;
+         unsigned long i, l;
          unsigned long current_pos;
 
-         printf (_("Index of archive %s: (%ld entries, 0x%lx bytes in the symbol table)\n"),
-                 file_name, (long) arch.index_num, arch.sym_size);
+         printf (_("Index of archive %s: (%lu entries, 0x%lx bytes in the symbol table)\n"),
+                 file_name, (unsigned long) arch.index_num, arch.sym_size);
          current_pos = ftell (file);
 
          for (i = l = 0; i < arch.index_num; i++)
@@ -13704,8 +15912,9 @@ process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive)
                         file_name);
                  break;
                }
-             printf ("\t%s\n", arch.sym_table + l);
-             l += strlen (arch.sym_table + l) + 1;
+             /* PR 17531: file: 0b6630b2.  */
+             printf ("\t%.*s\n", (int) (arch.sym_size - l), arch.sym_table + l);
+             l += strnlen (arch.sym_table + l, arch.sym_size - l) + 1;
            }
 
          if (arch.uses_64bit_indicies)
@@ -13817,6 +16026,15 @@ process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive)
         }
       else if (is_thin_archive)
         {
+         /* PR 15140: Allow for corrupt thin archives.  */
+         if (nested_arch.file == NULL)
+           {
+             error (_("%s: contains corrupt thin archive: %s\n"),
+                    file_name, name);
+             ret = 1;
+             break;
+           }
+
           /* This is a proxy for a member of a nested archive.  */
           archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr;
 
@@ -13896,6 +16114,8 @@ process_file (char * file_name)
       return 1;
     }
 
+  current_file_size = (bfd_size_type) statbuf.st_size;
+
   if (memcmp (armag, ARMAG, SARMAG) == 0)
     ret = process_archive (file_name, file, FALSE);
   else if (memcmp (armag, ARMAGT, SARMAG) == 0)
@@ -13913,6 +16133,7 @@ process_file (char * file_name)
 
   fclose (file);
 
+  current_file_size = 0;
   return ret;
 }
 
@@ -13970,6 +16191,11 @@ main (int argc, char ** argv)
 
   if (optind < (argc - 1))
     show_name = 1;
+  else if (optind >= argc)
+    {
+      warn (_("Nothing to do.\n"));
+      usage (stderr);
+    }
 
   err = 0;
   while (optind < argc)
This page took 0.177549 seconds and 4 git commands to generate.