+2015-01-05  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/17512
+       * archive.c (do_slurp_bsd_armap): Make sure that the parsed sized
+       is at least big enough for the header to be read.
+       * elf32-i386.c (elf_i386_get_plt_sym_val): Skip unknown relocs.
+       * mach-o.c (bfd_mach_o_get_synthetic_symtab): Add range checks.
+       (bfd_mach_o_read_command): Prevetn duplicate error messages about
+       unrecognized commands.
+       * syms.c (_bfd_stab_section_find_nearest_line): Add range checks
+       when indexing into the string table.
+
 2015-01-01  Alan Modra  <amodra@gmail.com>
 
        Update year range in copyright notice of all files.
 
   parsed_size = mapdata->parsed_size;
   free (mapdata);
   /* PR 17512: file: 883ff754.  */
-  if (parsed_size == 0)
+  /* PR 17512: file: 0458885f.  */
+  if (parsed_size < 4)
     return FALSE;
 
   raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size);
 
     {
       long reloc_index;
 
-      if (p->howto->type != R_386_JUMP_SLOT
-         && p->howto->type != R_386_IRELATIVE)
+      if (p->howto == NULL /* PR 17512: file: bc9d6cf5.  */
+         || (p->howto->type != R_386_JUMP_SLOT
+             && p->howto->type != R_386_IRELATIVE))
        continue;
 
       reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset
 
       for (isym = isymbuf + 1, sym = symbase; isym < isymend; isym++, sym++)
        {
          memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym));
-         sym->symbol.the_bfd = abfd;
 
+         sym->symbol.the_bfd = abfd;
          sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL);
-
          sym->symbol.value = isym->st_value;
 
          if (isym->st_shndx == SHN_UNDEF)
 
   bfd_mach_o_dysymtab_command *dysymtab = mdata->dysymtab;
   bfd_mach_o_symtab_command *symtab = mdata->symtab;
   asymbol *s;
+  char * s_start;
+  char * s_end;
   unsigned long count, i, j, n;
   size_t size;
   char *names;
   char *nul_name;
+  const char stub [] = "$stub";
 
   *ret = NULL;
 
   /* Stop now if no symbols or no indirect symbols.  */
-  if (dysymtab == NULL || symtab == NULL || symtab->symbols == NULL)
-    return 0;
-
-  if (dysymtab->nindirectsyms == 0)
+  if (dysymtab == NULL || dysymtab->nindirectsyms == 0
+      || symtab == NULL || symtab->symbols == NULL)
     return 0;
 
   /* We need to allocate a bfd symbol for every indirect symbol and to
 
   for (j = 0; j < count; j++)
     {
+      const char * strng;
       unsigned int isym = dysymtab->indirect_syms[j];
 
       /* Some indirect symbols are anonymous.  */
-      if (isym < symtab->nsyms && symtab->symbols[isym].symbol.name)
-        size += strlen (symtab->symbols[isym].symbol.name) + sizeof ("$stub");
+      if (isym < symtab->nsyms && (strng = symtab->symbols[isym].symbol.name))
+       /* PR 17512: file: f5b8eeba.  */
+       size += strnlen (strng, symtab->strsize - (strng - symtab->strtab)) + sizeof (stub);
     }
 
-  s = *ret = (asymbol *) bfd_malloc (size);
+  s_start = bfd_malloc (size);
+  s = *ret = (asymbol *) s_start;
   if (s == NULL)
     return -1;
   names = (char *) (s + count);
   nul_name = names;
   *names++ = 0;
+  s_end = s_start + size;
 
   n = 0;
   for (i = 0; i < mdata->nsects; i++)
           last = first + bfd_mach_o_section_get_nbr_indirect (abfd, sec);
           addr = sec->addr;
           entry_size = bfd_mach_o_section_get_entry_size (abfd, sec);
+
+         /* PR 17512: file: 08e15eec.  */
+         if (first >= count || last >= count || first > last)
+           goto fail;
+
           for (j = first; j < last; j++)
             {
               unsigned int isym = dysymtab->indirect_syms[j];
 
+             /* PR 17512: file: 04d64d9b.  */
+             if (((char *) s) + sizeof (* s) > s_end)
+               goto fail;
+
               s->flags = BSF_GLOBAL | BSF_SYNTHETIC;
               s->section = sec->bfdsection;
               s->value = addr - sec->addr;
 
                   s->name = names;
                   len = strlen (sym);
+                 /* PR 17512: file: 47dfd4d2.  */
+                 if (names + len >= s_end)
+                   goto fail;
                   memcpy (names, sym, len);
                   names += len;
-                  memcpy (names, "$stub", sizeof ("$stub"));
-                  names += sizeof ("$stub");
+                 /* PR 17512: file: 18f340a4.  */
+                 if (names + sizeof (stub) >= s_end)
+                   goto fail;
+                  memcpy (names, stub, sizeof (stub));
+                  names += sizeof (stub);
                 }
               else
                 s->name = nul_name;
     }
 
   return n;
