* mips-dis.c: Add missing prototypes.
[deliverable/binutils-gdb.git] / binutils / ieee.c
index 46b528df6fa05dc9cb99e2eb926980c155b65161..ad5ddc7d65cb3aed0b6adcd83e4d2703fb3b7ae6 100644 (file)
@@ -1,5 +1,5 @@
 /* ieee.c -- Read and write IEEE-695 debugging information.
-   Copyright (C) 1996 Free Software Foundation, Inc.
+   Copyright 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@cygnus.com>.
 
    This file is part of GNU Binutils.
@@ -30,6 +30,7 @@
 #include "libiberty.h"
 #include "debug.h"
 #include "budbg.h"
+#include "filenames.h"
 
 /* This structure holds an entry on the block stack.  */
 
@@ -41,6 +42,8 @@ struct ieee_block
   const char *filename;
   /* The index of the function type, for a BB4 or BB6 block.  */
   unsigned int fnindx;
+  /* True if this function is being skipped.  */
+  boolean skip;
 };
 
 /* This structure is the block stack.  */
@@ -152,10 +155,16 @@ struct ieee_info
   const bfd_byte *pend;
   /* The block stack.  */
   struct ieee_blockstack blockstack;
+  /* Whether we have seen a BB1 or BB2.  */
+  boolean saw_filename;
   /* The variables.  */
   struct ieee_vars vars;
+  /* The global variables, after a global typedef block.  */
+  struct ieee_vars *global_vars;
   /* The types.  */
   struct ieee_types types;
+  /* The global types, after a global typedef block.  */
+  struct ieee_types *global_types;
   /* The list of tagged structs.  */
   struct ieee_tag *tags;
 };
@@ -305,7 +314,7 @@ ieee_eof (info)
      struct ieee_info *info;
 {
   ieee_error (info, (const bfd_byte *) NULL,
-             "unexpected end of debugging information");
+             _("unexpected end of debugging information"));
 }
 
 /* Save a string in memory.  */
@@ -400,8 +409,8 @@ ieee_read_optional_number (info, pp, pv, ppresent)
       return true;
     }
 
-  ieee_error (info, *pp - 1, "invalid number");
-  return false;  
+  ieee_error (info, *pp - 1, _("invalid number"));
+  return false;
 }
 
 /* Read a required string from an IEEE file.  */
@@ -459,7 +468,7 @@ ieee_read_optional_id (info, pp, pname, pnamlen, ppresent)
          *ppresent = false;
          return true;
        }
-      ieee_error (info, *pp - 1, "invalid string length");
+      ieee_error (info, *pp - 1, _("invalid string length"));
       return false;
     }
 
@@ -516,7 +525,7 @@ ieee_read_expression (info, pp, pv)
        {
          if (esp - expr_stack >= EXPR_STACK_SIZE)
            {
-             ieee_error (info, start, "expression stack overflow");
+             ieee_error (info, start, _("expression stack overflow"));
              return false;
            }
          *esp++ = val;
@@ -536,7 +545,7 @@ ieee_read_expression (info, pp, pv)
       switch (c)
        {
        default:
-         ieee_error (info, start, "unsupported IEEE expression operator");
+         ieee_error (info, start, _("unsupported IEEE expression operator"));
          break;
 
        case ieee_variable_R_enum:
@@ -551,13 +560,13 @@ ieee_read_expression (info, pp, pv)
                break;
            if (s == NULL)
              {
-               ieee_error (info, start, "unknown section");
+               ieee_error (info, start, _("unknown section"));
                return false;
              }
-           
+
            if (esp - expr_stack >= EXPR_STACK_SIZE)
              {
-               ieee_error (info, start, "expression stack overflow");
+               ieee_error (info, start, _("expression stack overflow"));
                return false;
              }
 
@@ -572,7 +581,7 @@ ieee_read_expression (info, pp, pv)
 
            if (esp - expr_stack < 2)
              {
-               ieee_error (info, start, "expression stack underflow");
+               ieee_error (info, start, _("expression stack underflow"));
                return false;
              }
 
@@ -586,7 +595,7 @@ ieee_read_expression (info, pp, pv)
 
   if (esp - 1 != expr_stack)
     {
-      ieee_error (info, expr_start, "expression stack mismatch");
+      ieee_error (info, expr_start, _("expression stack mismatch"));
       return false;
     }
 
@@ -625,7 +634,7 @@ ieee_builtin_type (info, p, indx)
   switch ((enum builtin_types) indx)
     {
     default:
-      ieee_error (info, p, "unknown builtin type");
+      ieee_error (info, p, _("unknown builtin type"));
       return NULL;
 
     case builtin_unknown:
@@ -770,8 +779,8 @@ ieee_builtin_type (info, p, indx)
       break;
 
     case builtin_bcd_float:
-      ieee_error (info, p, "BCD float type not supported");
-      return false;
+      ieee_error (info, p, _("BCD float type not supported"));
+      return DEBUG_TYPE_NULL;
     }
 
   if (name != NULL)
@@ -889,10 +898,13 @@ parse_ieee (dhandle, abfd, bytes, len)
   info.bytes = bytes;
   info.pend = bytes + len;
   info.blockstack.bsp = info.blockstack.stack;
+  info.saw_filename = false;
   info.vars.alloc = 0;
   info.vars.vars = NULL;
+  info.global_vars = NULL;
   info.types.alloc = 0;
   info.types.types = NULL;
+  info.global_types = NULL;
   info.tags = NULL;
   for (i = 0; i < BUILTIN_TYPE_COUNT; i++)
     info.types.builtins[i] = DEBUG_TYPE_NULL;
@@ -913,14 +925,14 @@ parse_ieee (dhandle, abfd, bytes, len)
 
       if (c <= ieee_number_repeat_end_enum)
        {
-         ieee_error (&info, record_start, "unexpected number");
+         ieee_error (&info, record_start, _("unexpected number"));
          return false;
        }
 
       switch (c)
        {
        default:
-         ieee_error (&info, record_start, "unexpected record type");
+         ieee_error (&info, record_start, _("unexpected record type"));
          return false;
 
        case ieee_bb_record_enum:
@@ -953,7 +965,7 @@ parse_ieee (dhandle, abfd, bytes, len)
   if (info.blockstack.bsp != info.blockstack.stack)
     {
       ieee_error (&info, (const bfd_byte *) NULL,
-                 "blocks left on stack at end");
+                 _("blocks left on stack at end"));
       return false;
     }
 
@@ -972,8 +984,9 @@ parse_ieee_bb (info, pp)
   bfd_vma size;
   const char *name;
   unsigned long namlen;
-  char *namcopy;
+  char *namcopy = NULL;
   unsigned int fnindx;
+  boolean skip;
 
   block_start = *pp;
 
@@ -985,6 +998,7 @@ parse_ieee_bb (info, pp)
     return false;
 
   fnindx = (unsigned int) -1;
+  skip = false;
 
   switch (b)
     {
@@ -995,6 +1009,29 @@ parse_ieee_bb (info, pp)
        return false;
       if (! debug_set_filename (info->dhandle, namcopy))
        return false;
+      info->saw_filename = true;
+
+      /* Discard any variables or types we may have seen before.  */
+      if (info->vars.vars != NULL)
+       free (info->vars.vars);
+      info->vars.vars = NULL;
+      info->vars.alloc = 0;
+      if (info->types.types != NULL)
+       free (info->types.types);
+      info->types.types = NULL;
+      info->types.alloc = 0;
+
+      /* Initialize the types to the global types.  */
+      if (info->global_types != NULL)
+       {
+         info->types.alloc = info->global_types->alloc;
+         info->types.types = ((struct ieee_type *)
+                              xmalloc (info->types.alloc
+                                       * sizeof (*info->types.types)));
+         memcpy (info->types.types, info->global_types->types,
+                 info->types.alloc * sizeof (*info->types.types));
+       }
+
       break;
 
     case 2:
@@ -1002,6 +1039,7 @@ parse_ieee_bb (info, pp)
         empty, but we don't check. */
       if (! debug_set_filename (info->dhandle, "*global*"))
        return false;
+      info->saw_filename = true;
       break;
 
     case 3:
@@ -1098,40 +1136,51 @@ parse_ieee_bb (info, pp)
          }
        else
          {
-           debug_type return_type;
-
-           if (typindx < 256)
-             {
-               return_type = ieee_builtin_type (info, block_start, typindx);
-               if (return_type == NULL)
-                 return false;
-             }
+           /* The MRI C++ compiler will output a fake function named
+              __XRYCPP to hold C++ debugging information.  We skip
+              that function.  This is not crucial, but it makes
+              converting from IEEE to other debug formats work
+              better.  */
+           if (strncmp (name, "__XRYCPP", namlen) == 0)
+             skip = true;
            else
              {
-               typindx -= 256;
-               if (! ieee_alloc_type (info, typindx, true))
+               debug_type return_type;
+
+               if (typindx < 256)
+                 {
+                   return_type = ieee_builtin_type (info, block_start,
+                                                    typindx);
+                   if (return_type == NULL)
+                     return false;
+                 }
+               else
+                 {
+                   typindx -= 256;
+                   if (! ieee_alloc_type (info, typindx, true))
+                     return false;
+                   fnindx = typindx;
+                   return_type = info->types.types[typindx].type;
+                   if (debug_get_type_kind (info->dhandle, return_type)
+                       == DEBUG_KIND_FUNCTION)
+                     return_type = debug_get_return_type (info->dhandle,
+                                                          return_type);
+                 }
+
+               namcopy = savestring (name, namlen);
+               if (namcopy == NULL)
+                 return false;
+               if (! debug_record_function (info->dhandle, namcopy,
+                                            return_type, false, offset))
                  return false;
-               fnindx = typindx;
-               return_type = info->types.types[typindx].type;
-               if (debug_get_type_kind (info->dhandle, return_type)
-                   == DEBUG_KIND_FUNCTION)
-                 return_type = debug_get_return_type (info->dhandle,
-                                                      return_type);
              }
-
-           namcopy = savestring (name, namlen);
-           if (namcopy == NULL)
-             return false;
-           if (! debug_record_function (info->dhandle, namcopy, return_type,
-                                        false, offset))
-             return false;
          }
       }
       break;
 
     case 10:
-      /* BB10: Assembler module scope.  We completely ignore all this
-        information.  FIXME.  */
+      /* BB10: Assembler module scope.  In the normal case, we
+        completely ignore all this information.  FIXME.  */
       {
        const char *inam, *vstr;
        unsigned long inamlen, vstrlen;
@@ -1139,6 +1188,16 @@ parse_ieee_bb (info, pp)
        boolean present;
        unsigned int i;
 
+       if (! info->saw_filename)
+         {
+           namcopy = savestring (name, namlen);
+           if (namcopy == NULL)
+             return false;
+           if (! debug_set_filename (info->dhandle, namcopy))
+             return false;
+           info->saw_filename = true;
+         }
+
        if (! ieee_read_id (info, pp, &inam, &inamlen)
            || ! ieee_read_number (info, pp, &tool_type)
            || ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present))
@@ -1171,7 +1230,7 @@ parse_ieee_bb (info, pp)
       break;
 
     default:
-      ieee_error (info, block_start, "unknown BB type");
+      ieee_error (info, block_start, _("unknown BB type"));
       return false;
     }
 
@@ -1180,7 +1239,7 @@ parse_ieee_bb (info, pp)
 
   if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE)
     {
-      ieee_error (info, (const bfd_byte *) NULL, "stack overflow");
+      ieee_error (info, (const bfd_byte *) NULL, _("stack overflow"));
       return false;
     }
 
@@ -1188,6 +1247,7 @@ parse_ieee_bb (info, pp)
   if (b == 5)
     info->blockstack.bsp->filename = namcopy;
   info->blockstack.bsp->fnindx = fnindx;
+  info->blockstack.bsp->skip = skip;
   ++info->blockstack.bsp;
 
   return true;
@@ -1204,19 +1264,53 @@ parse_ieee_be (info, pp)
 
   if (info->blockstack.bsp <= info->blockstack.stack)
     {
-      ieee_error (info, *pp, "stack underflow");
+      ieee_error (info, *pp, _("stack underflow"));
       return false;
     }
   --info->blockstack.bsp;
 
   switch (info->blockstack.bsp->kind)
     {
+    case 2:
+      /* When we end the global typedefs block, we copy out the the
+         contents of info->vars.  This is because the variable indices
+         may be reused in the local blocks.  However, we need to
+         preserve them so that we can locate a function returning a
+         reference variable whose type is named in the global typedef
+         block.  */
+      info->global_vars = ((struct ieee_vars *)
+                          xmalloc (sizeof *info->global_vars));
+      info->global_vars->alloc = info->vars.alloc;
+      info->global_vars->vars = ((struct ieee_var *)
+                                xmalloc (info->vars.alloc
+                                         * sizeof (*info->vars.vars)));
+      memcpy (info->global_vars->vars, info->vars.vars,
+             info->vars.alloc * sizeof (*info->vars.vars));
+
+      /* We also copy out the non builtin parts of info->types, since
+         the types are discarded when we start a new block.  */
+      info->global_types = ((struct ieee_types *)
+                           xmalloc (sizeof *info->global_types));
+      info->global_types->alloc = info->types.alloc;
+      info->global_types->types = ((struct ieee_type *)
+                                  xmalloc (info->types.alloc
+                                           * sizeof (*info->types.types)));
+      memcpy (info->global_types->types, info->types.types,
+             info->types.alloc * sizeof (*info->types.types));
+      memset (info->global_types->builtins, 0,
+             sizeof (info->global_types->builtins));
+
+      break;
+
     case 4:
     case 6:
       if (! ieee_read_expression (info, pp, &offset))
        return false;
-      if (! debug_end_function (info->dhandle, offset))
-       return false;
+      if (! info->blockstack.bsp->skip)
+       {
+         if (! debug_end_function (info->dhandle, offset + 1))
+           return false;
+       }
       break;
 
     case 0x86:
@@ -1224,7 +1318,7 @@ parse_ieee_be (info, pp)
         function.  */
       if (! ieee_read_expression (info, pp, &offset))
        return false;
-      if (! debug_end_block (info->dhandle, offset))
+      if (! debug_end_block (info->dhandle, offset + 1))
        return false;
       break;
 
@@ -1284,7 +1378,7 @@ parse_ieee_nn (info, pp)
 
   if (varindx < 32)
     {
-      ieee_error (info, nn_start, "illegal variable index");
+      ieee_error (info, nn_start, _("illegal variable index"));
       return false;
     }
   varindx -= 32;
@@ -1334,7 +1428,7 @@ parse_ieee_ty (info, pp)
 
   if (typeindx < 256)
     {
-      ieee_error (info, ty_start, "illegal type index");
+      ieee_error (info, ty_start, _("illegal type index"));
       return false;
     }
 
@@ -1344,7 +1438,7 @@ parse_ieee_ty (info, pp)
 
   if (**pp != 0xce)
     {
-      ieee_error (info, *pp, "unknown TY code");
+      ieee_error (info, *pp, _("unknown TY code"));
       return false;
     }
   ++*pp;
@@ -1356,14 +1450,14 @@ parse_ieee_ty (info, pp)
 
   if (varindx < 32)
     {
-      ieee_error (info, ty_var_start, "illegal variable index");
+      ieee_error (info, ty_var_start, _("illegal variable index"));
       return false;
     }
   varindx -= 32;
 
   if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL)
     {
-      ieee_error (info, ty_var_start, "undefined variable in TY");
+      ieee_error (info, ty_var_start, _("undefined variable in TY"));
       return false;
     }
 
@@ -1381,7 +1475,7 @@ parse_ieee_ty (info, pp)
   switch (tc)
     {
     default:
-      ieee_error (info, ty_code_start, "unknown TY code");
+      ieee_error (info, ty_code_start, _("unknown TY code"));
       return false;
 
     case '!':
@@ -1734,6 +1828,11 @@ parse_ieee_ty (info, pp)
       }
       break;
 
