171671b9obrien/* Routines to link ECOFF debugging information.
20acbbeedim   Copyright 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3d0f678fdim   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
471671b9obrien   Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
571671b9obrien
671671b9obrien   This file is part of BFD, the Binary File Descriptor library.
771671b9obrien
871671b9obrien   This program is free software; you can redistribute it and/or modify
971671b9obrien   it under the terms of the GNU General Public License as published by
1071671b9obrien   the Free Software Foundation; either version 2 of the License, or
1171671b9obrien   (at your option) any later version.
1271671b9obrien
1371671b9obrien   This program is distributed in the hope that it will be useful,
1471671b9obrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1571671b9obrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1671671b9obrien   GNU General Public License for more details.
1771671b9obrien
1871671b9obrien   You should have received a copy of the GNU General Public License
1971671b9obrien   along with this program; if not, write to the Free Software
200acbbeedim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2171671b9obrien
2271671b9obrien#include "sysdep.h"
23d0f678fdim#include "bfd.h"
2471671b9obrien#include "bfdlink.h"
2571671b9obrien#include "libbfd.h"
2671671b9obrien#include "objalloc.h"
2771671b9obrien#include "aout/stab_gnu.h"
2871671b9obrien#include "coff/internal.h"
2971671b9obrien#include "coff/sym.h"
3071671b9obrien#include "coff/symconst.h"
3171671b9obrien#include "coff/ecoff.h"
3271671b9obrien#include "libcoff.h"
3371671b9obrien#include "libecoff.h"
3471671b9obrien
3571671b9obrienstatic bfd_boolean ecoff_add_bytes
3671671b9obrien  PARAMS ((char **buf, char **bufend, size_t need));
3771671b9obrienstatic struct bfd_hash_entry *string_hash_newfunc
3871671b9obrien  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
3971671b9obrien	   const char *));
4071671b9obrienstatic void ecoff_align_debug
4171671b9obrien  PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
4271671b9obrien	   const struct ecoff_debug_swap *swap));
4371671b9obrienstatic bfd_boolean ecoff_write_symhdr
4471671b9obrien  PARAMS ((bfd *, struct ecoff_debug_info *, const struct ecoff_debug_swap *,
4571671b9obrien	   file_ptr where));
4671671b9obrienstatic int cmp_fdrtab_entry
4771671b9obrien  PARAMS ((const PTR, const PTR));
4871671b9obrienstatic bfd_boolean mk_fdrtab
4971671b9obrien  PARAMS ((bfd *, struct ecoff_debug_info * const,
5071671b9obrien	   const struct ecoff_debug_swap * const, struct ecoff_find_line *));
5171671b9obrienstatic long fdrtab_lookup
5271671b9obrien  PARAMS ((struct ecoff_find_line *, bfd_vma));
5371671b9obrienstatic bfd_boolean lookup_line
5471671b9obrien  PARAMS ((bfd *, struct ecoff_debug_info * const,
5571671b9obrien	   const struct ecoff_debug_swap * const, struct ecoff_find_line *));
5671671b9obrien
5771671b9obrien/* Routines to swap auxiliary information in and out.  I am assuming
5871671b9obrien   that the auxiliary information format is always going to be target
5971671b9obrien   independent.  */
6071671b9obrien
6171671b9obrien/* Swap in a type information record.
6271671b9obrien   BIGEND says whether AUX symbols are big-endian or little-endian; this
6371671b9obrien   info comes from the file header record (fh-fBigendian).  */
6471671b9obrien
6571671b9obrienvoid
6671671b9obrien_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
6771671b9obrien     int bigend;
6871671b9obrien     const struct tir_ext *ext_copy;
6971671b9obrien     TIR *intern;
7071671b9obrien{
7171671b9obrien  struct tir_ext ext[1];
7271671b9obrien
7371671b9obrien  *ext = *ext_copy;		/* Make it reasonable to do in-place.  */
7471671b9obrien
7571671b9obrien  /* now the fun stuff...  */
7671671b9obrien  if (bigend) {
7771671b9obrien    intern->fBitfield   = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG);
7871671b9obrien    intern->continued   = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG);
7971671b9obrien    intern->bt          = (ext->t_bits1[0] & TIR_BITS1_BT_BIG)
8071671b9obrien			>>		    TIR_BITS1_BT_SH_BIG;
8171671b9obrien    intern->tq4         = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG)
8271671b9obrien			>>		    TIR_BITS_TQ4_SH_BIG;
8371671b9obrien    intern->tq5         = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG)
8471671b9obrien			>>		    TIR_BITS_TQ5_SH_BIG;
8571671b9obrien    intern->tq0         = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG)
8671671b9obrien			>>		    TIR_BITS_TQ0_SH_BIG;
8771671b9obrien    intern->tq1         = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG)
8871671b9obrien			>>		    TIR_BITS_TQ1_SH_BIG;
8971671b9obrien    intern->tq2         = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG)
9071671b9obrien			>>		    TIR_BITS_TQ2_SH_BIG;
9171671b9obrien    intern->tq3         = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG)
9271671b9obrien			>>		    TIR_BITS_TQ3_SH_BIG;
9371671b9obrien  } else {
9471671b9obrien    intern->fBitfield   = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE);
9571671b9obrien    intern->continued   = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE);
9671671b9obrien    intern->bt          = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE)
9771671b9obrien			>>		    TIR_BITS1_BT_SH_LITTLE;
9871671b9obrien    intern->tq4         = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE)
9971671b9obrien			>>		    TIR_BITS_TQ4_SH_LITTLE;
10071671b9obrien    intern->tq5         = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE)
10171671b9obrien			>>		    TIR_BITS_TQ5_SH_LITTLE;
10271671b9obrien    intern->tq0         = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE)
10371671b9obrien			>>		    TIR_BITS_TQ0_SH_LITTLE;
10471671b9obrien    intern->tq1         = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE)
10571671b9obrien			>>		    TIR_BITS_TQ1_SH_LITTLE;
10671671b9obrien    intern->tq2         = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE)
10771671b9obrien			>>		    TIR_BITS_TQ2_SH_LITTLE;
10871671b9obrien    intern->tq3         = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE)
10971671b9obrien			>>		    TIR_BITS_TQ3_SH_LITTLE;
11071671b9obrien  }
11171671b9obrien
11271671b9obrien#ifdef TEST
11371671b9obrien  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
11471671b9obrien    abort ();
11571671b9obrien#endif
11671671b9obrien}
11771671b9obrien
11871671b9obrien/* Swap out a type information record.
11971671b9obrien   BIGEND says whether AUX symbols are big-endian or little-endian; this
12071671b9obrien   info comes from the file header record (fh-fBigendian).  */
12171671b9obrien
12271671b9obrienvoid
12371671b9obrien_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
12471671b9obrien     int bigend;
12571671b9obrien     const TIR *intern_copy;
12671671b9obrien     struct tir_ext *ext;
12771671b9obrien{
12871671b9obrien  TIR intern[1];
12971671b9obrien
13071671b9obrien  *intern = *intern_copy;	/* Make it reasonable to do in-place.  */
13171671b9obrien
13271671b9obrien  /* now the fun stuff...  */
13371671b9obrien  if (bigend) {
13471671b9obrien    ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0)
13571671b9obrien		       | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0)
13671671b9obrien		       | ((intern->bt << TIR_BITS1_BT_SH_BIG)
13771671b9obrien			  & TIR_BITS1_BT_BIG));
13871671b9obrien    ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG)
13971671b9obrien		       & TIR_BITS_TQ4_BIG)
14071671b9obrien		      | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG)
14171671b9obrien			 & TIR_BITS_TQ5_BIG));
14271671b9obrien    ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG)
14371671b9obrien		       & TIR_BITS_TQ0_BIG)
14471671b9obrien		      | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG)
14571671b9obrien			 & TIR_BITS_TQ1_BIG));
14671671b9obrien    ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG)
14771671b9obrien		       & TIR_BITS_TQ2_BIG)
14871671b9obrien		      | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG)
14971671b9obrien			 & TIR_BITS_TQ3_BIG));
15071671b9obrien  } else {
15171671b9obrien    ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0)
15271671b9obrien		       | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0)
15371671b9obrien		       | ((intern->bt << TIR_BITS1_BT_SH_LITTLE)
15471671b9obrien			  & TIR_BITS1_BT_LITTLE));
15571671b9obrien    ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE)
15671671b9obrien		       & TIR_BITS_TQ4_LITTLE)
15771671b9obrien		      | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE)
15871671b9obrien			 & TIR_BITS_TQ5_LITTLE));
15971671b9obrien    ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE)
16071671b9obrien		       & TIR_BITS_TQ0_LITTLE)
16171671b9obrien		      | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE)
16271671b9obrien			 & TIR_BITS_TQ1_LITTLE));
16371671b9obrien    ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE)
16471671b9obrien		       & TIR_BITS_TQ2_LITTLE)
16571671b9obrien		      | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE)
16671671b9obrien			 & TIR_BITS_TQ3_LITTLE));
16771671b9obrien  }
16871671b9obrien
16971671b9obrien#ifdef TEST
17071671b9obrien  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
17171671b9obrien    abort ();
17271671b9obrien#endif
17371671b9obrien}
17471671b9obrien
17571671b9obrien/* Swap in a relative symbol record.  BIGEND says whether it is in
17671671b9obrien   big-endian or little-endian format.*/
17771671b9obrien
17871671b9obrienvoid
17971671b9obrien_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
18071671b9obrien     int bigend;
18171671b9obrien     const struct rndx_ext *ext_copy;
18271671b9obrien     RNDXR *intern;
18371671b9obrien{
18471671b9obrien  struct rndx_ext ext[1];
18571671b9obrien
18671671b9obrien  *ext = *ext_copy;		/* Make it reasonable to do in-place.  */
18771671b9obrien
18871671b9obrien  /* now the fun stuff...  */
18971671b9obrien  if (bigend) {
19071671b9obrien    intern->rfd   = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG)
19171671b9obrien		  | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG)
19271671b9obrien		    		    >> RNDX_BITS1_RFD_SH_BIG);
19371671b9obrien    intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG)
19471671b9obrien		    		    << RNDX_BITS1_INDEX_SH_LEFT_BIG)
19571671b9obrien		  | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG)
19671671b9obrien		  | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG);
19771671b9obrien  } else {
19871671b9obrien    intern->rfd   = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE)
19971671b9obrien		  | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE)
20071671b9obrien		    		    << RNDX_BITS1_RFD_SH_LEFT_LITTLE);
20171671b9obrien    intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE)
20271671b9obrien		    		    >> RNDX_BITS1_INDEX_SH_LITTLE)
20371671b9obrien		  | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE)
20471671b9obrien		  | ((unsigned int) ext->r_bits[3]
20571671b9obrien		     << RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
20671671b9obrien  }
20771671b9obrien
20871671b9obrien#ifdef TEST
20971671b9obrien  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
21071671b9obrien    abort ();
21171671b9obrien#endif
21271671b9obrien}
21371671b9obrien
21471671b9obrien/* Swap out a relative symbol record.  BIGEND says whether it is in
21571671b9obrien   big-endian or little-endian format.*/
21671671b9obrien
21771671b9obrienvoid
21871671b9obrien_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
21971671b9obrien     int bigend;
22071671b9obrien     const RNDXR *intern_copy;
22171671b9obrien     struct rndx_ext *ext;
22271671b9obrien{
22371671b9obrien  RNDXR intern[1];
22471671b9obrien
22571671b9obrien  *intern = *intern_copy;	/* Make it reasonable to do in-place.  */
22671671b9obrien
22771671b9obrien  /* now the fun stuff...  */
22871671b9obrien  if (bigend) {
22971671b9obrien    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG;
23071671b9obrien    ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG)
23171671b9obrien		       & RNDX_BITS1_RFD_BIG)
23271671b9obrien		      | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG)
23371671b9obrien			 & RNDX_BITS1_INDEX_BIG));
23471671b9obrien    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG;
23571671b9obrien    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG;
23671671b9obrien  } else {
23771671b9obrien    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE;
23871671b9obrien    ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE)
23971671b9obrien		       & RNDX_BITS1_RFD_LITTLE)
24071671b9obrien		      | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE)
24171671b9obrien			 & RNDX_BITS1_INDEX_LITTLE));
24271671b9obrien    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE;
24371671b9obrien    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE;
24471671b9obrien  }
24571671b9obrien
24671671b9obrien#ifdef TEST
24771671b9obrien  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
24871671b9obrien    abort ();
24971671b9obrien#endif
25071671b9obrien}
25171671b9obrien
25271671b9obrien/* The minimum amount of data to allocate.  */
25371671b9obrien#define ALLOC_SIZE (4064)
25471671b9obrien
25571671b9obrien/* Add bytes to a buffer.  Return success.  */
25671671b9obrien
25771671b9obrienstatic bfd_boolean
25871671b9obrienecoff_add_bytes (buf, bufend, need)
25971671b9obrien     char **buf;
26071671b9obrien     char **bufend;
26171671b9obrien     size_t need;
26271671b9obrien{
26371671b9obrien  size_t have;
26471671b9obrien  size_t want;
26571671b9obrien  char *newbuf;
26671671b9obrien
26771671b9obrien  have = *bufend - *buf;
26871671b9obrien  if (have > need)
26971671b9obrien    want = ALLOC_SIZE;
27071671b9obrien  else
27171671b9obrien    {
27271671b9obrien      want = need - have;
27371671b9obrien      if (want < ALLOC_SIZE)
27471671b9obrien	want = ALLOC_SIZE;
27571671b9obrien    }
27671671b9obrien  newbuf = (char *) bfd_realloc (*buf, (bfd_size_type) have + want);
27771671b9obrien  if (newbuf == NULL)
27871671b9obrien    return FALSE;
27971671b9obrien  *buf = newbuf;
28071671b9obrien  *bufend = *buf + have + want;
28171671b9obrien  return TRUE;
28271671b9obrien}
28371671b9obrien
28471671b9obrien/* We keep a hash table which maps strings to numbers.  We use it to
28571671b9obrien   map FDR names to indices in the output file, and to map local
28671671b9obrien   strings when combining stabs debugging information.  */
28771671b9obrien
28871671b9obrienstruct string_hash_entry
28971671b9obrien{
29071671b9obrien  struct bfd_hash_entry root;
29171671b9obrien  /* FDR index or string table offset.  */
29271671b9obrien  long val;
29371671b9obrien  /* Next entry in string table.  */
29471671b9obrien  struct string_hash_entry *next;
29571671b9obrien};
29671671b9obrien
29771671b9obrienstruct string_hash_table
29871671b9obrien{
29971671b9obrien  struct bfd_hash_table table;
30071671b9obrien};
30171671b9obrien
30271671b9obrien/* Routine to create an entry in a string hash table.  */
30371671b9obrien
30471671b9obrienstatic struct bfd_hash_entry *
30571671b9obrienstring_hash_newfunc (entry, table, string)
30671671b9obrien     struct bfd_hash_entry *entry;
30771671b9obrien     struct bfd_hash_table *table;
30871671b9obrien     const char *string;
30971671b9obrien{
31071671b9obrien  struct string_hash_entry *ret = (struct string_hash_entry *) entry;
31171671b9obrien
31271671b9obrien  /* Allocate the structure if it has not already been allocated by a
31371671b9obrien     subclass.  */
31471671b9obrien  if (ret == (struct string_hash_entry *) NULL)
31571671b9obrien    ret = ((struct string_hash_entry *)
31671671b9obrien	   bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
31771671b9obrien  if (ret == (struct string_hash_entry *) NULL)
31871671b9obrien    return NULL;
31971671b9obrien
32071671b9obrien  /* Call the allocation method of the superclass.  */
32171671b9obrien  ret = ((struct string_hash_entry *)
32271671b9obrien	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
32371671b9obrien
32471671b9obrien  if (ret)
32571671b9obrien    {
32671671b9obrien      /* Initialize the local fields.  */
32771671b9obrien      ret->val = -1;
32871671b9obrien      ret->next = NULL;
32971671b9obrien    }
33071671b9obrien
33171671b9obrien  return (struct bfd_hash_entry *) ret;
33271671b9obrien}
33371671b9obrien
33471671b9obrien/* Look up an entry in an string hash table.  */
33571671b9obrien
33671671b9obrien#define string_hash_lookup(t, string, create, copy) \
33771671b9obrien  ((struct string_hash_entry *) \
33871671b9obrien   bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
33971671b9obrien
34071671b9obrien/* We can't afford to read in all the debugging information when we do
34171671b9obrien   a link.  Instead, we build a list of these structures to show how
34271671b9obrien   different parts of the input file map to the output file.  */
34371671b9obrien
34471671b9obrienstruct shuffle
34571671b9obrien{
34671671b9obrien  /* The next entry in this linked list.  */
34771671b9obrien  struct shuffle *next;
34871671b9obrien  /* The length of the information.  */
34971671b9obrien  unsigned long size;
35071671b9obrien  /* Whether this information comes from a file or not.  */
35171671b9obrien  bfd_boolean filep;
35271671b9obrien  union
35371671b9obrien    {
35471671b9obrien      struct
35571671b9obrien	{
35671671b9obrien	  /* The BFD the data comes from.  */
35771671b9obrien	  bfd *input_bfd;
35871671b9obrien	  /* The offset within input_bfd.  */
35971671b9obrien	  file_ptr offset;
36071671b9obrien	} file;
36171671b9obrien      /* The data to be written out.  */
36271671b9obrien      PTR memory;
36371671b9obrien    } u;
36471671b9obrien};
36571671b9obrien
36671671b9obrien/* This structure holds information across calls to
36771671b9obrien   bfd_ecoff_debug_accumulate.  */
36871671b9obrien
36971671b9obrienstruct accumulate
37071671b9obrien{
37171671b9obrien  /* The FDR hash table.  */
37271671b9obrien  struct string_hash_table fdr_hash;
37371671b9obrien  /* The strings hash table.  */
37471671b9obrien  struct string_hash_table str_hash;
37571671b9obrien  /* Linked lists describing how to shuffle the input debug
37671671b9obrien     information into the output file.  We keep a pointer to both the
37771671b9obrien     head and the tail.  */
37871671b9obrien  struct shuffle *line;
37971671b9obrien  struct shuffle *line_end;
38071671b9obrien  struct shuffle *pdr;
38171671b9obrien  struct shuffle *pdr_end;
38271671b9obrien  struct shuffle *sym;
38371671b9obrien  struct shuffle *sym_end;
38471671b9obrien  struct shuffle *opt;
38571671b9obrien  struct shuffle *opt_end;
38671671b9obrien  struct shuffle *aux;
38771671b9obrien  struct shuffle *aux_end;
38871671b9obrien  struct shuffle *ss;
38971671b9obrien  struct shuffle *ss_end;
39071671b9obrien  struct string_hash_entry *ss_hash;
39171671b9obrien  struct string_hash_entry *ss_hash_end;
39271671b9obrien  struct shuffle *fdr;
39371671b9obrien  struct shuffle *fdr_end;
39471671b9obrien  struct shuffle *rfd;
39571671b9obrien  struct shuffle *rfd_end;
39671671b9obrien  /* The size of the largest file shuffle.  */
39771671b9obrien  unsigned long largest_file_shuffle;
39871671b9obrien  /* An objalloc for debugging information.  */
39971671b9obrien  struct objalloc *memory;
40071671b9obrien};
40171671b9obrien
40271671b9obrien/* Add a file entry to a shuffle list.  */
40371671b9obrien
40471671b9obrienstatic bfd_boolean add_file_shuffle
40571671b9obrien  PARAMS ((struct accumulate *, struct shuffle **, struct shuffle **,
40671671b9obrien	   bfd *, file_ptr, unsigned long));
40771671b9obrien
40871671b9obrienstatic bfd_boolean
40971671b9obrienadd_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
41071671b9obrien     struct accumulate *ainfo;
41171671b9obrien     struct shuffle **head;
41271671b9obrien     struct shuffle **tail;
41371671b9obrien     bfd *input_bfd;
41471671b9obrien     file_ptr offset;
41571671b9obrien     unsigned long size;
41671671b9obrien{
41771671b9obrien  struct shuffle *n;
41871671b9obrien
41971671b9obrien  if (*tail != (struct shuffle *) NULL
42071671b9obrien      && (*tail)->filep
42171671b9obrien      && (*tail)->u.file.input_bfd == input_bfd
42271671b9obrien      && (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset)
42371671b9obrien    {
42471671b9obrien      /* Just merge this entry onto the existing one.  */
42571671b9obrien      (*tail)->size += size;
42671671b9obrien      if ((*tail)->size > ainfo->largest_file_shuffle)
42771671b9obrien	ainfo->largest_file_shuffle = (*tail)->size;
42871671b9obrien      return TRUE;
42971671b9obrien    }
43071671b9obrien
43171671b9obrien  n = (struct shuffle *) objalloc_alloc (ainfo->memory,
43271671b9obrien					 sizeof (struct shuffle));
43371671b9obrien  if (!n)
43471671b9obrien    {
43571671b9obrien      bfd_set_error (bfd_error_no_memory);
43671671b9obrien      return FALSE;
43771671b9obrien    }
43871671b9obrien  n->next = NULL;
43971671b9obrien  n->size = size;
44071671b9obrien  n->filep = TRUE;
44171671b9obrien  n->u.file.input_bfd = input_bfd;
44271671b9obrien  n->u.file.offset = offset;
44371671b9obrien  if (*head == (struct shuffle *) NULL)
44471671b9obrien    *head = n;
44571671b9obrien  if (*tail != (struct shuffle *) NULL)
44671671b9obrien    (*tail)->next = n;
44771671b9obrien  *tail = n;
44871671b9obrien  if (size > ainfo->largest_file_shuffle)
44971671b9obrien    ainfo->largest_file_shuffle = size;
45071671b9obrien  return TRUE;
45171671b9obrien}
45271671b9obrien
45371671b9obrien/* Add a memory entry to a shuffle list.  */
45471671b9obrien
45571671b9obrienstatic bfd_boolean add_memory_shuffle
45671671b9obrien  PARAMS ((struct accumulate *, struct shuffle **head, struct shuffle **tail,
45771671b9obrien	   bfd_byte *data, unsigned long size));
45871671b9obrien
45971671b9obrienstatic bfd_boolean
46071671b9obrienadd_memory_shuffle (ainfo, head, tail, data, size)
46171671b9obrien     struct accumulate *ainfo;
46271671b9obrien     struct shuffle **head;
46371671b9obrien     struct shuffle **tail;
46471671b9obrien     bfd_byte *data;
46571671b9obrien     unsigned long size;
46671671b9obrien{
46771671b9obrien  struct shuffle *n;
46871671b9obrien
46971671b9obrien  n = (struct shuffle *) objalloc_alloc (ainfo->memory,
47071671b9obrien					 sizeof (struct shuffle));
47171671b9obrien  if (!n)
47271671b9obrien    {
47371671b9obrien      bfd_set_error (bfd_error_no_memory);
47471671b9obrien      return FALSE;
47571671b9obrien    }
47671671b9obrien  n->next = NULL;
47771671b9obrien  n->size = size;
47871671b9obrien  n->filep = FALSE;
47971671b9obrien  n->u.memory = (PTR) data;
48071671b9obrien  if (*head == (struct shuffle *) NULL)
48171671b9obrien    *head = n;
48271671b9obrien  if (*tail != (struct shuffle *) NULL)
48371671b9obrien    (*tail)->next = n;
48471671b9obrien  *tail = n;
48571671b9obrien  return TRUE;
48671671b9obrien}
48771671b9obrien
48871671b9obrien/* Initialize the FDR hash table.  This returns a handle which is then
48971671b9obrien   passed in to bfd_ecoff_debug_accumulate, et. al.  */
49071671b9obrien
49171671b9obrienPTR
49271671b9obrienbfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
49371671b9obrien     bfd *output_bfd ATTRIBUTE_UNUSED;
49471671b9obrien     struct ecoff_debug_info *output_debug;
49571671b9obrien     const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
49671671b9obrien     struct bfd_link_info *info;
49771671b9obrien{
49871671b9obrien  struct accumulate *ainfo;
49971671b9obrien  bfd_size_type amt = sizeof (struct accumulate);
50071671b9obrien
50171671b9obrien  ainfo = (struct accumulate *) bfd_malloc (amt);
50271671b9obrien  if (!ainfo)
50371671b9obrien    return NULL;
5040acbbeedim  if (!bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc,
5050acbbeedim			      sizeof (struct string_hash_entry), 1021))
50671671b9obrien    return NULL;
50771671b9obrien
50871671b9obrien  ainfo->line = NULL;
50971671b9obrien  ainfo->line_end = NULL;
51071671b9obrien  ainfo->pdr = NULL;
51171671b9obrien  ainfo->pdr_end = NULL;
51271671b9obrien  ainfo->sym = NULL;
51371671b9obrien  ainfo->sym_end = NULL;
51471671b9obrien  ainfo->opt = NULL;
51571671b9obrien  ainfo->opt_end = NULL;
51671671b9obrien  ainfo->aux = NULL;
51771671b9obrien  ainfo->aux_end = NULL;
51871671b9obrien  ainfo->ss = NULL;
51971671b9obrien  ainfo->ss_end = NULL;
52071671b9obrien  ainfo->ss_hash = NULL;
52171671b9obrien  ainfo->ss_hash_end = NULL;
52271671b9obrien  ainfo->fdr = NULL;
52371671b9obrien  ainfo->fdr_end = NULL;
52471671b9obrien  ainfo->rfd = NULL;
52571671b9obrien  ainfo->rfd_end = NULL;
52671671b9obrien
52771671b9obrien  ainfo->largest_file_shuffle = 0;
52871671b9obrien
52971671b9obrien  if (! info->relocatable)
53071671b9obrien    {
5310acbbeedim      if (!bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc,
5320acbbeedim				sizeof (struct string_hash_entry)))
53371671b9obrien	return NULL;
53471671b9obrien
53571671b9obrien      /* The first entry in the string table is the empty string.  */
53671671b9obrien      output_debug->symbolic_header.issMax = 1;
53771671b9obrien    }
53871671b9obrien
53971671b9obrien  ainfo->memory = objalloc_create ();
54071671b9obrien  if (ainfo->memory == NULL)
54171671b9obrien    {
54271671b9obrien      bfd_set_error (bfd_error_no_memory);
54371671b9obrien      return NULL;
54471671b9obrien    }
54571671b9obrien
54671671b9obrien  return (PTR) ainfo;
54771671b9obrien}
54871671b9obrien
54971671b9obrien/* Free the accumulated debugging information.  */
55071671b9obrien
55171671b9obrienvoid
55271671b9obrienbfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
55371671b9obrien     PTR handle;
55471671b9obrien     bfd *output_bfd ATTRIBUTE_UNUSED;
55571671b9obrien     struct ecoff_debug_info *output_debug ATTRIBUTE_UNUSED;
55671671b9obrien     const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
55771671b9obrien     struct bfd_link_info *info;
55871671b9obrien{
55971671b9obrien  struct accumulate *ainfo = (struct accumulate *) handle;
56071671b9obrien
56171671b9obrien  bfd_hash_table_free (&ainfo->fdr_hash.table);
56271671b9obrien
56371671b9obrien  if (! info->relocatable)
56471671b9obrien    bfd_hash_table_free (&ainfo->str_hash.table);
56571671b9obrien
56671671b9obrien  objalloc_free (ainfo->memory);
56771671b9obrien
56871671b9obrien  free (ainfo);
56971671b9obrien}
57071671b9obrien
57171671b9obrien/* Accumulate the debugging information from INPUT_BFD into
57271671b9obrien   OUTPUT_BFD.  The INPUT_DEBUG argument points to some ECOFF
57371671b9obrien   debugging information which we want to link into the information
57471671b9obrien   pointed to by the OUTPUT_DEBUG argument.  OUTPUT_SWAP and
57571671b9obrien   INPUT_SWAP point to the swapping information needed.  INFO is the
57671671b9obrien   linker information structure.  HANDLE is returned by
57771671b9obrien   bfd_ecoff_debug_init.  */
57871671b9obrien
57971671b9obrienbfd_boolean
58071671b9obrienbfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
58171671b9obrien			    input_bfd, input_debug, input_swap,
58271671b9obrien			    info)
58371671b9obrien     PTR handle;
58471671b9obrien     bfd *output_bfd;
58571671b9obrien     struct ecoff_debug_info *output_debug;
58671671b9obrien     const struct ecoff_debug_swap *output_swap;
58771671b9obrien     bfd *input_bfd;
58871671b9obrien     struct ecoff_debug_info *input_debug;
58971671b9obrien     const struct ecoff_debug_swap *input_swap;
59071671b9obrien     struct bfd_link_info *info;
59171671b9obrien{
59271671b9obrien  struct accumulate *ainfo = (struct accumulate *) handle;
59371671b9obrien  void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
59471671b9obrien    = input_swap->swap_sym_in;
59571671b9obrien  void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
59671671b9obrien    = input_swap->swap_rfd_in;
59771671b9obrien  void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
59871671b9obrien    = output_swap->swap_sym_out;
59971671b9obrien  void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR))
60071671b9obrien    = output_swap->swap_fdr_out;
60171671b9obrien  void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR))
60271671b9obrien    = output_swap->swap_rfd_out;
60371671b9obrien  bfd_size_type external_pdr_size = output_swap->external_pdr_size;
60471671b9obrien  bfd_size_type external_sym_size = output_swap->external_sym_size;
60571671b9obrien  bfd_size_type external_opt_size = output_swap->external_opt_size;
60671671b9obrien  bfd_size_type external_fdr_size = output_swap->external_fdr_size;
60771671b9obrien  bfd_size_type external_rfd_size = output_swap->external_rfd_size;
60871671b9obrien  HDRR * const output_symhdr = &output_debug->symbolic_header;
60971671b9obrien  HDRR * const input_symhdr = &input_debug->symbolic_header;
61071671b9obrien  bfd_vma section_adjust[scMax];
61171671b9obrien  asection *sec;
61271671b9obrien  bfd_byte *fdr_start;
61371671b9obrien  bfd_byte *fdr_ptr;
61471671b9obrien  bfd_byte *fdr_end;
61571671b9obrien  bfd_size_type fdr_add;
61671671b9obrien  unsigned int copied;
61771671b9obrien  RFDT i;
61871671b9obrien  unsigned long sz;
61971671b9obrien  bfd_byte *rfd_out;
62071671b9obrien  bfd_byte *rfd_in;
62171671b9obrien  bfd_byte *rfd_end;
62271671b9obrien  long newrfdbase = 0;
62371671b9obrien  long oldrfdbase = 0;
62471671b9obrien  bfd_byte *fdr_out;
62571671b9obrien  bfd_size_type amt;
62671671b9obrien
62771671b9obrien  /* Use section_adjust to hold the value to add to a symbol in a
62871671b9obrien     particular section.  */
62971671b9obrien  memset ((PTR) section_adjust, 0, sizeof section_adjust);
63071671b9obrien
63171671b9obrien#define SET(name, indx) \
63271671b9obrien  sec = bfd_get_section_by_name (input_bfd, name); \
63371671b9obrien  if (sec != NULL) \
63471671b9obrien    section_adjust[indx] = (sec->output_section->vma \
63571671b9obrien			    + sec->output_offset \
63671671b9obrien			    - sec->vma);
63771671b9obrien
63871671b9obrien  SET (".text", scText);
63971671b9obrien  SET (".data", scData);
64071671b9obrien  SET (".bss", scBss);
64171671b9obrien  SET (".sdata", scSData);
64271671b9obrien  SET (".sbss", scSBss);
64371671b9obrien  /* scRdata section may be either .rdata or .rodata.  */
64471671b9obrien  SET (".rdata", scRData);
64571671b9obrien  SET (".rodata", scRData);
64671671b9obrien  SET (".init", scInit);
64771671b9obrien  SET (".fini", scFini);
64871671b9obrien  SET (".rconst", scRConst);
64971671b9obrien
65071671b9obrien#undef SET
65171671b9obrien
65271671b9obrien  /* Find all the debugging information based on the FDR's.  We need
65371671b9obrien     to handle them whether they are swapped or not.  */
65471671b9obrien  if (input_debug->fdr != (FDR *) NULL)
65571671b9obrien    {
65671671b9obrien      fdr_start = (bfd_byte *) input_debug->fdr;
65771671b9obrien      fdr_add = sizeof (FDR);
65871671b9obrien    }
65971671b9obrien  else
66071671b9obrien    {
66171671b9obrien      fdr_start = (bfd_byte *) input_debug->external_fdr;
66271671b9obrien      fdr_add = input_swap->external_fdr_size;
66371671b9obrien    }
66471671b9obrien  fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add;
66571671b9obrien
66671671b9obrien  amt = input_symhdr->ifdMax;
66771671b9obrien  amt *= sizeof (RFDT);
66871671b9obrien  input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, amt);
66971671b9obrien
67071671b9obrien  sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size;
67171671b9obrien  rfd_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
67271671b9obrien  if (!input_debug->ifdmap || !rfd_out)
67371671b9obrien    {
67471671b9obrien      bfd_set_error (bfd_error_no_memory);
67571671b9obrien      return FALSE;
67671671b9obrien    }
67771671b9obrien  if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz))
67871671b9obrien    return FALSE;
67971671b9obrien
68071671b9obrien  copied = 0;
68171671b9obrien
68271671b9obrien  /* Look through the FDR's to see which ones we are going to include
68371671b9obrien     in the final output.  We do not want duplicate FDR information
68471671b9obrien     for header files, because ECOFF debugging is often very large.
68571671b9obrien     When we find an FDR with no line information which can be merged,
68671671b9obrien     we look it up in a hash table to ensure that we only include it
68771671b9obrien     once.  We keep a table mapping FDR numbers to the final number
68871671b9obrien     they get with the BFD, so that we can refer to it when we write
68971671b9obrien     out the external symbols.  */
69071671b9obrien  for (fdr_ptr = fdr_start, i = 0;
69171671b9obrien       fdr_ptr < fdr_end;
69271671b9obrien       fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size)
69371671b9obrien    {
69471671b9obrien      FDR fdr;
69571671b9obrien
69671671b9obrien      if (input_debug->fdr != (FDR *) NULL)
69771671b9obrien	fdr = *(FDR *) fdr_ptr;
69871671b9obrien      else
69971671b9obrien	(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
70071671b9obrien
70171671b9obrien      /* See if this FDR can be merged with an existing one.  */
70271671b9obrien      if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge)
70371671b9obrien	{
70471671b9obrien	  const char *name;
70571671b9obrien	  char *lookup;
70671671b9obrien	  struct string_hash_entry *fh;
70771671b9obrien
70871671b9obrien	  /* We look up a string formed from the file name and the
70971671b9obrien	     number of symbols and aux entries.  Sometimes an include
71071671b9obrien	     file will conditionally define a typedef or something
71171671b9obrien	     based on the order of include files.  Using the number of
71271671b9obrien	     symbols and aux entries as a hash reduces the chance that
71371671b9obrien	     we will merge symbol information that should not be
71471671b9obrien	     merged.  */
71571671b9obrien	  name = input_debug->ss + fdr.issBase + fdr.rss;
71671671b9obrien
71771671b9obrien	  lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20);
71871671b9obrien	  if (lookup == NULL)
71971671b9obrien	    return FALSE;
72071671b9obrien	  sprintf (lookup, "%s %lx %lx", name, fdr.csym, fdr.caux);
72171671b9obrien
72271671b9obrien	  fh = string_hash_lookup (&ainfo->fdr_hash, lookup, TRUE, TRUE);
72371671b9obrien	  free (lookup);
72471671b9obrien	  if (fh == (struct string_hash_entry *) NULL)
72571671b9obrien	    return FALSE;
72671671b9obrien
72771671b9obrien	  if (fh->val != -1)
72871671b9obrien	    {
72971671b9obrien	      input_debug->ifdmap[i] = fh->val;
73071671b9obrien	      (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i,
73171671b9obrien			       (PTR) rfd_out);
73271671b9obrien
73371671b9obrien	      /* Don't copy this FDR.  */
73471671b9obrien	      continue;
73571671b9obrien	    }
73671671b9obrien
73771671b9obrien	  fh->val = output_symhdr->ifdMax + copied;
73871671b9obrien	}
73971671b9obrien
74071671b9obrien      input_debug->ifdmap[i] = output_symhdr->ifdMax + copied;
74171671b9obrien      (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out);
74271671b9obrien      ++copied;
74371671b9obrien    }
74471671b9obrien
74571671b9obrien  newrfdbase = output_symhdr->crfd;
74671671b9obrien  output_symhdr->crfd += input_symhdr->ifdMax;
74771671b9obrien
74871671b9obrien  /* Copy over any existing RFD's.  RFD's are only created by the
74971671b9obrien     linker, so this will only happen for input files which are the
75071671b9obrien     result of a partial link.  */
75171671b9obrien  rfd_in = (bfd_byte *) input_debug->external_rfd;
75271671b9obrien  rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size;
75371671b9obrien  for (;
75471671b9obrien       rfd_in < rfd_end;
75571671b9obrien       rfd_in += input_swap->external_rfd_size)
75671671b9obrien    {
75771671b9obrien      RFDT rfd;
75871671b9obrien
75971671b9obrien      (*swap_rfd_in) (input_bfd, (PTR) rfd_in, &rfd);
76071671b9obrien      BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax);
76171671b9obrien      rfd = input_debug->ifdmap[rfd];
76271671b9obrien      (*swap_rfd_out) (output_bfd, &rfd, (PTR) rfd_out);
76371671b9obrien      rfd_out += external_rfd_size;
76471671b9obrien    }
76571671b9obrien
76671671b9obrien  oldrfdbase = output_symhdr->crfd;
76771671b9obrien  output_symhdr->crfd += input_symhdr->crfd;
76871671b9obrien
76971671b9obrien  /* Look through the FDR's and copy over all associated debugging
77071671b9obrien     information.  */
77171671b9obrien  sz = copied * external_fdr_size;
77271671b9obrien  fdr_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
77371671b9obrien  if (!fdr_out)
77471671b9obrien    {
77571671b9obrien      bfd_set_error (bfd_error_no_memory);
77671671b9obrien      return FALSE;
77771671b9obrien    }
77871671b9obrien  if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz))
77971671b9obrien    return FALSE;
78071671b9obrien  for (fdr_ptr = fdr_start, i = 0;
78171671b9obrien       fdr_ptr < fdr_end;
78271671b9obrien       fdr_ptr += fdr_add, i++)
78371671b9obrien    {
78471671b9obrien      FDR fdr;
78571671b9obrien      bfd_byte *sym_out;
78671671b9obrien      bfd_byte *lraw_src;
78771671b9obrien      bfd_byte *lraw_end;
78871671b9obrien      bfd_boolean fgotfilename;
78971671b9obrien
79071671b9obrien      if (input_debug->ifdmap[i] < output_symhdr->ifdMax)
79171671b9obrien	{
79271671b9obrien	  /* We are not copying this FDR.  */
79371671b9obrien	  continue;
79471671b9obrien	}
79571671b9obrien
79671671b9obrien      if (input_debug->fdr != (FDR *) NULL)
79771671b9obrien	fdr = *(FDR *) fdr_ptr;
79871671b9obrien      else
79971671b9obrien	(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
80071671b9obrien
80171671b9obrien      /* FIXME: It is conceivable that this FDR points to the .init or
80271671b9obrien	 .fini section, in which case this will not do the right
80371671b9obrien	 thing.  */
80471671b9obrien      fdr.adr += section_adjust[scText];
80571671b9obrien
80671671b9obrien      /* Swap in the local symbols, adjust their values, and swap them
80771671b9obrien	 out again.  */
80871671b9obrien      fgotfilename = FALSE;
80971671b9obrien      sz = fdr.csym * external_sym_size;
81071671b9obrien      sym_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
81171671b9obrien      if (!sym_out)
81271671b9obrien	{
81371671b9obrien	  bfd_set_error (bfd_error_no_memory);
81471671b9obrien	  return FALSE;
81571671b9obrien	}
81671671b9obrien      if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out,
81771671b9obrien			       sz))
81871671b9obrien	return FALSE;
81971671b9obrien      lraw_src = ((bfd_byte *) input_debug->external_sym
82071671b9obrien		  + fdr.isymBase * input_swap->external_sym_size);
82171671b9obrien      lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size;
82271671b9obrien      for (;  lraw_src < lraw_end;  lraw_src += input_swap->external_sym_size)
82371671b9obrien	{
82471671b9obrien	  SYMR internal_sym;
82571671b9obrien
82671671b9obrien	  (*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym);
82771671b9obrien
82871671b9obrien	  BFD_ASSERT (internal_sym.sc != scCommon
82971671b9obrien		      && internal_sym.sc != scSCommon);
83071671b9obrien
83171671b9obrien	  /* Adjust the symbol value if appropriate.  */
83271671b9obrien	  switch (internal_sym.st)
83371671b9obrien	    {
83471671b9obrien	    case stNil:
83571671b9obrien	      if (ECOFF_IS_STAB (&internal_sym))
83671671b9obrien		break;
83771671b9obrien	      /* Fall through.  */
83871671b9obrien	    case stGlobal:
83971671b9obrien	    case stStatic:
84071671b9obrien	    case stLabel:
84171671b9obrien	    case stProc:
84271671b9obrien	    case stStaticProc:
84371671b9obrien	      internal_sym.value += section_adjust[internal_sym.sc];
84471671b9obrien	      break;
84571671b9obrien
84671671b9obrien	    default:
84771671b9obrien	      break;
84871671b9obrien	    }
84971671b9obrien
85071671b9obrien	  /* If we are doing a final link, we hash all the strings in
85171671b9obrien	     the local symbol table together.  This reduces the amount
85271671b9obrien	     of space required by debugging information.  We don't do
85371671b9obrien	     this when performing a relocatable link because it would
85471671b9obrien	     prevent us from easily merging different FDR's.  */
85571671b9obrien	  if (! info->relocatable)
85671671b9obrien	    {
85771671b9obrien	      bfd_boolean ffilename;
85871671b9obrien	      const char *name;
85971671b9obrien
86071671b9obrien	      if (! fgotfilename && internal_sym.iss == fdr.rss)
86171671b9obrien		ffilename = TRUE;
86271671b9obrien	      else
86371671b9obrien		ffilename = FALSE;
86471671b9obrien
86571671b9obrien	      /* Hash the name into the string table.  */
86671671b9obrien	      name = input_debug->ss + fdr.issBase + internal_sym.iss;
86771671b9obrien	      if (*name == '\0')
86871671b9obrien		internal_sym.iss = 0;
86971671b9obrien	      else
87071671b9obrien		{
87171671b9obrien		  struct string_hash_entry *sh;
87271671b9obrien
87371671b9obrien		  sh = string_hash_lookup (&ainfo->str_hash, name, TRUE, TRUE);
87471671b9obrien		  if (sh == (struct string_hash_entry *) NULL)
87571671b9obrien		    return FALSE;
87671671b9obrien		  if (sh->val == -1)
87771671b9obrien		    {
87871671b9obrien		      sh->val = output_symhdr->issMax;
87971671b9obrien		      output_symhdr->issMax += strlen (name) + 1;
88071671b9obrien		      if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
88171671b9obrien			ainfo->ss_hash = sh;
88271671b9obrien		      if (ainfo->ss_hash_end
88371671b9obrien			  != (struct string_hash_entry *) NULL)
88471671b9obrien			ainfo->ss_hash_end->next = sh;
88571671b9obrien		      ainfo->ss_hash_end = sh;
88671671b9obrien		    }
88771671b9obrien		  internal_sym.iss = sh->val;
88871671b9obrien		}
88971671b9obrien
89071671b9obrien	      if (ffilename)
89171671b9obrien		{
89271671b9obrien		  fdr.rss = internal_sym.iss;
89371671b9obrien		  fgotfilename = TRUE;
89471671b9obrien		}
89571671b9obrien	    }
89671671b9obrien
89771671b9obrien	  (*swap_sym_out) (output_bfd, &internal_sym, sym_out);
89871671b9obrien	  sym_out += external_sym_size;
89971671b9obrien	}
90071671b9obrien
90171671b9obrien      fdr.isymBase = output_symhdr->isymMax;
90271671b9obrien      output_symhdr->isymMax += fdr.csym;
90371671b9obrien
90471671b9obrien      /* Copy the information that does not need swapping.  */
90571671b9obrien
90671671b9obrien      /* FIXME: If we are relaxing, we need to adjust the line
90771671b9obrien	 numbers.  Frankly, forget it.  Anybody using stabs debugging
90871671b9obrien	 information will not use this line number information, and
90971671b9obrien	 stabs are adjusted correctly.  */
91071671b9obrien      if (fdr.cbLine > 0)
91171671b9obrien	{
91271671b9obrien	  file_ptr pos = input_symhdr->cbLineOffset + fdr.cbLineOffset;
91371671b9obrien	  if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end,
91471671b9obrien				 input_bfd, pos, (unsigned long) fdr.cbLine))
91571671b9obrien	    return FALSE;
91671671b9obrien	  fdr.ilineBase = output_symhdr->ilineMax;
91771671b9obrien	  fdr.cbLineOffset = output_symhdr->cbLine;
91871671b9obrien	  output_symhdr->ilineMax += fdr.cline;
91971671b9obrien	  output_symhdr->cbLine += fdr.cbLine;
92071671b9obrien	}
92171671b9obrien      if (fdr.caux > 0)
92271671b9obrien	{
92371671b9obrien	  file_ptr pos = (input_symhdr->cbAuxOffset
92471671b9obrien			  + fdr.iauxBase * sizeof (union aux_ext));
92571671b9obrien	  if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end,
92671671b9obrien				 input_bfd, pos,
92771671b9obrien				 fdr.caux * sizeof (union aux_ext)))
92871671b9obrien	    return FALSE;
92971671b9obrien	  fdr.iauxBase = output_symhdr->iauxMax;
93071671b9obrien	  output_symhdr->iauxMax += fdr.caux;
93171671b9obrien	}
93271671b9obrien      if (! info->relocatable)
93371671b9obrien	{
93471671b9obrien
93571671b9obrien	  /* When are are hashing strings, we lie about the number of
93671671b9obrien	     strings attached to each FDR.  We need to set cbSs
93771671b9obrien	     because some versions of dbx apparently use it to decide
93871671b9obrien	     how much of the string table to read in.  */
93971671b9obrien	  fdr.issBase = 0;
94071671b9obrien	  fdr.cbSs = output_symhdr->issMax;
94171671b9obrien	}
94271671b9obrien      else if (fdr.cbSs > 0)
94371671b9obrien	{
94471671b9obrien	  file_ptr pos = input_symhdr->cbSsOffset + fdr.issBase;
94571671b9obrien	  if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end,
94671671b9obrien				 input_bfd, pos, (unsigned long) fdr.cbSs))
94771671b9obrien	    return FALSE;
94871671b9obrien	  fdr.issBase = output_symhdr->issMax;
94971671b9obrien	  output_symhdr->issMax += fdr.cbSs;
95071671b9obrien	}
95171671b9obrien
9520acbbeedim      if (output_bfd->xvec->header_byteorder
9530acbbeedim	  == input_bfd->xvec->header_byteorder)
95471671b9obrien	{
95571671b9obrien	  /* The two BFD's have the same endianness, and we don't have
95671671b9obrien	     to adjust the PDR addresses, so simply copying the
95771671b9obrien	     information will suffice.  */
95871671b9obrien	  BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size);
95971671b9obrien	  if (fdr.cpd > 0)
96071671b9obrien	    {
96171671b9obrien	      file_ptr pos = (input_symhdr->cbPdOffset
96271671b9obrien			      + fdr.ipdFirst * external_pdr_size);
96371671b9obrien	      unsigned long size = fdr.cpd * external_pdr_size;
96471671b9obrien	      if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end,
96571671b9obrien				     input_bfd, pos, size))
96671671b9obrien		return FALSE;
96771671b9obrien	    }
96871671b9obrien	  BFD_ASSERT (external_opt_size == input_swap->external_opt_size);
96971671b9obrien	  if (fdr.copt > 0)
97071671b9obrien	    {
97171671b9obrien	      file_ptr pos = (input_symhdr->cbOptOffset
97271671b9obrien			      + fdr.ioptBase * external_opt_size);
97371671b9obrien	      unsigned long size = fdr.copt * external_opt_size;
97471671b9obrien	      if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end,
97571671b9obrien				     input_bfd, pos, size))
97671671b9obrien		return FALSE;
97771671b9obrien	    }
97871671b9obrien	}
97971671b9obrien      else
98071671b9obrien	{
98171671b9obrien	  bfd_size_type outsz, insz;
98271671b9obrien	  bfd_byte *in;
98371671b9obrien	  bfd_byte *end;
98471671b9obrien	  bfd_byte *out;
98571671b9obrien
98671671b9obrien	  /* The two BFD's have different endianness, so we must swap
98771671b9obrien	     everything in and out.  This code would always work, but
98871671b9obrien	     it would be unnecessarily slow in the normal case.  */
98971671b9obrien	  outsz = external_pdr_size;
99071671b9obrien	  insz = input_swap->external_pdr_size;
99171671b9obrien	  in = ((bfd_byte *) input_debug->external_pdr
99271671b9obrien		+ fdr.ipdFirst * insz);
99371671b9obrien	  end = in + fdr.cpd * insz;
99471671b9obrien	  sz = fdr.cpd * outsz;
99571671b9obrien	  out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
99671671b9obrien	  if (!out)
99771671b9obrien	    {
99871671b9obrien	      bfd_set_error (bfd_error_no_memory);
99971671b9obrien	      return FALSE;
100071671b9obrien	    }
100171671b9obrien	  if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out,
100271671b9obrien				   sz))
100371671b9obrien	    return FALSE;
100471671b9obrien	  for (; in < end; in += insz, out += outsz)
100571671b9obrien	    {
100671671b9obrien	      PDR pdr;
100771671b9obrien
100871671b9obrien	      (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr);
100971671b9obrien	      (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out);
101071671b9obrien	    }
101171671b9obrien
101271671b9obrien	  /* Swap over the optimization information.  */
101371671b9obrien	  outsz = external_opt_size;
101471671b9obrien	  insz = input_swap->external_opt_size;
101571671b9obrien	  in = ((bfd_byte *) input_debug->external_opt
101671671b9obrien		+ fdr.ioptBase * insz);
101771671b9obrien	  end = in + fdr.copt * insz;
101871671b9obrien	  sz = fdr.copt * outsz;
101971671b9obrien	  out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
102071671b9obrien	  if (!out)
102171671b9obrien	    {
102271671b9obrien	      bfd_set_error (bfd_error_no_memory);
102371671b9obrien	      return FALSE;
102471671b9obrien	    }
102571671b9obrien	  if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out,
102671671b9obrien				   sz))
102771671b9obrien	    return FALSE;
102871671b9obrien	  for (; in < end; in += insz, out += outsz)
102971671b9obrien	    {
103071671b9obrien	      OPTR opt;
103171671b9obrien
103271671b9obrien	      (*input_swap->swap_opt_in) (input_bfd, (PTR) in, &opt);
103371671b9obrien	      (*output_swap->swap_opt_out) (output_bfd, &opt, (PTR) out);
103471671b9obrien	    }
103571671b9obrien	}
103671671b9obrien
103771671b9obrien      fdr.ipdFirst = output_symhdr->ipdMax;
103871671b9obrien      output_symhdr->ipdMax += fdr.cpd;
103971671b9obrien      fdr.ioptBase = output_symhdr->ioptMax;
104071671b9obrien      output_symhdr->ioptMax += fdr.copt;
104171671b9obrien
104271671b9obrien      if (fdr.crfd <= 0)
104371671b9obrien	{
104471671b9obrien	  /* Point this FDR at the table of RFD's we created.  */
104571671b9obrien	  fdr.rfdBase = newrfdbase;
104671671b9obrien	  fdr.crfd = input_symhdr->ifdMax;
104771671b9obrien	}
104871671b9obrien      else
104971671b9obrien	{
105071671b9obrien	  /* Point this FDR at the remapped RFD's.  */
105171671b9obrien	  fdr.rfdBase += oldrfdbase;
105271671b9obrien	}
105371671b9obrien
105471671b9obrien      (*swap_fdr_out) (output_bfd, &fdr, fdr_out);
105571671b9obrien      fdr_out += external_fdr_size;
105671671b9obrien      ++output_symhdr->ifdMax;
105771671b9obrien    }
105871671b9obrien
105971671b9obrien  return TRUE;
106071671b9obrien}
106171671b9obrien
106271671b9obrien/* Add a string to the debugging information we are accumulating.
106371671b9obrien   Return the offset from the fdr string base.  */
106471671b9obrien
106571671b9obrienstatic long ecoff_add_string
106671671b9obrien  PARAMS ((struct accumulate *, struct bfd_link_info *,
106771671b9obrien	   struct ecoff_debug_info *, FDR *fdr, const char *string));
106871671b9obrien
106971671b9obrienstatic long
107071671b9obrienecoff_add_string (ainfo, info, debug, fdr, string)
107171671b9obrien     struct accumulate *ainfo;
107271671b9obrien     struct bfd_link_info *info;
107371671b9obrien     struct ecoff_debug_info *debug;
107471671b9obrien     FDR *fdr;
107571671b9obrien     const char *string;
107671671b9obrien{
107771671b9obrien  HDRR *symhdr;
107871671b9obrien  size_t len;
107971671b9obrien  bfd_size_type ret;
108071671b9obrien
108171671b9obrien  symhdr = &debug->symbolic_header;
108271671b9obrien  len = strlen (string);
108371671b9obrien  if (info->relocatable)
108471671b9obrien    {
108571671b9obrien      if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string,
108671671b9obrien			       len + 1))
108771671b9obrien	return -1;
108871671b9obrien      ret = symhdr->issMax;
108971671b9obrien      symhdr->issMax += len + 1;
109071671b9obrien      fdr->cbSs += len + 1;
109171671b9obrien    }
109271671b9obrien  else
109371671b9obrien    {
109471671b9obrien      struct string_hash_entry *sh;
109571671b9obrien
109671671b9obrien      sh = string_hash_lookup (&ainfo->str_hash, string, TRUE, TRUE);
109771671b9obrien      if (sh == (struct string_hash_entry *) NULL)
109871671b9obrien	return -1;
109971671b9obrien      if (sh->val == -1)
110071671b9obrien	{
110171671b9obrien	  sh->val = symhdr->issMax;
110271671b9obrien	  symhdr->issMax += len + 1;
110371671b9obrien	  if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
110471671b9obrien	    ainfo->ss_hash = sh;
110571671b9obrien	  if (ainfo->ss_hash_end
110671671b9obrien	      != (struct string_hash_entry *) NULL)
110771671b9obrien	    ainfo->ss_hash_end->next = sh;
110871671b9obrien	  ainfo->ss_hash_end = sh;
110971671b9obrien	}
111071671b9obrien      ret = sh->val;
111171671b9obrien    }
111271671b9obrien
111371671b9obrien  return ret;
111471671b9obrien}
111571671b9obrien
111671671b9obrien/* Add debugging information from a non-ECOFF file.  */
111771671b9obrien
111871671b9obrienbfd_boolean
111971671b9obrienbfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
112071671b9obrien				  output_swap, input_bfd, info)
112171671b9obrien     PTR handle;
112271671b9obrien     bfd *output_bfd;
112371671b9obrien     struct ecoff_debug_info *output_debug;
112471671b9obrien     const struct ecoff_debug_swap *output_swap;
112571671b9obrien     bfd *input_bfd;
112671671b9obrien     struct bfd_link_info *info;
112771671b9obrien{
112871671b9obrien  struct accumulate *ainfo = (struct accumulate *) handle;
112971671b9obrien  void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
113071671b9obrien    = output_swap->swap_sym_out;
113171671b9obrien  HDRR *output_symhdr = &output_debug->symbolic_header;
113271671b9obrien  FDR fdr;
113371671b9obrien  asection *sec;
113471671b9obrien  asymbol **symbols;
113571671b9obrien  asymbol **sym_ptr;
113671671b9obrien  asymbol **sym_end;
113771671b9obrien  long symsize;
113871671b9obrien  long symcount;
113971671b9obrien  PTR external_fdr;
114071671b9obrien
114171671b9obrien  memset ((PTR) &fdr, 0, sizeof fdr);
114271671b9obrien
114371671b9obrien  sec = bfd_get_section_by_name (input_bfd, ".text");
114471671b9obrien  if (sec != NULL)
114571671b9obrien    fdr.adr = sec->output_section->vma + sec->output_offset;
114671671b9obrien  else
114771671b9obrien    {
114871671b9obrien      /* FIXME: What about .init or .fini?  */
114971671b9obrien      fdr.adr = 0;
115071671b9obrien    }
115171671b9obrien
115271671b9obrien  fdr.issBase = output_symhdr->issMax;
115371671b9obrien  fdr.cbSs = 0;
115471671b9obrien  fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr,
11550acbbeedim			      input_bfd->filename);
115671671b9obrien  if (fdr.rss == -1)
115771671b9obrien    return FALSE;
115871671b9obrien  fdr.isymBase = output_symhdr->isymMax;
115971671b9obrien
116071671b9obrien  /* Get the local symbols from the input BFD.  */
116171671b9obrien  symsize = bfd_get_symtab_upper_bound (input_bfd);
116271671b9obrien  if (symsize < 0)
116371671b9obrien    return FALSE;
116471671b9obrien  symbols = (asymbol **) bfd_alloc (output_bfd, (bfd_size_type) symsize);
116571671b9obrien  if (symbols == (asymbol **) NULL)
116671671b9obrien    return FALSE;
116771671b9obrien  symcount = bfd_canonicalize_symtab (input_bfd, symbols);
116871671b9obrien  if (symcount < 0)
116971671b9obrien    return FALSE;
117071671b9obrien  sym_end = symbols + symcount;
117171671b9obrien
117271671b9obrien  /* Handle the local symbols.  Any external symbols are handled
117371671b9obrien     separately.  */
117471671b9obrien  fdr.csym = 0;
117571671b9obrien  for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
117671671b9obrien    {
117771671b9obrien      SYMR internal_sym;
117871671b9obrien      PTR external_sym;
117971671b9obrien
118071671b9obrien      if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
118171671b9obrien	continue;
118271671b9obrien      memset ((PTR) &internal_sym, 0, sizeof internal_sym);
118371671b9obrien      internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr,
118471671b9obrien					   (*sym_ptr)->name);
118571671b9obrien
118671671b9obrien      if (internal_sym.iss == -1)
118771671b9obrien	return FALSE;
118871671b9obrien      if (bfd_is_com_section ((*sym_ptr)->section)
118971671b9obrien	  || bfd_is_und_section ((*sym_ptr)->section))
119071671b9obrien	internal_sym.value = (*sym_ptr)->value;
119171671b9obrien      else
119271671b9obrien	internal_sym.value = ((*sym_ptr)->value
119371671b9obrien			      + (*sym_ptr)->section->output_offset
119471671b9obrien			      + (*sym_ptr)->section->output_section->vma);
119571671b9obrien      internal_sym.st = stNil;
119671671b9obrien      internal_sym.sc = scUndefined;
119771671b9obrien      internal_sym.index = indexNil;
119871671b9obrien
119971671b9obrien      external_sym = (PTR) objalloc_alloc (ainfo->memory,
120071671b9obrien					   output_swap->external_sym_size);
120171671b9obrien      if (!external_sym)
120271671b9obrien	{
120371671b9obrien	  bfd_set_error (bfd_error_no_memory);
120471671b9obrien	  return FALSE;
120571671b9obrien	}
120671671b9obrien      (*swap_sym_out) (output_bfd, &internal_sym, external_sym);
120771671b9obrien      add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end,
120871671b9obrien			  external_sym,
120971671b9obrien			  (unsigned long) output_swap->external_sym_size);
121071671b9obrien      ++fdr.csym;
121171671b9obrien      ++output_symhdr->isymMax;
121271671b9obrien    }
121371671b9obrien
121471671b9obrien  bfd_release (output_bfd, (PTR) symbols);
121571671b9obrien
121671671b9obrien  /* Leave everything else in the FDR zeroed out.  This will cause
121771671b9obrien     the lang field to be langC.  The fBigendian field will
121871671b9obrien     indicate little endian format, but it doesn't matter because
121971671b9obrien     it only applies to aux fields and there are none.  */
122071671b9obrien  external_fdr = (PTR) objalloc_alloc (ainfo->memory,
122171671b9obrien				       output_swap->external_fdr_size);
122271671b9obrien  if (!external_fdr)
122371671b9obrien    {
122471671b9obrien      bfd_set_error (bfd_error_no_memory);
122571671b9obrien      return FALSE;
122671671b9obrien    }
122771671b9obrien  (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr);
122871671b9obrien  add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end,
122971671b9obrien		      external_fdr,
123071671b9obrien		      (unsigned long) output_swap->external_fdr_size);
123171671b9obrien
123271671b9obrien  ++output_symhdr->ifdMax;
123371671b9obrien
123471671b9obrien  return TRUE;
123571671b9obrien}
123671671b9obrien
123771671b9obrien/* Set up ECOFF debugging information for the external symbols.
123871671b9obrien   FIXME: This is done using a memory buffer, but it should be
123971671b9obrien   probably be changed to use a shuffle structure.  The assembler uses
124071671b9obrien   this interface, so that must be changed to do something else.  */
124171671b9obrien
124271671b9obrienbfd_boolean
124371671b9obrienbfd_ecoff_debug_externals (abfd, debug, swap, relocatable, get_extr,
124471671b9obrien			   set_index)
124571671b9obrien     bfd *abfd;
124671671b9obrien     struct ecoff_debug_info *debug;
124771671b9obrien     const struct ecoff_debug_swap *swap;
124871671b9obrien     bfd_boolean relocatable;
124971671b9obrien     bfd_boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
125071671b9obrien     void (*set_index) PARAMS ((asymbol *, bfd_size_type));
125171671b9obrien{
125271671b9obrien  HDRR * const symhdr = &debug->symbolic_header;
125371671b9obrien  asymbol **sym_ptr_ptr;
125471671b9obrien  size_t c;
125571671b9obrien
125671671b9obrien  sym_ptr_ptr = bfd_get_outsymbols (abfd);
125771671b9obrien  if (sym_ptr_ptr == NULL)
125871671b9obrien    return TRUE;
125971671b9obrien
126071671b9obrien  for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++)
126171671b9obrien    {
126271671b9obrien      asymbol *sym_ptr;
126371671b9obrien      EXTR esym;
126471671b9obrien
126571671b9obrien      sym_ptr = *sym_ptr_ptr;
126671671b9obrien
126771671b9obrien      /* Get the external symbol information.  */
126871671b9obrien      if (! (*get_extr) (sym_ptr, &esym))
126971671b9obrien	continue;
127071671b9obrien
127171671b9obrien      /* If we're producing an executable, move common symbols into
127271671b9obrien	 bss.  */
127371671b9obrien      if (! relocatable)
127471671b9obrien	{
127571671b9obrien	  if (esym.asym.sc == scCommon)
127671671b9obrien	    esym.asym.sc = scBss;
127771671b9obrien	  else if (esym.asym.sc == scSCommon)
127871671b9obrien	    esym.asym.sc = scSBss;
127971671b9obrien	}
128071671b9obrien
128171671b9obrien      if (bfd_is_com_section (sym_ptr->section)
128271671b9obrien	  || bfd_is_und_section (sym_ptr->section)
128371671b9obrien	  || sym_ptr->section->output_section == (asection *) NULL)
128471671b9obrien	{
128571671b9obrien	  /* FIXME: gas does not keep the value of a small undefined
128671671b9obrien	     symbol in the symbol itself, because of relocation
128771671b9obrien	     problems.  */
128871671b9obrien	  if (esym.asym.sc != scSUndefined
128971671b9obrien	      || esym.asym.value == 0
129071671b9obrien	      || sym_ptr->value != 0)
129171671b9obrien	    esym.asym.value = sym_ptr->value;
129271671b9obrien	}
129371671b9obrien      else
129471671b9obrien	esym.asym.value = (sym_ptr->value
129571671b9obrien			   + sym_ptr->section->output_offset
129671671b9obrien			   + sym_ptr->section->output_section->vma);
129771671b9obrien
129871671b9obrien      if (set_index)
129971671b9obrien	(*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax);
130071671b9obrien
130171671b9obrien      if (! bfd_ecoff_debug_one_external (abfd, debug, swap,
130271671b9obrien					  sym_ptr->name, &esym))
130371671b9obrien	return FALSE;
130471671b9obrien    }
130571671b9obrien
130671671b9obrien  return TRUE;
130771671b9obrien}
130871671b9obrien
130971671b9obrien/* Add a single external symbol to the debugging information.  */
131071671b9obrien
131171671b9obrienbfd_boolean
131271671b9obrienbfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
131371671b9obrien     bfd *abfd;
131471671b9obrien     struct ecoff_debug_info *debug;
131571671b9obrien     const struct ecoff_debug_swap *swap;
131671671b9obrien     const char *name;
131771671b9obrien     EXTR *esym;
131871671b9obrien{
131971671b9obrien  const bfd_size_type external_ext_size = swap->external_ext_size;
132071671b9obrien  void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR))
132171671b9obrien    = swap->swap_ext_out;
132271671b9obrien  HDRR * const symhdr = &debug->symbolic_header;
132371671b9obrien  size_t namelen;
132471671b9obrien
132571671b9obrien  namelen = strlen (name);
132671671b9obrien
132771671b9obrien  if ((size_t) (debug->ssext_end - debug->ssext)
132871671b9obrien      < symhdr->issExtMax + namelen + 1)
132971671b9obrien    {
133071671b9obrien      if (! ecoff_add_bytes ((char **) &debug->ssext,
133171671b9obrien			     (char **) &debug->ssext_end,
133271671b9obrien			     symhdr->issExtMax + namelen + 1))
133371671b9obrien	return FALSE;
133471671b9obrien    }
133571671b9obrien  if ((size_t) ((char *) debug->external_ext_end
133671671b9obrien		- (char *) debug->external_ext)
133771671b9obrien      < (symhdr->iextMax + 1) * external_ext_size)
133871671b9obrien    {
13390acbbeedim      char *external_ext = debug->external_ext;
13400acbbeedim      char *external_ext_end = debug->external_ext_end;
13410acbbeedim      if (! ecoff_add_bytes ((char **) &external_ext,
13420acbbeedim			     (char **) &external_ext_end,
134371671b9obrien			     (symhdr->iextMax + 1) * (size_t) external_ext_size))
134471671b9obrien	return FALSE;
13450acbbeedim      debug->external_ext = external_ext;
13460acbbeedim      debug->external_ext_end = external_ext_end;
134771671b9obrien    }
134871671b9obrien
134971671b9obrien  esym->asym.iss = symhdr->issExtMax;
135071671b9obrien
135171671b9obrien  (*swap_ext_out) (abfd, esym,
135271671b9obrien		   ((char *) debug->external_ext
135371671b9obrien		    + symhdr->iextMax * swap->external_ext_size));
135471671b9obrien
135571671b9obrien  ++symhdr->iextMax;
135671671b9obrien
135771671b9obrien  strcpy (debug->ssext + symhdr->issExtMax, name);
135871671b9obrien  symhdr->issExtMax += namelen + 1;
135971671b9obrien
136071671b9obrien  return TRUE;
136171671b9obrien}
136271671b9obrien
136371671b9obrien/* Align the ECOFF debugging information.  */
136471671b9obrien
136571671b9obrienstatic void
136671671b9obrienecoff_align_debug (abfd, debug, swap)
136771671b9obrien     bfd *abfd ATTRIBUTE_UNUSED;
136871671b9obrien     struct ecoff_debug_info *debug;
136971671b9obrien     const struct ecoff_debug_swap *swap;
137071671b9obrien{
137171671b9obrien  HDRR * const symhdr = &debug->symbolic_header;
137271671b9obrien  bfd_size_type debug_align, aux_align, rfd_align;
137371671b9obrien  size_t add;
137471671b9obrien
137571671b9obrien  /* Adjust the counts so that structures are aligned.  */
137671671b9obrien  debug_align = swap->debug_align;
137771671b9obrien  aux_align = debug_align / sizeof (union aux_ext);
137871671b9obrien  rfd_align = debug_align / swap->external_rfd_size;
137971671b9obrien
138071671b9obrien  add = debug_align - (symhdr->cbLine & (debug_align - 1));
138171671b9obrien  if (add != debug_align)
138271671b9obrien    {
138371671b9obrien      if (debug->line != (unsigned char *) NULL)
138471671b9obrien	memset ((PTR) (debug->line + symhdr->cbLine), 0, add);
138571671b9obrien      symhdr->cbLine += add;
138671671b9obrien    }
138771671b9obrien
138871671b9obrien  add = debug_align - (symhdr->issMax & (debug_align - 1));
138971671b9obrien  if (add != debug_align)
139071671b9obrien    {
139171671b9obrien      if (debug->ss != (char *) NULL)
139271671b9obrien	memset ((PTR) (debug->ss + symhdr->issMax), 0, add);
139371671b9obrien      symhdr->issMax += add;
139471671b9obrien    }
139571671b9obrien
139671671b9obrien  add = debug_align - (symhdr->issExtMax & (debug_align - 1));
139771671b9obrien  if (add != debug_align)
139871671b9obrien    {
139971671b9obrien      if (debug->ssext != (char *) NULL)
140071671b9obrien	memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add);
140171671b9obrien      symhdr->issExtMax += add;
140271671b9obrien    }
140371671b9obrien
140471671b9obrien  add = aux_align - (symhdr->iauxMax & (aux_align - 1));
140571671b9obrien  if (add != aux_align)
140671671b9obrien    {
140771671b9obrien      if (debug->external_aux != (union aux_ext *) NULL)
140871671b9obrien	memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0,
140971671b9obrien		add * sizeof (union aux_ext));
141071671b9obrien      symhdr->iauxMax += add;
141171671b9obrien    }
141271671b9obrien
141371671b9obrien  add = rfd_align - (symhdr->crfd & (rfd_align - 1));
141471671b9obrien  if (add != rfd_align)
141571671b9obrien    {
141671671b9obrien      if (debug->external_rfd != (PTR) NULL)
141771671b9obrien	memset ((PTR) ((char *) debug->external_rfd
141871671b9obrien		       + symhdr->crfd * swap->external_rfd_size),
141971671b9obrien		0, (size_t) (add * swap->external_rfd_size));
142071671b9obrien      symhdr->crfd += add;
142171671b9obrien    }
142271671b9obrien}
142371671b9obrien
142471671b9obrien/* Return the size required by the ECOFF debugging information.  */
142571671b9obrien
142671671b9obrienbfd_size_type
142771671b9obrienbfd_ecoff_debug_size (abfd, debug, swap)
142871671b9obrien     bfd *abfd;
142971671b9obrien     struct ecoff_debug_info *debug;
143071671b9obrien     const struct ecoff_debug_swap *swap;
143171671b9obrien{
143271671b9obrien  bfd_size_type tot;
143371671b9obrien
143471671b9obrien  ecoff_align_debug (abfd, debug, swap);
143571671b9obrien  tot = swap->external_hdr_size;
143671671b9obrien
143771671b9obrien#define ADD(count, size) \
143871671b9obrien  tot += debug->symbolic_header.count * size
143971671b9obrien
144071671b9obrien  ADD (cbLine, sizeof (unsigned char));
144171671b9obrien  ADD (idnMax, swap->external_dnr_size);
144271671b9obrien  ADD (ipdMax, swap->external_pdr_size);
144371671b9obrien  ADD (isymMax, swap->external_sym_size);
144471671b9obrien  ADD (ioptMax, swap->external_opt_size);
144571671b9obrien  ADD (iauxMax, sizeof (union aux_ext));
144671671b9obrien  ADD (issMax, sizeof (char));
144771671b9obrien  ADD (issExtMax, sizeof (char));
144871671b9obrien  ADD (ifdMax, swap->external_fdr_size);
144971671b9obrien  ADD (crfd, swap->external_rfd_size);
145071671b9obrien  ADD (iextMax, swap->external_ext_size);
145171671b9obrien
145271671b9obrien#undef ADD
145371671b9obrien
145471671b9obrien  return tot;
145571671b9obrien}
145671671b9obrien
145771671b9obrien/* Write out the ECOFF symbolic header, given the file position it is
145871671b9obrien   going to be placed at.  This assumes that the counts are set
145971671b9obrien   correctly.  */
146071671b9obrien
146171671b9obrienstatic bfd_boolean
146271671b9obrienecoff_write_symhdr (abfd, debug, swap, where)
146371671b9obrien     bfd *abfd;
146471671b9obrien     struct ecoff_debug_info *debug;
146571671b9obrien     const struct ecoff_debug_swap *swap;
146671671b9obrien     file_ptr where;
146771671b9obrien{
146871671b9obrien  HDRR * const symhdr = &debug->symbolic_header;
146971671b9obrien  char *buff = NULL;
147071671b9obrien
147171671b9obrien  ecoff_align_debug (abfd, debug, swap);
147271671b9obrien
147371671b9obrien  /* Go to the right location in the file.  */
147471671b9obrien  if (bfd_seek (abfd, where, SEEK_SET) != 0)
147571671b9obrien    return FALSE;
147671671b9obrien
147771671b9obrien  where += swap->external_hdr_size;
147871671b9obrien
147971671b9obrien  symhdr->magic = swap->sym_magic;
148071671b9obrien
148171671b9obrien  /* Fill in the file offsets.  */
148271671b9obrien#define SET(offset, count, size) \
148371671b9obrien  if (symhdr->count == 0) \
148471671b9obrien    symhdr->offset = 0; \
148571671b9obrien  else \
148671671b9obrien    { \
148771671b9obrien      symhdr->offset = where; \
148871671b9obrien      where += symhdr->count * size; \
148971671b9obrien    }
149071671b9obrien
149171671b9obrien  SET (cbLineOffset, cbLine, sizeof (unsigned char));
149271671b9obrien  SET (cbDnOffset, idnMax, swap->external_dnr_size);
149371671b9obrien  SET (cbPdOffset, ipdMax, swap->external_pdr_size);
149471671b9obrien  SET (cbSymOffset, isymMax, swap->external_sym_size);
149571671b9obrien  SET (cbOptOffset, ioptMax, swap->external_opt_size);
149671671b9obrien  SET (cbAuxOffset, iauxMax, sizeof (union aux_ext));
149771671b9obrien  SET (cbSsOffset, issMax, sizeof (char));
149871671b9obrien  SET (cbSsExtOffset, issExtMax, sizeof (char));
149971671b9obrien  SET (cbFdOffset, ifdMax, swap->external_fdr_size);
150071671b9obrien  SET (cbRfdOffset, crfd, swap->external_rfd_size);
150171671b9obrien  SET (cbExtOffset, iextMax, swap->external_ext_size);
150271671b9obrien#undef SET
150371671b9obrien
150471671b9obrien  buff = (PTR) bfd_malloc (swap->external_hdr_size);
150571671b9obrien  if (buff == NULL && swap->external_hdr_size != 0)
150671671b9obrien    goto error_return;
150771671b9obrien
150871671b9obrien  (*swap->swap_hdr_out) (abfd, symhdr, buff);
150971671b9obrien  if (bfd_bwrite (buff, swap->external_hdr_size, abfd)
151071671b9obrien      != swap->external_hdr_size)
151171671b9obrien    goto error_return;
151271671b9obrien
151371671b9obrien  if (buff != NULL)
151471671b9obrien    free (buff);
151571671b9obrien  return TRUE;
151671671b9obrien error_return:
151771671b9obrien  if (buff != NULL)
151871671b9obrien    free (buff);
151971671b9obrien  return FALSE;
152071671b9obrien}
152171671b9obrien
152271671b9obrien/* Write out the ECOFF debugging information.  This function assumes
152371671b9obrien   that the information (the pointers and counts) in *DEBUG have been
152471671b9obrien   set correctly.  WHERE is the position in the file to write the
152571671b9obrien   information to.  This function fills in the file offsets in the
152671671b9obrien   symbolic header.  */
152771671b9obrien
152871671b9obrienbfd_boolean
152971671b9obrienbfd_ecoff_write_debug (abfd, debug, swap, where)
153071671b9obrien     bfd *abfd;
153171671b9obrien     struct ecoff_debug_info *debug;
153271671b9obrien     const struct ecoff_debug_swap *swap;
153371671b9obrien     file_ptr where;
153471671b9obrien{
153571671b9obrien  HDRR * const symhdr = &debug->symbolic_header;
153671671b9obrien
153771671b9obrien  if (! ecoff_write_symhdr (abfd, debug, swap, where))
153871671b9obrien    return FALSE;
153971671b9obrien
154071671b9obrien#define WRITE(ptr, count, size, offset) \
154171671b9obrien  BFD_ASSERT (symhdr->offset == 0 \
154271671b9obrien	      || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \
154371671b9obrien  if (bfd_bwrite ((PTR) debug->ptr, (bfd_size_type) size * symhdr->count, abfd)\
154471671b9obrien      != size * symhdr->count) \
154571671b9obrien    return FALSE;
154671671b9obrien
154771671b9obrien  WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset);
154871671b9obrien  WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset);
154971671b9obrien  WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset);
155071671b9obrien  WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset);
155171671b9obrien  WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset);
155271671b9obrien  WRITE (external_aux, iauxMax, (bfd_size_type) sizeof (union aux_ext),
155371671b9obrien	 cbAuxOffset);
155471671b9obrien  WRITE (ss, issMax, sizeof (char), cbSsOffset);
155571671b9obrien  WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset);
155671671b9obrien  WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset);
155771671b9obrien  WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset);
155871671b9obrien  WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset);
155971671b9obrien#undef WRITE
156071671b9obrien
156171671b9obrien  return TRUE;
156271671b9obrien}
156371671b9obrien
156471671b9obrien/* Write out a shuffle list.  */
156571671b9obrien
156671671b9obrienstatic bfd_boolean ecoff_write_shuffle
156771671b9obrien  PARAMS ((bfd *, const struct ecoff_debug_swap *, struct shuffle *,
156871671b9obrien	   PTR space));
156971671b9obrien
157071671b9obrienstatic bfd_boolean
157171671b9obrienecoff_write_shuffle (abfd, swap, shuffle, space)
157271671b9obrien     bfd *abfd;
157371671b9obrien     const struct ecoff_debug_swap *swap;
157471671b9obrien     struct shuffle *shuffle;
157571671b9obrien     PTR space;
157671671b9obrien{
157771671b9obrien  register struct shuffle *l;
157871671b9obrien  unsigned long total;
157971671b9obrien
158071671b9obrien  total = 0;
158171671b9obrien  for (l = shuffle; l != (struct shuffle *) NULL; l = l->next)
158271671b9obrien    {
158371671b9obrien      if (! l->filep)
158471671b9obrien	{
158571671b9obrien	  if (bfd_bwrite (l->u.memory, (bfd_size_type) l->size, abfd)
158671671b9obrien	      != l->size)
158771671b9obrien	    return FALSE;
158871671b9obrien	}
158971671b9obrien      else
159071671b9obrien	{
159171671b9obrien	  if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
159271671b9obrien	      || bfd_bread (space, (bfd_size_type) l->size,
159371671b9obrien			   l->u.file.input_bfd) != l->size
159471671b9obrien	      || bfd_bwrite (space, (bfd_size_type) l->size, abfd) != l->size)
159571671b9obrien	    return FALSE;
159671671b9obrien	}
159771671b9obrien      total += l->size;
159871671b9obrien    }
159971671b9obrien
160071671b9obrien  if ((total & (swap->debug_align - 1)) != 0)
160171671b9obrien    {
160271671b9obrien      unsigned int i;
160371671b9obrien      bfd_byte *s;
160471671b9obrien
160571671b9obrien      i = swap->debug_align - (total & (swap->debug_align - 1));
160671671b9obrien      s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
160771671b9obrien      if (s == NULL && i != 0)
160871671b9obrien	return FALSE;
160971671b9obrien
161071671b9obrien      if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
161171671b9obrien	{
161271671b9obrien	  free (s);
161371671b9obrien	  return FALSE;
161471671b9obrien	}
161571671b9obrien      free (s);
161671671b9obrien    }
161771671b9obrien
161871671b9obrien  return TRUE;
161971671b9obrien}
162071671b9obrien
162171671b9obrien/* Write out debugging information using accumulated linker
162271671b9obrien   information.  */
162371671b9obrien
162471671b9obrienbfd_boolean
162571671b9obrienbfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
162671671b9obrien     PTR handle;
162771671b9obrien     bfd *abfd;
162871671b9obrien     struct ecoff_debug_info *debug;
162971671b9obrien     const struct ecoff_debug_swap *swap;
163071671b9obrien     struct bfd_link_info *info;
163171671b9obrien     file_ptr where;
163271671b9obrien{
163371671b9obrien  struct accumulate *ainfo = (struct accumulate *) handle;
163471671b9obrien  PTR space = NULL;
163571671b9obrien  bfd_size_type amt;
163671671b9obrien
163771671b9obrien  if (! ecoff_write_symhdr (abfd, debug, swap, where))
163871671b9obrien    goto error_return;
163971671b9obrien
164071671b9obrien  amt = ainfo->largest_file_shuffle;
164171671b9obrien  space = (PTR) bfd_malloc (amt);
164271671b9obrien  if (space == NULL && ainfo->largest_file_shuffle != 0)
164371671b9obrien    goto error_return;
164471671b9obrien
164571671b9obrien  if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
164671671b9obrien      || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
164771671b9obrien      || ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
164871671b9obrien      || ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
164971671b9obrien      || ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
165071671b9obrien    goto error_return;
165171671b9obrien
165271671b9obrien  /* The string table is written out from the hash table if this is a
165371671b9obrien     final link.  */
165471671b9obrien  if (info->relocatable)
165571671b9obrien    {
165671671b9obrien      BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
165771671b9obrien      if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
165871671b9obrien	goto error_return;
165971671b9obrien    }
166071671b9obrien  else
166171671b9obrien    {
166271671b9obrien      unsigned long total;
166371671b9obrien      bfd_byte null;
166471671b9obrien      struct string_hash_entry *sh;
166571671b9obrien
166671671b9obrien      BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
166771671b9obrien      null = 0;
166871671b9obrien      if (bfd_bwrite ((PTR) &null, (bfd_size_type) 1, abfd) != 1)
166971671b9obrien	goto error_return;
167071671b9obrien      total = 1;
167171671b9obrien      BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
167271671b9obrien      for (sh = ainfo->ss_hash;
167371671b9obrien	   sh != (struct string_hash_entry *) NULL;
167471671b9obrien	   sh = sh->next)
167571671b9obrien	{
167671671b9obrien	  size_t len;
167771671b9obrien
167871671b9obrien	  len = strlen (sh->root.string);
167971671b9obrien	  amt = len + 1;
168071671b9obrien	  if (bfd_bwrite ((PTR) sh->root.string, amt, abfd) != amt)
168171671b9obrien	    goto error_return;
168271671b9obrien	  total += len + 1;
168371671b9obrien	}
168471671b9obrien
168571671b9obrien      if ((total & (swap->debug_align - 1)) != 0)
168671671b9obrien	{
168771671b9obrien	  unsigned int i;
168871671b9obrien	  bfd_byte *s;
168971671b9obrien
169071671b9obrien	  i = swap->debug_align - (total & (swap->debug_align - 1));
169171671b9obrien	  s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
169271671b9obrien	  if (s == NULL && i != 0)
169371671b9obrien	    goto error_return;
169471671b9obrien
169571671b9obrien	  if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
169671671b9obrien	    {
169771671b9obrien	      free (s);
169871671b9obrien	      goto error_return;
169971671b9obrien	    }
170071671b9obrien	  free (s);
170171671b9obrien	}
170271671b9obrien    }
170371671b9obrien
170471671b9obrien  /* The external strings and symbol are not converted over to using
170571671b9obrien     shuffles.  FIXME: They probably should be.  */
170671671b9obrien  amt = debug->symbolic_header.issExtMax;
170771671b9obrien  if (bfd_bwrite (debug->ssext, amt, abfd) != amt)
170871671b9obrien    goto error_return;
170971671b9obrien  if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0)
171071671b9obrien    {
171171671b9obrien      unsigned int i;
171271671b9obrien      bfd_byte *s;
171371671b9obrien
171471671b9obrien      i = (swap->debug_align
171571671b9obrien	   - (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
171671671b9obrien      s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
171771671b9obrien      if (s == NULL && i != 0)
171871671b9obrien	goto error_return;
171971671b9obrien
172071671b9obrien      if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
172171671b9obrien	{
172271671b9obrien	  free (s);
172371671b9obrien	  goto error_return;
172471671b9obrien	}
172571671b9obrien      free (s);
172671671b9obrien    }
172771671b9obrien
172871671b9obrien  if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
172971671b9obrien      || ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
173071671b9obrien    goto error_return;
173171671b9obrien
173271671b9obrien  BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
173371671b9obrien	      || (debug->symbolic_header.cbExtOffset
173471671b9obrien		  == (bfd_vma) bfd_tell (abfd)));
173571671b9obrien
173671671b9obrien  amt = debug->symbolic_header.iextMax * swap->external_ext_size;
173771671b9obrien  if (bfd_bwrite (debug->external_ext, amt, abfd) != amt)
173871671b9obrien    goto error_return;
173971671b9obrien
174071671b9obrien  if (space != NULL)
174171671b9obrien    free (space);
174271671b9obrien  return TRUE;
174371671b9obrien
174471671b9obrien error_return:
174571671b9obrien  if (space != NULL)
174671671b9obrien    free (space);
174771671b9obrien  return FALSE;
174871671b9obrien}
174971671b9obrien
175071671b9obrien/* Handle the find_nearest_line function for both ECOFF and MIPS ELF
175171671b9obrien   files.  */
175271671b9obrien
175371671b9obrien/* Compare FDR entries.  This is called via qsort.  */
175471671b9obrien
175571671b9obrienstatic int
175671671b9obriencmp_fdrtab_entry (leftp, rightp)
175771671b9obrien     const PTR leftp;
175871671b9obrien     const PTR rightp;
175971671b9obrien{
176071671b9obrien  const struct ecoff_fdrtab_entry *lp =
176171671b9obrien    (const struct ecoff_fdrtab_entry *) leftp;
176271671b9obrien  const struct ecoff_fdrtab_entry *rp =
176371671b9obrien    (const struct ecoff_fdrtab_entry *) rightp;
176471671b9obrien
176571671b9obrien  if (lp->base_addr < rp->base_addr)
176671671b9obrien    return -1;
176771671b9obrien  if (lp->base_addr > rp->base_addr)
176871671b9obrien    return 1;
176971671b9obrien  return 0;
177071671b9obrien}
177171671b9obrien
177271671b9obrien/* Each file descriptor (FDR) has a memory address, to simplify
177371671b9obrien   looking up an FDR by address, we build a table covering all FDRs
177471671b9obrien   that have a least one procedure descriptor in them.  The final
177571671b9obrien   table will be sorted by address so we can look it up via binary
177671671b9obrien   search.  */
177771671b9obrien
177871671b9obrienstatic bfd_boolean
177971671b9obrienmk_fdrtab (abfd, debug_info, debug_swap, line_info)
178071671b9obrien     bfd *abfd;
178171671b9obrien     struct ecoff_debug_info * const debug_info;
178271671b9obrien     const struct ecoff_debug_swap * const debug_swap;
178371671b9obrien     struct ecoff_find_line *line_info;
178471671b9obrien{
178571671b9obrien  struct ecoff_fdrtab_entry *tab;
178671671b9obrien  FDR *fdr_ptr;
178771671b9obrien  FDR *fdr_start;
178871671b9obrien  FDR *fdr_end;
178971671b9obrien  bfd_boolean stabs;
179071671b9obrien  long len;
179171671b9obrien  bfd_size_type amt;
179271671b9obrien
179371671b9obrien  fdr_start = debug_info->fdr;
179471671b9obrien  fdr_end = fdr_start + debug_info->symbolic_header.ifdMax;
179571671b9obrien
179671671b9obrien  /* First, let's see how long the table needs to be.  */
179771671b9obrien  for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
179871671b9obrien    {
179971671b9obrien      if (fdr_ptr->cpd == 0)	/* Skip FDRs that have no PDRs.  */
180071671b9obrien	continue;
180171671b9obrien      ++len;
180271671b9obrien    }
180371671b9obrien
180471671b9obrien  /* Now, create and fill in the table.  */
180571671b9obrien  amt = (bfd_size_type) len * sizeof (struct ecoff_fdrtab_entry);
180671671b9obrien  line_info->fdrtab = (struct ecoff_fdrtab_entry*) bfd_zalloc (abfd, amt);
180771671b9obrien  if (line_info->fdrtab == NULL)
180871671b9obrien    return FALSE;
180971671b9obrien  line_info->fdrtab_len = len;
181071671b9obrien
181171671b9obrien  tab = line_info->fdrtab;
181271671b9obrien  for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
181371671b9obrien    {
181471671b9obrien      if (fdr_ptr->cpd == 0)
181571671b9obrien	continue;
181671671b9obrien
181771671b9obrien      /* Check whether this file has stabs debugging information.  In
181871671b9obrien	 a file with stabs debugging information, the second local
181971671b9obrien	 symbol is named @stabs.  */
182071671b9obrien      stabs = FALSE;
182171671b9obrien      if (fdr_ptr->csym >= 2)
182271671b9obrien	{
182371671b9obrien	  char *sym_ptr;
182471671b9obrien	  SYMR sym;
182571671b9obrien
182671671b9obrien	  sym_ptr = ((char *) debug_info->external_sym
182771671b9obrien		     + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
182871671b9obrien	  (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
182971671b9obrien	  if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
183071671b9obrien		      STABS_SYMBOL) == 0)
183171671b9obrien	    stabs = TRUE;
183271671b9obrien	}
183371671b9obrien
183471671b9obrien      if (!stabs)
183571671b9obrien	{
183671671b9obrien	  /* eraxxon: There are at least two problems with this computation:
183771671b9obrien	     1) PDRs do *not* contain offsets but full vma's; and typically the
183871671b9obrien	     address of the first PDR is the address of the FDR, which will
183971671b9obrien	     make (most) of the results of the original computation 0!
184071671b9obrien	     2) Once in a wacky while, the Compaq compiler generated PDR
184171671b9obrien	     addresses do not equal the FDR vma, but they (the PDR address)
184271671b9obrien	     are still vma's and not offsets.  Cf. comments in
184371671b9obrien	     'lookup_line'.  */
184471671b9obrien	  /* The address of the first PDR is the offset of that
184571671b9obrien	     procedure relative to the beginning of file FDR.  */
184671671b9obrien	  tab->base_addr = fdr_ptr->adr;
184771671b9obrien	}
184871671b9obrien      else
184971671b9obrien	{
185071671b9obrien	  /* XXX I don't know about stabs, so this is a guess
185171671b9obrien	     (davidm@cs.arizona.edu).  */
185271671b9obrien	  tab->base_addr = fdr_ptr->adr;
185371671b9obrien	}
185471671b9obrien      tab->fdr = fdr_ptr;
185571671b9obrien      ++tab;
185671671b9obrien    }
185771671b9obrien
185871671b9obrien  /* Finally, the table is sorted in increasing memory-address order.
185971671b9obrien     The table is mostly sorted already, but there are cases (e.g.,
186071671b9obrien     static functions in include files), where this does not hold.
186171671b9obrien     Use "odump -PFv" to verify...  */
186271671b9obrien  qsort ((PTR) line_info->fdrtab, (size_t) len,
186371671b9obrien	 sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry);
186471671b9obrien
186571671b9obrien  return TRUE;
186671671b9obrien}
186771671b9obrien
186871671b9obrien/* Return index of first FDR that covers to OFFSET.  */
186971671b9obrien
187071671b9obrienstatic long
187171671b9obrienfdrtab_lookup (line_info, offset)
187271671b9obrien     struct ecoff_find_line *line_info;
187371671b9obrien     bfd_vma offset;
187471671b9obrien{
187571671b9obrien  long low, high, len;
187671671b9obrien  long mid = -1;
187771671b9obrien  struct ecoff_fdrtab_entry *tab;
187871671b9obrien
187971671b9obrien  len = line_info->fdrtab_len;
188071671b9obrien  if (len == 0)
188171671b9obrien    return -1;
188271671b9obrien
188371671b9obrien  tab = line_info->fdrtab;
188471671b9obrien  for (low = 0, high = len - 1 ; low != high ;)
188571671b9obrien    {
188671671b9obrien      mid = (high + low) / 2;
188771671b9obrien      if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr)
188871671b9obrien	goto find_min;
188971671b9obrien
189071671b9obrien      if (tab[mid].base_addr > offset)
189171671b9obrien	high = mid;
189271671b9obrien      else
189371671b9obrien	low = mid + 1;
189471671b9obrien    }
189571671b9obrien
189671671b9obrien  /* eraxxon: at this point 'offset' is either lower than the lowest entry or
189771671b9obrien     higher than the highest entry. In the former case high = low = mid = 0;
189871671b9obrien     we want to return -1.  In the latter case, low = high and mid = low - 1;
189971671b9obrien     we want to return the index of the highest entry.  Only in former case
190071671b9obrien     will the following 'catch-all' test be true.  */
190171671b9obrien  ++mid;
190271671b9obrien
190371671b9obrien  /* Last entry is catch-all for all higher addresses.  */
190471671b9obrien  if (offset < tab[mid].base_addr)
190571671b9obrien    return -1;
190671671b9obrien
190771671b9obrien find_min:
190871671b9obrien
190971671b9obrien  /* eraxxon: There may be multiple FDRs in the table with the
191071671b9obrien     same base_addr; make sure that we are at the first one.  */
191171671b9obrien  while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr)
191271671b9obrien    --mid;
191371671b9obrien
191471671b9obrien  return mid;
191571671b9obrien}
191671671b9obrien
191771671b9obrien/* Look up a line given an address, storing the information in
191871671b9obrien   LINE_INFO->cache.  */
191971671b9obrien
192071671b9obrienstatic bfd_boolean
192171671b9obrienlookup_line (abfd, debug_info, debug_swap, line_info)
192271671b9obrien     bfd *abfd;
192371671b9obrien     struct ecoff_debug_info * const debug_info;
192471671b9obrien     const struct ecoff_debug_swap * const debug_swap;
192571671b9obrien     struct ecoff_find_line *line_info;
192671671b9obrien{
192771671b9obrien  struct ecoff_fdrtab_entry *tab;
192871671b9obrien  bfd_vma offset;
192971671b9obrien  bfd_boolean stabs;
193071671b9obrien  FDR *fdr_ptr;
193171671b9obrien  int i;
193271671b9obrien
193371671b9obrien  /* eraxxon: note that 'offset' is the full vma, not a section offset.  */
193471671b9obrien  offset = line_info->cache.start;
193571671b9obrien
193671671b9obrien  /* Build FDR table (sorted by object file's base-address) if we
193771671b9obrien     don't have it already.  */
193871671b9obrien  if (line_info->fdrtab == NULL
193971671b9obrien      && !mk_fdrtab (abfd, debug_info, debug_swap, line_info))
194071671b9obrien    return FALSE;
194171671b9obrien
194271671b9obrien  tab = line_info->fdrtab;
194371671b9obrien
194471671b9obrien  /* Find first FDR for address OFFSET.  */
194571671b9obrien  i = fdrtab_lookup (line_info, offset);
194671671b9obrien  if (i < 0)
194771671b9obrien    return FALSE;		/* no FDR, no fun...  */
194871671b9obrien
194971671b9obrien  /* eraxxon: 'fdrtab_lookup' doesn't give what we want, at least for Compaq's
195071671b9obrien     C++ compiler 6.2.  Consider three FDRs with starting addresses of x, y,
195171671b9obrien     and z, respectively, such that x < y < z.  Assume further that
195271671b9obrien     y < 'offset' < z.  It is possible at times that the PDR for 'offset' is
195371671b9obrien     associated with FDR x and *not* with FDR y.  Erg!!
195471671b9obrien
195571671b9obrien     From a binary dump of my C++ test case 'moo' using Compaq's coffobjanl
195671671b9obrien     (output format has been edited for our purposes):
195771671b9obrien
195871671b9obrien     FDR [2]: (main.C): First instruction: 0x12000207c <x>
195971671b9obrien       PDR [5] for File [2]: LoopTest__Xv                 <0x1200020a0> (a)
196071671b9obrien       PDR [7] for File [2]: foo__Xv                      <0x120002168>
196171671b9obrien     FDR [1]: (-1):     First instruction: 0x1200020e8 <y>
196271671b9obrien       PDR [3] for File [1]:                              <0x120001ad0> (b)
196371671b9obrien     FDR [6]: (-1):     First instruction: 0x1200026f0 <z>
196471671b9obrien
196571671b9obrien     (a) In the case of PDR5, the vma is such that the first few instructions
196671671b9obrien     of the procedure can be found.  But since the size of this procedure is
196771671b9obrien     160b, the vma will soon cross into the 'address space' of FDR1 and no
196871671b9obrien     debugging info will be found.  How repugnant!
196971671b9obrien
197071671b9obrien     (b) It is also possible for a PDR to have a *lower* vma than its associated
197171671b9obrien     FDR; see FDR1 and PDR3.  Gross!
197271671b9obrien
197371671b9obrien     Since the FDRs that are causing so much havok (in this case) 1) do not
197471671b9obrien     describe actual files (fdr.rss == -1), and 2) contain only compiler
197571671b9obrien     generated routines, I thought a simple fix would be to exclude them from
197671671b9obrien     the FDR table in 'mk_fdrtab'.  But, besides not knowing for certain
197771671b9obrien     whether this would be correct, it creates an additional problem.  If we
197871671b9obrien     happen to ask for source file info on a compiler generated (procedure)
197971671b9obrien     symbol -- which is still in the symbol table -- the result can be
198071671b9obrien     information from a real procedure!  This is because compiler generated
198171671b9obrien     procedures with vma's higher than the last FDR in the fdr table will be
198271671b9obrien     associated with a PDR from this FDR, specifically the PDR with the
198371671b9obrien     highest vma.  This wasn't a problem before, because each procedure had a
198471671b9obrien     PDR.  (Yes, this problem could be eliminated if we kept the size of the
198571671b9obrien     last PDR around, but things are already getting ugly).
198671671b9obrien
198771671b9obrien     Probably, a better solution would be to have a sorted PDR table.  Each
198871671b9obrien     PDR would have a pointer to its FDR so file information could still be
198971671b9obrien     obtained.  A FDR table could still be constructed if necessary -- since
199071671b9obrien     it only contains pointers, not much extra memory would be used -- but
199171671b9obrien     the PDR table would be searched to locate debugging info.
199271671b9obrien
199371671b9obrien     There is still at least one remaining issue.  Sometimes a FDR can have a
199471671b9obrien     bogus name, but contain PDRs that should belong to another FDR with a
199571671b9obrien     real name.  E.g:
199671671b9obrien
199771671b9obrien     FDR [3]: 0000000120001b50 (/home/.../Array.H~alt~deccxx_5E5A62AD)
199871671b9obrien       PDR [a] for File [3]: 0000000120001b50
199971671b9obrien       PDR [b] for File [3]: 0000000120001cf0
200071671b9obrien       PDR [c] for File [3]: 0000000120001dc8
200171671b9obrien       PDR [d] for File [3]: 0000000120001e40
200271671b9obrien       PDR [e] for File [3]: 0000000120001eb8
200371671b9obrien       PDR [f] for File [3]: 0000000120001f4c
200471671b9obrien     FDR [4]: 0000000120001b50 (/home/.../Array.H)
200571671b9obrien
200671671b9obrien     Here, FDR4 has the correct name, but should (seemingly) contain PDRa-f.
200771671b9obrien     The symbol table for PDR4 does contain symbols for PDRa-f, but so does
200871671b9obrien     the symbol table for FDR3.  However the former is different; perhaps this
200971671b9obrien     can be detected easily. (I'm not sure at this point.)  This problem only
201071671b9obrien     seems to be associated with files with templates.  I am assuming the idea
201171671b9obrien     is that there is a 'fake' FDR (with PDRs) for each differently typed set
201271671b9obrien     of templates that must be generated.  Currently, FDR4 is completely
201371671b9obrien     excluded from the FDR table in 'mk_fdrtab' because it contains no PDRs.
201471671b9obrien
201571671b9obrien     Since I don't have time to prepare a real fix for this right now, be
201671671b9obrien     prepared for 'A Horrible Hack' to force the inspection of all non-stabs
201771671b9obrien     FDRs.  It's coming...  */
201871671b9obrien  fdr_ptr = tab[i].fdr;
201971671b9obrien
202071671b9obrien  /* Check whether this file has stabs debugging information.  In a
202171671b9obrien     file with stabs debugging information, the second local symbol is
202271671b9obrien     named @stabs.  */
202371671b9obrien  stabs = FALSE;
202471671b9obrien  if (fdr_ptr->csym >= 2)
202571671b9obrien    {
202671671b9obrien      char *sym_ptr;
202771671b9obrien      SYMR sym;
202871671b9obrien
202971671b9obrien      sym_ptr = ((char *) debug_info->external_sym
203071671b9obrien		 + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
203171671b9obrien      (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
203271671b9obrien      if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
203371671b9obrien		  STABS_SYMBOL) == 0)
203471671b9obrien	stabs = TRUE;
203571671b9obrien    }
203671671b9obrien
203771671b9obrien  if (!stabs)
203871671b9obrien    {
203971671b9obrien      bfd_size_type external_pdr_size;
204071671b9obrien      char *pdr_ptr;
204171671b9obrien      char *best_pdr = NULL;
204271671b9obrien      FDR *best_fdr;
204371671b9obrien      bfd_signed_vma best_dist = -1;
204471671b9obrien      PDR pdr;
204571671b9obrien      unsigned char *line_ptr;
204671671b9obrien      unsigned char *line_end;
204771671b9obrien      int lineno;
204871671b9obrien      /* This file uses ECOFF debugging information.  Each FDR has a
204971671b9obrien         list of procedure descriptors (PDR).  The address in the FDR
205071671b9obrien         is the absolute address of the first procedure.  The address
205171671b9obrien         in the first PDR gives the offset of that procedure relative
205271671b9obrien         to the object file's base-address.  The addresses in
205371671b9obrien         subsequent PDRs specify each procedure's address relative to
205471671b9obrien         the object file's base-address.  To make things more juicy,
205571671b9obrien         whenever the PROF bit in the PDR is set, the real entry point
205671671b9obrien         of the procedure may be 16 bytes below what would normally be
205771671b9obrien         the procedure's entry point.  Instead, DEC came up with a
205871671b9obrien         wicked scheme to create profiled libraries "on the fly":
205971671b9obrien         instead of shipping a regular and a profiled version of each
206071671b9obrien         library, they insert 16 bytes of unused space in front of
206171671b9obrien         each procedure and set the "prof" bit in the PDR to indicate
206271671b9obrien         that there is a gap there (this is done automagically by "as"
206371671b9obrien         when option "-pg" is specified).  Thus, normally, you link
206471671b9obrien         against such a library and, except for lots of 16 byte gaps
206571671b9obrien         between functions, things will behave as usual.  However,
206671671b9obrien         when invoking "ld" with option "-pg", it will fill those gaps
206771671b9obrien         with code that calls mcount().  It then moves the function's
206871671b9obrien         entry point down by 16 bytes, and out pops a binary that has
206971671b9obrien         all functions profiled.
207071671b9obrien
207171671b9obrien         NOTE: Neither FDRs nor PDRs are strictly sorted in memory
207271671b9obrien               order.  For example, when including header-files that
207371671b9obrien               define functions, the FDRs follow behind the including
207471671b9obrien               file, even though their code may have been generated at
207571671b9obrien               a lower address.  File coff-alpha.c from libbfd
207671671b9obrien               illustrates this (use "odump -PFv" to look at a file's
207771671b9obrien               FDR/PDR).  Similarly, PDRs are sometimes out of order
207871671b9obrien               as well.  An example of this is OSF/1 v3.0 libc's
207971671b9obrien               malloc.c.  I'm not sure why this happens, but it could
208071671b9obrien               be due to optimizations that reorder a function's
208171671b9obrien               position within an object-file.
208271671b9obrien
208371671b9obrien         Strategy:
208471671b9obrien
208571671b9obrien         On the first call to this function, we build a table of FDRs
208671671b9obrien         that is sorted by the base-address of the object-file the FDR
208771671b9obrien         is referring to.  Notice that each object-file may contain
208871671b9obrien         code from multiple source files (e.g., due to code defined in
208971671b9obrien         include files).  Thus, for any given base-address, there may
209071671b9obrien         be multiple FDRs (but this case is, fortunately, uncommon).
209171671b9obrien         lookup(addr) guarantees to return the first FDR that applies
209271671b9obrien         to address ADDR.  Thus, after invoking lookup(), we have a
209371671b9obrien         list of FDRs that may contain the PDR for ADDR.  Next, we
209471671b9obrien         walk through the PDRs of these FDRs and locate the one that
209571671b9obrien         is closest to ADDR (i.e., for which the difference between
209671671b9obrien         ADDR and the PDR's entry point is positive and minimal).
209771671b9obrien         Once, the right FDR and PDR are located, we simply walk
209871671b9obrien         through the line-number table to lookup the line-number that
209971671b9obrien         best matches ADDR.  Obviously, things could be sped up by
210071671b9obrien         keeping a sorted list of PDRs instead of a sorted list of
210171671b9obrien         FDRs.  However, this would increase space requirements
210271671b9obrien         considerably, which is undesirable.  */
210371671b9obrien      external_pdr_size = debug_swap->external_pdr_size;
210471671b9obrien
210571671b9obrien      /* eraxxon: The Horrible Hack: Because of the problems above, set 'i'
210671671b9obrien	 to 0 so we look through all FDRs.
210771671b9obrien
210871671b9obrien	 Because FDR's without any symbols are assumed to be non-stabs,
210971671b9obrien	 searching through all FDRs may cause the following code to try to
211071671b9obrien	 read stabs FDRs as ECOFF ones.  However, I don't think this will
211171671b9obrien	 harm anything.  */
211271671b9obrien      i = 0;
211371671b9obrien
211471671b9obrien      /* Search FDR list starting at tab[i] for the PDR that best matches
211571671b9obrien         OFFSET.  Normally, the FDR list is only one entry long.  */
211671671b9obrien      best_fdr = NULL;
211771671b9obrien      do
211871671b9obrien	{
211971671b9obrien	  /* eraxxon: 'dist' and 'min_dist' can be negative now
212071671b9obrien             because we iterate over every FDR rather than just ones
212171671b9obrien             with a base address less than or equal to 'offset'.  */
212271671b9obrien	  bfd_signed_vma dist = -1, min_dist = -1;
212371671b9obrien	  char *pdr_hold;
212471671b9obrien	  char *pdr_end;
212571671b9obrien
212671671b9obrien	  fdr_ptr = tab[i].fdr;
212771671b9obrien
212871671b9obrien	  pdr_ptr = ((char *) debug_info->external_pdr
212971671b9obrien		     + fdr_ptr->ipdFirst * external_pdr_size);
213071671b9obrien	  pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
213171671b9obrien	  (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
213271671b9obrien	  /* Find PDR that is closest to OFFSET.  If pdr.prof is set,
213371671b9obrien	     the procedure entry-point *may* be 0x10 below pdr.adr.  We
213471671b9obrien	     simply pretend that pdr.prof *implies* a lower entry-point.
213571671b9obrien	     This is safe because it just means that may identify 4 NOPs
213671671b9obrien	     in front of the function as belonging to the function.  */
213771671b9obrien	  for (pdr_hold = NULL;
213871671b9obrien	       pdr_ptr < pdr_end;
213971671b9obrien	       (pdr_ptr += external_pdr_size,
214071671b9obrien		(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr)))
214171671b9obrien	    {
214271671b9obrien	      if (offset >= (pdr.adr - 0x10 * pdr.prof))
214371671b9obrien		{
214471671b9obrien		  dist = offset - (pdr.adr - 0x10 * pdr.prof);
214571671b9obrien
214671671b9obrien		  /* eraxxon: 'dist' can be negative now.  Note that
214771671b9obrien                     'min_dist' can be negative if 'pdr_hold' below is NULL.  */
214871671b9obrien		  if (!pdr_hold || (dist >= 0 && dist < min_dist))
214971671b9obrien		    {
215071671b9obrien		      min_dist = dist;
215171671b9obrien		      pdr_hold = pdr_ptr;
215271671b9obrien		    }
215371671b9obrien		}
215471671b9obrien	    }
215571671b9obrien
215671671b9obrien	  if (!best_pdr || (min_dist >= 0 && min_dist < best_dist))
215771671b9obrien	    {
215871671b9obrien	      best_dist = (bfd_vma) min_dist;
215971671b9obrien	      best_fdr = fdr_ptr;
216071671b9obrien	      best_pdr = pdr_hold;
216171671b9obrien	    }
216271671b9obrien	  /* Continue looping until base_addr of next entry is different.  */
216371671b9obrien	}
216471671b9obrien      /* eraxxon: We want to iterate over all FDRs.
216571671b9obrien	 See previous comment about 'fdrtab_lookup'.  */
216671671b9obrien      while (++i < line_info->fdrtab_len);
216771671b9obrien
216871671b9obrien      if (!best_fdr || !best_pdr)
216971671b9obrien	return FALSE;			/* Shouldn't happen...  */
217071671b9obrien
217171671b9obrien      /* Phew, finally we got something that we can hold onto.  */
217271671b9obrien      fdr_ptr = best_fdr;
217371671b9obrien      pdr_ptr = best_pdr;
217471671b9obrien      (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
217571671b9obrien      /* Now we can look for the actual line number.  The line numbers
217671671b9obrien         are stored in a very funky format, which I won't try to
217771671b9obrien         describe.  The search is bounded by the end of the FDRs line
217871671b9obrien         number entries.  */
217971671b9obrien      line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
218071671b9obrien
218171671b9obrien      /* Make offset relative to procedure entry.  */
218271671b9obrien      offset -= pdr.adr - 0x10 * pdr.prof;
218371671b9obrien      lineno = pdr.lnLow;
218471671b9obrien      line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset;
218571671b9obrien      while (line_ptr < line_end)
218671671b9obrien	{
218771671b9obrien	  int delta;
218871671b9obrien	  unsigned int count;
218971671b9obrien
219071671b9obrien	  delta = *line_ptr >> 4;
219171671b9obrien	  if (delta >= 0x8)
219271671b9obrien	    delta -= 0x10;
219371671b9obrien	  count = (*line_ptr & 0xf) + 1;
219471671b9obrien	  ++line_ptr;
219571671b9obrien	  if (delta == -8)
219671671b9obrien	    {
219771671b9obrien	      delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
219871671b9obrien	      if (delta >= 0x8000)
219971671b9obrien		delta -= 0x10000;
220071671b9obrien	      line_ptr += 2;
220171671b9obrien	    }
220271671b9obrien	  lineno += delta;
220371671b9obrien	  if (offset < count * 4)
220471671b9obrien	    {
220571671b9obrien	      line_info->cache.stop += count * 4 - offset;
220671671b9obrien	      break;
220771671b9obrien	    }
220871671b9obrien	  offset -= count * 4;
220971671b9obrien	}
221071671b9obrien
221171671b9obrien      /* If fdr_ptr->rss is -1, then this file does not have full
221271671b9obrien         symbols, at least according to gdb/mipsread.c.  */
221371671b9obrien      if (fdr_ptr->rss == -1)
221471671b9obrien	{
221571671b9obrien	  line_info->cache.filename = NULL;
221671671b9obrien	  if (pdr.isym == -1)
221771671b9obrien	    line_info->cache.functionname = NULL;
221871671b9obrien	  else
221971671b9obrien	    {
222071671b9obrien	      EXTR proc_ext;
222171671b9obrien
222271671b9obrien	      (*debug_swap->swap_ext_in)
222371671b9obrien		(abfd,
222471671b9obrien		 ((char *) debug_info->external_ext
222571671b9obrien		  + pdr.isym * debug_swap->external_ext_size),
222671671b9obrien		 &proc_ext);
222771671b9obrien	      line_info->cache.functionname = (debug_info->ssext
222871671b9obrien					       + proc_ext.asym.iss);
222971671b9obrien	    }
223071671b9obrien	}
223171671b9obrien      else
223271671b9obrien	{
223371671b9obrien	  SYMR proc_sym;
223471671b9obrien
223571671b9obrien	  line_info->cache.filename = (debug_info->ss
223671671b9obrien				       + fdr_ptr->issBase
223771671b9obrien				       + fdr_ptr->rss);
223871671b9obrien	  (*debug_swap->swap_sym_in)
223971671b9obrien	    (abfd,
224071671b9obrien	     ((char *) debug_info->external_sym
224171671b9obrien	      + ((fdr_ptr->isymBase + pdr.isym)
224271671b9obrien		 * debug_swap->external_sym_size)),
224371671b9obrien	     &proc_sym);
224471671b9obrien	  line_info->cache.functionname = (debug_info->ss
224571671b9obrien					   + fdr_ptr->issBase
224671671b9obrien					   + proc_sym.iss);
224771671b9obrien	}
224871671b9obrien      if (lineno == ilineNil)
224971671b9obrien	lineno = 0;
225071671b9obrien      line_info->cache.line_num = lineno;
225171671b9obrien    }
225271671b9obrien  else
225371671b9obrien    {
225471671b9obrien      bfd_size_type external_sym_size;
225571671b9obrien      const char *directory_name;
225671671b9obrien      const char *main_file_name;
225771671b9obrien      const char *current_file_name;
225871671b9obrien      const char *function_name;
225971671b9obrien      const char *line_file_name;
226071671b9obrien      bfd_vma low_func_vma;
226171671b9obrien      bfd_vma low_line_vma;
226271671b9obrien      bfd_boolean past_line;
226371671b9obrien      bfd_boolean past_fn;
226471671b9obrien      char *sym_ptr, *sym_ptr_end;
226571671b9obrien      size_t len, funclen;
226671671b9obrien      char *buffer = NULL;
226771671b9obrien
226871671b9obrien      /* This file uses stabs debugging information.  When gcc is not
226971671b9obrien	 optimizing, it will put the line number information before
227071671b9obrien	 the function name stabs entry.  When gcc is optimizing, it
227171671b9obrien	 will put the stabs entry for all the function first, followed
227271671b9obrien	 by the line number information.  (This appears to happen
227371671b9obrien	 because of the two output files used by the -mgpopt switch,
227471671b9obrien	 which is implied by -O).  This means that we must keep
227571671b9obrien	 looking through the symbols until we find both a line number
227671671b9obrien	 and a function name which are beyond the address we want.  */
227771671b9obrien
227871671b9obrien      line_info->cache.filename = NULL;
227971671b9obrien      line_info->cache.functionname = NULL;
228071671b9obrien      line_info->cache.line_num = 0;
228171671b9obrien
228271671b9obrien      directory_name = NULL;
228371671b9obrien      main_file_name = NULL;
228471671b9obrien      current_file_name = NULL;
228571671b9obrien      function_name = NULL;
228671671b9obrien      line_file_name = NULL;
228771671b9obrien      low_func_vma = 0;
228871671b9obrien      low_line_vma = 0;
228971671b9obrien      past_line = FALSE;
229071671b9obrien      past_fn = FALSE;
229171671b9obrien
229271671b9obrien      external_sym_size = debug_swap->external_sym_size;
229371671b9obrien
229471671b9obrien      sym_ptr = ((char *) debug_info->external_sym
229571671b9obrien		 + (fdr_ptr->isymBase + 2) * external_sym_size);
229671671b9obrien      sym_ptr_end = sym_ptr + (fdr_ptr->csym - 2) * external_sym_size;
229771671b9obrien      for (;
229871671b9obrien	   sym_ptr < sym_ptr_end && (! past_line || ! past_fn);
229971671b9obrien	   sym_ptr += external_sym_size)
230071671b9obrien	{
230171671b9obrien	  SYMR sym;
230271671b9obrien
230371671b9obrien	  (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
230471671b9obrien
230571671b9obrien	  if (ECOFF_IS_STAB (&sym))
230671671b9obrien	    {
230771671b9obrien	      switch (ECOFF_UNMARK_STAB (sym.index))
230871671b9obrien		{
230971671b9obrien		case N_SO:
231071671b9obrien		  main_file_name = current_file_name =
231171671b9obrien		    debug_info->ss + fdr_ptr->issBase + sym.iss;
231271671b9obrien
231371671b9obrien		  /* Check the next symbol to see if it is also an
231471671b9obrien                     N_SO symbol.  */
231571671b9obrien		  if (sym_ptr + external_sym_size < sym_ptr_end)
231671671b9obrien		    {
231771671b9obrien		      SYMR nextsym;
231871671b9obrien
231971671b9obrien		      (*debug_swap->swap_sym_in) (abfd,
232071671b9obrien						  sym_ptr + external_sym_size,
232171671b9obrien						  &nextsym);
232271671b9obrien		      if (ECOFF_IS_STAB (&nextsym)
232371671b9obrien			  && ECOFF_UNMARK_STAB (nextsym.index) == N_SO)
232471671b9obrien			{
232571671b9obrien 			  directory_name = current_file_name;
232671671b9obrien			  main_file_name = current_file_name =
232771671b9obrien			    debug_info->ss + fdr_ptr->issBase + nextsym.iss;
232871671b9obrien			  sym_ptr += external_sym_size;
232971671b9obrien			}
233071671b9obrien		    }
233171671b9obrien		  break;
233271671b9obrien
233371671b9obrien		case N_SOL:
233471671b9obrien		  current_file_name =
233571671b9obrien		    debug_info->ss + fdr_ptr->issBase + sym.iss;
233671671b9obrien		  break;
233771671b9obrien
233871671b9obrien		case N_FUN:
233971671b9obrien		  if (sym.value > offset)
234071671b9obrien		    past_fn = TRUE;
234171671b9obrien		  else if (sym.value >= low_func_vma)
234271671b9obrien		    {
234371671b9obrien		      low_func_vma = sym.value;
234471671b9obrien		      function_name =
234571671b9obrien			debug_info->ss + fdr_ptr->issBase + sym.iss;
234671671b9obrien		    }
234771671b9obrien		  break;
234871671b9obrien		}
234971671b9obrien	    }
235071671b9obrien	  else if (sym.st == stLabel && sym.index != indexNil)
235171671b9obrien	    {
235271671b9obrien	      if (sym.value > offset)
235371671b9obrien		past_line = TRUE;
235471671b9obrien	      else if (sym.value >= low_line_vma)
235571671b9obrien		{
235671671b9obrien		  low_line_vma = sym.value;
235771671b9obrien		  line_file_name = current_file_name;
235871671b9obrien		  line_info->cache.line_num = sym.index;
235971671b9obrien		}
236071671b9obrien	    }
236171671b9obrien	}
236271671b9obrien
236371671b9obrien      if (line_info->cache.line_num != 0)
236471671b9obrien	main_file_name = line_file_name;
236571671b9obrien
236671671b9obrien      /* We need to remove the stuff after the colon in the function
236771671b9obrien         name.  We also need to put the directory name and the file
236871671b9obrien         name together.  */
236971671b9obrien      if (function_name == NULL)
237071671b9obrien	len = funclen = 0;
237171671b9obrien      else
237271671b9obrien	len = funclen = strlen (function_name) + 1;
237371671b9obrien
237471671b9obrien      if (main_file_name != NULL
237571671b9obrien	  && directory_name != NULL
237671671b9obrien	  && main_file_name[0] != '/')
237771671b9obrien	len += strlen (directory_name) + strlen (main_file_name) + 1;
237871671b9obrien
237971671b9obrien      if (len != 0)
238071671b9obrien	{
238171671b9obrien	  if (line_info->find_buffer != NULL)
238271671b9obrien	    free (line_info->find_buffer);
238371671b9obrien	  buffer = (char *) bfd_malloc ((bfd_size_type) len);
238471671b9obrien	  if (buffer == NULL)
238571671b9obrien	    return FALSE;
238671671b9obrien	  line_info->find_buffer = buffer;
238771671b9obrien	}
238871671b9obrien
238971671b9obrien      if (function_name != NULL)
239071671b9obrien	{
239171671b9obrien	  char *colon;
239271671b9obrien
239371671b9obrien	  strcpy (buffer, function_name);
239471671b9obrien	  colon = strchr (buffer, ':');
239571671b9obrien	  if (colon != NULL)
239671671b9obrien	    *colon = '\0';
239771671b9obrien	  line_info->cache.functionname = buffer;
239871671b9obrien	}
239971671b9obrien
240071671b9obrien      if (main_file_name != NULL)
240171671b9obrien	{
240271671b9obrien	  if (directory_name == NULL || main_file_name[0] == '/')
240371671b9obrien	    line_info->cache.filename = main_file_name;
240471671b9obrien	  else
240571671b9obrien	    {
240671671b9obrien	      sprintf (buffer + funclen, "%s%s", directory_name,
240771671b9obrien		       main_file_name);
240871671b9obrien	      line_info->cache.filename = buffer + funclen;
240971671b9obrien	    }
241071671b9obrien	}
241171671b9obrien    }
241271671b9obrien
241371671b9obrien  return TRUE;
241471671b9obrien}
241571671b9obrien
241671671b9obrien/* Do the work of find_nearest_line.  */
241771671b9obrien
241871671b9obrienbfd_boolean
241971671b9obrien_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap,
242071671b9obrien			line_info, filename_ptr, functionname_ptr, retline_ptr)
242171671b9obrien     bfd *abfd;
242271671b9obrien     asection *section;
242371671b9obrien     bfd_vma offset;
242471671b9obrien     struct ecoff_debug_info * const debug_info;
242571671b9obrien     const struct ecoff_debug_swap * const debug_swap;
242671671b9obrien     struct ecoff_find_line *line_info;
242771671b9obrien     const char **filename_ptr;
242871671b9obrien     const char **functionname_ptr;
242971671b9obrien     unsigned int *retline_ptr;
243071671b9obrien{
243171671b9obrien  offset += section->vma;
243271671b9obrien
243371671b9obrien  if (line_info->cache.sect == NULL
243471671b9obrien      || line_info->cache.sect != section
243571671b9obrien      || offset < line_info->cache.start
243671671b9obrien      || offset >= line_info->cache.stop)
243771671b9obrien    {
243871671b9obrien      line_info->cache.sect = section;
243971671b9obrien      line_info->cache.start = offset;
244071671b9obrien      line_info->cache.stop = offset;
244171671b9obrien      if (! lookup_line (abfd, debug_info, debug_swap, line_info))
244271671b9obrien	{
244371671b9obrien	  line_info->cache.sect = NULL;
244471671b9obrien	  return FALSE;
244571671b9obrien	}
244671671b9obrien    }
244771671b9obrien
244871671b9obrien  *filename_ptr = line_info->cache.filename;
244971671b9obrien  *functionname_ptr = line_info->cache.functionname;
245071671b9obrien  *retline_ptr = line_info->cache.line_num;
245171671b9obrien
245271671b9obrien  return TRUE;
245371671b9obrien}
245471671b9obrien
245571671b9obrien/* These routines copy symbolic information into a memory buffer.
245671671b9obrien
245771671b9obrien   FIXME: The whole point of the shuffle code is to avoid storing
245871671b9obrien   everything in memory, since the linker is such a memory hog.  This
245971671b9obrien   code makes that effort useless.  It is only called by the MIPS ELF
246071671b9obrien   code when generating a shared library, so it is not that big a
246171671b9obrien   deal, but it should be fixed eventually.  */
246271671b9obrien
246371671b9obrien/* Collect a shuffle into a memory buffer.  */
246471671b9obrien
246571671b9obrienstatic bfd_boolean ecoff_collect_shuffle
246671671b9obrien  PARAMS ((struct shuffle *, bfd_byte *));
246771671b9obrien
246871671b9obrienstatic bfd_boolean
246971671b9obrienecoff_collect_shuffle (l, buff)
247071671b9obrien     struct shuffle *l;
247171671b9obrien     bfd_byte *buff;
247271671b9obrien{
247371671b9obrien  unsigned long total;
247471671b9obrien
247571671b9obrien  total = 0;
247671671b9obrien  for (; l != (struct shuffle *) NULL; l = l->next)
247771671b9obrien    {
247871671b9obrien      if (! l->filep)
247971671b9obrien	memcpy (buff, l->u.memory, l->size);
248071671b9obrien      else
248171671b9obrien	{
248271671b9obrien	  if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
248371671b9obrien	      || (bfd_bread (buff, (bfd_size_type) l->size, l->u.file.input_bfd)
248471671b9obrien		  != l->size))
248571671b9obrien	    return FALSE;
248671671b9obrien	}
248771671b9obrien      total += l->size;
248871671b9obrien      buff += l->size;
248971671b9obrien    }
249071671b9obrien
249171671b9obrien  return TRUE;
249271671b9obrien}
249371671b9obrien
249471671b9obrien/* Copy PDR information into a memory buffer.  */
249571671b9obrien
249671671b9obrienbfd_boolean
249771671b9obrien_bfd_ecoff_get_accumulated_pdr (handle, buff)
249871671b9obrien     PTR handle;
249971671b9obrien     bfd_byte *buff;
250071671b9obrien{
250171671b9obrien  struct accumulate *ainfo = (struct accumulate *) handle;
250271671b9obrien
250371671b9obrien  return ecoff_collect_shuffle (ainfo->pdr, buff);
250471671b9obrien}
250571671b9obrien
250671671b9obrien/* Copy symbol information into a memory buffer.  */
250771671b9obrien
250871671b9obrienbfd_boolean
250971671b9obrien_bfd_ecoff_get_accumulated_sym (handle, buff)
251071671b9obrien     PTR handle;
251171671b9obrien     bfd_byte *buff;
251271671b9obrien{
251371671b9obrien  struct accumulate *ainfo = (struct accumulate *) handle;
251471671b9obrien
251571671b9obrien  return ecoff_collect_shuffle (ainfo->sym, buff);
251671671b9obrien}
251771671b9obrien
251871671b9obrien/* Copy the string table into a memory buffer.  */
251971671b9obrien
252071671b9obrienbfd_boolean
252171671b9obrien_bfd_ecoff_get_accumulated_ss (handle, buff)
252271671b9obrien     PTR handle;
252371671b9obrien     bfd_byte *buff;
252471671b9obrien{
252571671b9obrien  struct accumulate *ainfo = (struct accumulate *) handle;
252671671b9obrien  struct string_hash_entry *sh;
252771671b9obrien  unsigned long total;
252871671b9obrien
252971671b9obrien  /* The string table is written out from the hash table if this is a
253071671b9obrien     final link.  */
253171671b9obrien  BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
253271671b9obrien  *buff++ = '\0';
253371671b9obrien  total = 1;
253471671b9obrien  BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
253571671b9obrien  for (sh = ainfo->ss_hash;
253671671b9obrien       sh != (struct string_hash_entry *) NULL;
253771671b9obrien       sh = sh->next)
253871671b9obrien    {
253971671b9obrien      size_t len;
254071671b9obrien
254171671b9obrien      len = strlen (sh->root.string);
254271671b9obrien      memcpy (buff, (PTR) sh->root.string, len + 1);
254371671b9obrien      total += len + 1;
254471671b9obrien      buff += len + 1;
254571671b9obrien    }
254671671b9obrien
254771671b9obrien  return TRUE;
254871671b9obrien}
2549