* ChangeLog: Fix typos.
[deliverable/binutils-gdb.git] / bfd / ecofflink.c
index 7fd34cb6ff6031bf1457b4a408a29ebda3843f30..9e23848fda7da98b476b67b1321d0ce8a03a216b 100644 (file)
 /* Routines to link ECOFF debugging information.
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003
+   Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
 #include "bfdlink.h"
 #include "libbfd.h"
-#include "obstack.h"
+#include "objalloc.h"
+#include "aout/stab_gnu.h"
 #include "coff/internal.h"
 #include "coff/sym.h"
 #include "coff/symconst.h"
 #include "coff/ecoff.h"
+#include "libcoff.h"
+#include "libecoff.h"
 \f
-static boolean ecoff_add_bytes PARAMS ((char **buf, char **bufend,
-                                       size_t need));
+static bfd_boolean ecoff_add_bytes
+  PARAMS ((char **buf, char **bufend, size_t need));
 static struct bfd_hash_entry *string_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
           const char *));
-static void ecoff_align_debug PARAMS ((bfd *abfd,
-                                      struct ecoff_debug_info *debug,
-                                      const struct ecoff_debug_swap *swap));
-static boolean ecoff_write_symhdr PARAMS ((bfd *, struct ecoff_debug_info *,
-                                          const struct ecoff_debug_swap *,
-                                          file_ptr where));
-
-/* Obstack allocation and deallocation routines.  */
-#define obstack_chunk_alloc malloc
-#define obstack_chunk_free free
+static void ecoff_align_debug
+  PARAMS ((bfd *abfd, struct ecoff_debug_info *debug,
+          const struct ecoff_debug_swap *swap));
+static bfd_boolean ecoff_write_symhdr
+  PARAMS ((bfd *, struct ecoff_debug_info *, const struct ecoff_debug_swap *,
+          file_ptr where));
+static int cmp_fdrtab_entry
+  PARAMS ((const PTR, const PTR));
+static bfd_boolean mk_fdrtab
+  PARAMS ((bfd *, struct ecoff_debug_info * const,
+          const struct ecoff_debug_swap * const, struct ecoff_find_line *));
+static long fdrtab_lookup
+  PARAMS ((struct ecoff_find_line *, bfd_vma));
+static bfd_boolean lookup_line
+  PARAMS ((bfd *, struct ecoff_debug_info * const,
+          const struct ecoff_debug_swap * const, struct ecoff_find_line *));
+\f
+/* Routines to swap auxiliary information in and out.  I am assuming
+   that the auxiliary information format is always going to be target
+   independent.  */
+
+/* Swap in a type information record.
+   BIGEND says whether AUX symbols are big-endian or little-endian; this
+   info comes from the file header record (fh-fBigendian).  */
+
+void
+_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
+     int bigend;
+     const struct tir_ext *ext_copy;
+     TIR *intern;
+{
+  struct tir_ext ext[1];
+
+  *ext = *ext_copy;            /* Make it reasonable to do in-place.  */
+
+  /* now the fun stuff...  */
+  if (bigend) {
+    intern->fBitfield   = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG);
+    intern->continued   = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG);
+    intern->bt          = (ext->t_bits1[0] & TIR_BITS1_BT_BIG)
+                       >>                  TIR_BITS1_BT_SH_BIG;
+    intern->tq4         = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG)
+                       >>                  TIR_BITS_TQ4_SH_BIG;
+    intern->tq5         = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG)
+                       >>                  TIR_BITS_TQ5_SH_BIG;
+    intern->tq0         = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG)
+                       >>                  TIR_BITS_TQ0_SH_BIG;
+    intern->tq1         = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG)
+                       >>                  TIR_BITS_TQ1_SH_BIG;
+    intern->tq2         = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG)
+                       >>                  TIR_BITS_TQ2_SH_BIG;
+    intern->tq3         = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG)
+                       >>                  TIR_BITS_TQ3_SH_BIG;
+  } else {
+    intern->fBitfield   = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE);
+    intern->continued   = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE);
+    intern->bt          = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE)
+                       >>                  TIR_BITS1_BT_SH_LITTLE;
+    intern->tq4         = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE)
+                       >>                  TIR_BITS_TQ4_SH_LITTLE;
+    intern->tq5         = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE)
+                       >>                  TIR_BITS_TQ5_SH_LITTLE;
+    intern->tq0         = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE)
+                       >>                  TIR_BITS_TQ0_SH_LITTLE;
+    intern->tq1         = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE)
+                       >>                  TIR_BITS_TQ1_SH_LITTLE;
+    intern->tq2         = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE)
+                       >>                  TIR_BITS_TQ2_SH_LITTLE;
+    intern->tq3         = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE)
+                       >>                  TIR_BITS_TQ3_SH_LITTLE;
+  }
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort ();
+#endif
+}
+
+/* Swap out a type information record.
+   BIGEND says whether AUX symbols are big-endian or little-endian; this
+   info comes from the file header record (fh-fBigendian).  */
+
+void
+_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
+     int bigend;
+     const TIR *intern_copy;
+     struct tir_ext *ext;
+{
+  TIR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+
+  /* now the fun stuff...  */
+  if (bigend) {
+    ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0)
+                      | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0)
+                      | ((intern->bt << TIR_BITS1_BT_SH_BIG)
+                         & TIR_BITS1_BT_BIG));
+    ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG)
+                      & TIR_BITS_TQ4_BIG)
+                     | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG)
+                        & TIR_BITS_TQ5_BIG));
+    ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG)
+                      & TIR_BITS_TQ0_BIG)
+                     | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG)
+                        & TIR_BITS_TQ1_BIG));
+    ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG)
+                      & TIR_BITS_TQ2_BIG)
+                     | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG)
+                        & TIR_BITS_TQ3_BIG));
+  } else {
+    ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0)
+                      | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0)
+                      | ((intern->bt << TIR_BITS1_BT_SH_LITTLE)
+                         & TIR_BITS1_BT_LITTLE));
+    ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE)
+                      & TIR_BITS_TQ4_LITTLE)
+                     | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE)
+                        & TIR_BITS_TQ5_LITTLE));
+    ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE)
+                      & TIR_BITS_TQ0_LITTLE)
+                     | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE)
+                        & TIR_BITS_TQ1_LITTLE));
+    ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE)
+                      & TIR_BITS_TQ2_LITTLE)
+                     | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE)
+                        & TIR_BITS_TQ3_LITTLE));
+  }
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort ();
+#endif
+}
+
+/* Swap in a relative symbol record.  BIGEND says whether it is in
+   big-endian or little-endian format.*/
+
+void
+_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
+     int bigend;
+     const struct rndx_ext *ext_copy;
+     RNDXR *intern;
+{
+  struct rndx_ext ext[1];
+
+  *ext = *ext_copy;            /* Make it reasonable to do in-place.  */
+
+  /* now the fun stuff...  */
+  if (bigend) {
+    intern->rfd   = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG)
+                 | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG)
+                                   >> RNDX_BITS1_RFD_SH_BIG);
+    intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG)
+                                   << RNDX_BITS1_INDEX_SH_LEFT_BIG)
+                 | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG)
+                 | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG);
+  } else {
+    intern->rfd   = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE)
+                 | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE)
+                                   << RNDX_BITS1_RFD_SH_LEFT_LITTLE);
+    intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE)
+                                   >> RNDX_BITS1_INDEX_SH_LITTLE)
+                 | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE)
+                 | ((unsigned int) ext->r_bits[3]
+                    << RNDX_BITS3_INDEX_SH_LEFT_LITTLE);
+  }
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort ();
+#endif
+}
+
+/* Swap out a relative symbol record.  BIGEND says whether it is in
+   big-endian or little-endian format.*/
+
+void
+_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
+     int bigend;
+     const RNDXR *intern_copy;
+     struct rndx_ext *ext;
+{
+  RNDXR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+
+  /* now the fun stuff...  */
+  if (bigend) {
+    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG;
+    ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG)
+                      & RNDX_BITS1_RFD_BIG)
+                     | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG)
+                        & RNDX_BITS1_INDEX_BIG));
+    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG;
+    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG;
+  } else {
+    ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE;
+    ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE)
+                      & RNDX_BITS1_RFD_LITTLE)
+                     | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE)
+                        & RNDX_BITS1_INDEX_LITTLE));
+    ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE;
+    ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE;
+  }
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort ();
+#endif
+}
 \f
 /* The minimum amount of data to allocate.  */
 #define ALLOC_SIZE (4064)
 
 /* Add bytes to a buffer.  Return success.  */
 