+
+ fail:
+  free (s_start);
+  * ret = NULL;
+  return -1;
 }
 
 void
        return FALSE;
       break;
     default:
-      (*_bfd_error_handler)(_("%B: unknown load command 0x%lx"),
-         abfd, (unsigned long) command->type);
-      break;
+      {
+       static bfd_boolean unknown_set = FALSE;
+       static unsigned long unknown_command = 0;
+
+       /* Prevent reams of error messages when parsing corrupt binaries.  */
+       if (!unknown_set)
+         unknown_set = TRUE;
+       else if (command->type == unknown_command)
+         break;
+       unknown_command = command->type;
+
+       (*_bfd_error_handler)(_("%B: unknown load command 0x%lx"),
+                             abfd, (unsigned long) command->type);
+       break;
+      }
     }
 
   return TRUE;
 
 
   *minisymsp = syms;
   *sizep = sizeof (asymbol *);
+
   return symcount;
 
  error_return:
                {
                  nul_fun = stab;
                  nul_str = str;
+                 if (file_name >= (char *) info->strs + strsize)
+                   file_name = NULL;
                  if (stab + STABSIZE + TYPEOFF < info->stabs + stabsize
                      && *(stab + STABSIZE + TYPEOFF) == (bfd_byte) N_SO)
                    {
                      directory_name = file_name;
                      file_name = ((char *) str
                                   + bfd_get_32 (abfd, stab + STRDXOFF));
+                     if (file_name >= (char *) info->strs + strsize)
+                       file_name = NULL;
                    }
                }
              break;
            case N_SOL:
              /* The name of an include file.  */
              file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
+             /* PR 17512: file: 0c680a1f.  */
+             if (file_name >= (char *) info->strs + strsize)
+               file_name = NULL;
              break;
 
            case N_FUN:
              function_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
              if (function_name == (char *) str)
                continue;
+             if (function_name >= (char *) info->strs + strsize)
+               function_name = NULL;
 
              nul_fun = NULL;
              info->indextable[i].val = bfd_get_32 (abfd, stab + VALOFF);
          if (val <= offset)
            {
              file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
+             if (file_name >= (char *) info->strs + strsize)
+               file_name = NULL;
              *pline = 0;
            }
          break;
 
+2015-01-05  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/17512
+       * nm.c (print_symbol): Add 'is_synthetic' parameter.  Use it to
+       help initialize the info.elfinfo field.
+       (print_size_symbols): Add 'synth_count' parameter.  Use it to set
+       the is_synthetic parameter when calling print_symbol.
+       (print_symbols): Likewise.
+       (display_rel_file): Pass synth_count to printing function.
+       (display_archive): Break loop if the last archive displayed
+       matches the current archive.
+       * size.c (display_archive): Likewise.
+
 2015-01-05  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/17531
 
 /* Print a single symbol.  */
 
 static void