+    case 'V':
+      /* Void.  This is not documented, but the MRI compiler emits it.  */
+      type = debug_make_void_type (dhandle);
+      break;
+
     case 'Z':
       /* Array with 0 lower bound.  */
       {
@@ -1769,22 +1868,37 @@ parse_ieee_ty (info, pp)
 
     case 'f':
       /* Pascal file name.  FIXME.  */
-      ieee_error (info, ty_code_start, "Pascal file name not supported");
+      ieee_error (info, ty_code_start, _("Pascal file name not supported"));
       return false;
 
     case 'g':
       /* Bitfield type.  */
       {
-       bfd_vma signedp, bitsize;
+       bfd_vma signedp, bitsize, dummy;
+       const bfd_byte *hold;
+       boolean present;
 
        if (! ieee_read_number (info, pp, &signedp)
-           || ! ieee_read_number (info, pp, &bitsize)
-           || ! ieee_read_type_index (info, pp, &type))
+           || ! ieee_read_number (info, pp, &bitsize))
          return false;
 
-       /* FIXME: This is just a guess.  */
-       if (! signedp)
-         type = debug_make_int_type (dhandle, 4, true);
+       /* I think the documentation says that there is a type index,
+           but some actual files do not have one.  */
+       hold = *pp;
+       if (! ieee_read_optional_number (info, pp, &dummy, &present))
+         return false;
+       if (! present)
+         {
+           /* FIXME: This is just a guess.  */
+           type = debug_make_int_type (dhandle, 4,
+                                       signedp ? false : true);
+         }
+       else
+         {
+           *pp = hold;
+           if (! ieee_read_type_index (info, pp, &type))
+             return false;
+         }
        type_bitsize = bitsize;
       }
       break;
@@ -1802,7 +1916,7 @@ parse_ieee_ty (info, pp)
        switch (kind)
          {
          default:
-           ieee_error (info, ty_start, "unsupported qualifer");
+           ieee_error (info, ty_start, _("unsupported qualifer"));
            return false;
 
          case 1:
@@ -1935,8 +2049,7 @@ parse_ieee_ty (info, pp)
       break;
     }
 
-  /* Record the type in the table.  If the corresponding NN record has
-     a name, name it.  FIXME: Is this always correct?  */
+  /* Record the type in the table.  */
 
   if (type == DEBUG_TYPE_NULL)
     return false;
@@ -2031,7 +2144,12 @@ parse_ieee_atn (info, pp)
     }
   else if (varindx < 32)
     {
-      ieee_error (info, atn_start, "illegal variable index");
+      /* The MRI compiler reportedly sometimes emits variable lifetime
+         information for a register.  We just ignore it.  */
+      if (atn_code == 9)
+       return ieee_read_number (info, pp, &v);
+
+      ieee_error (info, atn_start, _("illegal variable index"));
       return false;
     }
   else
@@ -2040,8 +2158,38 @@ parse_ieee_atn (info, pp)
       if (varindx >= info->vars.alloc
          || info->vars.vars[varindx].name == NULL)
        {
-         ieee_error (info, atn_start, "undefined variable in ATN");
-         return false;
+         /* The MRI compiler or linker sometimes omits the NN record
+             for a pmisc record.  */
+         if (atn_code == 62)
+           {
+             if (varindx >= info->vars.alloc)
+               {
+                 unsigned int alloc;
+
+                 alloc = info->vars.alloc;
+                 if (alloc == 0)
+                   alloc = 4;
+                 while (varindx >= alloc)
+                   alloc *= 2;
+                 info->vars.vars = ((struct ieee_var *)
+                                    xrealloc (info->vars.vars,
+                                              (alloc
+                                               * sizeof *info->vars.vars)));
+                 memset (info->vars.vars + info->vars.alloc, 0,
+                         ((alloc - info->vars.alloc)
+                          * sizeof *info->vars.vars));
+                 info->vars.alloc = alloc;
+               }
+
+             pvar = info->vars.vars + varindx;
+             pvar->name = "";
+             pvar->namlen = 0;
+           }
+         else
+           {
+             ieee_error (info, atn_start, _("undefined variable in ATN"));
+             return false;
+           }
        }
 
       pvar = info->vars.vars + varindx;
@@ -2082,7 +2230,7 @@ parse_ieee_atn (info, pp)
   switch (atn_code)
     {
     default:
-      ieee_error (info, atn_code_start, "unknown ATN type");
+      ieee_error (info, atn_code_start, _("unknown ATN type"));
       return false;
 
     case 1:
@@ -2185,9 +2333,11 @@ parse_ieee_atn (info, pp)
       return true;
 
     case 10:
-      /* Locked register.  */
+      /* Locked register.  The spec says that there are two required
+         fields, but at least on occasion the MRI compiler only emits
+         one.  */
       if (! ieee_read_number (info, pp, &v)
-         || ! ieee_read_number (info, pp, &v2))
+         || ! ieee_read_optional_number (info, pp, &v2, &present))
        return false;
 
       /* I think this means a variable that is both in a register and
@@ -2202,7 +2352,7 @@ parse_ieee_atn (info, pp)
 
     case 11:
       /* Reserved for FORTRAN common.  */
-      ieee_error (info, atn_code_start, "unsupported ATN11");
+      ieee_error (info, atn_code_start, _("unsupported ATN11"));
 
       /* Return true to keep going.  */
       return true;
@@ -2229,7 +2379,7 @@ parse_ieee_atn (info, pp)
 
       /* We have no way to record this information.  FIXME.  */
 
-      ieee_error (info, atn_code_start, "unsupported ATN12");
+      ieee_error (info, atn_code_start, _("unsupported ATN12"));
 
       /* Return true to keep going.  */
       return true;
@@ -2289,7 +2439,7 @@ parse_ieee_atn (info, pp)
          if (present)
            {
              ieee_error (info, atn_code_start,
-                         "unexpected string in C++ misc");
+                         _("unexpected string in C++ misc"));
              return false;
            }
          return ieee_read_cxx_misc (info, pp, v2);
@@ -2302,7 +2452,7 @@ parse_ieee_atn (info, pp)
          switch ((ieee_record_enum_type) **pp)
            {
            default:
-             ieee_error (info, *pp, "bad misc record");
+             ieee_error (info, *pp, _("bad misc record"));
              return false;
 
            case ieee_at_record_enum:
@@ -2345,7 +2495,7 @@ ieee_read_cxx_misc (info, pp, count)
   switch (category)
     {
     default:
-      ieee_error (info, start, "unrecognized C++ misc record");
+      ieee_error (info, start, _("unrecognized C++ misc record"));
       return false;
 
     case 'T':
@@ -2462,7 +2612,7 @@ ieee_read_cxx_class (info, pp, count)
       break;
   if (it == NULL)
     {
-      ieee_error (info, start, "undefined C++ object");
+      ieee_error (info, start, _("undefined C++ object"));
       return false;
     }
 
@@ -2496,7 +2646,7 @@ ieee_read_cxx_class (info, pp, count)
       switch (id)
        {
        default:
-         ieee_error (info, spec_start, "unrecognized C++ object spec");
+         ieee_error (info, spec_start, _("unrecognized C++ object spec"));
          return false;
 
        case 'b':
@@ -2532,7 +2682,7 @@ ieee_read_cxx_class (info, pp, count)
 
            if ((fieldlen == 0) == (cinline == 0))
              {
-               ieee_error (info, start, "unsupported C++ object type");
+               ieee_error (info, start, _("unsupported C++ object type"));
                return false;
              }
 
@@ -2542,7 +2692,7 @@ ieee_read_cxx_class (info, pp, count)
            free (basecopy);
            if (basetype == DEBUG_TYPE_NULL)
              {
-               ieee_error (info, start, "C++ base class not defined");
+               ieee_error (info, start, _("C++ base class not defined"));
                return false;
              }
 
@@ -2554,7 +2704,7 @@ ieee_read_cxx_class (info, pp, count)
 
                if (structfields == NULL)
                  {
-                   ieee_error (info, start, "C++ object has no fields");
+                   ieee_error (info, start, _("C++ object has no fields"));
                    return false;
                  }
 
@@ -2573,7 +2723,7 @@ ieee_read_cxx_class (info, pp, count)
                if (*pf == DEBUG_FIELD_NULL)
                  {
                    ieee_error (info, start,
-                               "C++ base class not found in container");
+                               _("C++ base class not found in container"));
                    return false;
                  }
 
@@ -2617,7 +2767,7 @@ ieee_read_cxx_class (info, pp, count)
            char *fieldcopy;
            boolean staticp;
            debug_type ftype;
-           const debug_field *pf;
+           const debug_field *pf = NULL;
            enum debug_visibility visibility;
            debug_field field;
 
@@ -2659,7 +2809,7 @@ ieee_read_cxx_class (info, pp, count)
 
                if (structfields == NULL)
                  {
-                   ieee_error (info, start, "C++ object has no fields");
+                   ieee_error (info, start, _("C++ object has no fields"));
                    return false;
                  }
 
@@ -2680,7 +2830,7 @@ ieee_read_cxx_class (info, pp, count)
                if (*pf == DEBUG_FIELD_NULL)
                  {
                    ieee_error (info, start,
-                               "C++ data member not found in container");
+                               _("C++ data member not found in container"));
                    return false;
                  }
 
@@ -2721,7 +2871,7 @@ ieee_read_cxx_class (info, pp, count)
            switch (flags & CXXFLAGS_VISIBILITY)
              {
              default:
-               ieee_error (info, start, "unknown C++ visibility");
+               ieee_error (info, start, _("unknown C++ visibility"));
                return false;
 
              case CXXFLAGS_VISIBILITY_PUBLIC:
@@ -2755,7 +2905,7 @@ ieee_read_cxx_class (info, pp, count)
                bitsize = debug_get_field_bitsize (dhandle, *pf);
                if (bitpos == (bfd_vma) -1 || bitsize == (bfd_vma) -1)
                  {
-                   ieee_error (info, start, "bad C++ field bit pos or size");
+                   ieee_error (info, start, _("bad C++ field bit pos or size"));
                    return false;
                  }
                field = debug_make_field (dhandle, fieldcopy, ftype, bitpos,
@@ -2781,7 +2931,7 @@ ieee_read_cxx_class (info, pp, count)
        case 'm':
        case 'v':
          {
-           bfd_vma flags, virtindex, control;
+           bfd_vma flags, voffset, control;
            const char *name, *mangled;
            unsigned long namlen, mangledlen;
            struct ieee_var *pv, *pvend;
@@ -2798,9 +2948,11 @@ ieee_read_cxx_class (info, pp, count)
                || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen))
              return false;
            count -= 3;
-           if (id == 'v')
+           if (id != 'v')
+             voffset = 0;
+           else
              {
-               if (! ieee_require_asn (info, pp, &virtindex))
+               if (! ieee_require_asn (info, pp, &voffset))
                  return false;
                --count;
              }
@@ -2845,7 +2997,7 @@ ieee_read_cxx_class (info, pp, count)
                    != DEBUG_KIND_FUNCTION)
                  {
                    ieee_error (info, start,
-                               "bad type for C++ method function");
+                               _("bad type for C++ method function"));
                    return false;
                  }
 
@@ -2855,7 +3007,7 @@ ieee_read_cxx_class (info, pp, count)
                if (return_type == DEBUG_TYPE_NULL || arg_types == NULL)
                  {
                    ieee_error (info, start,
-                               "no type information for C++ method function");
+                               _("no type information for C++ method function"));
                    return false;
                  }
 
@@ -2869,7 +3021,7 @@ ieee_read_cxx_class (info, pp, count)
            switch (flags & CXXFLAGS_VISIBILITY)
              {
              default:
-               ieee_error (info, start, "unknown C++ visibility");
+               ieee_error (info, start, _("unknown C++ visibility"));
                return false;
 
              case CXXFLAGS_VISIBILITY_PUBLIC:
@@ -2894,7 +3046,7 @@ ieee_read_cxx_class (info, pp, count)
              {
                if (id == 'v')
                  {
-                   ieee_error (info, start, "C++ static virtual method");
+                   ieee_error (info, start, _("C++ static virtual method"));
                    return false;
                  }
                mv = debug_make_static_method_variant (dhandle, mangledcopy,
@@ -2903,19 +3055,12 @@ ieee_read_cxx_class (info, pp, count)
              }
            else
              {
-               bfd_vma voffset;
                debug_type vcontext;
 
                if (id != 'v')
-                 {
-                   voffset = 0;
-                   vcontext = DEBUG_TYPE_NULL;
-                 }
+                 vcontext = DEBUG_TYPE_NULL;
                else
                  {
-                   /* FIXME: This should depend upon the pointer
-                       size.  */
-                   voffset = virtindex * 4;
                    /* FIXME: How can we calculate this correctly?  */
                    vcontext = it->type;
                  }
@@ -2996,7 +3141,7 @@ ieee_read_cxx_class (info, pp, count)
            else
              {
                ieee_error (info, start,
-                           "unrecognized C++ object overhead spec");
+                           _("unrecognized C++ object overhead spec"));
                return false;
              }
          }
@@ -3035,7 +3180,7 @@ ieee_read_cxx_class (info, pp, count)
                free (basecopy);
                if (vptrbase == DEBUG_TYPE_NULL)
                  {
-                   ieee_error (info, start, "undefined C++ vtable");
+                   ieee_error (info, start, _("undefined C++ vtable"));
                    return false;
                  }
              }
@@ -3106,7 +3251,7 @@ ieee_read_cxx_defaults (info, pp, count)
   if (info->blockstack.bsp <= info->blockstack.stack
       || info->blockstack.bsp[-1].fnindx == (unsigned int) -1)
     {
-      ieee_error (info, start, "C++ default values not in a function");
+      ieee_error (info, start, _("C++ default values not in a function"));
       return false;
     }
 
@@ -3146,7 +3291,7 @@ ieee_read_cxx_defaults (info, pp, count)
          break;
 
        default:
-         ieee_error (info, start, "unrecognized C++ default type");
+         ieee_error (info, start, _("unrecognized C++ default type"));
          return false;
        }
 
@@ -3177,7 +3322,7 @@ ieee_read_cxx_defaults (info, pp, count)
              || (debug_get_type_kind (dhandle, arg_slots[indx])
                  != DEBUG_KIND_POINTER))
            {
-             ieee_error (info, start, "reference parameter is not a pointer");
+             ieee_error (info, start, _("reference parameter is not a pointer"));
              return false;
            }
 
@@ -3224,60 +3369,79 @@ ieee_read_reference (info, pp)
   pslot = NULL;
   if (flags != 3)
     {
-      int i;
-      struct ieee_var *pv = NULL;
+      int pass;
 
       /* We search from the last variable indices to the first in
-        hopes of finding local variables correctly.  FIXME: This
-        probably won't work in all cases.  On the other hand, I don't
-        know what will.  */
-      for (i = (int) info->vars.alloc - 1; i >= 0; i--)
+        hopes of finding local variables correctly.  We search the
+        local variables on the first pass, and the global variables
+        on the second.  FIXME: This probably won't work in all cases.
+        On the other hand, I don't know what will.  */
+      for (pass = 0; pass < 2; pass++)
        {
-         boolean found;
+         struct ieee_vars *vars;
+         int i;
+         struct ieee_var *pv = NULL;
 
-         pv = info->vars.vars + i;
-
-         if (pv->pslot == NULL
-             || pv->namlen != namlen
-             || strncmp (pv->name, name, namlen) != 0)
-           continue;
+         if (pass == 0)
+           vars = &info->vars;
+         else
+           {
+             vars = info->global_vars;
+             if (vars == NULL)
+               break;
+           }
 
-         found = false;
-         switch (flags)
+         for (i = (int) vars->alloc - 1; i >= 0; i--)
            {
-           default:
-             ieee_error (info, start,
-                         "unrecognized C++ reference type");
-             return false;
+             boolean found;
 
-           case 0:
-             /* Global variable or function.  */
-             if (pv->kind == IEEE_GLOBAL
-                 || pv->kind == IEEE_EXTERNAL
-                 || pv->kind == IEEE_FUNCTION)
-               found = true;
-             break;
+             pv = vars->vars + i;
 
-           case 1:
-             /* Global static variable or function.  */
-             if (pv->kind == IEEE_STATIC
-                 || pv->kind == IEEE_FUNCTION)
-               found = true;
-             break;
+             if (pv->pslot == NULL
+                 || pv->namlen != namlen
+                 || strncmp (pv->name, name, namlen) != 0)
+               continue;
 
-           case 2:
-             /* Local variable.  */
-             if (pv->kind == IEEE_LOCAL)
-               found = true;
-             break;
+             found = false;
+             switch (flags)
+               {
+               default:
+                 ieee_error (info, start,
+                             _("unrecognized C++ reference type"));
+                 return false;
+
+               case 0:
+                 /* Global variable or function.  */
+                 if (pv->kind == IEEE_GLOBAL
+                     || pv->kind == IEEE_EXTERNAL
+                     || pv->kind == IEEE_FUNCTION)
+                   found = true;
+                 break;
+
+               case 1:
+                 /* Global static variable or function.  */
+                 if (pv->kind == IEEE_STATIC
+                     || pv->kind == IEEE_FUNCTION)
+                   found = true;
+                 break;
+
+               case 2:
+                 /* Local variable.  */
+                 if (pv->kind == IEEE_LOCAL)
+                   found = true;
+                 break;
+               }
+
+             if (found)
+               break;
            }
 
-         if (found)
-           break;
+         if (i >= 0)
+           {
+             pslot = pv->pslot;
+             break;
+           }
        }
-
-      if (i >= 0)
-       pslot = pv->pslot;
     }
   else
     {
@@ -3325,7 +3489,7 @@ ieee_read_reference (info, pp)
 
   if (pslot == NULL)
     {
-      ieee_error (info, start, "C++ reference not found");
+      ieee_error (info, start, _("C++ reference not found"));
       return false;
     }
 
@@ -3333,7 +3497,7 @@ ieee_read_reference (info, pp)
      to *pslot, which we can now update to be a reference type.  */
   if (debug_get_type_kind (info->dhandle, *pslot) != DEBUG_KIND_POINTER)
     {
-      ieee_error (info, start, "C++ reference is not pointer");
+      ieee_error (info, start, _("C++ reference is not pointer"));
       return false;
     }
 
@@ -3362,7 +3526,7 @@ ieee_require_asn (info, pp, pv)
   c = (ieee_record_enum_type) **pp;
   if (c != ieee_e2_first_byte_enum)
     {
-      ieee_error (info, start, "missing required ASN");
+      ieee_error (info, start, _("missing required ASN"));
       return false;
     }
   ++*pp;
@@ -3370,7 +3534,7 @@ ieee_require_asn (info, pp, pv)
   c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
   if (c != ieee_asn_record_enum)
     {
-      ieee_error (info, start, "missing required ASN");
+      ieee_error (info, start, _("missing required ASN"));
       return false;
     }
   ++*pp;
@@ -3400,7 +3564,7 @@ ieee_require_atn65 (info, pp, pname, pnamlen)
   c = (ieee_record_enum_type) **pp;
   if (c != ieee_at_record_enum)
     {
-      ieee_error (info, start, "missing required ATN65");
+      ieee_error (info, start, _("missing required ATN65"));
       return false;
     }
   ++*pp;
@@ -3408,7 +3572,7 @@ ieee_require_atn65 (info, pp, pname, pnamlen)
   c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp);
   if (c != ieee_atn_record_enum)
     {
-      ieee_error (info, start, "missing required ATN65");
+      ieee_error (info, start, _("missing required ATN65"));
       return false;
     }
   ++*pp;
