ecoff gprof related fixes & improvements from David Mosberger-Tang
authorKen Raeburn <raeburn@cygnus>
Tue, 7 Feb 1995 01:06:25 +0000 (01:06 +0000)
committerKen Raeburn <raeburn@cygnus>
Tue, 7 Feb 1995 01:06:25 +0000 (01:06 +0000)
bfd/ChangeLog
bfd/ecoff.c
bfd/ecoffswap.h

index be78ac049cecea885aa0bdf5309e00422f19661f..6434308b4c57e81d4dd3b7eed9447eab793a3b90 100644 (file)
@@ -1,3 +1,14 @@
+Mon Feb  6 20:01:24 1995  Ken Raeburn  <raeburn@cujo.cygnus.com>
+
+       Sat Feb  4 14:20:24 1995  David Mosberger-Tang  <davidm@piston.cs.arizona.edu>
+
+       * ecoffswap.h (ecoff_swap_pdr_in, ecoff_swap_pdr_out): added
+       internalizing/externalizing new "prof" field.
+
+       * libecoff.h (ecoff_tdata): added fdrtab.
+
+       * ecoff.c (_bfd_ecoff_find_nearest_line): Fixed.
+
 Mon Feb  6 14:25:24 1995  Ian Lance Taylor  <ian@cygnus.com>
 
        * libelf.h (struct elf_link_hash_table): Add saw_needed field.
index d6fbea93581461e3f46178e5b0b511dac31d6efe..4d80edc5d9b97794805fcaffb3e4f73ad05f0aab 100644 (file)
@@ -2002,6 +2002,172 @@ _bfd_ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
   return section->reloc_count;
 }
 \f
