2005-09-07 H.J. Lu <hongjiu.lu@intel.com>
[deliverable/binutils-gdb.git] / binutils / readelf.c
index 21b11a17ceb442bdd777588da61591e6598ffacf..d3e94579ce719edab17a7ab416c944adf2008931 100644 (file)
@@ -86,6 +86,7 @@
 #include "elf/i960.h"
 #include "elf/ia64.h"
 #include "elf/ip2k.h"
+#include "elf/m32c.h"
 #include "elf/m32r.h"
 #include "elf/m68k.h"
 #include "elf/m68hc11.h"
@@ -94,6 +95,7 @@
 #include "elf/mmix.h"
 #include "elf/mn10200.h"
 #include "elf/mn10300.h"
+#include "elf/ms1.h"
 #include "elf/msp430.h"
 #include "elf/or32.h"
 #include "elf/pj.h"
@@ -145,7 +147,7 @@ static int do_syms;
 static int do_reloc;
 static int do_sections;
 static int do_section_groups;
-static int do_full_section_name;
+static int do_section_details;
 static int do_segments;
 static int do_unwind;
 static int do_using_dynamic;
@@ -206,7 +208,7 @@ unsigned int num_dump_sects = 0;
 #define DISASS_DUMP    (1 << 1)
 #define DEBUG_DUMP     (1 << 2)
 