@@ -3422,7 +3586,7 @@ ieee_require_atn65 (info, pp, pname, pnamlen)
 
   if (type_indx != 0 || atn_code != 65)
     {
-      ieee_error (info, start, "bad ATN65 record");
+      ieee_error (info, start, _("bad ATN65 record"));
       return false;
     }
 
@@ -3437,6 +3601,25 @@ ieee_regno_to_genreg (abfd, r)
      bfd *abfd;
      int r;
 {
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_m68k:
+      /* For some reasons stabs adds 2 to the floating point register
+         numbers.  */
+      if (r >= 16)
+       r += 2;
+      break;
+
+    case bfd_arch_i960:
+      /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
+         32 to 35 for fp0 to fp3.  */
+      --r;
+      break;
+
+    default:
+      break;
+    }
+
   return r;
 }
 
@@ -3447,6 +3630,25 @@ ieee_genreg_to_regno (abfd, r)
      bfd *abfd;
      int r;
 {
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_m68k:
+      /* For some reason stabs add 2 to the floating point register
+         numbers.  */
+      if (r >= 18)
+       r -= 2;
+      break;
+
+    case bfd_arch_i960:
+      /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and
+         32 to 35 for fp0 to fp3.  */
+      ++r;
+      break;
+
+    default:
+      break;
+    }
+
   return r;
 }
 \f
@@ -3469,6 +3671,16 @@ struct ieee_buf
   bfd_byte buf[IEEE_BUFSIZE];
 };
 
+/* A list of buffers.  */
+
+struct ieee_buflist
+{
+  /* Head of list.  */
+  struct ieee_buf *head;
+  /* Tail--last buffer on list.  */
+  struct ieee_buf *tail;
+};
+
 /* In order to generate the BB11 blocks required by the HP emulator,
    we keep track of ranges of addresses which correspond to a given
    compilation unit.  */
@@ -3487,12 +3699,10 @@ struct ieee_range
 
 struct ieee_type_class
 {
-  /* The name of the class.  */
-  const char *name;
   /* The name index in the debugging information.  */
   unsigned int indx;
   /* The pmisc records for the class.  */
-  struct ieee_buf *pmiscbuf;
+  struct ieee_buflist pmiscbuf;
   /* The number of pmisc records.  */
   unsigned int pmisccount;
   /* The name of the class holding the virtual table, if not this
@@ -3505,7 +3715,7 @@ struct ieee_type_class
   /* The current method.  */
   const char *method;
   /* Additional pmisc records used to record fields of reference type.  */
-  struct ieee_buf *refs;
+  struct ieee_buflist refs;
 };
 
 /* This is how we store types for the writing routines.  Most types
@@ -3517,18 +3727,25 @@ struct ieee_write_type
   unsigned int indx;
   /* The size of the type, if known.  */
   unsigned int size;
+  /* The name of the type, if any.  */
+  const char *name;
   /* If this is a function or method type, we build the type here, and
      only add it to the output buffers if we need it.  */
-  struct ieee_buf *fndef;
+  struct ieee_buflist fndef;
   /* If this is a struct, this is where the struct definition is
      built.  */
-  struct ieee_buf *strdef;
+  struct ieee_buflist strdef;
   /* If this is a class, this is where the class information is built.  */
   struct ieee_type_class *classdef;
   /* Whether the type is unsigned.  */
   unsigned int unsignedp : 1;
   /* Whether this is a reference type.  */
   unsigned int referencep : 1;
+  /* Whether this is in the local type block.  */
+  unsigned int localp : 1;
+  /* Whether this is a duplicate struct definition which we are
+     ignoring.  */
+  unsigned int ignorep : 1;
 };
 
 /* This is the type stack used by the debug writing routines.  FIXME:
@@ -3543,15 +3760,16 @@ struct ieee_type_stack
   struct ieee_write_type type;
 };
 
-/* This is a list of associations between names and types.  This could
-   be more efficiently implemented as a hash table.  */
+/* This is a list of associations between a name and some types.
+   These are used for typedefs and tags.  */
 
 struct ieee_name_type
 {
-  /* Next name/type assocation.  */
+  /* Next type for this name.  */
   struct ieee_name_type *next;
-  /* Name.  */
-  const char *name;
+  /* ID number.  For a typedef, this is the index of the type to which
+     this name is typedefed.  */
+  unsigned int id;
   /* Type.  */
   struct ieee_write_type type;
   /* If this is a tag which has not yet been defined, this is the
@@ -3559,6 +3777,38 @@ struct ieee_name_type
   enum debug_type_kind kind;
 };
 
+/* We use a hash table to associate names and types.  */
+
+struct ieee_name_type_hash_table
+{
+  struct bfd_hash_table root;
+};
+
+struct ieee_name_type_hash_entry
+{
+  struct bfd_hash_entry root;
+  /* Information for this name.  */
+  struct ieee_name_type *types;
+};
+
+/* This is a list of enums.  */
+
+struct ieee_defined_enum
+{
+  /* Next enum.  */
+  struct ieee_defined_enum *next;
+  /* Type index.  */
+  unsigned int indx;
+  /* Whether this enum has been defined.  */
+  boolean defined;
+  /* Tag.  */
+  const char *tag;
+  /* Names.  */
+  const char **names;
+  /* Values.  */
+  bfd_signed_vma *vals;
+};
+
 /* We keep a list of modified versions of types, so that we don't
    output them more than once.  */
 
@@ -3566,10 +3816,28 @@ struct ieee_modified_type
 {
   /* Pointer to this type.  */
   unsigned int pointer;
+  /* Function with unknown arguments returning this type.  */
+  unsigned int function;
   /* Const version of this type.  */
   unsigned int const_qualified;
   /* Volatile version of this type.  */
   unsigned int volatile_qualified;
+  /* List of arrays of this type of various bounds.  */
+  struct ieee_modified_array_type *arrays;
+};
+
+/* A list of arrays bounds.  */
+
+struct ieee_modified_array_type
+{
+  /* Next array bounds.  */
+  struct ieee_modified_array_type *next;
+  /* Type index with these bounds.  */
+  unsigned int indx;
+  /* Low bound.  */
+  bfd_signed_vma low;
+  /* High bound.  */
+  bfd_signed_vma high;
 };
 
 /* This is a list of pending function parameter information.  We don't
@@ -3597,26 +3865,35 @@ struct ieee_handle
 {
   /* BFD we are writing to.  */
   bfd *abfd;
+  /* Whether we got an error in a subroutine called via traverse or
+     map_over_sections.  */
+  boolean error;
+  /* Current data buffer list.  */
+  struct ieee_buflist *current;
   /* Current data buffer.  */
-  struct ieee_buf *current;
+  struct ieee_buf *curbuf;
   /* Filename of current compilation unit.  */
   const char *filename;
   /* Module name of current compilation unit.  */
   const char *modname;
+  /* List of buffer for global types.  */
+  struct ieee_buflist global_types;
   /* List of finished data buffers.  */
-  struct ieee_buf *data;
+  struct ieee_buflist data;
   /* List of buffers for typedefs in the current compilation unit.  */
-  struct ieee_buf *types;
+  struct ieee_buflist types;
   /* List of buffers for variables and functions in the current
      compilation unit.  */
-  struct ieee_buf *vars;
+  struct ieee_buflist vars;
   /* List of buffers for C++ class definitions in the current
      compilation unit.  */
-  struct ieee_buf *cxx;
+  struct ieee_buflist cxx;
   /* List of buffers for line numbers in the current compilation unit.  */
-  struct ieee_buf *linenos;
+  struct ieee_buflist linenos;
   /* Ranges for the current compilation unit.  */
   struct ieee_range *ranges;
+  /* Ranges for all debugging information.  */
+  struct ieee_range *global_ranges;
   /* Nested pending ranges.  */
   struct ieee_range *pending_ranges;
   /* Type stack.  */
@@ -3626,13 +3903,19 @@ struct ieee_handle
   /* Next unallocated name index.  */
   unsigned int name_indx;
   /* Typedefs.  */
-  struct ieee_name_type *typedefs;
+  struct ieee_name_type_hash_table typedefs;
   /* Tags.  */
-  struct ieee_name_type *tags;
+  struct ieee_name_type_hash_table tags;
+  /* Enums.  */
+  struct ieee_defined_enum *enums;
   /* Modified versions of types.  */
   struct ieee_modified_type *modified;
   /* Number of entries allocated in modified.  */
   unsigned int modified_alloc;
+  /* 4 byte complex type.  */
+  unsigned int complex_float_index;
+  /* 8 byte complex type.  */
+  unsigned int complex_double_index;
   /* The depth of block nesting.  This is 0 outside a function, and 1
      just after start_function is called.  */
   unsigned int block_depth;
@@ -3640,10 +3923,10 @@ struct ieee_handle
   const char *fnname;
   /* List of buffers for the type of the function we are currently
      writing out.  */
-  struct ieee_buf *fntype;
+  struct ieee_buflist fntype;
   /* List of buffers for the parameters of the function we are
      currently writing out.  */
-  struct ieee_buf *fnargs;
+  struct ieee_buflist fnargs;
   /* Number of arguments written to fnargs.  */
   unsigned int fnargcount;
   /* Pending function parameters.  */
@@ -3652,12 +3935,23 @@ struct ieee_handle
   const char *lineno_filename;
   /* Line number name index.  */
   unsigned int lineno_name_indx;
+  /* Filename of pending line number.  */
+  const char *pending_lineno_filename;
+  /* Pending line number.  */
+  unsigned long pending_lineno;
+  /* Address of pending line number.  */
+  bfd_vma pending_lineno_addr;
   /* Highest address seen at end of procedure.  */
   bfd_vma highaddr;
 };
 
+static boolean ieee_init_buffer
+  PARAMS ((struct ieee_handle *, struct ieee_buflist *));
 static boolean ieee_change_buffer
-  PARAMS ((struct ieee_handle *, struct ieee_buf **));
+  PARAMS ((struct ieee_handle *, struct ieee_buflist *));
+static boolean ieee_append_buffer
+  PARAMS ((struct ieee_handle *, struct ieee_buflist *,
+          struct ieee_buflist *));
 static boolean ieee_real_write_byte PARAMS ((struct ieee_handle *, int));
 static boolean ieee_write_2bytes PARAMS ((struct ieee_handle *, int));
 static boolean ieee_write_number PARAMS ((struct ieee_handle *, bfd_vma));
@@ -3667,23 +3961,31 @@ static boolean ieee_write_asn
 static boolean ieee_write_atn65
   PARAMS ((struct ieee_handle *, unsigned int, const char *));
 static boolean ieee_push_type
-  PARAMS ((struct ieee_handle *, unsigned int, unsigned int, boolean));
+  PARAMS ((struct ieee_handle *, unsigned int, unsigned int, boolean,
+          boolean));
 static unsigned int ieee_pop_type PARAMS ((struct ieee_handle *));
 static void ieee_pop_unused_type PARAMS ((struct ieee_handle *));
 static unsigned int ieee_pop_type_used
   PARAMS ((struct ieee_handle *, boolean));
 static boolean ieee_add_range
-  PARAMS ((struct ieee_handle *, bfd_vma, bfd_vma));
+  PARAMS ((struct ieee_handle *, boolean, bfd_vma, bfd_vma));
 static boolean ieee_start_range PARAMS ((struct ieee_handle *, bfd_vma));
 static boolean ieee_end_range PARAMS ((struct ieee_handle *, bfd_vma));
 static boolean ieee_define_type
-  PARAMS ((struct ieee_handle *, unsigned int, boolean));
+  PARAMS ((struct ieee_handle *, unsigned int, boolean, boolean));
 static boolean ieee_define_named_type
-  PARAMS ((struct ieee_handle *, const char *, boolean, unsigned int,
-          unsigned int, boolean, struct ieee_buf **));
+  PARAMS ((struct ieee_handle *, const char *, unsigned int, unsigned int,
+          boolean, boolean, struct ieee_buflist *));
 static struct ieee_modified_type *ieee_get_modified_info
   PARAMS ((struct ieee_handle *, unsigned int));
+static struct bfd_hash_entry *ieee_name_type_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean ieee_write_undefined_tag
+  PARAMS ((struct ieee_name_type_hash_entry *, PTR));
 static boolean ieee_finish_compilation_unit PARAMS ((struct ieee_handle *));
+static void ieee_add_bb11_blocks PARAMS ((bfd *, asection *, PTR));
+static boolean ieee_add_bb11
+  PARAMS ((struct ieee_handle *, asection *, bfd_vma, bfd_vma));
 static boolean ieee_output_pending_parms PARAMS ((struct ieee_handle *));
 static unsigned int ieee_vis_to_flags PARAMS ((enum debug_visibility));
 static boolean ieee_class_method_var
@@ -3798,29 +4100,64 @@ static const struct debug_write_fns ieee_fns =
   ieee_lineno
 };
 
+/* Initialize a buffer to be empty.  */
+
+/*ARGSUSED*/
+static boolean
+ieee_init_buffer (info, buflist)
+     struct ieee_handle *info ATTRIBUTE_UNUSED;
+     struct ieee_buflist *buflist;
+{
+  buflist->head = NULL;
+  buflist->tail = NULL;
+  return true;
+}
+
+/* See whether a buffer list has any data.  */
+
+#define ieee_buffer_emptyp(buflist) ((buflist)->head == NULL)
+
 /* Change the current buffer to a specified buffer chain.  */
 
 static boolean
-ieee_change_buffer (info, ppbuf)
+ieee_change_buffer (info, buflist)
      struct ieee_handle *info;