+
+static int
+cmp_fdrtab_entry (const void *leftp, const void *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 (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 (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.  */
@@ -2021,49 +2187,39 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
   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;
-  FDR *fdr_ptr;
-  FDR *fdr_start;
-  FDR *fdr_end;
-  FDR *fdr_hold;
+  struct ecoff_fdrtab_entry *tab;
   boolean stabs;
+  FDR *fdr_ptr;
+  int i;
 
   offset += section->vma;
-
-  /* If we're not in the .text section, we don't have any line
-     numbers.  */
+  /*
+   * 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;
+  /*
+   * 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;
+  }
+  tab = ecoff_data (abfd)->fdrtab;
 
-  /* 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;
+  i = lookup(abfd, offset);    /* find first FDR for address OFFSET */
+  if (i < 0)
+    return false;              /* no FDR, no fun... */
+  fdr_ptr = tab[i].fdr;
 
-  /* 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 = debug_info->fdr;
-  fdr_end = fdr_start + 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)
-    return false;
-  fdr_ptr = fdr_hold;
-
-  /* Check whether this file has stabs debugging information.  In a
-     file with stabs debugging information, the second local symbol is
-     named @stabs.  */
+  /*
+   * 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)
     {
@@ -2078,58 +2234,143 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
        stabs = true;
     }
 
-  if (! stabs)
+  if (!stabs)
     {
       bfd_size_type external_pdr_size;
       char *pdr_ptr;
-      char *pdr_end;
+      char *best_pdr = NULL;
+      FDR *best_fdr;
+      bfd_vma best_dist = ~0;
       PDR pdr;
-      bfd_vma first_off;
       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).  PDR's also have an
-        address, which is relative to the FDR address, and are also
-        stored in increasing memory order.  */
-      if (offset < fdr_ptr->adr)
-       return false;
-      offset -= fdr_ptr->adr;
+      /*
+       * 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;
-      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);
 
-      /* The address of the first PDR is an offset which applies to
-        the addresses of all the PDR's.  */
-      first_off = pdr.adr;
+      /* 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 {
+       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;
+                 }
+             }
+         }
 
-      for (pdr_ptr += external_pdr_size;
-          pdr_ptr < pdr_end;
-          pdr_ptr += external_pdr_size)
-       {
-         (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
-         if (offset < pdr.adr - first_off)
-           break;
-       }
+       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: */
+      } while (++i < ecoff_data (abfd)->fdrtab_len
+              && tab[i].base_addr == tab[i - 1].base_addr);
 
-      /* 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 = debug_info->line;
-      if (pdr_ptr == pdr_end)
-       line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
-      else
-       line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset;
+      if (!best_fdr || !best_pdr)
+       return false;                   /* shouldn't happen... */
 
-      /* Now change pdr and pdr_ptr to the one we want.  */
-      pdr_ptr -= external_pdr_size;
+      /* 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;
 
-      offset -= pdr.adr - first_off;
+      /* 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)
@@ -2155,8 +2396,10 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
          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 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;
@@ -2346,6 +2589,7 @@ _bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
 
   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
index 087e0528b9ce9120d0985d1603c8cbeb136b3dd8..4500f0fd7425a13cf2104a861fc7a760921d38f7 100644 (file)
@@ -53,12 +53,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* ECOFF auxiliary information swapping routines.  These are the same
    for all ECOFF targets, so they are defined in ecoff.c.  */
-extern void ecoff_swap_tir_in PARAMS ((int, const struct tir_ext *, TIR *));
-extern void ecoff_swap_tir_out PARAMS ((int, const TIR *, struct tir_ext *));
-extern void ecoff_swap_rndx_in PARAMS ((int, const struct rndx_ext *,
-                                       RNDXR *));
-extern void ecoff_swap_rndx_out PARAMS ((int, const RNDXR *,
-                                        struct rndx_ext *));
+extern void _bfd_ecoff_swap_tir_in
+  PARAMS ((int, const struct tir_ext *, TIR *));
+extern void _bfd_ecoff_swap_tir_out
+  PARAMS ((int, const TIR *, struct tir_ext *));
+extern void _bfd_ecoff_swap_rndx_in
+  PARAMS ((int, const struct rndx_ext *, RNDXR *));
+extern void _bfd_ecoff_swap_rndx_out
+  PARAMS ((int, const RNDXR *, struct rndx_ext *));
 
 /* Swap in the symbolic header.  */
 
@@ -281,6 +283,9 @@ ecoff_swap_fdr_out (abfd, intern_copy, ext_ptr)
 #endif
 }
 
+/* start-sanitize-mpw */
+#ifndef MPW_C
+/* end-sanitize-mpw */
 /* Swap in the procedure descriptor record.  */
 
 static void
@@ -317,6 +322,7 @@ ecoff_swap_pdr_in (abfd, ext_copy, intern)
     {
       intern->gp_used = 0 != (ext->p_bits1[0] & PDR_BITS1_GP_USED_BIG);
       intern->reg_frame = 0 != (ext->p_bits1[0] & PDR_BITS1_REG_FRAME_BIG);
+      intern->prof = 0 != (ext->p_bits1[0] & PDR_BITS1_PROF_BIG);
       intern->reserved = (((ext->p_bits1[0] & PDR_BITS1_RESERVED_BIG)
                           << PDR_BITS1_RESERVED_SH_LEFT_BIG)
                          | ((ext->p_bits2[0] & PDR_BITS2_RESERVED_BIG)
@@ -326,6 +332,7 @@ ecoff_swap_pdr_in (abfd, ext_copy, intern)
     {
       intern->gp_used = 0 != (ext->p_bits1[0] & PDR_BITS1_GP_USED_LITTLE);
       intern->reg_frame = 0 != (ext->p_bits1[0] & PDR_BITS1_REG_FRAME_LITTLE);
+      intern->prof = 0 != (ext->p_bits1[0] & PDR_BITS1_PROF_LITTLE);
       intern->reserved = (((ext->p_bits1[0] & PDR_BITS1_RESERVED_LITTLE)
                           >> PDR_BITS1_RESERVED_SH_LITTLE)
                          | ((ext->p_bits2[0] & PDR_BITS2_RESERVED_LITTLE)
@@ -374,6 +381,7 @@ ecoff_swap_pdr_out (abfd, intern_copy, ext_ptr)
     {
       ext->p_bits1[0] = ((intern->gp_used ? PDR_BITS1_GP_USED_BIG : 0)
                         | (intern->reg_frame ? PDR_BITS1_REG_FRAME_BIG : 0)
+                        | (intern->prof ? PDR_BITS1_PROF_BIG : 0)
                         | ((intern->reserved
                             >> PDR_BITS1_RESERVED_SH_LEFT_BIG)
                            & PDR_BITS1_RESERVED_BIG));
@@ -384,6 +392,7 @@ ecoff_swap_pdr_out (abfd, intern_copy, ext_ptr)
     {
       ext->p_bits1[0] = ((intern->gp_used ? PDR_BITS1_GP_USED_LITTLE : 0)
                         | (intern->reg_frame ? PDR_BITS1_REG_FRAME_LITTLE : 0)
+                        | (intern->prof ? PDR_BITS1_PROF_LITTLE : 0)
                         | ((intern->reserved << PDR_BITS1_RESERVED_SH_LITTLE)
                            & PDR_BITS1_RESERVED_LITTLE));
       ext->p_bits2[0] = ((intern->reserved >>
@@ -398,6 +407,81 @@ ecoff_swap_pdr_out (abfd, intern_copy, ext_ptr)
     abort();
 #endif
 }
+/* start-sanitize-mpw */
+#else /* MPW_C */
+/* Same routines, but with ECOFF_64 code removed, so ^&%$#&! MPW C doesn't
+   corrupt itself and then freak out. */
+/* Swap in the procedure descriptor record.  */
+
+static void
+ecoff_swap_pdr_in (abfd, ext_copy, intern)
+     bfd *abfd;
+     PTR ext_copy;
+     PDR *intern;
+{
+  struct pdr_ext ext[1];
+
+  *ext = *(struct pdr_ext *) ext_copy;
+  
+  intern->adr           = ecoff_get_off (abfd, (bfd_byte *)ext->p_adr);
+  intern->isym          = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_isym);
+  intern->iline         = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_iline);
+  intern->regmask       = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_regmask);
+  intern->regoffset     = bfd_h_get_signed_32 (abfd,
+                                              (bfd_byte *)ext->p_regoffset);
+  intern->iopt          = bfd_h_get_signed_32 (abfd, (bfd_byte *)ext->p_iopt);
+  intern->fregmask      = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_fregmask);
+  intern->fregoffset    = bfd_h_get_signed_32 (abfd,
+                                              (bfd_byte *)ext->p_fregoffset);
+  intern->frameoffset   = bfd_h_get_signed_32 (abfd,
+                                              (bfd_byte *)ext->p_frameoffset);
+  intern->framereg      = bfd_h_get_16 (abfd, (bfd_byte *)ext->p_framereg);
+  intern->pcreg         = bfd_h_get_16 (abfd, (bfd_byte *)ext->p_pcreg);
+  intern->lnLow         = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_lnLow);
+  intern->lnHigh        = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_lnHigh);
+  intern->cbLineOffset  = ecoff_get_off (abfd, (bfd_byte *)ext->p_cbLineOffset);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+
+/* Swap out the procedure descriptor record.  */
+
+static void
+ecoff_swap_pdr_out (abfd, intern_copy, ext_ptr)
+     bfd *abfd;
+     const PDR *intern_copy;
+     PTR ext_ptr;
+{
+  struct pdr_ext *ext = (struct pdr_ext *) ext_ptr;
+  PDR intern[1];
+
+  *intern = *intern_copy;      /* Make it reasonable to do in-place.  */
+  
+  ecoff_put_off (abfd, intern->adr, (bfd_byte *)ext->p_adr);
+  bfd_h_put_32 (abfd, intern->isym, (bfd_byte *)ext->p_isym);
+  bfd_h_put_32 (abfd, intern->iline, (bfd_byte *)ext->p_iline);
+  bfd_h_put_32 (abfd, intern->regmask, (bfd_byte *)ext->p_regmask);
+  bfd_h_put_32 (abfd, intern->regoffset, (bfd_byte *)ext->p_regoffset);
+  bfd_h_put_32 (abfd, intern->iopt, (bfd_byte *)ext->p_iopt);
+  bfd_h_put_32 (abfd, intern->fregmask, (bfd_byte *)ext->p_fregmask);
+  bfd_h_put_32 (abfd, intern->fregoffset, (bfd_byte *)ext->p_fregoffset);
+  bfd_h_put_32 (abfd, intern->frameoffset, (bfd_byte *)ext->p_frameoffset);
+  bfd_h_put_16 (abfd, intern->framereg, (bfd_byte *)ext->p_framereg);
+  bfd_h_put_16 (abfd, intern->pcreg, (bfd_byte *)ext->p_pcreg);
+  bfd_h_put_32 (abfd, intern->lnLow, (bfd_byte *)ext->p_lnLow);
+  bfd_h_put_32 (abfd, intern->lnHigh, (bfd_byte *)ext->p_lnHigh);
+  ecoff_put_off (abfd, intern->cbLineOffset, (bfd_byte *)ext->p_cbLineOffset);
+
+#ifdef TEST
+  if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0)
+    abort();
+#endif
+}
+#endif /* MPW_C */
+/* end-sanitize-mpw */
 
 /* Swap in a symbol record.  */
 
@@ -555,11 +639,19 @@ ecoff_swap_ext_out (abfd, intern_copy, ext_ptr)
                        | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_BIG : 0)
                        | (intern->weakext ? EXT_BITS1_WEAKEXT_BIG : 0));
     ext->es_bits2[0] = 0;
+#ifdef ECOFF_64
+    ext->es_bits2[1] = 0;
+    ext->es_bits2[2] = 0;
+#endif
   } else {
     ext->es_bits1[0] = ((intern->jmptbl ? EXT_BITS1_JMPTBL_LITTLE : 0)
                        | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_LITTLE : 0)
                        | (intern->weakext ? EXT_BITS1_WEAKEXT_LITTLE : 0));
     ext->es_bits2[0] = 0;
+#ifdef ECOFF_64
+    ext->es_bits2[1] = 0;
+    ext->es_bits2[2] = 0;
+#endif
   }
 
 #ifdef ECOFF_32
@@ -643,8 +735,8 @@ ecoff_swap_opt_in (abfd, ext_copy, intern)
                       | (ext->o_bits4[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE));
     }
 
-  ecoff_swap_rndx_in (abfd->xvec->header_byteorder_big_p != false,
-                     &ext->o_rndx, &intern->rndx);
+  _bfd_ecoff_swap_rndx_in (abfd->xvec->header_byteorder_big_p != false,
+                          &ext->o_rndx, &intern->rndx);
 
   intern->offset = bfd_h_get_32 (abfd, (bfd_byte *) ext->o_offset);
 
@@ -682,8 +774,8 @@ ecoff_swap_opt_out (abfd, intern_copy, ext_ptr)
       ext->o_bits4[0] = intern->value >> OPT_BITS4_VALUE_SH_LEFT_LITTLE;
     }
 
-  ecoff_swap_rndx_out (abfd->xvec->header_byteorder_big_p != false,
-                      &intern->rndx, &ext->o_rndx);
+  _bfd_ecoff_swap_rndx_out (abfd->xvec->header_byteorder_big_p != false,
+                           &intern->rndx, &ext->o_rndx);
 
   bfd_h_put_32 (abfd, intern->value, (bfd_byte *) ext->o_offset);