-/* How to rpint a vma value.  */
+/* How to print a vma value.  */
 typedef enum print_mode
 {
   HEX,
@@ -263,7 +265,7 @@ static void (*byte_put) (unsigned char *, bfd_vma, int);
 #define streq(a,b)     (strcmp ((a), (b)) == 0)
 #define strneq(a,b,n)  (strncmp ((a), (b), (n)) == 0)
 \f
-static void
+static void ATTRIBUTE_PRINTF_1
 error (const char *message, ...)
 {
   va_list args;
@@ -274,7 +276,7 @@ error (const char *message, ...)
   va_end (args);
 }
 
-static void
+static void ATTRIBUTE_PRINTF_1
 warn (const char *message, ...)
 {
   va_list args;
@@ -286,16 +288,47 @@ warn (const char *message, ...)
 }
 
 static void *
-get_data (void *var, FILE *file, long offset, size_t size, const char *reason)
+cmalloc (size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return malloc (nmemb * size);
+}
+
+static void *
+xcmalloc (size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return xmalloc (nmemb * size);
+}
+
+static void *
+xcrealloc (void *ptr, size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return xrealloc (ptr, nmemb * size);
+}
+
+static void *
+get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
+         const char *reason)
 {
   void *mvar;
 
-  if (size == 0)
+  if (size == 0 || nmemb == 0)
     return NULL;
 
   if (fseek (file, archive_file_offset + offset, SEEK_SET))
     {
-      error (_("Unable to seek to 0x%x for %s\n"),
+      error (_("Unable to seek to 0x%lx for %s\n"),
             archive_file_offset + offset, reason);
       return NULL;
     }
@@ -303,19 +336,25 @@ get_data (void *var, FILE *file, long offset, size_t size, const char *reason)
   mvar = var;
   if (mvar == NULL)
     {
-      mvar = malloc (size);
+      /* Check for overflow.  */
+      if (nmemb < (~(size_t) 0 - 1) / size)
+       /* + 1 so that we can '\0' terminate invalid string table sections.  */
+       mvar = malloc (size * nmemb + 1);
 
       if (mvar == NULL)
        {
-         error (_("Out of memory allocating 0x%x bytes for %s\n"),
-                size, reason);
+         error (_("Out of memory allocating 0x%lx bytes for %s\n"),
+                (unsigned long)(size * nmemb), reason);
          return NULL;
        }
+
+      ((char *) mvar)[size * nmemb] = '\0';
     }
 
-  if (fread (mvar, size, 1, file) != 1)
+  if (fread (mvar, size, nmemb, file) != nmemb)
     {
-      error (_("Unable to read in 0x%x bytes of %s\n"), size, reason);
+      error (_("Unable to read in 0x%lx bytes of %s\n"),
+            (unsigned long)(size * nmemb), reason);
       if (mvar != var)
        free (mvar);
       return NULL;
@@ -729,6 +768,8 @@ guess_is_rela (unsigned long e_machine)
     case EM_XTENSA:
     case EM_XTENSA_OLD:
     case EM_M32R:
+    case EM_M32C:
+    case EM_MS1:
       return TRUE;
 
     case EM_MMA:
@@ -769,16 +810,17 @@ slurp_rela_relocs (FILE *file,
     {
       Elf32_External_Rela *erelas;
 
-      erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erelas)
        return 0;
 
       nrelas = rel_size / sizeof (Elf32_External_Rela);
 
-      relas = malloc (nrelas * sizeof (Elf_Internal_Rela));
+      relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela));
 
       if (relas == NULL)
        {
+         free (erelas);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -796,16 +838,17 @@ slurp_rela_relocs (FILE *file,
     {
       Elf64_External_Rela *erelas;
 
-      erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erelas)
        return 0;
 
       nrelas = rel_size / sizeof (Elf64_External_Rela);
 
-      relas = malloc (nrelas * sizeof (Elf_Internal_Rela));
+      relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela));
 
       if (relas == NULL)
        {
+         free (erelas);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -839,16 +882,17 @@ slurp_rel_relocs (FILE *file,
     {
       Elf32_External_Rel *erels;
 
-      erels = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erels)
        return 0;
 
       nrels = rel_size / sizeof (Elf32_External_Rel);
 
-      rels = malloc (nrels * sizeof (Elf_Internal_Rela));
+      rels = cmalloc (nrels, sizeof (Elf_Internal_Rela));
 
       if (rels == NULL)
        {
+         free (erels);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -866,16 +910,17 @@ slurp_rel_relocs (FILE *file,
     {
       Elf64_External_Rel *erels;
 
-      erels = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erels)
        return 0;
 
       nrels = rel_size / sizeof (Elf64_External_Rel);
 
-      rels = malloc (nrels * sizeof (Elf_Internal_Rela));
+      rels = cmalloc (nrels, sizeof (Elf_Internal_Rela));
 
       if (rels == NULL)
        {
+         free (erels);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -1232,6 +1277,14 @@ dump_relocations (FILE *file,
        case EM_XTENSA:
          rtype = elf_xtensa_reloc_type (type);
          break;
+
+       case EM_M32C:
+         rtype = elf_m32c_reloc_type (type);
+         break;
+
+       case EM_MS1:
+         rtype = elf_ms1_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1243,7 +1296,31 @@ dump_relocations (FILE *file,
       else
        printf (do_wide ? "%-22.22s" : "%-17.17s", rtype);
 
-      if (symtab_index)
+      if (elf_header.e_machine == EM_ALPHA
+         && streq (rtype, "R_ALPHA_LITUSE")
+         && is_rela)
+       {
+         switch (rels[i].r_addend)
+           {
+           case LITUSE_ALPHA_ADDR:   rtype = "ADDR";   break;
+           case LITUSE_ALPHA_BASE:   rtype = "BASE";   break;
+           case LITUSE_ALPHA_BYTOFF: rtype = "BYTOFF"; break;
+           case LITUSE_ALPHA_JSR:    rtype = "JSR";    break;
+           case LITUSE_ALPHA_TLSGD:  rtype = "TLSGD";  break;
+           case LITUSE_ALPHA_TLSLDM: rtype = "TLSLDM"; break;
+           case LITUSE_ALPHA_JSRDIRECT: rtype = "JSRDIRECT"; break;
+           default: rtype = NULL;
+           }
+         if (rtype)
+           printf (" (%s)", rtype);
+         else
+           {
+             putchar (' ');
+             printf (_("<unknown addend: %lx>"),
+                     (unsigned long) rels[i].r_addend);
+           }
+       }
+      else if (symtab_index)
        {
          if (symtab == NULL || symtab_index >= nsyms)
            printf (" bad symbol index: %08lx", (unsigned long) symtab_index);
@@ -1278,6 +1355,9 @@ dump_relocations (FILE *file,
                        sec_name = "ABS";
                      else if (psym->st_shndx == SHN_COMMON)
                        sec_name = "COMMON";
+                     else if (elf_header.e_machine == EM_X86_64
+                              && psym->st_shndx == SHN_X86_64_LCOMMON)
+                       sec_name = "LARGE_COMMON";
                      else if (elf_header.e_machine == EM_IA_64
                               && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX
                               && psym->st_shndx == SHN_IA_64_ANSI_COMMON)
@@ -1293,7 +1373,7 @@ dump_relocations (FILE *file,
                }
              else if (strtab == NULL)
                printf (_("<string table index: %3ld>"), psym->st_name);
-             else if (psym->st_name > strtablen)
+             else if (psym->st_name >= strtablen)
                printf (_("<corrupt string table index: %3ld>"), psym->st_name);
              else
                print_symbol (22, strtab + psym->st_name);
@@ -1309,8 +1389,7 @@ dump_relocations (FILE *file,
          print_vma (rels[i].r_addend, LONG_HEX);
        }
 
-      if (elf_header.e_machine == EM_SPARCV9
-         && streq (rtype, "R_SPARC_OLO10"))
+      if (elf_header.e_machine == EM_SPARCV9 && streq (rtype, "R_SPARC_OLO10"))
        printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info));
 
       putchar ('\n');
@@ -1454,6 +1533,17 @@ get_parisc_dynamic_type (unsigned long type)
     case DT_HP_GST_SIZE:       return "HP_GST_SIZE";
     case DT_HP_GST_VERSION:    return "HP_GST_VERSION";
     case DT_HP_GST_HASHVAL:    return "HP_GST_HASHVAL";
+    case DT_HP_EPLTREL:                return "HP_GST_EPLTREL";
+    case DT_HP_EPLTRELSZ:      return "HP_GST_EPLTRELSZ";
+    case DT_HP_FILTERED:       return "HP_FILTERED";
+    case DT_HP_FILTER_TLS:     return "HP_FILTER_TLS";
+    case DT_HP_COMPAT_FILTERED:        return "HP_COMPAT_FILTERED";
+    case DT_HP_LAZYLOAD:       return "HP_LAZYLOAD";
+    case DT_HP_BIND_NOW_COUNT: return "HP_BIND_NOW_COUNT";
+    case DT_PLT:               return "PLT";
+    case DT_PLT_SIZE:          return "PLT_SIZE";
+    case DT_DLT:               return "DLT";
+    case DT_DLT_SIZE:          return "DLT_SIZE";
     default:
       return NULL;
     }
@@ -1470,6 +1560,17 @@ get_ia64_dynamic_type (unsigned long type)
     }
 }
 
+static const char *
+get_alpha_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    case DT_ALPHA_PLTRO: return "ALPHA_PLTRO";
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_dynamic_type (unsigned long type)
 {
@@ -1572,6 +1673,9 @@ get_dynamic_type (unsigned long type)
            case EM_IA_64:
              result = get_ia64_dynamic_type (type);
              break;
+           case EM_ALPHA:
+             result = get_alpha_dynamic_type (type);
+             break;
            default:
              result = NULL;
              break;
@@ -1582,7 +1686,9 @@ get_dynamic_type (unsigned long type)
 
          snprintf (buff, sizeof (buff), _("Processor Specific: %lx"), type);
        }
-      else if ((type >= DT_LOOS) && (type <= DT_HIOS))
+      else if (((type >= DT_LOOS) && (type <= DT_HIOS))
+              || (elf_header.e_machine == EM_PARISC
+                  && (type >= OLD_DT_LOOS) && (type <= OLD_DT_HIOS)))
        {
          const char *result;
 
@@ -1734,6 +1840,8 @@ get_machine_name (unsigned e_machine)
     case EM_IQ2000:            return "Vitesse IQ2000";
     case EM_XTENSA_OLD:
     case EM_XTENSA:            return "Tensilica Xtensa Processor";
+    case EM_M32C:              return "Renesas M32c";
+    case EM_MS1:                return "Morpho Techologies MS1 processor";
     default:
       snprintf (buff, sizeof (buff), _("<unknown>: %x"), e_machine);
       return buff;
@@ -2297,8 +2405,13 @@ get_parisc_segment_type (unsigned long type)
     case PT_HP_CORE_MMF:       return "HP_CORE_MMF";
     case PT_HP_PARALLEL:       return "HP_PARALLEL";
     case PT_HP_FASTBIND:       return "HP_FASTBIND";
+    case PT_HP_OPT_ANNOT:      return "HP_OPT_ANNOT";
+    case PT_HP_HSL_ANNOT:      return "HP_HSL_ANNOT";
+    case PT_HP_STACK:          return "HP_STACK";
+    case PT_HP_CORE_UTSNAME:   return "HP_CORE_UTSNAME";
     case PT_PARISC_ARCHEXT:    return "PARISC_ARCHEXT";
     case PT_PARISC_UNWIND:     return "PARISC_UNWIND";
+    case PT_PARISC_WEAKORDER:  return "PARISC_WEAKORDER";
     default:
       break;
     }
@@ -2462,6 +2575,10 @@ get_parisc_section_type_name (unsigned int sh_type)
     case SHT_PARISC_EXT:       return "PARISC_EXT";
     case SHT_PARISC_UNWIND:    return "PARISC_UNWIND";
     case SHT_PARISC_DOC:       return "PARISC_DOC";
+    case SHT_PARISC_ANNOT:     return "PARISC_ANNOT";
+    case SHT_PARISC_SYMEXTN:   return "PARISC_SYMEXTN";
+    case SHT_PARISC_STUBS:     return "PARISC_STUBS";
+    case SHT_PARISC_DLKM:      return "PARISC_DLKM";
     default:
       break;
     }
@@ -2601,6 +2718,7 @@ static struct option options[] =
   {"sections",        no_argument, 0, 'S'},
   {"section-headers",  no_argument, 0, 'S'},
   {"section-groups",   no_argument, 0, 'g'},
+  {"section-details",  no_argument, 0, 't'},
   {"full-section-name",no_argument, 0, 'N'},
   {"symbols",         no_argument, 0, 's'},
   {"syms",            no_argument, 0, 's'},
@@ -2636,8 +2754,7 @@ usage (void)
   -S --section-headers   Display the sections' header\n\
      --sections          An alias for --section-headers\n\
   -g --section-groups    Display the section groups\n\
-  -N --full-section-name\n\
-                         Display the full section name\n\
+  -t --section-details   Display the section details\n\
   -e --headers           Equivalent to: -h -l -S\n\
   -s --syms              Display the symbol table\n\
       --symbols          An alias for --syms\n\
@@ -2710,7 +2827,7 @@ parse_args (int argc, char **argv)
     usage ();
 
   while ((c = getopt_long
-         (argc, argv, "ersuahnldSDAINgw::x:i:vVWH", options, NULL)) != EOF)
+         (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF)
     {
       char *cp;
       int section;
@@ -2741,8 +2858,10 @@ parse_args (int argc, char **argv)
        case 'g':
          do_section_groups++;
          break;
+       case 't':
        case 'N':
-         do_full_section_name++;
+         do_sections++;
+         do_section_details++;
          break;
        case 'e':
          do_header++;
@@ -3107,7 +3226,7 @@ get_32bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers)
   unsigned int i;
 
   phdrs = get_data (NULL, file, elf_header.e_phoff,
-                   elf_header.e_phentsize * elf_header.e_phnum,
+                   elf_header.e_phentsize, elf_header.e_phnum,
                    _("program headers"));
   if (!phdrs)
     return 0;
@@ -3140,7 +3259,7 @@ get_64bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers)
   unsigned int i;
 
   phdrs = get_data (NULL, file, elf_header.e_phoff,
-                   elf_header.e_phentsize * elf_header.e_phnum,
+                   elf_header.e_phentsize, elf_header.e_phnum,
                    _("program headers"));
   if (!phdrs)
     return 0;
@@ -3175,7 +3294,7 @@ get_program_headers (FILE *file)
   if (program_headers != NULL)
     return 1;
 
-  phdrs = malloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
+  phdrs = cmalloc (elf_header.e_phnum, sizeof (Elf_Internal_Phdr));
 
   if (phdrs == NULL)
     {
@@ -3388,13 +3507,11 @@ process_program_headers (FILE *file)
        putc ('\n', stdout);
     }
 
-  if (do_segments && section_headers != NULL)
+  if (do_segments && section_headers != NULL && string_table != NULL)
     {
       printf (_("\n Section to Segment mapping:\n"));
       printf (_("  Segment Sections...\n"));
 
-      assert (string_table != NULL);
-
       for (i = 0; i < elf_header.e_phnum; i++)
        {
          unsigned int j;
@@ -3472,11 +3589,11 @@ get_32bit_section_headers (FILE *file, unsigned int num)
   unsigned int i;
 
   shdrs = get_data (NULL, file, elf_header.e_shoff,
-                   elf_header.e_shentsize * num, _("section headers"));
+                   elf_header.e_shentsize, num, _("section headers"));
   if (!shdrs)
     return 0;
 
-  section_headers = malloc (num * sizeof (Elf_Internal_Shdr));
+  section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr));
 
   if (section_headers == NULL)
     {
@@ -3513,11 +3630,11 @@ get_64bit_section_headers (FILE *file, unsigned int num)
   unsigned int i;
 
   shdrs = get_data (NULL, file, elf_header.e_shoff,
-                   elf_header.e_shentsize * num, _("section headers"));
+                   elf_header.e_shentsize, num, _("section headers"));
   if (!shdrs)
     return 0;
 
-  section_headers = malloc (num * sizeof (Elf_Internal_Shdr));
+  section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr));
 
   if (section_headers == NULL)
     {
@@ -3556,7 +3673,7 @@ get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
   Elf_Internal_Sym *psym;
   unsigned int j;
 
-  esyms = get_data (NULL, file, section->sh_offset, section->sh_size,
+  esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                    _("symbols"));
   if (!esyms)
     return NULL;
@@ -3567,7 +3684,7 @@ get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
          == (unsigned long) SECTION_HEADER_NUM (section - section_headers)))
     {
       shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset,
-                       symtab_shndx_hdr->sh_size, _("symtab shndx"));
+                       1, symtab_shndx_hdr->sh_size, _("symtab shndx"));
       if (!shndx)
        {
          free (esyms);
@@ -3576,7 +3693,7 @@ get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
     }
 
   number = section->sh_size / section->sh_entsize;
-  isyms = malloc (number * sizeof (Elf_Internal_Sym));
+  isyms = cmalloc (number, sizeof (Elf_Internal_Sym));
 
   if (isyms == NULL)
     {
@@ -3619,7 +3736,7 @@ get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
   Elf_Internal_Sym *psym;
   unsigned int j;
 
-  esyms = get_data (NULL, file, section->sh_offset, section->sh_size,
+  esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                    _("symbols"));
   if (!esyms)
     return NULL;
@@ -3630,7 +3747,7 @@ get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
          == (unsigned long) SECTION_HEADER_NUM (section - section_headers)))
     {
       shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset,
-                       symtab_shndx_hdr->sh_size, _("symtab shndx"));
+                       1, symtab_shndx_hdr->sh_size, _("symtab shndx"));
       if (!shndx)
        {
          free (esyms);
@@ -3639,7 +3756,7 @@ get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
     }
 
   number = section->sh_size / section->sh_entsize;