-     struct ieee_buf **ppbuf;
+     struct ieee_buflist *buflist;
 {
-  struct ieee_buf *buf;
-
-  if (*ppbuf != NULL)
-    {
-      for (buf = *ppbuf; buf->next != NULL; buf = buf->next)
-       ;
-    }
-  else
+  if (buflist->head == NULL)
     {
+      struct ieee_buf *buf;
+
       buf = (struct ieee_buf *) xmalloc (sizeof *buf);
       buf->next = NULL;
       buf->c = 0;
-      *ppbuf = buf;
+      buflist->head = buf;
+      buflist->tail = buf;
     }
 
-  info->current = buf;
+  info->current = buflist;
+  info->curbuf = buflist->tail;
+
+  return true;
+}
+
+/* Append a buffer chain.  */
+
+/*ARGSUSED*/
+static boolean
+ieee_append_buffer (info, mainbuf, newbuf)
+     struct ieee_handle *info ATTRIBUTE_UNUSED;
+     struct ieee_buflist *mainbuf;
+     struct ieee_buflist *newbuf;
+{
+  if (newbuf->head != NULL)
+    {
+      if (mainbuf->head == NULL)
+       mainbuf->head = newbuf->head;
+      else
+       mainbuf->tail->next = newbuf->head;
+      mainbuf->tail = newbuf->tail;
+    }
   return true;
 }
 
@@ -3828,8 +4165,8 @@ ieee_change_buffer (info, ppbuf)
    function for the complex cases.  */
 
 #define ieee_write_byte(info, b)                               \
