Fix a possible integer overflow problem when examining corrupt binaries using a 32...
[binutils-gdb.git] / binutils / rddbg.c
index 75ddab54488d18af35251ef9d7be3f1b78c475f3..92052783ba919c5e3156bbf34fad9bb5e787afd1 100644 (file)
@@ -1,13 +1,12 @@
 /* rddbg.c -- Read debugging information into a generic form.
 /* rddbg.c -- Read debugging information into a generic form.
-   Copyright 1995, 1996, 1997, 2000, 2002, 2003
-   Free Software Foundation, Inc.
+   Copyright (C) 1995-2019 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@cygnus.com>.
 
    This file is part of GNU Binutils.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Written by Ian Lance Taylor <ian@cygnus.com>.
 
    This file is part of GNU Binutils.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
 
 /* This file reads debugging information into a generic form.  This
    file knows how to dig the debugging information out of an object
    file.  */
 
 
 /* This file reads debugging information into a generic form.  This
    file knows how to dig the debugging information out of an object
    file.  */
 
+#include "sysdep.h"
 #include "bfd.h"
 #include "bfd.h"
-#include "bucomm.h"
 #include "libiberty.h"
 #include "libiberty.h"
+#include "bucomm.h"
 #include "debug.h"
 #include "budbg.h"
 
 #include "debug.h"
 #include "budbg.h"
 
@@ -34,7 +35,6 @@ static bfd_boolean read_section_stabs_debugging_info
   (bfd *, asymbol **, long, void *, bfd_boolean *);
 static bfd_boolean read_symbol_stabs_debugging_info
   (bfd *, asymbol **, long, void *, bfd_boolean *);
   (bfd *, asymbol **, long, void *, bfd_boolean *);
 static bfd_boolean read_symbol_stabs_debugging_info
   (bfd *, asymbol **, long, void *, bfd_boolean *);
-static bfd_boolean read_ieee_debugging_info (bfd *, void *, bfd_boolean *);
 static void save_stab (int, int, bfd_vma, const char *);
 static void stab_context (void);
 static void free_saved_stabs (void);
 static void save_stab (int, int, bfd_vma, const char *);
 static void stab_context (void);
 static void free_saved_stabs (void);
@@ -43,7 +43,7 @@ static void free_saved_stabs (void);
    pointer.  */
 
 void *
    pointer.  */
 
 void *
-read_debugging_info (bfd *abfd, asymbol **syms, long symcount)
+read_debugging_info (bfd *abfd, asymbol **syms, long symcount, bfd_boolean no_messages)
 {
   void *dhandle;
   bfd_boolean found;
 {
   void *dhandle;
   bfd_boolean found;
@@ -63,12 +63,6 @@ read_debugging_info (bfd *abfd, asymbol **syms, long symcount)
        return NULL;
     }
 
        return NULL;
     }
 
-  if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour)
-    {
-      if (! read_ieee_debugging_info (abfd, dhandle, &found))
-       return NULL;
-    }
-
   /* Try reading the COFF symbols if we didn't find any stabs in COFF
      sections.  */
   if (! found
   /* Try reading the COFF symbols if we didn't find any stabs in COFF
      sections.  */
   if (! found
@@ -82,8 +76,9 @@ read_debugging_info (bfd *abfd, asymbol **syms, long symcount)
 
   if (! found)
     {
 
   if (! found)
     {
-      non_fatal (_("%s: no recognized debugging information"),
-                bfd_get_filename (abfd));
+      if (! no_messages)
+       non_fatal (_("%s: no recognized debugging information"),
+                  bfd_get_filename (abfd));
       return NULL;
     }
 
       return NULL;
     }
 
@@ -100,8 +95,13 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
     {
       const char *secname;
       const char *strsecname;
     {
       const char *secname;
       const char *strsecname;
-    } names[] = { { ".stab", ".stabstr" },
-                 { "LC_SYMTAB.stabs", "LC_SYMTAB.stabstr" } };
+    }
+  names[] =
+    {
+      { ".stab", ".stabstr" },
+      { "LC_SYMTAB.stabs", "LC_SYMTAB.stabstr" },
+      { "$GDB_SYMBOLS$", "$GDB_STRINGS$" }
+    };
   unsigned int i;
   void *shandle;
 
   unsigned int i;
   void *shandle;
 
@@ -128,35 +128,46 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
              fprintf (stderr, "%s: %s: %s\n",
                       bfd_get_filename (abfd), names[i].secname,
                       bfd_errmsg (bfd_get_error ()));
              fprintf (stderr, "%s: %s: %s\n",
                       bfd_get_filename (abfd), names[i].secname,
                       bfd_errmsg (bfd_get_error ()));
+             free (shandle);
+             free (stabs);
              return FALSE;
            }
 
          strsize = bfd_section_size (abfd, strsec);
              return FALSE;
            }
 
          strsize = bfd_section_size (abfd, strsec);
-         strings = (bfd_byte *) xmalloc (strsize);
+         strings = (bfd_byte *) xmalloc (strsize + 1);
          if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize))
            {
              fprintf (stderr, "%s: %s: %s\n",
                       bfd_get_filename (abfd), names[i].strsecname,
                       bfd_errmsg (bfd_get_error ()));
          if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize))
            {
              fprintf (stderr, "%s: %s: %s\n",
                       bfd_get_filename (abfd), names[i].strsecname,
                       bfd_errmsg (bfd_get_error ()));
+             free (shandle);
+             free (strings);
+             free (stabs);
              return FALSE;
            }
              return FALSE;
            }