-static boolean
+static bfd_boolean
 ecoff_add_bytes (buf, bufend, need)
      char **buf;
      char **bufend;
@@ -68,18 +273,12 @@ ecoff_add_bytes (buf, bufend, need)
       if (want < ALLOC_SIZE)
        want = ALLOC_SIZE;
     }
-  if (*buf == NULL)
-    newbuf = (char *) malloc (have + want);
-  else
-    newbuf = (char *) realloc (*buf, have + want);
+  newbuf = (char *) bfd_realloc (*buf, (bfd_size_type) have + want);
   if (newbuf == NULL)
-    {
-      bfd_error = no_memory;
-      return false;
-    }
+    return FALSE;
   *buf = newbuf;
   *bufend = *buf + have + want;
-  return true;
+  return TRUE;
 }
 
 /* We keep a hash table which maps strings to numbers.  We use it to
@@ -116,10 +315,7 @@ string_hash_newfunc (entry, table, string)
     ret = ((struct string_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
   if (ret == (struct string_hash_entry *) NULL)
-    {
-      bfd_error = no_memory;
-      return NULL;
-    }
+    return NULL;
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct string_hash_entry *)
@@ -152,7 +348,7 @@ struct shuffle
   /* The length of the information.  */
   unsigned long size;
   /* Whether this information comes from a file or not.  */
-  boolean filep;
+  bfd_boolean filep;
   union
     {
       struct
@@ -199,18 +395,17 @@ struct accumulate
   struct shuffle *rfd_end;
   /* The size of the largest file shuffle.  */
   unsigned long largest_file_shuffle;
-  /* An obstack for debugging information.  */
-  struct obstack memory;
+  /* An objalloc for debugging information.  */
+  struct objalloc *memory;
 };
 
 /* Add a file entry to a shuffle list.  */
 
-static boolean add_file_shuffle PARAMS ((struct accumulate *,
-                                     struct shuffle **,
-                                     struct shuffle **, bfd *, file_ptr,
-                                     unsigned long));
+static bfd_boolean add_file_shuffle
+  PARAMS ((struct accumulate *, struct shuffle **, struct shuffle **,
+          bfd *, file_ptr, unsigned long));
 
-static boolean
+static bfd_boolean
 add_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
      struct accumulate *ainfo;
      struct shuffle **head;
@@ -224,25 +419,25 @@ add_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
   if (*tail != (struct shuffle *) NULL
       && (*tail)->filep
       && (*tail)->u.file.input_bfd == input_bfd
-      && (*tail)->u.file.offset + (*tail)->size == offset)
+      && (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset)
     {
       /* Just merge this entry onto the existing one.  */
       (*tail)->size += size;
       if ((*tail)->size > ainfo->largest_file_shuffle)
        ainfo->largest_file_shuffle = (*tail)->size;
-      return true;
+      return TRUE;
     }
 
-  n = (struct shuffle *) obstack_alloc (&ainfo->memory,
-                                       sizeof (struct shuffle));
+  n = (struct shuffle *) objalloc_alloc (ainfo->memory,
+                                        sizeof (struct shuffle));
   if (!n)
     {
-      bfd_error = no_memory;
-      return false;
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
     }
   n->next = NULL;
   n->size = size;
-  n->filep = true;
+  n->filep = TRUE;
   n->u.file.input_bfd = input_bfd;
   n->u.file.offset = offset;
   if (*head == (struct shuffle *) NULL)
@@ -252,17 +447,16 @@ add_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
   *tail = n;
   if (size > ainfo->largest_file_shuffle)
     ainfo->largest_file_shuffle = size;
-  return true;
+  return TRUE;
 }
 
 /* Add a memory entry to a shuffle list.  */
 
-static boolean add_memory_shuffle PARAMS ((struct accumulate *,
-                                          struct shuffle **head,
-                                          struct shuffle **tail,
-                                          bfd_byte *data, unsigned long size));
+static bfd_boolean add_memory_shuffle
+  PARAMS ((struct accumulate *, struct shuffle **head, struct shuffle **tail,
+          bfd_byte *data, unsigned long size));
 
-static boolean
+static bfd_boolean
 add_memory_shuffle (ainfo, head, tail, data, size)
      struct accumulate *ainfo;
      struct shuffle **head;
@@ -271,45 +465,42 @@ add_memory_shuffle (ainfo, head, tail, data, size)
      unsigned long size;
 {
   struct shuffle *n;
-     
-  n = (struct shuffle *) obstack_alloc (&ainfo->memory,
-                                       sizeof (struct shuffle));
+
+  n = (struct shuffle *) objalloc_alloc (ainfo->memory,
+                                        sizeof (struct shuffle));
   if (!n)
     {
-      bfd_error = no_memory;
-      return false;
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
     }
   n->next = NULL;
   n->size = size;
-  n->filep = false;
+  n->filep = FALSE;
   n->u.memory = (PTR) data;
   if (*head == (struct shuffle *) NULL)
     *head = n;
   if (*tail != (struct shuffle *) NULL)
     (*tail)->next = n;
   *tail = n;
-  return true;
+  return TRUE;
 }
 
 /* Initialize the FDR hash table.  This returns a handle which is then
    passed in to bfd_ecoff_debug_accumulate, et. al.  */
 
-/*ARGSUSED*/
 PTR
 bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct ecoff_debug_info *output_debug;
-     const struct ecoff_debug_swap *output_swap;
+     const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   struct accumulate *ainfo;
+  bfd_size_type amt = sizeof (struct accumulate);
 
-  ainfo = (struct accumulate *) malloc (sizeof (struct accumulate));
+  ainfo = (struct accumulate *) bfd_malloc (amt);
   if (!ainfo)
-    {
-      bfd_error = no_memory;
-      return NULL;
-    }
+    return NULL;
   if (! bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc,
                               1021))
     return NULL;
@@ -335,7 +526,7 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
 
   ainfo->largest_file_shuffle = 0;
 
-  if (! info->relocateable)
+  if (! info->relocatable)
     {
       if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc))
        return NULL;
@@ -344,9 +535,10 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
       output_debug->symbolic_header.issMax = 1;
     }
 
-  if (!obstack_begin (&ainfo->memory, 4050))
+  ainfo->memory = objalloc_create ();
+  if (ainfo->memory == NULL)
     {
-      bfd_error = no_memory;
+      bfd_set_error (bfd_error_no_memory);
       return NULL;
     }
 
@@ -355,23 +547,22 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
 
 /* Free the accumulated debugging information.  */
 
-/*ARGSUSED*/
 void
 bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
      PTR handle;
-     bfd *output_bfd;
-     struct ecoff_debug_info *output_debug;
-     const struct ecoff_debug_swap *output_swap;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct ecoff_debug_info *output_debug ATTRIBUTE_UNUSED;
+     const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   struct accumulate *ainfo = (struct accumulate *) handle;
-  
+
   bfd_hash_table_free (&ainfo->fdr_hash.table);
 
-  if (! info->relocateable)
+  if (! info->relocatable)
     bfd_hash_table_free (&ainfo->str_hash.table);
 
-  obstack_free (&ainfo->memory, (PTR) NULL);
+  objalloc_free (ainfo->memory);
 
   free (ainfo);
 }
@@ -384,8 +575,7 @@ bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
    linker information structure.  HANDLE is returned by
    bfd_ecoff_debug_init.  */
 
-/*ARGSUSED*/
-boolean
+bfd_boolean
 bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
                            input_bfd, input_debug, input_swap,
                            info)
@@ -431,6 +621,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
   long newrfdbase = 0;
   long oldrfdbase = 0;
   bfd_byte *fdr_out;
+  bfd_size_type amt;
 
   /* Use section_adjust to hold the value to add to a symbol in a
      particular section.  */
@@ -453,6 +644,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
   SET (".rodata", scRData);
   SET (".init", scInit);
   SET (".fini", scFini);
+  SET (".rconst", scRConst);
 
 #undef SET
 
@@ -470,19 +662,19 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
     }
   fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add;
 
-  input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd,
-                                           (input_symhdr->ifdMax
-                                            * sizeof (RFDT)));
+  amt = input_symhdr->ifdMax;
+  amt *= sizeof (RFDT);
+  input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, amt);
 
   sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size;