-  ((info)->current->c < IEEE_BUFSIZE                           \
-   ? ((info)->current->buf[(info)->current->c++] = (b), true)  \
+  ((info)->curbuf->c < IEEE_BUFSIZE                            \
+   ? ((info)->curbuf->buf[(info)->curbuf->c++] = (b), true)    \
    : ieee_real_write_byte ((info), (b)))
 
 static boolean
@@ -3837,19 +4174,23 @@ ieee_real_write_byte (info, b)
      struct ieee_handle *info;
      int b;
 {
-  if (info->current->c >= IEEE_BUFSIZE)
+  if (info->curbuf->c >= IEEE_BUFSIZE)
     {
       struct ieee_buf *n;
 
       n = (struct ieee_buf *) xmalloc (sizeof *n);
       n->next = NULL;
       n->c = 0;
-      info->current->next = n;
-      info->current = n;
+      if (info->current->head == NULL)
+       info->current->head = n;
+      else
+       info->current->tail->next = n;
+      info->current->tail = n;
+      info->curbuf = n;
     }
 
-  info->current->buf[info->current->c] = b;
-  ++info->current->c;
+  info->curbuf->buf[info->curbuf->c] = b;
+  ++info->curbuf->c;
 
   return true;
 }
@@ -3892,7 +4233,7 @@ ieee_write_number (info, v)
   if (c > (unsigned int) (ieee_number_repeat_end_enum
                          - ieee_number_repeat_start_enum))
     {
-      fprintf (stderr, "IEEE numeric overflow: 0x");
+      fprintf (stderr, _("IEEE numeric overflow: 0x"));
       fprintf_vma (stderr, v);
       fprintf (stderr, "\n");
       return false;
@@ -3938,7 +4279,7 @@ ieee_write_id (info, s)
     }
   else
     {
-      fprintf (stderr, "IEEE string length overflow: %u\n", len);
+      fprintf (stderr, _("IEEE string length overflow: %u\n"), len);
       return false;
     }
 
@@ -3980,11 +4321,12 @@ ieee_write_atn65 (info, indx, s)
 /* Push a type index onto the type stack.  */
 
 static boolean
-ieee_push_type (info, indx, size, unsignedp)
+ieee_push_type (info, indx, size, unsignedp, localp)
      struct ieee_handle *info;
      unsigned int indx;
      unsigned int size;
      boolean unsignedp;
+     boolean localp;
 {
   struct ieee_type_stack *ts;
 
@@ -3994,6 +4336,7 @@ ieee_push_type (info, indx, size, unsignedp)
   ts->type.indx = indx;
   ts->type.size = size;
   ts->type.unsignedp = unsignedp;
+  ts->type.localp = localp;
 
   ts->next = info->type_stack;
   info->type_stack = ts;
@@ -4034,24 +4377,41 @@ ieee_pop_type_used (info, used)
 
   /* If this is a function type, and we need it, we need to append the
      actual definition to the typedef block now.  */
-  if (ts->type.fndef != NULL && used)
+  if (used && ! ieee_buffer_emptyp (&ts->type.fndef))
     {
-      struct ieee_buf **pb;
+      struct ieee_buflist *buflist;
 
-      /* Make sure we have started the types block.  */
-      if (info->types == NULL)
+      if (ts->type.localp)
        {
-         if (! ieee_change_buffer (info, &info->types)
-             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-             || ! ieee_write_byte (info, 1)
-             || ! ieee_write_number (info, 0)
-             || ! ieee_write_id (info, info->modname))
-           return false;
+         /* Make sure we have started the types block.  */
+         if (ieee_buffer_emptyp (&info->types))
+           {
+             if (! ieee_change_buffer (info, &info->types)
+                 || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+                 || ! ieee_write_byte (info, 1)
+                 || ! ieee_write_number (info, 0)
+                 || ! ieee_write_id (info, info->modname))
+               return false;
+           }
+         buflist = &info->types;
+       }
+      else
+       {
+         /* Make sure we started the global type block.  */
+         if (ieee_buffer_emptyp (&info->global_types))
+           {
+             if (! ieee_change_buffer (info, &info->global_types)
+                 || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+                 || ! ieee_write_byte (info, 2)
+                 || ! ieee_write_number (info, 0)
+                 || ! ieee_write_id (info, ""))
+               return false;
+           }
+         buflist = &info->global_types;
        }
 
-      for (pb = &info->types; *pb != NULL; pb = &(*pb)->next)
-       ;
-      *pb = ts->type.fndef;
+      if (! ieee_append_buffer (info, buflist, &ts->type.fndef))
+       return false;
     }
 
   ret = ts->type.indx;
@@ -4063,17 +4423,23 @@ ieee_pop_type_used (info, used)
 /* Add a range of bytes included in the current compilation unit.  */
 
 static boolean
-ieee_add_range (info, low, high)
+ieee_add_range (info, global, low, high)
      struct ieee_handle *info;
+     boolean global;
      bfd_vma low;
      bfd_vma high;
 {
-  struct ieee_range *r, **pr;
+  struct ieee_range **plist, *r, **pr;
 
-  if (low == (bfd_vma) -1 || high == (bfd_vma) -1)
+  if (low == (bfd_vma) -1 || high == (bfd_vma) -1 || low == high)
     return true;
 
-  for (r = info->ranges; r != NULL; r = r->next)
+  if (global)
+    plist = &info->global_ranges;
+  else
+    plist = &info->ranges;
+
+  for (r = *plist; r != NULL; r = r->next)
     {
       if (high >= r->low && low <= r->high)
        {
@@ -4104,8 +4470,8 @@ ieee_add_range (info, low, high)
   r->high = high;
 
   /* Store the ranges sorted by address.  */
-  for (pr = &info->ranges; *pr != NULL; pr = &(*pr)->next)
-    if ((*pr)->next != NULL && (*pr)->next->low > high)
+  for (pr = plist; *pr != NULL; pr = &(*pr)->next)
+    if ((*pr)->low > high)
       break;
   r->next = *pr;
   *pr = r;
@@ -4128,7 +4494,7 @@ ieee_start_range (info, low)
   r->next = info->pending_ranges;
   info->pending_ranges = r;
   return true;
-}  
+}
 
 /* Finish a range started by ieee_start_range.  */
 
@@ -4145,84 +4511,45 @@ ieee_end_range (info, high)
   low = r->low;
   info->pending_ranges = r->next;
   free (r);
-  return ieee_add_range (info, low, high);
+  return ieee_add_range (info, false, low, high);
 }
 
 /* Start defining a type.  */
 
 static boolean
-ieee_define_type (info, size, unsignedp)
+ieee_define_type (info, size, unsignedp, localp)
      struct ieee_handle *info;
      unsigned int size;
      boolean unsignedp;
+     boolean localp;
 {
-  return ieee_define_named_type (info, (const char *) NULL, false, 0, size,
-                                unsignedp, (struct ieee_buf **) NULL);
+  return ieee_define_named_type (info, (const char *) NULL,
+                                (unsigned int) -1, size, unsignedp,
+                                localp, (struct ieee_buflist *) NULL);
 }
 
 /* Start defining a named type.  */
 
 static boolean
-ieee_define_named_type (info, name, tagp, id, size, unsignedp, ppbuf)
+ieee_define_named_type (info, name, indx, size, unsignedp, localp, buflist)
      struct ieee_handle *info;
      const char *name;
-     boolean tagp;
-     unsigned int id;
+     unsigned int indx;
      unsigned int size;
      boolean unsignedp;
-     struct ieee_buf **ppbuf;
+     boolean localp;
+     struct ieee_buflist *buflist;
 {
   unsigned int type_indx;
   unsigned int name_indx;
 
-  if (! tagp || id == (unsigned int) -1)
+  if (indx != (unsigned int) -1)
+    type_indx = indx;
+  else
     {
       type_indx = info->type_indx;
       ++info->type_indx;
     }
-  else
-    {
-      struct ieee_name_type *nt;
-      const char *tag;
-      char ab[20];
-
-      /* We need to create a tag for internal use even if we don't
-         want one for external use.  This will let us refer to an
-         anonymous struct.  */
-      if (name != NULL)
-       tag = name;
-      else
-       {
-         sprintf (ab, "__anon%u", id);
-         tag = ab;
-       }
-
-      /* The name is a tag.  If we have already defined the tag, we
-         must use the existing type index.  */
-      for (nt = info->tags; nt != NULL; nt = nt->next)
-       if (nt->name[0] == tag[0]
-           && strcmp (nt->name, tag) == 0)
-         break;
-
-      if (nt == NULL)
-       {
-         nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
-         memset (nt, 0, sizeof *nt);
-         if (tag != name)
-           tag = xstrdup (ab);
-         nt->name = tag;
-         nt->next = info->tags;
-         info->tags = nt;
-         nt->type.indx = info->type_indx;
-         ++info->type_indx;
-       }
-
-      nt->type.size = size;
-      nt->type.unsignedp = unsignedp;
-      nt->kind = DEBUG_KIND_ILLEGAL;
-
-      type_indx = nt->type.indx;
-    }
 
   name_indx = info->name_indx;
   ++info->name_indx;
@@ -4230,33 +4557,56 @@ ieee_define_named_type (info, name, tagp, id, size, unsignedp, ppbuf)
   if (name == NULL)
     name = "";
 
-  /* If we were given a buffer, use it; otherwise, use the general
-     type information, and make sure that the type block is started.  */
-  if (ppbuf != NULL)
+  /* If we were given a buffer, use it; otherwise, use either the
+     local or the global type information, and make sure that the type
+     block is started.  */
+  if (buflist != NULL)
     {
-      if (! ieee_change_buffer (info, ppbuf))
+      if (! ieee_change_buffer (info, buflist))
        return false;
     }
-  else if (info->types != NULL)
+  else if (localp)
     {
-      if (! ieee_change_buffer (info, &info->types))
-       return false;
+      if (! ieee_buffer_emptyp (&info->types))
+       {
+         if (! ieee_change_buffer (info, &info->types))
+           return false;
+       }
+      else
+       {
+         if (! ieee_change_buffer (info, &info->types)
+             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+             || ! ieee_write_byte (info, 1)
+             || ! ieee_write_number (info, 0)
+             || ! ieee_write_id (info, info->modname))
+           return false;
+       }
     }
   else
     {
-      if (! ieee_change_buffer (info, &info->types)
-         || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-         || ! ieee_write_byte (info, 1)
-         || ! ieee_write_number (info, 0)
-         || ! ieee_write_id (info, info->modname))
-       return false;
+      if (! ieee_buffer_emptyp (&info->global_types))
+       {
+         if (! ieee_change_buffer (info, &info->global_types))
+           return false;
+       }
+      else
+       {
+         if (! ieee_change_buffer (info, &info->global_types)
+             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+             || ! ieee_write_byte (info, 2)
+             || ! ieee_write_number (info, 0)
+             || ! ieee_write_id (info, ""))
+           return false;
+       }
     }
 
   /* Push the new type on the type stack, write out an NN record, and
      write out the start of a TY record.  The caller will then finish
      the TY record.  */
-  return (ieee_push_type (info, type_indx, size, unsignedp)
-         && ieee_write_byte (info, (int) ieee_nn_record)
+  if (! ieee_push_type (info, type_indx, size, unsignedp, localp))
+    return false;
+
+  return (ieee_write_byte (info, (int) ieee_nn_record)
          && ieee_write_number (info, name_indx)
          && ieee_write_id (info, name)
          && ieee_write_byte (info, (int) ieee_ty_record_enum)
@@ -4292,6 +4642,53 @@ ieee_get_modified_info (info, indx)
   return info->modified + indx;
 }
 \f
+/* Routines for the hash table mapping names to types.  */
+
+/* Initialize an entry in the hash table.  */
+
+static struct bfd_hash_entry *
+ieee_name_type_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct ieee_name_type_hash_entry *ret =
+    (struct ieee_name_type_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == NULL)
+    ret = ((struct ieee_name_type_hash_entry *)
+          bfd_hash_allocate (table, sizeof *ret));
+  if (ret == NULL)
+    return NULL;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct ieee_name_type_hash_entry *)
+        bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->types = NULL;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in the hash table.  */
+
+#define ieee_name_type_hash_lookup(table, string, create, copy) \
+  ((struct ieee_name_type_hash_entry *) \
+   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
+/* Traverse the hash table.  */
+
+#define ieee_name_type_hash_traverse(table, func, info)                        \
+  (bfd_hash_traverse                                                   \
+   (&(table)->root,                                                    \
+    (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func),      \
+    (info)))
+\f
 /* The general routine to write out IEEE debugging information.  */
 
 boolean
@@ -4300,8 +4697,6 @@ write_ieee_debugging_info (abfd, dhandle)
      PTR dhandle;
 {
   struct ieee_handle info;
-  struct ieee_buf *tags;
-  struct ieee_name_type *nt;
   asection *s;
   const char *err;
   struct ieee_buf *b;
@@ -4311,6 +4706,20 @@ write_ieee_debugging_info (abfd, dhandle)
   info.type_indx = 256;
   info.name_indx = 32;
 
+  if (! bfd_hash_table_init (&info.typedefs.root, ieee_name_type_newfunc)
+      || ! bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc))
+    return false;
+
+  if (! ieee_init_buffer (&info, &info.global_types)
+      || ! ieee_init_buffer (&info, &info.data)
+      || ! ieee_init_buffer (&info, &info.types)
+      || ! ieee_init_buffer (&info, &info.vars)
+      || ! ieee_init_buffer (&info, &info.cxx)
+      || ! ieee_init_buffer (&info, &info.linenos)
+      || ! ieee_init_buffer (&info, &info.fntype)
+      || ! ieee_init_buffer (&info, &info.fnargs))
+    return false;
+
   if (! debug_write (dhandle, &ieee_fns, (PTR) &info))
     return false;
 
@@ -4321,72 +4730,59 @@ write_ieee_debugging_info (abfd, dhandle)
     }
 
   /* Put any undefined tags in the global typedef information.  */
-  tags = NULL;
-  for (nt = info.tags; nt != NULL; nt = nt->next)
-    {
-      unsigned int name_indx;
-      char code;
+  info.error = false;
+  ieee_name_type_hash_traverse (&info.tags,
+                               ieee_write_undefined_tag,
+                               (PTR) &info);
+  if (info.error)
+    return false;
 
-      if (nt->kind == DEBUG_KIND_ILLEGAL)
-       continue;
-      if (tags == NULL)
-       {
-         if (! ieee_change_buffer (&info, &tags)
-             || ! ieee_write_byte (&info, (int) ieee_bb_record_enum)
-             || ! ieee_write_byte (&info, 2)
-             || ! ieee_write_number (&info, 0)
-             || ! ieee_write_id (&info, ""))
-           return false;
-       }
-      name_indx = info.name_indx;
-      ++info.name_indx;
-      if (! ieee_write_byte (&info, (int) ieee_nn_record)
-         || ! ieee_write_number (&info, name_indx)
-         || ! ieee_write_id (&info, nt->name)
+  /* Prepend the global typedef information to the other data.  */
+  if (! ieee_buffer_emptyp (&info.global_types))
+    {
+      /* The HP debugger seems to have a bug in which it ignores the
+         last entry in the global types, so we add a dummy entry.  */
+      if (! ieee_change_buffer (&info, &info.global_types)
+         || ! ieee_write_byte (&info, (int) ieee_nn_record)
+         || ! ieee_write_number (&info, info.name_indx)
+         || ! ieee_write_id (&info, "")
          || ! ieee_write_byte (&info, (int) ieee_ty_record_enum)
-         || ! ieee_write_number (&info, nt->type.indx)
+         || ! ieee_write_number (&info, info.type_indx)
          || ! ieee_write_byte (&info, 0xce)
-         || ! ieee_write_number (&info, name_indx))
+         || ! ieee_write_number (&info, info.name_indx)
+         || ! ieee_write_number (&info, 'P')
+         || ! ieee_write_number (&info, (int) builtin_void + 32)
+         || ! ieee_write_byte (&info, (int) ieee_be_record_enum))
        return false;
-      switch (nt->kind)
-       {
-       default:
-         abort ();
-         return false;
-       case DEBUG_KIND_STRUCT:
-       case DEBUG_KIND_CLASS:
-         code = 'S';
-         break;
-       case DEBUG_KIND_UNION:
-       case DEBUG_KIND_UNION_CLASS:
-         code = 'U';
-         break;
-       case DEBUG_KIND_ENUM:
-         code = 'E';
-         break;
-       }
-      if (! ieee_write_number (&info, code)
-         || ! ieee_write_number (&info, 0))
+
+      if (! ieee_append_buffer (&info, &info.global_types, &info.data))
        return false;
+      info.data = info.global_types;
     }
-  if (tags != NULL)
-    {
-      struct ieee_buf **pb;
 
-      if (! ieee_write_byte (&info, (int) ieee_be_record_enum))
+  /* Make sure that we have declare BB11 blocks for each range in the
+     file.  They are added to info->vars.  */
+  info.error = false;
+  if (! ieee_init_buffer (&info, &info.vars))
+    return false;
+  bfd_map_over_sections (abfd, ieee_add_bb11_blocks, (PTR) &info);
+  if (info.error)
+    return false;
+  if (! ieee_buffer_emptyp (&info.vars))
+    {
+      if (! ieee_change_buffer (&info, &info.vars)
+         || ! ieee_write_byte (&info, (int) ieee_be_record_enum))
        return false;
 
-      for (pb = &tags; *pb != NULL; pb = &(*pb)->next)
-       ;
-      *pb = info.data;
-      info.data = tags;
+      if (! ieee_append_buffer (&info, &info.data, &info.vars))
+       return false;
     }
 
   /* Now all the data is in info.data.  Write it out to the BFD.  We
      normally would need to worry about whether all the other sections
      are set up yet, but the IEEE backend will handle this particular
      case correctly regardless.  */
-  if (info.data == NULL)
+  if (ieee_buffer_emptyp (&info.data))
     {
       /* There is no debugging information.  */
       return true;
@@ -4405,7 +4801,7 @@ write_ieee_debugging_info (abfd, dhandle)
       bfd_size_type size;
 
       size = 0;
-      for (b = info.data; b != NULL; b = b->next)
+      for (b = info.data.head; b != NULL; b = b->next)
        size += b->c;
       if (! bfd_set_section_size (abfd, s, size))
        err = "bfd_set_section_size";
@@ -4415,7 +4811,7 @@ write_ieee_debugging_info (abfd, dhandle)
       file_ptr offset;
 
       offset = 0;
-      for (b = info.data; b != NULL; b = b->next)
+      for (b = info.data.head; b != NULL; b = b->next)
        {
          if (! bfd_set_section_contents (abfd, s, b->buf, offset, b->c))
            {
@@ -4433,6 +4829,92 @@ write_ieee_debugging_info (abfd, dhandle)
       return false;
     }
 
+  bfd_hash_table_free (&info.typedefs.root);
+  bfd_hash_table_free (&info.tags.root);
+
+  return true;
+}
+
+/* Write out information for an undefined tag.  This is called via
+   ieee_name_type_hash_traverse.  */
+
+static boolean
+ieee_write_undefined_tag (h, p)
+     struct ieee_name_type_hash_entry *h;
+     PTR p;
+{
+  struct ieee_handle *info = (struct ieee_handle *) p;
+  struct ieee_name_type *nt;
+
+  for (nt = h->types; nt != NULL; nt = nt->next)
+    {
+      unsigned int name_indx;
+      char code;
+
+      if (nt->kind == DEBUG_KIND_ILLEGAL)
+       continue;
+
+      if (ieee_buffer_emptyp (&info->global_types))
+       {
+         if (! ieee_change_buffer (info, &info->global_types)
+             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+             || ! ieee_write_byte (info, 2)
+             || ! ieee_write_number (info, 0)
+             || ! ieee_write_id (info, ""))
+           {
+             info->error = true;
+             return false;
+           }
+       }
+      else
+       {
+         if (! ieee_change_buffer (info, &info->global_types))
+           {
+             info->error = true;
+             return false;
+           }
+       }
+
+      name_indx = info->name_indx;
+      ++info->name_indx;
+      if (! ieee_write_byte (info, (int) ieee_nn_record)
+         || ! ieee_write_number (info, name_indx)
+         || ! ieee_write_id (info, nt->type.name)
+         || ! ieee_write_byte (info, (int) ieee_ty_record_enum)
+         || ! ieee_write_number (info, nt->type.indx)
+         || ! ieee_write_byte (info, 0xce)
+         || ! ieee_write_number (info, name_indx))
+       {
+         info->error = true;
+         return false;
+       }
+
+      switch (nt->kind)
+       {
+       default:
+         abort ();
+         info->error = true;
+         return false;
+       case DEBUG_KIND_STRUCT:
+       case DEBUG_KIND_CLASS:
+         code = 'S';
+         break;
+       case DEBUG_KIND_UNION:
+       case DEBUG_KIND_UNION_CLASS:
+         code = 'U';
+         break;
+       case DEBUG_KIND_ENUM:
+         code = 'E';
+         break;
+       }
+      if (! ieee_write_number (info, code)
+         || ! ieee_write_number (info, 0))
+       {
+         info->error = true;
+         return false;
+       }
+    }
+
   return true;
 }
 
@@ -4445,7 +4927,11 @@ ieee_start_compilation_unit (p, filename)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   const char *modname;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  const char *backslash;
+#endif
   char *c, *s;
+  unsigned int nindx;
 
   if (info->filename != NULL)
     {
@@ -4455,28 +4941,53 @@ ieee_start_compilation_unit (p, filename)
 
   info->filename = filename;
   modname = strrchr (filename, '/');
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  /* We could have a mixed forward/back slash case.  */
+  backslash = strrchr (filename, '\\');
+  if (modname == NULL || (backslash != NULL && backslash > modname))
+    modname = backslash;
+#endif
+
   if (modname != NULL)
     ++modname;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  else if (filename[0] && filename[1] == ':')
+    modname = filename + 2;
+#endif
   else
-    {
-      modname = strrchr (filename, '\\');
-      if (modname != NULL)
-       ++modname;
-      else
-       modname = filename;
-    }
+    modname = filename;
+
   c = xstrdup (modname);
   s = strrchr (c, '.');
   if (s != NULL)
     *s = '\0';
   info->modname = c;
 
-  info->types = NULL;
-  info->vars = NULL;
-  info->cxx = NULL;
-  info->linenos = NULL;
+  if (! ieee_init_buffer (info, &info->types)
+      || ! ieee_init_buffer (info, &info->vars)
+      || ! ieee_init_buffer (info, &info->cxx)
+      || ! ieee_init_buffer (info, &info->linenos))
+    return false;
   info->ranges = NULL;
 
+  /* Always include a BB1 and a BB3 block.  That is what the output of
+     the MRI linker seems to look like.  */
+  if (! ieee_change_buffer (info, &info->types)
+      || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+      || ! ieee_write_byte (info, 1)
+      || ! ieee_write_number (info, 0)
+      || ! ieee_write_id (info, info->modname))
+    return false;
+
+  nindx = info->name_indx;
+  ++info->name_indx;
+  if (! ieee_change_buffer (info, &info->vars)
+      || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+      || ! ieee_write_byte (info, 3)
+      || ! ieee_write_number (info, 0)
+      || ! ieee_write_id (info, info->modname))
+    return false;
+
   return true;
 }
 
@@ -4486,34 +4997,22 @@ static boolean
 ieee_finish_compilation_unit (info)
      struct ieee_handle *info;
 {
-  struct ieee_buf **pp;
   struct ieee_range *r;
 
-  if (info->types != NULL)
+  if (! ieee_buffer_emptyp (&info->types))
     {
       if (! ieee_change_buffer (info, &info->types)
          || ! ieee_write_byte (info, (int) ieee_be_record_enum))
        return false;
     }
 
-  if (info->cxx != NULL)
+  if (! ieee_buffer_emptyp (&info->cxx))
     {
       /* Append any C++ information to the global function and
          variable information.  */
-      if (info->vars != NULL)
-       {
-         if (! ieee_change_buffer (info, &info->vars))
-           return false;
-       }
-      else
-       {
-         if (! ieee_change_buffer (info, &info->vars)
-             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-             || ! ieee_write_byte (info, 3)
-             || ! ieee_write_number (info, 0)
-             || ! ieee_write_id (info, info->modname))
-           return false;
-       }
+      assert (! ieee_buffer_emptyp (&info->vars));
+      if (! ieee_change_buffer (info, &info->vars))
+       return false;
 
       /* We put the pmisc records in a dummy procedure, just as the
          MRI compiler does.  */
@@ -4523,42 +5022,46 @@ ieee_finish_compilation_unit (info)
          || ! ieee_write_id (info, "__XRYCPP")
          || ! ieee_write_number (info, 0)
          || ! ieee_write_number (info, 0)
-         || ! ieee_write_number (info, info->highaddr))
-       return false;
-
-      for (pp = &info->vars; *pp != NULL; pp = &(*pp)->next)
-       ;
-      *pp = info->cxx;
-
-      if (! ieee_change_buffer (info, &info->vars)
+         || ! ieee_write_number (info, info->highaddr - 1)
+         || ! ieee_append_buffer (info, &info->vars, &info->cxx)
+         || ! ieee_change_buffer (info, &info->vars)
          || ! ieee_write_byte (info, (int) ieee_be_record_enum)
-         || ! ieee_write_number (info, info->highaddr))
+         || ! ieee_write_number (info, info->highaddr - 1))
        return false;
     }
 
-  if (info->vars != NULL)
+  if (! ieee_buffer_emptyp (&info->vars))
     {
       if (! ieee_change_buffer (info, &info->vars)
          || ! ieee_write_byte (info, (int) ieee_be_record_enum))
        return false;
     }
 
-  if (info->linenos != NULL)
+  if (info->pending_lineno_filename != NULL)
+    {
+      /* Force out the pending line number.  */
+      if (! ieee_lineno ((PTR) info, (const char *) NULL, 0, (bfd_vma) -1))
+       return false;
+    }
+  if (! ieee_buffer_emptyp (&info->linenos))
     {
       if (! ieee_change_buffer (info, &info->linenos)
          || ! ieee_write_byte (info, (int) ieee_be_record_enum))
        return false;
+      if (strcmp (info->filename, info->lineno_filename) != 0)
+       {
+         /* We were not in the main file.  We just closed the
+             included line number block, and now we must close the
+             main line number block.  */
+         if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+           return false;
+       }
     }
 
-  for (pp = &info->data; *pp != NULL; pp = &(*pp)->next)
-    ;
-  *pp = info->types;
-  for (; *pp != NULL; pp = &(*pp)->next)
-    ;
-  *pp = info->vars;
-  for (; *pp != NULL; pp = &(*pp)->next)
-    ;
-  *pp = info->linenos;
+  if (! ieee_append_buffer (info, &info->data, &info->types)
+      || ! ieee_append_buffer (info, &info->data, &info->vars)
+      || ! ieee_append_buffer (info, &info->data, &info->linenos))
+    return false;
 
   /* Build BB10/BB11 blocks based on the ranges we recorded.  */
   if (! ieee_change_buffer (info, &info->data))
@@ -4599,13 +5102,13 @@ ieee_finish_compilation_unit (info)
 
       /* Coalesce ranges if it seems reasonable.  */
       while (r->next != NULL
-            && high + 64 >= r->next->low
+            && high + 0x1000 >= r->next->low
             && (r->next->high
                 <= (bfd_get_section_vma (info->abfd, s)
                     + bfd_section_size (info->abfd, s))))
        {
          r = r->next;
-         high = r->next->high;
+         high = r->high;
        }
 
       if ((s->flags & SEC_CODE) != 0)
@@ -4620,11 +5123,15 @@ ieee_finish_compilation_unit (info)
          || ! ieee_write_number (info, 0)
          || ! ieee_write_id (info, "")
          || ! ieee_write_number (info, kind)
-         || ! ieee_write_number (info, s->index)
+         || ! ieee_write_number (info, s->index + IEEE_SECTION_NUMBER_BASE)
          || ! ieee_write_number (info, low)
          || ! ieee_write_byte (info, (int) ieee_be_record_enum)
          || ! ieee_write_number (info, high - low))
        return false;
+
+      /* Add this range to the list of global ranges.  */
+      if (! ieee_add_range (info, true, low, high))
+       return false;
     }
 
   if (! ieee_write_byte (info, (int) ieee_be_record_enum))
@@ -4633,6 +5140,133 @@ ieee_finish_compilation_unit (info)
   return true;
 }
 
+/* Add BB11 blocks describing each range that we have not already
+   described.  */
+
+static void
+ieee_add_bb11_blocks (abfd, sec, data)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     PTR data;
+{
+  struct ieee_handle *info = (struct ieee_handle *) data;
+  bfd_vma low, high;
+  struct ieee_range *r;
+
+  low = bfd_get_section_vma (abfd, sec);
+  high = low + bfd_section_size (abfd, sec);
+
+  /* Find the first range at or after this section.  The ranges are
+     sorted by address.  */
+  for (r = info->global_ranges; r != NULL; r = r->next)
+    if (r->high > low)
+      break;
+
+  while (low < high)
+    {
+      if (r == NULL || r->low >= high)
+       {
+         if (! ieee_add_bb11 (info, sec, low, high))
+           info->error = true;
+         return;
+       }
+
+      if (low < r->low
+         && r->low - low > 0x100)
+       {
+         if (! ieee_add_bb11 (info, sec, low, r->low))
+           {
+             info->error = true;
+             return;
+           }
+       }
+      low = r->high;
+
+      r = r->next;
+    }
+}
+
+/* Add a single BB11 block for a range.  We add it to info->vars.  */
+
+static boolean
+ieee_add_bb11 (info, sec, low, high)
+     struct ieee_handle *info;
+     asection *sec;
+     bfd_vma low;
+     bfd_vma high;
+{
+  int kind;
+
+  if (! ieee_buffer_emptyp (&info->vars))
+    {
+      if (! ieee_change_buffer (info, &info->vars))
+       return false;
+    }
+  else
+    {
+      const char *filename, *modname;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+      const char *backslash;
+#endif
+      char *c, *s;
+
+      /* Start the enclosing BB10 block.  */
+      filename = bfd_get_filename (info->abfd);
+      modname = strrchr (filename, '/');
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+      backslash = strrchr (filename, '\\');
+      if (modname == NULL || (backslash != NULL && backslash > modname))
+       modname = backslash;
+#endif
+
+      if (modname != NULL)
+       ++modname;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+      else if (filename[0] && filename[1] == ':')
+       modname = filename + 2;
+#endif
+      else
+       modname = filename;
+
+      c = xstrdup (modname);
+      s = strrchr (c, '.');
+      if (s != NULL)
+       *s = '\0';
+
+      if (! ieee_change_buffer (info, &info->vars)
+         || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+         || ! ieee_write_byte (info, 10)
+         || ! ieee_write_number (info, 0)
+         || ! ieee_write_id (info, c)
+         || ! ieee_write_id (info, "")
+         || ! ieee_write_number (info, 0)
+         || ! ieee_write_id (info, "GNU objcopy"))
+       return false;
+
+      free (c);
+    }
+
+  if ((sec->flags & SEC_CODE) != 0)
+    kind = 1;
+  else if ((sec->flags & SEC_READONLY) != 0)
+    kind = 3;
+  else
+    kind = 2;
+
+  if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+      || ! ieee_write_byte (info, 11)
+      || ! ieee_write_number (info, 0)
+      || ! ieee_write_id (info, "")
+      || ! ieee_write_number (info, kind)
+      || ! ieee_write_number (info, sec->index + IEEE_SECTION_NUMBER_BASE)
+      || ! ieee_write_number (info, low)
+      || ! ieee_write_byte (info, (int) ieee_be_record_enum)
+      || ! ieee_write_number (info, high - low))
+    return false;
+
+  return true;
+}
+
 /* Start recording information from a particular source file.  This is
    used to record which file defined which types, variables, etc.  It
    is not used for line numbers, since the lineno entry point passes
@@ -4642,8 +5276,8 @@ ieee_finish_compilation_unit (info)
 /*ARGSUSED*/
 static boolean
 ieee_start_source (p, filename)
-     PTR p;
-     const char *filename;
+     PTR p ATTRIBUTE_UNUSED;
+     const char *filename ATTRIBUTE_UNUSED;
 {
   return true;
 }
@@ -4656,7 +5290,7 @@ ieee_empty_type (p)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
 
-  return ieee_push_type (info, 0, 0, false);
+  return ieee_push_type (info, (int) builtin_unknown, 0, false, false);
 }
 
 /* Make a void type.  */