-  isyms = malloc (number * sizeof (Elf_Internal_Sym));
+  isyms = cmalloc (number, sizeof (Elf_Internal_Sym));
 
   if (isyms == NULL)
     {
@@ -3675,8 +3792,38 @@ get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section)
 static const char *
 get_elf_section_flags (bfd_vma sh_flags)
 {
-  static char buff[33];
+  static char buff[1024];
   char *p = buff;
+  int field_size = is_32bit_elf ? 8 : 16;
+  int index, size = sizeof (buff) - (field_size + 4 + 1);
+  bfd_vma os_flags = 0;
+  bfd_vma proc_flags = 0;
+  bfd_vma unknown_flags = 0;
+  const struct
+    {
+      const char *str;
+      int len;
+    }
+  flags [] =
+    {
+       { "WRITE", 5 },
+       { "ALLOC", 5 },
+       { "EXEC", 4 },
+       { "MERGE", 5 },
+       { "STRINGS", 7 },
+       { "INFO LINK", 9 },
+       { "LINK ORDER", 10 },
+       { "OS NONCONF", 10 },
+       { "GROUP", 5 },
+       { "TLS", 3 }
+    };
+
+  if (do_section_details)
+    {
+      sprintf (buff, "[%*.*lx]: ",
+              field_size, field_size, (unsigned long) sh_flags);
+      p += field_size + 4;
+    }
 
   while (sh_flags)
     {
@@ -3685,35 +3832,131 @@ get_elf_section_flags (bfd_vma sh_flags)
       flag = sh_flags & - sh_flags;
       sh_flags &= ~ flag;
 
-      switch (flag)
+      if (do_section_details)
        {
-       case SHF_WRITE:            *p = 'W'; break;
-       case SHF_ALLOC:            *p = 'A'; break;
-       case SHF_EXECINSTR:        *p = 'X'; break;
-       case SHF_MERGE:            *p = 'M'; break;
-       case SHF_STRINGS:          *p = 'S'; break;
-       case SHF_INFO_LINK:        *p = 'I'; break;
-       case SHF_LINK_ORDER:       *p = 'L'; break;
-       case SHF_OS_NONCONFORMING: *p = 'O'; break;
-       case SHF_GROUP:            *p = 'G'; break;
-       case SHF_TLS:              *p = 'T'; break;
+         switch (flag)
+           {
+           case SHF_WRITE:             index = 0; break;
+           case SHF_ALLOC:             index = 1; break;
+           case SHF_EXECINSTR:         index = 2; break;
+           case SHF_MERGE:             index = 3; break;
+           case SHF_STRINGS:           index = 4; break;
+           case SHF_INFO_LINK:         index = 5; break;
+           case SHF_LINK_ORDER:        index = 6; break;
+           case SHF_OS_NONCONFORMING:  index = 7; break;
+           case SHF_GROUP:             index = 8; break;
+           case SHF_TLS:               index = 9; break;
 
-       default:
-         if (flag & SHF_MASKOS)
+           default:
+             index = -1;
+             break;
+           }
+
+         if (index != -1)
            {
-             *p = 'o';
-             sh_flags &= ~ SHF_MASKOS;
+             if (p != buff + field_size + 4)
+               {
+                 if (size < (10 + 2))
+                   abort ();
+                 size -= 2;
+                 *p++ = ',';
+                 *p++ = ' ';
+               }
+
+             size -= flags [index].len;
+             p = stpcpy (p, flags [index].str);
            }
+         else if (flag & SHF_MASKOS)
+           os_flags |= flag;
          else if (flag & SHF_MASKPROC)
+           proc_flags |= flag;
+         else
+           unknown_flags |= flag;
+       }
+      else
+       {
+         switch (flag)
            {
-             *p = 'p';
-             sh_flags &= ~ SHF_MASKPROC;
+           case SHF_WRITE:             *p = 'W'; break;
+           case SHF_ALLOC:             *p = 'A'; break;
+           case SHF_EXECINSTR:         *p = 'X'; break;
+           case SHF_MERGE:             *p = 'M'; break;
+           case SHF_STRINGS:           *p = 'S'; break;
+           case SHF_INFO_LINK:         *p = 'I'; break;
+           case SHF_LINK_ORDER:        *p = 'L'; break;
+           case SHF_OS_NONCONFORMING:  *p = 'O'; break;
+           case SHF_GROUP:             *p = 'G'; break;
+           case SHF_TLS:               *p = 'T'; break;
+
+           default:
+             if (elf_header.e_machine == EM_X86_64
+                 && flag == SHF_X86_64_LARGE)
+               *p = 'l';
+             else if (flag & SHF_MASKOS)
+               {
+                 *p = 'o';
+                 sh_flags &= ~ SHF_MASKOS;
+               }
+             else if (flag & SHF_MASKPROC)
+               {
+                 *p = 'p';
+                 sh_flags &= ~ SHF_MASKPROC;
+               }
+             else
+               *p = 'x';
+             break;
            }
-         else
-           *p = 'x';
-         break;
+         p++;
+       }
+    }
+
+  if (do_section_details)
+    {
+      if (os_flags)
+       {
+         size -= 5 + field_size;
+         if (p != buff + field_size + 4)
+           {
+             if (size < (2 + 1))
+               abort ();
+             size -= 2;
+             *p++ = ',';
+             *p++ = ' ';
+           }
+         sprintf (p, "OS (%*.*lx)", field_size, field_size,
+                  (unsigned long) os_flags);
+         p += 5 + field_size;
+       }
+      if (proc_flags)
+       {
+         size -= 7 + field_size;
+         if (p != buff + field_size + 4)
+           {
+             if (size < (2 + 1))
+               abort ();
+             size -= 2;
+             *p++ = ',';
+             *p++ = ' ';
+           }
+         sprintf (p, "PROC (%*.*lx)", field_size, field_size,
+                  (unsigned long) proc_flags);
+         p += 7 + field_size;
+       }
+      if (unknown_flags)
+       {
+         size -= 10 + field_size;
+         if (p != buff + field_size + 4)
+           {
+             if (size < (2 + 1))
+               abort ();
+             size -= 2;
+             *p++ = ',';
+             *p++ = ' ';
+           }
+         sprintf (p, "UNKNOWN (%*.*lx)", field_size, field_size,
+                  (unsigned long) unknown_flags);
+         p += 10 + field_size;
        }
-      p++;
     }
 
   *p = '\0';
@@ -3749,17 +3992,17 @@ process_section_headers (FILE *file)
     return 0;
 
   /* Read in the string table, so that we have names to display.  */
-  section = SECTION_HEADER (elf_header.e_shstrndx);
-
-  if (section->sh_size != 0)
+  if (SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum)
     {
-      string_table = get_data (NULL, file, section->sh_offset,
-                              section->sh_size, _("string table"));
+      section = SECTION_HEADER (elf_header.e_shstrndx);
 
-      if (string_table == NULL)
-       return 0;
+      if (section->sh_size != 0)
+       {
+         string_table = get_data (NULL, file, section->sh_offset,
+                                  1, section->sh_size, _("string table"));
 
-      string_table_length = section->sh_size;
+         string_table_length = string_table != NULL ? section->sh_size : 0;
+       }
     }
 
   /* Scan the sections for the dynamic symbol table
@@ -3789,6 +4032,22 @@ 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;                              \
+    }                                                                      \
+  while (0)
+#define CHECK_ENTSIZE(section, i, type) \
+  CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type),        \
+                       sizeof (Elf64_External_##type))
+
   for (i = 0, section = section_headers;
        i < elf_header.e_shnum;
        i++, section++)
@@ -3803,6 +4062,7 @@ process_section_headers (FILE *file)
              continue;
            }
 
+         CHECK_ENTSIZE (section, i, Sym);
          num_dynamic_syms = section->sh_size / section->sh_entsize;
          dynamic_symbols = GET_ELF_SYMBOLS (file, section);
        }
@@ -3816,7 +4076,7 @@ process_section_headers (FILE *file)
            }
 
          dynamic_strings = get_data (NULL, file, section->sh_offset,
-                                     section->sh_size, _("dynamic strings"));
+                                     1, section->sh_size, _("dynamic strings"));
          dynamic_strings_length = section->sh_size;
        }
       else if (section->sh_type == SHT_SYMTAB_SHNDX)
@@ -3828,6 +4088,14 @@ process_section_headers (FILE *file)
            }
          symtab_shndx_hdr = section;
        }
+      else if (section->sh_type == SHT_SYMTAB)
+       CHECK_ENTSIZE (section, i, Sym);
+      else if (section->sh_type == SHT_GROUP)
+       CHECK_ENTSIZE_VALUES (section, i, GRP_ENTRY_SIZE, GRP_ENTRY_SIZE);
+      else if (section->sh_type == SHT_REL)
+       CHECK_ENTSIZE (section, i, Rel);
+      else if (section->sh_type == SHT_RELA)
+       CHECK_ENTSIZE (section, i, Rela);
       else if ((do_debugging || do_debug_info || do_debug_abbrevs
                || do_debug_lines || do_debug_pubnames || do_debug_aranges
                || do_debug_frames || do_debug_macinfo || do_debug_str
@@ -3868,10 +4136,10 @@ process_section_headers (FILE *file)
 
   if (is_32bit_elf)
     {
-      if (do_full_section_name)
+      if (do_section_details)
        {
          printf (_("  [Nr] Name\n"));
-         printf (_("       Type            Addr     Off    Size   ES Flg Lk Inf Al\n"));
+         printf (_("       Type            Addr     Off    Size   ES   Lk Inf Al\n"));
        }
       else
        printf
@@ -3879,10 +4147,10 @@ process_section_headers (FILE *file)
     }
   else if (do_wide)
     {
-      if (do_full_section_name)
+      if (do_section_details)
        {
          printf (_("  [Nr] Name\n"));
-         printf (_("       Type            Address          Off    Size   ES Flg Lk Inf Al\n"));
+         printf (_("       Type            Address          Off    Size   ES   Lk Inf Al\n"));
        }
       else
        printf
@@ -3890,11 +4158,11 @@ process_section_headers (FILE *file)
     }
   else
     {
-      if (do_full_section_name)
+      if (do_section_details)
        {
          printf (_("  [Nr] Name\n"));
-         printf (_("       Flags             Type             Address           Offset\n"));
-         printf (_("       Size              EntSize          Link     Info     Align\n"));
+         printf (_("       Type              Address          Offset            Link\n"));
+         printf (_("       Size              EntSize          Info              Align\n"));
        }
       else
        {
@@ -3903,11 +4171,14 @@ process_section_headers (FILE *file)
        }
     }
 
+  if (do_section_details)
+    printf (_("       Flags\n"));
+
   for (i = 0, section = section_headers;
        i < elf_header.e_shnum;
        i++, section++)
     {
-      if (do_full_section_name)
+      if (do_section_details)
        {
          printf ("  [%2u] %s\n",
                  SECTION_HEADER_NUM (i),
@@ -3931,7 +4202,10 @@ process_section_headers (FILE *file)
                   (unsigned long) section->sh_size,
                   (unsigned long) section->sh_entsize);
 
-         printf (" %3s ", get_elf_section_flags (section->sh_flags));
+         if (do_section_details)
+           fputs ("  ", stdout);
+         else
+           printf (" %3s ", get_elf_section_flags (section->sh_flags));
 
          printf ("%2ld %3lu %2ld\n",
                  (unsigned long) section->sh_link,
@@ -3966,7 +4240,10 @@ process_section_headers (FILE *file)
              print_vma (section->sh_entsize, LONG_HEX);
            }
 
-         printf (" %3s ", get_elf_section_flags (section->sh_flags));
+         if (do_section_details)
+           fputs ("  ", stdout);
+         else
+           printf (" %3s ", get_elf_section_flags (section->sh_flags));
 
          printf ("%2ld %3lu ",
                  (unsigned long) section->sh_link,
@@ -3980,27 +4257,24 @@ process_section_headers (FILE *file)
              putchar ('\n');
            }
        }
-      else if (do_full_section_name)
+      else if (do_section_details)
        {
-         printf ("       %-15.15s   %-15.15s ",
-                 get_elf_section_flags (section->sh_flags),
+         printf ("       %-15.15s  ",
                  get_section_type_name (section->sh_type));
-         putchar (' ');
          print_vma (section->sh_addr, LONG_HEX);
          if ((long) section->sh_offset == section->sh_offset)
-           printf ("  %8.8lx", (unsigned long) section->sh_offset);
+           printf ("  %16.16lx", (unsigned long) section->sh_offset);
          else
            {
              printf ("  ");
              print_vma (section->sh_offset, LONG_HEX);
            }
-         printf ("\n       ");
+         printf ("  %ld\n       ", (unsigned long) section->sh_link);
          print_vma (section->sh_size, LONG_HEX);
-         printf ("  ");
+         putchar (' ');
          print_vma (section->sh_entsize, LONG_HEX);
 
-         printf ("   %2ld      %3lu        %ld\n",
-                 (unsigned long) section->sh_link,
+         printf ("  %-16lu  %ld\n",
                  (unsigned long) section->sh_info,
                  (unsigned long) section->sh_addralign);
        }
@@ -4027,9 +4301,13 @@ process_section_headers (FILE *file)
                  (unsigned long) section->sh_info,
                  (unsigned long) section->sh_addralign);
        }
+
+      if (do_section_details)
+       printf ("       %s\n", get_elf_section_flags (section->sh_flags));
     }
 
-  printf (_("Key to Flags:\n\
+  if (!do_section_details)
+    printf (_("Key to Flags:\n\
   W (write), A (alloc), X (execute), M (merge), S (strings)\n\
   I (info), L (link order), G (group), x (unknown)\n\
   O (extra OS processing required) o (OS specific), p (processor specific)\n"));
@@ -4062,6 +4340,7 @@ process_section_groups (FILE *file)
   Elf_Internal_Shdr *symtab_sec, *strtab_sec;
   Elf_Internal_Sym *symtab;
   char *strtab;
+  size_t strtab_size;
 
   /* Don't process section groups unless needed.  */
   if (!do_unwind && !do_section_groups)
@@ -4118,6 +4397,7 @@ process_section_groups (FILE *file)
   strtab_sec = NULL;
   symtab = NULL;
   strtab = NULL;
+  strtab_size = 0;
   for (i = 0, section = section_headers, group = section_groups;
        i < elf_header.e_shnum;
        i++, section++)
@@ -4132,8 +4412,9 @@ process_section_groups (FILE *file)
          Elf_Internal_Sym *sym;
 
          /* Get the symbol table.  */
-         sec = SECTION_HEADER (section->sh_link);
-         if (sec->sh_type != SHT_SYMTAB)
+         if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum
+             || ((sec = SECTION_HEADER (section->sh_link))->sh_type
+                 != SHT_SYMTAB))
            {
              error (_("Bad sh_link in group section `%s'\n"), name);
              continue;
@@ -4159,26 +4440,41 @@ process_section_groups (FILE *file)
                }
 
              group_name = SECTION_NAME (section_headers + sec_index);