-  rfd_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+  rfd_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
   if (!input_debug->ifdmap || !rfd_out)
     {
-      bfd_error = no_memory;
-      return false;
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
     }
   if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz))
-    return false;
+    return FALSE;
 
   copied = 0;
 
@@ -513,18 +705,23 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
          struct string_hash_entry *fh;
 
          /* We look up a string formed from the file name and the
-            number of symbols.  Sometimes an include file will
-            conditionally define a typedef or something based on the
-            order of include files.  Using the number of symbols as a
-            hash reduces the chance that we will merge symbol
-            information that should not be merged.  */
+            number of symbols and aux entries.  Sometimes an include
+            file will conditionally define a typedef or something
+            based on the order of include files.  Using the number of
+            symbols and aux entries as a hash reduces the chance that
+            we will merge symbol information that should not be
+            merged.  */
          name = input_debug->ss + fdr.issBase + fdr.rss;
-         lookup = (char *) alloca (strlen (name) + 20);
-         sprintf (lookup, "%s %lx", name, fdr.csym);
 
-         fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true);
+         lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20);
+         if (lookup == NULL)
+           return FALSE;
+         sprintf (lookup, "%s %lx %lx", name, fdr.csym, fdr.caux);
+
+         fh = string_hash_lookup (&ainfo->fdr_hash, lookup, TRUE, TRUE);
+         free (lookup);
          if (fh == (struct string_hash_entry *) NULL)
-           return false;
+           return FALSE;
 
          if (fh->val != -1)
            {
@@ -571,23 +768,24 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
   /* Look through the FDR's and copy over all associated debugging
      information.  */
   sz = copied * external_fdr_size;
-  fdr_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+  fdr_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
   if (!fdr_out)
     {
-      bfd_error = no_memory;
-      return false;
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
     }
   if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz))
-    return false;
+    return FALSE;
   for (fdr_ptr = fdr_start, i = 0;
        fdr_ptr < fdr_end;
        fdr_ptr += fdr_add, i++)
     {
       FDR fdr;
+      bfd_vma fdr_adr;
       bfd_byte *sym_out;
       bfd_byte *lraw_src;
       bfd_byte *lraw_end;
-      boolean fgotfilename;
+      bfd_boolean fgotfilename;
 
       if (input_debug->ifdmap[i] < output_symhdr->ifdMax)
        {
@@ -600,6 +798,22 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
       else
        (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
 
+      fdr_adr = fdr.adr;
+
+      /* Adjust the FDR address for any changes that may have been
+        made by relaxing.  */
+      if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
+       {
+         struct ecoff_value_adjust *adjust;
+
+         for (adjust = input_debug->adjust;
+              adjust != (struct ecoff_value_adjust *) NULL;
+              adjust = adjust->next)
+           if (fdr_adr >= adjust->start
+               && fdr_adr < adjust->end)
+             fdr.adr += adjust->adjust;
+       }
+
       /* FIXME: It is conceivable that this FDR points to the .init or
         .fini section, in which case this will not do the right
         thing.  */
@@ -607,16 +821,17 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
 
       /* Swap in the local symbols, adjust their values, and swap them
         out again.  */
-      fgotfilename = false;
+      fgotfilename = FALSE;
       sz = fdr.csym * external_sym_size;
-      sym_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+      sym_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
       if (!sym_out)
        {
-         bfd_error = no_memory;
-         return false;
+         bfd_set_error (bfd_error_no_memory);
+         return FALSE;
        }
-      if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out, sz))
-       return false;
+      if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out,
+                              sz))
+       return FALSE;
       lraw_src = ((bfd_byte *) input_debug->external_sym
                  + fdr.isymBase * input_swap->external_sym_size);
       lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size;
@@ -641,6 +856,19 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
            case stLabel:
            case stProc:
            case stStaticProc:
+             if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
+               {
+                 bfd_vma value;
+                 struct ecoff_value_adjust *adjust;
+
+                 value = internal_sym.value;
+                 for (adjust = input_debug->adjust;
+                      adjust != (struct ecoff_value_adjust *) NULL;
+                      adjust = adjust->next)
+                   if (value >= adjust->start
+                       && value < adjust->end)
+                     internal_sym.value += adjust->adjust;
+               }
              internal_sym.value += section_adjust[internal_sym.sc];
              break;
 
@@ -651,17 +879,17 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
          /* If we are doing a final link, we hash all the strings in
             the local symbol table together.  This reduces the amount
             of space required by debugging information.  We don't do
-            this when performing a relocateable link because it would
+            this when performing a relocatable link because it would
             prevent us from easily merging different FDR's.  */
-         if (! info->relocateable)
+         if (! info->relocatable)
            {
-             boolean ffilename;
+             bfd_boolean ffilename;
              const char *name;
 
              if (! fgotfilename && internal_sym.iss == fdr.rss)
-               ffilename = true;
+               ffilename = TRUE;
              else
-               ffilename = false;
+               ffilename = FALSE;
 
              /* Hash the name into the string table.  */
              name = input_debug->ss + fdr.issBase + internal_sym.iss;
@@ -671,9 +899,9 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
                {
                  struct string_hash_entry *sh;
 
-                 sh = string_hash_lookup (&ainfo->str_hash, name, true, true);
+                 sh = string_hash_lookup (&ainfo->str_hash, name, TRUE, TRUE);
                  if (sh == (struct string_hash_entry *) NULL)
-                   return false;
+                   return FALSE;
                  if (sh->val == -1)
                    {
                      sh->val = output_symhdr->issMax;
@@ -691,7 +919,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
              if (ffilename)
                {
                  fdr.rss = internal_sym.iss;
-                 fgotfilename = true;
+                 fgotfilename = TRUE;
                }
            }
 
@@ -703,13 +931,17 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
       output_symhdr->isymMax += fdr.csym;
 
       /* Copy the information that does not need swapping.  */
+
+      /* FIXME: If we are relaxing, we need to adjust the line
+        numbers.  Frankly, forget it.  Anybody using stabs debugging
+        information will not use this line number information, and
+        stabs are adjusted correctly.  */
       if (fdr.cbLine > 0)
        {
+         file_ptr pos = input_symhdr->cbLineOffset + fdr.cbLineOffset;
          if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end,
-                           input_bfd,
-                           input_symhdr->cbLineOffset + fdr.cbLineOffset,
-                           fdr.cbLine))
-           return false;
+                                input_bfd, pos, (unsigned long) fdr.cbLine))
+           return FALSE;
          fdr.ilineBase = output_symhdr->ilineMax;
          fdr.cbLineOffset = output_symhdr->cbLine;
          output_symhdr->ilineMax += fdr.cline;
@@ -717,16 +949,16 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
        }
       if (fdr.caux > 0)
        {
+         file_ptr pos = (input_symhdr->cbAuxOffset
+                         + fdr.iauxBase * sizeof (union aux_ext));
          if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end,
-                           input_bfd,
-                           (input_symhdr->cbAuxOffset
-                            + fdr.iauxBase * sizeof (union aux_ext)),
-                           fdr.caux * sizeof (union aux_ext)))
-           return false;
+                                input_bfd, pos,
+                                fdr.caux * sizeof (union aux_ext)))
+           return FALSE;
          fdr.iauxBase = output_symhdr->iauxMax;
          output_symhdr->iauxMax += fdr.caux;
        }