@@ -4667,7 +5301,7 @@ ieee_void_type (p)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
 
-  return ieee_push_type (info, 1, 0, false);
+  return ieee_push_type (info, (int) builtin_void, 0, false, false);
 }
 
 /* Make an integer type.  */
@@ -4696,14 +5330,14 @@ ieee_int_type (p, size, unsignedp)
       indx = (int) builtin_signed_long_long;
       break;
     default:
-      fprintf (stderr, "IEEE unsupported integer type size %u\n", size);
+      fprintf (stderr, _("IEEE unsupported integer type size %u\n"), size);
       return false;
     }
 
   if (unsignedp)
     ++indx;
 
-  return ieee_push_type (info, indx, size, unsignedp);
+  return ieee_push_type (info, indx, size, unsignedp, false);
 }
 
 /* Make a floating point type.  */
@@ -4732,11 +5366,11 @@ ieee_float_type (p, size)
       indx = (int) builtin_long_long_double;
       break;
     default:
-      fprintf (stderr, "IEEE unsupported float type size %u\n", size);
+      fprintf (stderr, _("IEEE unsupported float type size %u\n"), size);
       return false;
     }
 
-  return ieee_push_type (info, indx, size, false);
+  return ieee_push_type (info, indx, size, false, false);
 }
 
 /* Make a complex type.  */
@@ -4752,20 +5386,38 @@ ieee_complex_type (p, size)
   switch (size)
     {
     case 4:
+      if (info->complex_float_index != 0)
+       return ieee_push_type (info, info->complex_float_index, size * 2,
+                              false, false);
       code = 'c';
       break;
+    case 12:
+    case 16:
+      /* These cases can be output by gcc -gstabs.  Outputting the
+         wrong type is better than crashing.  */
     case 8:
+      if (info->complex_double_index != 0)
+       return ieee_push_type (info, info->complex_double_index, size * 2,
+                              false, false);
       code = 'd';
       break;
     default:
-      fprintf (stderr, "IEEE unsupported complex type size %u\n", size);
+      fprintf (stderr, _("IEEE unsupported complex type size %u\n"), size);
       return false;
     }
 
   /* FIXME: I don't know what the string is for.  */
-  return (ieee_define_type (info, size, false)
-         && ieee_write_number (info, code)
-         && ieee_write_id (info, ""));
+  if (! ieee_define_type (info, size * 2, false, false)
+      || ! ieee_write_number (info, code)
+      || ! ieee_write_id (info, ""))
+    return false;
+
+  if (size == 4)
+    info->complex_float_index = info->type_stack->type.indx;
+  else
+    info->complex_double_index = info->type_stack->type.indx;
+
+  return true;
 }
 
 /* Make a boolean type.  IEEE doesn't support these, so we just make
@@ -4789,8 +5441,64 @@ ieee_enum_type (p, tag, names, vals)
      bfd_signed_vma *vals;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
-  boolean simple;
-  int i;
+  struct ieee_defined_enum *e;
+  boolean localp, simple;
+  unsigned int indx;
+  int i = 0;
+
+  localp = false;
+  indx = (unsigned int) -1;
+  for (e = info->enums; e != NULL; e = e->next)
+    {
+      if (tag == NULL)
+       {
+         if (e->tag != NULL)
+           continue;
+       }
+      else
+       {
+         if (e->tag == NULL
+             || tag[0] != e->tag[0]
+             || strcmp (tag, e->tag) != 0)
+           continue;
+       }
+
+      if (! e->defined)
+       {
+         /* This enum tag has been seen but not defined.  */
+         indx = e->indx;
+         break;
+       }
+
+      if (names != NULL && e->names != NULL)
+       {
+         for (i = 0; names[i] != NULL && e->names[i] != NULL; i++)
+           {
+             if (names[i][0] != e->names[i][0]
+                 || vals[i] != e->vals[i]
+                 || strcmp (names[i], e->names[i]) != 0)
+               break;
+           }
+       }
+
+      if ((names == NULL && e->names == NULL)
+         || (names != NULL
+             && e->names != NULL
+             && names[i] == NULL
+             && e->names[i] == NULL))
+       {
+         /* We've seen this enum before.  */
+         return ieee_push_type (info, e->indx, 0, true, false);
+       }
+
+      if (tag != NULL)
+       {
+         /* We've already seen an enum of the same name, so we must make
+            sure to output this one locally.  */
+         localp = true;
+         break;
+       }
+    }
 
   /* If this is a simple enumeration, in which the values start at 0
      and always increment by 1, we can use type E.  Otherwise we must
@@ -4809,8 +5517,8 @@ ieee_enum_type (p, tag, names, vals)
        }
     }
 
-  if (! ieee_define_named_type (info, tag, true, (unsigned int) -1, 0,
-                               true, (struct ieee_buf **) NULL)
+  if (! ieee_define_named_type (info, tag, indx, 0, true, localp,
+                               (struct ieee_buflist *) NULL)
       || ! ieee_write_number (info, simple ? 'E' : 'N'))
     return false;
   if (simple)
@@ -4834,6 +5542,24 @@ ieee_enum_type (p, tag, names, vals)
        }
     }
 
+  if (! localp)
+    {
+      if (indx == (unsigned int) -1)
+       {
+         e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
+         memset (e, 0, sizeof *e);
+         e->indx = info->type_stack->type.indx;
+         e->tag = tag;
+
+         e->next = info->enums;
+         info->enums = e;
+       }
+
+      e->names = names;
+      e->vals = vals;
+      e->defined = true;
+    }
+
   return true;
 }
 
@@ -4844,28 +5570,36 @@ ieee_pointer_type (p)
      PTR p;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
+  boolean localp;
   unsigned int indx;
-  struct ieee_modified_type *m;
+  struct ieee_modified_type *m = NULL;
 
+  localp = info->type_stack->type.localp;
   indx = ieee_pop_type (info);
 
-  /* A pointer to a simple builtin type can be obtained by adding 32.  */
+  /* A pointer to a simple builtin type can be obtained by adding 32.
+     FIXME: Will this be a short pointer, and will that matter?  */
   if (indx < 32)
-    return ieee_push_type (info, indx + 32, 0, true);
+    return ieee_push_type (info, indx + 32, 0, true, false);
 
-  m = ieee_get_modified_info (p, indx);
-  if (m == NULL)
-    return false;
+  if (! localp)
+    {
+      m = ieee_get_modified_info (p, indx);
+      if (m == NULL)
+       return false;
 
-  if (m->pointer > 0)
-    return ieee_push_type (info, m->pointer, 0, true);
+      /* FIXME: The size should depend upon the architecture.  */
+      if (m->pointer > 0)
+       return ieee_push_type (info, m->pointer, 4, true, false);
+    }
 
-  if (! ieee_define_type (info, 0, true)
+  if (! ieee_define_type (info, 4, true, localp)
       || ! ieee_write_number (info, 'P')
       || ! ieee_write_number (info, indx))
     return false;
 
-  m->pointer = info->type_stack->type.indx;
+  if (! localp)
+    m->pointer = info->type_stack->type.indx;
 
   return true;
 }
@@ -4882,27 +5616,49 @@ ieee_function_type (p, argcount, varargs)
      boolean varargs;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
+  boolean localp;
   unsigned int *args = NULL;
   int i;
   unsigned int retindx;
-  struct ieee_buf *fndef;
+  struct ieee_buflist fndef;
+  struct ieee_modified_type *m;
+
+  localp = false;
 
   if (argcount > 0)
     {
       args = (unsigned int *) xmalloc (argcount * sizeof *args);
       for (i = argcount - 1; i >= 0; i--)
-       args[i] = ieee_pop_type (info);
+       {
+         if (info->type_stack->type.localp)
+           localp = true;
+         args[i] = ieee_pop_type (info);
+       }
     }
   else if (argcount < 0)
     varargs = false;
 
+  if (info->type_stack->type.localp)
+    localp = true;
   retindx = ieee_pop_type (info);
 
+  m = NULL;
+  if (argcount < 0 && ! localp)
+    {
+      m = ieee_get_modified_info (p, retindx);
+      if (m == NULL)
+       return false;
+
+      if (m->function > 0)
+       return ieee_push_type (info, m->function, 0, true, false);
+    }
+
   /* An attribute of 0x41 means that the frame and push mask are
      unknown.  */
