2002-11-06 Richard Sandiford <rsandifo@redhat.com>
[deliverable/binutils-gdb.git] / bfd / stabs.c
index ffc000d499ec0aed5551b4ad6289bb1bdb304fbb..0cb37412983d3d53a8a759f6de545f1359bd9727 100644 (file)
@@ -1,5 +1,6 @@
 /* Stabs in sections linking support.
-   Copyright 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -25,8 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "sysdep.h"
 #include "libbfd.h"
 #include "aout/stab_gnu.h"
-
-#include <ctype.h>
+#include "safe-ctype.h"
 
 /* Stabs entries use a 12 byte format:
      4 byte string table index
@@ -108,7 +108,7 @@ struct stab_section_info
      as the input offsets, because no stabs have been deleted from
      this section.  Otherwise the i'th entry is the number of
      bytes of stabs that have been deleted prior to the i'th
-     stab. */
+     stab.  */
   bfd_size_type *cumulative_skips;
 
   /* This is an array of string indices.  For each stab symbol, we
@@ -178,7 +178,7 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
 {
   boolean first;
   struct stab_info *sinfo;
-  bfd_size_type count;
+  bfd_size_type count, amt;
   struct stab_section_info *secinfo;
   bfd_byte *stabbuf = NULL;
   bfd_byte *stabstrbuf = NULL;
@@ -223,13 +223,16 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
     {
       /* Initialize the stabs information we need to keep track of.  */
       first = true;
-      *psinfo = (PTR) bfd_alloc (abfd, sizeof (struct stab_info));
+      amt = sizeof (struct stab_info);
+      *psinfo = (PTR) bfd_alloc (abfd, amt);
       if (*psinfo == NULL)
        goto error_return;
       sinfo = (struct stab_info *) *psinfo;
       sinfo->strings = _bfd_stringtab_init ();
       if (sinfo->strings == NULL)
        goto error_return;
+      /* Make sure the first byte is zero.  */
+      (void) _bfd_stringtab_add (sinfo->strings, "", true, true);
       if (! bfd_hash_table_init_n (&sinfo->includes.root,
                                   stab_link_includes_newfunc,
                                   251))
@@ -245,16 +248,16 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
 
   count = stabsec->_raw_size / STABSIZE;
 
-  *psecinfo = bfd_alloc (abfd,
-                        (sizeof (struct stab_section_info)
-                         + (count - 1) * sizeof (bfd_size_type)));
+  amt = sizeof (struct stab_section_info);
+  amt += (count - 1) * sizeof (bfd_size_type);
+  *psecinfo = bfd_alloc (abfd, amt);
   if (*psecinfo == NULL)
     goto error_return;
 
   secinfo = (struct stab_section_info *) *psecinfo;
   secinfo->excls = NULL;
   secinfo->cumulative_skips = NULL;
-  memset (secinfo->stridxs, 0, count * sizeof (bfd_size_type));
+  memset (secinfo->stridxs, 0, (size_t) count * sizeof (bfd_size_type));
 
   /* Read the stabs information from abfd.  */
 
@@ -263,9 +266,9 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
   if (stabbuf == NULL || stabstrbuf == NULL)
     goto error_return;
 
