Home | History | Annotate | Download | only in bfd
      1 /* Stabs in sections linking support.
      2    Copyright (C) 1996-2016 Free Software Foundation, Inc.
      3    Written by Ian Lance Taylor, Cygnus Support.
      4 
      5    This file is part of BFD, the Binary File Descriptor library.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program; if not, write to the Free Software
     19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 
     23 /* This file contains support for linking stabs in sections, as used
     24    on COFF and ELF.  */
     25 
     26 #include "sysdep.h"
     27 #include "bfd.h"
     28 #include "libbfd.h"
     29 #include "aout/stab_gnu.h"
     30 #include "safe-ctype.h"
     31 
     32 /* Stabs entries use a 12 byte format:
     33      4 byte string table index
     34      1 byte stab type
     35      1 byte stab other field
     36      2 byte stab desc field
     37      4 byte stab value
     38    FIXME: This will have to change for a 64 bit object format.
     39 
     40    The stabs symbols are divided into compilation units.  For the
     41    first entry in each unit, the type of 0, the value is the length of
     42    the string table for this unit, and the desc field is the number of
     43    stabs symbols for this unit.  */
     44 
     45 #define STRDXOFF  0
     46 #define TYPEOFF   4
     47 #define OTHEROFF  5
     48 #define DESCOFF   6
     49 #define VALOFF    8
     50 #define STABSIZE  12
     51 
     52 /* A linked list of totals that we have found for a particular header
     53    file.  A total is a unique identifier for a particular BINCL...EINCL
     54    sequence of STABs that can be used to identify duplicate sequences.
     55    It consists of three fields, 'sum_chars' which is the sum of all the
     56    STABS characters; 'num_chars' which is the number of these charactes
     57    and 'symb' which is a buffer of all the symbols in the sequence.  This
     58    buffer is only checked as a last resort.  */
     59 
     60 struct stab_link_includes_totals
     61 {
     62   struct stab_link_includes_totals *next;
     63   bfd_vma sum_chars;  /* Accumulated sum of STABS characters.  */
     64   bfd_vma num_chars;  /* Number of STABS characters.  */
     65   const char* symb;   /* The STABS characters themselves.  */
     66 };
     67 
     68 /* An entry in the header file hash table.  */
     69 
     70 struct stab_link_includes_entry
     71 {
     72   struct bfd_hash_entry root;
     73   /* List of totals we have found for this file.  */
     74   struct stab_link_includes_totals *totals;
     75 };
     76 
     77 /* This structure is used to hold a list of N_BINCL symbols, some of
     78    which might be converted into N_EXCL symbols.  */
     79 
     80 struct stab_excl_list
     81 {
     82   /* The next symbol to convert.  */
     83   struct stab_excl_list *next;
     84   /* The offset to this symbol in the section contents.  */
     85   bfd_size_type offset;
     86   /* The value to use for the symbol.  */
     87   bfd_vma val;
     88   /* The type of this symbol (N_BINCL or N_EXCL).  */
     89   int type;
     90 };
     91 
     92 /* This structure is stored with each .stab section.  */
     93 
     94 struct stab_section_info
     95 {
     96   /* This is a linked list of N_BINCL symbols which should be
     97      converted into N_EXCL symbols.  */
     98   struct stab_excl_list *excls;
     99 
    100   /* This is used to map input stab offsets within their sections
    101      to output stab offsets, to take into account stabs that have
    102      been deleted.  If it is NULL, the output offsets are the same
    103      as the input offsets, because no stabs have been deleted from
    104      this section.  Otherwise the i'th entry is the number of
    105      bytes of stabs that have been deleted prior to the i'th
    106      stab.  */
    107   bfd_size_type *cumulative_skips;
    108 
    109   /* This is an array of string indices.  For each stab symbol, we
    110      store the string index here.  If a stab symbol should not be
    111      included in the final output, the string index is -1.  */
    112   bfd_size_type stridxs[1];
    113 };
    114 
    115 
    116 /* The function to create a new entry in the header file hash table.  */
    118 
    119 static struct bfd_hash_entry *
    120 stab_link_includes_newfunc (struct bfd_hash_entry *entry,
    121 			    struct bfd_hash_table *table,
    122 			    const char *string)
    123 {
    124   struct stab_link_includes_entry *ret =
    125     (struct stab_link_includes_entry *) entry;
    126 
    127   /* Allocate the structure if it has not already been allocated by a
    128      subclass.  */
    129   if (ret == NULL)
    130     ret = (struct stab_link_includes_entry *)
    131         bfd_hash_allocate (table, sizeof (struct stab_link_includes_entry));
    132   if (ret == NULL)
    133     return NULL;
    134 
    135   /* Call the allocation method of the superclass.  */
    136   ret = ((struct stab_link_includes_entry *)
    137 	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
    138   if (ret)
    139     /* Set local fields.  */
    140     ret->totals = NULL;
    141 
    142   return (struct bfd_hash_entry *) ret;
    143 }
    144 
    145 /* This function is called for each input file from the add_symbols
    147    pass of the linker.  */
    148 
    149 bfd_boolean
    150 _bfd_link_section_stabs (bfd *abfd,
    151 			 struct stab_info *sinfo,
    152 			 asection *stabsec,
    153 			 asection *stabstrsec,
    154 			 void * *psecinfo,
    155 			 bfd_size_type *pstring_offset)
    156 {
    157   bfd_boolean first;
    158   bfd_size_type count, amt;
    159   struct stab_section_info *secinfo;
    160   bfd_byte *stabbuf = NULL;
    161   bfd_byte *stabstrbuf = NULL;
    162   bfd_byte *sym, *symend;
    163   bfd_size_type stroff, next_stroff, skip;
    164   bfd_size_type *pstridx;
    165 
    166   if (stabsec->size == 0
    167       || stabstrsec->size == 0)
    168     /* This file does not contain stabs debugging information.  */
    169     return TRUE;
    170 
    171   if (stabsec->size % STABSIZE != 0)
    172     /* Something is wrong with the format of these stab symbols.
    173        Don't try to optimize them.  */
    174     return TRUE;
    175 
    176   if ((stabstrsec->flags & SEC_RELOC) != 0)
    177     /* We shouldn't see relocations in the strings, and we aren't
    178        prepared to handle them.  */
    179     return TRUE;
    180 
    181   if (bfd_is_abs_section (stabsec->output_section)
    182       || bfd_is_abs_section (stabstrsec->output_section))
    183     /* At least one of the sections is being discarded from the
    184        link, so we should just ignore them.  */
    185     return TRUE;
    186 
    187   first = FALSE;
    188 
    189   if (sinfo->stabstr == NULL)
    190     {
    191       flagword flags;
    192 
    193       /* Initialize the stabs information we need to keep track of.  */
    194       first = TRUE;
    195       sinfo->strings = _bfd_stringtab_init ();
    196       if (sinfo->strings == NULL)
    197 	goto error_return;
    198       /* Make sure the first byte is zero.  */
    199       (void) _bfd_stringtab_add (sinfo->strings, "", TRUE, TRUE);
    200       if (! bfd_hash_table_init (&sinfo->includes,
    201 				 stab_link_includes_newfunc,
    202 				 sizeof (struct stab_link_includes_entry)))
    203 	goto error_return;
    204       flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING
    205 	       | SEC_LINKER_CREATED);
    206       sinfo->stabstr = bfd_make_section_anyway_with_flags (abfd, ".stabstr",
    207 							   flags);
    208       if (sinfo->stabstr == NULL)
    209 	goto error_return;
    210     }
    211 
    212   /* Initialize the information we are going to store for this .stab
    213      section.  */
    214   count = stabsec->size / STABSIZE;
    215 
    216   amt = sizeof (struct stab_section_info);
    217   amt += (count - 1) * sizeof (bfd_size_type);
    218   *psecinfo = bfd_alloc (abfd, amt);
    219   if (*psecinfo == NULL)
    220     goto error_return;
    221 
    222   secinfo = (struct stab_section_info *) *psecinfo;
    223   secinfo->excls = NULL;
    224   stabsec->rawsize = stabsec->size;
    225   secinfo->cumulative_skips = NULL;
    226   memset (secinfo->stridxs, 0, (size_t) count * sizeof (bfd_size_type));
    227 
    228   /* Read the stabs information from abfd.  */
    229   if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf)
    230       || !bfd_malloc_and_get_section (abfd, stabstrsec, &stabstrbuf))
    231     goto error_return;
    232 
    233   /* Look through the stabs symbols, work out the new string indices,
    234      and identify N_BINCL symbols which can be eliminated.  */
    235   stroff = 0;
    236   /* The stabs sections can be split when
    237      -split-by-reloc/-split-by-file is used.  We must keep track of
    238      each stab section's place in the single concatenated string
    239      table.  */
    240   next_stroff = pstring_offset ? *pstring_offset : 0;
    241   skip = 0;
    242 
    243   symend = stabbuf + stabsec->size;
    244   for (sym = stabbuf, pstridx = secinfo->stridxs;
    245        sym < symend;
    246        sym += STABSIZE, ++pstridx)
    247     {
    248       bfd_size_type symstroff;
    249       int type;
    250       const char *string;
    251 
    252       if (*pstridx != 0)
    253 	/* This symbol has already been handled by an N_BINCL pass.  */
    254 	continue;
    255 
    256       type = sym[TYPEOFF];
    257 
    258       if (type == 0)
    259 	{
    260 	  /* Special type 0 stabs indicate the offset to the next
    261 	     string table.  We only copy the very first one.  */
    262 	  stroff = next_stroff;
    263 	  next_stroff += bfd_get_32 (abfd, sym + 8);
    264 	  if (pstring_offset)
    265 	    *pstring_offset = next_stroff;
    266 	  if (! first)
    267 	    {
    268 	      *pstridx = (bfd_size_type) -1;
    269 	      ++skip;
    270 	      continue;
    271 	    }
    272 	  first = FALSE;
    273 	}
    274 
    275       /* Store the string in the hash table, and record the index.  */
    276       symstroff = stroff + bfd_get_32 (abfd, sym + STRDXOFF);
    277       if (symstroff >= stabstrsec->size)
    278 	{
    279 	  (*_bfd_error_handler)
    280 	    (_("%B(%A+0x%lx): Stabs entry has invalid string index."),
    281 	     abfd, stabsec, (long) (sym - stabbuf));
    282 	  bfd_set_error (bfd_error_bad_value);
    283 	  goto error_return;
    284 	}
    285       string = (char *) stabstrbuf + symstroff;
    286       *pstridx = _bfd_stringtab_add (sinfo->strings, string, TRUE, TRUE);
    287 
    288       /* An N_BINCL symbol indicates the start of the stabs entries
    289 	 for a header file.  We need to scan ahead to the next N_EINCL
    290 	 symbol, ignoring nesting, adding up all the characters in the
    291 	 symbol names, not including the file numbers in types (the
    292 	 first number after an open parenthesis).  */
    293       if (type == (int) N_BINCL)
    294 	{
    295 	  bfd_vma sum_chars;
    296 	  bfd_vma num_chars;
    297 	  bfd_vma buf_len = 0;
    298 	  char * symb;
    299 	  char * symb_rover;
    300 	  int nest;
    301 	  bfd_byte * incl_sym;
    302 	  struct stab_link_includes_entry * incl_entry;
    303 	  struct stab_link_includes_totals * t;
    304 	  struct stab_excl_list * ne;
    305 
    306 	  symb = symb_rover = NULL;
    307 	  sum_chars = num_chars = 0;
    308 	  nest = 0;
    309 
    310 	  for (incl_sym = sym + STABSIZE;
    311 	       incl_sym < symend;
    312 	       incl_sym += STABSIZE)
    313 	    {
    314 	      int incl_type;
    315 
    316 	      incl_type = incl_sym[TYPEOFF];
    317 	      if (incl_type == 0)
    318 		break;
    319 	      else if (incl_type == (int) N_EXCL)
    320 		continue;
    321 	      else if (incl_type == (int) N_EINCL)
    322 		{
    323 		  if (nest == 0)
    324 		    break;
    325 		  --nest;
    326 		}
    327 	      else if (incl_type == (int) N_BINCL)
    328 		++nest;
    329 	      else if (nest == 0)
    330 		{
    331 		  const char *str;
    332 
    333 		  str = ((char *) stabstrbuf
    334 			 + stroff
    335 			 + bfd_get_32 (abfd, incl_sym + STRDXOFF));
    336 		  for (; *str != '\0'; str++)
    337 		    {
    338 		      if (num_chars >= buf_len)
    339 			{
    340 			  buf_len += 32 * 1024;
    341 			  symb = (char *) bfd_realloc_or_free (symb, buf_len);
    342 			  if (symb == NULL)
    343 			    goto error_return;
    344 			  symb_rover = symb + num_chars;
    345 			}
    346 		      * symb_rover ++ = * str;
    347 		      sum_chars += *str;
    348 		      num_chars ++;
    349 		      if (*str == '(')
    350 			{
    351 			  /* Skip the file number.  */
    352 			  ++str;
    353 			  while (ISDIGIT (*str))
    354 			    ++str;
    355 			  --str;
    356 			}
    357 		    }
    358 		}
    359 	    }
    360 
    361 	  BFD_ASSERT (num_chars == (bfd_vma) (symb_rover - symb));
    362 
    363 	  /* If we have already included a header file with the same
    364 	     value, then replaced this one with an N_EXCL symbol.  */
    365 	  incl_entry = (struct stab_link_includes_entry * )
    366 	    bfd_hash_lookup (&sinfo->includes, string, TRUE, TRUE);
    367 	  if (incl_entry == NULL)
    368 	    goto error_return;
    369 
    370 	  for (t = incl_entry->totals; t != NULL; t = t->next)
    371 	    if (t->sum_chars == sum_chars
    372 		&& t->num_chars == num_chars
    373 		&& memcmp (t->symb, symb, num_chars) == 0)
    374 	      break;
    375 
    376 	  /* Record this symbol, so that we can set the value
    377 	     correctly.  */
    378 	  amt = sizeof *ne;
    379 	  ne = (struct stab_excl_list *) bfd_alloc (abfd, amt);
    380 	  if (ne == NULL)
    381 	    goto error_return;
    382 	  ne->offset = sym - stabbuf;
    383 	  ne->val = sum_chars;
    384 	  ne->type = (int) N_BINCL;
    385 	  ne->next = secinfo->excls;
    386 	  secinfo->excls = ne;
    387 
    388 	  if (t == NULL)
    389 	    {
    390 	      /* This is the first time we have seen this header file
    391 		 with this set of stabs strings.  */
    392 	      t = (struct stab_link_includes_totals *)
    393                   bfd_hash_allocate (&sinfo->includes, sizeof *t);
    394 	      if (t == NULL)
    395 		goto error_return;
    396 	      t->sum_chars = sum_chars;
    397 	      t->num_chars = num_chars;
    398               /* Trim data down.  */
    399 	      t->symb = symb = (char *) bfd_realloc_or_free (symb, num_chars);
    400 	      t->next = incl_entry->totals;
    401 	      incl_entry->totals = t;
    402 	    }
    403 	  else
    404 	    {
    405 	      bfd_size_type *incl_pstridx;
    406 
    407 	      /* We have seen this header file before.  Tell the final
    408 		 pass to change the type to N_EXCL.  */
    409 	      ne->type = (int) N_EXCL;
    410 
    411 	      /* Free off superfluous symbols.  */
    412 	      free (symb);
    413 
    414 	      /* Mark the skipped symbols.  */
    415 
    416 	      nest = 0;
    417 	      for (incl_sym = sym + STABSIZE, incl_pstridx = pstridx + 1;
    418 		   incl_sym < symend;
    419 		   incl_sym += STABSIZE, ++incl_pstridx)
    420 		{
    421 		  int incl_type;
    422 
    423 		  incl_type = incl_sym[TYPEOFF];
    424 
    425 		  if (incl_type == (int) N_EINCL)
    426 		    {
    427 		      if (nest == 0)
    428 			{
    429 			  *incl_pstridx = (bfd_size_type) -1;
    430 			  ++skip;
    431 			  break;
    432 			}
    433 		      --nest;
    434 		    }
    435 		  else if (incl_type == (int) N_BINCL)
    436 		    ++nest;
    437 		  else if (incl_type == (int) N_EXCL)
    438 		    /* Keep existing exclusion marks.  */
    439 		    continue;
    440 		  else if (nest == 0)
    441 		    {
    442 		      *incl_pstridx = (bfd_size_type) -1;
    443 		      ++skip;
    444 		    }
    445 		}
    446 	    }
    447 	}
    448     }
    449 
    450   free (stabbuf);
    451   stabbuf = NULL;
    452   free (stabstrbuf);
    453   stabstrbuf = NULL;
    454 
    455   /* We need to set the section sizes such that the linker will
    456      compute the output section sizes correctly.  We set the .stab
    457      size to not include the entries we don't want.  We set
    458      SEC_EXCLUDE for the .stabstr section, so that it will be dropped
    459      from the link.  We record the size of the strtab in the first
    460      .stabstr section we saw, and make sure we don't set SEC_EXCLUDE
    461      for that section.  */
    462   stabsec->size = (count - skip) * STABSIZE;
    463   if (stabsec->size == 0)
    464     stabsec->flags |= SEC_EXCLUDE | SEC_KEEP;
    465   stabstrsec->flags |= SEC_EXCLUDE | SEC_KEEP;
    466   sinfo->stabstr->size = _bfd_stringtab_size (sinfo->strings);
    467 
    468   /* Calculate the `cumulative_skips' array now that stabs have been
    469      deleted for this section.  */
    470 
    471   if (skip != 0)
    472     {
    473       bfd_size_type i, offset;
    474       bfd_size_type *pskips;
    475 
    476       amt = count * sizeof (bfd_size_type);
    477       secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt);
    478       if (secinfo->cumulative_skips == NULL)
    479 	goto error_return;
    480 
    481       pskips = secinfo->cumulative_skips;
    482       pstridx = secinfo->stridxs;
    483       offset = 0;
    484 
    485       for (i = 0; i < count; i++, pskips++, pstridx++)
    486 	{
    487 	  *pskips = offset;
    488 	  if (*pstridx == (bfd_size_type) -1)
    489 	    offset += STABSIZE;
    490 	}
    491 
    492       BFD_ASSERT (offset != 0);
    493     }
    494 
    495   return TRUE;
    496 
    497  error_return:
    498   if (stabbuf != NULL)
    499     free (stabbuf);
    500   if (stabstrbuf != NULL)
    501     free (stabstrbuf);
    502   return FALSE;
    503 }
    504 
    505 /* This function is called for each input file before the stab
    507    section is relocated.  It discards stab entries for discarded
    508    functions and variables.  The function returns TRUE iff
    509    any entries have been deleted.
    510 */
    511 
    512 bfd_boolean
    513 _bfd_discard_section_stabs (bfd *abfd,
    514 			    asection *stabsec,
    515 			    void * psecinfo,
    516 			    bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *),
    517 			    void * cookie)
    518 {
    519   bfd_size_type count, amt;
    520   struct stab_section_info *secinfo;
    521   bfd_byte *stabbuf = NULL;
    522   bfd_byte *sym, *symend;
    523   bfd_size_type skip;
    524   bfd_size_type *pstridx;
    525   int deleting;
    526 
    527   if (stabsec->size == 0)
    528     /* This file does not contain stabs debugging information.  */
    529     return FALSE;
    530 
    531   if (stabsec->size % STABSIZE != 0)
    532     /* Something is wrong with the format of these stab symbols.
    533        Don't try to optimize them.  */
    534     return FALSE;
    535 
    536   if ((stabsec->output_section != NULL
    537        && bfd_is_abs_section (stabsec->output_section)))
    538     /* At least one of the sections is being discarded from the
    539        link, so we should just ignore them.  */
    540     return FALSE;
    541 
    542   /* We should have initialized our data in _bfd_link_section_stabs.
    543      If there was some bizarre error reading the string sections, though,
    544      we might not have.  Bail rather than asserting.  */
    545   if (psecinfo == NULL)
    546     return FALSE;
    547 
    548   count = stabsec->rawsize / STABSIZE;
    549   secinfo = (struct stab_section_info *) psecinfo;
    550 
    551   /* Read the stabs information from abfd.  */
    552   if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf))
    553     goto error_return;
    554 
    555   /* Look through the stabs symbols and discard any information for
    556      discarded functions.  */
    557   skip = 0;
    558   deleting = -1;
    559 
    560   symend = stabbuf + stabsec->rawsize;
    561   for (sym = stabbuf, pstridx = secinfo->stridxs;
    562        sym < symend;
    563        sym += STABSIZE, ++pstridx)
    564     {
    565       int type;
    566 
    567       if (*pstridx == (bfd_size_type) -1)
    568 	/* This stab was deleted in a previous pass.  */
    569 	continue;
    570 
    571       type = sym[TYPEOFF];
    572 
    573       if (type == (int) N_FUN)
    574 	{
    575 	  int strx = bfd_get_32 (abfd, sym + STRDXOFF);
    576 
    577 	  if (strx == 0)
    578 	    {
    579 	      if (deleting)
    580 		{
    581 		  skip++;
    582 		  *pstridx = -1;
    583 		}
    584 	      deleting = -1;
    585 	      continue;
    586 	    }
    587 	  deleting = 0;
    588 	  if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie))
    589 	    deleting = 1;
    590 	}
    591 
    592       if (deleting == 1)
    593 	{
    594 	  *pstridx = -1;
    595 	  skip++;
    596 	}
    597       else if (deleting == -1)
    598 	{
    599 	  /* Outside of a function.  Check for deleted variables.  */
    600 	  if (type == (int) N_STSYM || type == (int) N_LCSYM)
    601 	    if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie))
    602 	      {
    603 		*pstridx = -1;
    604 		skip ++;
    605 	      }
    606 	  /* We should also check for N_GSYM entries which reference a
    607 	     deleted global, but those are less harmful to debuggers
    608 	     and would require parsing the stab strings.  */
    609 	}
    610     }
    611 
    612   free (stabbuf);
    613   stabbuf = NULL;
    614 
    615   /* Shrink the stabsec as needed.  */
    616   stabsec->size -= skip * STABSIZE;
    617   if (stabsec->size == 0)
    618     stabsec->flags |= SEC_EXCLUDE | SEC_KEEP;
    619 
    620   /* Recalculate the `cumulative_skips' array now that stabs have been
    621      deleted for this section.  */
    622 
    623   if (skip != 0)
    624     {
    625       bfd_size_type i, offset;
    626       bfd_size_type *pskips;
    627 
    628       if (secinfo->cumulative_skips == NULL)
    629 	{
    630 	  amt = count * sizeof (bfd_size_type);
    631 	  secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt);
    632 	  if (secinfo->cumulative_skips == NULL)
    633 	    goto error_return;
    634 	}
    635 
    636       pskips = secinfo->cumulative_skips;
    637       pstridx = secinfo->stridxs;
    638       offset = 0;
    639 
    640       for (i = 0; i < count; i++, pskips++, pstridx++)
    641 	{
    642 	  *pskips = offset;
    643 	  if (*pstridx == (bfd_size_type) -1)
    644 	    offset += STABSIZE;
    645 	}
    646 
    647       BFD_ASSERT (offset != 0);
    648     }
    649 
    650   return skip > 0;
    651 
    652  error_return:
    653   if (stabbuf != NULL)
    654     free (stabbuf);
    655   return FALSE;
    656 }
    657 
    658 /* Write out the stab section.  This is called with the relocated
    659    contents.  */
    660 
    661 bfd_boolean
    662 _bfd_write_section_stabs (bfd *output_bfd,
    663 			  struct stab_info *sinfo,
    664 			  asection *stabsec,
    665 			  void * *psecinfo,
    666 			  bfd_byte *contents)
    667 {
    668   struct stab_section_info *secinfo;
    669   struct stab_excl_list *e;
    670   bfd_byte *sym, *tosym, *symend;
    671   bfd_size_type *pstridx;
    672 
    673   secinfo = (struct stab_section_info *) *psecinfo;
    674 
    675   if (secinfo == NULL)
    676     return bfd_set_section_contents (output_bfd, stabsec->output_section,
    677 				     contents, stabsec->output_offset,
    678 				     stabsec->size);
    679 
    680   /* Handle each N_BINCL entry.  */
    681   for (e = secinfo->excls; e != NULL; e = e->next)
    682     {
    683       bfd_byte *excl_sym;
    684 
    685       BFD_ASSERT (e->offset < stabsec->rawsize);
    686       excl_sym = contents + e->offset;
    687       bfd_put_32 (output_bfd, e->val, excl_sym + VALOFF);
    688       excl_sym[TYPEOFF] = e->type;
    689     }
    690 
    691   /* Copy over all the stabs symbols, omitting the ones we don't want,
    692      and correcting the string indices for those we do want.  */
    693   tosym = contents;
    694   symend = contents + stabsec->rawsize;
    695   for (sym = contents, pstridx = secinfo->stridxs;
    696        sym < symend;
    697        sym += STABSIZE, ++pstridx)
    698     {
    699       if (*pstridx != (bfd_size_type) -1)
    700 	{
    701 	  if (tosym != sym)
    702 	    memcpy (tosym, sym, STABSIZE);
    703 	  bfd_put_32 (output_bfd, *pstridx, tosym + STRDXOFF);
    704 
    705 	  if (sym[TYPEOFF] == 0)
    706 	    {
    707 	      /* This is the header symbol for the stabs section.  We
    708 		 don't really need one, since we have merged all the
    709 		 input stabs sections into one, but we generate one
    710 		 for the benefit of readers which expect to see one.  */
    711 	      BFD_ASSERT (sym == contents);
    712 	      bfd_put_32 (output_bfd, _bfd_stringtab_size (sinfo->strings),
    713 			  tosym + VALOFF);
    714 	      bfd_put_16 (output_bfd,
    715 			  stabsec->output_section->size / STABSIZE - 1,
    716 			  tosym + DESCOFF);
    717 	    }
    718 
    719 	  tosym += STABSIZE;
    720 	}
    721     }
    722 
    723   BFD_ASSERT ((bfd_size_type) (tosym - contents) == stabsec->size);
    724 
    725   return bfd_set_section_contents (output_bfd, stabsec->output_section,
    726 				   contents, (file_ptr) stabsec->output_offset,
    727 				   stabsec->size);
    728 }
    729 
    730 /* Write out the .stabstr section.  */
    731 
    732 bfd_boolean
    733 _bfd_write_stab_strings (bfd *output_bfd, struct stab_info *sinfo)
    734 {
    735   if (bfd_is_abs_section (sinfo->stabstr->output_section))
    736     /* The section was discarded from the link.  */
    737     return TRUE;
    738 
    739   BFD_ASSERT ((sinfo->stabstr->output_offset
    740 	       + _bfd_stringtab_size (sinfo->strings))
    741 	      <= sinfo->stabstr->output_section->size);
    742 
    743   if (bfd_seek (output_bfd,
    744 		(file_ptr) (sinfo->stabstr->output_section->filepos
    745 			    + sinfo->stabstr->output_offset),
    746 		SEEK_SET) != 0)
    747     return FALSE;
    748 
    749   if (! _bfd_stringtab_emit (output_bfd, sinfo->strings))
    750     return FALSE;
    751 
    752   /* We no longer need the stabs information.  */
    753   _bfd_stringtab_free (sinfo->strings);
    754   bfd_hash_table_free (&sinfo->includes);
    755 
    756   return TRUE;
    757 }
    758 
    759 /* Adjust an address in the .stab section.  Given OFFSET within
    760    STABSEC, this returns the new offset in the adjusted stab section,
    761    or -1 if the address refers to a stab which has been removed.  */
    762 
    763 bfd_vma
    764 _bfd_stab_section_offset (asection *stabsec,
    765 			  void * psecinfo,
    766 			  bfd_vma offset)
    767 {
    768   struct stab_section_info *secinfo;
    769 
    770   secinfo = (struct stab_section_info *) psecinfo;
    771 
    772   if (secinfo == NULL)
    773     return offset;
    774 
    775   if (offset >= stabsec->rawsize)
    776     return offset - stabsec->rawsize + stabsec->size;
    777 
    778   if (secinfo->cumulative_skips)
    779     {
    780       bfd_vma i;
    781 
    782       i = offset / STABSIZE;
    783 
    784       if (secinfo->stridxs [i] == (bfd_size_type) -1)
    785 	return (bfd_vma) -1;
    786 
    787       return offset - secinfo->cumulative_skips [i];
    788     }
    789 
    790   return offset;
    791 }
    792