-      if (! info->relocateable)
+      if (! info->relocatable)
        {
 
          /* When are are hashing strings, we lie about the number of
@@ -738,39 +970,40 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
        }
       else if (fdr.cbSs > 0)
        {
+         file_ptr pos = input_symhdr->cbSsOffset + fdr.issBase;
          if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end,
-                           input_bfd,
-                           input_symhdr->cbSsOffset + fdr.issBase,
-                           fdr.cbSs))
-           return false;
+                                input_bfd, pos, (unsigned long) fdr.cbSs))
+           return FALSE;
          fdr.issBase = output_symhdr->issMax;
          output_symhdr->issMax += fdr.cbSs;
        }
 
-      if (output_bfd->xvec->header_byteorder_big_p
-         == input_bfd->xvec->header_byteorder_big_p)
+      if ((output_bfd->xvec->header_byteorder
+          == input_bfd->xvec->header_byteorder)
+         && input_debug->adjust == (struct ecoff_value_adjust *) NULL)
        {
-         /* The two BFD's have the same endianness, so simply copying
-            the information will suffice.  */
+         /* The two BFD's have the same endianness, and we don't have
+            to adjust the PDR addresses, so simply copying the
+            information will suffice.  */
          BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size);
          if (fdr.cpd > 0)
            {
+             file_ptr pos = (input_symhdr->cbPdOffset
+                             + fdr.ipdFirst * external_pdr_size);
+             unsigned long size = fdr.cpd * external_pdr_size;
              if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end,
-                                    input_bfd,
-                                    (input_symhdr->cbPdOffset
-                                     + fdr.ipdFirst * external_pdr_size),
-                                    fdr.cpd * external_pdr_size))
-               return false;
+                                    input_bfd, pos, size))
+               return FALSE;
            }
          BFD_ASSERT (external_opt_size == input_swap->external_opt_size);
          if (fdr.copt > 0)
            {
+             file_ptr pos = (input_symhdr->cbOptOffset
+                             + fdr.ioptBase * external_opt_size);
+             unsigned long size = fdr.copt * external_opt_size;
              if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end,
-                                    input_bfd,
-                                    (input_symhdr->cbOptOffset
-                                     + fdr.ioptBase * external_opt_size),
-                                    fdr.copt * external_opt_size))
-               return false;
+                                    input_bfd, pos, size))
+               return FALSE;
            }
        }
       else
@@ -789,19 +1022,37 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
                + fdr.ipdFirst * insz);
          end = in + fdr.cpd * insz;
          sz = fdr.cpd * outsz;
-         out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+         out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
          if (!out)
            {
-             bfd_error = no_memory;
-             return false;
+             bfd_set_error (bfd_error_no_memory);
+             return FALSE;
            }
-         if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out, sz))
-           return false;
+         if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out,
+                                  sz))
+           return FALSE;
          for (; in < end; in += insz, out += outsz)
            {
              PDR pdr;
 
              (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr);
+
+             /* If we have been relaxing, we may have to adjust the
+                address.  */
+             if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
+               {
+                 bfd_vma adr;
+                 struct ecoff_value_adjust *adjust;
+
+                 adr = fdr_adr + pdr.adr;
+                 for (adjust = input_debug->adjust;
+                      adjust != (struct ecoff_value_adjust *) NULL;
+                      adjust = adjust->next)
+                   if (adr >= adjust->start
+                       && adr < adjust->end)
+                     pdr.adr += adjust->adjust;
+               }
+
              (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out);
            }
 
@@ -812,14 +1063,15 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
                + fdr.ioptBase * insz);
          end = in + fdr.copt * insz;
          sz = fdr.copt * outsz;
-         out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
+         out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
          if (!out)
            {
-             bfd_error = no_memory;
-             return false;
+             bfd_set_error (bfd_error_no_memory);
+             return FALSE;
            }
-         if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out, sz))
-           return false;
+         if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out,
+                                  sz))
+           return FALSE;
          for (; in < end; in += insz, out += outsz)
            {
              OPTR opt;
@@ -851,16 +1103,15 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
       ++output_symhdr->ifdMax;
     }
 
-  return true;
+  return TRUE;
 }
 
 /* Add a string to the debugging information we are accumulating.
    Return the offset from the fdr string base.  */
 
-static long ecoff_add_string PARAMS ((struct accumulate *,
-                                     struct bfd_link_info *,
-                                     struct ecoff_debug_info *,
-                                     FDR *fdr, const char *string));
+static long ecoff_add_string
+  PARAMS ((struct accumulate *, struct bfd_link_info *,
+          struct ecoff_debug_info *, FDR *fdr, const char *string));
 
 static long
 ecoff_add_string (ainfo, info, debug, fdr, string)
@@ -876,7 +1127,7 @@ ecoff_add_string (ainfo, info, debug, fdr, string)
 
   symhdr = &debug->symbolic_header;
   len = strlen (string);
-  if (info->relocateable)
+  if (info->relocatable)
     {
       if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string,
                               len + 1))
@@ -889,9 +1140,9 @@ ecoff_add_string (ainfo, info, debug, fdr, string)
     {
       struct string_hash_entry *sh;
 
-      sh = string_hash_lookup (&ainfo->str_hash, string, true, true);
+      sh = string_hash_lookup (&ainfo->str_hash, string, TRUE, TRUE);
       if (sh == (struct string_hash_entry *) NULL)
-       return (bfd_size_type) -1;
+       return -1;
       if (sh->val == -1)
        {
          sh->val = symhdr->issMax;
@@ -911,7 +1162,7 @@ ecoff_add_string (ainfo, info, debug, fdr, string)
 
 /* Add debugging information from a non-ECOFF file.  */
 
-boolean
+bfd_boolean
 bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
                                  output_swap, input_bfd, info)
      PTR handle;
@@ -930,9 +1181,11 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
   asymbol **symbols;
   asymbol **sym_ptr;
   asymbol **sym_end;
+  long symsize;
+  long symcount;
   PTR external_fdr;
 
-  memset (&fdr, 0, sizeof fdr);
+  memset ((PTR) &fdr, 0, sizeof fdr);
 
   sec = bfd_get_section_by_name (input_bfd, ".text");
   if (sec != NULL)
@@ -946,20 +1199,22 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
   fdr.issBase = output_symhdr->issMax;
   fdr.cbSs = 0;
   fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr,
-                             bfd_get_filename (input_bfd));
+                             bfd_archive_filename (input_bfd));
   if (fdr.rss == -1)
-    return false;
+    return FALSE;
   fdr.isymBase = output_symhdr->isymMax;
 
   /* Get the local symbols from the input BFD.  */
-  symbols = (asymbol **) bfd_alloc (output_bfd,
-                                   get_symtab_upper_bound (input_bfd));
+  symsize = bfd_get_symtab_upper_bound (input_bfd);
+  if (symsize < 0)
+    return FALSE;
+  symbols = (asymbol **) bfd_alloc (output_bfd, (bfd_size_type) symsize);
   if (symbols == (asymbol **) NULL)
-    {
-      bfd_error = no_memory;
-      return false;
-    }
-  sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+    return FALSE;
+  symcount = bfd_canonicalize_symtab (input_bfd, symbols);
+  if (symcount < 0)
+    return FALSE;
+  sym_end = symbols + symcount;
 
   /* Handle the local symbols.  Any external symbols are handled
      separately.  */
@@ -971,14 +1226,14 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
 
       if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
        continue;
-      memset (&internal_sym, 0, sizeof internal_sym);
+      memset ((PTR) &internal_sym, 0, sizeof internal_sym);
       internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr,
                                           (*sym_ptr)->name);
 
       if (internal_sym.iss == -1)
-       return false;
+       return FALSE;
       if (bfd_is_com_section ((*sym_ptr)->section)
-         || (*sym_ptr)->section == &bfd_und_section)
+         || bfd_is_und_section ((*sym_ptr)->section))
        internal_sym.value = (*sym_ptr)->value;
       else
        internal_sym.value = ((*sym_ptr)->value
@@ -988,16 +1243,17 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
       internal_sym.sc = scUndefined;
       internal_sym.index = indexNil;
 
-      external_sym = (PTR) obstack_alloc (&ainfo->memory,
-                                         output_swap->external_sym_size);
+      external_sym = (PTR) objalloc_alloc (ainfo->memory,
+                                          output_swap->external_sym_size);
       if (!external_sym)
        {
-         bfd_error = no_memory;
-         return false;
+         bfd_set_error (bfd_error_no_memory);
+         return FALSE;
        }
       (*swap_sym_out) (output_bfd, &internal_sym, external_sym);
       add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end,
-                         external_sym, output_swap->external_sym_size);
+                         external_sym,
+                         (unsigned long) output_swap->external_sym_size);
       ++fdr.csym;
       ++output_symhdr->isymMax;
     }
@@ -1008,20 +1264,21 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
      the lang field to be langC.  The fBigendian field will
      indicate little endian format, but it doesn't matter because
      it only applies to aux fields and there are none.  */
-  external_fdr = (PTR) obstack_alloc (&ainfo->memory,
-                                     output_swap->external_fdr_size);
+  external_fdr = (PTR) objalloc_alloc (ainfo->memory,
+                                      output_swap->external_fdr_size);
   if (!external_fdr)
     {
-      bfd_error = no_memory;
-      return false;
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
     }
   (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr);
   add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end,
-                     external_fdr, output_swap->external_fdr_size);
+                     external_fdr,
+                     (unsigned long) output_swap->external_fdr_size);
 
   ++output_symhdr->ifdMax;
 