-  fndef = NULL;
-  if (! ieee_define_named_type (info, (const char *) NULL, false, 0, 0,
-                               true, &fndef)
+  if (! ieee_init_buffer (info, &fndef)
+      || ! ieee_define_named_type (info, (const char *) NULL,
+                                  (unsigned int) -1, 0, true, localp,
+                                  &fndef)
       || ! ieee_write_number (info, 'x')
       || ! ieee_write_number (info, 0x41)
       || ! ieee_write_number (info, 0)
@@ -4932,6 +5688,9 @@ ieee_function_type (p, argcount, varargs)
      It will be appended to info->types by ieee_pop_type.  */
   info->type_stack->type.fndef = fndef;
 
+  if (m != NULL)
+    m->function = info->type_stack->type.indx;
+
   return true;
 }
 
@@ -4962,12 +5721,13 @@ ieee_range_type (p, low, high)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   unsigned int size;
-  boolean unsignedp;
+  boolean unsignedp, localp;
 
   size = info->type_stack->type.size;
   unsignedp = info->type_stack->type.unsignedp;
+  localp = info->type_stack->type.localp;
   ieee_pop_unused_type (info);
-  return (ieee_define_type (info, size, unsignedp)
+  return (ieee_define_type (info, size, unsignedp, localp)
          && ieee_write_number (info, 'R')
          && ieee_write_number (info, (bfd_vma) low)
          && ieee_write_number (info, (bfd_vma) high)
@@ -4983,26 +5743,66 @@ ieee_array_type (p, low, high, stringp)
      PTR p;
      bfd_signed_vma low;
      bfd_signed_vma high;
-     boolean stringp;
+     boolean stringp ATTRIBUTE_UNUSED;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   unsigned int eleindx;
+  boolean localp;
+  unsigned int size;
+  struct ieee_modified_type *m = NULL;
+  struct ieee_modified_array_type *a;
 
   /* IEEE does not store the range, so we just ignore it.  */
   ieee_pop_unused_type (info);
+  localp = info->type_stack->type.localp;
+  size = info->type_stack->type.size;
   eleindx = ieee_pop_type (info);
 
-  if (! ieee_define_type (info, 0, false)
+  /* If we don't know the range, treat the size as exactly one
+     element.  */
+  if (low < high)
+    size *= (high - low) + 1;
+
+  if (! localp)
+    {
+      m = ieee_get_modified_info (info, eleindx);
+      if (m == NULL)
+       return false;
+
+      for (a = m->arrays; a != NULL; a = a->next)
+       {
+         if (a->low == low && a->high == high)
+           return ieee_push_type (info, a->indx, size, false, false);
+       }
+    }
+
+  if (! ieee_define_type (info, size, false, localp)
       || ! ieee_write_number (info, low == 0 ? 'Z' : 'C')
       || ! ieee_write_number (info, eleindx))
     return false;
   if (low != 0)
     {
-      if (! ieee_write_number (info, low))
-       return false;
+      if (! ieee_write_number (info, low))
+       return false;
+    }
+
+  if (! ieee_write_number (info, high + 1))
+    return false;
+
+  if (! localp)
+    {
+      a = (struct ieee_modified_array_type *) xmalloc (sizeof *a);
+      memset (a, 0, sizeof *a);
+
+      a->indx = info->type_stack->type.indx;
+      a->low = low;
+      a->high = high;
+
+      a->next = m->arrays;
+      m->arrays = a;
     }
 
-  return ieee_write_number (info, high);
+  return true;
 }
 
 /* Make a set type.  */
@@ -5010,16 +5810,18 @@ ieee_array_type (p, low, high, stringp)
 static boolean
 ieee_set_type (p, bitstringp)
      PTR p;
-     boolean bitstringp;
+     boolean bitstringp ATTRIBUTE_UNUSED;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
+  boolean localp;
   unsigned int eleindx;
 
+  localp = info->type_stack->type.localp;
   eleindx = ieee_pop_type (info);
 
   /* FIXME: We don't know the size, so we just use 4.  */
 
-  return (ieee_define_type (info, 0, true)
+  return (ieee_define_type (info, 0, true, localp)
          && ieee_write_number (info, 's')
          && ieee_write_number (info, 4)
          && ieee_write_number (info, eleindx));
@@ -5045,7 +5847,7 @@ ieee_offset_type (p)
      which seems pretty important.  I'm going to punt this for now.  */
 
   return ieee_int_type (p, 4, true);
-}  
+}
 
 /* Make a method type.  */
 
@@ -5076,28 +5878,34 @@ ieee_const_type (p)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   unsigned int size;
-  boolean unsignedp;
+  boolean unsignedp, localp;
   unsigned int indx;
-  struct ieee_modified_type *m;
+  struct ieee_modified_type *m = NULL;
 
   size = info->type_stack->type.size;
   unsignedp = info->type_stack->type.unsignedp;
+  localp = info->type_stack->type.localp;
   indx = ieee_pop_type (info);
 
-  m = ieee_get_modified_info (info, indx);
-  if (m == NULL)
-    return false;
+  if (! localp)
+    {
+      m = ieee_get_modified_info (info, indx);
+      if (m == NULL)
+       return false;
 
-  if (m->const_qualified > 0)
-    return ieee_push_type (info, m->const_qualified, size, unsignedp);
+      if (m->const_qualified > 0)
+       return ieee_push_type (info, m->const_qualified, size, unsignedp,
+                              false);
+    }
 
-  if (! ieee_define_type (info, size, unsignedp)
+  if (! ieee_define_type (info, size, unsignedp, localp)
       || ! ieee_write_number (info, 'n')
       || ! ieee_write_number (info, 1)
       || ! ieee_write_number (info, indx))
     return false;
 
-  m->const_qualified = info->type_stack->type.indx;
+  if (! localp)
+    m->const_qualified = info->type_stack->type.indx;
 
   return true;
 }
@@ -5110,28 +5918,34 @@ ieee_volatile_type (p)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   unsigned int size;
-  boolean unsignedp;
+  boolean unsignedp, localp;
   unsigned int indx;
-  struct ieee_modified_type *m;
+  struct ieee_modified_type *m = NULL;
 
   size = info->type_stack->type.size;
   unsignedp = info->type_stack->type.unsignedp;
+  localp = info->type_stack->type.localp;
   indx = ieee_pop_type (info);
 
-  m = ieee_get_modified_info (info, indx);
-  if (m == NULL)
-    return false;
+  if (! localp)
+    {
+      m = ieee_get_modified_info (info, indx);
+      if (m == NULL)
+       return false;
 
-  if (m->volatile_qualified > 0)
-    return ieee_push_type (info, m->volatile_qualified, size, unsignedp);
+      if (m->volatile_qualified > 0)
+       return ieee_push_type (info, m->volatile_qualified, size, unsignedp,
+                              false);
+    }
 
-  if (! ieee_define_type (info, size, unsignedp)
+  if (! ieee_define_type (info, size, unsignedp, localp)
       || ! ieee_write_number (info, 'n')
       || ! ieee_write_number (info, 2)
       || ! ieee_write_number (info, indx))
     return false;
 
-  m->volatile_qualified = info->type_stack->type.indx;
+  if (! localp)
+    m->volatile_qualified = info->type_stack->type.indx;
 
   return true;
 }
@@ -5169,15 +5983,98 @@ ieee_start_struct_type (p, tag, id, structp, size)
      unsigned int size;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
-  struct ieee_buf *strdef;
+  boolean localp, ignorep;
+  boolean copy;
+  char ab[20];
+  const char *look;
+  struct ieee_name_type_hash_entry *h;
+  struct ieee_name_type *nt, *ntlook;
+  struct ieee_buflist strdef;
+
+  localp = false;
+  ignorep = false;
+
+  /* We need to create a tag for internal use even if we don't want
+     one for external use.  This will let us refer to an anonymous
+     struct.  */
+  if (tag != NULL)
+    {
+      look = tag;
+      copy = false;
+    }
+  else
+    {
+      sprintf (ab, "__anon%u", id);
+      look = ab;
+      copy = true;
+    }
+
+  /* If we already have references to the tag, we must use the
+     existing type index.  */
+  h = ieee_name_type_hash_lookup (&info->tags, look, true, copy);
+  if (h == NULL)
+    return false;
+
+  nt = NULL;
+  for (ntlook = h->types; ntlook != NULL; ntlook = ntlook->next)
+    {
+      if (ntlook->id == id)
+       nt = ntlook;
+      else if (! ntlook->type.localp)
+       {
+         /* We are creating a duplicate definition of a globally
+            defined tag.  Force it to be local to avoid
+            confusion.  */
+         localp = true;
+       }
+    }
+
+  if (nt != NULL)
+    {
+      assert (localp == nt->type.localp);
+      if (nt->kind == DEBUG_KIND_ILLEGAL && ! localp)
+       {
+         /* We've already seen a global definition of the type.
+             Ignore this new definition.  */
+         ignorep = true;
+       }
+    }
+  else
+    {
+      nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+      memset (nt, 0, sizeof *nt);
+      nt->id = id;
+      nt->type.name = h->root.string;
+      nt->next = h->types;
+      h->types = nt;
+      nt->type.indx = info->type_indx;
+      ++info->type_indx;
+    }
+
+  nt->kind = DEBUG_KIND_ILLEGAL;
 
-  strdef = NULL;
-  if (! ieee_define_named_type (info, tag, true, id, size, true, &strdef)
+  if (! ieee_init_buffer (info, &strdef)
+      || ! ieee_define_named_type (info, tag, nt->type.indx, size, true,
+                                  localp, &strdef)
       || ! ieee_write_number (info, structp ? 'S' : 'U')
       || ! ieee_write_number (info, size))
     return false;
 
+  if (! ignorep)
+    {
+      const char *hold;
+
+      /* We never want nt->type.name to be NULL.  We want the rest of
+        the type to be the object set up on the type stack; it will
+        have a NULL name if tag is NULL.  */
+      hold = nt->type.name;
+      nt->type = info->type_stack->type;
+      nt->type.name = hold;
+    }
+
+  info->type_stack->type.name = tag;
   info->type_stack->type.strdef = strdef;
+  info->type_stack->type.ignorep = ignorep;
 
   return true;
 }
@@ -5196,15 +6093,30 @@ ieee_struct_field (p, name, bitpos, bitsize, visibility)
   unsigned int size;
   boolean unsignedp;
   boolean referencep;
+  boolean localp;
   unsigned int indx;
   bfd_vma offset;
 
+  assert (info->type_stack != NULL
+         && info->type_stack->next != NULL
+         && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
+
+  /* If we are ignoring this struct definition, just pop and ignore
+     the type.  */
+  if (info->type_stack->next->type.ignorep)
+    {
+      ieee_pop_unused_type (info);
+      return true;
+    }
+
   size = info->type_stack->type.size;
   unsignedp = info->type_stack->type.unsignedp;
   referencep = info->type_stack->type.referencep;
+  localp = info->type_stack->type.localp;
   indx = ieee_pop_type (info);
 
-  assert (info->type_stack != NULL && info->type_stack->type.strdef != NULL);
+  if (localp)
+    info->type_stack->type.localp = true;
 
   if (info->type_stack->type.classdef != NULL)
     {
@@ -5250,8 +6162,7 @@ ieee_struct_field (p, name, bitpos, bitsize, visibility)
              || ! ieee_write_number (info, 4)
              || ! ieee_write_asn (info, nindx, 'R')
              || ! ieee_write_asn (info, nindx, 3)
-             || ! ieee_write_atn65 (info, nindx,
-                                    info->type_stack->type.classdef->name)
+             || ! ieee_write_atn65 (info, nindx, info->type_stack->type.name)
              || ! ieee_write_atn65 (info, nindx, name))
            return false;
        }
@@ -5259,13 +6170,15 @@ ieee_struct_field (p, name, bitpos, bitsize, visibility)
 
   /* If the bitsize doesn't match the expected size, we need to output
      a bitfield type.  */
-  if (size == 0 || bitsize == size * 8)
+  if (size == 0 || bitsize == 0 || bitsize == size * 8)
     offset = bitpos / 8;
   else
     {
-      if (! ieee_define_type (info, 0, unsignedp)
+      if (! ieee_define_type (info, 0, unsignedp,
+                             info->type_stack->type.localp)
          || ! ieee_write_number (info, 'g')
          || ! ieee_write_number (info, unsignedp ? 0 : 1)
+         || ! ieee_write_number (info, bitsize)
          || ! ieee_write_number (info, indx))
        return false;
       indx = ieee_pop_type (info);
@@ -5287,26 +6200,54 @@ ieee_end_struct_type (p)
      PTR p;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
-  struct ieee_buf **pb;
+  struct ieee_buflist *pb;
 
-  assert (info->type_stack != NULL && info->type_stack->type.strdef != NULL);
+  assert (info->type_stack != NULL
+         && ! ieee_buffer_emptyp (&info->type_stack->type.strdef));
+
+  /* If we were ignoring this struct definition because it was a
+     duplicate defintion, just through away whatever bytes we have
+     accumulated.  Leave the type on the stack. */
+  if (info->type_stack->type.ignorep)
+    return true;
 
-  /* Make sure we have started the types block.  */
-  if (info->types == NULL)
+  /* If this is not a duplicate definition of this tag, then localp
+     will be false, and we can put it in the global type block.
+     FIXME: We should avoid outputting duplicate definitions which are
+     the same.  */
+  if (! info->type_stack->type.localp)
     {
-      if (! ieee_change_buffer (info, &info->types)
-         || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-         || ! ieee_write_byte (info, 1)
-         || ! ieee_write_number (info, 0)
-         || ! ieee_write_id (info, info->modname))
-       return false;
+      /* Make sure we have started the global type block.  */
+      if (ieee_buffer_emptyp (&info->global_types))
+       {
+         if (! ieee_change_buffer (info, &info->global_types)
+             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+             || ! ieee_write_byte (info, 2)
+             || ! ieee_write_number (info, 0)
+             || ! ieee_write_id (info, ""))
+           return false;
+       }
+      pb = &info->global_types;
+    }
+  else
+    {
+      /* Make sure we have started the types block.  */
+      if (ieee_buffer_emptyp (&info->types))
+       {
+         if (! ieee_change_buffer (info, &info->types)
+             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
+             || ! ieee_write_byte (info, 1)
+             || ! ieee_write_number (info, 0)
+             || ! ieee_write_id (info, info->modname))
+           return false;
+       }
+      pb = &info->types;
     }
 
   /* Append the struct definition to the types.  */
-  for (pb = &info->types; *pb != NULL; pb = &(*pb)->next)
-    ;
-  *pb = info->type_stack->type.strdef;
-  info->type_stack->type.strdef = NULL;
+  if (! ieee_append_buffer (info, pb, &info->type_stack->type.strdef)
+      || ! ieee_init_buffer (info, &info->type_stack->type.strdef))
+    return false;
 
   /* Leave the struct on the type stack.  */
 
@@ -5327,10 +6268,9 @@ ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   const char *vclass;
-  struct ieee_buf *pmiscbuf;
+  struct ieee_buflist pmiscbuf;
   unsigned int indx;
   struct ieee_type_class *classdef;
-  struct ieee_name_type *nt;
 
   /* A C++ class is output as a C++ struct along with a set of pmisc
      records describing the class.  */
@@ -5352,8 +6292,8 @@ ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
   vclass = NULL;
   if (vptr && ! ownvptr)
     {
-      assert (info->type_stack->type.classdef != NULL);
-      vclass = info->type_stack->type.classdef->name;
+      vclass = info->type_stack->type.name;
+      assert (vclass != NULL);
       /* We don't call ieee_pop_unused_type, since the class should
          get defined.  */
       (void) ieee_pop_type (info);
@@ -5368,8 +6308,8 @@ ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
   /* We write out pmisc records into the classdef field.  We will
      write out the pmisc start after we know the number of records we
      need.  */
-  pmiscbuf = NULL;
-  if (! ieee_change_buffer (info, &pmiscbuf)
+  if (! ieee_init_buffer (info, &pmiscbuf)
+      || ! ieee_change_buffer (info, &pmiscbuf)
       || ! ieee_write_asn (info, indx, 'T')
       || ! ieee_write_asn (info, indx, structp ? 'o' : 'u')
       || ! ieee_write_atn65 (info, indx, tag))
@@ -5378,7 +6318,6 @@ ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
   classdef = (struct ieee_type_class *) xmalloc (sizeof *classdef);
   memset (classdef, 0, sizeof *classdef);
 
-  classdef->name = tag;
   classdef->indx = indx;
   classdef->pmiscbuf = pmiscbuf;
   classdef->pmisccount = 3;
@@ -5387,15 +6326,6 @@ ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
 
   info->type_stack->type.classdef = classdef;
 
-  /* We need to fill in the classdef in the tag as well, so that it
-     will be set when ieee_tag_type is called.  */
-  for (nt = info->tags; nt != NULL; nt = nt->next)
-    if (nt->name[0] == tag[0]
-       && strcmp (nt->name, tag) == 0)
-      break;
-  assert (nt != NULL);
-  nt->type.classdef = classdef;
-
   return true;
 }
 
@@ -5447,18 +6377,20 @@ ieee_class_baseclass (p, bitpos, virtual, visibility)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   const char *bname;
+  boolean localp;
   unsigned int bindx;
   char *fname;
   unsigned int flags;
   unsigned int nindx;
 
   assert (info->type_stack != NULL
-         && info->type_stack->type.classdef != NULL
+         && info->type_stack->type.name != NULL
          && info->type_stack->next != NULL
          && info->type_stack->next->type.classdef != NULL
-         && info->type_stack->next->type.strdef != NULL);
+         && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef));
 
-  bname = info->type_stack->type.classdef->name;
+  bname = info->type_stack->type.name;
+  localp = info->type_stack->type.localp;
   bindx = ieee_pop_type (info);
 
   /* We are currently defining both a struct and a class.  We must
@@ -5474,6 +6406,9 @@ ieee_class_baseclass (p, bitpos, virtual, visibility)
     }
   else
     {
+      if (localp)
+       info->type_stack->type.localp = true;
+
       fname = (char *) xmalloc (strlen (bname) + sizeof "_b$");
       sprintf (fname, "_b$%s", bname);
 
@@ -5583,9 +6518,7 @@ ieee_class_method_var (info, physname, visibility, staticp, constp,
     {
       if (voffset > info->type_stack->type.classdef->voffset)
        info->type_stack->type.classdef->voffset = voffset;
-      /* FIXME: The size of a vtable entry depends upon the
-         architecture.  */
-      if (! ieee_write_asn (info, nindx, (voffset / 4) + 1))
+      if (! ieee_write_asn (info, nindx, voffset))
        return false;
       ++info->type_stack->type.classdef->pmisccount;
     }
@@ -5658,27 +6591,28 @@ ieee_end_class_type (p)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
   unsigned int nindx;
-  struct ieee_buf **pb;
 
   assert (info->type_stack != NULL
          && info->type_stack->type.classdef != NULL);
 
+  /* If we were ignoring this class definition because it was a
+     duplicate definition, just through away whatever bytes we have
+     accumulated.  Leave the type on the stack.  */
+  if (info->type_stack->type.ignorep)
+    return true;
+
   nindx = info->type_stack->type.classdef->indx;
 
   /* If we have a virtual table, we can write out the information now.  */
   if (info->type_stack->type.classdef->vclass != NULL
       || info->type_stack->type.classdef->ownvptr)
     {
-      bfd_vma vsize;
-
-      /* FIXME: This calculation is architecture dependent.  */
-      vsize = (info->type_stack->type.classdef->voffset + 4) / 4;
-
       if (! ieee_change_buffer (info,
                                &info->type_stack->type.classdef->pmiscbuf)
          || ! ieee_write_asn (info, nindx, 'z')
          || ! ieee_write_atn65 (info, nindx, "")
-         || ! ieee_write_asn (info, nindx, vsize))
+         || ! ieee_write_asn (info, nindx,
+                              info->type_stack->type.classdef->voffset))
        return false;
       if (info->type_stack->type.classdef->ownvptr)
        {
@@ -5713,14 +6647,14 @@ ieee_end_class_type (p)
                              info->type_stack->type.classdef->pmisccount))
     return false;
 
-  for (pb = &info->cxx; *pb != NULL; pb = &(*pb)->next)
-    ;
-  *pb = info->type_stack->type.classdef->pmiscbuf;
-  if (info->type_stack->type.classdef->refs != NULL)
+  if (! ieee_append_buffer (info, &info->cxx,
+                           &info->type_stack->type.classdef->pmiscbuf))
+    return false;
+  if (! ieee_buffer_emptyp (&info->type_stack->type.classdef->refs))
     {
-      for (; *pb != NULL; pb = &(*pb)->next)
-       ;
-      *pb = info->type_stack->type.classdef->refs;
+      if (! ieee_append_buffer (info, &info->cxx,
+                               &info->type_stack->type.classdef->refs))
+       return false;
     }
 
   return ieee_end_struct_type (p);
@@ -5734,23 +6668,28 @@ ieee_typedef_type (p, name)
      const char *name;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
-  register struct ieee_name_type *nt;
+  struct ieee_name_type_hash_entry *h;
+  struct ieee_name_type *nt;
 
-  for (nt = info->typedefs; nt != NULL; nt = nt->next)
-    {
-      if (nt->name[0] == name[0]
-         && strcmp (nt->name, name) == 0)
-       {
-         if (! ieee_push_type (info, nt->type.indx, nt->type.size,
-                               nt->type.unsignedp))
-           return false;
-         /* Copy over any other type information we may have.  */
-         info->type_stack->type = nt->type;
-         return true;
-       }
-    }
+  h = ieee_name_type_hash_lookup (&info->typedefs, name, false, false);
+
+  /* h should never be NULL, since that would imply that the generic
+     debugging code has asked for a typedef which it has not yet
+     defined.  */
+  assert (h != NULL);
+
+  /* We always use the most recently defined type for this name, which
+     will be the first one on the list.  */
 
-  abort ();
+  nt = h->types;
+  if (! ieee_push_type (info, nt->type.indx, nt->type.size,
+                       nt->type.unsignedp, nt->type.localp))
+    return false;
+
+  /* Copy over any other type information we may have.  */
+  info->type_stack->type = nt->type;
+
+  return true;
 }
 
 /* Push a tagged type onto the type stack.  */
@@ -5763,43 +6702,89 @@ ieee_tag_type (p, name, id, kind)
      enum debug_type_kind kind;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
-  register struct ieee_name_type *nt;
+  boolean localp;
+  boolean copy;
   char ab[20];
+  struct ieee_name_type_hash_entry *h;
+  struct ieee_name_type *nt;
+
+  if (kind == DEBUG_KIND_ENUM)
+    {
+      struct ieee_defined_enum *e;
+
+      if (name == NULL)
+       abort ();
+      for (e = info->enums; e != NULL; e = e->next)
+       if (e->tag != NULL && strcmp (e->tag, name) == 0)
+         return ieee_push_type (info, e->indx, 0, true, false);
+
+      e = (struct ieee_defined_enum *) xmalloc (sizeof *e);
+      memset (e, 0, sizeof *e);
+
+      e->indx = info->type_indx;
+      ++info->type_indx;
+      e->tag = name;
+      e->defined = false;
+
+      e->next = info->enums;
+      info->enums = e;
 
+      return ieee_push_type (info, e->indx, 0, true, false);
+    }
+
+  localp = false;
+
+  copy = false;
   if (name == NULL)
     {
       sprintf (ab, "__anon%u", id);
       name = ab;
+      copy = true;
     }
 
-  for (nt = info->tags; nt != NULL; nt = nt->next)
+  h = ieee_name_type_hash_lookup (&info->tags, name, true, copy);
+  if (h == NULL)
+    return false;
+
+  for (nt = h->types; nt != NULL; nt = nt->next)
     {
-      if (nt->name[0] == name[0]
-         && strcmp (nt->name, name) == 0)
+      if (nt->id == id)
        {
          if (! ieee_push_type (info, nt->type.indx, nt->type.size,
-                               nt->type.unsignedp))
+                               nt->type.unsignedp, nt->type.localp))
            return false;
          /* Copy over any other type information we may have.  */
          info->type_stack->type = nt->type;
          return true;
        }