+             strtab_sec = NULL;
+             if (strtab)
+               free (strtab);
              strtab = NULL;
+             strtab_size = 0;
            }
          else
            {
              /* Get the string table.  */
-             sec = SECTION_HEADER (symtab_sec->sh_link);
-             if (strtab_sec != sec)
+             if (SECTION_HEADER_INDEX (symtab_sec->sh_link)
+                 >= elf_header.e_shnum)
+               {
+                 strtab_sec = NULL;
+                 if (strtab)
+                   free (strtab);
+                 strtab = NULL;
+                 strtab_size = 0;
+               }
+             else if (strtab_sec
+                      != (sec = SECTION_HEADER (symtab_sec->sh_link)))
                {
                  strtab_sec = sec;
                  if (strtab)
                    free (strtab);
                  strtab = get_data (NULL, file, strtab_sec->sh_offset,
-                                    strtab_sec->sh_size,
+                                    1, strtab_sec->sh_size,
                                     _("string table"));
+                 strtab_size = strtab != NULL ? strtab_sec->sh_size : 0;
                }
-             group_name = strtab + sym->st_name;
+             group_name = sym->st_name < strtab_size
+                          ? strtab + sym->st_name : "<corrupt>";
            }
 
          start = get_data (NULL, file, section->sh_offset,
-                           section->sh_size, _("section data"));
+                           1, section->sh_size, _("section data"));
 
          indices = start;
          size = (section->sh_size / section->sh_entsize) - 1;
@@ -4187,8 +4483,8 @@ process_section_groups (FILE *file)
 
          if (do_section_groups)
            {
-             printf ("\n%s group section `%s' [%s] contains %u sections:\n",
-                     get_group_flags (entry), name, group_name, size);
+             printf ("\n%s group section [%5u] `%s' [%s] contains %u sections:\n",
+                     get_group_flags (entry), i, name, group_name, size);
 
              printf (_("   [Index]    Name\n"));
            }
@@ -4202,13 +4498,26 @@ process_section_groups (FILE *file)
              entry = byte_get (indices, 4);
              indices += 4;
 
