* coff-h8300.c (COFF_LONG_FILENAMES): Define.
[deliverable/binutils-gdb.git] / bfd / ecoff.c
index ba5214c5d3d80870e8ee9a4ce323f643e350e4af..f5461aee0d42cd93900b7efaca3d5c3ef402e1c7 100644 (file)
@@ -1,5 +1,5 @@
 /* Generic ECOFF (Extended-COFF) routines.
-   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Original version by Per Bothner.
    Full support added by Ian Lance Taylor, ian@cygnus.com.
 
@@ -25,6 +25,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "libbfd.h"
 #include "aout/ar.h"
 #include "aout/ranlib.h"
+#include "aout/stab_gnu.h"
 
 /* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines
    some other stuff which we don't want and which conflicts with stuff
@@ -45,6 +46,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /* Prototypes for static functions.  */
 
 static int ecoff_get_magic PARAMS ((bfd *abfd));
+static long ecoff_sec_to_styp_flags PARAMS ((const char *name,
+                                            flagword flags));
 static boolean ecoff_slurp_symbolic_header PARAMS ((bfd *abfd));
 static boolean ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym,
                                           asymbol *asym, int ext,
@@ -73,7 +76,7 @@ static asection bfd_debug_section = { "*DEBUG*" };
 /* Create an ECOFF object.  */
 
 boolean
-ecoff_mkobject (abfd)
+_bfd_ecoff_mkobject (abfd)
      bfd *abfd;
 {
   abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *)
@@ -91,7 +94,7 @@ ecoff_mkobject (abfd)
    specific information.  */
 
 PTR
-ecoff_mkobject_hook (abfd, filehdr, aouthdr)
+_bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr)
      bfd *abfd;
      PTR filehdr;
      PTR aouthdr;
@@ -100,7 +103,7 @@ ecoff_mkobject_hook (abfd, filehdr, aouthdr)
   struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
   ecoff_data_type *ecoff;
 
-  if (ecoff_mkobject (abfd) == false)
+  if (_bfd_ecoff_mkobject (abfd) == false)
     return NULL;
 
   ecoff = ecoff_data (abfd);
@@ -135,7 +138,7 @@ ecoff_mkobject_hook (abfd, filehdr, aouthdr)
 
 /*ARGSUSED*/
 asection *