-  return true;
+  return TRUE;
 }
 
 /* Set up ECOFF debugging information for the external symbols.
@@ -1029,14 +1286,14 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
    probably be changed to use a shuffle structure.  The assembler uses
    this interface, so that must be changed to do something else.  */
 
-boolean
-bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr,
+bfd_boolean
+bfd_ecoff_debug_externals (abfd, debug, swap, relocatable, get_extr,
                           set_index)
      bfd *abfd;
      struct ecoff_debug_info *debug;
      const struct ecoff_debug_swap *swap;
-     boolean relocateable;
-     boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
+     bfd_boolean relocatable;
+     bfd_boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
      void (*set_index) PARAMS ((asymbol *, bfd_size_type));
 {
   HDRR * const symhdr = &debug->symbolic_header;
@@ -1045,7 +1302,7 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr,
 
   sym_ptr_ptr = bfd_get_outsymbols (abfd);
   if (sym_ptr_ptr == NULL)
-    return true;
+    return TRUE;
 
   for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++)
     {
@@ -1055,12 +1312,12 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr,
       sym_ptr = *sym_ptr_ptr;
 
       /* Get the external symbol information.  */
-      if ((*get_extr) (sym_ptr, &esym) == false)
+      if (! (*get_extr) (sym_ptr, &esym))
        continue;
 
       /* If we're producing an executable, move common symbols into
         bss.  */
-      if (relocateable == false)
+      if (! relocatable)
        {
          if (esym.asym.sc == scCommon)
            esym.asym.sc = scBss;
@@ -1069,7 +1326,8 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr,
        }
 
       if (bfd_is_com_section (sym_ptr->section)
-         || sym_ptr->section == &bfd_und_section)
+         || bfd_is_und_section (sym_ptr->section)
+         || sym_ptr->section->output_section == (asection *) NULL)
        {
          /* FIXME: gas does not keep the value of a small undefined
             symbol in the symbol itself, because of relocation
@@ -1089,15 +1347,15 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr,
 
       if (! bfd_ecoff_debug_one_external (abfd, debug, swap,
                                          sym_ptr->name, &esym))
-       return false;
+       return FALSE;
     }
 
-  return true;
+  return TRUE;
 }
 
 /* Add a single external symbol to the debugging information.  */
 
-boolean
+bfd_boolean
 bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
      bfd *abfd;
      struct ecoff_debug_info *debug;
@@ -1113,23 +1371,22 @@ bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
 
   namelen = strlen (name);
 
-  if (debug->ssext_end - debug->ssext
+  if ((size_t) (debug->ssext_end - debug->ssext)
       < symhdr->issExtMax + namelen + 1)
     {
-      if (ecoff_add_bytes ((char **) &debug->ssext,
-                          (char **) &debug->ssext_end,
-                          symhdr->issExtMax + namelen + 1)
-         == false)
-       return false;
+      if (! ecoff_add_bytes ((char **) &debug->ssext,
+                            (char **) &debug->ssext_end,
+                            symhdr->issExtMax + namelen + 1))
+       return FALSE;
     }
-  if ((char *) debug->external_ext_end - (char *) debug->external_ext
+  if ((size_t) ((char *) debug->external_ext_end
+               - (char *) debug->external_ext)
       < (symhdr->iextMax + 1) * external_ext_size)
     {
-      if (ecoff_add_bytes ((char **) &debug->external_ext,
-                          (char **) &debug->external_ext_end,
-                          (symhdr->iextMax + 1) * external_ext_size)
-         == false)
-       return false;
+      if (! ecoff_add_bytes ((char **) &debug->external_ext,
+                            (char **) &debug->external_ext_end,
+                            (symhdr->iextMax + 1) * (size_t) external_ext_size))
+       return FALSE;
     }
 
   esym->asym.iss = symhdr->issExtMax;
@@ -1143,15 +1400,14 @@ bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
   strcpy (debug->ssext + symhdr->issExtMax, name);
   symhdr->issExtMax += namelen + 1;
 
-  return true;
+  return TRUE;
 }
 
 /* Align the ECOFF debugging information.  */
 
-/*ARGSUSED*/
 static void
 ecoff_align_debug (abfd, debug, swap)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      struct ecoff_debug_info *debug;
      const struct ecoff_debug_swap *swap;
 {
@@ -1168,7 +1424,7 @@ ecoff_align_debug (abfd, debug, swap)
   if (add != debug_align)
     {
       if (debug->line != (unsigned char *) NULL)
-       memset (debug->line + symhdr->cbLine, 0, add);
+       memset ((PTR) (debug->line + symhdr->cbLine), 0, add);
       symhdr->cbLine += add;
     }
 
@@ -1176,7 +1432,7 @@ ecoff_align_debug (abfd, debug, swap)
   if (add != debug_align)
     {
       if (debug->ss != (char *) NULL)
-       memset (debug->ss + symhdr->issMax, 0, add);
+       memset ((PTR) (debug->ss + symhdr->issMax), 0, add);
       symhdr->issMax += add;
     }
 
@@ -1184,7 +1440,7 @@ ecoff_align_debug (abfd, debug, swap)
   if (add != debug_align)
     {
       if (debug->ssext != (char *) NULL)
-       memset (debug->ssext + symhdr->issExtMax, 0, add);
+       memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add);
       symhdr->issExtMax += add;
     }
 
@@ -1192,7 +1448,7 @@ ecoff_align_debug (abfd, debug, swap)
   if (add != aux_align)
     {
       if (debug->external_aux != (union aux_ext *) NULL)
-       memset (debug->external_aux + symhdr->iauxMax, 0,
+       memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0,
                add * sizeof (union aux_ext));
       symhdr->iauxMax += add;
     }
@@ -1201,9 +1457,9 @@ ecoff_align_debug (abfd, debug, swap)
   if (add != rfd_align)
     {
       if (debug->external_rfd != (PTR) NULL)
-       memset (((char *) debug->external_rfd
-                + symhdr->crfd * swap->external_rfd_size),
-               0, add * swap->external_rfd_size);
+       memset ((PTR) ((char *) debug->external_rfd
+                      + symhdr->crfd * swap->external_rfd_size),
+               0, (size_t) (add * swap->external_rfd_size));
       symhdr->crfd += add;
     }
 }
@@ -1245,7 +1501,7 @@ bfd_ecoff_debug_size (abfd, debug, swap)
    going to be placed at.  This assumes that the counts are set
    correctly.  */
 
-static boolean
+static bfd_boolean
 ecoff_write_symhdr (abfd, debug, swap, where)
      bfd *abfd;
      struct ecoff_debug_info *debug;
@@ -1253,16 +1509,18 @@ ecoff_write_symhdr (abfd, debug, swap, where)
      file_ptr where;
 {
   HDRR * const symhdr = &debug->symbolic_header;
-  char *buff;
+  char *buff = NULL;
 
   ecoff_align_debug (abfd, debug, swap);
 
   /* Go to the right location in the file.  */
   if (bfd_seek (abfd, where, SEEK_SET) != 0)
-    return false;
+    return FALSE;
 
   where += swap->external_hdr_size;
 
+  symhdr->magic = swap->sym_magic;
+
   /* Fill in the file offsets.  */
 #define SET(offset, count, size) \
   if (symhdr->count == 0) \
@@ -1286,13 +1544,22 @@ ecoff_write_symhdr (abfd, debug, swap, where)
   SET (cbExtOffset, iextMax, swap->external_ext_size);
 #undef SET
 
-  buff = (PTR) alloca (swap->external_hdr_size);
+  buff = (PTR) bfd_malloc (swap->external_hdr_size);
+  if (buff == NULL && swap->external_hdr_size != 0)
+    goto error_return;
+
   (*swap->swap_hdr_out) (abfd, symhdr, buff);
-  if (bfd_write (buff, 1, swap->external_hdr_size, abfd)
+  if (bfd_bwrite (buff, swap->external_hdr_size, abfd)
       != swap->external_hdr_size)
-    return false;
-
-  return true;
+    goto error_return;
+
+  if (buff != NULL)
+    free (buff);
+  return TRUE;
+ error_return:
+  if (buff != NULL)
+    free (buff);
+  return FALSE;
 }
 
 /* Write out the ECOFF debugging information.  This function assumes
@@ -1301,7 +1568,7 @@ ecoff_write_symhdr (abfd, debug, swap, where)
    information to.  This function fills in the file offsets in the
    symbolic header.  */
 
-boolean
+bfd_boolean
 bfd_ecoff_write_debug (abfd, debug, swap, where)
      bfd *abfd;
      struct ecoff_debug_info *debug;
@@ -1311,20 +1578,22 @@ bfd_ecoff_write_debug (abfd, debug, swap, where)
   HDRR * const symhdr = &debug->symbolic_header;
 
   if (! ecoff_write_symhdr (abfd, debug, swap, where))
-    return false;
+    return FALSE;
 
 #define WRITE(ptr, count, size, offset) \
-  BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \
-  if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \
+  BFD_ASSERT (symhdr->offset == 0 \
+             || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \
+  if (bfd_bwrite ((PTR) debug->ptr, (bfd_size_type) size * symhdr->count, abfd)\
       != size * symhdr->count) \
-    return false;
+    return FALSE;
 
   WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset);
   WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset);
   WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset);
   WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset);
   WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset);