-  if (! bfd_get_section_contents (abfd, stabsec, stabbuf, 0,
+  if (! bfd_get_section_contents (abfd, stabsec, stabbuf, (bfd_vma) 0,
                                  stabsec->_raw_size)
-      || ! bfd_get_section_contents (abfd, stabstrsec, stabstrbuf, 0,
+      || ! bfd_get_section_contents (abfd, stabstrsec, stabstrbuf, (bfd_vma) 0,
                                     stabstrsec->_raw_size))
     goto error_return;
 
@@ -281,6 +284,7 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
        sym < symend;
        sym += STABSIZE, ++pstridx)
     {
+      bfd_size_type symstroff;
       int type;
       const char *string;
 
@@ -308,9 +312,18 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
        }
 
       /* Store the string in the hash table, and record the index.  */
-      string = ((char *) stabstrbuf
-               + stroff
-               + bfd_get_32 (abfd, sym + STRDXOFF));
+      symstroff = stroff + bfd_get_32 (abfd, sym + STRDXOFF);
+      if (symstroff >= stabstrsec->_raw_size)
+       {
+         (*_bfd_error_handler)
+           (_("%s(%s+0x%lx): Stabs entry has invalid string index."),
+            bfd_archive_filename (abfd),
+            bfd_get_section_name (abfd, stabsec),
+            (long) (sym - stabbuf));
+         bfd_set_error (bfd_error_bad_value);
+         goto error_return;
+       }
+      string = (char *) stabstrbuf + symstroff;
       *pstridx = _bfd_stringtab_add (sinfo->strings, string, true, true);
 
       /* An N_BINCL symbol indicates the start of the stabs entries
@@ -318,7 +331,7 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
         symbol, ignoring nesting, adding up all the characters in the
         symbol names, not including the file numbers in types (the
         first number after an open parenthesis).  */
-      if (type == N_BINCL)
+      if (type == (int) N_BINCL)
        {
          bfd_vma val;
          int nest;
@@ -338,13 +351,13 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
              incl_type = incl_sym[TYPEOFF];
              if (incl_type == 0)
                break;
-             else if (incl_type == N_EINCL)
+             else if (incl_type == (int) N_EINCL)
                {
                  if (nest == 0)
                    break;
                  --nest;
                }
-             else if (incl_type == N_BINCL)
+             else if (incl_type == (int) N_BINCL)
                ++nest;
              else if (nest == 0)
                {
@@ -360,7 +373,7 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
                        {
                          /* Skip the file number.  */
                          ++str;
-                         while (isdigit ((unsigned char) *str))
+                         while (ISDIGIT (*str))
                            ++str;
                          --str;
                        }
@@ -381,12 +394,13 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
 
          /* Record this symbol, so that we can set the value
              correctly.  */
-         ne = (struct stab_excl_list *) bfd_alloc (abfd, sizeof *ne);
+         amt = sizeof *ne;
+         ne = (struct stab_excl_list *) bfd_alloc (abfd, amt);
          if (ne == NULL)
            goto error_return;
          ne->offset = sym - stabbuf;
          ne->val = val;
-         ne->type = N_BINCL;
+         ne->type = (int) N_BINCL;
          ne->next = secinfo->excls;
          secinfo->excls = ne;
 
@@ -408,7 +422,7 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
 
              /* We have seen this header file before.  Tell the final
                 pass to change the type to N_EXCL.  */
-             ne->type = N_EXCL;
+             ne->type = (int) N_EXCL;
 
              /* Mark the skipped symbols.  */
 
@@ -421,7 +435,7 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
 
                  incl_type = incl_sym[TYPEOFF];
 
-                 if (incl_type == N_EINCL)
+                 if (incl_type == (int) N_EINCL)
                    {
                      if (nest == 0)
                        {
@@ -431,7 +445,7 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
                        }
                      --nest;
                    }
-                 else if (incl_type == N_BINCL)
+                 else if (incl_type == (int) N_BINCL)
                    ++nest;
                  else if (nest == 0)
                    {
@@ -462,15 +476,15 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
   sinfo->stabstr->_cooked_size = _bfd_stringtab_size (sinfo->strings);
 
   /* Calculate the `cumulative_skips' array now that stabs have been
-     deleted for this section. */
+     deleted for this section.  */
 
   if (skip != 0)
     {
       bfd_size_type i, offset;
       bfd_size_type *pskips;
 
-      secinfo->cumulative_skips =
-       (bfd_size_type *) bfd_alloc (abfd, count * sizeof (bfd_size_type));
+      amt = count * sizeof (bfd_size_type);
+      secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt);
       if (secinfo->cumulative_skips == NULL)
        goto error_return;
 
@@ -498,6 +512,176 @@ _bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo)
   return false;
 }
 
+\f
+/* This function is called for each input file before the stab
+   section is relocated.  It discards stab entries for discarded
+   functions and variables.  The function returns true iff
+   any entries have been deleted.
+*/
+
+boolean
+_bfd_discard_section_stabs (abfd, stabsec, psecinfo,
+                           reloc_symbol_deleted_p, cookie)
+     bfd *abfd;
+     asection *stabsec;
+     PTR psecinfo;
+     boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR));
+     PTR cookie;
+{
+  bfd_size_type count, amt;
+  struct stab_section_info *secinfo;
+  bfd_byte *stabbuf = NULL;
+  bfd_byte *sym, *symend;
+  bfd_size_type skip;
+  bfd_size_type *pstridx;
+  int deleting;
+
+  if (stabsec->_raw_size == 0)
+    {
+      /* This file does not contain stabs debugging information.  */
+      return false;
+    }
+
+  if (stabsec->_raw_size % STABSIZE != 0)
+    {
+      /* Something is wrong with the format of these stab symbols.
+         Don't try to optimize them.  */
+      return false;
+    }
+
+  if ((stabsec->output_section != NULL
+       && bfd_is_abs_section (stabsec->output_section)))
+    {
+      /* At least one of the sections is being discarded from the
+         link, so we should just ignore them.  */
+      return false;
+    }
+
+  /* We should have initialized our data in _bfd_link_stab_sections.
+     If there was some bizarre error reading the string sections, though,
+     we might not have.  Bail rather than asserting.  */
+  if (psecinfo == NULL)
+    return false;
+
+  count = stabsec->_raw_size / STABSIZE;
+  secinfo = (struct stab_section_info *) psecinfo;
+
+  /* Read the stabs information from abfd.  */
+
+  stabbuf = (bfd_byte *) bfd_malloc (stabsec->_raw_size);
+  if (stabbuf == NULL)
+    goto error_return;
+
+  if (! bfd_get_section_contents (abfd, stabsec, stabbuf, (bfd_vma) 0,
+                                 stabsec->_raw_size))
+    goto error_return;
+
+  /* Look through the stabs symbols and discard any information for
+     discarded functions.  */
+
+  skip = 0;
+  deleting = -1;
+
+  symend = stabbuf + stabsec->_raw_size;
+  for (sym = stabbuf, pstridx = secinfo->stridxs;
+       sym < symend;
+       sym += STABSIZE, ++pstridx)
+    {
+      int type;
+
+      if (*pstridx == (bfd_size_type) -1)
+       {
+         /* This stab was deleted in a previous pass.  */
+         continue;
+       }
+
+      type = sym[TYPEOFF];
+
+      if (type == (int) N_FUN)
+       {
+         int strx = bfd_get_32 (abfd, sym + STRDXOFF);
+
+         if (strx == 0)
+           {
+             if (deleting)
+               {
+                 skip++;
+                 *pstridx = -1;
+               }
+             deleting = -1;
+             continue;
+           }
+         deleting = 0;
+         if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie))
+           deleting = 1;
+       }
+
+      if (deleting == 1)
+       {
+         *pstridx = -1;
+         skip++;
+       }
+      else if (deleting == -1)
+       {
+         /* Outside of a function.  Check for deleted variables.  */
+         if (type == (int) N_STSYM || type == (int) N_LCSYM)
+           if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie))
+             {
+               *pstridx = -1;
+               skip ++;
+             }
+         /* We should also check for N_GSYM entries which reference a
+            deleted global, but those are less harmful to debuggers
+            and would require parsing the stab strings.  */
+       }
+    }
+
+  free (stabbuf);
+  stabbuf = NULL;
+
+  /* Shrink the stabsec as needed.  */
+  stabsec->_cooked_size -= skip * STABSIZE;
+  if (stabsec->_cooked_size == 0)
+    stabsec->flags |= SEC_EXCLUDE;
+
+  /* Recalculate the `cumulative_skips' array now that stabs have been
+     deleted for this section.  */
+
+  if (skip != 0)
+    {
+      bfd_size_type i, offset;
+      bfd_size_type *pskips;
+
+      if (secinfo->cumulative_skips == NULL)
+       {
+         amt = count * sizeof (bfd_size_type);
+         secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt);
+         if (secinfo->cumulative_skips == NULL)
+           goto error_return;
+       }
+
+      pskips = secinfo->cumulative_skips;
+      pstridx = secinfo->stridxs;
+      offset = 0;
+
+      for (i = 0; i < count; i++, pskips++, pstridx++)
+       {
+         *pskips = offset;
+         if (*pstridx == (bfd_size_type) -1)
+           offset += STABSIZE;
+       }
+
+      BFD_ASSERT (offset != 0);
+    }
+
+  return (boolean) (skip > 0);
+
+ error_return:
+  if (stabbuf != NULL)
+    free (stabbuf);
+  return false;
+}
+
 /* Write out the stab section.  This is called with the relocated
    contents.  */
 