-
+         /* Zero terminate the strings table, just in case.  */
+         strings [strsize] = 0;
          if (shandle == NULL)
            {
              shandle = start_stab (dhandle, abfd, TRUE, syms, symcount);
              if (shandle == NULL)
          if (shandle == NULL)
            {
              shandle = start_stab (dhandle, abfd, TRUE, syms, symcount);
              if (shandle == NULL)
-               return FALSE;
+               {
+                 free (strings);
+                 free (stabs);
+                 return FALSE;
+               }
            }
 
          *pfound = TRUE;
 
          stroff = 0;
          next_stroff = 0;
            }
 
          *pfound = TRUE;
 
          stroff = 0;
          next_stroff = 0;
-         for (stab = stabs; stab < stabs + stabsize; stab += 12)
+         /* PR 17512: file: 078-60391-0.001:0.1.  */
+         for (stab = stabs; stab <= (stabs + stabsize) - 12; stab += 12)
            {
              unsigned int strx;
              int type;
            {
              unsigned int strx;
              int type;
-             int other;
+             int other ATTRIBUTE_UNUSED;
              int desc;
              bfd_vma value;
 
              int desc;
              bfd_vma value;
 
@@ -177,32 +188,42 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
                }
              else
                {
                }
              else
                {
+                 size_t len;
                  char *f, *s;
 
                  char *f, *s;
 
-                 f = NULL;
-
-                 if (stroff + strx > strsize)
+                 if (stroff + strx >= strsize)
                    {
                    {
-                     fprintf (stderr, "%s: %s: stab entry %ld is corrupt, strx = 0x%x, type = %d\n",
+                     fprintf (stderr, _("%s: %s: stab entry %ld is corrupt, strx = 0x%x, type = %d\n"),
                               bfd_get_filename (abfd), names[i].secname,
                               (long) (stab - stabs) / 12, strx, type);
                      continue;
                    }
 
                  s = (char *) strings + stroff + strx;
                               bfd_get_filename (abfd), names[i].secname,
                               (long) (stab - stabs) / 12, strx, type);
                      continue;
                    }
 
                  s = (char *) strings + stroff + strx;
+                 f = NULL;
 
 
-                 while (s[strlen (s) - 1] == '\\'
+                 /* PR 17512: file: 002-87578-0.001:0.1.
+                    It is possible to craft a file where, without the 'strlen (s) > 0',
+                    an attempt to read the byte before 'strings' would occur.  */
+                 while ((len = strlen (s)) > 0
+                        && s[len  - 1] == '\\'
                         && stab + 12 < stabs + stabsize)
                    {
                      char *p;
 
                      stab += 12;
                         && stab + 12 < stabs + stabsize)
                    {
                      char *p;
 
                      stab += 12;
-                     p = s + strlen (s) - 1;
+                     p = s + len - 1;
                      *p = '\0';
                      *p = '\0';
-                     s = concat (s,
-                                 ((char *) strings
-                                  + stroff
-                                  + bfd_get_32 (abfd, stab)),
+                     strx = stroff + bfd_get_32 (abfd, stab);
+                     if (strx >= strsize)
+                       {
+                         fprintf (stderr, _("%s: %s: stab entry %ld is corrupt\n"),
+                                  bfd_get_filename (abfd), names[i].secname,
+                                  (long) (stab - stabs) / 12);
+                         break;
+                       }
+
+                     s = concat (s, (char *) strings + strx,
                                  (const char *) NULL);
 
                      /* We have to restore the backslash, because, if
                                  (const char *) NULL);
 
                      /* We have to restore the backslash, because, if
@@ -210,8 +231,7 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
                         see the same string more than once.  */
                      *p = '\\';
 
                         see the same string more than once.  */
                      *p = '\\';
 
-                     if (f != NULL)
-                       free (f);
+                     free (f);
                      f = s;
                    }
 
                      f = s;
                    }
 
@@ -221,6 +241,10 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
                    {
                      stab_context ();
                      free_saved_stabs ();
                    {
                      stab_context ();
                      free_saved_stabs ();
+                     free (f);
+                     free (shandle);
+                     free (stabs);
+                     free (strings);
                      return FALSE;
                    }
 
                      return FALSE;
                    }
 
@@ -280,8 +304,12 @@ read_symbol_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
          *pfound = TRUE;
 
          s = i.name;
          *pfound = TRUE;
 
          s = i.name;
+         if (s == NULL || strlen (s) < 1)
+           return FALSE;
          f = NULL;
          f = NULL;
-         while (s[strlen (s) - 1] == '\\'
+
+         while (strlen (s) > 0
+                && s[strlen (s) - 1] == '\\'
                 && ps + 1 < symend)
            {
              char *sc, *n;
                 && ps + 1 < symend)
            {
              char *sc, *n;
@@ -323,37 +351,6 @@ read_symbol_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
 
   return TRUE;
 }
 
   return TRUE;
 }
-
-/* Read IEEE debugging information.  */
-
-static bfd_boolean
-read_ieee_debugging_info (bfd *abfd, void *dhandle, bfd_boolean *pfound)
-{
-  asection *dsec;
-  bfd_size_type size;
-  bfd_byte *contents;
-
-  /* The BFD backend puts the debugging information into a section
-     named .debug.  */
-
-  dsec = bfd_get_section_by_name (abfd, ".debug");
-  if (dsec == NULL)
-    return TRUE;
-
-  size = bfd_section_size (abfd, dsec);
-  contents = (bfd_byte *) xmalloc (size);
-  if (! bfd_get_section_contents (abfd, dsec, contents, 0, size))
-    return FALSE;
-
-  if (! parse_ieee (dhandle, abfd, contents, size))
-    return FALSE;
-
-  free (contents);
-
-  *pfound = TRUE;
-
-  return TRUE;
-}
 \f
 /* Record stabs strings, so that we can give some context for errors.  */
 
 \f
 /* Record stabs strings, so that we can give some context for errors.  */