+
+      if (! nt->type.localp)
+       {
+         /* This is a duplicate of a global type, so it must be
+             local. */
+         localp = true;
+       }
     }
 
   nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
   memset (nt, 0, sizeof *nt);
 
-  if (name == ab)
-    name = xstrdup (ab);
-  nt->name = name;
+  nt->id = id;
+  nt->type.name = h->root.string;
   nt->type.indx = info->type_indx;
+  nt->type.localp = localp;
   ++info->type_indx;
   nt->kind = kind;
 
-  nt->next = info->tags;
-  info->tags = nt;
+  nt->next = h->types;
+  h->types = nt;
 
-  return ieee_push_type (info, nt->type.indx, 0, false);
+  if (! ieee_push_type (info, nt->type.indx, 0, false, localp))
+    return false;
+
+  info->type_stack->type.name = h->root.string;
+
+  return true;
 }
 
 /* Output a typedef.  */
@@ -5810,34 +6795,24 @@ ieee_typdef (p, name)
      const char *name;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
-  struct ieee_name_type *nt;
-  unsigned int size;
-  boolean unsignedp;
+  struct ieee_write_type type;
   unsigned int indx;
+  boolean found;
+  boolean localp;
+  struct ieee_name_type_hash_entry *h;
+  struct ieee_name_type *nt;
 
-  nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
-  memset (nt, 0, sizeof *nt);
-  nt->name = name;
-  nt->type = info->type_stack->type;
-  nt->kind = DEBUG_KIND_ILLEGAL;
-
-  nt->next = info->typedefs;
-  info->typedefs = nt;
-
-  size = info->type_stack->type.size;
-  unsignedp = info->type_stack->type.unsignedp;
-  indx = ieee_pop_type (info);
+  type = info->type_stack->type;
+  indx = type.indx;
 
   /* If this is a simple builtin type using a builtin name, we don't
      want to output the typedef itself.  We also want to change the
      type index to correspond to the name being used.  We recognize
      names used in stabs debugging output even if they don't exactly
      correspond to the names used for the IEEE builtin types.  */
+  found = false;
   if (indx <= (unsigned int) builtin_bcd_float)
     {
-      boolean found;
-
-      found = false;
       switch ((enum builtin_types) indx)
        {
        default:
@@ -5984,14 +6959,60 @@ ieee_typdef (p, name)
        }
 
       if (found)
+       type.indx = indx;
+    }
+
+  h = ieee_name_type_hash_lookup (&info->typedefs, name, true, false);
+  if (h == NULL)
+    return false;
+
+  /* See if we have already defined this type with this name.  */
+  localp = type.localp;
+  for (nt = h->types; nt != NULL; nt = nt->next)
+    {
+      if (nt->id == indx)
        {
-         nt->type.indx = indx;
-         return true;
+         /* If this is a global definition, then we don't need to
+            do anything here.  */
+         if (! nt->type.localp)
+           {
+             ieee_pop_unused_type (info);
+             return true;
+           }
+       }
+      else
+       {
+         /* This is a duplicate definition, so make this one local.  */
+         localp = true;
        }
     }
 
-  if (! ieee_define_named_type (info, name, false, 0, size, unsignedp,
-                               (struct ieee_buf **) NULL)
+  /* We need to add a new typedef for this type.  */
+
+  nt = (struct ieee_name_type *) xmalloc (sizeof *nt);
+  memset (nt, 0, sizeof *nt);
+  nt->id = indx;
+  nt->type = type;
+  nt->type.name = name;
+  nt->type.localp = localp;
+  nt->kind = DEBUG_KIND_ILLEGAL;
+
+  nt->next = h->types;
+  h->types = nt;
+
+  if (found)
+    {
+      /* This is one of the builtin typedefs, so we don't need to
+         actually define it.  */
+      ieee_pop_unused_type (info);
+      return true;
+    }
+
+  indx = ieee_pop_type (info);
+
+  if (! ieee_define_named_type (info, name, (unsigned int) -1, type.size,
+                               type.unsignedp, localp,
+                               (struct ieee_buflist *) NULL)
       || ! ieee_write_number (info, 'T')
       || ! ieee_write_number (info, indx))
     return false;
@@ -6009,7 +7030,7 @@ ieee_typdef (p, name)
 static boolean
 ieee_tag (p, name)
      PTR p;
-     const char *name;
+     const char *name ATTRIBUTE_UNUSED;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
 
@@ -6023,9 +7044,9 @@ ieee_tag (p, name)
 
 static boolean
 ieee_int_constant (p, name, val)
-     PTR p;
-     const char *name;
-     bfd_vma val;
+     PTR p ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
 {
   /* FIXME.  */
   return true;
@@ -6035,9 +7056,9 @@ ieee_int_constant (p, name, val)
 
 static boolean
 ieee_float_constant (p, name, val)
-     PTR p;
-     const char *name;
-     double val;
+     PTR p ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
+     double val ATTRIBUTE_UNUSED;
 {
   /* FIXME.  */
   return true;
@@ -6048,8 +7069,8 @@ ieee_float_constant (p, name, val)
 static boolean
 ieee_typed_constant (p, name, val)
      PTR p;
-     const char *name;
-     bfd_vma val;
+     const char *name ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
 
@@ -6079,21 +7100,9 @@ ieee_variable (p, name, kind, val)
   referencep = info->type_stack->type.referencep;
   type_indx = ieee_pop_type (info);
 
-  /* Make sure the variable section is started.  */
-  if (info->vars != NULL)
-    {
-      if (! ieee_change_buffer (info, &info->vars))
-       return false;
-    }
-  else
-    {
-      if (! ieee_change_buffer (info, &info->vars)
-         || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-         || ! ieee_write_byte (info, 3)
-         || ! ieee_write_number (info, 0)
-         || ! ieee_write_id (info, info->modname))
-       return false;
-    }
+  assert (! ieee_buffer_emptyp (&info->vars));
+  if (! ieee_change_buffer (info, &info->vars))
+    return false;
 
   name_indx = info->name_indx;
   ++info->name_indx;
@@ -6113,21 +7122,21 @@ ieee_variable (p, name, kind, val)
       return false;
     case DEBUG_GLOBAL:
       if (! ieee_write_number (info, 8)
-         || ! ieee_add_range (info, val, val + size))
+         || ! ieee_add_range (info, false, val, val + size))
        return false;
       refflag = 0;
       asn = true;
       break;
     case DEBUG_STATIC:
       if (! ieee_write_number (info, 3)
-         || ! ieee_add_range (info, val, val + size))
+         || ! ieee_add_range (info, false, val, val + size))
        return false;
       refflag = 1;
       asn = true;
       break;
     case DEBUG_LOCAL_STATIC:
       if (! ieee_write_number (info, 3)
-         || ! ieee_add_range (info, val, val + size))
+         || ! ieee_add_range (info, false, val, val + size))
        return false;
       refflag = 2;
       asn = true;
@@ -6212,7 +7221,7 @@ ieee_start_function (p, name, global)
      function in the BB1 typedef block.  We can't write out the full
      type until we have seen all the parameters, so we accumulate it
      in info->fntype and info->fnargs.  */
-  if (info->fntype != NULL)
+  if (! ieee_buffer_emptyp (&info->fntype))
     {
       /* FIXME: This might happen someday if we support nested
          functions.  */
@@ -6221,11 +7230,11 @@ ieee_start_function (p, name, global)
 
   info->fnname = name;
 
-  /* An attribute of 0x41 means that the frame and push mask are
-     unknown.  */
-  if (! ieee_define_named_type (info, name, false, 0, 0, false, &info->fntype)
+  /* An attribute of 0x40 means that the push mask is unknown.  */
+  if (! ieee_define_named_type (info, name, (unsigned int) -1, 0, false, true,
+                               &info->fntype)
       || ! ieee_write_number (info, 'x')
-      || ! ieee_write_number (info, 0x41)
+      || ! ieee_write_number (info, 0x40)
       || ! ieee_write_number (info, 0)
       || ! ieee_write_number (info, 0)
       || ! ieee_write_number (info, retindx))
@@ -6233,7 +7242,8 @@ ieee_start_function (p, name, global)
 
   typeindx = ieee_pop_type (info);
 
-  info->fnargs = NULL;
+  if (! ieee_init_buffer (info, &info->fnargs))
+    return false;
   info->fnargcount = 0;
 
   /* If the function return value is actually a reference type, we
@@ -6260,21 +7270,9 @@ ieee_start_function (p, name, global)
        return false;
     }
 
-  /* Make sure the variable section is started.  */
-  if (info->vars != NULL)
-    {
-      if (! ieee_change_buffer (info, &info->vars))
-       return false;
-    }
-  else
-    {
-      if (! ieee_change_buffer (info, &info->vars)
-         || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-         || ! ieee_write_byte (info, 3)
-         || ! ieee_write_number (info, 0)
-         || ! ieee_write_id (info, info->modname))
-       return false;
-    }
+  assert (! ieee_buffer_emptyp (&info->vars));
+  if (! ieee_change_buffer (info, &info->vars))
+    return false;
 
   /* The address is written out as the first block.  */
 
@@ -6323,7 +7321,7 @@ ieee_function_parameter (p, name, kind, val)
     return false;
   ++info->fnargcount;
 
-  return true;  
+  return true;
 }
 
 /* Output pending function parameters.  */
@@ -6355,7 +7353,7 @@ ieee_output_pending_parms (info)
          break;
        }
 
-      if (! ieee_push_type (info, m->type, 0, false))
+      if (! ieee_push_type (info, m->type, 0, false, false))
        return false;
       info->type_stack->type.referencep = m->referencep;
       if (m->referencep)
@@ -6463,9 +7461,12 @@ ieee_end_block (p, addr)
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
 
+  /* The address we are given is the end of the block, but IEEE seems
+     to want to the address of the last byte in the block, so we
+     subtract one.  */
   if (! ieee_change_buffer (info, &info->vars)
       || ! ieee_write_byte (info, (int) ieee_be_record_enum)
-      || ! ieee_write_number (info, addr))
+      || ! ieee_write_number (info, addr - 1))
     return false;
 
   if (! ieee_end_range (info, addr))
@@ -6486,7 +7487,6 @@ ieee_end_function (p)
      PTR p;
 {
   struct ieee_handle *info = (struct ieee_handle *) p;
-  struct ieee_buf **pb;
 
   assert (info->block_depth == 1);
 
@@ -6505,7 +7505,7 @@ ieee_end_function (p)
     return false;
 
   /* Make sure the typdef block has been started.  */
-  if (info->types == NULL)
+  if (ieee_buffer_emptyp (&info->types))
     {
       if (! ieee_change_buffer (info, &info->types)
          || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
@@ -6515,16 +7515,14 @@ ieee_end_function (p)
        return false;
     }
 
-  for (pb = &info->types; *pb != NULL; pb = &(*pb)->next)
-    ;
-  *pb = info->fntype;
-  for (; *pb != NULL; pb = &(*pb)->next)
-    ;
-  *pb = info->fnargs;
+  if (! ieee_append_buffer (info, &info->types, &info->fntype)
+      || ! ieee_append_buffer (info, &info->types, &info->fnargs))
+    return false;
 
   info->fnname = NULL;
-  info->fntype = NULL;
-  info->fnargs = NULL;
+  if (! ieee_init_buffer (info, &info->fntype)
+      || ! ieee_init_buffer (info, &info->fnargs))
+    return false;
   info->fnargcount = 0;
 
   return true;
@@ -6543,55 +7541,87 @@ ieee_lineno (p, filename, lineno, addr)
 
   assert (info->filename != NULL);
 
-  /* Make sure we have a line number block.  */
-  if (info->linenos != NULL)
-    {
-      if (! ieee_change_buffer (info, &info->linenos))
-       return false;
-    }
-  else
-    {
-      info->lineno_name_indx = info->name_indx;
-      ++info->name_indx;
-      if (! ieee_change_buffer (info, &info->linenos)
-         || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-         || ! ieee_write_byte (info, 5)
-         || ! ieee_write_number (info, 0)
-         || ! ieee_write_id (info, info->filename)
-         || ! ieee_write_byte (info, (int) ieee_nn_record)
-         || ! ieee_write_number (info, info->lineno_name_indx)
-         || ! ieee_write_id (info, ""))
-       return false;
-      info->lineno_filename = info->filename;
-    }
-
-  if (strcmp (filename, info->lineno_filename) != 0)
+  /* The HP simulator seems to get confused when more than one line is
+     listed for the same address, at least if they are in different
+     files.  We handle this by always listing the last line for a
+     given address, since that seems to be the one that gdb uses.  */
+  if (info->pending_lineno_filename != NULL
+      && addr != info->pending_lineno_addr)
     {
-      if (strcmp (info->filename, info->lineno_filename) != 0)
+      /* Make sure we have a line number block.  */
+      if (! ieee_buffer_emptyp (&info->linenos))
        {
-         /* We were not in the main file.  Close the block for the
-             included file.  */
-         if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+         if (! ieee_change_buffer (info, &info->linenos))
            return false;
        }
-      if (strcmp (info->filename, filename) != 0)
+      else
        {
-         /* We are not changing to the main file.  Open a block for
-             the new included file.  */
-         if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+         info->lineno_name_indx = info->name_indx;
+         ++info->name_indx;
+         if (! ieee_change_buffer (info, &info->linenos)
+             || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
              || ! ieee_write_byte (info, 5)
              || ! ieee_write_number (info, 0)
-             || ! ieee_write_id (info, filename))
+             || ! ieee_write_id (info, info->filename)
+             || ! ieee_write_byte (info, (int) ieee_nn_record)
+             || ! ieee_write_number (info, info->lineno_name_indx)
+             || ! ieee_write_id (info, ""))
            return false;
+         info->lineno_filename = info->filename;
+       }
+
+      if (strcmp (info->pending_lineno_filename, info->lineno_filename) != 0)
+       {
+         if (strcmp (info->filename, info->lineno_filename) != 0)
+           {
+             /* We were not in the main file.  Close the block for the
+                included file.  */
+             if (! ieee_write_byte (info, (int) ieee_be_record_enum))
+               return false;
+             if (strcmp (info->filename, info->pending_lineno_filename) == 0)
+               {
+                 /* We need a new NN record, and we aren't about to
+                    output one.  */
+                 info->lineno_name_indx = info->name_indx;
+                 ++info->name_indx;
+                 if (! ieee_write_byte (info, (int) ieee_nn_record)
+                     || ! ieee_write_number (info, info->lineno_name_indx)
+                     || ! ieee_write_id (info, ""))
+                   return false;
+               }
+           }
+         if (strcmp (info->filename, info->pending_lineno_filename) != 0)
+           {
+             /* We are not changing to the main file.  Open a block for
+                the new included file.  */
+             info->lineno_name_indx = info->name_indx;
+             ++info->name_indx;
+             if (! ieee_write_byte (info, (int) ieee_bb_record_enum)
+                 || ! ieee_write_byte (info, 5)
+                 || ! ieee_write_number (info, 0)
+                 || ! ieee_write_id (info, info->pending_lineno_filename)
+                 || ! ieee_write_byte (info, (int) ieee_nn_record)
+                 || ! ieee_write_number (info, info->lineno_name_indx)
+                 || ! ieee_write_id (info, ""))
+               return false;
+           }
+         info->lineno_filename = info->pending_lineno_filename;
        }
-      info->lineno_filename = filename;
+
+      if (! ieee_write_2bytes (info, (int) ieee_atn_record_enum)
+         || ! ieee_write_number (info, info->lineno_name_indx)
+         || ! ieee_write_number (info, 0)
+         || ! ieee_write_number (info, 7)
+         || ! ieee_write_number (info, info->pending_lineno)
+         || ! ieee_write_number (info, 0)
+         || ! ieee_write_asn (info, info->lineno_name_indx,
+                              info->pending_lineno_addr))
+       return false;
     }
 
-  return (ieee_write_2bytes (info, (int) ieee_atn_record_enum)
-         && ieee_write_number (info, info->lineno_name_indx)
-         && ieee_write_number (info, 0)
-         && ieee_write_number (info, 7)
-         && ieee_write_number (info, lineno)
-         && ieee_write_number (info, 0)
-         && ieee_write_asn (info, info->lineno_name_indx, addr));
+  info->pending_lineno_filename = filename;
+  info->pending_lineno = lineno;
+  info->pending_lineno_addr = addr;
+
+  return true;
 }
This page took 0.075992 seconds and 4 git commands to generate.