+             if (SECTION_HEADER_INDEX (entry) >= elf_header.e_shnum)
+               {
+                 error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"),
+                        entry, i, elf_header.e_shnum - 1);
+                 continue;
+               }
+             else if (entry >= SHN_LORESERVE && entry <= SHN_HIRESERVE)
+               {
+                 error (_("invalid section [%5u] in group section [%5u]\n"),
+                        entry, i);
+                 continue;
+               }
+
              if (section_headers_groups [SECTION_HEADER_INDEX (entry)]
                  != NULL)
                {
                  if (entry)
                    {
-                     error (_("section [%5u] already in group section [%5u]\n"),
-                            entry,
+                     error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"),
+                            entry, i,
                             section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index);
                      continue;
                    }
@@ -4233,8 +4542,7 @@ process_section_groups (FILE *file)
              if (do_section_groups)
                {
                  sec = SECTION_HEADER (entry);
-                 printf ("   [%5u]   %s\n",
-                         entry, SECTION_NAME (sec));
+                 printf ("   [%5u]   %s\n", entry, SECTION_NAME (sec));
                }
 
              g = xmalloc (sizeof (struct group_list));
@@ -4365,26 +4673,37 @@ process_relocs (FILE *file)
 
              is_rela = section->sh_type == SHT_RELA;
 
-             if (section->sh_link)
+             if (section->sh_link
+                 && SECTION_HEADER_INDEX (section->sh_link)
+                    < elf_header.e_shnum)
                {
                  Elf_Internal_Shdr *symsec;
                  Elf_Internal_Sym *symtab;
                  unsigned long nsyms;
-                 unsigned long strtablen;
+                 unsigned long strtablen = 0;
                  char *strtab = NULL;
 
                  symsec = SECTION_HEADER (section->sh_link);
+                 if (symsec->sh_type != SHT_SYMTAB
+                     && symsec->sh_type != SHT_DYNSYM)
+                    continue;
+
                  nsyms = symsec->sh_size / symsec->sh_entsize;
                  symtab = GET_ELF_SYMBOLS (file, symsec);
 
                  if (symtab == NULL)
                    continue;
 
-                 strsec = SECTION_HEADER (symsec->sh_link);
+                 if (SECTION_HEADER_INDEX (symsec->sh_link)
+                     < elf_header.e_shnum)
+                   {
+                     strsec = SECTION_HEADER (symsec->sh_link);
 
-                 strtab = get_data (NULL, file, strsec->sh_offset,
-                                    strsec->sh_size, _("string table"));
-                 strtablen = strtab == NULL ? 0 : strsec->sh_size;
+                     strtab = get_data (NULL, file, strsec->sh_offset,
+                                        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);
@@ -4575,11 +4894,11 @@ slurp_ia64_unwind_table (FILE *file,
 
   /* Second, build the unwind table from the contents of the unwind section:  */
   size = sec->sh_size;
-  table = get_data (NULL, file, sec->sh_offset, size, _("unwind table"));
+  table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table"));
   if (!table)
     return 0;
 
-  aux->table = xmalloc (size / (3 * eh_addr_size) * sizeof (aux->table[0]));
+  aux->table = xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0]));
   tep = aux->table;
   for (tp = table; tp < table + size; tp += 3 * eh_addr_size, ++tep)
     {
@@ -4611,6 +4930,7 @@ slurp_ia64_unwind_table (FILE *file,
        ++relsec)
     {
       if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
          || SECTION_HEADER (relsec->sh_info) != sec)
        continue;
 
@@ -4676,15 +4996,16 @@ ia64_process_unwind (FILE *file)
 
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
-      if (sec->sh_type == SHT_SYMTAB)
+      if (sec->sh_type == SHT_SYMTAB
+         && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum)
        {
          aux.nsyms = sec->sh_size / sec->sh_entsize;
          aux.symtab = GET_ELF_SYMBOLS (file, sec);
 
          strsec = SECTION_HEADER (sec->sh_link);
-         aux.strtab_size = strsec->sh_size;
          aux.strtab = get_data (NULL, file, strsec->sh_offset,
-                                aux.strtab_size, _("string table"));
+                                1, strsec->sh_size, _("string table"));
+         aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
        }
       else if (sec->sh_type == SHT_IA_64_UNWIND)
        unwcount++;
@@ -4765,7 +5086,7 @@ ia64_process_unwind (FILE *file)
        {
          aux.info_size = sec->sh_size;
          aux.info_addr = sec->sh_addr;
-         aux.info = get_data (NULL, file, sec->sh_offset, aux.info_size,
+         aux.info = get_data (NULL, file, sec->sh_offset, 1, aux.info_size,
                               _("unwind info"));
 
          printf (_("\nUnwind section "));
@@ -4919,7 +5240,7 @@ slurp_hppa_unwind_table (FILE *file,
                         struct hppa_unw_aux_info *aux,
                         Elf_Internal_Shdr *sec)
 {
-  unsigned long size, unw_ent_size, nrelas, i;
+  unsigned long size, unw_ent_size, nentries, nrelas, i;
   Elf_Internal_Phdr *seg;
   struct hppa_unw_table_entry *tep;
   Elf_Internal_Shdr *relsec;
@@ -4955,35 +5276,30 @@ slurp_hppa_unwind_table (FILE *file,
   /* Second, build the unwind table from the contents of the unwind
      section.  */
   size = sec->sh_size;
-  table = get_data (NULL, file, sec->sh_offset, size, _("unwind table"));
+  table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table"));
   if (!table)
     return 0;
 
-  unw_ent_size = 2 * eh_addr_size + 8;
+  unw_ent_size = 16;
+  nentries = size / unw_ent_size;
+  size = unw_ent_size * nentries;
 
-  tep = aux->table = xmalloc (size / unw_ent_size * sizeof (aux->table[0]));
+  tep = aux->table = xcmalloc (nentries, sizeof (aux->table[0]));
 
-  for (tp = table; tp < table + size; tp += (2 * eh_addr_size + 8), ++tep)
+  for (tp = table; tp < table + size; tp += unw_ent_size, ++tep)
     {
       unsigned int tmp1, tmp2;
 
       tep->start.section = SHN_UNDEF;
       tep->end.section   = SHN_UNDEF;
 
-      if (is_32bit_elf)
-       {
-         tep->start.offset = byte_get ((unsigned char *) tp + 0, 4);
-         tep->end.offset = byte_get ((unsigned char *) tp + 4, 4);
-         tmp1 = byte_get ((unsigned char *) tp + 8, 4);
-         tmp2 = byte_get ((unsigned char *) tp + 12, 4);
-       }
-      else
-       {
-         tep->start.offset = BYTE_GET ((unsigned char *) tp + 0);
-         tep->end.offset = BYTE_GET ((unsigned char *) tp + 8);
-         tmp1 = byte_get ((unsigned char *) tp + 16, 4);
-         tmp2 = byte_get ((unsigned char *) tp + 20, 4);
-       }
+      tep->start.offset = byte_get ((unsigned char *) tp + 0, 4);
+      tep->end.offset = byte_get ((unsigned char *) tp + 4, 4);
+      tmp1 = byte_get ((unsigned char *) tp + 8, 4);
+      tmp2 = byte_get ((unsigned char *) tp + 12, 4);
+
+      tep->start.offset += aux->seg_base;
+      tep->end.offset   += aux->seg_base;
 
       tep->Cannot_unwind = (tmp1 >> 31) & 0x1;
       tep->Millicode = (tmp1 >> 30) & 0x1;
@@ -5016,9 +5332,6 @@ slurp_hppa_unwind_table (FILE *file,
       tep->Pseudo_SP_Set = (tmp2 >> 28) & 0x1;
       tep->reserved4 = (tmp2 >> 27) & 0x1;
       tep->Total_frame_size = tmp2 & 0x7ffffff;
-
-      tep->start.offset += aux->seg_base;
-      tep->end.offset   += aux->seg_base;
     }
   free (table);
 
@@ -5029,6 +5342,7 @@ slurp_hppa_unwind_table (FILE *file,
        ++relsec)
     {
       if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
          || SECTION_HEADER (relsec->sh_info) != sec)
        continue;
 
@@ -5076,7 +5390,7 @@ slurp_hppa_unwind_table (FILE *file,
       free (rela);
     }
 
-  aux->table_len = size / unw_ent_size;
+  aux->table_len = nentries;
 
   return 1;
 }
@@ -5092,19 +5406,21 @@ hppa_process_unwind (FILE *file)
 
   memset (& aux, 0, sizeof (aux));
 
-  assert (string_table != NULL);
+  if (string_table == NULL)
+    return 1;
 
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
-      if (sec->sh_type == SHT_SYMTAB)
+      if (sec->sh_type == SHT_SYMTAB
+         && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum)
        {
          aux.nsyms = sec->sh_size / sec->sh_entsize;
          aux.symtab = GET_ELF_SYMBOLS (file, sec);
 
          strsec = SECTION_HEADER (sec->sh_link);
-         aux.strtab_size = strsec->sh_size;
          aux.strtab = get_data (NULL, file, strsec->sh_offset,
-                                aux.strtab_size, _("string table"));
+                                1, strsec->sh_size, _("string table"));
+         aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
        }
       else if (streq (SECTION_NAME (sec), ".PARISC.unwind"))
        unwsec = sec;
@@ -5263,7 +5579,13 @@ dynamic_section_parisc_val (Elf_Internal_Dyn *entry)
          { DT_HP_BIND_RESTRICTED, "HP_BIND_RESTRICTED" },
          { DT_HP_BIND_SYMBOLIC, "HP_BIND_SYMBOLIC" },
          { DT_HP_RPATH_FIRST, "HP_RPATH_FIRST" },
-         { DT_HP_BIND_DEPTH_FIRST, "HP_BIND_DEPTH_FIRST" }
+         { DT_HP_BIND_DEPTH_FIRST, "HP_BIND_DEPTH_FIRST" },
+         { DT_HP_GST, "HP_GST" },
+         { DT_HP_SHLIB_FIXED, "HP_SHLIB_FIXED" },
+         { DT_HP_MERGE_SHLIB_SEG, "HP_MERGE_SHLIB_SEG" },
+         { DT_HP_NODELETE, "HP_NODELETE" },
+         { DT_HP_GROUP, "HP_GROUP" },
+         { DT_HP_PROTECT_LINKAGE_TABLE, "HP_PROTECT_LINKAGE_TABLE" }
        };
        int first = 1;
        size_t cnt;
@@ -5320,7 +5642,7 @@ get_32bit_dynamic_section (FILE *file)
   Elf32_External_Dyn *edyn, *ext;
   Elf_Internal_Dyn *entry;
 
-  edyn = get_data (NULL, file, dynamic_addr, dynamic_size,
+  edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
                   _("dynamic section"));
   if (!edyn)
     return 0;
@@ -5337,7 +5659,7 @@ get_32bit_dynamic_section (FILE *file)
        break;
     }
 
-  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+  dynamic_section = cmalloc (dynamic_nent, sizeof (*entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -5364,7 +5686,7 @@ get_64bit_dynamic_section (FILE *file)
   Elf64_External_Dyn *edyn, *ext;
   Elf_Internal_Dyn *entry;
 
-  edyn = get_data (NULL, file, dynamic_addr, dynamic_size,
+  edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
                   _("dynamic section"));
   if (!edyn)
     return 0;
@@ -5381,7 +5703,7 @@ get_64bit_dynamic_section (FILE *file)
        break;
     }
 
-  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+  dynamic_section = cmalloc (dynamic_nent, sizeof (*entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -5539,7 +5861,7 @@ process_dynamic_section (FILE *file)
              continue;
            }
 
-         dynamic_strings = get_data (NULL, file, offset, str_tab_len,
+         dynamic_strings = get_data (NULL, file, offset, 1, str_tab_len,
                                      _("dynamic string table"));
          dynamic_strings_length = str_tab_len;
          break;
@@ -5574,8 +5896,8 @@ process_dynamic_section (FILE *file)
          Elf_Internal_Syminfo *syminfo;
 
          /* There is a syminfo section.  Read the data.  */
-         extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, syminsz,
-                                _("symbol information"));
+         extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, 1,
+                                syminsz, _("symbol information"));
          if (!extsyminfo)
            return 0;
 
@@ -6051,9 +6373,13 @@ process_version_sections (FILE *file)
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link: %lx (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   SECTION_NAME (SECTION_HEADER (section->sh_link)));
+                   SECTION_HEADER_INDEX (section->sh_link)
+                   < elf_header.e_shnum
+                   ? SECTION_NAME (SECTION_HEADER (section->sh_link))
+                   : "<corrupt>");
 
-           edefs = get_data (NULL, file, section->sh_offset, section->sh_size,
+           edefs = get_data (NULL, file, section->sh_offset, 1,
+                             section->sh_size,
                              _("version definition section"));
            if (!edefs)
              break;
@@ -6140,9 +6466,13 @@ process_version_sections (FILE *file)
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link to section: %ld (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   SECTION_NAME (SECTION_HEADER (section->sh_link)));
+                   SECTION_HEADER_INDEX (section->sh_link)
+                   < elf_header.e_shnum
+                   ? SECTION_NAME (SECTION_HEADER (section->sh_link))
+                   : "<corrupt>");
 
-           eneed = get_data (NULL, file, section->sh_offset, section->sh_size,
+           eneed = get_data (NULL, file, section->sh_offset, 1,
+                             section->sh_size,
                              _("version need section"));
            if (!eneed)
              break;
@@ -6222,8 +6552,15 @@ process_version_sections (FILE *file)
            Elf_Internal_Shdr *string_sec;
            long off;
 
+           if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum)
+             break;
+
            link_section = SECTION_HEADER (section->sh_link);
-           total = section->sh_size / section->sh_entsize;
+           total = section->sh_size / sizeof (Elf_External_Versym);
+
+           if (SECTION_HEADER_INDEX (link_section->sh_link)
+               >= elf_header.e_shnum)
+             break;
 
            found = 1;
 
@@ -6231,7 +6568,7 @@ process_version_sections (FILE *file)
 
            string_sec = SECTION_HEADER (link_section->sh_link);
 
-           strtab = get_data (NULL, file, string_sec->sh_offset,
+           strtab = get_data (NULL, file, string_sec->sh_offset, 1,
                               string_sec->sh_size, _("version string table"));
            if (!strtab)
              break;
@@ -6248,7 +6585,7 @@ process_version_sections (FILE *file)
            off = offset_from_vma (file,
                                   version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
                                   total * sizeof (short));
-           edata = get_data (NULL, file, off, total * sizeof (short),
+           edata = get_data (NULL, file, off, total, sizeof (short),
                              _("version symbol data"));
            if (!edata)
              {
@@ -6256,7 +6593,7 @@ process_version_sections (FILE *file)
                break;
              }
 
-           data = malloc (total * sizeof (short));
+           data = cmalloc (total, sizeof (short));
 
            for (cnt = total; cnt --;)
              data[cnt] = byte_get (edata + cnt * sizeof (short),
@@ -6289,8 +6626,10 @@ process_version_sections (FILE *file)
 
                      check_def = 1;
                      check_need = 1;
-                     if (SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type
-                         != SHT_NOBITS)
+                     if (SECTION_HEADER_INDEX (symbols[cnt + j].st_shndx)
+                         >= elf_header.e_shnum
+                         || SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type
+                            != SHT_NOBITS)
                        {
                          if (symbols[cnt + j].st_shndx == SHN_UNDEF)
                            check_def = 0;
@@ -6315,7 +6654,7 @@ process_version_sections (FILE *file)
                              Elf_External_Vernaux evna;
                              unsigned long a_off;
 
-                             get_data (&evn, file, offset, sizeof (evn),
+                             get_data (&evn, file, offset, sizeof (evn), 1,
                                        _("version need"));
 
                              ivn.vn_aux  = BYTE_GET (evn.vn_aux);
@@ -6326,7 +6665,7 @@ process_version_sections (FILE *file)
                              do
                                {
                                  get_data (&evna, file, a_off, sizeof (evna),
-                                           _("version need aux (2)"));
+                                           1, _("version need aux (2)"));
 
                                  ivna.vna_next  = BYTE_GET (evna.vna_next);
                                  ivna.vna_other = BYTE_GET (evna.vna_other);
@@ -6367,7 +6706,7 @@ process_version_sections (FILE *file)
 
                          do
                            {
-                             get_data (&evd, file, offset, sizeof (evd),
+                             get_data (&evd, file, offset, sizeof (evd), 1,
                                        _("version def"));
 
                              ivd.vd_next = BYTE_GET (evd.vd_next);
@@ -6387,7 +6726,8 @@ process_version_sections (FILE *file)
 
                              get_data (&evda, file,
                                        offset - ivd.vd_next + ivd.vd_aux,
-                                       sizeof (evda), _("version def aux"));
+                                       sizeof (evda), 1,
+                                       _("version def aux"));
 
                              ivda.vda_name = BYTE_GET (evda.vda_name);
 
@@ -6519,6 +6859,9 @@ get_symbol_index_type (unsigned int type)
          && elf_header.e_machine == EM_IA_64
          && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX)
        return "ANSI_COM";
+      else if (elf_header.e_machine == EM_X86_64
+              && type == SHN_X86_64_LCOMMON)
+       return "LARGE_COM";
       else if (type >= SHN_LOPROC && type <= SHN_HIPROC)
        sprintf (buff, "PRC[0x%04x]", type);
       else if (type >= SHN_LOOS && type <= SHN_HIOS)
@@ -6539,7 +6882,7 @@ get_dynamic_data (FILE *file, unsigned int number, unsigned int ent_size)
   unsigned char *e_data;
   bfd_vma *i_data;
 
-  e_data = malloc (number * ent_size);
+  e_data = cmalloc (number, ent_size);
 
   if (e_data == NULL)
     {
@@ -6553,7 +6896,7 @@ get_dynamic_data (FILE *file, unsigned int number, unsigned int ent_size)
       return NULL;
     }
 
-  i_data = malloc (number * sizeof (*i_data));
+  i_data = cmalloc (number, sizeof (*i_data));
 
   if (i_data == NULL)
     {
@@ -6681,7 +7024,8 @@ process_symbol_table (FILE *file)
           i++, section++)
        {
          unsigned int si;
-         char *strtab;
+         char *strtab = NULL;
+         unsigned long int strtab_size = 0;
          Elf_Internal_Sym *symtab;
          Elf_Internal_Sym *psym;
 
@@ -6703,15 +7047,19 @@ process_symbol_table (FILE *file)
            continue;
 
          if (section->sh_link == elf_header.e_shstrndx)
-           strtab = string_table;
-         else
+           {
+             strtab = string_table;
+             strtab_size = string_table_length;
+           }
+         else if (SECTION_HEADER_INDEX (section->sh_link) < elf_header.e_shnum)
            {
              Elf_Internal_Shdr *string_sec;
 
              string_sec = SECTION_HEADER (section->sh_link);
 
              strtab = get_data (NULL, file, string_sec->sh_offset,
-                                string_sec->sh_size, _("string table"));
+                                1, string_sec->sh_size, _("string table"));
+             strtab_size = strtab != NULL ? string_sec->sh_size : 0;
            }
 
          for (si = 0, psym = symtab;
@@ -6726,7 +7074,8 @@ process_symbol_table (FILE *file)
              printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
              printf (" %-3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
              printf (" %4s ", get_symbol_index_type (psym->st_shndx));
-             print_symbol (25, strtab + psym->st_name);
+             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)
@@ -6742,12 +7091,14 @@ process_symbol_table (FILE *file)
                     sizeof data + si * sizeof (vers_data));
 
                  get_data (&data, file, offset + si * sizeof (vers_data),
-                           sizeof (data), _("version data"));
+                           sizeof (data), 1, _("version data"));
 
                  vers_data = byte_get (data, 2);
 
-                 is_nobits = (SECTION_HEADER (psym->st_shndx)->sh_type
-                              == SHT_NOBITS);
+                 is_nobits = (SECTION_HEADER_INDEX (psym->st_shndx)
+                              < elf_header.e_shnum
+                              && SECTION_HEADER (psym->st_shndx)->sh_type
+                                 == SHT_NOBITS);
 
                  check_def = (psym->st_shndx != SHN_UNDEF);
 
@@ -6769,7 +7120,7 @@ process_symbol_table (FILE *file)
                            {
                              unsigned long vna_off;
 
-                             get_data (&evn, file, offset, sizeof (evn),
+                             get_data (&evn, file, offset, sizeof (evn), 1,
                                        _("version need"));
 
                              ivn.vn_aux  = BYTE_GET (evn.vn_aux);
@@ -6782,7 +7133,7 @@ process_symbol_table (FILE *file)
                                  Elf_External_Vernaux evna;
 
                                  get_data (&evna, file, vna_off,
-                                           sizeof (evna),
+                                           sizeof (evna), 1,
                                            _("version need aux (3)"));
 
                                  ivna.vna_other = BYTE_GET (evna.vna_other);
@@ -6804,7 +7155,9 @@ process_symbol_table (FILE *file)
                          if (ivna.vna_other == vers_data)
                            {
                              printf ("@%s (%d)",
-                                     strtab + ivna.vna_name, ivna.vna_other);
+                                     ivna.vna_name < strtab_size
+                                     ? strtab + ivna.vna_name : "<corrupt>",
+                                     ivna.vna_other);
                              check_def = 0;
                            }
                          else if (! is_nobits)
@@ -6833,7 +7186,7 @@ process_symbol_table (FILE *file)
                                  Elf_External_Verdef evd;
 
                                  get_data (&evd, file, offset, sizeof (evd),
-                                           _("version def"));
+                                           1, _("version def"));
 
                                  ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
                                  ivd.vd_aux = BYTE_GET (evd.vd_aux);
@@ -6848,14 +7201,15 @@ process_symbol_table (FILE *file)
                              offset += ivd.vd_aux;
 
                              get_data (&evda, file, offset, sizeof (evda),
-                                       _("version def aux"));
+                                       1, _("version def aux"));
 
                              ivda.vda_name = BYTE_GET (evda.vda_name);
 
                              if (psym->st_name != ivda.vda_name)
                                printf ((vers_data & 0x8000)
                                        ? "@%s" : "@@%s",
-                                       strtab + ivda.vda_name);
+                                       ivda.vda_name < strtab_size
+                                       ? strtab + ivda.vda_name : "<corrupt>");
                            }
                        }
                    }
@@ -7040,7 +7394,8 @@ dump_section (Elf_Internal_Shdr *section, FILE *file)
 
   addr = section->sh_addr;
 
-  start = get_data (NULL, file, section->sh_offset, bytes, _("section data"));
+  start = get_data (NULL, file, section->sh_offset, 1, bytes,
+                   _("section data"));
   if (!start)
     return 0;
 
@@ -7247,7 +7602,7 @@ load_debug_str (FILE *file)
 
   debug_str_size = sec->sh_size;
 
-  debug_str_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+  debug_str_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
                                 _("debug_str section data"));
 }
 