-ecoff_make_section_hook (abfd, name)
+_bfd_ecoff_make_section_hook (abfd, name)
      bfd *abfd;
      char *name;
 {
@@ -145,19 +148,22 @@ ecoff_make_section_hook (abfd, name)
 /* Initialize a new section.  */
 
 boolean
-ecoff_new_section_hook (abfd, section)
+_bfd_ecoff_new_section_hook (abfd, section)
      bfd *abfd;
      asection *section;
 {
   /* For the .pdata section, which has a special meaning on the Alpha,
-     we set the alignment to 8.  We correct this later in
+     we set the alignment power to 3.  We correct this later in
      ecoff_compute_section_file_positions.  We do this hackery because
      we need to know the exact unaligned size of the .pdata section in
-     order to set the lnnoptr field correctly.  */
+     order to set the lnnoptr field correctly.  For every other
+     section we use an alignment power of 4; this could be made target
+     dependent by adding a field to ecoff_backend_data, but 4 appears
+     to be correct for both the MIPS and the Alpha.  */
   if (strcmp (section->name, _PDATA) == 0)
     section->alignment_power = 3;
   else
-    section->alignment_power = abfd->xvec->align_power_min;
+    section->alignment_power = 4;
 
   if (strcmp (section->name, _TEXT) == 0)
     section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
@@ -190,7 +196,7 @@ ecoff_new_section_hook (abfd, section)
    for each target, but there aren't all that many ECOFF targets.  */
 
 boolean
-ecoff_set_arch_mach_hook (abfd, filehdr)
+_bfd_ecoff_set_arch_mach_hook (abfd, filehdr)
      bfd *abfd;
      PTR filehdr;
 {
@@ -236,7 +242,7 @@ ecoff_set_arch_mach_hook (abfd, filehdr)
 }
 
 /* Get the magic number to use based on the architecture and machine.
-   This is the inverse of ecoff_set_arch_mach_hook, above.  */
+   This is the inverse of _bfd_ecoff_set_arch_mach_hook, above.  */
 
 static int
 ecoff_get_magic (abfd)
@@ -280,9 +286,9 @@ ecoff_get_magic (abfd)
 
 /* Get the section s_flags to use for a section.  */
 
-long
+static long
 ecoff_sec_to_styp_flags (name, flags)
-     CONST char *name;
+     const char *name;
      flagword flags;
 {
   long styp;
@@ -338,9 +344,10 @@ ecoff_sec_to_styp_flags (name, flags)
 
 /*ARGSUSED*/
 flagword
-ecoff_styp_to_sec_flags (abfd, hdr)
+_bfd_ecoff_styp_to_sec_flags (abfd, hdr, name)
      bfd *abfd;
      PTR hdr;
+     const char *name;
 {
   struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
   long styp_flags = internal_s->s_flags;
@@ -410,9 +417,9 @@ ecoff_styp_to_sec_flags (abfd, hdr)
    info comes from the file header record (fh-fBigendian).  */
 
 void
-ecoff_swap_tir_in (bigend, ext_copy, intern)
+_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
      int bigend;
-     struct tir_ext *ext_copy;
+     const struct tir_ext *ext_copy;
      TIR *intern;
 {
   struct tir_ext ext[1];
@@ -467,9 +474,9 @@ ecoff_swap_tir_in (bigend, ext_copy, intern)
    info comes from the file header record (fh-fBigendian).  */
 
 void
-ecoff_swap_tir_out (bigend, intern_copy, ext)
+_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
      int bigend;
-     TIR *intern_copy;
+     const TIR *intern_copy;
      struct tir_ext *ext;
 {
   TIR intern[1];
@@ -523,9 +530,9 @@ ecoff_swap_tir_out (bigend, intern_copy, ext)
    big-endian or little-endian format.*/
 
 void
-ecoff_swap_rndx_in (bigend, ext_copy, intern)
+_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
      int bigend;
-     struct rndx_ext *ext_copy;
+     const struct rndx_ext *ext_copy;
      RNDXR *intern;
 {
   struct rndx_ext ext[1];
@@ -562,9 +569,9 @@ ecoff_swap_rndx_in (bigend, ext_copy, intern)
    big-endian or little-endian format.*/
 
 void
-ecoff_swap_rndx_out (bigend, intern_copy, ext)
+_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
      int bigend;
-     RNDXR *intern_copy;
+     const RNDXR *intern_copy;
      struct rndx_ext *ext;
 {
   RNDXR intern[1];
@@ -665,11 +672,15 @@ ecoff_slurp_symbolic_header (abfd)
 }
 
 /* Read in and swap the important symbolic information for an ECOFF
-   object file.  This is called by gdb.  */
+   object file.  This is called by gdb via the read_debug_info entry
+   point in the backend structure.  */
 
+/*ARGSUSED*/
 boolean
-ecoff_slurp_symbolic_info (abfd)
+_bfd_ecoff_slurp_symbolic_info (abfd, ignore, debug)
      bfd *abfd;
+     asection *ignore;
+     struct ecoff_debug_info *debug;
 {
   const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
   HDRR *internal_symhdr;
@@ -683,6 +694,8 @@ ecoff_slurp_symbolic_info (abfd)
   bfd_size_type raw_end;
   bfd_size_type cb_end;
 
+  BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info);
+
   /* Check whether we've already gotten it, and whether there's any to
      get.  */
   if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
@@ -696,7 +709,7 @@ ecoff_slurp_symbolic_info (abfd)
   if (! ecoff_slurp_symbolic_header (abfd))
     return false;
 
-  internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
+  internal_symhdr = &debug->symbolic_header;
 
   /* Read all the symbolic information at once.  */
   raw_base = (ecoff_data (abfd)->sym_filepos
@@ -756,11 +769,11 @@ ecoff_slurp_symbolic_info (abfd)
   /* Get pointers for the numeric offsets in the HDRR structure.  */
 #define FIX(off1, off2, type) \
   if (internal_symhdr->off1 == 0) \
-    ecoff_data (abfd)->debug_info.off2 = (type) NULL; \
+    debug->off2 = (type) NULL; \
   else \
-    ecoff_data (abfd)->debug_info.off2 = (type) ((char *) raw \
-                                                + internal_symhdr->off1 \
-                                                - raw_base)
+    debug->off2 = (type) ((char *) raw \
+                         + internal_symhdr->off1 \
+                         - raw_base)
   FIX (cbLineOffset, line, unsigned char *);
   FIX (cbDnOffset, external_dnr, PTR);
   FIX (cbPdOffset, external_pdr, PTR);
@@ -782,18 +795,17 @@ ecoff_slurp_symbolic_info (abfd)
 
      We need to look at the fdr to deal with a lot of information in
      the symbols, so we swap them here.  */
-  ecoff_data (abfd)->debug_info.fdr =
-    (struct fdr *) bfd_alloc (abfd,
-                             (internal_symhdr->ifdMax *
-                              sizeof (struct fdr)));
-  if (ecoff_data (abfd)->debug_info.fdr == NULL)
+  debug->fdr = (struct fdr *) bfd_alloc (abfd,
+                                        (internal_symhdr->ifdMax *
+                                         sizeof (struct fdr)));
+  if (debug->fdr == NULL)
     {
       bfd_set_error (bfd_error_no_memory);
       return false;
     }
   external_fdr_size = backend->debug_swap.external_fdr_size;
-  fdr_ptr = ecoff_data (abfd)->debug_info.fdr;
-  fraw_src = (char *) ecoff_data (abfd)->debug_info.external_fdr;
+  fdr_ptr = debug->fdr;
+  fraw_src = (char *) debug->external_fdr;
   fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size;
   for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
     (*backend->debug_swap.swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
@@ -816,7 +828,7 @@ static asymbol *ecoff_scom_symbol_ptr;
 /* Create an empty symbol.  */
 
 asymbol *
-ecoff_make_empty_symbol (abfd)
+_bfd_ecoff_make_empty_symbol (abfd)
      bfd *abfd;
 {
   ecoff_symbol_type *new;
@@ -849,7 +861,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
   asym->the_bfd = abfd;
   asym->value = ecoff_sym->value;
   asym->section = &bfd_debug_section;
-  asym->udata = NULL;
+  asym->udata.i = 0;
 
   /* An indirect symbol requires two consecutive stabs symbols.  */
   if (*indirect_ptr_ptr != (asymbol *) NULL)
@@ -864,7 +876,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
       (*indirect_ptr_ptr)->value = (bfd_vma) asym;
 
       asym->flags = BSF_DEBUGGING;
-      asym->section = &bfd_und_section;
+      asym->section = bfd_und_section_ptr;
       *indirect_ptr_ptr = NULL;
       return true;
     }
@@ -873,7 +885,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
       && (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT))
     {
       asym->flags = BSF_DEBUGGING | BSF_INDIRECT;
-      asym->section = &bfd_ind_section;
+      asym->section = bfd_ind_section_ptr;
       /* Pass this symbol on to the next call to this function.  */
       *indirect_ptr_ptr = asym;
       return true;
@@ -903,7 +915,19 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
   if (ext)
     asym->flags = BSF_EXPORT | BSF_GLOBAL;
   else
-    asym->flags = BSF_LOCAL;
+    {
+      asym->flags = BSF_LOCAL;
+      /* Normally, a local stProc symbol will have a corresponding
+         external symbol.  We mark the local symbol as a debugging
+         symbol, in order to prevent nm from printing both out.
+         Similarly, we mark stLabel and stabs symbols as debugging
+         symbols.  In both cases, we do want to set the value
+         correctly based on the symbol class.  */
+      if (ecoff_sym->st == stProc
+         || ecoff_sym->st == stLabel
+         || ECOFF_IS_STAB (ecoff_sym))
+       asym->flags |= BSF_DEBUGGING;
+    }
   switch (ecoff_sym->sc)
     {
     case scNil:
@@ -929,10 +953,10 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
       asym->flags = BSF_DEBUGGING;
       break;
     case scAbs:
-      asym->section = &bfd_abs_section;
+      asym->section = bfd_abs_section_ptr;
       break;
     case scUndefined:
-      asym->section = &bfd_und_section;
+      asym->section = bfd_und_section_ptr;
       asym->flags = 0;
       asym->value = 0;
       break;
@@ -962,7 +986,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
     case scCommon:
       if (asym->value > ecoff_data (abfd)->gp_size)
        {
-         asym->section = &bfd_com_section;
+         asym->section = bfd_com_section_ptr;
          asym->flags = 0;
          break;
        }
@@ -989,7 +1013,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
       asym->flags = BSF_DEBUGGING;
       break;
     case scSUndefined:
-      asym->section = &bfd_und_section;
+      asym->section = bfd_und_section_ptr;
       asym->flags = 0;
       asym->value = 0;
       break;
@@ -1102,7 +1126,7 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr)
 /* Read an ECOFF symbol table.  */
 
 boolean
-ecoff_slurp_symbol_table (abfd)
+_bfd_ecoff_slurp_symbol_table (abfd)
      bfd *abfd;
 {
   const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
@@ -1128,7 +1152,8 @@ ecoff_slurp_symbol_table (abfd)
     return true;
 
   /* Get the symbolic information.  */
-  if (ecoff_slurp_symbolic_info (abfd) == false)
+  if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
+                                       &ecoff_data (abfd)->debug_info))
     return false;
   if (bfd_get_symcount (abfd) == 0)
     return true;
@@ -1208,10 +1233,11 @@ ecoff_slurp_symbol_table (abfd)
 /* Return the amount of space needed for the canonical symbols.  */
 
 long
-ecoff_get_symtab_upper_bound (abfd)
+_bfd_ecoff_get_symtab_upper_bound (abfd)
      bfd *abfd;
 {
-  if (! ecoff_slurp_symbolic_info (abfd))
+  if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
+                                       &ecoff_data (abfd)->debug_info))
     return -1;
 
   if (bfd_get_symcount (abfd) == 0)
@@ -1223,7 +1249,7 @@ ecoff_get_symtab_upper_bound (abfd)
 /* Get the canonical symbols.  */
 
 long
-ecoff_get_symtab (abfd, alocation)
+_bfd_ecoff_get_symtab (abfd, alocation)
      bfd *abfd;
      asymbol **alocation;
 {
@@ -1231,7 +1257,7 @@ ecoff_get_symtab (abfd, alocation)
   ecoff_symbol_type *symbase;
   ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
 
-  if (ecoff_slurp_symbol_table (abfd) == false)
+  if (_bfd_ecoff_slurp_symbol_table (abfd) == false)
     return -1;
   if (bfd_get_symcount (abfd) == 0)
     return 0;
@@ -1332,7 +1358,7 @@ ecoff_type_to_string (abfd, fdr, indx)
   } qualifiers[7];
   unsigned int basic_type;
   int i;
-  static char buffer1[1024];
+  char buffer1[1024];
   static char buffer2[1024];
   char *p1 = buffer1;
   char *p2 = buffer2;
@@ -1350,7 +1376,7 @@ ecoff_type_to_string (abfd, fdr, indx)
 
   if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == -1)
     return "-1 (no type)";
-  ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
+  _bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
 
   basic_type = u.ti.bt;
   qualifiers[0].type = u.ti.tq0;
@@ -1419,7 +1445,7 @@ ecoff_type_to_string (abfd, fdr, indx)
         2nd word is file index if 1st word rfd is ST_RFDESCAPE.  */
 
     case btStruct:             /* Structure (Record) */
-      ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+      _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
       ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
                            (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
                            "struct");
@@ -1431,7 +1457,7 @@ ecoff_type_to_string (abfd, fdr, indx)
         2nd word is file index if 1st word rfd is ST_RFDESCAPE.  */
 
     case btUnion:              /* Union */
-      ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+      _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
       ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
                            (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
                            "union");
@@ -1443,7 +1469,7 @@ ecoff_type_to_string (abfd, fdr, indx)
         2nd word is file index if 1st word rfd is ST_RFDESCAPE.  */
 
     case btEnum:               /* Enumeration */
-      ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+      _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
       ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
                            (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
                            "enum");
@@ -1626,7 +1652,7 @@ ecoff_type_to_string (abfd, fdr, indx)
 
 /*ARGSUSED*/
 void
-ecoff_get_symbol_info (abfd, symbol, ret)
+_bfd_ecoff_get_symbol_info (abfd, symbol, ret)
      bfd *abfd;                        /* Ignored.  */
      asymbol *symbol;
      symbol_info *ret;
@@ -1637,7 +1663,7 @@ ecoff_get_symbol_info (abfd, symbol, ret)
 /* Print information about an ECOFF symbol.  */
 
 void
-ecoff_print_symbol (abfd, filep, symbol, how)
+_bfd_ecoff_print_symbol (abfd, filep, symbol, how)
      bfd *abfd;
      PTR filep;
      asymbol *symbol;
@@ -1844,7 +1870,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols)
       || (section->flags & SEC_CONSTRUCTOR) != 0)
     return true;
 
-  if (ecoff_slurp_symbol_table (abfd) == false)
+  if (_bfd_ecoff_slurp_symbol_table (abfd) == false)
     return false;
   
   internal_relocs = (arelent *) bfd_alloc (abfd,
@@ -1886,7 +1912,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols)
       else if (intern.r_symndx == RELOC_SECTION_NONE
               || intern.r_symndx == RELOC_SECTION_ABS)
        {
-         rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
+         rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
          rptr->addend = 0;
        }
       else
@@ -1938,7 +1964,7 @@ ecoff_slurp_reloc_table (abfd, section, symbols)
 /* Get a canonical list of relocs.  */
 
 long
-ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
+_bfd_ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
      bfd *abfd;
      asection *section;
      arelent **relptr;
@@ -1976,19 +2002,172 @@ ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
   return section->reloc_count;
 }
 \f
+
+static int
+cmp_fdrtab_entry (leftp, rightp)
+     const void *leftp, *rightp;
+{
+  const struct ecoff_fdrtab_entry *lp = leftp;
+  const struct ecoff_fdrtab_entry *rp = rightp;
+
+  if (lp->base_addr < rp->base_addr)
+    return -1;
+  if (lp->base_addr > rp->base_addr)
+    return  1;
+  return 0;
+}
+
+/* Each file descriptor (FDR) has a memory address, to simplify
+   looking up an FDR by address, we build a table covering all FDRs
+   that have a least one procedure descriptor in them.  The final
+   table will be sorted by address so we can look it up via binary
+   search.  */
+static boolean
+mk_fdrtab (abfd)
+     bfd *abfd;
+{
+  struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
+  const struct ecoff_debug_swap * const debug_swap
+    = &ecoff_backend (abfd)->debug_swap;
+  struct ecoff_fdrtab_entry *tab;
+  FDR *fdr_ptr;
+  FDR *fdr_start;
+  FDR *fdr_end;
+  boolean stabs;
+  long len;
+
+  /* Make sure we have the FDR's.  */
+  if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, debug_info)
+      || bfd_get_symcount (abfd) == 0)
+    return false;
+
+  fdr_start = debug_info->fdr;
+  fdr_end = fdr_start + debug_info->symbolic_header.ifdMax;
+
+  /* First, let's see how long the table needs to be: */
+  for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
+    {
+      if (fdr_ptr->cpd == 0)   /* skip FDRs that have no PDRs */
+       continue;
+      ++len;
+    }
+
+  /* Now, create and fill in the table: */
+
+  ecoff_data (abfd)->fdrtab = (struct ecoff_fdrtab_entry*)
+    bfd_zalloc (abfd,len * sizeof (struct ecoff_fdrtab_entry));
+  if (ecoff_data (abfd)->fdrtab == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return false;
+    }
+  ecoff_data (abfd)->fdrtab_len = len;
+
+  tab = ecoff_data (abfd)->fdrtab;
+  for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
+    {
+      if (fdr_ptr->cpd == 0)
+       continue;
+
+      /* Check whether this file has stabs debugging information.  In
+        a file with stabs debugging information, the second local
+        symbol is named @stabs.  */
+      stabs = false;
+      if (fdr_ptr->csym >= 2)
+       {
+         char *sym_ptr;
+         SYMR sym;
+
+         sym_ptr = ((char *) debug_info->external_sym
+                    + (fdr_ptr->isymBase + 1)*debug_swap->external_sym_size);
+         (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
+         if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
+                     STABS_SYMBOL) == 0)
+           stabs = true;
+       }
+
+      if (!stabs)
+       {
+         bfd_size_type external_pdr_size;
+         char *pdr_ptr;
+         PDR pdr;
+
+         external_pdr_size = debug_swap->external_pdr_size;
+
+         pdr_ptr = ((char *) debug_info->external_pdr
+                    + fdr_ptr->ipdFirst * external_pdr_size);
+         (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+         /* The address of the first PDR is the offset of that
+            procedure relative to the beginning of file FDR.  */
+         tab->base_addr = fdr_ptr->adr - pdr.adr;
+       }
+      else
+       {
+         /* XXX I don't know about stabs, so this is a guess
+            (davidm@cs.arizona.edu): */
+         tab->base_addr = fdr_ptr->adr;
+       }
+      tab->fdr = fdr_ptr;
+      ++tab;
+    }
+  /* Finally, the table is sorted in increasing memory-address order.
+     The table is mostly sorted already, but there are cases (e.g.,
+     static functions in include files), where this does not hold.
+     Use "odump -PFv" to verify...  */
+  qsort((char*) ecoff_data (abfd)->fdrtab, len,
+       sizeof(struct ecoff_fdrtab_entry), cmp_fdrtab_entry);
+
+  return true;
+}
+
+/* Return index of first FDR that covers to OFFSET.  */
+static long
+lookup (abfd, offset)
+     bfd *abfd;
+     bfd_vma offset;
+{
+  long low, high, len;
+  long mid = -1;
+  struct ecoff_fdrtab_entry *tab;
+
+  len = ecoff_data(abfd)->fdrtab_len;
+  if (!len)
+    return -1;
+
+  tab = ecoff_data(abfd)->fdrtab;
+  for (low = 0, high = len - 1 ; low != high ;)
+    {
+      mid = (high + low) / 2;
+      if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr)
+       goto find_min;
+
+      if (tab[mid].base_addr > offset)
+       high = mid;
+      else
+       low = mid + 1;
+    }
+  ++mid;
+
+  /* last entry is catch-all for all higher addresses: */
+  if (offset < tab[mid].base_addr)
+    return -1;
+
+ find_min:
+
+  while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr)
+    --mid;
+
+  return mid;
+}
+
 /* Provided a BFD, a section and an offset into the section, calculate
    and return the name of the source file and the line nearest to the
    wanted location.  */
 
 /*ARGSUSED*/
 boolean