-  WRITE (external_aux, iauxMax, sizeof (union aux_ext), cbAuxOffset);
+  WRITE (external_aux, iauxMax, (bfd_size_type) sizeof (union aux_ext),
+        cbAuxOffset);
   WRITE (ss, issMax, sizeof (char), cbSsOffset);
   WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset);
   WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset);
@@ -1332,16 +1601,16 @@ bfd_ecoff_write_debug (abfd, debug, swap, where)
   WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset);
 #undef WRITE
 
-  return true;
+  return TRUE;
 }
 
 /* Write out a shuffle list.  */
 
-static boolean ecoff_write_shuffle PARAMS ((bfd *,
-                                           const struct ecoff_debug_swap *,
-                                           struct shuffle *, PTR space));
+static bfd_boolean ecoff_write_shuffle
+  PARAMS ((bfd *, const struct ecoff_debug_swap *, struct shuffle *,
+          PTR space));
 
-static boolean
+static bfd_boolean
 ecoff_write_shuffle (abfd, swap, shuffle, space)
      bfd *abfd;
      const struct ecoff_debug_swap *swap;
@@ -1356,38 +1625,46 @@ ecoff_write_shuffle (abfd, swap, shuffle, space)
     {
       if (! l->filep)
        {
-         if (bfd_write (l->u.memory, 1, l->size, abfd) != l->size)
-           return false;
+         if (bfd_bwrite (l->u.memory, (bfd_size_type) l->size, abfd)
+             != l->size)
+           return FALSE;
        }
       else
        {
          if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
-             || bfd_read (space, 1, l->size, l->u.file.input_bfd) != l->size
-             || bfd_write (space, 1, l->size, abfd) != l->size)
-           return false;
+             || bfd_bread (space, (bfd_size_type) l->size,
+                          l->u.file.input_bfd) != l->size
+             || bfd_bwrite (space, (bfd_size_type) l->size, abfd) != l->size)
+           return FALSE;
        }
       total += l->size;
     }
 
   if ((total & (swap->debug_align - 1)) != 0)
     {
-      int i;
+      unsigned int i;
       bfd_byte *s;
 
       i = swap->debug_align - (total & (swap->debug_align - 1));
-      s = (bfd_byte *) alloca (i);
-      memset (s, 0, i);
-      if (bfd_write ((PTR) s, 1, i, abfd) != i)
-       return false;
+      s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
+      if (s == NULL && i != 0)
+       return FALSE;
+
+      if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
+       {
+         free (s);
+         return FALSE;
+       }
+      free (s);
     }
 
-  return true;
+  return TRUE;
 }
 
 /* Write out debugging information using accumulated linker
    information.  */
 
-boolean
+bfd_boolean
 bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
      PTR handle;
      bfd *abfd;
@@ -1397,27 +1674,31 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
      file_ptr where;
 {
   struct accumulate *ainfo = (struct accumulate *) handle;
-  PTR space;
+  PTR space = NULL;
+  bfd_size_type amt;
 
   if (! ecoff_write_symhdr (abfd, debug, swap, where))
-    return false;
+    goto error_return;
 
-  space = (PTR) alloca (ainfo->largest_file_shuffle);
+  amt = ainfo->largest_file_shuffle;
+  space = (PTR) bfd_malloc (amt);
+  if (space == NULL && ainfo->largest_file_shuffle != 0)
+    goto error_return;
 
   if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
       || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
       || ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
       || ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
       || ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
-    return false;
+    goto error_return;
 
   /* The string table is written out from the hash table if this is a
      final link.  */
-  if (info->relocateable)
+  if (info->relocatable)
     {
       BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
       if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
-       return false;
+       goto error_return;
     }
   else
     {
@@ -1427,8 +1708,8 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
 
       BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
       null = 0;
-      if (bfd_write ((PTR) &null, 1, 1, abfd) != 1)
-       return false;
+      if (bfd_bwrite ((PTR) &null, (bfd_size_type) 1, abfd) != 1)
+       goto error_return;
       total = 1;
       BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
       for (sh = ainfo->ss_hash;
@@ -1438,53 +1719,893 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
          size_t len;
 
          len = strlen (sh->root.string);
-         if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1)
-           return false;
+         amt = len + 1;
+         if (bfd_bwrite ((PTR) sh->root.string, amt, abfd) != amt)
+           goto error_return;
          total += len + 1;
        }
 
       if ((total & (swap->debug_align - 1)) != 0)
        {
-         int i;
+         unsigned int i;
          bfd_byte *s;
 
          i = swap->debug_align - (total & (swap->debug_align - 1));
-         s = (bfd_byte *) alloca (i);
-         memset (s, 0, i);
-         if (bfd_write ((PTR) s, 1, i, abfd) != i)
-           return false;
+         s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
+         if (s == NULL && i != 0)
+           goto error_return;
+
+         if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
+           {
+             free (s);
+             goto error_return;
+           }
+         free (s);
        }
     }
 
   /* The external strings and symbol are not converted over to using
      shuffles.  FIXME: They probably should be.  */