@@ -7269,7 +7624,10 @@ fetch_indirect_string (unsigned long offset)
     return _("<no .debug_str section>");
 
   if (offset > debug_str_size)
-    return _("<offset is too big>");
+    {
+      warn (_("DW_FORM_strp offset too big: %lx\n"), offset);
+      return _("<offset is too big>");
+    }
 
   return debug_str_contents + offset;
 }
@@ -7293,7 +7651,7 @@ load_debug_loc (FILE *file)
 
   debug_loc_size = sec->sh_size;
 
-  debug_loc_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+  debug_loc_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
                                 _("debug_loc section data"));
 }
 
@@ -7327,7 +7685,7 @@ load_debug_range (FILE *file)
 
   debug_range_size = sec->sh_size;
 
-  debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+  debug_range_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
                                   _("debug_range section data"));
 }
 
@@ -7342,6 +7700,41 @@ free_debug_range (void)
   debug_range_size = 0;
 }
 
+static unsigned char *debug_abbrev_contents;
+static unsigned long debug_abbrev_size;
+
+static void
+load_debug_abbrev (FILE *file)
+{
+  Elf_Internal_Shdr *sec;
+
+  /* If it is already loaded, do nothing.  */
+  if (debug_abbrev_contents != NULL)
+    return;
+
+  /* Locate the .debug_ranges section.  */
+  sec = find_section (".debug_abbrev");
+  if (sec == NULL)
+    return;
+
+  debug_abbrev_size = sec->sh_size;
+
+  debug_abbrev_contents = get_data (NULL, file, sec->sh_offset, 1,
+                                   sec->sh_size,
+                                   _("debug_abbrev section data"));
+}
+
+static void
+free_debug_abbrev (void)
+{
+  if (debug_abbrev_contents == NULL)
+    return;
+
+  free ((char *) debug_abbrev_contents);
+  debug_abbrev_contents = NULL;
+  debug_abbrev_size = 0;
+}
+
 /* Apply addends of RELA relocations.  */
 
 static int