-print_symbol (bfd *abfd, asymbol *sym, bfd_vma ssize, bfd *archive_bfd)
+print_symbol (bfd *        abfd,
+             asymbol *    sym,
+             bfd_vma      ssize,
+             bfd *        archive_bfd,
+             bfd_boolean  is_synthetic)
 {
   symbol_info syminfo;
   struct extended_symbol_info info;
   format->print_symbol_filename (archive_bfd, abfd);
 
   bfd_get_symbol_info (abfd, sym, &syminfo);
+
   info.sinfo = &syminfo;
   info.ssize = ssize;
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
-    info.elfinfo = (elf_symbol_type *) sym;
-  else
-    info.elfinfo = NULL;
+  /* Synthetic symbols do not have a full elf_symbol_type set of data available.  */
+  info.elfinfo = is_synthetic ? NULL : elf_symbol_from (abfd, sym);
+
   format->print_symbol_info (&info, abfd);
 
   if (line_numbers)
 /* Print the symbols when sorting by size.  */
 
 static void
-print_size_symbols (bfd *abfd, bfd_boolean is_dynamic,
-                   struct size_sym *symsizes, long symcount,
-                   bfd *archive_bfd)
+print_size_symbols (bfd *              abfd,
+                   bfd_boolean        is_dynamic,
+                   struct size_sym *  symsizes,
+                   long               symcount,
+                   long               synth_count,
+                   bfd *              archive_bfd)
 {
   asymbol *store;
-  struct size_sym *from, *fromend;
+  struct size_sym *from;
+  struct size_sym *fromend;
+  struct size_sym *fromsynth;
 
   store = bfd_make_empty_symbol (abfd);
   if (store == NULL)
 
   from = symsizes;
   fromend = from + symcount;
+  fromsynth = symsizes + (symcount - synth_count);
+
   for (; from < fromend; from++)
     {
       asymbol *sym;
       if (sym == NULL)
        bfd_fatal (bfd_get_filename (abfd));
 
-      print_symbol (abfd, sym, from->size, archive_bfd);
+      print_symbol (abfd, sym, from->size, archive_bfd, from >= fromsynth);
     }
 }
 
 \f
-/* Print the symbols.  If ARCHIVE_BFD is non-NULL, it is the archive
-   containing ABFD.  */
+/* Print the symbols of ABFD that are held in MINISYMS.
+
+   If ARCHIVE_BFD is non-NULL, it is the archive containing ABFD.
+
+   SYMCOUNT is the number of symbols in MINISYMS and SYNTH_COUNT
+   is the number of these that are synthetic.  Synthetic symbols,
+   if any are present, always come at the end of the MINISYMS.
+   
+   SIZE is the size of a symbol in MINISYMS.  */
 
 static void
-print_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms, long symcount,
-              unsigned int size, bfd *archive_bfd)
+print_symbols (bfd *         abfd,
+              bfd_boolean   is_dynamic,
+              void *        minisyms,
+              long          symcount,
+              long          synth_count,
+              unsigned int  size,
+              bfd *         archive_bfd)
 {
   asymbol *store;
-  bfd_byte *from, *fromend;
+  bfd_byte *from;
+  bfd_byte *fromend;
+  bfd_byte *fromsynth;
 
   store = bfd_make_empty_symbol (abfd);
   if (store == NULL)
 
   from = (bfd_byte *) minisyms;
   fromend = from + symcount * size;
+  fromsynth = (bfd_byte *) minisyms + ((symcount - synth_count) * size);
+
   for (; from < fromend; from += size)
     {
       asymbol *sym;
       if (sym == NULL)
        bfd_fatal (bfd_get_filename (abfd));
 
-      print_symbol (abfd, sym, (bfd_vma) 0, archive_bfd);
+      print_symbol (abfd, sym, (bfd_vma) 0, archive_bfd, from >= fromsynth);
     }
 }
 
 display_rel_file (bfd *abfd, bfd *archive_bfd)
 {
   long symcount;
+  long synth_count = 0;
   void *minisyms;
   unsigned int size;
   struct size_sym *symsizes;
       non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
       return;
     }
-
+  
   if (show_synthetic && size == sizeof (asymbol *))
     {
       asymbol *synthsyms;
-      long synth_count;
       asymbol **static_syms = NULL;
       asymbol **dyn_syms = NULL;
       long static_count = 0;
                bfd_fatal (bfd_get_filename (abfd));
            }
        }
+
       synth_count = bfd_get_synthetic_symtab (abfd, static_count, static_syms,
                                              dyn_count, dyn_syms, &synthsyms);
       if (synth_count > 0)
     }
 
   if (! sort_by_size)
-    print_symbols (abfd, dynamic, minisyms, symcount, size, archive_bfd);
+    print_symbols (abfd, dynamic, minisyms, symcount, synth_count, size, archive_bfd);
   else
-    print_size_symbols (abfd, dynamic, symsizes, symcount, archive_bfd);
+    print_size_symbols (abfd, dynamic, symsizes, symcount, synth_count, archive_bfd);
 
   free (minisyms);
   free (symsizes);
          bfd_close (last_arfile);
          lineno_cache_bfd = NULL;
          lineno_cache_rel_bfd = NULL;
+         if (arfile == last_arfile)
+           return;
        }
       last_arfile = arfile;
     }
        print_value (abfd, SYM_SIZE (info));
       else
        print_value (abfd, SYM_VALUE (info));
-
       if (print_size && SYM_SIZE (info))
        {
          printf (" ");
 
       display_bfd (arfile);
 
       if (last_arfile != NULL)
-       bfd_close (last_arfile);
+       {
+         bfd_close (last_arfile);
+
+         /* PR 17512: file: a244edbc.  */
+         if (last_arfile == arfile)
+           return;
+       }
+
       last_arfile = arfile;
     }