133965Sjdp/* Routines to link ECOFF debugging information.
2218822Sdim   Copyright 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
3218822Sdim   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
433965Sjdp   Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
533965Sjdp
6130561Sobrien   This file is part of BFD, the Binary File Descriptor library.
733965Sjdp
8130561Sobrien   This program is free software; you can redistribute it and/or modify
9130561Sobrien   it under the terms of the GNU General Public License as published by
10130561Sobrien   the Free Software Foundation; either version 2 of the License, or
11130561Sobrien   (at your option) any later version.
1233965Sjdp
13130561Sobrien   This program is distributed in the hope that it will be useful,
14130561Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
15130561Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130561Sobrien   GNU General Public License for more details.
1733965Sjdp
18130561Sobrien   You should have received a copy of the GNU General Public License
19130561Sobrien   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2133965Sjdp
22218822Sdim#include "sysdep.h"
2333965Sjdp#include "bfd.h"
2433965Sjdp#include "bfdlink.h"
2533965Sjdp#include "libbfd.h"
2633965Sjdp#include "objalloc.h"
2733965Sjdp#include "aout/stab_gnu.h"
2833965Sjdp#include "coff/internal.h"
2933965Sjdp#include "coff/sym.h"
3033965Sjdp#include "coff/symconst.h"
3133965Sjdp#include "coff/ecoff.h"
3233965Sjdp#include "libcoff.h"
3333965Sjdp#include "libecoff.h"
3433965Sjdp
35130561Sobrienstatic bfd_boolean ecoff_add_bytes
36130561Sobrien  PARAMS ((char **buf, char **bufend, size_t need));
3733965Sjdpstatic struct bfd_hash_entry *string_hash_newfunc
3833965Sjdp  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
3933965Sjdp	   const char *));
40130561Sobrienstatic void ecoff_align_debug
41130561Sobrien  PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
42130561Sobrien	   const struct ecoff_debug_swap *swap));
43130561Sobrienstatic bfd_boolean ecoff_write_symhdr
44130561Sobrien  PARAMS ((bfd *, struct ecoff_debug_info *, const struct ecoff_debug_swap *,
45130561Sobrien	   file_ptr where));
46130561Sobrienstatic int cmp_fdrtab_entry
47130561Sobrien  PARAMS ((const PTR, const PTR));
48130561Sobrienstatic bfd_boolean mk_fdrtab
4933965Sjdp  PARAMS ((bfd *, struct ecoff_debug_info * const,
5033965Sjdp	   const struct ecoff_debug_swap * const, struct ecoff_find_line *));
51130561Sobrienstatic long fdrtab_lookup
52130561Sobrien  PARAMS ((struct ecoff_find_line *, bfd_vma));
53130561Sobrienstatic bfd_boolean lookup_line
54130561Sobrien  PARAMS ((bfd *, struct ecoff_debug_info * const,
55130561Sobrien	   const struct ecoff_debug_swap * const, struct ecoff_find_line *));
5633965Sjdp
5733965Sjdp/* Routines to swap auxiliary information in and out.  I am assuming
5833965Sjdp   that the auxiliary information format is always going to be target
5933965Sjdp   independent.  */
6033965Sjdp
6133965Sjdp/* Swap in a type information record.
6233965Sjdp   BIGEND says whether AUX symbols are big-endian or little-endian; this
6333965Sjdp   info comes from the file header record (fh-fBigendian).  */
6433965Sjdp
6533965Sjdpvoid
6633965Sjdp_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
6733965Sjdp     int bigend;
6833965Sjdp     const struct tir_ext *ext_copy;
6933965Sjdp     TIR *intern;
7033965Sjdp{
7133965Sjdp  struct tir_ext ext[1];
7233965Sjdp
7333965Sjdp  *ext = *ext_copy;		/* Make it reasonable to do in-place.  */
7477298Sobrien
7577298Sobrien  /* now the fun stuff...  */
7633965Sjdp  if (bigend) {
7733965Sjdp    intern->fBitfield   = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG);
7833965Sjdp    intern->continued   = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG);
7933965Sjdp    intern->bt          = (ext->t_bits1[0] & TIR_BITS1_BT_BIG)
8033965Sjdp			>>		    TIR_BITS1_BT_SH_BIG;
8133965Sjdp    intern->tq4         = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG)
8233965Sjdp			>>		    TIR_BITS_TQ4_SH_BIG;
8333965Sjdp    intern->tq5         = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG)
8433965Sjdp			>>		    TIR_BITS_TQ5_SH_BIG;
8533965Sjdp    intern->tq0         = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG)
8633965Sjdp			>>		    TIR_BITS_TQ0_SH_BIG;
8733965Sjdp    intern->tq1         = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG)
8833965Sjdp			>>		    TIR_BITS_TQ1_SH_BIG;
8933965Sjdp    intern->tq2         = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG)
9033965Sjdp			>>		    TIR_BITS_TQ2_SH_BIG;
9133965Sjdp    intern->tq3         = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG)
9233965Sjdp			>>		    TIR_BITS_TQ3_SH_BIG;
9333965Sjdp  } else {
9433965Sjdp    intern->fBitfield   = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE);
9533965Sjdp    intern->continued   = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE);
9633965Sjdp    intern->bt          = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE)
9733965Sjdp			>>		    TIR_BITS1_BT_SH_LITTLE;
9833965Sjdp    intern->tq4         = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE)
9933965Sjdp			>>		    TIR_BITS_TQ4_SH_LITTLE;
10033965Sjdp    intern->tq5         = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE)
10133965Sjdp			>>		    TIR_BITS_TQ5_SH_LITTLE;
10233965Sjdp    intern->tq0         = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE)
10333965Sjdp			>>		    TIR_BITS_TQ0_SH_LITTLE;
10433965Sjdp    intern->tq1         = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE)
10533965Sjdp			>>		    TIR_BITS_TQ1_SH_LITTLE;
10633965Sjdp    intern->tq2         = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE)
10733965Sjdp			>>		    TIR_BITS_TQ2_SH_LITTLE;
10833965Sjdp    intern->tq3         = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE)
10933965Sjdp			>>		    TIR_BITS_TQ3_SH_LITTLE;
11033965Sjdp  }
11133965Sjdp
11233965Sjdp#ifdef TEST
11333965Sjdp  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
11477298Sobrien    abort ();
11533965Sjdp#endif
11633965Sjdp}
11733965Sjdp
11833965Sjdp/* Swap out a type information record.
11933965Sjdp   BIGEND says whether AUX symbols are big-endian or little-endian; this
12033965Sjdp   info comes from the file header record (fh-fBigendian).  */
12133965Sjdp
12233965Sjdpvoid
12333965Sjdp_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
12433965Sjdp     int bigend;
12533965Sjdp     const TIR *intern_copy;
12633965Sjdp     struct tir_ext *ext;
12733965Sjdp{
12833965Sjdp  TIR intern[1];
12933965Sjdp
13033965Sjdp  *intern = *intern_copy;	/* Make it reasonable to do in-place.  */
13177298Sobrien
13277298Sobrien  /* now the fun stuff...  */
13333965Sjdp  if (bigend) {
13433965Sjdp    ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0)
13533965Sjdp		       | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0)
13633965Sjdp		       | ((intern->bt << TIR_BITS1_BT_SH_BIG)
13733965Sjdp			  & TIR_BITS1_BT_BIG));
13833965Sjdp    ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG)
13933965Sjdp		       & TIR_BITS_TQ4_BIG)
14033965Sjdp		      | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG)
14133965Sjdp			 & TIR_BITS_TQ5_BIG));
14233965Sjdp    ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG)
14333965Sjdp		       & TIR_BITS_TQ0_BIG)
14433965Sjdp		      | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG)
14533965Sjdp			 & TIR_BITS_TQ1_BIG));
14633965Sjdp    ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG)
14733965Sjdp		       & TIR_BITS_TQ2_BIG)
14833965Sjdp		      | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG)
14933965Sjdp			 & TIR_BITS_TQ3_BIG));
15033965Sjdp  } else {
15133965Sjdp    ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0)
15233965Sjdp		       | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0)
15333965Sjdp		       | ((intern->bt << TIR_BITS1_BT_SH_LITTLE)
15433965Sjdp			  & TIR_BITS1_BT_LITTLE));
15533965Sjdp    ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE)
15633965Sjdp		       & TIR_BITS_TQ4_LITTLE)
15733965Sjdp		      | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE)
15833965Sjdp			 & TIR_BITS_TQ5_LITTLE));
15933965Sjdp    ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE)
16033965Sjdp		       & TIR_BITS_TQ0_LITTLE)
16133965Sjdp		      | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE)
16233965Sjdp			 & TIR_BITS_TQ1_LITTLE));
16333965Sjdp    ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE)
16433965Sjdp		       & TIR_BITS_TQ2_LITTLE)
16533965Sjdp		      | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE)
16633965Sjdp			 & TIR_BITS_TQ3_LITTLE));
16733965Sjdp  }
16833965Sjdp
16933965Sjdp#ifdef TEST
17033965Sjdp  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
17177298Sobrien    abort ();
17233965Sjdp#endif
17333965Sjdp}
17433965Sjdp
17533965Sjdp/* Swap in a relative symbol record.  BIGEND says whether it is in
17633965Sjdp   big-endian or little-endian format.*/
17733965Sjdp
17833965Sjdpvoid
17933965Sjdp_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
18033965Sjdp     int bigend;
18133965Sjdp     const struct rndx_ext *ext_copy;
18233965Sjdp     RNDXR *intern;
18333965Sjdp{
18433965Sjdp  struct rndx_ext ext[1];
18533965Sjdp
18633965Sjdp  *ext = *ext_copy;		/* Make it reasonable to do in-place.  */
18777298Sobrien
18877298Sobrien  /* now the fun stuff...  */
18933965Sjdp  if (bigend) {
19033965Sjdp    intern->rfd   = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG)
19133965Sjdp		  | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG)
19233965Sjdp		    		    >> RNDX_BITS1_RFD_SH_BIG);
19333965Sjdp    intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG)
19433965Sjdp		    		    << RNDX_BITS1_INDEX_SH_LEFT_BIG)
19533965Sjdp		  | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG)
19633965Sjdp		  | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG);
19733965Sjdp  } else {
19833965Sjdp    intern->rfd   = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE)
19933965Sjdp		  | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE)
20033965Sjdp		    		    << RNDX_BITS1_RFD_SH_LEFT_LITTLE);
20133965Sjdp    intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE)
20233965Sjdp		    		    >> RNDX_BITS1_INDEX_SH_LITTLE)
20333965Sjdp		  | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE)
20433965Sjdp		  | ((unsigned int) ext->r_bits[3]
20533965Sjdp		     << RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
20633965Sjdp  }
20733965Sjdp
20833965Sjdp#ifdef TEST
20933965Sjdp  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
21077298Sobrien    abort ();
21133965Sjdp#endif
21233965Sjdp}
21333965Sjdp
21433965Sjdp/* Swap out a relative symbol record.  BIGEND says whether it is in
21533965Sjdp   big-endian or little-endian format.*/
21633965Sjdp
21733965Sjdpvoid
21833965Sjdp_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
21933965Sjdp     int bigend;
22033965Sjdp     const RNDXR *intern_copy;
22133965Sjdp     struct rndx_ext *ext;
22233965Sjdp{
22333965Sjdp  RNDXR intern[1];
22433965Sjdp
22533965Sjdp  *intern = *intern_copy;	/* Make it reasonable to do in-place.  */
22677298Sobrien
22777298Sobrien  /* now the fun stuff...  */
22833965Sjdp  if (bigend) {
22933965Sjdp    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG;
23033965Sjdp    ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG)
23133965Sjdp		       & RNDX_BITS1_RFD_BIG)
23233965Sjdp		      | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG)
23333965Sjdp			 & RNDX_BITS1_INDEX_BIG));
23433965Sjdp    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG;
23533965Sjdp    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG;
23633965Sjdp  } else {
23733965Sjdp    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE;
23833965Sjdp    ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE)
23933965Sjdp		       & RNDX_BITS1_RFD_LITTLE)
24033965Sjdp		      | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE)
24133965Sjdp			 & RNDX_BITS1_INDEX_LITTLE));
24233965Sjdp    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE;
24333965Sjdp    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE;
24433965Sjdp  }
24533965Sjdp
24633965Sjdp#ifdef TEST
24733965Sjdp  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
24877298Sobrien    abort ();
24933965Sjdp#endif
25033965Sjdp}
25133965Sjdp
25233965Sjdp/* The minimum amount of data to allocate.  */
25333965Sjdp#define ALLOC_SIZE (4064)
25433965Sjdp
25533965Sjdp/* Add bytes to a buffer.  Return success.  */
25633965Sjdp
257130561Sobrienstatic bfd_boolean
25833965Sjdpecoff_add_bytes (buf, bufend, need)
25933965Sjdp     char **buf;
26033965Sjdp     char **bufend;
26133965Sjdp     size_t need;
26233965Sjdp{
26333965Sjdp  size_t have;
26433965Sjdp  size_t want;
26533965Sjdp  char *newbuf;
26633965Sjdp
26733965Sjdp  have = *bufend - *buf;
26833965Sjdp  if (have > need)
26933965Sjdp    want = ALLOC_SIZE;
27033965Sjdp  else
27133965Sjdp    {
27233965Sjdp      want = need - have;
27333965Sjdp      if (want < ALLOC_SIZE)
27433965Sjdp	want = ALLOC_SIZE;
27533965Sjdp    }
27689857Sobrien  newbuf = (char *) bfd_realloc (*buf, (bfd_size_type) have + want);
27733965Sjdp  if (newbuf == NULL)
278130561Sobrien    return FALSE;
27933965Sjdp  *buf = newbuf;
28033965Sjdp  *bufend = *buf + have + want;
281130561Sobrien  return TRUE;
28233965Sjdp}
28333965Sjdp
28433965Sjdp/* We keep a hash table which maps strings to numbers.  We use it to
28533965Sjdp   map FDR names to indices in the output file, and to map local
28633965Sjdp   strings when combining stabs debugging information.  */
28733965Sjdp
28833965Sjdpstruct string_hash_entry
28933965Sjdp{
29033965Sjdp  struct bfd_hash_entry root;
29133965Sjdp  /* FDR index or string table offset.  */
29233965Sjdp  long val;
29333965Sjdp  /* Next entry in string table.  */
29433965Sjdp  struct string_hash_entry *next;
29533965Sjdp};
29633965Sjdp
29733965Sjdpstruct string_hash_table
29833965Sjdp{
29933965Sjdp  struct bfd_hash_table table;
30033965Sjdp};
30133965Sjdp
30233965Sjdp/* Routine to create an entry in a string hash table.  */
30333965Sjdp
30433965Sjdpstatic struct bfd_hash_entry *
30533965Sjdpstring_hash_newfunc (entry, table, string)
30633965Sjdp     struct bfd_hash_entry *entry;
30733965Sjdp     struct bfd_hash_table *table;
30833965Sjdp     const char *string;
30933965Sjdp{
31033965Sjdp  struct string_hash_entry *ret = (struct string_hash_entry *) entry;
31133965Sjdp
31233965Sjdp  /* Allocate the structure if it has not already been allocated by a
31333965Sjdp     subclass.  */
31433965Sjdp  if (ret == (struct string_hash_entry *) NULL)
31533965Sjdp    ret = ((struct string_hash_entry *)
31633965Sjdp	   bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
31733965Sjdp  if (ret == (struct string_hash_entry *) NULL)
31833965Sjdp    return NULL;
31933965Sjdp
32033965Sjdp  /* Call the allocation method of the superclass.  */
32133965Sjdp  ret = ((struct string_hash_entry *)
32233965Sjdp	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
32333965Sjdp
32433965Sjdp  if (ret)
32533965Sjdp    {
32633965Sjdp      /* Initialize the local fields.  */
32733965Sjdp      ret->val = -1;
32833965Sjdp      ret->next = NULL;
32933965Sjdp    }
33033965Sjdp
33133965Sjdp  return (struct bfd_hash_entry *) ret;
33233965Sjdp}
33333965Sjdp
33433965Sjdp/* Look up an entry in an string hash table.  */
33533965Sjdp
33633965Sjdp#define string_hash_lookup(t, string, create, copy) \
33733965Sjdp  ((struct string_hash_entry *) \
33833965Sjdp   bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
33933965Sjdp
34033965Sjdp/* We can't afford to read in all the debugging information when we do
34133965Sjdp   a link.  Instead, we build a list of these structures to show how
34233965Sjdp   different parts of the input file map to the output file.  */
34333965Sjdp
34433965Sjdpstruct shuffle
34533965Sjdp{
34633965Sjdp  /* The next entry in this linked list.  */
34733965Sjdp  struct shuffle *next;
34833965Sjdp  /* The length of the information.  */
34933965Sjdp  unsigned long size;
35033965Sjdp  /* Whether this information comes from a file or not.  */
351130561Sobrien  bfd_boolean filep;
35233965Sjdp  union
35333965Sjdp    {
35433965Sjdp      struct
35533965Sjdp	{
35633965Sjdp	  /* The BFD the data comes from.  */
35733965Sjdp	  bfd *input_bfd;
35833965Sjdp	  /* The offset within input_bfd.  */
35933965Sjdp	  file_ptr offset;
36033965Sjdp	} file;
36133965Sjdp      /* The data to be written out.  */
36233965Sjdp      PTR memory;
36333965Sjdp    } u;
36433965Sjdp};
36533965Sjdp
36633965Sjdp/* This structure holds information across calls to
36733965Sjdp   bfd_ecoff_debug_accumulate.  */
36833965Sjdp
36933965Sjdpstruct accumulate
37033965Sjdp{
37133965Sjdp  /* The FDR hash table.  */
37233965Sjdp  struct string_hash_table fdr_hash;
37333965Sjdp  /* The strings hash table.  */
37433965Sjdp  struct string_hash_table str_hash;
37533965Sjdp  /* Linked lists describing how to shuffle the input debug
37633965Sjdp     information into the output file.  We keep a pointer to both the
37733965Sjdp     head and the tail.  */
37833965Sjdp  struct shuffle *line;
37933965Sjdp  struct shuffle *line_end;
38033965Sjdp  struct shuffle *pdr;
38133965Sjdp  struct shuffle *pdr_end;
38233965Sjdp  struct shuffle *sym;
38333965Sjdp  struct shuffle *sym_end;
38433965Sjdp  struct shuffle *opt;
38533965Sjdp  struct shuffle *opt_end;
38633965Sjdp  struct shuffle *aux;
38733965Sjdp  struct shuffle *aux_end;
38833965Sjdp  struct shuffle *ss;
38933965Sjdp  struct shuffle *ss_end;
39033965Sjdp  struct string_hash_entry *ss_hash;
39133965Sjdp  struct string_hash_entry *ss_hash_end;
39233965Sjdp  struct shuffle *fdr;
39333965Sjdp  struct shuffle *fdr_end;
39433965Sjdp  struct shuffle *rfd;
39533965Sjdp  struct shuffle *rfd_end;
39633965Sjdp  /* The size of the largest file shuffle.  */
39733965Sjdp  unsigned long largest_file_shuffle;
39833965Sjdp  /* An objalloc for debugging information.  */
39933965Sjdp  struct objalloc *memory;
40033965Sjdp};
40133965Sjdp
40233965Sjdp/* Add a file entry to a shuffle list.  */
40333965Sjdp
404130561Sobrienstatic bfd_boolean add_file_shuffle
405130561Sobrien  PARAMS ((struct accumulate *, struct shuffle **, struct shuffle **,
406130561Sobrien	   bfd *, file_ptr, unsigned long));
40733965Sjdp
408130561Sobrienstatic bfd_boolean
40933965Sjdpadd_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
41033965Sjdp     struct accumulate *ainfo;
41133965Sjdp     struct shuffle **head;
41233965Sjdp     struct shuffle **tail;
41333965Sjdp     bfd *input_bfd;
41433965Sjdp     file_ptr offset;
41533965Sjdp     unsigned long size;
41633965Sjdp{
41733965Sjdp  struct shuffle *n;
41833965Sjdp
41933965Sjdp  if (*tail != (struct shuffle *) NULL
42033965Sjdp      && (*tail)->filep
42133965Sjdp      && (*tail)->u.file.input_bfd == input_bfd
42233965Sjdp      && (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset)
42333965Sjdp    {
42433965Sjdp      /* Just merge this entry onto the existing one.  */
42533965Sjdp      (*tail)->size += size;
42633965Sjdp      if ((*tail)->size > ainfo->largest_file_shuffle)
42733965Sjdp	ainfo->largest_file_shuffle = (*tail)->size;
428130561Sobrien      return TRUE;
42933965Sjdp    }
43033965Sjdp
43133965Sjdp  n = (struct shuffle *) objalloc_alloc (ainfo->memory,
43233965Sjdp					 sizeof (struct shuffle));
43333965Sjdp  if (!n)
43433965Sjdp    {
43533965Sjdp      bfd_set_error (bfd_error_no_memory);
436130561Sobrien      return FALSE;
43733965Sjdp    }
43833965Sjdp  n->next = NULL;
43933965Sjdp  n->size = size;
440130561Sobrien  n->filep = TRUE;
44133965Sjdp  n->u.file.input_bfd = input_bfd;
44233965Sjdp  n->u.file.offset = offset;
44333965Sjdp  if (*head == (struct shuffle *) NULL)
44433965Sjdp    *head = n;
44533965Sjdp  if (*tail != (struct shuffle *) NULL)
44633965Sjdp    (*tail)->next = n;
44733965Sjdp  *tail = n;
44833965Sjdp  if (size > ainfo->largest_file_shuffle)
44933965Sjdp    ainfo->largest_file_shuffle = size;
450130561Sobrien  return TRUE;
45133965Sjdp}
45233965Sjdp
45333965Sjdp/* Add a memory entry to a shuffle list.  */
45433965Sjdp
455130561Sobrienstatic bfd_boolean add_memory_shuffle
456130561Sobrien  PARAMS ((struct accumulate *, struct shuffle **head, struct shuffle **tail,
457130561Sobrien	   bfd_byte *data, unsigned long size));
45833965Sjdp
459130561Sobrienstatic bfd_boolean
46033965Sjdpadd_memory_shuffle (ainfo, head, tail, data, size)
46133965Sjdp     struct accumulate *ainfo;
46233965Sjdp     struct shuffle **head;
46333965Sjdp     struct shuffle **tail;
46433965Sjdp     bfd_byte *data;
46533965Sjdp     unsigned long size;
46633965Sjdp{
46733965Sjdp  struct shuffle *n;
46877298Sobrien
46933965Sjdp  n = (struct shuffle *) objalloc_alloc (ainfo->memory,
47033965Sjdp					 sizeof (struct shuffle));
47133965Sjdp  if (!n)
47233965Sjdp    {
47333965Sjdp      bfd_set_error (bfd_error_no_memory);
474130561Sobrien      return FALSE;
47533965Sjdp    }
47633965Sjdp  n->next = NULL;
47733965Sjdp  n->size = size;
478130561Sobrien  n->filep = FALSE;
47933965Sjdp  n->u.memory = (PTR) data;
48033965Sjdp  if (*head == (struct shuffle *) NULL)
48133965Sjdp    *head = n;
48233965Sjdp  if (*tail != (struct shuffle *) NULL)
48333965Sjdp    (*tail)->next = n;
48433965Sjdp  *tail = n;
485130561Sobrien  return TRUE;
48633965Sjdp}
48733965Sjdp
48833965Sjdp/* Initialize the FDR hash table.  This returns a handle which is then
48933965Sjdp   passed in to bfd_ecoff_debug_accumulate, et. al.  */
49033965Sjdp
49133965SjdpPTR
49233965Sjdpbfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
49360484Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
49433965Sjdp     struct ecoff_debug_info *output_debug;
49560484Sobrien     const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
49633965Sjdp     struct bfd_link_info *info;
49733965Sjdp{
49833965Sjdp  struct accumulate *ainfo;
49989857Sobrien  bfd_size_type amt = sizeof (struct accumulate);
50033965Sjdp
50189857Sobrien  ainfo = (struct accumulate *) bfd_malloc (amt);
50233965Sjdp  if (!ainfo)
50333965Sjdp    return NULL;
504218822Sdim  if (!bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc,
505218822Sdim			      sizeof (struct string_hash_entry), 1021))
50633965Sjdp    return NULL;
50733965Sjdp
50833965Sjdp  ainfo->line = NULL;
50933965Sjdp  ainfo->line_end = NULL;
51033965Sjdp  ainfo->pdr = NULL;
51133965Sjdp  ainfo->pdr_end = NULL;
51233965Sjdp  ainfo->sym = NULL;
51333965Sjdp  ainfo->sym_end = NULL;
51433965Sjdp  ainfo->opt = NULL;
51533965Sjdp  ainfo->opt_end = NULL;
51633965Sjdp  ainfo->aux = NULL;
51733965Sjdp  ainfo->aux_end = NULL;
51833965Sjdp  ainfo->ss = NULL;
51933965Sjdp  ainfo->ss_end = NULL;
52033965Sjdp  ainfo->ss_hash = NULL;
52133965Sjdp  ainfo->ss_hash_end = NULL;
52233965Sjdp  ainfo->fdr = NULL;
52333965Sjdp  ainfo->fdr_end = NULL;
52433965Sjdp  ainfo->rfd = NULL;
52533965Sjdp  ainfo->rfd_end = NULL;
52633965Sjdp
52733965Sjdp  ainfo->largest_file_shuffle = 0;
52833965Sjdp
529130561Sobrien  if (! info->relocatable)
53033965Sjdp    {
531218822Sdim      if (!bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc,
532218822Sdim				sizeof (struct string_hash_entry)))
53333965Sjdp	return NULL;
53433965Sjdp
53533965Sjdp      /* The first entry in the string table is the empty string.  */
53633965Sjdp      output_debug->symbolic_header.issMax = 1;
53733965Sjdp    }
53833965Sjdp
53933965Sjdp  ainfo->memory = objalloc_create ();
54033965Sjdp  if (ainfo->memory == NULL)
54133965Sjdp    {
54233965Sjdp      bfd_set_error (bfd_error_no_memory);
54333965Sjdp      return NULL;
54433965Sjdp    }
54533965Sjdp
54633965Sjdp  return (PTR) ainfo;
54733965Sjdp}
54833965Sjdp
54933965Sjdp/* Free the accumulated debugging information.  */
55033965Sjdp
55133965Sjdpvoid
55233965Sjdpbfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
55333965Sjdp     PTR handle;
55460484Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
55560484Sobrien     struct ecoff_debug_info *output_debug ATTRIBUTE_UNUSED;
55660484Sobrien     const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
55733965Sjdp     struct bfd_link_info *info;
55833965Sjdp{
55933965Sjdp  struct accumulate *ainfo = (struct accumulate *) handle;
56077298Sobrien
56133965Sjdp  bfd_hash_table_free (&ainfo->fdr_hash.table);
56233965Sjdp
563130561Sobrien  if (! info->relocatable)
56433965Sjdp    bfd_hash_table_free (&ainfo->str_hash.table);
56533965Sjdp
56633965Sjdp  objalloc_free (ainfo->memory);
56733965Sjdp
56833965Sjdp  free (ainfo);
56933965Sjdp}
57033965Sjdp
57133965Sjdp/* Accumulate the debugging information from INPUT_BFD into
57233965Sjdp   OUTPUT_BFD.  The INPUT_DEBUG argument points to some ECOFF
57333965Sjdp   debugging information which we want to link into the information
57433965Sjdp   pointed to by the OUTPUT_DEBUG argument.  OUTPUT_SWAP and
57533965Sjdp   INPUT_SWAP point to the swapping information needed.  INFO is the
57633965Sjdp   linker information structure.  HANDLE is returned by
57733965Sjdp   bfd_ecoff_debug_init.  */
57833965Sjdp
579130561Sobrienbfd_boolean
58033965Sjdpbfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
58133965Sjdp			    input_bfd, input_debug, input_swap,
58233965Sjdp			    info)
58333965Sjdp     PTR handle;
58433965Sjdp     bfd *output_bfd;
58533965Sjdp     struct ecoff_debug_info *output_debug;
58633965Sjdp     const struct ecoff_debug_swap *output_swap;
58733965Sjdp     bfd *input_bfd;
58833965Sjdp     struct ecoff_debug_info *input_debug;
58933965Sjdp     const struct ecoff_debug_swap *input_swap;
59033965Sjdp     struct bfd_link_info *info;
59133965Sjdp{
59233965Sjdp  struct accumulate *ainfo = (struct accumulate *) handle;
59333965Sjdp  void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
59433965Sjdp    = input_swap->swap_sym_in;
59533965Sjdp  void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
59633965Sjdp    = input_swap->swap_rfd_in;
59733965Sjdp  void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
59833965Sjdp    = output_swap->swap_sym_out;
59933965Sjdp  void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR))
60033965Sjdp    = output_swap->swap_fdr_out;
60133965Sjdp  void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR))
60233965Sjdp    = output_swap->swap_rfd_out;
60333965Sjdp  bfd_size_type external_pdr_size = output_swap->external_pdr_size;
60433965Sjdp  bfd_size_type external_sym_size = output_swap->external_sym_size;
60533965Sjdp  bfd_size_type external_opt_size = output_swap->external_opt_size;
60633965Sjdp  bfd_size_type external_fdr_size = output_swap->external_fdr_size;
60733965Sjdp  bfd_size_type external_rfd_size = output_swap->external_rfd_size;
60833965Sjdp  HDRR * const output_symhdr = &output_debug->symbolic_header;
60933965Sjdp  HDRR * const input_symhdr = &input_debug->symbolic_header;
61033965Sjdp  bfd_vma section_adjust[scMax];
61133965Sjdp  asection *sec;
61233965Sjdp  bfd_byte *fdr_start;
61333965Sjdp  bfd_byte *fdr_ptr;
61433965Sjdp  bfd_byte *fdr_end;
61533965Sjdp  bfd_size_type fdr_add;
61633965Sjdp  unsigned int copied;
61733965Sjdp  RFDT i;
61833965Sjdp  unsigned long sz;
61933965Sjdp  bfd_byte *rfd_out;
62033965Sjdp  bfd_byte *rfd_in;
62133965Sjdp  bfd_byte *rfd_end;
62233965Sjdp  long newrfdbase = 0;
62333965Sjdp  long oldrfdbase = 0;
62433965Sjdp  bfd_byte *fdr_out;
62589857Sobrien  bfd_size_type amt;
62633965Sjdp
62733965Sjdp  /* Use section_adjust to hold the value to add to a symbol in a
62833965Sjdp     particular section.  */
62933965Sjdp  memset ((PTR) section_adjust, 0, sizeof section_adjust);
63033965Sjdp
63133965Sjdp#define SET(name, indx) \
63233965Sjdp  sec = bfd_get_section_by_name (input_bfd, name); \
63333965Sjdp  if (sec != NULL) \
63433965Sjdp    section_adjust[indx] = (sec->output_section->vma \
63533965Sjdp			    + sec->output_offset \
63633965Sjdp			    - sec->vma);
63733965Sjdp
63833965Sjdp  SET (".text", scText);
63933965Sjdp  SET (".data", scData);
64033965Sjdp  SET (".bss", scBss);
64133965Sjdp  SET (".sdata", scSData);
64233965Sjdp  SET (".sbss", scSBss);
64333965Sjdp  /* scRdata section may be either .rdata or .rodata.  */
64433965Sjdp  SET (".rdata", scRData);
64533965Sjdp  SET (".rodata", scRData);
64633965Sjdp  SET (".init", scInit);
64733965Sjdp  SET (".fini", scFini);
64833965Sjdp  SET (".rconst", scRConst);
64933965Sjdp
65033965Sjdp#undef SET
65133965Sjdp
65233965Sjdp  /* Find all the debugging information based on the FDR's.  We need
65333965Sjdp     to handle them whether they are swapped or not.  */
65433965Sjdp  if (input_debug->fdr != (FDR *) NULL)
65533965Sjdp    {
65633965Sjdp      fdr_start = (bfd_byte *) input_debug->fdr;
65733965Sjdp      fdr_add = sizeof (FDR);
65833965Sjdp    }
65933965Sjdp  else
66033965Sjdp    {
66133965Sjdp      fdr_start = (bfd_byte *) input_debug->external_fdr;
66233965Sjdp      fdr_add = input_swap->external_fdr_size;
66333965Sjdp    }
66433965Sjdp  fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add;
66533965Sjdp
66689857Sobrien  amt = input_symhdr->ifdMax;
66789857Sobrien  amt *= sizeof (RFDT);
66889857Sobrien  input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, amt);
66933965Sjdp
67033965Sjdp  sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size;
67133965Sjdp  rfd_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
67233965Sjdp  if (!input_debug->ifdmap || !rfd_out)
67333965Sjdp    {
67433965Sjdp      bfd_set_error (bfd_error_no_memory);
675130561Sobrien      return FALSE;
67633965Sjdp    }
67733965Sjdp  if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz))
678130561Sobrien    return FALSE;
67933965Sjdp
68033965Sjdp  copied = 0;
68133965Sjdp
68233965Sjdp  /* Look through the FDR's to see which ones we are going to include
68333965Sjdp     in the final output.  We do not want duplicate FDR information
68433965Sjdp     for header files, because ECOFF debugging is often very large.
68533965Sjdp     When we find an FDR with no line information which can be merged,
68633965Sjdp     we look it up in a hash table to ensure that we only include it
68733965Sjdp     once.  We keep a table mapping FDR numbers to the final number
68833965Sjdp     they get with the BFD, so that we can refer to it when we write
68933965Sjdp     out the external symbols.  */
69033965Sjdp  for (fdr_ptr = fdr_start, i = 0;
69133965Sjdp       fdr_ptr < fdr_end;
69233965Sjdp       fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size)
69333965Sjdp    {
69433965Sjdp      FDR fdr;
69533965Sjdp
69633965Sjdp      if (input_debug->fdr != (FDR *) NULL)
69733965Sjdp	fdr = *(FDR *) fdr_ptr;
69833965Sjdp      else
69933965Sjdp	(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
70033965Sjdp
70133965Sjdp      /* See if this FDR can be merged with an existing one.  */
70233965Sjdp      if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge)
70333965Sjdp	{
70433965Sjdp	  const char *name;
70533965Sjdp	  char *lookup;
70633965Sjdp	  struct string_hash_entry *fh;
70733965Sjdp
70833965Sjdp	  /* We look up a string formed from the file name and the
70938889Sjdp	     number of symbols and aux entries.  Sometimes an include
71038889Sjdp	     file will conditionally define a typedef or something
71138889Sjdp	     based on the order of include files.  Using the number of
71238889Sjdp	     symbols and aux entries as a hash reduces the chance that
71338889Sjdp	     we will merge symbol information that should not be
71438889Sjdp	     merged.  */
71533965Sjdp	  name = input_debug->ss + fdr.issBase + fdr.rss;
71633965Sjdp
71789857Sobrien	  lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20);
71833965Sjdp	  if (lookup == NULL)
719130561Sobrien	    return FALSE;
72038889Sjdp	  sprintf (lookup, "%s %lx %lx", name, fdr.csym, fdr.caux);
72133965Sjdp
722130561Sobrien	  fh = string_hash_lookup (&ainfo->fdr_hash, lookup, TRUE, TRUE);
72333965Sjdp	  free (lookup);
72433965Sjdp	  if (fh == (struct string_hash_entry *) NULL)
725130561Sobrien	    return FALSE;
72633965Sjdp
72733965Sjdp	  if (fh->val != -1)
72833965Sjdp	    {
72933965Sjdp	      input_debug->ifdmap[i] = fh->val;
73033965Sjdp	      (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i,
73133965Sjdp			       (PTR) rfd_out);
73233965Sjdp
73333965Sjdp	      /* Don't copy this FDR.  */
73433965Sjdp	      continue;
73533965Sjdp	    }
73633965Sjdp
73733965Sjdp	  fh->val = output_symhdr->ifdMax + copied;
73833965Sjdp	}
73933965Sjdp
74033965Sjdp      input_debug->ifdmap[i] = output_symhdr->ifdMax + copied;
74133965Sjdp      (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out);
74233965Sjdp      ++copied;
74333965Sjdp    }
74433965Sjdp
74533965Sjdp  newrfdbase = output_symhdr->crfd;
74633965Sjdp  output_symhdr->crfd += input_symhdr->ifdMax;
74733965Sjdp
74833965Sjdp  /* Copy over any existing RFD's.  RFD's are only created by the
74933965Sjdp     linker, so this will only happen for input files which are the
75033965Sjdp     result of a partial link.  */
75133965Sjdp  rfd_in = (bfd_byte *) input_debug->external_rfd;
75233965Sjdp  rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size;
75333965Sjdp  for (;
75433965Sjdp       rfd_in < rfd_end;
75533965Sjdp       rfd_in += input_swap->external_rfd_size)
75633965Sjdp    {
75733965Sjdp      RFDT rfd;
75833965Sjdp
75933965Sjdp      (*swap_rfd_in) (input_bfd, (PTR) rfd_in, &rfd);
76033965Sjdp      BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax);
76133965Sjdp      rfd = input_debug->ifdmap[rfd];
76233965Sjdp      (*swap_rfd_out) (output_bfd, &rfd, (PTR) rfd_out);
76333965Sjdp      rfd_out += external_rfd_size;
76433965Sjdp    }
76533965Sjdp
76633965Sjdp  oldrfdbase = output_symhdr->crfd;
76733965Sjdp  output_symhdr->crfd += input_symhdr->crfd;
76833965Sjdp
76933965Sjdp  /* Look through the FDR's and copy over all associated debugging
77033965Sjdp     information.  */
77133965Sjdp  sz = copied * external_fdr_size;
77233965Sjdp  fdr_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
77333965Sjdp  if (!fdr_out)
77433965Sjdp    {
77533965Sjdp      bfd_set_error (bfd_error_no_memory);
776130561Sobrien      return FALSE;
77733965Sjdp    }
77833965Sjdp  if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz))
779130561Sobrien    return FALSE;
78033965Sjdp  for (fdr_ptr = fdr_start, i = 0;
78133965Sjdp       fdr_ptr < fdr_end;
78233965Sjdp       fdr_ptr += fdr_add, i++)
78333965Sjdp    {
78433965Sjdp      FDR fdr;
78533965Sjdp      bfd_byte *sym_out;
78633965Sjdp      bfd_byte *lraw_src;
78733965Sjdp      bfd_byte *lraw_end;
788130561Sobrien      bfd_boolean fgotfilename;
78933965Sjdp
79033965Sjdp      if (input_debug->ifdmap[i] < output_symhdr->ifdMax)
79133965Sjdp	{
79233965Sjdp	  /* We are not copying this FDR.  */
79333965Sjdp	  continue;
79433965Sjdp	}
79533965Sjdp
79633965Sjdp      if (input_debug->fdr != (FDR *) NULL)
79733965Sjdp	fdr = *(FDR *) fdr_ptr;
79833965Sjdp      else
79933965Sjdp	(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
80033965Sjdp
80133965Sjdp      /* FIXME: It is conceivable that this FDR points to the .init or
80233965Sjdp	 .fini section, in which case this will not do the right
80333965Sjdp	 thing.  */
80433965Sjdp      fdr.adr += section_adjust[scText];
80533965Sjdp
80633965Sjdp      /* Swap in the local symbols, adjust their values, and swap them
80733965Sjdp	 out again.  */
808130561Sobrien      fgotfilename = FALSE;
80933965Sjdp      sz = fdr.csym * external_sym_size;
81033965Sjdp      sym_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
81133965Sjdp      if (!sym_out)
81233965Sjdp	{
81333965Sjdp	  bfd_set_error (bfd_error_no_memory);
814130561Sobrien	  return FALSE;
81533965Sjdp	}
81633965Sjdp      if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out,
81733965Sjdp			       sz))
818130561Sobrien	return FALSE;
81933965Sjdp      lraw_src = ((bfd_byte *) input_debug->external_sym
82033965Sjdp		  + fdr.isymBase * input_swap->external_sym_size);
82133965Sjdp      lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size;
82233965Sjdp      for (;  lraw_src < lraw_end;  lraw_src += input_swap->external_sym_size)
82333965Sjdp	{
82433965Sjdp	  SYMR internal_sym;
82533965Sjdp
82633965Sjdp	  (*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym);
82733965Sjdp
82833965Sjdp	  BFD_ASSERT (internal_sym.sc != scCommon
82933965Sjdp		      && internal_sym.sc != scSCommon);
83033965Sjdp
83133965Sjdp	  /* Adjust the symbol value if appropriate.  */
83233965Sjdp	  switch (internal_sym.st)
83333965Sjdp	    {
83433965Sjdp	    case stNil:
83533965Sjdp	      if (ECOFF_IS_STAB (&internal_sym))
83633965Sjdp		break;
83733965Sjdp	      /* Fall through.  */
83833965Sjdp	    case stGlobal:
83933965Sjdp	    case stStatic:
84033965Sjdp	    case stLabel:
84133965Sjdp	    case stProc:
84233965Sjdp	    case stStaticProc:
84333965Sjdp	      internal_sym.value += section_adjust[internal_sym.sc];
84433965Sjdp	      break;
84533965Sjdp
84633965Sjdp	    default:
84733965Sjdp	      break;
84833965Sjdp	    }
84933965Sjdp
85033965Sjdp	  /* If we are doing a final link, we hash all the strings in
85133965Sjdp	     the local symbol table together.  This reduces the amount
85233965Sjdp	     of space required by debugging information.  We don't do
853130561Sobrien	     this when performing a relocatable link because it would
85433965Sjdp	     prevent us from easily merging different FDR's.  */
855130561Sobrien	  if (! info->relocatable)
85633965Sjdp	    {
857130561Sobrien	      bfd_boolean ffilename;
85833965Sjdp	      const char *name;
85933965Sjdp
86033965Sjdp	      if (! fgotfilename && internal_sym.iss == fdr.rss)
861130561Sobrien		ffilename = TRUE;
86233965Sjdp	      else
863130561Sobrien		ffilename = FALSE;
86433965Sjdp
86533965Sjdp	      /* Hash the name into the string table.  */
86633965Sjdp	      name = input_debug->ss + fdr.issBase + internal_sym.iss;
86733965Sjdp	      if (*name == '\0')
86833965Sjdp		internal_sym.iss = 0;
86933965Sjdp	      else
87033965Sjdp		{
87133965Sjdp		  struct string_hash_entry *sh;
87233965Sjdp
873130561Sobrien		  sh = string_hash_lookup (&ainfo->str_hash, name, TRUE, TRUE);
87433965Sjdp		  if (sh == (struct string_hash_entry *) NULL)
875130561Sobrien		    return FALSE;
87633965Sjdp		  if (sh->val == -1)
87733965Sjdp		    {
87833965Sjdp		      sh->val = output_symhdr->issMax;
87933965Sjdp		      output_symhdr->issMax += strlen (name) + 1;
88033965Sjdp		      if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
88133965Sjdp			ainfo->ss_hash = sh;
88233965Sjdp		      if (ainfo->ss_hash_end
88333965Sjdp			  != (struct string_hash_entry *) NULL)
88433965Sjdp			ainfo->ss_hash_end->next = sh;
88533965Sjdp		      ainfo->ss_hash_end = sh;
88633965Sjdp		    }
88733965Sjdp		  internal_sym.iss = sh->val;
88833965Sjdp		}
88933965Sjdp
89033965Sjdp	      if (ffilename)
89133965Sjdp		{
89233965Sjdp		  fdr.rss = internal_sym.iss;
893130561Sobrien		  fgotfilename = TRUE;
89433965Sjdp		}
89533965Sjdp	    }
89633965Sjdp
89733965Sjdp	  (*swap_sym_out) (output_bfd, &internal_sym, sym_out);
89833965Sjdp	  sym_out += external_sym_size;
89933965Sjdp	}
90033965Sjdp
90133965Sjdp      fdr.isymBase = output_symhdr->isymMax;
90233965Sjdp      output_symhdr->isymMax += fdr.csym;
90333965Sjdp
90433965Sjdp      /* Copy the information that does not need swapping.  */
90533965Sjdp
90633965Sjdp      /* FIXME: If we are relaxing, we need to adjust the line
90733965Sjdp	 numbers.  Frankly, forget it.  Anybody using stabs debugging
90833965Sjdp	 information will not use this line number information, and
90933965Sjdp	 stabs are adjusted correctly.  */
91033965Sjdp      if (fdr.cbLine > 0)
91133965Sjdp	{
91289857Sobrien	  file_ptr pos = input_symhdr->cbLineOffset + fdr.cbLineOffset;
91333965Sjdp	  if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end,
91489857Sobrien				 input_bfd, pos, (unsigned long) fdr.cbLine))
915130561Sobrien	    return FALSE;
91633965Sjdp	  fdr.ilineBase = output_symhdr->ilineMax;
91733965Sjdp	  fdr.cbLineOffset = output_symhdr->cbLine;
91833965Sjdp	  output_symhdr->ilineMax += fdr.cline;
91933965Sjdp	  output_symhdr->cbLine += fdr.cbLine;
92033965Sjdp	}
92133965Sjdp      if (fdr.caux > 0)
92233965Sjdp	{
92389857Sobrien	  file_ptr pos = (input_symhdr->cbAuxOffset
92489857Sobrien			  + fdr.iauxBase * sizeof (union aux_ext));
92533965Sjdp	  if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end,
92689857Sobrien				 input_bfd, pos,
92733965Sjdp				 fdr.caux * sizeof (union aux_ext)))
928130561Sobrien	    return FALSE;
92933965Sjdp	  fdr.iauxBase = output_symhdr->iauxMax;
93033965Sjdp	  output_symhdr->iauxMax += fdr.caux;
93133965Sjdp	}
932130561Sobrien      if (! info->relocatable)
93333965Sjdp	{
93433965Sjdp
93533965Sjdp	  /* When are are hashing strings, we lie about the number of
93633965Sjdp	     strings attached to each FDR.  We need to set cbSs
93733965Sjdp	     because some versions of dbx apparently use it to decide
93833965Sjdp	     how much of the string table to read in.  */
93933965Sjdp	  fdr.issBase = 0;
94033965Sjdp	  fdr.cbSs = output_symhdr->issMax;
94133965Sjdp	}
94233965Sjdp      else if (fdr.cbSs > 0)
94333965Sjdp	{
94489857Sobrien	  file_ptr pos = input_symhdr->cbSsOffset + fdr.issBase;
94533965Sjdp	  if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end,
94689857Sobrien				 input_bfd, pos, (unsigned long) fdr.cbSs))
947130561Sobrien	    return FALSE;
94833965Sjdp	  fdr.issBase = output_symhdr->issMax;
94933965Sjdp	  output_symhdr->issMax += fdr.cbSs;
95033965Sjdp	}
95133965Sjdp
952218822Sdim      if (output_bfd->xvec->header_byteorder
953218822Sdim	  == input_bfd->xvec->header_byteorder)
95433965Sjdp	{
95533965Sjdp	  /* The two BFD's have the same endianness, and we don't have
95633965Sjdp	     to adjust the PDR addresses, so simply copying the
95733965Sjdp	     information will suffice.  */
95833965Sjdp	  BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size);
95933965Sjdp	  if (fdr.cpd > 0)
96033965Sjdp	    {
96189857Sobrien	      file_ptr pos = (input_symhdr->cbPdOffset
96289857Sobrien			      + fdr.ipdFirst * external_pdr_size);
96389857Sobrien	      unsigned long size = fdr.cpd * external_pdr_size;
96433965Sjdp	      if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end,
96589857Sobrien				     input_bfd, pos, size))
966130561Sobrien		return FALSE;
96733965Sjdp	    }
96833965Sjdp	  BFD_ASSERT (external_opt_size == input_swap->external_opt_size);
96933965Sjdp	  if (fdr.copt > 0)
97033965Sjdp	    {
97189857Sobrien	      file_ptr pos = (input_symhdr->cbOptOffset
97289857Sobrien			      + fdr.ioptBase * external_opt_size);
97389857Sobrien	      unsigned long size = fdr.copt * external_opt_size;
97433965Sjdp	      if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end,
97589857Sobrien				     input_bfd, pos, size))
976130561Sobrien		return FALSE;
97733965Sjdp	    }
97833965Sjdp	}
97933965Sjdp      else
98033965Sjdp	{
98133965Sjdp	  bfd_size_type outsz, insz;
98233965Sjdp	  bfd_byte *in;
98333965Sjdp	  bfd_byte *end;
98433965Sjdp	  bfd_byte *out;
98533965Sjdp
98633965Sjdp	  /* The two BFD's have different endianness, so we must swap
98733965Sjdp	     everything in and out.  This code would always work, but
98833965Sjdp	     it would be unnecessarily slow in the normal case.  */
98933965Sjdp	  outsz = external_pdr_size;
99033965Sjdp	  insz = input_swap->external_pdr_size;
99133965Sjdp	  in = ((bfd_byte *) input_debug->external_pdr
99233965Sjdp		+ fdr.ipdFirst * insz);
99333965Sjdp	  end = in + fdr.cpd * insz;
99433965Sjdp	  sz = fdr.cpd * outsz;
99533965Sjdp	  out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
99633965Sjdp	  if (!out)
99733965Sjdp	    {
99833965Sjdp	      bfd_set_error (bfd_error_no_memory);
999130561Sobrien	      return FALSE;
100033965Sjdp	    }
100133965Sjdp	  if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out,
100233965Sjdp				   sz))
1003130561Sobrien	    return FALSE;
100433965Sjdp	  for (; in < end; in += insz, out += outsz)
100533965Sjdp	    {
100633965Sjdp	      PDR pdr;
100733965Sjdp
100833965Sjdp	      (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr);
100933965Sjdp	      (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out);
101033965Sjdp	    }
101133965Sjdp
101233965Sjdp	  /* Swap over the optimization information.  */
101333965Sjdp	  outsz = external_opt_size;
101433965Sjdp	  insz = input_swap->external_opt_size;
101533965Sjdp	  in = ((bfd_byte *) input_debug->external_opt
101633965Sjdp		+ fdr.ioptBase * insz);
101733965Sjdp	  end = in + fdr.copt * insz;
101833965Sjdp	  sz = fdr.copt * outsz;
101933965Sjdp	  out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
102033965Sjdp	  if (!out)
102133965Sjdp	    {
102233965Sjdp	      bfd_set_error (bfd_error_no_memory);
1023130561Sobrien	      return FALSE;
102433965Sjdp	    }
102533965Sjdp	  if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out,
102633965Sjdp				   sz))
1027130561Sobrien	    return FALSE;
102833965Sjdp	  for (; in < end; in += insz, out += outsz)
102933965Sjdp	    {
103033965Sjdp	      OPTR opt;
103133965Sjdp
103233965Sjdp	      (*input_swap->swap_opt_in) (input_bfd, (PTR) in, &opt);
103333965Sjdp	      (*output_swap->swap_opt_out) (output_bfd, &opt, (PTR) out);
103433965Sjdp	    }
103533965Sjdp	}
103633965Sjdp
103733965Sjdp      fdr.ipdFirst = output_symhdr->ipdMax;
103833965Sjdp      output_symhdr->ipdMax += fdr.cpd;
103933965Sjdp      fdr.ioptBase = output_symhdr->ioptMax;
104033965Sjdp      output_symhdr->ioptMax += fdr.copt;
104133965Sjdp
104233965Sjdp      if (fdr.crfd <= 0)
104333965Sjdp	{
104433965Sjdp	  /* Point this FDR at the table of RFD's we created.  */
104533965Sjdp	  fdr.rfdBase = newrfdbase;
104633965Sjdp	  fdr.crfd = input_symhdr->ifdMax;
104733965Sjdp	}
104833965Sjdp      else
104933965Sjdp	{
105033965Sjdp	  /* Point this FDR at the remapped RFD's.  */
105133965Sjdp	  fdr.rfdBase += oldrfdbase;
105233965Sjdp	}
105333965Sjdp
105433965Sjdp      (*swap_fdr_out) (output_bfd, &fdr, fdr_out);
105533965Sjdp      fdr_out += external_fdr_size;
105633965Sjdp      ++output_symhdr->ifdMax;
105733965Sjdp    }
105833965Sjdp
1059130561Sobrien  return TRUE;
106033965Sjdp}
106133965Sjdp
106233965Sjdp/* Add a string to the debugging information we are accumulating.
106333965Sjdp   Return the offset from the fdr string base.  */
106433965Sjdp
1065130561Sobrienstatic long ecoff_add_string
1066130561Sobrien  PARAMS ((struct accumulate *, struct bfd_link_info *,
1067130561Sobrien	   struct ecoff_debug_info *, FDR *fdr, const char *string));
106833965Sjdp
106933965Sjdpstatic long
107033965Sjdpecoff_add_string (ainfo, info, debug, fdr, string)
107133965Sjdp     struct accumulate *ainfo;
107233965Sjdp     struct bfd_link_info *info;
107333965Sjdp     struct ecoff_debug_info *debug;
107433965Sjdp     FDR *fdr;
107533965Sjdp     const char *string;
107633965Sjdp{
107733965Sjdp  HDRR *symhdr;
107833965Sjdp  size_t len;
107933965Sjdp  bfd_size_type ret;
108033965Sjdp
108133965Sjdp  symhdr = &debug->symbolic_header;
108233965Sjdp  len = strlen (string);
1083130561Sobrien  if (info->relocatable)
108433965Sjdp    {
108533965Sjdp      if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string,
108633965Sjdp			       len + 1))
108733965Sjdp	return -1;
108833965Sjdp      ret = symhdr->issMax;
108933965Sjdp      symhdr->issMax += len + 1;
109033965Sjdp      fdr->cbSs += len + 1;
109133965Sjdp    }
109233965Sjdp  else
109333965Sjdp    {
109433965Sjdp      struct string_hash_entry *sh;
109533965Sjdp
1096130561Sobrien      sh = string_hash_lookup (&ainfo->str_hash, string, TRUE, TRUE);
109733965Sjdp      if (sh == (struct string_hash_entry *) NULL)
109833965Sjdp	return -1;
109933965Sjdp      if (sh->val == -1)
110033965Sjdp	{
110133965Sjdp	  sh->val = symhdr->issMax;
110233965Sjdp	  symhdr->issMax += len + 1;
110333965Sjdp	  if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
110433965Sjdp	    ainfo->ss_hash = sh;
110533965Sjdp	  if (ainfo->ss_hash_end
110633965Sjdp	      != (struct string_hash_entry *) NULL)
110733965Sjdp	    ainfo->ss_hash_end->next = sh;
110833965Sjdp	  ainfo->ss_hash_end = sh;
110933965Sjdp	}
111033965Sjdp      ret = sh->val;
111133965Sjdp    }
111233965Sjdp
111333965Sjdp  return ret;
111433965Sjdp}
111533965Sjdp
111633965Sjdp/* Add debugging information from a non-ECOFF file.  */
111733965Sjdp
1118130561Sobrienbfd_boolean
111933965Sjdpbfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
112033965Sjdp				  output_swap, input_bfd, info)
112133965Sjdp     PTR handle;
112233965Sjdp     bfd *output_bfd;
112333965Sjdp     struct ecoff_debug_info *output_debug;
112433965Sjdp     const struct ecoff_debug_swap *output_swap;
112533965Sjdp     bfd *input_bfd;
112633965Sjdp     struct bfd_link_info *info;
112733965Sjdp{
112833965Sjdp  struct accumulate *ainfo = (struct accumulate *) handle;
112933965Sjdp  void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
113033965Sjdp    = output_swap->swap_sym_out;
113133965Sjdp  HDRR *output_symhdr = &output_debug->symbolic_header;
113233965Sjdp  FDR fdr;
113333965Sjdp  asection *sec;
113433965Sjdp  asymbol **symbols;
113533965Sjdp  asymbol **sym_ptr;
113633965Sjdp  asymbol **sym_end;
113733965Sjdp  long symsize;
113833965Sjdp  long symcount;
113933965Sjdp  PTR external_fdr;
114033965Sjdp
114133965Sjdp  memset ((PTR) &fdr, 0, sizeof fdr);
114233965Sjdp
114333965Sjdp  sec = bfd_get_section_by_name (input_bfd, ".text");
114433965Sjdp  if (sec != NULL)
114533965Sjdp    fdr.adr = sec->output_section->vma + sec->output_offset;
114633965Sjdp  else
114733965Sjdp    {
114833965Sjdp      /* FIXME: What about .init or .fini?  */
114933965Sjdp      fdr.adr = 0;
115033965Sjdp    }
115133965Sjdp
115233965Sjdp  fdr.issBase = output_symhdr->issMax;
115333965Sjdp  fdr.cbSs = 0;
115433965Sjdp  fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr,
1155218822Sdim			      input_bfd->filename);
115633965Sjdp  if (fdr.rss == -1)
1157130561Sobrien    return FALSE;
115833965Sjdp  fdr.isymBase = output_symhdr->isymMax;
115933965Sjdp
116033965Sjdp  /* Get the local symbols from the input BFD.  */
116133965Sjdp  symsize = bfd_get_symtab_upper_bound (input_bfd);
116233965Sjdp  if (symsize < 0)
1163130561Sobrien    return FALSE;
116489857Sobrien  symbols = (asymbol **) bfd_alloc (output_bfd, (bfd_size_type) symsize);
116533965Sjdp  if (symbols == (asymbol **) NULL)
1166130561Sobrien    return FALSE;
116733965Sjdp  symcount = bfd_canonicalize_symtab (input_bfd, symbols);
116833965Sjdp  if (symcount < 0)
1169130561Sobrien    return FALSE;
117033965Sjdp  sym_end = symbols + symcount;
117133965Sjdp
117233965Sjdp  /* Handle the local symbols.  Any external symbols are handled
117333965Sjdp     separately.  */
117433965Sjdp  fdr.csym = 0;
117533965Sjdp  for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
117633965Sjdp    {
117733965Sjdp      SYMR internal_sym;
117833965Sjdp      PTR external_sym;
117933965Sjdp
118033965Sjdp      if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
118133965Sjdp	continue;
118233965Sjdp      memset ((PTR) &internal_sym, 0, sizeof internal_sym);
118333965Sjdp      internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr,
118433965Sjdp					   (*sym_ptr)->name);
118533965Sjdp
118633965Sjdp      if (internal_sym.iss == -1)
1187130561Sobrien	return FALSE;
118833965Sjdp      if (bfd_is_com_section ((*sym_ptr)->section)
118933965Sjdp	  || bfd_is_und_section ((*sym_ptr)->section))
119033965Sjdp	internal_sym.value = (*sym_ptr)->value;
119133965Sjdp      else
119233965Sjdp	internal_sym.value = ((*sym_ptr)->value
119333965Sjdp			      + (*sym_ptr)->section->output_offset
119433965Sjdp			      + (*sym_ptr)->section->output_section->vma);
119533965Sjdp      internal_sym.st = stNil;
119633965Sjdp      internal_sym.sc = scUndefined;
119733965Sjdp      internal_sym.index = indexNil;
119833965Sjdp
119933965Sjdp      external_sym = (PTR) objalloc_alloc (ainfo->memory,
120033965Sjdp					   output_swap->external_sym_size);
120133965Sjdp      if (!external_sym)
120233965Sjdp	{
120333965Sjdp	  bfd_set_error (bfd_error_no_memory);
1204130561Sobrien	  return FALSE;
120533965Sjdp	}
120633965Sjdp      (*swap_sym_out) (output_bfd, &internal_sym, external_sym);
120733965Sjdp      add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end,
120889857Sobrien			  external_sym,
120989857Sobrien			  (unsigned long) output_swap->external_sym_size);
121033965Sjdp      ++fdr.csym;
121133965Sjdp      ++output_symhdr->isymMax;
121233965Sjdp    }
121333965Sjdp
121433965Sjdp  bfd_release (output_bfd, (PTR) symbols);
121533965Sjdp
121633965Sjdp  /* Leave everything else in the FDR zeroed out.  This will cause
121733965Sjdp     the lang field to be langC.  The fBigendian field will
121833965Sjdp     indicate little endian format, but it doesn't matter because
121933965Sjdp     it only applies to aux fields and there are none.  */
122033965Sjdp  external_fdr = (PTR) objalloc_alloc (ainfo->memory,
122133965Sjdp				       output_swap->external_fdr_size);
122233965Sjdp  if (!external_fdr)
122333965Sjdp    {
122433965Sjdp      bfd_set_error (bfd_error_no_memory);
1225130561Sobrien      return FALSE;
122633965Sjdp    }
122733965Sjdp  (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr);
122833965Sjdp  add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end,
122989857Sobrien		      external_fdr,
123089857Sobrien		      (unsigned long) output_swap->external_fdr_size);
123133965Sjdp
123233965Sjdp  ++output_symhdr->ifdMax;
123333965Sjdp
1234130561Sobrien  return TRUE;
123533965Sjdp}
123633965Sjdp
123733965Sjdp/* Set up ECOFF debugging information for the external symbols.
123833965Sjdp   FIXME: This is done using a memory buffer, but it should be
123933965Sjdp   probably be changed to use a shuffle structure.  The assembler uses
124033965Sjdp   this interface, so that must be changed to do something else.  */
124133965Sjdp
1242130561Sobrienbfd_boolean
1243130561Sobrienbfd_ecoff_debug_externals (abfd, debug, swap, relocatable, get_extr,
124433965Sjdp			   set_index)
124533965Sjdp     bfd *abfd;
124633965Sjdp     struct ecoff_debug_info *debug;
124733965Sjdp     const struct ecoff_debug_swap *swap;
1248130561Sobrien     bfd_boolean relocatable;
1249130561Sobrien     bfd_boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
125033965Sjdp     void (*set_index) PARAMS ((asymbol *, bfd_size_type));
125133965Sjdp{
125233965Sjdp  HDRR * const symhdr = &debug->symbolic_header;
125333965Sjdp  asymbol **sym_ptr_ptr;
125433965Sjdp  size_t c;
125533965Sjdp
125633965Sjdp  sym_ptr_ptr = bfd_get_outsymbols (abfd);
125733965Sjdp  if (sym_ptr_ptr == NULL)
1258130561Sobrien    return TRUE;
125933965Sjdp
126033965Sjdp  for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++)
126133965Sjdp    {
126233965Sjdp      asymbol *sym_ptr;
126333965Sjdp      EXTR esym;
126433965Sjdp
126533965Sjdp      sym_ptr = *sym_ptr_ptr;
126633965Sjdp
126733965Sjdp      /* Get the external symbol information.  */
1268104834Sobrien      if (! (*get_extr) (sym_ptr, &esym))
126933965Sjdp	continue;
127033965Sjdp
127133965Sjdp      /* If we're producing an executable, move common symbols into
127233965Sjdp	 bss.  */
1273130561Sobrien      if (! relocatable)
127433965Sjdp	{
127533965Sjdp	  if (esym.asym.sc == scCommon)
127633965Sjdp	    esym.asym.sc = scBss;
127733965Sjdp	  else if (esym.asym.sc == scSCommon)
127833965Sjdp	    esym.asym.sc = scSBss;
127933965Sjdp	}
128033965Sjdp
128133965Sjdp      if (bfd_is_com_section (sym_ptr->section)
128233965Sjdp	  || bfd_is_und_section (sym_ptr->section)
128333965Sjdp	  || sym_ptr->section->output_section == (asection *) NULL)
128433965Sjdp	{
128533965Sjdp	  /* FIXME: gas does not keep the value of a small undefined
128633965Sjdp	     symbol in the symbol itself, because of relocation
128733965Sjdp	     problems.  */
128833965Sjdp	  if (esym.asym.sc != scSUndefined
128933965Sjdp	      || esym.asym.value == 0
129033965Sjdp	      || sym_ptr->value != 0)
129133965Sjdp	    esym.asym.value = sym_ptr->value;
129233965Sjdp	}
129333965Sjdp      else
129433965Sjdp	esym.asym.value = (sym_ptr->value
129533965Sjdp			   + sym_ptr->section->output_offset
129633965Sjdp			   + sym_ptr->section->output_section->vma);
129733965Sjdp
129833965Sjdp      if (set_index)
129933965Sjdp	(*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax);
130033965Sjdp
130133965Sjdp      if (! bfd_ecoff_debug_one_external (abfd, debug, swap,
130233965Sjdp					  sym_ptr->name, &esym))
1303130561Sobrien	return FALSE;
130433965Sjdp    }
130533965Sjdp
1306130561Sobrien  return TRUE;
130733965Sjdp}
130833965Sjdp
130933965Sjdp/* Add a single external symbol to the debugging information.  */
131033965Sjdp
1311130561Sobrienbfd_boolean
131233965Sjdpbfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
131333965Sjdp     bfd *abfd;
131433965Sjdp     struct ecoff_debug_info *debug;
131533965Sjdp     const struct ecoff_debug_swap *swap;
131633965Sjdp     const char *name;
131733965Sjdp     EXTR *esym;
131833965Sjdp{
131933965Sjdp  const bfd_size_type external_ext_size = swap->external_ext_size;
132033965Sjdp  void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR))
132133965Sjdp    = swap->swap_ext_out;
132233965Sjdp  HDRR * const symhdr = &debug->symbolic_header;
132333965Sjdp  size_t namelen;
132433965Sjdp
132533965Sjdp  namelen = strlen (name);
132633965Sjdp
132733965Sjdp  if ((size_t) (debug->ssext_end - debug->ssext)
132833965Sjdp      < symhdr->issExtMax + namelen + 1)
132933965Sjdp    {
1330104834Sobrien      if (! ecoff_add_bytes ((char **) &debug->ssext,
1331104834Sobrien			     (char **) &debug->ssext_end,
1332104834Sobrien			     symhdr->issExtMax + namelen + 1))
1333130561Sobrien	return FALSE;
133433965Sjdp    }
133533965Sjdp  if ((size_t) ((char *) debug->external_ext_end
133633965Sjdp		- (char *) debug->external_ext)
133733965Sjdp      < (symhdr->iextMax + 1) * external_ext_size)
133833965Sjdp    {
1339218822Sdim      char *external_ext = debug->external_ext;
1340218822Sdim      char *external_ext_end = debug->external_ext_end;
1341218822Sdim      if (! ecoff_add_bytes ((char **) &external_ext,
1342218822Sdim			     (char **) &external_ext_end,
1343104834Sobrien			     (symhdr->iextMax + 1) * (size_t) external_ext_size))
1344130561Sobrien	return FALSE;
1345218822Sdim      debug->external_ext = external_ext;
1346218822Sdim      debug->external_ext_end = external_ext_end;
134733965Sjdp    }
134833965Sjdp
134933965Sjdp  esym->asym.iss = symhdr->issExtMax;
135033965Sjdp
135133965Sjdp  (*swap_ext_out) (abfd, esym,
135233965Sjdp		   ((char *) debug->external_ext
135333965Sjdp		    + symhdr->iextMax * swap->external_ext_size));
135433965Sjdp
135533965Sjdp  ++symhdr->iextMax;
135633965Sjdp
135733965Sjdp  strcpy (debug->ssext + symhdr->issExtMax, name);
135833965Sjdp  symhdr->issExtMax += namelen + 1;
135933965Sjdp
1360130561Sobrien  return TRUE;
136133965Sjdp}
136233965Sjdp
136333965Sjdp/* Align the ECOFF debugging information.  */
136433965Sjdp
136533965Sjdpstatic void
136633965Sjdpecoff_align_debug (abfd, debug, swap)
136760484Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
136833965Sjdp     struct ecoff_debug_info *debug;
136933965Sjdp     const struct ecoff_debug_swap *swap;
137033965Sjdp{
137133965Sjdp  HDRR * const symhdr = &debug->symbolic_header;
137233965Sjdp  bfd_size_type debug_align, aux_align, rfd_align;
137333965Sjdp  size_t add;
137433965Sjdp
137533965Sjdp  /* Adjust the counts so that structures are aligned.  */
137633965Sjdp  debug_align = swap->debug_align;
137733965Sjdp  aux_align = debug_align / sizeof (union aux_ext);
137833965Sjdp  rfd_align = debug_align / swap->external_rfd_size;
137933965Sjdp
138033965Sjdp  add = debug_align - (symhdr->cbLine & (debug_align - 1));
138133965Sjdp  if (add != debug_align)
138233965Sjdp    {
138333965Sjdp      if (debug->line != (unsigned char *) NULL)
138433965Sjdp	memset ((PTR) (debug->line + symhdr->cbLine), 0, add);
138533965Sjdp      symhdr->cbLine += add;
138633965Sjdp    }
138733965Sjdp
138833965Sjdp  add = debug_align - (symhdr->issMax & (debug_align - 1));
138933965Sjdp  if (add != debug_align)
139033965Sjdp    {
139133965Sjdp      if (debug->ss != (char *) NULL)
139233965Sjdp	memset ((PTR) (debug->ss + symhdr->issMax), 0, add);
139333965Sjdp      symhdr->issMax += add;
139433965Sjdp    }
139533965Sjdp
139633965Sjdp  add = debug_align - (symhdr->issExtMax & (debug_align - 1));
139733965Sjdp  if (add != debug_align)
139833965Sjdp    {
139933965Sjdp      if (debug->ssext != (char *) NULL)
140033965Sjdp	memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add);
140133965Sjdp      symhdr->issExtMax += add;
140233965Sjdp    }
140333965Sjdp
140433965Sjdp  add = aux_align - (symhdr->iauxMax & (aux_align - 1));
140533965Sjdp  if (add != aux_align)
140633965Sjdp    {
140733965Sjdp      if (debug->external_aux != (union aux_ext *) NULL)
140833965Sjdp	memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0,
140933965Sjdp		add * sizeof (union aux_ext));
141033965Sjdp      symhdr->iauxMax += add;
141133965Sjdp    }
141233965Sjdp
141333965Sjdp  add = rfd_align - (symhdr->crfd & (rfd_align - 1));
141433965Sjdp  if (add != rfd_align)
141533965Sjdp    {
141633965Sjdp      if (debug->external_rfd != (PTR) NULL)
141733965Sjdp	memset ((PTR) ((char *) debug->external_rfd
141833965Sjdp		       + symhdr->crfd * swap->external_rfd_size),
141933965Sjdp		0, (size_t) (add * swap->external_rfd_size));
142033965Sjdp      symhdr->crfd += add;
142133965Sjdp    }
142233965Sjdp}
142333965Sjdp
142433965Sjdp/* Return the size required by the ECOFF debugging information.  */
142533965Sjdp
142633965Sjdpbfd_size_type
142733965Sjdpbfd_ecoff_debug_size (abfd, debug, swap)
142833965Sjdp     bfd *abfd;
142933965Sjdp     struct ecoff_debug_info *debug;
143033965Sjdp     const struct ecoff_debug_swap *swap;
143133965Sjdp{
143233965Sjdp  bfd_size_type tot;
143333965Sjdp
143433965Sjdp  ecoff_align_debug (abfd, debug, swap);
143533965Sjdp  tot = swap->external_hdr_size;
143633965Sjdp
143733965Sjdp#define ADD(count, size) \
143833965Sjdp  tot += debug->symbolic_header.count * size
143933965Sjdp
144033965Sjdp  ADD (cbLine, sizeof (unsigned char));
144133965Sjdp  ADD (idnMax, swap->external_dnr_size);
144233965Sjdp  ADD (ipdMax, swap->external_pdr_size);
144333965Sjdp  ADD (isymMax, swap->external_sym_size);
144433965Sjdp  ADD (ioptMax, swap->external_opt_size);
144533965Sjdp  ADD (iauxMax, sizeof (union aux_ext));
144633965Sjdp  ADD (issMax, sizeof (char));
144733965Sjdp  ADD (issExtMax, sizeof (char));
144833965Sjdp  ADD (ifdMax, swap->external_fdr_size);
144933965Sjdp  ADD (crfd, swap->external_rfd_size);
145033965Sjdp  ADD (iextMax, swap->external_ext_size);
145133965Sjdp
145233965Sjdp#undef ADD
145333965Sjdp
145433965Sjdp  return tot;
145533965Sjdp}
145633965Sjdp
145733965Sjdp/* Write out the ECOFF symbolic header, given the file position it is
145833965Sjdp   going to be placed at.  This assumes that the counts are set
145933965Sjdp   correctly.  */
146033965Sjdp
1461130561Sobrienstatic bfd_boolean
146233965Sjdpecoff_write_symhdr (abfd, debug, swap, where)
146333965Sjdp     bfd *abfd;
146433965Sjdp     struct ecoff_debug_info *debug;
146533965Sjdp     const struct ecoff_debug_swap *swap;
146633965Sjdp     file_ptr where;
146733965Sjdp{
146833965Sjdp  HDRR * const symhdr = &debug->symbolic_header;
146933965Sjdp  char *buff = NULL;
147033965Sjdp
147133965Sjdp  ecoff_align_debug (abfd, debug, swap);
147233965Sjdp
147333965Sjdp  /* Go to the right location in the file.  */
147433965Sjdp  if (bfd_seek (abfd, where, SEEK_SET) != 0)
1475130561Sobrien    return FALSE;
147633965Sjdp
147733965Sjdp  where += swap->external_hdr_size;
147833965Sjdp
147933965Sjdp  symhdr->magic = swap->sym_magic;
148033965Sjdp
148133965Sjdp  /* Fill in the file offsets.  */
148233965Sjdp#define SET(offset, count, size) \
148333965Sjdp  if (symhdr->count == 0) \
148433965Sjdp    symhdr->offset = 0; \
148533965Sjdp  else \
148633965Sjdp    { \
148733965Sjdp      symhdr->offset = where; \
148833965Sjdp      where += symhdr->count * size; \
148933965Sjdp    }
149033965Sjdp
149133965Sjdp  SET (cbLineOffset, cbLine, sizeof (unsigned char));
149233965Sjdp  SET (cbDnOffset, idnMax, swap->external_dnr_size);
149333965Sjdp  SET (cbPdOffset, ipdMax, swap->external_pdr_size);
149433965Sjdp  SET (cbSymOffset, isymMax, swap->external_sym_size);
149533965Sjdp  SET (cbOptOffset, ioptMax, swap->external_opt_size);
149633965Sjdp  SET (cbAuxOffset, iauxMax, sizeof (union aux_ext));
149733965Sjdp  SET (cbSsOffset, issMax, sizeof (char));
149833965Sjdp  SET (cbSsExtOffset, issExtMax, sizeof (char));
149933965Sjdp  SET (cbFdOffset, ifdMax, swap->external_fdr_size);
150033965Sjdp  SET (cbRfdOffset, crfd, swap->external_rfd_size);
150133965Sjdp  SET (cbExtOffset, iextMax, swap->external_ext_size);
150233965Sjdp#undef SET
150333965Sjdp
150489857Sobrien  buff = (PTR) bfd_malloc (swap->external_hdr_size);
150533965Sjdp  if (buff == NULL && swap->external_hdr_size != 0)
150633965Sjdp    goto error_return;
150733965Sjdp
150833965Sjdp  (*swap->swap_hdr_out) (abfd, symhdr, buff);
150989857Sobrien  if (bfd_bwrite (buff, swap->external_hdr_size, abfd)
151033965Sjdp      != swap->external_hdr_size)
151133965Sjdp    goto error_return;
151233965Sjdp
151333965Sjdp  if (buff != NULL)
151433965Sjdp    free (buff);
1515130561Sobrien  return TRUE;
151633965Sjdp error_return:
151733965Sjdp  if (buff != NULL)
151833965Sjdp    free (buff);
1519130561Sobrien  return FALSE;
152033965Sjdp}
152133965Sjdp
152233965Sjdp/* Write out the ECOFF debugging information.  This function assumes
152333965Sjdp   that the information (the pointers and counts) in *DEBUG have been
152433965Sjdp   set correctly.  WHERE is the position in the file to write the
152533965Sjdp   information to.  This function fills in the file offsets in the
152633965Sjdp   symbolic header.  */
152733965Sjdp
1528130561Sobrienbfd_boolean
152933965Sjdpbfd_ecoff_write_debug (abfd, debug, swap, where)
153033965Sjdp     bfd *abfd;
153133965Sjdp     struct ecoff_debug_info *debug;
153233965Sjdp     const struct ecoff_debug_swap *swap;
153333965Sjdp     file_ptr where;
153433965Sjdp{
153533965Sjdp  HDRR * const symhdr = &debug->symbolic_header;
153633965Sjdp
153733965Sjdp  if (! ecoff_write_symhdr (abfd, debug, swap, where))
1538130561Sobrien    return FALSE;
153933965Sjdp
154033965Sjdp#define WRITE(ptr, count, size, offset) \
154133965Sjdp  BFD_ASSERT (symhdr->offset == 0 \
154233965Sjdp	      || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \
154389857Sobrien  if (bfd_bwrite ((PTR) debug->ptr, (bfd_size_type) size * symhdr->count, abfd)\
154433965Sjdp      != size * symhdr->count) \
1545130561Sobrien    return FALSE;
154633965Sjdp
154733965Sjdp  WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset);
154833965Sjdp  WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset);
154933965Sjdp  WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset);
155033965Sjdp  WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset);
155133965Sjdp  WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset);
155289857Sobrien  WRITE (external_aux, iauxMax, (bfd_size_type) sizeof (union aux_ext),
155389857Sobrien	 cbAuxOffset);
155433965Sjdp  WRITE (ss, issMax, sizeof (char), cbSsOffset);
155533965Sjdp  WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset);
155633965Sjdp  WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset);
155733965Sjdp  WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset);
155833965Sjdp  WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset);
155933965Sjdp#undef WRITE
156033965Sjdp
1561130561Sobrien  return TRUE;
156233965Sjdp}
156333965Sjdp
156433965Sjdp/* Write out a shuffle list.  */
156533965Sjdp
1566130561Sobrienstatic bfd_boolean ecoff_write_shuffle
1567130561Sobrien  PARAMS ((bfd *, const struct ecoff_debug_swap *, struct shuffle *,
1568130561Sobrien	   PTR space));
156933965Sjdp
1570130561Sobrienstatic bfd_boolean
157133965Sjdpecoff_write_shuffle (abfd, swap, shuffle, space)
157233965Sjdp     bfd *abfd;
157333965Sjdp     const struct ecoff_debug_swap *swap;
157433965Sjdp     struct shuffle *shuffle;
157533965Sjdp     PTR space;
157633965Sjdp{
157733965Sjdp  register struct shuffle *l;
157833965Sjdp  unsigned long total;
157933965Sjdp
158033965Sjdp  total = 0;
158133965Sjdp  for (l = shuffle; l != (struct shuffle *) NULL; l = l->next)
158233965Sjdp    {
158333965Sjdp      if (! l->filep)
158433965Sjdp	{
158589857Sobrien	  if (bfd_bwrite (l->u.memory, (bfd_size_type) l->size, abfd)
158689857Sobrien	      != l->size)
1587130561Sobrien	    return FALSE;
158833965Sjdp	}
158933965Sjdp      else
159033965Sjdp	{
159133965Sjdp	  if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
159289857Sobrien	      || bfd_bread (space, (bfd_size_type) l->size,
159389857Sobrien			   l->u.file.input_bfd) != l->size
159489857Sobrien	      || bfd_bwrite (space, (bfd_size_type) l->size, abfd) != l->size)
1595130561Sobrien	    return FALSE;
159633965Sjdp	}
159733965Sjdp      total += l->size;
159833965Sjdp    }
159933965Sjdp
160033965Sjdp  if ((total & (swap->debug_align - 1)) != 0)
160133965Sjdp    {
160233965Sjdp      unsigned int i;
160333965Sjdp      bfd_byte *s;
160433965Sjdp
160533965Sjdp      i = swap->debug_align - (total & (swap->debug_align - 1));
1606104834Sobrien      s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
160733965Sjdp      if (s == NULL && i != 0)
1608130561Sobrien	return FALSE;
160933965Sjdp
161089857Sobrien      if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
161133965Sjdp	{
161233965Sjdp	  free (s);
1613130561Sobrien	  return FALSE;
161433965Sjdp	}
161533965Sjdp      free (s);
161633965Sjdp    }
161733965Sjdp
1618130561Sobrien  return TRUE;
161933965Sjdp}
162033965Sjdp
162133965Sjdp/* Write out debugging information using accumulated linker
162233965Sjdp   information.  */
162333965Sjdp
1624130561Sobrienbfd_boolean
162533965Sjdpbfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
162633965Sjdp     PTR handle;
162733965Sjdp     bfd *abfd;
162833965Sjdp     struct ecoff_debug_info *debug;
162933965Sjdp     const struct ecoff_debug_swap *swap;
163033965Sjdp     struct bfd_link_info *info;
163133965Sjdp     file_ptr where;
163233965Sjdp{
163333965Sjdp  struct accumulate *ainfo = (struct accumulate *) handle;
163433965Sjdp  PTR space = NULL;
163589857Sobrien  bfd_size_type amt;
163633965Sjdp
163733965Sjdp  if (! ecoff_write_symhdr (abfd, debug, swap, where))
163833965Sjdp    goto error_return;
163933965Sjdp
164089857Sobrien  amt = ainfo->largest_file_shuffle;
164189857Sobrien  space = (PTR) bfd_malloc (amt);
164233965Sjdp  if (space == NULL && ainfo->largest_file_shuffle != 0)
164333965Sjdp    goto error_return;
164433965Sjdp
164533965Sjdp  if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
164633965Sjdp      || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
164733965Sjdp      || ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
164833965Sjdp      || ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
164933965Sjdp      || ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
165033965Sjdp    goto error_return;
165133965Sjdp
165233965Sjdp  /* The string table is written out from the hash table if this is a
165333965Sjdp     final link.  */
1654130561Sobrien  if (info->relocatable)
165533965Sjdp    {
165633965Sjdp      BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
165733965Sjdp      if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
165833965Sjdp	goto error_return;
165933965Sjdp    }
166033965Sjdp  else
166133965Sjdp    {
166233965Sjdp      unsigned long total;
166333965Sjdp      bfd_byte null;
166433965Sjdp      struct string_hash_entry *sh;
166533965Sjdp
166633965Sjdp      BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
166733965Sjdp      null = 0;
166889857Sobrien      if (bfd_bwrite ((PTR) &null, (bfd_size_type) 1, abfd) != 1)
166933965Sjdp	goto error_return;
167033965Sjdp      total = 1;
167133965Sjdp      BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
167233965Sjdp      for (sh = ainfo->ss_hash;
167333965Sjdp	   sh != (struct string_hash_entry *) NULL;
167433965Sjdp	   sh = sh->next)
167533965Sjdp	{
167633965Sjdp	  size_t len;
167733965Sjdp
167833965Sjdp	  len = strlen (sh->root.string);
167989857Sobrien	  amt = len + 1;
168089857Sobrien	  if (bfd_bwrite ((PTR) sh->root.string, amt, abfd) != amt)
168133965Sjdp	    goto error_return;
168233965Sjdp	  total += len + 1;
168333965Sjdp	}
168433965Sjdp
168533965Sjdp      if ((total & (swap->debug_align - 1)) != 0)
168633965Sjdp	{
168733965Sjdp	  unsigned int i;
168833965Sjdp	  bfd_byte *s;
168933965Sjdp
169033965Sjdp	  i = swap->debug_align - (total & (swap->debug_align - 1));
1691104834Sobrien	  s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
169233965Sjdp	  if (s == NULL && i != 0)
169333965Sjdp	    goto error_return;
1694104834Sobrien
169589857Sobrien	  if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
169633965Sjdp	    {
169733965Sjdp	      free (s);
169833965Sjdp	      goto error_return;
169933965Sjdp	    }
170033965Sjdp	  free (s);
170133965Sjdp	}
170233965Sjdp    }
170333965Sjdp
170433965Sjdp  /* The external strings and symbol are not converted over to using
170533965Sjdp     shuffles.  FIXME: They probably should be.  */
170689857Sobrien  amt = debug->symbolic_header.issExtMax;
170789857Sobrien  if (bfd_bwrite (debug->ssext, amt, abfd) != amt)
170833965Sjdp    goto error_return;
170933965Sjdp  if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0)
171033965Sjdp    {
171133965Sjdp      unsigned int i;
171233965Sjdp      bfd_byte *s;
171333965Sjdp
171433965Sjdp      i = (swap->debug_align
171533965Sjdp	   - (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
1716104834Sobrien      s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
171733965Sjdp      if (s == NULL && i != 0)
171833965Sjdp	goto error_return;
1719104834Sobrien
172089857Sobrien      if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
172133965Sjdp	{
172233965Sjdp	  free (s);
172333965Sjdp	  goto error_return;
172433965Sjdp	}
172533965Sjdp      free (s);
172633965Sjdp    }
172733965Sjdp
172833965Sjdp  if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
172933965Sjdp      || ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
173033965Sjdp    goto error_return;
173133965Sjdp
173233965Sjdp  BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
173333965Sjdp	      || (debug->symbolic_header.cbExtOffset
173433965Sjdp		  == (bfd_vma) bfd_tell (abfd)));
173533965Sjdp
173689857Sobrien  amt = debug->symbolic_header.iextMax * swap->external_ext_size;
173789857Sobrien  if (bfd_bwrite (debug->external_ext, amt, abfd) != amt)
173833965Sjdp    goto error_return;
173933965Sjdp
174033965Sjdp  if (space != NULL)
174133965Sjdp    free (space);
1742130561Sobrien  return TRUE;
174333965Sjdp
174433965Sjdp error_return:
174533965Sjdp  if (space != NULL)
174633965Sjdp    free (space);
1747130561Sobrien  return FALSE;
174833965Sjdp}
174933965Sjdp
175033965Sjdp/* Handle the find_nearest_line function for both ECOFF and MIPS ELF
175133965Sjdp   files.  */
175233965Sjdp
175333965Sjdp/* Compare FDR entries.  This is called via qsort.  */
175433965Sjdp
175533965Sjdpstatic int
175633965Sjdpcmp_fdrtab_entry (leftp, rightp)
175733965Sjdp     const PTR leftp;
175833965Sjdp     const PTR rightp;
175933965Sjdp{
176033965Sjdp  const struct ecoff_fdrtab_entry *lp =
176133965Sjdp    (const struct ecoff_fdrtab_entry *) leftp;
176233965Sjdp  const struct ecoff_fdrtab_entry *rp =
176333965Sjdp    (const struct ecoff_fdrtab_entry *) rightp;
176433965Sjdp
176533965Sjdp  if (lp->base_addr < rp->base_addr)
176633965Sjdp    return -1;
176733965Sjdp  if (lp->base_addr > rp->base_addr)
176833965Sjdp    return 1;
176933965Sjdp  return 0;
177033965Sjdp}
177133965Sjdp
177233965Sjdp/* Each file descriptor (FDR) has a memory address, to simplify
177333965Sjdp   looking up an FDR by address, we build a table covering all FDRs
177433965Sjdp   that have a least one procedure descriptor in them.  The final
177533965Sjdp   table will be sorted by address so we can look it up via binary
177633965Sjdp   search.  */
177733965Sjdp
1778130561Sobrienstatic bfd_boolean
177933965Sjdpmk_fdrtab (abfd, debug_info, debug_swap, line_info)
178033965Sjdp     bfd *abfd;
178133965Sjdp     struct ecoff_debug_info * const debug_info;
178233965Sjdp     const struct ecoff_debug_swap * const debug_swap;
178333965Sjdp     struct ecoff_find_line *line_info;
178433965Sjdp{
178533965Sjdp  struct ecoff_fdrtab_entry *tab;
178633965Sjdp  FDR *fdr_ptr;
178733965Sjdp  FDR *fdr_start;
178833965Sjdp  FDR *fdr_end;
1789130561Sobrien  bfd_boolean stabs;
179033965Sjdp  long len;
179189857Sobrien  bfd_size_type amt;
179233965Sjdp
179333965Sjdp  fdr_start = debug_info->fdr;
179433965Sjdp  fdr_end = fdr_start + debug_info->symbolic_header.ifdMax;
179533965Sjdp
1796130561Sobrien  /* First, let's see how long the table needs to be.  */
179733965Sjdp  for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
179833965Sjdp    {
1799130561Sobrien      if (fdr_ptr->cpd == 0)	/* Skip FDRs that have no PDRs.  */
180033965Sjdp	continue;
180133965Sjdp      ++len;
180233965Sjdp    }
180333965Sjdp
1804130561Sobrien  /* Now, create and fill in the table.  */
180589857Sobrien  amt = (bfd_size_type) len * sizeof (struct ecoff_fdrtab_entry);
180689857Sobrien  line_info->fdrtab = (struct ecoff_fdrtab_entry*) bfd_zalloc (abfd, amt);
180733965Sjdp  if (line_info->fdrtab == NULL)
1808130561Sobrien    return FALSE;
180933965Sjdp  line_info->fdrtab_len = len;
181033965Sjdp
181133965Sjdp  tab = line_info->fdrtab;
181233965Sjdp  for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
181333965Sjdp    {
181433965Sjdp      if (fdr_ptr->cpd == 0)
181533965Sjdp	continue;
181633965Sjdp
181733965Sjdp      /* Check whether this file has stabs debugging information.  In
181833965Sjdp	 a file with stabs debugging information, the second local
181933965Sjdp	 symbol is named @stabs.  */
1820130561Sobrien      stabs = FALSE;
182133965Sjdp      if (fdr_ptr->csym >= 2)
182233965Sjdp	{
182333965Sjdp	  char *sym_ptr;
182433965Sjdp	  SYMR sym;
182533965Sjdp
182633965Sjdp	  sym_ptr = ((char *) debug_info->external_sym
1827130561Sobrien		     + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
182833965Sjdp	  (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
182933965Sjdp	  if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
183033965Sjdp		      STABS_SYMBOL) == 0)
1831130561Sobrien	    stabs = TRUE;
183233965Sjdp	}
183333965Sjdp
183433965Sjdp      if (!stabs)
183533965Sjdp	{
1836130561Sobrien	  /* eraxxon: There are at least two problems with this computation:
1837130561Sobrien	     1) PDRs do *not* contain offsets but full vma's; and typically the
1838130561Sobrien	     address of the first PDR is the address of the FDR, which will
1839130561Sobrien	     make (most) of the results of the original computation 0!
1840130561Sobrien	     2) Once in a wacky while, the Compaq compiler generated PDR
1841130561Sobrien	     addresses do not equal the FDR vma, but they (the PDR address)
1842130561Sobrien	     are still vma's and not offsets.  Cf. comments in
1843130561Sobrien	     'lookup_line'.  */
184433965Sjdp	  /* The address of the first PDR is the offset of that
184533965Sjdp	     procedure relative to the beginning of file FDR.  */
1846130561Sobrien	  tab->base_addr = fdr_ptr->adr;
184733965Sjdp	}
184833965Sjdp      else
184933965Sjdp	{
185033965Sjdp	  /* XXX I don't know about stabs, so this is a guess
1851130561Sobrien	     (davidm@cs.arizona.edu).  */
185233965Sjdp	  tab->base_addr = fdr_ptr->adr;
185333965Sjdp	}
185433965Sjdp      tab->fdr = fdr_ptr;
185533965Sjdp      ++tab;
185633965Sjdp    }
185733965Sjdp
185833965Sjdp  /* Finally, the table is sorted in increasing memory-address order.
185933965Sjdp     The table is mostly sorted already, but there are cases (e.g.,
186033965Sjdp     static functions in include files), where this does not hold.
186133965Sjdp     Use "odump -PFv" to verify...  */
186289857Sobrien  qsort ((PTR) line_info->fdrtab, (size_t) len,
186333965Sjdp	 sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry);
186433965Sjdp
1865130561Sobrien  return TRUE;
186633965Sjdp}
186733965Sjdp
186833965Sjdp/* Return index of first FDR that covers to OFFSET.  */
186933965Sjdp
187033965Sjdpstatic long
187133965Sjdpfdrtab_lookup (line_info, offset)
187233965Sjdp     struct ecoff_find_line *line_info;
187333965Sjdp     bfd_vma offset;
187433965Sjdp{
187533965Sjdp  long low, high, len;
187633965Sjdp  long mid = -1;
187733965Sjdp  struct ecoff_fdrtab_entry *tab;
187833965Sjdp
187933965Sjdp  len = line_info->fdrtab_len;
188033965Sjdp  if (len == 0)
188133965Sjdp    return -1;
188233965Sjdp
188333965Sjdp  tab = line_info->fdrtab;
188433965Sjdp  for (low = 0, high = len - 1 ; low != high ;)
188533965Sjdp    {
188633965Sjdp      mid = (high + low) / 2;
188733965Sjdp      if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr)
188833965Sjdp	goto find_min;
188933965Sjdp
189033965Sjdp      if (tab[mid].base_addr > offset)
189133965Sjdp	high = mid;
189233965Sjdp      else
189333965Sjdp	low = mid + 1;
189433965Sjdp    }
1895130561Sobrien
1896130561Sobrien  /* eraxxon: at this point 'offset' is either lower than the lowest entry or
1897130561Sobrien     higher than the highest entry. In the former case high = low = mid = 0;
1898130561Sobrien     we want to return -1.  In the latter case, low = high and mid = low - 1;
1899130561Sobrien     we want to return the index of the highest entry.  Only in former case
1900130561Sobrien     will the following 'catch-all' test be true.  */
190133965Sjdp  ++mid;
190233965Sjdp
1903130561Sobrien  /* Last entry is catch-all for all higher addresses.  */
190433965Sjdp  if (offset < tab[mid].base_addr)
190533965Sjdp    return -1;
190633965Sjdp
190733965Sjdp find_min:
190833965Sjdp
1909130561Sobrien  /* eraxxon: There may be multiple FDRs in the table with the
1910130561Sobrien     same base_addr; make sure that we are at the first one.  */
191133965Sjdp  while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr)
191233965Sjdp    --mid;
191333965Sjdp
191433965Sjdp  return mid;
191533965Sjdp}
191633965Sjdp
191733965Sjdp/* Look up a line given an address, storing the information in
191833965Sjdp   LINE_INFO->cache.  */
191933965Sjdp
1920130561Sobrienstatic bfd_boolean
192133965Sjdplookup_line (abfd, debug_info, debug_swap, line_info)
192233965Sjdp     bfd *abfd;
192333965Sjdp     struct ecoff_debug_info * const debug_info;
192433965Sjdp     const struct ecoff_debug_swap * const debug_swap;
192533965Sjdp     struct ecoff_find_line *line_info;
192633965Sjdp{
192733965Sjdp  struct ecoff_fdrtab_entry *tab;
192833965Sjdp  bfd_vma offset;
1929130561Sobrien  bfd_boolean stabs;
193033965Sjdp  FDR *fdr_ptr;
193133965Sjdp  int i;
193277298Sobrien
1933130561Sobrien  /* eraxxon: note that 'offset' is the full vma, not a section offset.  */
193433965Sjdp  offset = line_info->cache.start;
193577298Sobrien
193633965Sjdp  /* Build FDR table (sorted by object file's base-address) if we
193733965Sjdp     don't have it already.  */
193833965Sjdp  if (line_info->fdrtab == NULL
193933965Sjdp      && !mk_fdrtab (abfd, debug_info, debug_swap, line_info))
1940130561Sobrien    return FALSE;
194133965Sjdp
194233965Sjdp  tab = line_info->fdrtab;
194333965Sjdp
1944130561Sobrien  /* Find first FDR for address OFFSET.  */
194533965Sjdp  i = fdrtab_lookup (line_info, offset);
194633965Sjdp  if (i < 0)
1947130561Sobrien    return FALSE;		/* no FDR, no fun...  */
1948130561Sobrien
1949130561Sobrien  /* eraxxon: 'fdrtab_lookup' doesn't give what we want, at least for Compaq's
1950130561Sobrien     C++ compiler 6.2.  Consider three FDRs with starting addresses of x, y,
1951130561Sobrien     and z, respectively, such that x < y < z.  Assume further that
1952130561Sobrien     y < 'offset' < z.  It is possible at times that the PDR for 'offset' is
1953130561Sobrien     associated with FDR x and *not* with FDR y.  Erg!!
1954130561Sobrien
1955130561Sobrien     From a binary dump of my C++ test case 'moo' using Compaq's coffobjanl
1956130561Sobrien     (output format has been edited for our purposes):
1957130561Sobrien
1958130561Sobrien     FDR [2]: (main.C): First instruction: 0x12000207c <x>
1959130561Sobrien       PDR [5] for File [2]: LoopTest__Xv                 <0x1200020a0> (a)
1960130561Sobrien       PDR [7] for File [2]: foo__Xv                      <0x120002168>
1961130561Sobrien     FDR [1]: (-1):     First instruction: 0x1200020e8 <y>
1962130561Sobrien       PDR [3] for File [1]:                              <0x120001ad0> (b)
1963130561Sobrien     FDR [6]: (-1):     First instruction: 0x1200026f0 <z>
1964130561Sobrien
1965130561Sobrien     (a) In the case of PDR5, the vma is such that the first few instructions
1966130561Sobrien     of the procedure can be found.  But since the size of this procedure is
1967130561Sobrien     160b, the vma will soon cross into the 'address space' of FDR1 and no
1968130561Sobrien     debugging info will be found.  How repugnant!
1969130561Sobrien
1970130561Sobrien     (b) It is also possible for a PDR to have a *lower* vma than its associated
1971130561Sobrien     FDR; see FDR1 and PDR3.  Gross!
1972130561Sobrien
1973130561Sobrien     Since the FDRs that are causing so much havok (in this case) 1) do not
1974130561Sobrien     describe actual files (fdr.rss == -1), and 2) contain only compiler
1975130561Sobrien     generated routines, I thought a simple fix would be to exclude them from
1976130561Sobrien     the FDR table in 'mk_fdrtab'.  But, besides not knowing for certain
1977130561Sobrien     whether this would be correct, it creates an additional problem.  If we
1978130561Sobrien     happen to ask for source file info on a compiler generated (procedure)
1979130561Sobrien     symbol -- which is still in the symbol table -- the result can be
1980130561Sobrien     information from a real procedure!  This is because compiler generated
1981130561Sobrien     procedures with vma's higher than the last FDR in the fdr table will be
1982130561Sobrien     associated with a PDR from this FDR, specifically the PDR with the
1983130561Sobrien     highest vma.  This wasn't a problem before, because each procedure had a
1984130561Sobrien     PDR.  (Yes, this problem could be eliminated if we kept the size of the
1985130561Sobrien     last PDR around, but things are already getting ugly).
1986130561Sobrien
1987130561Sobrien     Probably, a better solution would be to have a sorted PDR table.  Each
1988130561Sobrien     PDR would have a pointer to its FDR so file information could still be
1989130561Sobrien     obtained.  A FDR table could still be constructed if necessary -- since
1990130561Sobrien     it only contains pointers, not much extra memory would be used -- but
1991130561Sobrien     the PDR table would be searched to locate debugging info.
1992130561Sobrien
1993130561Sobrien     There is still at least one remaining issue.  Sometimes a FDR can have a
1994130561Sobrien     bogus name, but contain PDRs that should belong to another FDR with a
1995130561Sobrien     real name.  E.g:
1996130561Sobrien
1997130561Sobrien     FDR [3]: 0000000120001b50 (/home/.../Array.H~alt~deccxx_5E5A62AD)
1998130561Sobrien       PDR [a] for File [3]: 0000000120001b50
1999130561Sobrien       PDR [b] for File [3]: 0000000120001cf0
2000130561Sobrien       PDR [c] for File [3]: 0000000120001dc8
2001130561Sobrien       PDR [d] for File [3]: 0000000120001e40
2002130561Sobrien       PDR [e] for File [3]: 0000000120001eb8
2003130561Sobrien       PDR [f] for File [3]: 0000000120001f4c
2004130561Sobrien     FDR [4]: 0000000120001b50 (/home/.../Array.H)
2005130561Sobrien
2006130561Sobrien     Here, FDR4 has the correct name, but should (seemingly) contain PDRa-f.
2007130561Sobrien     The symbol table for PDR4 does contain symbols for PDRa-f, but so does
2008130561Sobrien     the symbol table for FDR3.  However the former is different; perhaps this
2009130561Sobrien     can be detected easily. (I'm not sure at this point.)  This problem only
2010130561Sobrien     seems to be associated with files with templates.  I am assuming the idea
2011130561Sobrien     is that there is a 'fake' FDR (with PDRs) for each differently typed set
2012130561Sobrien     of templates that must be generated.  Currently, FDR4 is completely
2013130561Sobrien     excluded from the FDR table in 'mk_fdrtab' because it contains no PDRs.
2014130561Sobrien
2015130561Sobrien     Since I don't have time to prepare a real fix for this right now, be
2016130561Sobrien     prepared for 'A Horrible Hack' to force the inspection of all non-stabs
2017130561Sobrien     FDRs.  It's coming...  */
201833965Sjdp  fdr_ptr = tab[i].fdr;
201933965Sjdp
202033965Sjdp  /* Check whether this file has stabs debugging information.  In a
202133965Sjdp     file with stabs debugging information, the second local symbol is
202233965Sjdp     named @stabs.  */
2023130561Sobrien  stabs = FALSE;
202433965Sjdp  if (fdr_ptr->csym >= 2)
202533965Sjdp    {
202633965Sjdp      char *sym_ptr;
202733965Sjdp      SYMR sym;
202833965Sjdp
202933965Sjdp      sym_ptr = ((char *) debug_info->external_sym
203033965Sjdp		 + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
203133965Sjdp      (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
203233965Sjdp      if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
203333965Sjdp		  STABS_SYMBOL) == 0)
2034130561Sobrien	stabs = TRUE;
203533965Sjdp    }
203633965Sjdp
203733965Sjdp  if (!stabs)
203833965Sjdp    {
203933965Sjdp      bfd_size_type external_pdr_size;
204033965Sjdp      char *pdr_ptr;
204133965Sjdp      char *best_pdr = NULL;
204233965Sjdp      FDR *best_fdr;
2043130561Sobrien      bfd_signed_vma best_dist = -1;
204433965Sjdp      PDR pdr;
204533965Sjdp      unsigned char *line_ptr;
204633965Sjdp      unsigned char *line_end;
204733965Sjdp      int lineno;
204833965Sjdp      /* This file uses ECOFF debugging information.  Each FDR has a
204933965Sjdp         list of procedure descriptors (PDR).  The address in the FDR
205033965Sjdp         is the absolute address of the first procedure.  The address
205133965Sjdp         in the first PDR gives the offset of that procedure relative
205233965Sjdp         to the object file's base-address.  The addresses in
205333965Sjdp         subsequent PDRs specify each procedure's address relative to
205433965Sjdp         the object file's base-address.  To make things more juicy,
205533965Sjdp         whenever the PROF bit in the PDR is set, the real entry point
205633965Sjdp         of the procedure may be 16 bytes below what would normally be
205733965Sjdp         the procedure's entry point.  Instead, DEC came up with a
205833965Sjdp         wicked scheme to create profiled libraries "on the fly":
205933965Sjdp         instead of shipping a regular and a profiled version of each
206033965Sjdp         library, they insert 16 bytes of unused space in front of
206133965Sjdp         each procedure and set the "prof" bit in the PDR to indicate
206233965Sjdp         that there is a gap there (this is done automagically by "as"
206333965Sjdp         when option "-pg" is specified).  Thus, normally, you link
206433965Sjdp         against such a library and, except for lots of 16 byte gaps
206533965Sjdp         between functions, things will behave as usual.  However,
206633965Sjdp         when invoking "ld" with option "-pg", it will fill those gaps
206733965Sjdp         with code that calls mcount().  It then moves the function's
206833965Sjdp         entry point down by 16 bytes, and out pops a binary that has
206933965Sjdp         all functions profiled.
207033965Sjdp
207133965Sjdp         NOTE: Neither FDRs nor PDRs are strictly sorted in memory
207233965Sjdp               order.  For example, when including header-files that
207333965Sjdp               define functions, the FDRs follow behind the including
207433965Sjdp               file, even though their code may have been generated at
207533965Sjdp               a lower address.  File coff-alpha.c from libbfd
207633965Sjdp               illustrates this (use "odump -PFv" to look at a file's
207733965Sjdp               FDR/PDR).  Similarly, PDRs are sometimes out of order
207833965Sjdp               as well.  An example of this is OSF/1 v3.0 libc's
207933965Sjdp               malloc.c.  I'm not sure why this happens, but it could
208033965Sjdp               be due to optimizations that reorder a function's
208133965Sjdp               position within an object-file.
208277298Sobrien
208333965Sjdp         Strategy:
208477298Sobrien
208533965Sjdp         On the first call to this function, we build a table of FDRs
208633965Sjdp         that is sorted by the base-address of the object-file the FDR
208733965Sjdp         is referring to.  Notice that each object-file may contain
208833965Sjdp         code from multiple source files (e.g., due to code defined in
208933965Sjdp         include files).  Thus, for any given base-address, there may
209033965Sjdp         be multiple FDRs (but this case is, fortunately, uncommon).
209133965Sjdp         lookup(addr) guarantees to return the first FDR that applies
209233965Sjdp         to address ADDR.  Thus, after invoking lookup(), we have a
209333965Sjdp         list of FDRs that may contain the PDR for ADDR.  Next, we
209433965Sjdp         walk through the PDRs of these FDRs and locate the one that
209533965Sjdp         is closest to ADDR (i.e., for which the difference between
209633965Sjdp         ADDR and the PDR's entry point is positive and minimal).
209733965Sjdp         Once, the right FDR and PDR are located, we simply walk
209833965Sjdp         through the line-number table to lookup the line-number that
209933965Sjdp         best matches ADDR.  Obviously, things could be sped up by
210033965Sjdp         keeping a sorted list of PDRs instead of a sorted list of
210133965Sjdp         FDRs.  However, this would increase space requirements
210233965Sjdp         considerably, which is undesirable.  */
210333965Sjdp      external_pdr_size = debug_swap->external_pdr_size;
210433965Sjdp
2105130561Sobrien      /* eraxxon: The Horrible Hack: Because of the problems above, set 'i'
2106130561Sobrien	 to 0 so we look through all FDRs.
2107130561Sobrien
2108130561Sobrien	 Because FDR's without any symbols are assumed to be non-stabs,
2109130561Sobrien	 searching through all FDRs may cause the following code to try to
2110130561Sobrien	 read stabs FDRs as ECOFF ones.  However, I don't think this will
2111130561Sobrien	 harm anything.  */
2112130561Sobrien      i = 0;
2113130561Sobrien
211433965Sjdp      /* Search FDR list starting at tab[i] for the PDR that best matches
211533965Sjdp         OFFSET.  Normally, the FDR list is only one entry long.  */
211633965Sjdp      best_fdr = NULL;
211733965Sjdp      do
211833965Sjdp	{
2119130561Sobrien	  /* eraxxon: 'dist' and 'min_dist' can be negative now
2120130561Sobrien             because we iterate over every FDR rather than just ones
2121130561Sobrien             with a base address less than or equal to 'offset'.  */
2122130561Sobrien	  bfd_signed_vma dist = -1, min_dist = -1;
212333965Sjdp	  char *pdr_hold;
212433965Sjdp	  char *pdr_end;
212577298Sobrien
212633965Sjdp	  fdr_ptr = tab[i].fdr;
212777298Sobrien
212833965Sjdp	  pdr_ptr = ((char *) debug_info->external_pdr
212933965Sjdp		     + fdr_ptr->ipdFirst * external_pdr_size);
213033965Sjdp	  pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
213133965Sjdp	  (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
213233965Sjdp	  /* Find PDR that is closest to OFFSET.  If pdr.prof is set,
213333965Sjdp	     the procedure entry-point *may* be 0x10 below pdr.adr.  We
213433965Sjdp	     simply pretend that pdr.prof *implies* a lower entry-point.
213533965Sjdp	     This is safe because it just means that may identify 4 NOPs
213633965Sjdp	     in front of the function as belonging to the function.  */
213733965Sjdp	  for (pdr_hold = NULL;
213833965Sjdp	       pdr_ptr < pdr_end;
213933965Sjdp	       (pdr_ptr += external_pdr_size,
214033965Sjdp		(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr)))
214133965Sjdp	    {
214233965Sjdp	      if (offset >= (pdr.adr - 0x10 * pdr.prof))
214333965Sjdp		{
214433965Sjdp		  dist = offset - (pdr.adr - 0x10 * pdr.prof);
2145130561Sobrien
2146130561Sobrien		  /* eraxxon: 'dist' can be negative now.  Note that
2147130561Sobrien                     'min_dist' can be negative if 'pdr_hold' below is NULL.  */
2148130561Sobrien		  if (!pdr_hold || (dist >= 0 && dist < min_dist))
214933965Sjdp		    {
215033965Sjdp		      min_dist = dist;
215133965Sjdp		      pdr_hold = pdr_ptr;
215233965Sjdp		    }
215333965Sjdp		}
215433965Sjdp	    }
215577298Sobrien
2156130561Sobrien	  if (!best_pdr || (min_dist >= 0 && min_dist < best_dist))
215733965Sjdp	    {
2158130561Sobrien	      best_dist = (bfd_vma) min_dist;
215933965Sjdp	      best_fdr = fdr_ptr;
216033965Sjdp	      best_pdr = pdr_hold;
216133965Sjdp	    }
2162130561Sobrien	  /* Continue looping until base_addr of next entry is different.  */
216333965Sjdp	}
2164130561Sobrien      /* eraxxon: We want to iterate over all FDRs.
2165130561Sobrien	 See previous comment about 'fdrtab_lookup'.  */
2166130561Sobrien      while (++i < line_info->fdrtab_len);
216733965Sjdp
216833965Sjdp      if (!best_fdr || !best_pdr)
2169130561Sobrien	return FALSE;			/* Shouldn't happen...  */
217033965Sjdp
2171130561Sobrien      /* Phew, finally we got something that we can hold onto.  */
217233965Sjdp      fdr_ptr = best_fdr;
217333965Sjdp      pdr_ptr = best_pdr;
217433965Sjdp      (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
217533965Sjdp      /* Now we can look for the actual line number.  The line numbers
217633965Sjdp         are stored in a very funky format, which I won't try to
217733965Sjdp         describe.  The search is bounded by the end of the FDRs line
217833965Sjdp         number entries.  */
217933965Sjdp      line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
218033965Sjdp
2181130561Sobrien      /* Make offset relative to procedure entry.  */
218233965Sjdp      offset -= pdr.adr - 0x10 * pdr.prof;
218333965Sjdp      lineno = pdr.lnLow;
218433965Sjdp      line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset;
218533965Sjdp      while (line_ptr < line_end)
218633965Sjdp	{
218733965Sjdp	  int delta;
218833965Sjdp	  unsigned int count;
218933965Sjdp
219033965Sjdp	  delta = *line_ptr >> 4;
219133965Sjdp	  if (delta >= 0x8)
219233965Sjdp	    delta -= 0x10;
219333965Sjdp	  count = (*line_ptr & 0xf) + 1;
219433965Sjdp	  ++line_ptr;
219533965Sjdp	  if (delta == -8)
219633965Sjdp	    {
219733965Sjdp	      delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
219833965Sjdp	      if (delta >= 0x8000)
219933965Sjdp		delta -= 0x10000;
220033965Sjdp	      line_ptr += 2;
220133965Sjdp	    }
220233965Sjdp	  lineno += delta;
220333965Sjdp	  if (offset < count * 4)
220433965Sjdp	    {
220533965Sjdp	      line_info->cache.stop += count * 4 - offset;
220633965Sjdp	      break;
220733965Sjdp	    }
220833965Sjdp	  offset -= count * 4;
220933965Sjdp	}
221033965Sjdp
221133965Sjdp      /* If fdr_ptr->rss is -1, then this file does not have full
221233965Sjdp         symbols, at least according to gdb/mipsread.c.  */
221333965Sjdp      if (fdr_ptr->rss == -1)
221433965Sjdp	{
221533965Sjdp	  line_info->cache.filename = NULL;
221633965Sjdp	  if (pdr.isym == -1)
221733965Sjdp	    line_info->cache.functionname = NULL;
221833965Sjdp	  else
221933965Sjdp	    {
222033965Sjdp	      EXTR proc_ext;
222133965Sjdp
222233965Sjdp	      (*debug_swap->swap_ext_in)
222333965Sjdp		(abfd,
222433965Sjdp		 ((char *) debug_info->external_ext
222533965Sjdp		  + pdr.isym * debug_swap->external_ext_size),
222633965Sjdp		 &proc_ext);
222733965Sjdp	      line_info->cache.functionname = (debug_info->ssext
222833965Sjdp					       + proc_ext.asym.iss);
222933965Sjdp	    }
223033965Sjdp	}
223133965Sjdp      else
223233965Sjdp	{
223333965Sjdp	  SYMR proc_sym;
223433965Sjdp
223533965Sjdp	  line_info->cache.filename = (debug_info->ss
223633965Sjdp				       + fdr_ptr->issBase
223733965Sjdp				       + fdr_ptr->rss);
223833965Sjdp	  (*debug_swap->swap_sym_in)
223933965Sjdp	    (abfd,
224033965Sjdp	     ((char *) debug_info->external_sym
224133965Sjdp	      + ((fdr_ptr->isymBase + pdr.isym)
224233965Sjdp		 * debug_swap->external_sym_size)),
224333965Sjdp	     &proc_sym);
224433965Sjdp	  line_info->cache.functionname = (debug_info->ss
224533965Sjdp					   + fdr_ptr->issBase
224633965Sjdp					   + proc_sym.iss);
224733965Sjdp	}
224833965Sjdp      if (lineno == ilineNil)
224933965Sjdp	lineno = 0;
225033965Sjdp      line_info->cache.line_num = lineno;
225133965Sjdp    }
225233965Sjdp  else
225333965Sjdp    {
225433965Sjdp      bfd_size_type external_sym_size;
225533965Sjdp      const char *directory_name;
225633965Sjdp      const char *main_file_name;
225733965Sjdp      const char *current_file_name;
225833965Sjdp      const char *function_name;
225933965Sjdp      const char *line_file_name;
226033965Sjdp      bfd_vma low_func_vma;
226133965Sjdp      bfd_vma low_line_vma;
2262130561Sobrien      bfd_boolean past_line;
2263130561Sobrien      bfd_boolean past_fn;
226433965Sjdp      char *sym_ptr, *sym_ptr_end;
226533965Sjdp      size_t len, funclen;
226633965Sjdp      char *buffer = NULL;
226733965Sjdp
226833965Sjdp      /* This file uses stabs debugging information.  When gcc is not
226933965Sjdp	 optimizing, it will put the line number information before
227033965Sjdp	 the function name stabs entry.  When gcc is optimizing, it
227133965Sjdp	 will put the stabs entry for all the function first, followed
227233965Sjdp	 by the line number information.  (This appears to happen
227333965Sjdp	 because of the two output files used by the -mgpopt switch,
227433965Sjdp	 which is implied by -O).  This means that we must keep
227533965Sjdp	 looking through the symbols until we find both a line number
227633965Sjdp	 and a function name which are beyond the address we want.  */
227733965Sjdp
227833965Sjdp      line_info->cache.filename = NULL;
227933965Sjdp      line_info->cache.functionname = NULL;
228033965Sjdp      line_info->cache.line_num = 0;
228133965Sjdp
228233965Sjdp      directory_name = NULL;
228333965Sjdp      main_file_name = NULL;
228433965Sjdp      current_file_name = NULL;
228533965Sjdp      function_name = NULL;
228633965Sjdp      line_file_name = NULL;
228733965Sjdp      low_func_vma = 0;
228833965Sjdp      low_line_vma = 0;
2289130561Sobrien      past_line = FALSE;
2290130561Sobrien      past_fn = FALSE;
229133965Sjdp
229233965Sjdp      external_sym_size = debug_swap->external_sym_size;
229333965Sjdp
229433965Sjdp      sym_ptr = ((char *) debug_info->external_sym
229533965Sjdp		 + (fdr_ptr->isymBase + 2) * external_sym_size);
229633965Sjdp      sym_ptr_end = sym_ptr + (fdr_ptr->csym - 2) * external_sym_size;
229733965Sjdp      for (;
229833965Sjdp	   sym_ptr < sym_ptr_end && (! past_line || ! past_fn);
229933965Sjdp	   sym_ptr += external_sym_size)
230033965Sjdp	{
230133965Sjdp	  SYMR sym;
230233965Sjdp
230333965Sjdp	  (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
230433965Sjdp
230533965Sjdp	  if (ECOFF_IS_STAB (&sym))
230633965Sjdp	    {
230733965Sjdp	      switch (ECOFF_UNMARK_STAB (sym.index))
230833965Sjdp		{
230933965Sjdp		case N_SO:
231033965Sjdp		  main_file_name = current_file_name =
231133965Sjdp		    debug_info->ss + fdr_ptr->issBase + sym.iss;
231233965Sjdp
231333965Sjdp		  /* Check the next symbol to see if it is also an
231433965Sjdp                     N_SO symbol.  */
231533965Sjdp		  if (sym_ptr + external_sym_size < sym_ptr_end)
231633965Sjdp		    {
231733965Sjdp		      SYMR nextsym;
231833965Sjdp
231933965Sjdp		      (*debug_swap->swap_sym_in) (abfd,
232033965Sjdp						  sym_ptr + external_sym_size,
232133965Sjdp						  &nextsym);
232233965Sjdp		      if (ECOFF_IS_STAB (&nextsym)
232333965Sjdp			  && ECOFF_UNMARK_STAB (nextsym.index) == N_SO)
232433965Sjdp			{
232533965Sjdp 			  directory_name = current_file_name;
232633965Sjdp			  main_file_name = current_file_name =
232733965Sjdp			    debug_info->ss + fdr_ptr->issBase + nextsym.iss;
232833965Sjdp			  sym_ptr += external_sym_size;
232933965Sjdp			}
233033965Sjdp		    }
233133965Sjdp		  break;
233233965Sjdp
233333965Sjdp		case N_SOL:
233433965Sjdp		  current_file_name =
233533965Sjdp		    debug_info->ss + fdr_ptr->issBase + sym.iss;
233633965Sjdp		  break;
233733965Sjdp
233833965Sjdp		case N_FUN:
233933965Sjdp		  if (sym.value > offset)
2340130561Sobrien		    past_fn = TRUE;
234133965Sjdp		  else if (sym.value >= low_func_vma)
234233965Sjdp		    {
234333965Sjdp		      low_func_vma = sym.value;
234433965Sjdp		      function_name =
234533965Sjdp			debug_info->ss + fdr_ptr->issBase + sym.iss;
234633965Sjdp		    }
234733965Sjdp		  break;
234833965Sjdp		}
234933965Sjdp	    }
235033965Sjdp	  else if (sym.st == stLabel && sym.index != indexNil)
235133965Sjdp	    {
235233965Sjdp	      if (sym.value > offset)
2353130561Sobrien		past_line = TRUE;
235433965Sjdp	      else if (sym.value >= low_line_vma)
235533965Sjdp		{
235633965Sjdp		  low_line_vma = sym.value;
235733965Sjdp		  line_file_name = current_file_name;
235833965Sjdp		  line_info->cache.line_num = sym.index;
235933965Sjdp		}
236033965Sjdp	    }
236133965Sjdp	}
236233965Sjdp
236333965Sjdp      if (line_info->cache.line_num != 0)
236433965Sjdp	main_file_name = line_file_name;
236533965Sjdp
236633965Sjdp      /* We need to remove the stuff after the colon in the function
236733965Sjdp         name.  We also need to put the directory name and the file
236833965Sjdp         name together.  */
236933965Sjdp      if (function_name == NULL)
237033965Sjdp	len = funclen = 0;
237133965Sjdp      else
237233965Sjdp	len = funclen = strlen (function_name) + 1;
237333965Sjdp
237433965Sjdp      if (main_file_name != NULL
237533965Sjdp	  && directory_name != NULL
237633965Sjdp	  && main_file_name[0] != '/')
237733965Sjdp	len += strlen (directory_name) + strlen (main_file_name) + 1;
237833965Sjdp
237933965Sjdp      if (len != 0)
238033965Sjdp	{
238133965Sjdp	  if (line_info->find_buffer != NULL)
238233965Sjdp	    free (line_info->find_buffer);
238389857Sobrien	  buffer = (char *) bfd_malloc ((bfd_size_type) len);
238433965Sjdp	  if (buffer == NULL)
2385130561Sobrien	    return FALSE;
238633965Sjdp	  line_info->find_buffer = buffer;
238733965Sjdp	}
238833965Sjdp
238933965Sjdp      if (function_name != NULL)
239033965Sjdp	{
239133965Sjdp	  char *colon;
239233965Sjdp
239333965Sjdp	  strcpy (buffer, function_name);
239433965Sjdp	  colon = strchr (buffer, ':');
239533965Sjdp	  if (colon != NULL)
239633965Sjdp	    *colon = '\0';
239733965Sjdp	  line_info->cache.functionname = buffer;
239833965Sjdp	}
239933965Sjdp
240033965Sjdp      if (main_file_name != NULL)
240133965Sjdp	{
240233965Sjdp	  if (directory_name == NULL || main_file_name[0] == '/')
240333965Sjdp	    line_info->cache.filename = main_file_name;
240433965Sjdp	  else
240533965Sjdp	    {
240633965Sjdp	      sprintf (buffer + funclen, "%s%s", directory_name,
240733965Sjdp		       main_file_name);
240833965Sjdp	      line_info->cache.filename = buffer + funclen;
240933965Sjdp	    }
241033965Sjdp	}
241133965Sjdp    }
241233965Sjdp
2413130561Sobrien  return TRUE;
241433965Sjdp}
241533965Sjdp
241633965Sjdp/* Do the work of find_nearest_line.  */
241733965Sjdp
2418130561Sobrienbfd_boolean
241933965Sjdp_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap,
242033965Sjdp			line_info, filename_ptr, functionname_ptr, retline_ptr)
242133965Sjdp     bfd *abfd;
242233965Sjdp     asection *section;
242333965Sjdp     bfd_vma offset;
242433965Sjdp     struct ecoff_debug_info * const debug_info;
242533965Sjdp     const struct ecoff_debug_swap * const debug_swap;
242633965Sjdp     struct ecoff_find_line *line_info;
242733965Sjdp     const char **filename_ptr;
242833965Sjdp     const char **functionname_ptr;
242933965Sjdp     unsigned int *retline_ptr;
243033965Sjdp{
243133965Sjdp  offset += section->vma;
243233965Sjdp
243333965Sjdp  if (line_info->cache.sect == NULL
243433965Sjdp      || line_info->cache.sect != section
243533965Sjdp      || offset < line_info->cache.start
243633965Sjdp      || offset >= line_info->cache.stop)
243733965Sjdp    {
243833965Sjdp      line_info->cache.sect = section;
243933965Sjdp      line_info->cache.start = offset;
244033965Sjdp      line_info->cache.stop = offset;
244133965Sjdp      if (! lookup_line (abfd, debug_info, debug_swap, line_info))
244233965Sjdp	{
244333965Sjdp	  line_info->cache.sect = NULL;
2444130561Sobrien	  return FALSE;
244533965Sjdp	}
244633965Sjdp    }
244733965Sjdp
244833965Sjdp  *filename_ptr = line_info->cache.filename;
244933965Sjdp  *functionname_ptr = line_info->cache.functionname;
245033965Sjdp  *retline_ptr = line_info->cache.line_num;
245133965Sjdp
2452130561Sobrien  return TRUE;
245333965Sjdp}
245433965Sjdp
245533965Sjdp/* These routines copy symbolic information into a memory buffer.
245633965Sjdp
245733965Sjdp   FIXME: The whole point of the shuffle code is to avoid storing
245833965Sjdp   everything in memory, since the linker is such a memory hog.  This
245933965Sjdp   code makes that effort useless.  It is only called by the MIPS ELF
246033965Sjdp   code when generating a shared library, so it is not that big a
246133965Sjdp   deal, but it should be fixed eventually.  */
246233965Sjdp
246333965Sjdp/* Collect a shuffle into a memory buffer.  */
246433965Sjdp
2465130561Sobrienstatic bfd_boolean ecoff_collect_shuffle
2466130561Sobrien  PARAMS ((struct shuffle *, bfd_byte *));
246733965Sjdp
2468130561Sobrienstatic bfd_boolean
246933965Sjdpecoff_collect_shuffle (l, buff)
247033965Sjdp     struct shuffle *l;
247133965Sjdp     bfd_byte *buff;
247233965Sjdp{
247333965Sjdp  unsigned long total;
247433965Sjdp
247533965Sjdp  total = 0;
247633965Sjdp  for (; l != (struct shuffle *) NULL; l = l->next)
247733965Sjdp    {
247833965Sjdp      if (! l->filep)
247933965Sjdp	memcpy (buff, l->u.memory, l->size);
248033965Sjdp      else
248133965Sjdp	{
248233965Sjdp	  if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
248389857Sobrien	      || (bfd_bread (buff, (bfd_size_type) l->size, l->u.file.input_bfd)
248489857Sobrien		  != l->size))
2485130561Sobrien	    return FALSE;
248633965Sjdp	}
248733965Sjdp      total += l->size;
248833965Sjdp      buff += l->size;
248933965Sjdp    }
249033965Sjdp
2491130561Sobrien  return TRUE;
249233965Sjdp}
249333965Sjdp
249433965Sjdp/* Copy PDR information into a memory buffer.  */
249533965Sjdp
2496130561Sobrienbfd_boolean
249733965Sjdp_bfd_ecoff_get_accumulated_pdr (handle, buff)
249833965Sjdp     PTR handle;
249933965Sjdp     bfd_byte *buff;
250033965Sjdp{
250133965Sjdp  struct accumulate *ainfo = (struct accumulate *) handle;
250233965Sjdp
250333965Sjdp  return ecoff_collect_shuffle (ainfo->pdr, buff);
250433965Sjdp}
250533965Sjdp
250633965Sjdp/* Copy symbol information into a memory buffer.  */
250733965Sjdp
2508130561Sobrienbfd_boolean
250933965Sjdp_bfd_ecoff_get_accumulated_sym (handle, buff)
251033965Sjdp     PTR handle;
251133965Sjdp     bfd_byte *buff;
251233965Sjdp{
251333965Sjdp  struct accumulate *ainfo = (struct accumulate *) handle;
251433965Sjdp
251533965Sjdp  return ecoff_collect_shuffle (ainfo->sym, buff);
251633965Sjdp}
251733965Sjdp
251833965Sjdp/* Copy the string table into a memory buffer.  */
251933965Sjdp
2520130561Sobrienbfd_boolean
252133965Sjdp_bfd_ecoff_get_accumulated_ss (handle, buff)
252233965Sjdp     PTR handle;
252333965Sjdp     bfd_byte *buff;
252433965Sjdp{
252533965Sjdp  struct accumulate *ainfo = (struct accumulate *) handle;
252633965Sjdp  struct string_hash_entry *sh;
252733965Sjdp  unsigned long total;
252833965Sjdp
252933965Sjdp  /* The string table is written out from the hash table if this is a
253033965Sjdp     final link.  */
253133965Sjdp  BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
253233965Sjdp  *buff++ = '\0';
253333965Sjdp  total = 1;
253433965Sjdp  BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
253533965Sjdp  for (sh = ainfo->ss_hash;
253633965Sjdp       sh != (struct string_hash_entry *) NULL;
253733965Sjdp       sh = sh->next)
253833965Sjdp    {
253933965Sjdp      size_t len;
254033965Sjdp
254133965Sjdp      len = strlen (sh->root.string);
254233965Sjdp      memcpy (buff, (PTR) sh->root.string, len + 1);
254333965Sjdp      total += len + 1;
254433965Sjdp      buff += len + 1;
254533965Sjdp    }
254633965Sjdp
2547130561Sobrien  return TRUE;
254833965Sjdp}
2549