@@ -7368,8 +7761,10 @@ debug_apply_rela_addends (FILE *file,
       Elf_Internal_Sym *sym;
 
       if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
          || SECTION_HEADER (relsec->sh_info) != section
-         || relsec->sh_size == 0)
+         || relsec->sh_size == 0
+         || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum)
        continue;
 
       if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
@@ -8276,7 +8671,7 @@ read_and_display_attr_value (unsigned long attribute,
       break;
 
     default:
-      warn (_("Unrecognized form: %d\n"), form);
+      warn (_("Unrecognized form: %lu\n"), form);
       break;
     }
 
@@ -8307,11 +8702,11 @@ read_and_display_attr_value (unsigned long attribute,
                {
                  max += 1024;
                  debug_info_p->loc_offsets
-                   = xrealloc (debug_info_p->loc_offsets,
-                               max * sizeof (*debug_info_p->loc_offsets));
+                   = xcrealloc (debug_info_p->loc_offsets,
+                                max, sizeof (*debug_info_p->loc_offsets));
                  debug_info_p->have_frame_base
-                   = xrealloc (debug_info_p->have_frame_base,
-                               max * sizeof (*debug_info_p->have_frame_base));
+                   = xcrealloc (debug_info_p->have_frame_base,
+                                max, sizeof (*debug_info_p->have_frame_base));
                  debug_info_p->max_loc_offsets = max;
                }
              debug_info_p->loc_offsets [num] = uvalue;
@@ -8336,8 +8731,8 @@ read_and_display_attr_value (unsigned long attribute,
                {
                  max += 1024;
                  debug_info_p->range_lists
-                   = xrealloc (debug_info_p->range_lists,
-                               max * sizeof (*debug_info_p->range_lists));
+                   = xcrealloc (debug_info_p->range_lists,
+                                max, sizeof (*debug_info_p->range_lists));
                  debug_info_p->max_range_lists = max;
                }
              debug_info_p->range_lists [num] = uvalue;
@@ -8419,8 +8814,7 @@ read_and_display_attr_value (unsigned long attribute,
        case DW_ATE_unsigned_char:      printf ("(unsigned char)"); break;
          /* DWARF 2.1 value.  */
        case DW_ATE_imaginary_float:    printf ("(imaginary float)"); break;
-         /* GNU extension.  */
-       case DW_ATE_GNU_decimal_float:  printf ("(decimal float)"); break;
+       case DW_ATE_decimal_float:      printf ("(decimal float)"); break;
        default:
          if (uvalue >= DW_ATE_lo_user
              && uvalue <= DW_ATE_hi_user)
@@ -8714,8 +9108,8 @@ process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
        }
 
       /* Then allocate an array to hold the information.  */
-      debug_information = malloc (num_units *
-                                 sizeof (* debug_information));
+      debug_information = cmalloc (num_units,
+                                  sizeof (* debug_information));
       if (debug_information == NULL)
        {
          error (_("Not enough memory for a debug info array of %u entries"),
@@ -8734,6 +9128,13 @@ process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
       load_debug_range (file);
     }
 
+  load_debug_abbrev (file);
+  if (debug_abbrev_contents == NULL)
+    {
+      warn (_("Unable to locate .debug_abbrev section!\n"));
+      return 0;
+    }
+
   for (section_begin = start, unit = 0; start < end; unit++)
     {
       DWARF2_Internal_CompUnit compunit;
@@ -8800,7 +9201,7 @@ process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
 
       if (!do_loc)
        {
-         printf (_("  Compilation Unit @ %lx:\n"), cu_offset);
+         printf (_("  Compilation Unit @ offset 0x%lx:\n"), cu_offset);
          printf (_("   Length:        %ld\n"), compunit.cu_length);
          printf (_("   Version:       %d\n"), compunit.cu_version);
          printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
@@ -8815,29 +9216,10 @@ process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
 
       free_abbrevs ();
 
-      /* Read in the abbrevs used by this compilation unit.  */
-      {
-       Elf_Internal_Shdr *sec;
-       unsigned char *begin;
-
-       /* Locate the .debug_abbrev section and process it.  */
-       sec = find_section (".debug_abbrev");
-       if (sec == NULL)
-         {
-           warn (_("Unable to locate .debug_abbrev section!\n"));
-           return 0;
-         }
-
-       begin = get_data (NULL, file, sec->sh_offset, sec->sh_size,
-                         _("debug_abbrev section data"));
-       if (!begin)
-         return 0;
-
-       process_abbrev_section (begin + compunit.cu_abbrev_offset,
-                               begin + sec->sh_size);
-
-       free (begin);
-      }
+      /* Process the abbrevs used by this compilation unit.  */
+      process_abbrev_section
+       (debug_abbrev_contents + compunit.cu_abbrev_offset,
+        debug_abbrev_contents + debug_abbrev_size);
 
       level = 0;
       while (tags < start)
@@ -8911,6 +9293,8 @@ process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
        }
     }
  
+  free_debug_abbrev ();
+
   /* Set num_debug_info_entries here so that it can be used to check if
      we need to process .debug_loc and .debug_ranges sections.  */
   if ((do_loc || do_debug_loc || do_debug_ranges)
@@ -8997,7 +9381,7 @@ get_debug_info (FILE * file)
   if (section == NULL)
     return 0;
 
-  start = get_data (NULL, file, section->sh_offset, section->sh_size,
+  start = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                    _("extracting information from .debug_info section"));
   if (start == NULL)
     return 0;
@@ -9088,7 +9472,7 @@ display_debug_lines (Elf_Internal_Shdr *section,
       /* Get the pointer size from the comp unit associated
         with this block of line number information.  */
       pointer_size = get_pointer_size_and_offset_of_comp_unit
-       (comp_unit, ".debug_lines", NULL);
+       (comp_unit, ".debug_line", NULL);
       comp_unit ++;
 
       printf (_("  Length:                      %ld\n"), info.li_length);
@@ -9199,7 +9583,7 @@ display_debug_lines (Elf_Internal_Shdr *section,
                }
 
              data += process_extended_line_op (data, info.li_default_is_stmt,
-                                                 pointer_size);
+                                               pointer_size);
              break;
 
            case DW_LNS_copy:
@@ -9611,15 +9995,29 @@ display_debug_loc (Elf_Internal_Shdr *section,
            {
              if (start < next)
                warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
-                     start - section_begin, next - section_begin);
+                     (long)(start - section_begin), (long)(next - section_begin));
              else if (start > next)
                warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
-                     start - section_begin, next - section_begin);
+                     (long)(start - section_begin), (long)(next - section_begin));
            }
          start = next;
 
+         if (offset >= bytes)
+           {
+             warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"),
+                   offset);
+             continue;
+           }
+
          while (1)
            {
+             if (start + 2 * pointer_size > section_end)
+               {
+                 warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
+                       offset);
+                 break;
+               }
+
              begin = byte_get (start, pointer_size);
              start += pointer_size;
              end = byte_get (start, pointer_size);