@@ -520,7 +704,8 @@ _bfd_write_section_stabs (output_bfd, psinfo, stabsec, psecinfo, contents)
 
   if (secinfo == NULL)
     return bfd_set_section_contents (output_bfd, stabsec->output_section,
-                                    contents, stabsec->output_offset,
+                                    contents,
+                                    (file_ptr) stabsec->output_offset,
                                     stabsec->_raw_size);
 
   /* Handle each N_BINCL entry.  */
@@ -569,7 +754,7 @@ _bfd_write_section_stabs (output_bfd, psinfo, stabsec, psecinfo, contents)
   BFD_ASSERT ((bfd_size_type) (tosym - contents) == stabsec->_cooked_size);
 
   return bfd_set_section_contents (output_bfd, stabsec->output_section,
-                                  contents, stabsec->output_offset,
+                                  contents, (file_ptr) stabsec->output_offset,
                                   stabsec->_cooked_size);
 }
 
@@ -598,8 +783,8 @@ _bfd_write_stab_strings (output_bfd, psinfo)
              <= sinfo->stabstr->output_section->_raw_size);
 
   if (bfd_seek (output_bfd,
-               (sinfo->stabstr->output_section->filepos
-                + sinfo->stabstr->output_offset),
+               (file_ptr) (sinfo->stabstr->output_section->filepos
+                           + sinfo->stabstr->output_offset),
                SEEK_SET) != 0)
     return false;
 
@@ -619,8 +804,8 @@ _bfd_write_stab_strings (output_bfd, psinfo)
 
 bfd_vma
 _bfd_stab_section_offset (output_bfd, psinfo, stabsec, psecinfo, offset)
-     bfd *output_bfd;
-     PTR *psinfo;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     PTR *psinfo ATTRIBUTE_UNUSED;
      asection *stabsec;
      PTR *psecinfo;
      bfd_vma offset;
This page took 0.048714 seconds and 4 git commands to generate.