+ 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.
+*/
+
+bfd_boolean
+_bfd_discard_section_stabs (bfd *abfd,
+ asection *stabsec,
+ void * psecinfo,
+ bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *),
+ void * 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->size == 0)
+ /* This file does not contain stabs debugging information. */
+ return FALSE;
+
+ if (stabsec->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_section_stabs.
+ 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->rawsize / STABSIZE;
+ secinfo = (struct stab_section_info *) psecinfo;
+
+ /* Read the stabs information from abfd. */
+ if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf))
+ goto error_return;
+
+ /* Look through the stabs symbols and discard any information for
+ discarded functions. */
+ skip = 0;
+ deleting = -1;
+
+ symend = stabbuf + stabsec->rawsize;
+ 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->size -= skip * STABSIZE;
+ if (stabsec->size == 0)
+ stabsec->flags |= SEC_EXCLUDE | SEC_KEEP;
+
+ /* 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 skip > 0;
+
+ error_return:
+ if (stabbuf != NULL)
+ free (stabbuf);
+ return FALSE;