@@ -9635,14 +10033,28 @@ display_debug_loc (Elf_Internal_Shdr *section,
              if (begin == -1UL && end != -1UL)
                {
                  base_address = end;
-                 printf ("    %8.8lx %8.8lx %8.8lx (base address)\n",
+                 printf (_("    %8.8lx %8.8lx %8.8lx (base address)\n"),
                          offset, begin, end);
                  continue;
                }
 
+             if (start + 2 > section_end)
+               {
+                 warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
+                       offset);
+                 break;
+               }
+
              length = byte_get (start, 2);
              start += 2;
 
+             if (start + length > section_end)
+               {
+                 warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
+                       offset);
+                 break;
+               }
+
              printf ("    %8.8lx %8.8lx %8.8lx (",
                      offset, begin + base_address, end + base_address);
              need_frame_base = decode_location_expression (start,
@@ -9936,10 +10348,10 @@ display_debug_ranges (Elf_Internal_Shdr *section,
            {
              if (start < next)
                warn (_("There is a hole [0x%lx - 0x%lx] in .debug_ranges section.\n"),
-                     start - section_begin, next - section_begin);
+                     (long)(start - section_begin), (long)(next - section_begin));
              else if (start > next)
                warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_ranges section.\n"),
-                     start - section_begin, next - section_begin);
+                     (long)(start - section_begin), (long)(next - section_begin));
            }
          start = next;
 
@@ -10015,8 +10427,8 @@ frame_need_space (Frame_Chunk *fc, int reg)
     return;
 
   fc->ncols = reg + 1;
-  fc->col_type = xrealloc (fc->col_type, fc->ncols * sizeof (short int));
-  fc->col_offset = xrealloc (fc->col_offset, fc->ncols * sizeof (int));
+  fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
+  fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
 
   while (prev < fc->ncols)
     {
@@ -10312,7 +10724,7 @@ display_debug_frames (Elf_Internal_Shdr *section,
 
          if (!cie)
            {
-             warn ("Invalid CIE pointer %08lx in FDE at %08lx\n",
+             warn ("Invalid CIE pointer %08lx in FDE at %p\n",
                    cie_id, saved_start);
              start = block_end;
              fc->ncols = 0;
@@ -10326,8 +10738,8 @@ display_debug_frames (Elf_Internal_Shdr *section,
          else
            {
              fc->ncols = cie->ncols;
-             fc->col_type = xmalloc (fc->ncols * sizeof (short int));
-             fc->col_offset = xmalloc (fc->ncols * sizeof (int));
+             fc->col_type = xcmalloc (fc->ncols, sizeof (short int));
+             fc->col_offset = xcmalloc (fc->ncols, sizeof (int));
              memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int));
              memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int));
              fc->augmentation = cie->augmentation;
@@ -10639,8 +11051,8 @@ display_debug_frames (Elf_Internal_Shdr *section,
                printf ("  DW_CFA_remember_state\n");
              rs = xmalloc (sizeof (Frame_Chunk));
              rs->ncols = fc->ncols;
-             rs->col_type = xmalloc (rs->ncols * sizeof (short int));
-             rs->col_offset = xmalloc (rs->ncols * sizeof (int));
+             rs->col_type = xcmalloc (rs->ncols, sizeof (short int));
+             rs->col_offset = xcmalloc (rs->ncols, sizeof (int));
              memcpy (rs->col_type, fc->col_type, rs->ncols);
              memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int));
              rs->next = remembered_state;
@@ -10862,7 +11274,7 @@ display_debug_section (Elf_Internal_Shdr *section, FILE *file)
       {
        unsigned char *start;
 
-       start = get_data (NULL, file, section->sh_offset, length,
+       start = get_data (NULL, file, section->sh_offset, 1, length,
                          _("debug section data"));
        if (start == NULL)
          {
@@ -10988,7 +11400,7 @@ process_mips_specific (FILE *file)
       size_t cnt;
 
       elib = get_data (NULL, file, liblist_offset,
-                      liblistno * sizeof (Elf32_External_Lib),
+                      liblistno, sizeof (Elf32_External_Lib),
                       _("liblist"));
       if (elib)
        {
@@ -11077,11 +11489,11 @@ process_mips_specific (FILE *file)
       while (sect->sh_type != SHT_MIPS_OPTIONS)
        ++sect;
 
-      eopt = get_data (NULL, file, options_offset, sect->sh_size,
+      eopt = get_data (NULL, file, options_offset, 1, sect->sh_size,
                       _("options"));
       if (eopt)
        {
-         iopt = malloc ((sect->sh_size / sizeof (eopt)) * sizeof (*iopt));
+         iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt));
          if (iopt == NULL)
            {
              error (_("Out of memory"));
@@ -11273,7 +11685,7 @@ process_mips_specific (FILE *file)
          return 0;
        }
 
-      iconf = malloc (conflictsno * sizeof (*iconf));
+      iconf = cmalloc (conflictsno, sizeof (*iconf));
       if (iconf == NULL)
        {
          error (_("Out of memory"));
@@ -11285,7 +11697,7 @@ process_mips_specific (FILE *file)
          Elf32_External_Conflict *econf32;
 
          econf32 = get_data (NULL, file, conflicts_offset,
-                             conflictsno * sizeof (*econf32), _("conflict"));
+                             conflictsno, sizeof (*econf32), _("conflict"));
          if (!econf32)
            return 0;
 
@@ -11299,7 +11711,7 @@ process_mips_specific (FILE *file)
          Elf64_External_Conflict *econf64;
 
          econf64 = get_data (NULL, file, conflicts_offset,
-                             conflictsno * sizeof (*econf64), _("conflict"));
+                             conflictsno, sizeof (*econf64), _("conflict"));
          if (!econf64)
            return 0;
 
@@ -11339,6 +11751,7 @@ process_gnu_liblist (FILE *file)
   Elf_Internal_Shdr *section, *string_sec;
   Elf32_External_Lib *elib;
   char *strtab;
+  size_t strtab_size;
   size_t cnt;
   unsigned i;
 
@@ -11352,15 +11765,19 @@ process_gnu_liblist (FILE *file)
       switch (section->sh_type)
        {
        case SHT_GNU_LIBLIST:
-         elib = get_data (NULL, file, section->sh_offset, section->sh_size,
+         if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum)
+           break;
+
+         elib = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                           _("liblist"));
 
          if (elib == NULL)
            break;
          string_sec = SECTION_HEADER (section->sh_link);
 
-         strtab = get_data (NULL, file, string_sec->sh_offset,
+         strtab = get_data (NULL, file, string_sec->sh_offset, 1,
                             string_sec->sh_size, _("liblist string table"));
+         strtab_size = string_sec->sh_size;
 
          if (strtab == NULL
              || section->sh_entsize != sizeof (Elf32_External_Lib))
@@ -11397,9 +11814,11 @@ process_gnu_liblist (FILE *file)
 
              printf ("%3lu: ", (unsigned long) cnt);
              if (do_wide)
-               printf ("%-20s", strtab + liblist.l_name);
+               printf ("%-20s", liblist.l_name < strtab_size
+                                ? strtab + liblist.l_name : "<corrupt>");
              else
-               printf ("%-20.20s", strtab + liblist.l_name);
+               printf ("%-20.20s", liblist.l_name < strtab_size
+                                   ? strtab + liblist.l_name : "<corrupt>");
              printf (" %s %#010lx %-7ld %-7ld\n", timebuf, liblist.l_checksum,
                      liblist.l_version, liblist.l_flags);
            }
@@ -11564,7 +11983,7 @@ process_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length)
   if (length <= 0)
     return 0;
 
-  pnotes = get_data (NULL, file, offset, length, _("notes"));
+  pnotes = get_data (NULL, file, offset, 1, length, _("notes"));
   if (!pnotes)
     return 0;
 
@@ -11591,9 +12010,9 @@ process_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length)
 
       if (((char *) next) > (((char *) pnotes) + length))
        {
-         warn (_("corrupt note found at offset %x into core notes\n"),
-               ((char *) external) - ((char *) pnotes));
-         warn (_(" type: %x, namesize: %08lx, descsize: %08lx\n"),
+         warn (_("corrupt note found at offset %lx into core notes\n"),
+               (long)((char *)external - (char *)pnotes));
+         warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"),
                inote.type, inote.namesz, inote.descsz);
          break;
        }
@@ -12072,7 +12491,7 @@ process_archive (char *file_name, FILE *file)
          off = strtoul (arhdr.ar_name + 1, NULL, 10);
          if (off >= longnames_size)
            {
-             error (_("%s: invalid archive string table offset %lu\n"), off);
+             error (_("%s: invalid archive string table offset %lu\n"), file_name, off);
              ret = 1;
              break;
            }
@@ -12088,7 +12507,7 @@ process_archive (char *file_name, FILE *file)
 
       if (nameend == NULL)
        {
-         error (_("%s: bad archive file name\n"));
+         error (_("%s: bad archive file name\n"), file_name);
          ret = 1;
          break;
        }
This page took 0.055429 seconds and 4 git commands to generate.