-  if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd)
-      != debug->symbolic_header.issExtMax)
-    return false;
+  amt = debug->symbolic_header.issExtMax;
+  if (bfd_bwrite (debug->ssext, amt, abfd) != amt)
+    goto error_return;
   if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0)
     {
-      int i;
+      unsigned int i;
       bfd_byte *s;
 
       i = (swap->debug_align
           - (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
-      s = (bfd_byte *) alloca (i);
-      memset (s, 0, i);
-      if (bfd_write ((PTR) s, 1, i, abfd) != i)
-       return false;
+      s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
+      if (s == NULL && i != 0)
+       goto error_return;
+
+      if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
+       {
+         free (s);
+         goto error_return;
+       }
+      free (s);
     }
 
   if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
       || ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
-    return false;
+    goto error_return;
 
   BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
-             || debug->symbolic_header.cbExtOffset == bfd_tell (abfd));
+             || (debug->symbolic_header.cbExtOffset
+                 == (bfd_vma) bfd_tell (abfd)));
+
+  amt = debug->symbolic_header.iextMax * swap->external_ext_size;
+  if (bfd_bwrite (debug->external_ext, amt, abfd) != amt)
+    goto error_return;
+
+  if (space != NULL)
+    free (space);
+  return TRUE;
+
+ error_return:
+  if (space != NULL)
+    free (space);
+  return FALSE;
+}
+\f
+/* Handle the find_nearest_line function for both ECOFF and MIPS ELF
+   files.  */
+
+/* Compare FDR entries.  This is called via qsort.  */
+
+static int
+cmp_fdrtab_entry (leftp, rightp)
+     const PTR leftp;
+     const PTR rightp;
+{
+  const struct ecoff_fdrtab_entry *lp =
+    (const struct ecoff_fdrtab_entry *) leftp;
+  const struct ecoff_fdrtab_entry *rp =
+    (const struct ecoff_fdrtab_entry *) 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 bfd_boolean
+mk_fdrtab (abfd, debug_info, debug_swap, line_info)
+     bfd *abfd;
+     struct ecoff_debug_info * const debug_info;
+     const struct ecoff_debug_swap * const debug_swap;
+     struct ecoff_find_line *line_info;
+{
+  struct ecoff_fdrtab_entry *tab;
+  FDR *fdr_ptr;
+  FDR *fdr_start;
+  FDR *fdr_end;
+  bfd_boolean stabs;
+  long len;
+  bfd_size_type amt;
+
+  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.  */
+  amt = (bfd_size_type) len * sizeof (struct ecoff_fdrtab_entry);
+  line_info->fdrtab = (struct ecoff_fdrtab_entry*) bfd_zalloc (abfd, amt);
+  if (line_info->fdrtab == NULL)
+    return FALSE;
+  line_info->fdrtab_len = len;
+
+  tab = line_info->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)
+       {
+         /* eraxxon: There are at least two problems with this computation:
+            1) PDRs do *not* contain offsets but full vma's; and typically the
+            address of the first PDR is the address of the FDR, which will
+            make (most) of the results of the original computation 0!
+            2) Once in a wacky while, the Compaq compiler generated PDR
+            addresses do not equal the FDR vma, but they (the PDR address)
+            are still vma's and not offsets.  Cf. comments in
+            'lookup_line'.  */
+#if 0
+           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
+         /* 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; 
+#endif
+       }
+      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 ((PTR) line_info->fdrtab, (size_t) len,
+        sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry);
+
+  return TRUE;
+}
+
+/* Return index of first FDR that covers to OFFSET.  */
+
+static long
+fdrtab_lookup (line_info, offset)
+     struct ecoff_find_line *line_info;
+     bfd_vma offset;
+{
+  long low, high, len;
+  long mid = -1;
+  struct ecoff_fdrtab_entry *tab;
+
+  len = line_info->fdrtab_len;
+  if (len == 0)
+    return -1;
+
+  tab = line_info->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;
+    }
+
+  /* eraxxon: at this point 'offset' is either lower than the lowest entry or
+     higher than the highest entry. In the former case high = low = mid = 0;
+     we want to return -1.  In the latter case, low = high and mid = low - 1;
+     we want to return the index of the highest entry.  Only in former case
+     will the following 'catch-all' test be true.  */
+  ++mid;
+
+  /* Last entry is catch-all for all higher addresses.  */
+  if (offset < tab[mid].base_addr)
+    return -1;
+
+ find_min:
+
+  /* eraxxon: There may be multiple FDRs in the table with the
+     same base_addr; make sure that we are at the first one.  */
+  while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr)
+    --mid;
+
+  return mid;
+}
+
+/* Look up a line given an address, storing the information in
+   LINE_INFO->cache.  */
+
+static bfd_boolean
+lookup_line (abfd, debug_info, debug_swap, line_info)
+     bfd *abfd;
+     struct ecoff_debug_info * const debug_info;
+     const struct ecoff_debug_swap * const debug_swap;
+     struct ecoff_find_line *line_info;
+{
+  struct ecoff_fdrtab_entry *tab;
+  bfd_vma offset;
+  bfd_boolean stabs;
+  FDR *fdr_ptr;
+  int i;
+
+  /* eraxxon: note that 'offset' is the full vma, not a section offset.  */
+  offset = line_info->cache.start;
+
+  /* Build FDR table (sorted by object file's base-address) if we
+     don't have it already.  */
+  if (line_info->fdrtab == NULL
+      && !mk_fdrtab (abfd, debug_info, debug_swap, line_info))
+    return FALSE;
+
+  tab = line_info->fdrtab;
+
+  /* Find first FDR for address OFFSET.  */
+  i = fdrtab_lookup (line_info, offset);
+  if (i < 0)
+    return FALSE;              /* no FDR, no fun...  */
+  
+  /* eraxxon: 'fdrtab_lookup' doesn't give what we want, at least for Compaq's
+     C++ compiler 6.2.  Consider three FDRs with starting addresses of x, y,
+     and z, respectively, such that x < y < z.  Assume further that
+     y < 'offset' < z.  It is possible at times that the PDR for 'offset' is
+     associated with FDR x and *not* with FDR y.  Erg!!
+
+     From a binary dump of my C++ test case 'moo' using Compaq's coffobjanl
+     (output format has been edited for our purposes):
+
+     FDR [2]: (main.C): First instruction: 0x12000207c <x>
+       PDR [5] for File [2]: LoopTest__Xv                 <0x1200020a0> (a)
+       PDR [7] for File [2]: foo__Xv                      <0x120002168>
+     FDR [1]: (-1):     First instruction: 0x1200020e8 <y>
+       PDR [3] for File [1]:                              <0x120001ad0> (b)
+     FDR [6]: (-1):     First instruction: 0x1200026f0 <z>
+
+     (a) In the case of PDR5, the vma is such that the first few instructions
+     of the procedure can be found.  But since the size of this procedure is
+     160b, the vma will soon cross into the 'address space' of FDR1 and no
+     debugging info will be found.  How repugnant!
+
+     (b) It is also possible for a PDR to have a *lower* vma than its associated
+     FDR; see FDR1 and PDR3.  Gross!
+
+     Since the FDRs that are causing so much havok (in this case) 1) do not
+     describe actual files (fdr.rss == -1), and 2) contain only compiler
+     generated routines, I thought a simple fix would be to exclude them from
+     the FDR table in 'mk_fdrtab'.  But, besides not knowing for certain
+     whether this would be correct, it creates an additional problem.  If we
+     happen to ask for source file info on a compiler generated (procedure)
+     symbol -- which is still in the symbol table -- the result can be
+     information from a real procedure!  This is because compiler generated
+     procedures with vma's higher than the last FDR in the fdr table will be
+     associated with a PDR from this FDR, specifically the PDR with the
+     highest vma.  This wasn't a problem before, because each procedure had a
+     PDR.  (Yes, this problem could be eliminated if we kept the size of the
+     last PDR around, but things are already getting ugly).
+
+     Probably, a better solution would be to have a sorted PDR table.  Each
+     PDR would have a pointer to its FDR so file information could still be
+     obtained.  A FDR table could still be constructed if necessary -- since
+     it only contains pointers, not much extra memory would be used -- but
+     the PDR table would be searched to locate debugging info.
+
+     There is still at least one remaining issue.  Sometimes a FDR can have a
+     bogus name, but contain PDRs that should belong to another FDR with a
+     real name.  E.g:
+
+     FDR [3]: 0000000120001b50 (/home/.../Array.H~alt~deccxx_5E5A62AD)
+       PDR [a] for File [3]: 0000000120001b50
+       PDR [b] for File [3]: 0000000120001cf0
+       PDR [c] for File [3]: 0000000120001dc8
+       PDR [d] for File [3]: 0000000120001e40
+       PDR [e] for File [3]: 0000000120001eb8
+       PDR [f] for File [3]: 0000000120001f4c
+     FDR [4]: 0000000120001b50 (/home/.../Array.H)
+
+     Here, FDR4 has the correct name, but should (seemingly) contain PDRa-f.
+     The symbol table for PDR4 does contain symbols for PDRa-f, but so does
+     the symbol table for FDR3.  However the former is different; perhaps this
+     can be detected easily. (I'm not sure at this point.)  This problem only
+     seems to be associated with files with templates.  I am assuming the idea
+     is that there is a 'fake' FDR (with PDRs) for each differently typed set
+     of templates that must be generated.  Currently, FDR4 is completely
+     excluded from the FDR table in 'mk_fdrtab' because it contains no PDRs.
+
+     Since I don't have time to prepare a real fix for this right now, be
+     prepared for 'A Horrible Hack' to force the inspection of all non-stabs
+     FDRs.  It's coming...  */
+  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)
+    {
+      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;
+      char *best_pdr = NULL;
+      FDR *best_fdr;
+      bfd_signed_vma best_dist = -1;
+      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;
+
+#if 0 /* eraxxon: PDR addresses (pdr.adr) are not relative to FDRs!
+        Leave 'offset' alone.  */
+      /* Make offset relative to object file's start-address.  */
+      offset -= tab[i].base_addr;
+#endif
+      /* eraxxon: The Horrible Hack: Because of the problems above, set 'i'
+        to 0 so we look through all FDRs.
+
+        Because FDR's without any symbols are assumed to be non-stabs,
+        searching through all FDRs may cause the following code to try to
+        read stabs FDRs as ECOFF ones.  However, I don't think this will
+        harm anything.  */
+      i = 0;
+      
+      /* 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
+       {
+         /* eraxxon: 'dist' and 'min_dist' can be negative now
+             because we iterate over every FDR rather than just ones
+             with a base address less than or equal to 'offset'.  */
+         bfd_signed_vma dist = -1, min_dist = -1;
+         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);
+
+                 /* eraxxon: 'dist' can be negative now.  Note that
+                     'min_dist' can be negative if 'pdr_hold' below is NULL.  */
+                 if (!pdr_hold || (dist >= 0 && dist < min_dist))
+                   {
+                     min_dist = dist;
+                     pdr_hold = pdr_ptr;
+                   }
+               }
+           }
+
+         if (!best_pdr || (min_dist >= 0 && min_dist < best_dist))
+           {
+             best_dist = (bfd_vma) min_dist;  
+             best_fdr = fdr_ptr;
+             best_pdr = pdr_hold;
+           }
+         /* Continue looping until base_addr of next entry is different.  */
+       }
+      /* eraxxon: We want to iterate over all FDRs.
+        See previous comment about 'fdrtab_lookup'.  */
+      while (++i < line_info->fdrtab_len);
+
+      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;
+         unsigned 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)
+           {
+             line_info->cache.stop += count * 4 - offset;
+             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)
+       {
+         line_info->cache.filename = NULL;
+         if (pdr.isym == -1)
+           line_info->cache.functionname = 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);
+             line_info->cache.functionname = (debug_info->ssext
+                                              + proc_ext.asym.iss);
+           }
+       }
+      else
+       {
+         SYMR proc_sym;
+
+         line_info->cache.filename = (debug_info->ss
+                                      + fdr_ptr->issBase
+                                      + fdr_ptr->rss);
+         (*debug_swap->swap_sym_in)
+           (abfd,
+            ((char *) debug_info->external_sym
+             + ((fdr_ptr->isymBase + pdr.isym)
+                * debug_swap->external_sym_size)),
+            &proc_sym);
+         line_info->cache.functionname = (debug_info->ss
+                                          + fdr_ptr->issBase
+                                          + proc_sym.iss);
+       }
+      if (lineno == ilineNil)
+       lineno = 0;
+      line_info->cache.line_num = lineno;
+    }
+  else
+    {
+      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;
+      bfd_boolean past_line;
+      bfd_boolean past_fn;
+      char *sym_ptr, *sym_ptr_end;
+      size_t len, funclen;
+      char *buffer = NULL;
+
+      /* This file uses stabs debugging information.  When gcc is not
+        optimizing, it will put the line number information before
+        the function name stabs entry.  When gcc is optimizing, it
+        will put the stabs entry for all the function first, followed
+        by the line number information.  (This appears to happen
+        because of the two output files used by the -mgpopt switch,
+        which is implied by -O).  This means that we must keep
+        looking through the symbols until we find both a line number
+        and a function name which are beyond the address we want.  */
+
+      line_info->cache.filename = NULL;
+      line_info->cache.functionname = NULL;
+      line_info->cache.line_num = 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;
+      past_line = FALSE;
+      past_fn = FALSE;
+
+      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 - 2) * external_sym_size;
+      for (;
+          sym_ptr < sym_ptr_end && (! past_line || ! past_fn);
+          sym_ptr += external_sym_size)
+       {
+         SYMR sym;
 
-  if (bfd_write (debug->external_ext, swap->external_ext_size,
-                debug->symbolic_header.iextMax, abfd)
-      != debug->symbolic_header.iextMax * swap->external_ext_size)
-    return false;
+         (*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 + nextsym.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 > offset)
+                   past_fn = TRUE;
+                 else if (sym.value >= low_func_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)
+               past_line = TRUE;
+             else if (sym.value >= low_line_vma)
+               {
+                 low_line_vma = sym.value;
+                 line_file_name = current_file_name;
+                 line_info->cache.line_num = sym.index;
+               }
+           }
+       }
+
+      if (line_info->cache.line_num != 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 (line_info->find_buffer != NULL)
+           free (line_info->find_buffer);
+         buffer = (char *) bfd_malloc ((bfd_size_type) len);
+         if (buffer == NULL)
+           return FALSE;
+         line_info->find_buffer = buffer;
+       }
+
+      if (function_name != NULL)
+       {
+         char *colon;
+
+         strcpy (buffer, function_name);
+         colon = strchr (buffer, ':');
+         if (colon != NULL)
+           *colon = '\0';
+         line_info->cache.functionname = buffer;
+       }
+
+      if (main_file_name != NULL)
+       {
+         if (directory_name == NULL || main_file_name[0] == '/')
+           line_info->cache.filename = main_file_name;
+         else
+           {
+             sprintf (buffer + funclen, "%s%s", directory_name,
+                      main_file_name);
+             line_info->cache.filename = buffer + funclen;
+           }
+       }
+    }
+
+  return TRUE;
+}
+
+/* Do the work of find_nearest_line.  */
+
+bfd_boolean
+_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap,
+                       line_info, filename_ptr, functionname_ptr, retline_ptr)
+     bfd *abfd;
+     asection *section;
+     bfd_vma offset;
+     struct ecoff_debug_info * const debug_info;
+     const struct ecoff_debug_swap * const debug_swap;
+     struct ecoff_find_line *line_info;
+     const char **filename_ptr;
+     const char **functionname_ptr;
+     unsigned int *retline_ptr;
+{
+  offset += section->vma;
+
+  if (line_info->cache.sect == NULL
+      || line_info->cache.sect != section
+      || offset < line_info->cache.start
+      || offset >= line_info->cache.stop)
+    {
+      line_info->cache.sect = section;
+      line_info->cache.start = offset;
+      line_info->cache.stop = offset;
+      if (! lookup_line (abfd, debug_info, debug_swap, line_info))
+       {
+         line_info->cache.sect = NULL;
+         return FALSE;
+       }
+    }
+
+  *filename_ptr = line_info->cache.filename;
+  *functionname_ptr = line_info->cache.functionname;
+  *retline_ptr = line_info->cache.line_num;
+
+  return TRUE;
+}
+\f
+/* These routines copy symbolic information into a memory buffer.
+
+   FIXME: The whole point of the shuffle code is to avoid storing
+   everything in memory, since the linker is such a memory hog.  This
+   code makes that effort useless.  It is only called by the MIPS ELF
+   code when generating a shared library, so it is not that big a
+   deal, but it should be fixed eventually.  */
+
+/* Collect a shuffle into a memory buffer.  */
+
+static bfd_boolean ecoff_collect_shuffle
+  PARAMS ((struct shuffle *, bfd_byte *));
+
+static bfd_boolean
+ecoff_collect_shuffle (l, buff)
+     struct shuffle *l;
+     bfd_byte *buff;
+{
+  unsigned long total;
+
+  total = 0;
+  for (; l != (struct shuffle *) NULL; l = l->next)
+    {
+      if (! l->filep)
+       memcpy (buff, l->u.memory, l->size);
+      else
+       {
+         if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
+             || (bfd_bread (buff, (bfd_size_type) l->size, l->u.file.input_bfd)
+                 != l->size))
+           return FALSE;
+       }
+      total += l->size;
+      buff += l->size;
+    }
+
+  return TRUE;
+}
+
+/* Copy PDR information into a memory buffer.  */
+
+bfd_boolean
+_bfd_ecoff_get_accumulated_pdr (handle, buff)
+     PTR handle;
+     bfd_byte *buff;
+{
+  struct accumulate *ainfo = (struct accumulate *) handle;
+
+  return ecoff_collect_shuffle (ainfo->pdr, buff);
+}
+
+/* Copy symbol information into a memory buffer.  */
+
+bfd_boolean
+_bfd_ecoff_get_accumulated_sym (handle, buff)
+     PTR handle;
+     bfd_byte *buff;
+{
+  struct accumulate *ainfo = (struct accumulate *) handle;
+
+  return ecoff_collect_shuffle (ainfo->sym, buff);
+}
+
+/* Copy the string table into a memory buffer.  */
+
+bfd_boolean
+_bfd_ecoff_get_accumulated_ss (handle, buff)
+     PTR handle;
+     bfd_byte *buff;
+{
+  struct accumulate *ainfo = (struct accumulate *) handle;
+  struct string_hash_entry *sh;
+  unsigned long total;
+
+  /* The string table is written out from the hash table if this is a
+     final link.  */
+  BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
+  *buff++ = '\0';
+  total = 1;
+  BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
+  for (sh = ainfo->ss_hash;
+       sh != (struct string_hash_entry *) NULL;
+       sh = sh->next)
+    {
+      size_t len;
+
+      len = strlen (sh->root.string);
+      memcpy (buff, (PTR) sh->root.string, len + 1);
+      total += len + 1;
+      buff += len + 1;
+    }
 
-  return true;
+  return TRUE;
 }
This page took 0.056124 seconds and 4 git commands to generate.