-ecoff_find_nearest_line (abfd,
-                        section,
-                        ignore_symbols,
-                        offset,
-                        filename_ptr,
-                        functionname_ptr,
-                        retline_ptr)
+_bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
+                             filename_ptr, functionname_ptr, retline_ptr)
      bfd *abfd;
      asection *section;
      asymbol **ignore_symbols;
@@ -1999,156 +2178,396 @@ ecoff_find_nearest_line (abfd,
 {
   const struct ecoff_debug_swap * const debug_swap
     = &ecoff_backend (abfd)->debug_swap;
+  struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
+  struct ecoff_fdrtab_entry *tab;
+  boolean stabs;
   FDR *fdr_ptr;
-  FDR *fdr_start;
-  FDR *fdr_end;
-  FDR *fdr_hold;
-  bfd_size_type external_pdr_size;
-  char *pdr_ptr;
-  char *pdr_end;
-  PDR pdr;
-  unsigned char *line_ptr;
-  unsigned char *line_end;
-  int lineno;
+  int i;
 
+  offset += section->vma;
   /* If we're not in the .text section, we don't have any line
      numbers.  */
   if (strcmp (section->name, _TEXT) != 0
       || offset < ecoff_data (abfd)->text_start
       || offset >= ecoff_data (abfd)->text_end)
     return false;
-
-  /* Make sure we have the FDR's.  */
-  if (ecoff_slurp_symbolic_info (abfd) == false
-      || bfd_get_symcount (abfd) == 0)
-    return false;
-
-  /* Each file descriptor (FDR) has a memory address.  Here we track
-     down which FDR we want.  The FDR's are stored in increasing
-     memory order.  If speed is ever important, this can become a
-     binary search.  We must ignore FDR's with no PDR entries; they
-     will have the adr of the FDR before or after them.  */
-  fdr_start = ecoff_data (abfd)->debug_info.fdr;
-  fdr_end = fdr_start + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax;
-  fdr_hold = (FDR *) NULL;
-  for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
-    {
-      if (fdr_ptr->cpd == 0)
-       continue;
-      if (offset < fdr_ptr->adr)
-       break;
-      fdr_hold = fdr_ptr;
-    }
-  if (fdr_hold == (FDR *) NULL)
+  /* Build FDR table (sorted by object file's base-address) if we
+     don't have it already.  */
+  if (!ecoff_data (abfd)->fdrtab && !mk_fdrtab (abfd))
     return false;
-  fdr_ptr = fdr_hold;
-
-  /* Each FDR has a list of procedure descriptors (PDR).  PDR's also
-     have an address, which is relative to the FDR address, and are
-     also stored in increasing memory order.  */
-  offset -= fdr_ptr->adr;
-  external_pdr_size = debug_swap->external_pdr_size;
-  pdr_ptr = ((char *) ecoff_data (abfd)->debug_info.external_pdr
-            + fdr_ptr->ipdFirst * external_pdr_size);
-  pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
-  (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
-
-  /* The address of the first PDR is an offset which applies to the
-     addresses of all the PDR's.  */
-  offset += pdr.adr;
-
-  for (pdr_ptr += external_pdr_size;
-       pdr_ptr < pdr_end;
-       pdr_ptr += external_pdr_size)
+  tab = ecoff_data (abfd)->fdrtab;
+
+  i = lookup(abfd, offset);    /* find first FDR for address OFFSET */
+  if (i < 0)
+    return false;              /* no FDR, no fun... */
+  fdr_ptr = tab[i].fdr;
+
+  /* Check whether this file has stabs debugging information.  In a
+     file with stabs debugging information, the second local symbol is
+     named @stabs.  */
+  stabs = false;
+  if (fdr_ptr->csym >= 2)
     {
-      (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
-      if (offset < pdr.adr)
-       break;
+      char *sym_ptr;
+      SYMR sym;
+
+      sym_ptr = ((char *) debug_info->external_sym
+                + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
+      (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
+      if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
+                 STABS_SYMBOL) == 0)
+       stabs = true;
     }
 
-  /* Now we can look for the actual line number.  The line numbers are
-     stored in a very funky format, which I won't try to describe.
-     Note that right here pdr_ptr and pdr hold the PDR *after* the one
-     we want; we need this to compute line_end.  */
-  line_end = ecoff_data (abfd)->debug_info.line;
-  if (pdr_ptr == pdr_end)
-    line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
-  else
-    line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset;
-
-  /* Now change pdr and pdr_ptr to the one we want.  */
-  pdr_ptr -= external_pdr_size;
-  (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
-
-  offset -= pdr.adr;
-  lineno = pdr.lnLow;
-  line_ptr = (ecoff_data (abfd)->debug_info.line
-             + fdr_ptr->cbLineOffset
-             + pdr.cbLineOffset);
-  while (line_ptr < line_end)
+  if (!stabs)
     {
-      int delta;
-      int count;
-
-      delta = *line_ptr >> 4;
-      if (delta >= 0x8)
-       delta -= 0x10;
-      count = (*line_ptr & 0xf) + 1;
-      ++line_ptr;
-      if (delta == -8)
+      bfd_size_type external_pdr_size;
+      char *pdr_ptr;
+      char *best_pdr = NULL;
+      FDR *best_fdr;
+      bfd_vma best_dist = ~0;
+      PDR pdr;
+      unsigned char *line_ptr;
+      unsigned char *line_end;
+      int lineno;
+      /* This file uses ECOFF debugging information.  Each FDR has a
+         list of procedure descriptors (PDR).  The address in the FDR
+         is the absolute address of the first procedure.  The address
+         in the first PDR gives the offset of that procedure relative
+         to the object file's base-address.  The addresses in
+         subsequent PDRs specify each procedure's address relative to
+         the object file's base-address.  To make things more juicy,
+         whenever the PROF bit in the PDR is set, the real entry point
+         of the procedure may be 16 bytes below what would normally be
+         the procedure's entry point.  Instead, DEC came up with a
+         wicked scheme to create profiled libraries "on the fly":
+         instead of shipping a regular and a profiled version of each
+         library, they insert 16 bytes of unused space in front of
+         each procedure and set the "prof" bit in the PDR to indicate
+         that there is a gap there (this is done automagically by "as"
+         when option "-pg" is specified).  Thus, normally, you link
+         against such a library and, except for lots of 16 byte gaps
+         between functions, things will behave as usual.  However,
+         when invoking "ld" with option "-pg", it will fill those gaps
+         with code that calls mcount().  It then moves the function's
+         entry point down by 16 bytes, and out pops a binary that has
+         all functions profiled.
+
+         NOTE: Neither FDRs nor PDRs are strictly sorted in memory
+               order.  For example, when including header-files that
+               define functions, the FDRs follow behind the including
+               file, even though their code may have been generated at
+               a lower address.  File coff-alpha.c from libbfd
+               illustrates this (use "odump -PFv" to look at a file's
+               FDR/PDR).  Similarly, PDRs are sometimes out of order
+               as well.  An example of this is OSF/1 v3.0 libc's
+               malloc.c.  I'm not sure why this happens, but it could
+               be due to optimizations that reorder a function's
+               position within an object-file.
+        
+         Strategy:
+         
+         On the first call to this function, we build a table of FDRs
+         that is sorted by the base-address of the object-file the FDR
+         is referring to.  Notice that each object-file may contain
+         code from multiple source files (e.g., due to code defined in
+         include files).  Thus, for any given base-address, there may
+         be multiple FDRs (but this case is, fortunately, uncommon).
+         lookup(addr) guarantees to return the first FDR that applies
+         to address ADDR.  Thus, after invoking lookup(), we have a
+         list of FDRs that may contain the PDR for ADDR.  Next, we
+         walk through the PDRs of these FDRs and locate the one that
+         is closest to ADDR (i.e., for which the difference between
+         ADDR and the PDR's entry point is positive and minimal).
+         Once, the right FDR and PDR are located, we simply walk
+         through the line-number table to lookup the line-number that
+         best matches ADDR.  Obviously, things could be sped up by
+         keeping a sorted list of PDRs instead of a sorted list of
+         FDRs.  However, this would increase space requirements
+         considerably, which is undesirable.  */
+      external_pdr_size = debug_swap->external_pdr_size;
+
+      /* Make offset relative to object file's start-address: */
+      offset -= tab[i].base_addr;
+      /* Search FDR list starting at tab[i] for the PDR that best matches
+         OFFSET.  Normally, the FDR list is only one entry long.  */
+      best_fdr = NULL;
+      do
        {
-         delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
-         if (delta >= 0x8000)
-           delta -= 0x10000;
-         line_ptr += 2;
+         bfd_vma dist, min_dist = 0;
+         char *pdr_hold;
+         char *pdr_end;
+         
+         fdr_ptr = tab[i].fdr;
+         
+         pdr_ptr = ((char *) debug_info->external_pdr
+                    + fdr_ptr->ipdFirst * external_pdr_size);
+         pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
+         (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+         /* Find PDR that is closest to OFFSET.  If pdr.prof is set,
+            the procedure entry-point *may* be 0x10 below pdr.adr.  We
+            simply pretend that pdr.prof *implies* a lower entry-point.
+            This is safe because it just means that may identify 4 NOPs
+            in front of the function as belonging to the function.  */
+         for (pdr_hold = NULL;
+              pdr_ptr < pdr_end;
+              (pdr_ptr += external_pdr_size,
+               (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr)))
+           {
+             if (offset >= (pdr.adr - 0x10 * pdr.prof))
+               {
+                 dist = offset - (pdr.adr - 0x10 * pdr.prof);
+                 if (!pdr_hold || dist < min_dist)
+                   {
+                     min_dist = dist;
+                     pdr_hold = pdr_ptr;
+                   }
+               }
+           }
+         
+         if (!best_pdr || min_dist < best_dist)
+           {
+             best_dist = min_dist;
+             best_fdr = fdr_ptr;
+             best_pdr = pdr_hold;
+           }
+         /* continue looping until base_addr of next entry is different: */
        }
-      lineno += delta;
-      if (offset < count * 4)
-       break;
-      offset -= count * 4;
-    }
+      while (++i < ecoff_data (abfd)->fdrtab_len
+            && tab[i].base_addr == tab[i - 1].base_addr);
 
-  /* If fdr_ptr->rss is -1, then this file does not have full symbols,
-     at least according to gdb/mipsread.c.  */
-  if (fdr_ptr->rss == -1)
-    {
-      *filename_ptr = NULL;
-      if (pdr.isym == -1)
-       *functionname_ptr = NULL;
+      if (!best_fdr || !best_pdr)
+       return false;                   /* shouldn't happen... */
+
+      /* phew, finally we got something that we can hold onto: */
+      fdr_ptr = best_fdr;
+      pdr_ptr = best_pdr;
+      (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+      /* Now we can look for the actual line number.  The line numbers
+         are stored in a very funky format, which I won't try to
+         describe.  The search is bounded by the end of the FDRs line
+         number entries.  */
+      line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
+
+      /* Make offset relative to procedure entry: */
+      offset -= pdr.adr - 0x10 * pdr.prof;
+      lineno = pdr.lnLow;
+      line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset;
+      while (line_ptr < line_end)
+       {
+         int delta;
+         int count;
+
+         delta = *line_ptr >> 4;
+         if (delta >= 0x8)
+           delta -= 0x10;
+         count = (*line_ptr & 0xf) + 1;
+         ++line_ptr;
+         if (delta == -8)
+           {
+             delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
+             if (delta >= 0x8000)
+               delta -= 0x10000;
+             line_ptr += 2;
+           }
+         lineno += delta;
+         if (offset < count * 4)
+           break;
+         offset -= count * 4;
+       }
+
+      /* If fdr_ptr->rss is -1, then this file does not have full
+         symbols, at least according to gdb/mipsread.c.  */
+      if (fdr_ptr->rss == -1)
+       {
+         *filename_ptr = NULL;
+         if (pdr.isym == -1)
+           *functionname_ptr = NULL;
+         else
+           {
+             EXTR proc_ext;
+
+             (*debug_swap->swap_ext_in)
+               (abfd,
+                ((char *) debug_info->external_ext
+                 + pdr.isym * debug_swap->external_ext_size),
+                &proc_ext);
+             *functionname_ptr = debug_info->ssext + proc_ext.asym.iss;
+           }
+       }
       else
        {
-         EXTR proc_ext;
+         SYMR proc_sym;
 
-         (*debug_swap->swap_ext_in)
+         *filename_ptr = debug_info->ss + fdr_ptr->issBase + fdr_ptr->rss;
+         (*debug_swap->swap_sym_in)
            (abfd,
-            ((char *) ecoff_data (abfd)->debug_info.external_ext
-             + pdr.isym * debug_swap->external_ext_size),
-            &proc_ext);
-         *functionname_ptr = (ecoff_data (abfd)->debug_info.ssext
-                              + proc_ext.asym.iss);
+            ((char *) debug_info->external_sym
+             + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size),
+            &proc_sym);
+         *functionname_ptr = debug_info->ss + fdr_ptr->issBase + proc_sym.iss;
        }
+      if (lineno == ilineNil)
+       lineno = 0;
+      *retline_ptr = lineno;
     }
   else
     {
-      SYMR proc_sym;
-
-      *filename_ptr = (ecoff_data (abfd)->debug_info.ss
-                      + fdr_ptr->issBase
-                      + fdr_ptr->rss);
-      (*debug_swap->swap_sym_in)
-       (abfd,
-        ((char *) ecoff_data (abfd)->debug_info.external_sym
-         + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size),
-        &proc_sym);
-      *functionname_ptr = (ecoff_data (abfd)->debug_info.ss
-                          + fdr_ptr->issBase
-                          + proc_sym.iss);
+      bfd_size_type external_sym_size;
+      const char *directory_name;
+      const char *main_file_name;
+      const char *current_file_name;
+      const char *function_name;
+      const char *line_file_name;
+      bfd_vma low_func_vma;
+      bfd_vma low_line_vma;
+      char *sym_ptr, *sym_ptr_end;
+      size_t len, funclen;
+      char *buffer = NULL;
+
+      /* This file uses stabs debugging information.  */
+
+      *filename_ptr = NULL;
+      *functionname_ptr = NULL;
+      *retline_ptr = 0;
+
+      directory_name = NULL;
+      main_file_name = NULL;
+      current_file_name = NULL;
+      function_name = NULL;
+      line_file_name = NULL;
+      low_func_vma = 0;
+      low_line_vma = 0;
+
+      external_sym_size = debug_swap->external_sym_size;
+
+      sym_ptr = ((char *) debug_info->external_sym
+                + (fdr_ptr->isymBase + 2) * external_sym_size);
+      sym_ptr_end = sym_ptr + fdr_ptr->csym * external_sym_size;
+      for (; sym_ptr < sym_ptr_end; sym_ptr += external_sym_size)
+       {
+         SYMR sym;
+
+         (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
+
+         if (ECOFF_IS_STAB (&sym))
+           {
+             switch (ECOFF_UNMARK_STAB (sym.index))
+               {
+               case N_SO:
+                 main_file_name = current_file_name =
+                   debug_info->ss + fdr_ptr->issBase + sym.iss;
+
+                 /* Check the next symbol to see if it is also an
+                     N_SO symbol.  */
+                 if (sym_ptr + external_sym_size < sym_ptr_end)
+                   {
+                     SYMR nextsym;
+
+                     (*debug_swap->swap_sym_in) (abfd,
+                                                 sym_ptr + external_sym_size,
+                                                 &nextsym);
+                     if (ECOFF_IS_STAB (&nextsym)
+                         && ECOFF_UNMARK_STAB (nextsym.index) == N_SO)
+                       {
+                         directory_name = current_file_name;
+                         main_file_name = current_file_name =
+                           debug_info->ss + fdr_ptr->issBase + sym.iss;
+                         sym_ptr += external_sym_size;
+                       }
+                   }
+                 break;
+
+               case N_SOL:
+                 current_file_name =
+                   debug_info->ss + fdr_ptr->issBase + sym.iss;
+                 break;
+
+               case N_FUN:
+                 if (sym.value >= low_func_vma
+                     && sym.value <= offset + section->vma)
+                   {
+                     low_func_vma = sym.value;
+                     function_name =
+                       debug_info->ss + fdr_ptr->issBase + sym.iss;
+                   }
+                 break;
+               }
+           }
+         else if (sym.st == stLabel && sym.index != indexNil)
+           {
+             if (sym.value > offset + section->vma)
+               {
+                 /* We have passed the location in the file we are
+                    looking for, so we can get out of the loop.  */
+                 break;
+               }
+
+             if (sym.value >= low_line_vma)
+               {
+                 low_line_vma = sym.value;
+                 line_file_name = current_file_name;
+                 *retline_ptr = sym.index;
+               }
+           }
+       }
+
+      if (*retline_ptr != 0)
+       main_file_name = line_file_name;
+
+      /* We need to remove the stuff after the colon in the function
+         name.  We also need to put the directory name and the file
+         name together.  */
+      if (function_name == NULL)
+       len = funclen = 0;
+      else
+       len = funclen = strlen (function_name) + 1;
+
+      if (main_file_name != NULL
+         && directory_name != NULL
+         && main_file_name[0] != '/')
+       len += strlen (directory_name) + strlen (main_file_name) + 1;
+
+      if (len != 0)
+       {
+         if (ecoff_data (abfd)->find_buffer != NULL)
+           free (ecoff_data (abfd)->find_buffer);
+         buffer = (char *) malloc (len);
+         if (buffer == NULL)
+           {
+             bfd_set_error (bfd_error_no_memory);
+             return false;
+           }
+         ecoff_data (abfd)->find_buffer = buffer;
+       }
+
+      if (function_name != NULL)
+       {
+         char *colon;
+
+         strcpy (buffer, function_name);
+         colon = strchr (buffer, ':');
+         if (colon != NULL)
+           *colon = '\0';
+         *functionname_ptr = buffer;
+       }
+
+      if (main_file_name != NULL)
+       {
+         if (directory_name == NULL || main_file_name[0] == '/')
+           *filename_ptr = main_file_name;
+         else
+           {
+             sprintf (buffer + funclen, "%s%s", directory_name,
+                      main_file_name);
+             *filename_ptr = buffer + funclen;
+           }
+       }
     }
-  if (lineno == ilineNil)
-    lineno = 0;
-  *retline_ptr = lineno;
+
   return true;
 }
+
 \f
 /* Copy private BFD data.  This is called by objcopy and strip.  We
    use it to copy the ECOFF debugging information from one BFD to the
@@ -2164,7 +2583,7 @@ ecoff_find_nearest_line (abfd,
    information.  */
 
 boolean
-ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
+_bfd_ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
      bfd *ibfd;
      bfd *obfd;
 {
@@ -2175,7 +2594,11 @@ ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
   size_t c;
   boolean local;
 
-  BFD_ASSERT (ibfd->xvec == obfd->xvec);
+  /* This function is selected based on the input vector.  We only
+     want to copy information over if the output BFD also uses ECOFF
+     format.  */
+  if (bfd_get_flavour (obfd) != bfd_target_ecoff_flavour)
+    return true;
 
   /* Copy the GP value and the register masks.  */
   ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp;
@@ -2270,7 +2693,7 @@ ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
    callers ignore the return value.  */
 
 boolean
-ecoff_set_arch_mach (abfd, arch, machine)
+_bfd_ecoff_set_arch_mach (abfd, arch, machine)
      bfd *abfd;
      enum bfd_architecture arch;
      unsigned long machine;
@@ -2283,7 +2706,7 @@ ecoff_set_arch_mach (abfd, arch, machine)
 
 /*ARGSUSED*/
 int
-ecoff_sizeof_headers (abfd, reloc)
+_bfd_ecoff_sizeof_headers (abfd, reloc)
      bfd *abfd;
      boolean reloc;
 {
@@ -2306,7 +2729,7 @@ ecoff_sizeof_headers (abfd, reloc)
 /* Get the contents of a section.  */
 
 boolean
-ecoff_get_section_contents (abfd, section, location, offset, count)
+_bfd_ecoff_get_section_contents (abfd, section, location, offset, count)
      bfd *abfd;
      asection *section;
      PTR location;
@@ -2329,7 +2752,7 @@ ecoff_compute_section_file_positions (abfd)
   file_ptr old_sofar;
   boolean first_data;
 
-  sofar = ecoff_sizeof_headers (abfd, false);
+  sofar = _bfd_ecoff_sizeof_headers (abfd, false);
 
   first_data = true;
   for (current = abfd->sections;
@@ -2460,7 +2883,7 @@ ecoff_compute_reloc_file_positions (abfd)
 /* Set the contents of a section.  */
 
 boolean
-ecoff_set_section_contents (abfd, section, location, offset, count)
+_bfd_ecoff_set_section_contents (abfd, section, location, offset, count)
      bfd *abfd;
      asection *section;
      PTR location;
@@ -2605,7 +3028,7 @@ ecoff_get_extr (sym, esym)
      symbol.  */
   if ((esym->asym.sc == scUndefined
        || esym->asym.sc == scSUndefined)
-      && bfd_get_section (sym) != &bfd_und_section)
+      && ! bfd_is_und_section (bfd_get_section (sym)))
     esym->asym.sc = scAbs;
 
   /* Adjust the FDR index for the symbol by that used for the input
@@ -2637,7 +3060,7 @@ ecoff_set_index (sym, indx)
 /* Write out an ECOFF file.  */
 
 boolean
-ecoff_write_object_contents (abfd)
+_bfd_ecoff_write_object_contents (abfd)
      bfd *abfd;
 {
   const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
@@ -2688,7 +3111,7 @@ ecoff_write_object_contents (abfd)
     }
 
   if ((abfd->flags & D_PAGED) != 0)
-    text_size = ecoff_sizeof_headers (abfd, false);
+    text_size = _bfd_ecoff_sizeof_headers (abfd, false);
   else
     text_size = 0;
   text_start = 0;
@@ -2911,11 +3334,10 @@ ecoff_write_object_contents (abfd)
     goto error_return;
 
   /* Build the external symbol information.  This must be done before
-     writing out the relocs so that we know the symbol indices.  The
-     condition checks makes sure this object was not created by
-     ecoff_bfd_final_link, since if it was we do not want to tamper
-     with the external symbols.  */
-  if (bfd_get_outsymbols (abfd) != (asymbol **) NULL)
+     writing out the relocs so that we know the symbol indices.  We
+     don't do this if this BFD was created by the backend linker,
+     since it will have already handled the symbols and relocs.  */
+  if (! ecoff_data (abfd)->linker)
     {
       symhdr->iextMax = 0;
       symhdr->issExtMax = 0;
@@ -3141,7 +3563,7 @@ ecoff_armap_hash (s, rehash, size, hlog)
 /* Read in the armap.  */
 
 boolean
-ecoff_slurp_armap (abfd)
+_bfd_ecoff_slurp_armap (abfd)
      bfd *abfd;
 {
   char nextname[17];
@@ -3314,7 +3736,7 @@ ecoff_slurp_armap (abfd)
 /* Write out an armap.  */
 
 boolean
-ecoff_write_armap (abfd, elength, map, orl_count, stridx)
+_bfd_ecoff_write_armap (abfd, elength, map, orl_count, stridx)
      bfd *abfd;
      unsigned int elength;
      struct orl *map;
@@ -3479,8 +3901,8 @@ ecoff_write_armap (abfd, elength, map, orl_count, stridx)
 /* See whether this BFD is an archive.  If it is, read in the armap
    and the extended name table.  */
 
-bfd_target *
-ecoff_archive_p (abfd)
+const bfd_target *
+_bfd_ecoff_archive_p (abfd)
      bfd *abfd;
 {
   char armag[SARMAG + 1];
@@ -3490,7 +3912,7 @@ ecoff_archive_p (abfd)
     {
       if (bfd_get_error () != bfd_error_system_call)
        bfd_set_error (bfd_error_wrong_format);
-      return (bfd_target *) NULL;
+      return (const bfd_target *) NULL;
     }
 
   /* We are setting bfd_ardata(abfd) here, but since bfd_ardata
@@ -3502,7 +3924,7 @@ ecoff_archive_p (abfd)
   if (bfd_ardata (abfd) == (struct artdata *) NULL)
     {
       bfd_set_error (bfd_error_no_memory);
-      return (bfd_target *) NULL;
+      return (const bfd_target *) NULL;
     }
 
   bfd_ardata (abfd)->first_file_filepos = SARMAG;
@@ -3512,12 +3934,12 @@ ecoff_archive_p (abfd)
   bfd_ardata (abfd)->extended_names = NULL;
   bfd_ardata (abfd)->tdata = NULL;
   
-  if (ecoff_slurp_armap (abfd) == false
-      || ecoff_slurp_extended_name_table (abfd) == false)
+  if (_bfd_ecoff_slurp_armap (abfd) == false
+      || _bfd_ecoff_slurp_extended_name_table (abfd) == false)
     {
       bfd_release (abfd, bfd_ardata (abfd));
       abfd->tdata.aout_ar_data = (struct artdata *) NULL;
-      return (bfd_target *) NULL;
+      return (const bfd_target *) NULL;
     }
   
   return abfd->xvec;
@@ -3569,6 +3991,8 @@ ecoff_link_hash_newfunc (entry, table, string)
       /* Set local fields.  */
       ret->indx = -1;
       ret->abfd = NULL;
+      ret->written = 0;
+      ret->small = 0;
     }
   memset ((PTR) &ret->esym, 0, sizeof ret->esym);
 
@@ -3578,7 +4002,7 @@ ecoff_link_hash_newfunc (entry, table, string)
 /* Create an ECOFF link hash table.  */
 
 struct bfd_link_hash_table *
-ecoff_bfd_link_hash_table_create (abfd)
+_bfd_ecoff_bfd_link_hash_table_create (abfd)
      bfd *abfd;
 {
   struct ecoff_link_hash_table *ret;
@@ -3622,7 +4046,7 @@ ecoff_bfd_link_hash_table_create (abfd)
    appropriate.  */
 
 boolean
-ecoff_bfd_link_add_symbols (abfd, info)
+_bfd_ecoff_bfd_link_add_symbols (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
@@ -3660,6 +4084,9 @@ ecoff_link_add_archive_symbols (abfd, info)
 
   if (! bfd_has_map (abfd))
     {
+      /* An empty archive is a special case.  */
+      if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL)
+       return true;
       bfd_set_error (bfd_error_no_symbols);
       return false;
     }
@@ -4086,10 +4513,10 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
          value -= section->vma;
          break;
        case scAbs:
-         section = &bfd_abs_section;
+         section = bfd_abs_section_ptr;
          break;
        case scUndefined:
-         section = &bfd_und_section;
+         section = bfd_und_section_ptr;
          break;
        case scSData:
          section = bfd_make_section_old_way (abfd, ".sdata");
@@ -4106,7 +4533,7 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
        case scCommon:
          if (value > ecoff_data (abfd)->gp_size)
            {
-             section = &bfd_com_section;
+             section = bfd_com_section_ptr;
              break;
            }
          /* Fall through.  */
@@ -4127,7 +4554,7 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
          section = &ecoff_scom_section;
          break;
        case scSUndefined:
-         section = &bfd_und_section;
+         section = bfd_und_section_ptr;
          break;
        case scInit:
          section = bfd_make_section_old_way (abfd, ".init");
@@ -4158,13 +4585,33 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
       if (info->hash->creator->flavour == bfd_get_flavour (abfd))
        {
          if (h->abfd == (bfd *) NULL
-             || (section != &bfd_und_section
+             || (! bfd_is_und_section (section)
                  && (! bfd_is_com_section (section)
-                     || h->root.type != bfd_link_hash_defined)))
+                     || (h->root.type != bfd_link_hash_defined
+                         && h->root.type != bfd_link_hash_defweak))))
            {
              h->abfd = abfd;
              h->esym = esym;
            }
+
+         /* Remember whether this symbol was small undefined.  */
+         if (esym.asym.sc == scSUndefined)
+           h->small = 1;
+
+         /* If this symbol was ever small undefined, it needs to wind
+            up in a GP relative section.  We can't control the
+            section of a defined symbol, but we can control the
+            section of a common symbol.  This case is actually needed
+            on Ultrix 4.2 to handle the symbol cred in -lckrb.  */
+         if (h->small
+             && h->root.type == bfd_link_hash_common
+             && strcmp (h->root.u.c.section->name, SCOMMON) != 0)
+           {
+             h->root.u.c.section = bfd_make_section_old_way (abfd, SCOMMON);
+             h->root.u.c.section->flags = SEC_ALLOC;
+             if (h->esym.asym.sc == scCommon)
+               h->esym.asym.sc = scSCommon;
+           }
        }
     }
 
@@ -4191,7 +4638,7 @@ static boolean ecoff_reloc_link_order
    close and reopen some input BFDs; I'll see how bad this is.  */
 
 boolean
-ecoff_bfd_final_link (abfd, info)
+_bfd_ecoff_bfd_final_link (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
@@ -4381,6 +4828,8 @@ ecoff_bfd_final_link (abfd, info)
 
   bfd_get_symcount (abfd) = symhdr->iextMax + symhdr->isymMax;
 
+  ecoff_data (abfd)->linker = true;
+
   return true;
 }
 
@@ -4424,7 +4873,7 @@ ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle)
     }
 
   /* If raw_syments is not NULL, then the data was already by read by
-     ecoff_slurp_symbolic_info.  */
+     _bfd_ecoff_slurp_symbolic_info.  */
   if (ecoff_data (input_bfd)->raw_syments == NULL)
     {
       READ (line, cbLineOffset, cbLine, sizeof (unsigned char),
@@ -4498,7 +4947,7 @@ ecoff_link_write_external (h, data)
 
   /* FIXME: We should check if this symbol is being stripped.  */
 
-  if (h->root.written)
+  if (h->written)
     return true;
 
   if (h->abfd == (bfd *) NULL)
@@ -4511,7 +4960,8 @@ ecoff_link_write_external (h, data)
       h->esym.asym.value = 0;
       h->esym.asym.st = stGlobal;
 
-      if (h->root.type != bfd_link_hash_defined)
+      if (h->root.type != bfd_link_hash_defined
+         && h->root.type != bfd_link_hash_defweak)
        h->esym.asym.sc = scAbs;
       else
        {
@@ -4566,12 +5016,13 @@ ecoff_link_write_external (h, data)
     case bfd_link_hash_new:
       abort ();
     case bfd_link_hash_undefined:
-    case bfd_link_hash_weak:
+    case bfd_link_hash_undefweak:
       if (h->esym.asym.sc != scUndefined
          && h->esym.asym.sc != scSUndefined)
        h->esym.asym.sc = scUndefined;
       break;
     case bfd_link_hash_defined:
+    case bfd_link_hash_defweak:
       if (h->esym.asym.sc == scUndefined
          || h->esym.asym.sc == scSUndefined)
        h->esym.asym.sc = scAbs;
@@ -4599,7 +5050,7 @@ ecoff_link_write_external (h, data)
   /* bfd_ecoff_debug_one_external uses iextMax to keep track of the
      symbol number.  */
   h->indx = ecoff_data (output_bfd)->debug_info.symbolic_header.iextMax;
-  h->root.written = true;
+  h->written = 1;
 
   return (bfd_ecoff_debug_one_external
          (output_bfd, &ecoff_data (output_bfd)->debug_info,
@@ -4758,7 +5209,7 @@ ecoff_reloc_link_order (output_bfd, info, output_section, link_order)
   rel.address = link_order->offset;
 
   rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
-  if (rel.howto == (const reloc_howto_type *) NULL)
+  if (rel.howto == 0)
     {
       bfd_set_error (bfd_error_bad_value);
       return false;
This page took 0.041293 seconds and 4 git commands to generate.